merge autoland to mozilla-central a=merge

This commit is contained in:
Iris Hsiao 2017-04-12 11:07:56 +08:00
Родитель 2fc8c8d483 8b825ab76e
Коммит e580f2db96
1490 изменённых файлов: 11640 добавлений и 54461 удалений

Просмотреть файл

@ -7,59 +7,75 @@ module.metadata = {
"stability": "experimental"
};
const { Ci, Cc } = require("chrome");
const { make: makeWindow, getHiddenWindow } = require("../window/utils");
const { create: makeFrame, getDocShell } = require("../frame/utils");
const { defer } = require("../core/promise");
const { Ci, Cc, Cu } = require("chrome");
const { when: unload } = require("../system/unload");
const cfxArgs = require("../test/options");
const prefs = require("../preferences/service");
var addonPrincipal = Cc["@mozilla.org/systemprincipal;1"].
createInstance(Ci.nsIPrincipal);
if (!prefs.get("extensions.usehiddenwindow", false)) {
const {HiddenFrame} = require("resource:///modules/HiddenFrame.jsm", {});
let hiddenFrame = new HiddenFrame();
exports.window = hiddenFrame.getWindow();
exports.ready = hiddenFrame.get();
var hiddenWindow = getHiddenWindow();
// Still destroy frame on unload to claim memory back early.
// NOTE: this doesn't seem to work and just doesn't get called. :-\
unload(function() {
hiddenFrame.destroy();
hiddenFrame = null;
});
} else {
const { make: makeWindow, getHiddenWindow } = require("../window/utils");
const { create: makeFrame, getDocShell } = require("../frame/utils");
const { defer } = require("../core/promise");
const cfxArgs = require("../test/options");
if (cfxArgs.parseable) {
console.info("hiddenWindow document.documentURI:" +
hiddenWindow.document.documentURI);
console.info("hiddenWindow document.readyState:" +
hiddenWindow.document.readyState);
var addonPrincipal = Cc["@mozilla.org/systemprincipal;1"].
createInstance(Ci.nsIPrincipal);
var hiddenWindow = getHiddenWindow();
if (cfxArgs.parseable) {
console.info("hiddenWindow document.documentURI:" +
hiddenWindow.document.documentURI);
console.info("hiddenWindow document.readyState:" +
hiddenWindow.document.readyState);
}
// Once Bug 565388 is fixed and shipped we'll be able to make invisible,
// permanent docShells. Meanwhile we create hidden top level window and
// use it's docShell.
var frame = makeFrame(hiddenWindow.document, {
nodeName: "iframe",
namespaceURI: "http://www.w3.org/1999/xhtml",
allowJavascript: true,
allowPlugins: true
})
var docShell = getDocShell(frame);
var eventTarget = docShell.chromeEventHandler;
// We need to grant docShell system principals in order to load XUL document
// from data URI into it.
docShell.createAboutBlankContentViewer(addonPrincipal);
// Get a reference to the DOM window of the given docShell and load
// such document into that would allow us to create XUL iframes, that
// are necessary for hidden frames etc..
var window = docShell.contentViewer.DOMDocument.defaultView;
window.location = "data:application/vnd.mozilla.xul+xml;charset=utf-8,<window/>";
// Create a promise that is delivered once add-on window is interactive,
// used by add-on runner to defer add-on loading until window is ready.
var { promise, resolve } = defer();
eventTarget.addEventListener("DOMContentLoaded", function(event) {
resolve();
}, {once: true});
exports.ready = promise;
exports.window = window;
// Still close window on unload to claim memory back early.
unload(function() {
window.close()
frame.remove();
});
}
// Once Bug 565388 is fixed and shipped we'll be able to make invisible,
// permanent docShells. Meanwhile we create hidden top level window and
// use it's docShell.
var frame = makeFrame(hiddenWindow.document, {
nodeName: "iframe",
namespaceURI: "http://www.w3.org/1999/xhtml",
allowJavascript: true,
allowPlugins: true
})
var docShell = getDocShell(frame);
var eventTarget = docShell.chromeEventHandler;
// We need to grant docShell system principals in order to load XUL document
// from data URI into it.
docShell.createAboutBlankContentViewer(addonPrincipal);
// Get a reference to the DOM window of the given docShell and load
// such document into that would allow us to create XUL iframes, that
// are necessary for hidden frames etc..
var window = docShell.contentViewer.DOMDocument.defaultView;
window.location = "data:application/vnd.mozilla.xul+xml;charset=utf-8,<window/>";
// Create a promise that is delivered once add-on window is interactive,
// used by add-on runner to defer add-on loading until window is ready.
var { promise, resolve } = defer();
eventTarget.addEventListener("DOMContentLoaded", function(event) {
resolve();
}, {once: true});
exports.ready = promise;
exports.window = window;
// Still close window on unload to claim memory back early.
unload(function() {
window.close()
frame.remove();
});

Просмотреть файл

@ -8,8 +8,9 @@ module.metadata = {
};
const { deprecateFunction } = require("../util/deprecate");
const { Cc, Ci } = require("chrome");
const XMLHttpRequest = require("../addon/window").window.XMLHttpRequest;
const { Ci, Cu } = require("chrome");
Cu.importGlobalProperties(["XMLHttpRequest"]);
Object.defineProperties(XMLHttpRequest.prototype, {
mozBackgroundRequest: {

Просмотреть файл

@ -13,7 +13,7 @@ const { Services } = require("resource://gre/modules/Services.jsm");
const { setTimeout } = require("../timers");
const { platform } = require("../system");
const { getMostRecentBrowserWindow, getOwnerBrowserWindow,
getHiddenWindow, getScreenPixelsPerCSSPixel } = require("../window/utils");
getScreenPixelsPerCSSPixel } = require("../window/utils");
const { create: createFrame, swapFrameLoaders, getDocShell } = require("../frame/utils");
const { window: addonWindow } = require("../addon/window");

Просмотреть файл

@ -426,6 +426,8 @@ pref("browser.link.open_newwindow.disabled_in_fullscreen", true);
pref("browser.link.open_newwindow.disabled_in_fullscreen", false);
#endif
pref("browser.photon.structure.enabled", false);
// Tabbed browser
pref("browser.tabs.closeWindowWithLastTab", true);
pref("browser.tabs.insertRelatedAfterCurrent", true);

Просмотреть файл

@ -52,6 +52,17 @@ function init(aEvent) {
let arch = bundle.GetStringFromName(archResource);
versionField.textContent += ` (${arch})`;
// Show a release notes link if we have a URL.
let relNotesLink = document.getElementById("releasenotes");
let relNotesPrefType = Services.prefs.getPrefType("app.releaseNotesURL");
if (relNotesPrefType != Services.prefs.PREF_INVALID) {
let relNotesURL = Services.urlFormatter.formatURLPref("app.releaseNotesURL");
if (relNotesURL != "about:blank") {
relNotesLink.href = relNotesURL;
relNotesLink.hidden = false;
}
}
if (AppConstants.MOZ_UPDATER) {
gAppUpdater = new appUpdater();

Просмотреть файл

@ -45,10 +45,8 @@
<vbox id="leftBox" flex="1"/>
<vbox id="rightBox" flex="1">
<hbox align="baseline">
#expand <label id="version">__MOZ_APP_VERSION_DISPLAY__</label>
#ifndef NIGHTLY_BUILD
#expand <label id="releasenotes" class="text-link" href="https://www.mozilla.org/firefox/__MOZ_APP_VERSION__/releasenotes/">&releaseNotes.link;</label>
#endif
#expand <label id="version">__MOZ_APP_VERSION_DISPLAY__</label>
<label id="releasenotes" class="text-link" hidden="true">&releaseNotes.link;</label>
</hbox>
<label id="distribution" class="text-blurb"/>

Просмотреть файл

@ -26,6 +26,7 @@
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="gBrowserInit.onLoad()" onunload="gBrowserInit.onUnload()" onclose="return WindowIsClosing();"
title="&mainWindow.title;"
@ -719,6 +720,8 @@
tooltiptext="&urlbar.microphoneBlocked.tooltip;"/>
<image data-permission-id="screen" class="blocked-permission-icon screen-icon" role="button"
tooltiptext="&urlbar.screenBlocked.tooltip;"/>
<image data-permission-id="persistent-storage" class="blocked-permission-icon persistent-storage-icon" role="button"
tooltiptext="&urlbar.persistentStorageBlocked.tooltip;"/>
</box>
<box id="notification-popup-box"
hidden="true"
@ -753,6 +756,8 @@
tooltiptext="&urlbar.translatedNotificationAnchor.tooltip;"/>
<image id="eme-notification-icon" class="notification-anchor-icon drm-icon" role="button"
tooltiptext="&urlbar.emeNotificationAnchor.tooltip;"/>
<image id="persistent-storage-notification-icon" class="notification-anchor-icon persistent-storage-icon" role="button"
tooltiptext="&urlbar.persistentStorageNotificationAnchor.tooltip;"/>
</box>
<image id="connection-icon"/>
<hbox id="identity-icon-labels">

Просмотреть файл

@ -355,7 +355,9 @@ var AboutNetAndCertErrorListener = {
// If the difference is more than a day.
if (Math.abs(difference) > 60 * 60 * 24) {
let formatter = new Intl.DateTimeFormat();
let formatter = Services.intl.createDateTimeFormat(undefined, {
dateStyle: "short"
});
let systemDate = formatter.format(new Date());
// negative difference means local time is behind server time
let actualDate = formatter.format(new Date(Date.now() - difference * 1000));
@ -385,7 +387,9 @@ var AboutNetAndCertErrorListener = {
let systemDate = new Date();
if (buildDate > systemDate) {
let formatter = new Intl.DateTimeFormat();
let formatter = Services.intl.createDateTimeFormat(undefined, {
dateStyle: "short"
});
content.document.getElementById("wrongSystemTimeWithoutReference_URL")
.textContent = content.document.location.hostname;

Просмотреть файл

@ -74,7 +74,6 @@
<popupnotification id="addon-webext-permissions-notification" hidden="true">
<popupnotificationcontent orient="vertical">
<description id="addon-webext-perm-header" class="addon-webext-perm-header"/>
<description id="addon-webext-perm-text" class="addon-webext-perm-text"/>
<label id="addon-webext-perm-intro" class="addon-webext-perm-text"/>
<html:ul id="addon-webext-perm-list" class="addon-webext-perm-list"/>

Просмотреть файл

@ -151,7 +151,9 @@ add_task(function* checkWrongSystemTimeWarning() {
});
}
let formatter = new Intl.DateTimeFormat();
let formatter = Services.intl.createDateTimeFormat(undefined, {
dateStyle: "short"
});
// pretend we have a positively skewed (ahead) system time
let serverDate = new Date("2015/10/27");

Просмотреть файл

@ -160,6 +160,23 @@ var tests = [
gNotification.remove();
}
},
// Test no checkbox hides warning label
{ id: "no_checkbox",
run() {
this.notifyObj = new BasicNotification(this.id);
this.notifyObj.options.checkbox = null;
gNotification = showNotification(this.notifyObj);
},
onShown(popup) {
checkPopup(popup, this.notifyObj);
let notification = popup.childNodes[0];
checkCheckbox(notification.checkbox, "", false, true);
checkMainAction(notification);
triggerMainCommand(popup);
},
onHidden() { },
},
];
// Test checkbox disabling the main action in different combinations

Просмотреть файл

@ -22,6 +22,8 @@ pref("app.update.url.manual", "https://www.mozilla.org/firefox/aurora/");
// supplied in the "An update is available" page of the update wizard.
pref("app.update.url.details", "https://www.mozilla.org/firefox/aurora/");
pref("app.releaseNotesURL", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/releasenotes/?utm_source=firefox-browser&utm_medium=firefox-browser&utm_campaign=whatsnew");
// The number of days a binary is permitted to be old
// without checking for an update. This assumes that
// app.update.checkInstallTime is true.

Просмотреть файл

@ -20,6 +20,8 @@ pref("app.update.url.manual", "https://www.mozilla.org/firefox/");
// supplied in the "An update is available" page of the update wizard.
pref("app.update.url.details", "https://www.mozilla.org/%LOCALE%/firefox/notes");
pref("app.releaseNotesURL", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/releasenotes/?utm_source=firefox-browser&utm_medium=firefox-browser&utm_campaign=whatsnew");
// The number of days a binary is permitted to be old
// without checking for an update. This assumes that
// app.update.checkInstallTime is true.

Просмотреть файл

@ -485,3 +485,13 @@
</popupnotificationcontent>
</popupnotification>
</panel>
<panel id="PanelUI-photon-popup"
role="group"
type="arrow"
hidden="true"
flip="slide"
position="bottomcenter topright"
noautofocus="true">
This space intentionally left blank.
</panel>

Просмотреть файл

@ -11,6 +11,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "ShortcutUtils",
XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
"resource://gre/modules/AppConstants.jsm");
XPCOMUtils.defineLazyPreferenceGetter(this, "gPhotonStructure",
"browser.photon.structure.enabled", false);
/**
* Maintains the state and dispatches events for the main menu panel.
*/
@ -31,7 +34,7 @@ const PanelUI = {
multiView: "PanelUI-multiView",
helpView: "PanelUI-helpView",
menuButton: "PanelUI-menu-button",
panel: "PanelUI-popup",
panel: gPhotonStructure ? "PanelUI-photon-popup" : "PanelUI-popup",
notificationPanel: "PanelUI-notification-popup",
scroller: "PanelUI-contents-scroller",
footer: "PanelUI-footer"

Просмотреть файл

@ -189,9 +189,11 @@ FeedWriter.prototype = {
__dateFormatter: null,
get _dateFormatter() {
if (!this.__dateFormatter) {
const dtOptions = { year: "numeric", month: "long", day: "numeric",
hour: "numeric", minute: "numeric" };
this.__dateFormatter = new Intl.DateTimeFormat(undefined, dtOptions);
const dtOptions = {
timeStyle: "short",
dateStyle: "long"
};
this.__dateFormatter = Services.intl.createDateTimeFormat(undefined, dtOptions);
}
return this.__dateFormatter;
},

Просмотреть файл

@ -2315,6 +2315,11 @@ const ContentPermissionIntegration = {
case "desktop-notification": {
return new PermissionUI.DesktopNotificationPermissionPrompt(request);
}
case "persistent-storage": {
if (Services.prefs.getBoolPref("browser.storageManager.enabled")) {
return new PermissionUI.PersistentStoragePermissionPrompt(request);
}
}
}
return undefined;
},

Просмотреть файл

@ -10,6 +10,7 @@
Components.utils.import("resource://gre/modules/AppConstants.jsm");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/TelemetryStopwatch.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "MigrationUtils",
"resource:///modules/MigrationUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
@ -411,8 +412,10 @@ var PlacesOrganizer = {
populateRestoreMenu: function PO_populateRestoreMenu() {
let restorePopup = document.getElementById("fileRestorePopup");
const dtOptions = { year: "numeric", month: "long", day: "numeric" };
let dateFormatter = new Intl.DateTimeFormat(undefined, dtOptions);
const dtOptions = {
dateStyle: "long"
};
let dateFormatter = Services.intl.createDateTimeFormat(undefined, dtOptions);
// Remove existing menu items. Last item is the restoreFromFile item.
while (restorePopup.childNodes.length > 1)

Просмотреть файл

@ -3,6 +3,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
const PTV_interfaces = [Ci.nsITreeView,
Ci.nsINavHistoryResultObserver,
@ -499,8 +500,8 @@ PlacesTreeView.prototype = {
__todayFormatter: null,
get _todayFormatter() {
if (!this.__todayFormatter) {
const dtOptions = { hour: "numeric", minute: "numeric" };
this.__todayFormatter = new Intl.DateTimeFormat(undefined, dtOptions);
const dtOptions = { timeStyle: "short" };
this.__todayFormatter = Services.intl.createDateTimeFormat(undefined, dtOptions);
}
return this.__todayFormatter;
},
@ -508,9 +509,11 @@ PlacesTreeView.prototype = {
__dateFormatter: null,
get _dateFormatter() {
if (!this.__dateFormatter) {
const dtOptions = { year: "numeric", month: "numeric", day: "numeric",
hour: "numeric", minute: "numeric" };
this.__dateFormatter = new Intl.DateTimeFormat(undefined, dtOptions);
const dtOptions = {
dateStyle: "short",
timeStyle: "short"
};
this.__dateFormatter = Services.intl.createDateTimeFormat(undefined, dtOptions);
}
return this.__dateFormatter;
},

Просмотреть файл

@ -124,18 +124,21 @@
case "date":
let timeObj = new Date(node.time / 1000);
// Default is short date format.
let dtOptions = { year: 'numeric', month: 'numeric', day: 'numeric',
hour: 'numeric', minute: 'numeric' };
let dtOptions = {
dateStyle: "short",
timeStyle: "short"
};
// For today's visits we don't show date portion.
if (node.uri == "http://at.midnight.com/" ||
node.uri == "http://after.midnight.com/") {
dtOptions = { hour: 'numeric', minute: 'numeric' };
dtOptions.dateStyle = undefined;
} else if (node.uri != "http://before.midnight.com/") {
// Avoid to test spurious uris, due to how the test works
// a redirecting uri could be put in the tree while we test.
break;
}
let timeStr = timeObj.toLocaleString(undefined, dtOptions);
let timeStr = Services.intl.createDateTimeFormat(undefined, dtOptions).format(timeObj);
is(text, timeStr, "Date format is correct");
break;

Просмотреть файл

@ -213,6 +213,7 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY urlbar.passwordNotificationAnchor.tooltip "Open save password message panel">
<!ENTITY urlbar.pluginsNotificationAnchor.tooltip "Manage plug-in use">
<!ENTITY urlbar.webNotificationAnchor.tooltip "Change whether you can receive notifications from the site">
<!ENTITY urlbar.persistentStorageNotificationAnchor.tooltip "Store data in Persistent Storage">
<!ENTITY urlbar.webRTCShareDevicesNotificationAnchor.tooltip "Manage sharing your camera and/or microphone with the site">
<!ENTITY urlbar.webRTCShareMicrophoneNotificationAnchor.tooltip "Manage sharing your microphone with the site">
@ -229,12 +230,13 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY urlbar.geolocationBlocked.tooltip "You have blocked location information for this website.">
<!ENTITY urlbar.indexedDBBlocked.tooltip "You have blocked data storage for this website.">
<!ENTITY urlbar.webNotificationsBlocked.tooltip "You have blocked notifications for this website.">
<!ENTITY urlbar.persistentStorageBlocked.tooltip "You have blocked persistent storage for this website.">
<!ENTITY urlbar.openHistoryPopup.tooltip "Show history">
<!ENTITY searchItem.title "Search">
<!-- Toolbar items -->
<!-- Toolbar items -->
<!ENTITY homeButton.label "Home">
<!ENTITY bookmarksButton.label "Bookmarks">

Просмотреть файл

@ -496,6 +496,14 @@ geolocation.shareWithSite3=Will you allow %S to access your location?
geolocation.shareWithFile3=Will you allow this local file to access your location?
geolocation.remember=Remember this decision
# Persistent storage UI
persistentStorage.allow=Allow
persistentStorage.allow.accesskey=A
persistentStorage.dontAllow=Dont Allow
persistentStorage.dontAllow.accesskey=n
persistentStorage.allowWithSite=Will you allow %S to store data in persistent storage?
persistentStorage.remember=Remember this decision
webNotifications.allow=Allow Notifications
webNotifications.allow.accesskey=A
webNotifications.notNow=Not Now

Просмотреть файл

@ -36,3 +36,4 @@ permission.popup.label = Open Pop-up Windows
permission.geo.label = Access Your Location
permission.indexedDB.label = Maintain Offline Storage
permission.focus-tab-by-prompt.label = Switch to this Tab
permission.persistent-storage.label = Store Data in Persistent Storage

Просмотреть файл

@ -63,6 +63,7 @@ mk
ml
mr
ms
my
nb-NO
nl
nn-NO

Просмотреть файл

@ -341,10 +341,11 @@ this.ExtensionsUI = {
showPermissionsPrompt(browser, strings, icon, histkey) {
function eventCallback(topic) {
if (topic == "showing") {
let doc = this.browser.ownerDocument;
doc.getElementById("addon-webext-perm-header").innerHTML = strings.header;
let doc = this.browser.ownerDocument;
if (topic == "shown") {
doc.getElementById("addon-webext-permissions-notification")
.description.innerHTML = strings.header;
} else if (topic == "showing") {
let textEl = doc.getElementById("addon-webext-perm-text");
textEl.innerHTML = strings.text;
textEl.hidden = !strings.text;
@ -397,7 +398,12 @@ this.ExtensionsUI = {
},
];
win.PopupNotifications.show(browser, "addon-webext-permissions", "",
// Get the text value of strings.header to pre-populate the header. This will get
// overwritten with the HTML version later.
let escapeHeader = browser.ownerDocument.createElement("div");
escapeHeader.innerHTML = strings.header;
win.PopupNotifications.show(browser, "addon-webext-permissions",
escapeHeader.textContent,
"addons-notification-icon",
action, secondaryActions, popupOptions);
});

Просмотреть файл

@ -14,11 +14,27 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const XUL_PAGE = "data:application/vnd.mozilla.xul+xml;charset=utf-8,<window%20id='win'/>";
const gAllHiddenFrames = new WeakSet();
let cleanupRegistered = false;
function ensureCleanupRegistered() {
if (!cleanupRegistered) {
cleanupRegistered = true;
Services.obs.addObserver(function() {
for (let hiddenFrame of ChromeUtils.nondeterministicGetWeakSetKeys(gAllHiddenFrames)) {
hiddenFrame.destroy();
}
}, "xpcom-shutdown", false);
}
}
/**
* An hidden frame object. It takes care of creating a windowless browser and
* passing the window containing a blank XUL <window> back.
*/
function HiddenFrame() {}
function HiddenFrame() {
}
HiddenFrame.prototype = {
_frame: null,
@ -41,6 +57,16 @@ HiddenFrame.prototype = {
return this._deferred.promise;
},
/**
* Fetch a sync ref to the window inside the frame (needed for the add-on SDK).
*/
getWindow() {
this.get();
this._browser.QueryInterface(Ci.nsIInterfaceRequestor);
return this._browser.getInterface(Ci.nsIDOMWindow);
},
destroy() {
if (this._browser) {
if (this._listener) {
@ -51,14 +77,17 @@ HiddenFrame.prototype = {
this._frame = null;
this._deferred = null;
gAllHiddenFrames.delete(this);
this._browser.close();
this._browser = null;
}
},
_create() {
ensureCleanupRegistered();
this._browser = Services.appShell.createWindowlessBrowser(true);
this._browser.QueryInterface(Ci.nsIInterfaceRequestor);
gAllHiddenFrames.add(this);
this._webProgress = this._browser.getInterface(Ci.nsIWebProgress);
this._listener = {
QueryInterface: XPCOMUtils.generateQI([

Просмотреть файл

@ -598,3 +598,75 @@ DesktopNotificationPermissionPrompt.prototype = {
PermissionUI.DesktopNotificationPermissionPrompt =
DesktopNotificationPermissionPrompt;
/**
* Creates a PermissionPrompt for a nsIContentPermissionRequest for
* the persistent-storage API.
*
* @param request (nsIContentPermissionRequest)
* The request for a permission from content.
*/
function PersistentStoragePermissionPrompt(request) {
this.request = request;
}
PersistentStoragePermissionPrompt.prototype = {
__proto__: PermissionPromptForRequestPrototype,
get permissionKey() {
return "persistent-storage";
},
get popupOptions() {
let checkbox = {
// In PB mode, we don't want the "always remember" checkbox
show: !PrivateBrowsingUtils.isWindowPrivate(this.browser.ownerGlobal)
};
if (checkbox.show) {
checkbox.checked = true;
checkbox.label = gBrowserBundle.GetStringFromName("persistentStorage.remember");
}
let learnMoreURL =
Services.urlFormatter.formatURLPref("app.support.baseURL") + "storage-permissions";
return {
checkbox,
learnMoreURL
};
},
get notificationID() {
return "persistent-storage";
},
get anchorID() {
return "persistent-storage-notification-icon";
},
get message() {
let hostPort = "<>";
try {
hostPort = this.principal.URI.hostPort;
} catch (ex) {}
return gBrowserBundle.formatStringFromName(
"persistentStorage.allowWithSite", [hostPort], 1);
},
get promptActions() {
return [
{
label: gBrowserBundle.GetStringFromName("persistentStorage.allow"),
accessKey:
gBrowserBundle.GetStringFromName("persistentStorage.allow.accesskey"),
action: Ci.nsIPermissionManager.ALLOW_ACTION
},
{
label: gBrowserBundle.GetStringFromName("persistentStorage.dontAllow"),
accessKey:
gBrowserBundle.GetStringFromName("persistentStorage.dontAllow.accesskey"),
action: Ci.nsIPermissionManager.DENY_ACTION
}
];
}
};
PermissionUI.PersistentStoragePermissionPrompt = PersistentStoragePermissionPrompt;

Просмотреть файл

@ -614,8 +614,16 @@ var gPermissionObject = {
exactHostMatch: true,
states: [ SitePermissions.UNKNOWN, SitePermissions.ALLOW ],
},
"persistent-storage": {
exactHostMatch: true
}
};
// Delete this entry while being pre-off
// or the persistent-storage permission would appear in Page info's Permission section
if (!Services.prefs.getBoolPref("browser.storageManager.enabled")) {
delete gPermissionObject["persistent-storage"];
}
XPCOMUtils.defineLazyPreferenceGetter(SitePermissions, "temporaryPermissionExpireTime",
"privacy.temporary_permission_expire_time_ms", 3600 * 1000);

Просмотреть файл

@ -20,6 +20,11 @@ add_task(function* test_desktop_notification_permission_prompt() {
yield testPrompt(PermissionUI.DesktopNotificationPermissionPrompt);
});
// Tests that PersistentStoragePermissionPrompt works as expected
add_task(function* test_persistent_storage_permission_prompt() {
yield testPrompt(PermissionUI.PersistentStoragePermissionPrompt);
});
function* testPrompt(Prompt) {
yield BrowserTestUtils.withNewTab({
gBrowser,

Просмотреть файл

@ -9,7 +9,7 @@ Components.utils.import("resource://gre/modules/Services.jsm");
add_task(function* testPermissionsListing() {
Assert.deepEqual(SitePermissions.listPermissions().sort(),
["camera", "cookie", "desktop-notification", "focus-tab-by-prompt", "geo", "image",
"indexedDB", "install", "microphone", "popup", "screen"],
"indexedDB", "install", "microphone", "persistent-storage", "popup", "screen"],
"Correct list of all permissions");
});
@ -72,7 +72,8 @@ add_task(function* testExactHostMatch() {
let uri = Services.io.newURI("https://example.com");
let subUri = Services.io.newURI("https://test1.example.com");
let exactHostMatched = ["desktop-notification", "focus-tab-by-prompt", "camera", "microphone", "screen", "geo"];
let exactHostMatched = ["desktop-notification", "focus-tab-by-prompt", "camera",
"microphone", "screen", "geo", "persistent-storage"];
let nonExactHostMatched = ["image", "cookie", "popup", "install", "indexedDB"];
let permissions = SitePermissions.listPermissions();

Просмотреть файл

@ -793,8 +793,18 @@ menuitem.bookmark-item {
font-weight: bold;
}
.addon-webext-perm-header {
font-size: 1.3em;
html|*.addon-webext-perm-list {
margin-block-end: 0;
padding-inline-start: 10px;
}
.addon-webext-perm-text {
margin-inline-start: 0;
}
.popup-notification-description[popupid="addon-webext-permissions"] {
margin: 0;
padding: 0;
}
.addon-webext-name {

Просмотреть файл

@ -3031,8 +3031,18 @@ menulist.translate-infobar-element > .menulist-dropmarker {
font-weight: bold;
}
.addon-webext-perm-header {
font-size: 1.3em;
html|*.addon-webext-perm-list {
margin-block-end: 0;
padding-inline-start: 10px;
}
.addon-webext-perm-text {
margin-inline-start: 0;
}
.popup-notification-description[popupid="addon-webext-permissions"] {
margin: 0;
padding: 0;
}
.addon-webext-name {

Просмотреть файл

@ -37,6 +37,15 @@
list-style-image: url(chrome://browser/skin/notification-icons.svg#focus-tab-by-prompt);
}
.popup-notification-icon[popupid="persistent-storage"],
.persistent-storage-icon {
list-style-image: url(chrome://browser/skin/notification-icons.svg#persistent-storage);
}
.persistent-storage-icon.blocked-permission-icon {
list-style-image: url(chrome://browser/skin/notification-icons.svg#persistent-storage-blocked);
}
.popup-notification-icon[popupid="web-notifications"],
.desktop-notification-icon {
list-style-image: url(chrome://browser/skin/notification-icons.svg#desktop-notification);

Просмотреть файл

@ -66,6 +66,7 @@
<path id="login-detailed-icon" d="m 1,27 0,3.5 a 0.5,0.5 0 0 0 0.5,0.5 l 5,0 a 0.5,0.5 0 0 0 0.5,-0.5 l 0,-1.5 1.5,0 a 0.5,0.5 0 0 0 0.5,-0.5 l 0,-1.5 1,0 a 0.5,0.5 0 0 0 0.5,-0.5 l 0,-1 1,0 a 0.5,0.5 0 0 0 0.5,-0.5 l 0,-2 2,0 2.5,-2.5 q 0.5,-0.5 1,0 l 1,1 c 0.5,0.5 1,0.5 1.5,-0.5 l 1,-2 a 9,9 0 1 0 -8,-8 l -2,1 c -1,0.5 -1,1 -0.5,1.5 l 1.5,1.5 q 0.5,0.5 0,1 z m 21,-19.1 a 2,2 0 1 1 0,0.2 z" />
<path id="microphone-icon" d="m 8,14 0,4 a 8,8 0 0 0 6,7.7 l 0,2.3 -2,0 a 2,2 0 0 0 -2,2 l 12,0 a 2,2 0 0 0 -2,-2 l -2,0 0,-2.3 a 8,8 0 0 0 6,-7.7 l 0,-4 -2,0 0,4 a 6,6 0 0 1 -12,0 l 0,-4 z m 4,4 a 4,4 0 0 0 8,0 l 0,-12 a 4,4 0 0 0 -8,0 z" />
<path id="microphone-detailed-icon" d="m 8,18 a 8,8 0 0 0 6,7.7 l 0,2.3 -1,0 a 3,2 0 0 0 -3,2 l 12,0 a 3,2 0 0 0 -3,-2 l -1,0 0,-2.3 a 8,8 0 0 0 6,-7.7 l 0,-4 a 1,1 0 0 0 -2,0 l 0,4 a 6,6 0 0 1 -12,0 l 0,-4 a 1,1 0 0 0 -2,0 z m 4,0 a 4,4 0 0 0 8,0 l 0,-12 a 4,4 0 0 0 -8,0 z" />
<path id="persistent-storage-icon" d="M26 21.1H6c-1.1 0-2 .9-2 2V27c0 1.1.9 2 2 2h20c1.1 0 2-.9 2-2v-3.9c0-1.1-.9-2-2-2zM24.1 27c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zM25 3H7C5.3 3 4 4.4 4 6.2v13.3c.6-.3 1.3-.5 2-.5h20c.7 0 1.4.2 2 .5V6.2C28 4.4 26.7 3 25 3z"/>
<path id="plugin-icon" d="m 2,26 a 2,2 0 0 0 2,2 l 24,0 a 2,2 0 0 0 2,-2 l 0,-16 a 2,2 0 0 0 -2,-2 l -24,0 a 2,2 0 0 0 -2,2 z m 2,-20 10,0 0,-2 a 2,2 0 0 0 -2,-2 l -6,0 a 2,2 0 0 0 -2,2 z m 14,0 10,0 0,-2 a 2,2 0 0 0 -2,-2 l -6,0 a 2,2 0 0 0 -2,2 z" />
<path id="popup-icon" d="m 2,24 a 4,4 0 0 0 4,4 l 8,0 a 10,10 0 0 1 -2,-4 l -4,0 a 2,2 0 0 1 -2,-2 l 0,-12 18,0 0,2 a 10,10 0 0 1 4,2 l 0,-8 a 4,4 0 0 0 -4,-4 l -18,0 a 4,4 0 0 0 -4,4 z m 12,-2.1 a 8,8 0 1 1 0,0.2 m 10.7,-4.3 a 5,5 0 0 0 -6.9,6.9 z m -5.4,8.4 a 5,5 0 0 0 6.9,-6.9 z" />
<path id="screen-icon" d="m 2,18 a 2,2 0 0 0 2,2 l 2,0 0,-6 a 4,4 0 0 1 4,-4 l 14,0 0,-6 a 2,2 0 0 0 -2,-2 l -18,0 a 2,2 0 0 0 -2,2 z m 6,10 a 2,2 0 0 0 2,2 l 18,0 a 2,2 0 0 0 2,-2 l 0,-14 a 2,2 0 0 0 -2,-2 l -18,0 a 2,2 0 0 0 -2,2 z" />
@ -111,6 +112,8 @@
<use id="microphone-indicator" xlink:href="#microphone-icon"/>
<use id="microphone-blocked" class="blocked" xlink:href="#microphone-icon" />
<use id="microphone-detailed" xlink:href="#microphone-detailed-icon" />
<use id="persistent-storage" xlink:href="#persistent-storage-icon" />
<use id="persistent-storage-blocked" class="blocked" xlink:href="#persistent-storage-icon" />
<use id="plugin" xlink:href="#plugin-icon" />
<use id="plugin-blocked" class="blocked" xlink:href="#plugin-icon" />
<use id="popup" xlink:href="#popup-icon" />

До

Ширина:  |  Высота:  |  Размер: 7.8 KiB

После

Ширина:  |  Высота:  |  Размер: 8.2 KiB

Просмотреть файл

@ -2074,8 +2074,18 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
font-weight: bold;
}
.addon-webext-perm-header {
font-size: 1.3em;
html|*.addon-webext-perm-list {
margin-block-end: 0;
padding-inline-start: 10px;
}
.addon-webext-perm-text {
margin-inline-start: 0;
}
.popup-notification-description[popupid="addon-webext-permissions"] {
margin: 0;
padding: 0;
}
.addon-webext-name {

Просмотреть файл

@ -1,4 +1,3 @@
altgraph.pth:python/altgraph
marionette_driver.pth:testing/marionette/client
marionette_harness.pth:testing/marionette/harness
browsermobproxy.pth:testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py
@ -16,7 +15,6 @@ optional:setup.py:python/psutil:build_ext:--inplace
optional:psutil.pth:python/psutil
which.pth:python/which
ply.pth:other-licenses/ply/
macholib.pth:python/macholib
mock.pth:python/mock-1.0.0
py.pth:python/py
pytest.pth:python/pytest
@ -32,7 +30,6 @@ objdir:build
gyp.pth:media/webrtc/trunk/tools/gyp/pylib
pyasn1.pth:python/pyasn1
pyasn1_modules.pth:python/pyasn1-modules
bitstring.pth:python/bitstring
redo.pth:python/redo
requests.pth:python/requests
rsa.pth:python/rsa

Просмотреть файл

@ -214,3 +214,78 @@ button {
.error-page .error-page-details {
color: gray;
}
.addon-target-container {
background: #fff;
box-shadow: 0 0 1px rgba(0, 0, 0, 0.12);
list-style-type: none;
margin: 0 0 8px;
padding: 4px 16px;
transition: box-shadow 150ms;
}
.addon-target-container:hover {
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.24);
}
.addon-target-container .target {
align-items: center;
display: flex;
margin: 0;
padding: 16px 0;
}
.addon-target-actions {
border-top: 1px solid rgba(0, 0, 0, 0.2);
}
.addon-target-container .target-icon {
margin-inline-end: 16px;
}
.addon-target-container .name {
align-self: center;
font-size: 16px;
font-weight: 600;
}
.addon-target-button {
background: none;
border: none;
color: #0087ff;
font-size: 14px;
margin: 12px;
min-width: auto;
padding: 4px;
transition: color 150ms;
}
.addon-target-button:active,
.addon-target-button:hover,
.addon-target-button:enabled:hover:active {
background: none;
}
.addon-target-button:disabled {
color: #999;
opacity: 1;
}
.addon-target-button:enabled:focus,
.addon-target-button:enabled:hover {
background: none;
color: #0052cc;
cursor: pointer;
text-decoration: underline;
}
.addon-target-button:enabled:hover:active {
color: #003399;
text-decoration: none;
}
.addon-target-button:first-of-type {
/* Subtract the start padding so the button is still a bigger click target but
* lines up with the icon. */
margin-inline-start: -4px;
}

Просмотреть файл

@ -59,27 +59,29 @@ module.exports = createClass({
const canBeReloaded = target.temporarilyInstalled;
return dom.li(
{ className: "target-container", "data-addon-id": target.addonID },
dom.img({
className: "target-icon",
role: "presentation",
src: target.icon
}),
{ className: "addon-target-container", "data-addon-id": target.addonID },
dom.div({ className: "target" },
dom.div({ className: "target-name", title: target.name }, target.name)
dom.img({
className: "target-icon",
role: "presentation",
src: target.icon
}),
dom.span({ className: "target-name", title: target.name }, target.name)
),
dom.div({className: "addon-target-actions"},
dom.button({
className: "debug-button addon-target-button",
onClick: this.debug,
disabled: debugDisabled,
}, Strings.GetStringFromName("debug")),
dom.button({
className: "reload-button addon-target-button",
onClick: this.reload,
disabled: !canBeReloaded,
title: !canBeReloaded ?
Strings.GetStringFromName("reloadDisabledTooltip") : ""
}, Strings.GetStringFromName("reload"))
),
dom.button({
className: "debug-button",
onClick: this.debug,
disabled: debugDisabled,
}, Strings.GetStringFromName("debug")),
dom.button({
className: "reload-button",
onClick: this.reload,
disabled: !canBeReloaded,
title: !canBeReloaded ?
Strings.GetStringFromName("reloadDisabledTooltip") : ""
}, Strings.GetStringFromName("reload"))
);
}
});

Просмотреть файл

@ -7,8 +7,7 @@
const Services = require("Services");
const { Curl } = require("devtools/client/shared/curl");
const { gDevTools } = require("devtools/client/framework/devtools");
const Menu = require("devtools/client/framework/menu");
const MenuItem = require("devtools/client/framework/menu-item");
const { showMenu } = require("devtools/client/netmonitor/src/utils/menu");
const FileSaver = require("devtools/client/shared/file-saver");
const clipboardHelper = require("devtools/shared/platform/clipboard");
const { HarExporter } = require("./har/har-exporter");
@ -48,66 +47,65 @@ RequestListContextMenu.prototype = {
* Since visible attribute only accept boolean value but the method call may
* return undefined, we use !! to force convert any object to boolean
*/
open({ screenX = 0, screenY = 0 } = {}) {
open(event = {}) {
let selectedRequest = this.selectedRequest;
let menu = [];
let copySubmenu = [];
let menu = new Menu();
let copySubmenu = new Menu();
copySubmenu.append(new MenuItem({
copySubmenu.push({
id: "request-list-context-copy-url",
label: L10N.getStr("netmonitor.context.copyUrl"),
accesskey: L10N.getStr("netmonitor.context.copyUrl.accesskey"),
visible: !!selectedRequest,
click: () => this.copyUrl(),
}));
});
copySubmenu.append(new MenuItem({
copySubmenu.push({
id: "request-list-context-copy-url-params",
label: L10N.getStr("netmonitor.context.copyUrlParams"),
accesskey: L10N.getStr("netmonitor.context.copyUrlParams.accesskey"),
visible: !!(selectedRequest && getUrlQuery(selectedRequest.url)),
click: () => this.copyUrlParams(),
}));
});
copySubmenu.append(new MenuItem({
copySubmenu.push({
id: "request-list-context-copy-post-data",
label: L10N.getStr("netmonitor.context.copyPostData"),
accesskey: L10N.getStr("netmonitor.context.copyPostData.accesskey"),
visible: !!(selectedRequest && selectedRequest.requestPostData),
click: () => this.copyPostData(),
}));
});
copySubmenu.append(new MenuItem({
copySubmenu.push({
id: "request-list-context-copy-as-curl",
label: L10N.getStr("netmonitor.context.copyAsCurl"),
accesskey: L10N.getStr("netmonitor.context.copyAsCurl.accesskey"),
visible: !!selectedRequest,
click: () => this.copyAsCurl(),
}));
});
copySubmenu.append(new MenuItem({
copySubmenu.push({
type: "separator",
visible: !!selectedRequest,
}));
});
copySubmenu.append(new MenuItem({
copySubmenu.push({
id: "request-list-context-copy-request-headers",
label: L10N.getStr("netmonitor.context.copyRequestHeaders"),
accesskey: L10N.getStr("netmonitor.context.copyRequestHeaders.accesskey"),
visible: !!(selectedRequest && selectedRequest.requestHeaders),
click: () => this.copyRequestHeaders(),
}));
});
copySubmenu.append(new MenuItem({
copySubmenu.push({
id: "response-list-context-copy-response-headers",
label: L10N.getStr("netmonitor.context.copyResponseHeaders"),
accesskey: L10N.getStr("netmonitor.context.copyResponseHeaders.accesskey"),
visible: !!(selectedRequest && selectedRequest.responseHeaders),
click: () => this.copyResponseHeaders(),
}));
});
copySubmenu.append(new MenuItem({
copySubmenu.push({
id: "request-list-context-copy-response",
label: L10N.getStr("netmonitor.context.copyResponse"),
accesskey: L10N.getStr("netmonitor.context.copyResponse.accesskey"),
@ -116,9 +114,9 @@ RequestListContextMenu.prototype = {
selectedRequest.responseContent.content.text &&
selectedRequest.responseContent.content.text.length !== 0),
click: () => this.copyResponse(),
}));
});
copySubmenu.append(new MenuItem({
copySubmenu.push({
id: "request-list-context-copy-image-as-data-uri",
label: L10N.getStr("netmonitor.context.copyImageAsDataUri"),
accesskey: L10N.getStr("netmonitor.context.copyImageAsDataUri.accesskey"),
@ -126,37 +124,37 @@ RequestListContextMenu.prototype = {
selectedRequest.responseContent &&
selectedRequest.responseContent.content.mimeType.includes("image/")),
click: () => this.copyImageAsDataUri(),
}));
});
copySubmenu.append(new MenuItem({
copySubmenu.push({
type: "separator",
visible: !!selectedRequest,
}));
});
copySubmenu.append(new MenuItem({
copySubmenu.push({
id: "request-list-context-copy-all-as-har",
label: L10N.getStr("netmonitor.context.copyAllAsHar"),
accesskey: L10N.getStr("netmonitor.context.copyAllAsHar.accesskey"),
visible: this.sortedRequests.size > 0,
click: () => this.copyAllAsHar(),
}));
});
menu.append(new MenuItem({
menu.push({
label: L10N.getStr("netmonitor.context.copy"),
accesskey: L10N.getStr("netmonitor.context.copy.accesskey"),
visible: !!selectedRequest,
submenu: copySubmenu,
}));
});
menu.append(new MenuItem({
menu.push({
id: "request-list-context-save-all-as-har",
label: L10N.getStr("netmonitor.context.saveAllAsHar"),
accesskey: L10N.getStr("netmonitor.context.saveAllAsHar.accesskey"),
visible: this.sortedRequests.size > 0,
click: () => this.saveAllAsHar(),
}));
});
menu.append(new MenuItem({
menu.push({
id: "request-list-context-save-image-as",
label: L10N.getStr("netmonitor.context.saveImageAs"),
accesskey: L10N.getStr("netmonitor.context.saveImageAs.accesskey"),
@ -164,46 +162,44 @@ RequestListContextMenu.prototype = {
selectedRequest.responseContent &&
selectedRequest.responseContent.content.mimeType.includes("image/")),
click: () => this.saveImageAs(),
}));
});
menu.append(new MenuItem({
menu.push({
type: "separator",
visible: !!(NetMonitorController.supportsCustomRequest &&
selectedRequest && !selectedRequest.isCustom),
}));
});
menu.append(new MenuItem({
menu.push({
id: "request-list-context-resend",
label: L10N.getStr("netmonitor.context.editAndResend"),
accesskey: L10N.getStr("netmonitor.context.editAndResend.accesskey"),
visible: !!(NetMonitorController.supportsCustomRequest &&
selectedRequest && !selectedRequest.isCustom),
click: this.cloneSelectedRequest,
}));
});
menu.append(new MenuItem({
menu.push({
type: "separator",
visible: !!selectedRequest,
}));
});
menu.append(new MenuItem({
menu.push({
id: "request-list-context-newtab",
label: L10N.getStr("netmonitor.context.newTab"),
accesskey: L10N.getStr("netmonitor.context.newTab.accesskey"),
visible: !!selectedRequest,
click: () => this.openRequestInTab()
}));
});
menu.append(new MenuItem({
menu.push({
id: "request-list-context-perf",
label: L10N.getStr("netmonitor.context.perfTools"),
accesskey: L10N.getStr("netmonitor.context.perfTools.accesskey"),
visible: !!NetMonitorController.supportsPerfStats,
click: () => this.openStatistics(true)
}));
});
menu.popup(screenX, screenY, { doc: window.parent.document });
return menu;
return showMenu(event, menu);
},
/**

Просмотреть файл

@ -4,8 +4,7 @@
"use strict";
const Menu = require("devtools/client/framework/menu");
const MenuItem = require("devtools/client/framework/menu-item");
const { showMenu } = require("devtools/client/netmonitor/src/utils/menu");
const { HEADERS } = require("./constants");
const { L10N } = require("./utils/l10n");
@ -30,12 +29,12 @@ class RequestListHeaderContextMenu {
/**
* Handle the context menu opening.
*/
open({ screenX = 0, screenY = 0 } = {}) {
let menu = new Menu();
open(event = {}) {
let menu = [];
let onlyOneColumn = this.visibleColumns.length === 1;
for (let [column, shown] of this.columns) {
menu.append(new MenuItem({
menu.push({
id: `request-list-header-${column}-toggle`,
label: L10N.getStr(`netmonitor.toolbar.${stringMap[column] || column}`),
type: "checkbox",
@ -43,19 +42,18 @@ class RequestListHeaderContextMenu {
click: () => this.toggleColumn(column),
// We don't want to allow hiding the last visible column
disabled: onlyOneColumn && shown,
}));
});
}
menu.append(new MenuItem({ type: "separator" }));
menu.push({ type: "separator" });
menu.append(new MenuItem({
menu.push({
id: "request-list-header-reset-columns",
label: L10N.getStr("netmonitor.toolbar.resetColumns"),
click: () => this.resetColumns(),
}));
});
menu.popup(screenX, screenY, { doc: window.parent.document });
return menu;
return showMenu(event, menu);
}
}

Просмотреть файл

@ -0,0 +1,36 @@
/* 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";
const Menu = require("devtools/client/framework/menu");
const MenuItem = require("devtools/client/framework/menu-item");
function showMenu(evt, items) {
if (items.length === 0) {
return;
}
let menu = new Menu();
items.forEach((item) => {
let menuItem = new MenuItem(item);
let subItems = item.submenu;
if (subItems) {
let subMenu = new Menu();
subItems.forEach((subItem) => {
subMenu.append(new MenuItem(subItem));
});
menuItem.submenu = subMenu;
}
menu.append(menuItem);
});
menu.popup(evt.screenX, evt.screenY, { doc: window.parent.document });
}
module.exports = {
showMenu,
};

Просмотреть файл

@ -11,6 +11,7 @@ DevToolsModules(
'format-utils.js',
'l10n.js',
'mdn-utils.js',
'menu.js',
'prefs.js',
'request-utils.js',
'sort-predicates.js',

Просмотреть файл

@ -53,6 +53,7 @@ let webpackConfig = {
"devtools/client/framework/menu": "devtools-modules/client/framework/menu",
"devtools/client/framework/menu-item": "devtools-modules/client/framework/menu-item",
"devtools/client/locales": path.join(__dirname, "../locales/en-US"),
"devtools/client/netmonitor/src/utils/menu": "devtools-launchpad/src/components/shared/menu",
"devtools/client/shared/components/reps/reps": "devtools-reps",
"devtools/client/shared/components/search-box": "devtools-modules/client/shared/components/search-box",
"devtools/client/shared/components/splitter/split-box": "devtools-splitter",

Просмотреть файл

@ -11,7 +11,7 @@ var gGroundTruthImageData;
function prepareSources() {
gVideo = document.createElement("video");
gVideo.src = "http://example.com/tests/dom/canvas/test/crossorigin/video.sjs?name=tests/dom/media/test/320x240.ogv&type=video/ogg&cors=anonymous";
gVideo.src = "http://example.com/tests/dom/canvas/test/crossorigin/video.sjs?name=tests/dom/canvas/test/320x240.ogv&type=video/ogg&cors=anonymous";
gVideo.crossOrigin = "anonymous";
gVideo.autoplay = "true"

Просмотреть файл

@ -39,6 +39,9 @@ support-files =
offscreencanvas_mask.svg
offscreencanvas_neuter.js
offscreencanvas_serviceworker_inner.html
crossorigin/image.png
crossorigin/video.sjs
../../media/test/320x240.ogv
[test_2d.clearRect.image.offscreen.html]
[test_2d.clip.winding.html]

Просмотреть файл

@ -6,7 +6,7 @@
<body>
<img src="image_anim-gr.gif" id="image" class="resource">
<video width="320" height="240" src="http://example.com/tests/dom/canvas/test/crossorigin/video.sjs?name=tests/dom/media/test/320x240.ogv&type=video/ogg&cors=anonymous" id="video" crossOrigin="anonymous" autoplay></video>
<video width="320" height="240" src="http://example.com/tests/dom/canvas/test/crossorigin/video.sjs?name=tests/dom/canvas/test/320x240.ogv&type=video/ogg&cors=anonymous" id="video" crossOrigin="anonymous" autoplay></video>
<canvas id="c1" class="output" width="128" height="128"></canvas>
<canvas id="c2" width="128" height="128"></canvas>
@ -226,7 +226,7 @@ function testSecurityErrors() {
reject();
}
uncleanVideo.src = "http://example.com/tests/dom/canvas/test/crossorigin/video.sjs?name=tests/dom/media/test/320x240.ogv&type=video/ogg";
uncleanVideo.src = "http://example.com/tests/dom/canvas/test/crossorigin/video.sjs?name=tests/dom/canvas/test/320x240.ogv&type=video/ogg";
uncleanVideo.play();
});
}

Просмотреть файл

@ -135,7 +135,7 @@ var gJPEGBlob;
function prepareSources() {
gVideo = document.createElement("video");
gVideo.src = "http://example.com/tests/dom/canvas/test/crossorigin/video.sjs?name=tests/dom/media/test/320x240.ogv&type=video/ogg&cors=anonymous";
gVideo.src = "http://example.com/tests/dom/canvas/test/crossorigin/video.sjs?name=tests/dom/canvas/test/320x240.ogv&type=video/ogg&cors=anonymous";
gVideo.crossOrigin = "anonymous";
gVideo.autoplay = "true"

Просмотреть файл

@ -44,7 +44,7 @@ fails == 596455-2b.html 596455-2b.html
# (Fuzzy necessary due to pixel-wise comparison of different JPEGs.
# The vast majority of the fuzziness comes from Linux and WinXP.)
== bug917595-iframe-1.html bug917595-iframe-1.html
fails == bug917595-exif-rotated.jpg bug917595-exif-rotated.jpg
== bug917595-exif-rotated.jpg bug917595-exif-rotated.jpg
# Test support for SVG-as-image in <picture> elements.
== bug1106522-1.html bug1106522-1.html

Просмотреть файл

@ -30,6 +30,7 @@ VRMockDisplay::VRMockDisplay(const nsCString& aID, uint32_t aDeviceID)
: mDeviceID(aDeviceID)
, mTimestamp(TimeStamp::Now())
{
mSensorState.Clear();
mDisplayInfo.mDisplayName = aID;
mDisplayInfo.mType = VRDeviceType::Puppet;
mDisplayInfo.mIsConnected = true;

Просмотреть файл

@ -27,6 +27,7 @@ public:
void SetPose(const Nullable<Float32Array>& aPosition, const Nullable<Float32Array>& aLinearVelocity,
const Nullable<Float32Array>& aLinearAcceleration, const Nullable<Float32Array>& aOrientation,
const Nullable<Float32Array>& aAngularVelocity, const Nullable<Float32Array>& aAngularAcceleration);
void SetMountState(bool aIsMounted) { mDisplayInfo.mIsMounted = aIsMounted; }
void Update();
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
@ -84,4 +85,4 @@ private:
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_VRServiceTest_h_
#endif // mozilla_dom_VRServiceTest_h_

Просмотреть файл

@ -33,6 +33,10 @@ var SetEyeParameter = function(eye, offsetX, offsetY, offsetZ,
downDegree, leftDegree);
}
var SetMountState = function(isMounted) {
vrMockDisplay.setMountState(isMounted);
}
var UpdateVRDisplay = function() {
vrMockDisplay.update();
}
@ -42,6 +46,7 @@ var API = {
SetVRDisplayPose: SetVRDisplayPose,
SetEyeResolution: SetEyeResolution,
SetEyeParameter: SetEyeParameter,
SetMountState: SetMountState,
UpdateVRDisplay: UpdateVRDisplay,
none: false

Просмотреть файл

@ -5,7 +5,9 @@ support-files =
runVRTest.js
WebVRHelpers.js
[test_vrDisplay_getFrameData.html]
[test_vrDisplay_exitPresent.html]
[test_vrDisplay_getFrameData.html]
[test_vrDisplay_onvrdisplaydeactivate_crosscontent.html]
skip-if = true
[test_vrDisplay_requestPresent.html]
skip-if = true
skip-if = true

Просмотреть файл

@ -0,0 +1,54 @@
<html>
<head>
<title>VRDisplay onvrdisplaydeactivate Crosscontent test</title>
<meta name="timeout" content="long"/>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="VRSimulationDriver.js"></script>
<script src="WebVRHelpers.js"></script>
<script src="requestPresent.js"></script>
<script src="runVRTest.js"></script>
</head>
<body>
<canvas id="vrCanvas"></canvas>
<script>
function startTest() {
var canvas = document.getElementById("vrCanvas");
var iframe1 = document.getElementById("iframe1").contentWindow;
var t = async_test("vrdisplaydeactivate crosscontent test");
window.addEventListener("vrdisplaydeactivate", () => {
t.step(() => {
assert_true(vrDisplay.isPresenting,
"VRDisplay should be still presenting now without being affected by the event.");
t.done();
});
});
iframe1.addEventListener("vrdisplaydeactivate", () => {
t.unreached_func("vrdisplaydeactivate should not be received by other iframe.");
});
promise_test((test) => {
return attachVRDisplay(test).then(() => {
return promise_test((test) => {
return setupVRDisplay(test).then(() => {
VRSimulationDriver.SetMountState(true);
VRSimulationDriver.UpdateVRDisplay();
return WebVRHelpers.RequestPresentOnVRDisplay(vrDisplay, [{source: canvas}]);
}).then(() => {
VRSimulationDriver.SetMountState(false);
VRSimulationDriver.UpdateVRDisplay();
});
});
});
});
}
runVRTest(startTest);
</script>
<iframe id="iframe1"></iframe>
</body>
</html>

Просмотреть файл

@ -15,6 +15,7 @@ interface VRMockDisplay {
void setPose(Float32Array? position, Float32Array? linearVelocity,
Float32Array? linearAcceleration, Float32Array? orientation,
Float32Array? angularVelocity, Float32Array? angularAcceleration);
void setMountState(boolean isMounted);
void update();
};

Просмотреть файл

@ -717,13 +717,12 @@ nsEditorSpellCheck::UpdateCurrentDictionary(nsIEditorSpellCheckCallback* aCallba
// Helper function that iterates over the list of dictionaries and sets the one
// that matches based on a given comparison type.
nsresult
nsEditorSpellCheck::TryDictionary(const nsAString& aDictName,
nsTArray<nsString>& aDictList,
enum dictCompare aCompareType)
void
nsEditorSpellCheck::BuildDictionaryList(const nsAString& aDictName,
const nsTArray<nsString>& aDictList,
enum dictCompare aCompareType,
nsTArray<nsString>& aOutList)
{
nsresult rv = NS_ERROR_NOT_AVAILABLE;
for (uint32_t i = 0; i < aDictList.Length(); i++) {
nsAutoString dictStr(aDictList.ElementAt(i));
bool equals = false;
@ -739,18 +738,18 @@ nsEditorSpellCheck::TryDictionary(const nsAString& aDictName,
break;
}
if (equals) {
rv = mSpellChecker->SetCurrentDictionary(dictStr);
aOutList.AppendElement(dictStr);
#ifdef DEBUG_DICT
if (NS_SUCCEEDED(rv))
printf("***** Set |%s|.\n", NS_ConvertUTF16toUTF8(dictStr).get());
if (NS_SUCCEEDED(rv)) {
printf("***** Trying |%s|.\n", NS_ConvertUTF16toUTF8(dictStr).get());
}
#endif
// We always break here. We tried to set the dictionary to an existing
// dictionary from the list. This must work, if it doesn't, there is
// no point trying another one.
break;
return;
}
}
return rv;
}
nsresult
@ -759,14 +758,13 @@ nsEditorSpellCheck::DictionaryFetched(DictionaryFetcher* aFetcher)
MOZ_ASSERT(aFetcher);
RefPtr<nsEditorSpellCheck> kungFuDeathGrip = this;
// Important: declare the holder after the callback caller so that the former
// is destructed first so that it's not active when the callback is called.
CallbackCaller callbackCaller(aFetcher->mCallback);
UpdateDictionaryHolder holder(this);
BeginUpdateDictionary();
if (aFetcher->mGroup < mDictionaryFetcherGroup) {
// SetCurrentDictionary was called after the fetch started. Don't overwrite
// that dictionary with the fetched one.
EndUpdateDictionary();
aFetcher->mCallback->EditorSpellCheckDone();
return NS_OK;
}
@ -810,13 +808,14 @@ nsEditorSpellCheck::DictionaryFetched(DictionaryFetcher* aFetcher)
#endif
}
// Auxiliary status.
nsresult rv2;
// We obtain a list of available dictionaries.
nsTArray<nsString> dictList;
rv2 = mSpellChecker->GetDictionaryList(&dictList);
NS_ENSURE_SUCCESS(rv2, rv2);
AutoTArray<nsString, 8> dictList;
nsresult rv = mSpellChecker->GetDictionaryList(&dictList);
if (NS_WARN_IF(NS_FAILED(rv))) {
EndUpdateDictionary();
aFetcher->mCallback->EditorSpellCheckDone();
return rv;
}
// Priority 1:
// If we successfully fetched a dictionary from content prefs, do not go
@ -828,27 +827,61 @@ nsEditorSpellCheck::DictionaryFetched(DictionaryFetcher* aFetcher)
if (!(flags & nsIPlaintextEditor::eEditorMailMask)) {
dictName.Assign(aFetcher->mDictionary);
if (!dictName.IsEmpty()) {
if (NS_SUCCEEDED(TryDictionary(dictName, dictList, DICT_NORMAL_COMPARE))) {
#ifdef DEBUG_DICT
printf("***** Assigned from content preferences |%s|\n",
NS_ConvertUTF16toUTF8(dictName).get());
#endif
AutoTArray<nsString, 1> tryDictList;
BuildDictionaryList(dictName, dictList, DICT_NORMAL_COMPARE, tryDictList);
// We take an early exit here, so let's not forget to clear the word
// list.
DeleteSuggestedWordList();
return NS_OK;
}
// May be dictionary was uninstalled ?
// Clear the content preference and continue.
ClearCurrentDictionary(mEditor);
RefPtr<nsEditorSpellCheck> self = this;
RefPtr<DictionaryFetcher> fetcher = aFetcher;
mSpellChecker->SetCurrentDictionaryFromList(tryDictList)->Then(
AbstractThread::MainThread(),
__func__,
[self, fetcher]() {
#ifdef DEBUG_DICT
printf("***** Assigned from content preferences |%s|\n",
NS_ConvertUTF16toUTF8(dictName).get());
#endif
// We take an early exit here, so let's not forget to clear the word
// list.
self->DeleteSuggestedWordList();
self->EndUpdateDictionary();
fetcher->mCallback->EditorSpellCheckDone();
},
[self, fetcher]() {
// May be dictionary was uninstalled ?
// Clear the content preference and continue.
ClearCurrentDictionary(self->mEditor);
// Priority 2 or later will handled by the following
self->SetFallbackDictionary(fetcher);
});
return NS_OK;
}
}
SetFallbackDictionary(aFetcher);
return NS_OK;
}
void
nsEditorSpellCheck::SetFallbackDictionary(DictionaryFetcher* aFetcher)
{
MOZ_ASSERT(mUpdateDictionaryRunning);
AutoTArray<nsString, 6> tryDictList;
// We obtain a list of available dictionaries.
AutoTArray<nsString, 8> dictList;
nsresult rv = mSpellChecker->GetDictionaryList(&dictList);
if (NS_WARN_IF(NS_FAILED(rv))) {
EndUpdateDictionary();
aFetcher->mCallback->EditorSpellCheckDone();
return;
}
// Priority 2:
// After checking the content preferences, we use the language of the element
// or document.
dictName.Assign(mPreferredLang);
nsAutoString dictName(mPreferredLang);
#ifdef DEBUG_DICT
printf("***** Assigned from element/doc |%s|\n",
NS_ConvertUTF16toUTF8(dictName).get());
@ -858,144 +891,134 @@ nsEditorSpellCheck::DictionaryFetched(DictionaryFetcher* aFetcher)
nsAutoString preferredDict;
preferredDict = Preferences::GetLocalizedString("spellchecker.dictionary");
// The following will be driven by this status. Once we were able to set a
// dictionary successfully, we're done. So we start with a "failed" status.
nsresult rv = NS_ERROR_NOT_AVAILABLE;
if (!dictName.IsEmpty()) {
// RFC 5646 explicitly states that matches should be case-insensitive.
rv = TryDictionary (dictName, dictList, DICT_COMPARE_CASE_INSENSITIVE);
BuildDictionaryList(dictName, dictList, DICT_COMPARE_CASE_INSENSITIVE,
tryDictList);
if (NS_FAILED(rv)) {
#ifdef DEBUG_DICT
printf("***** Setting of |%s| failed (or it wasn't available)\n",
NS_ConvertUTF16toUTF8(dictName).get());
printf("***** Trying from element/doc |%s| \n",
NS_ConvertUTF16toUTF8(dictName).get());
#endif
// Required dictionary was not available. Try to get a dictionary
// matching at least language part of dictName.
nsAutoString langCode;
int32_t dashIdx = dictName.FindChar('-');
if (dashIdx != -1) {
langCode.Assign(Substring(dictName, 0, dashIdx));
} else {
langCode.Assign(dictName);
}
// Try dictionary.spellchecker preference, if it starts with langCode,
// so we don't just get any random dictionary matching the language.
if (!preferredDict.IsEmpty() &&
nsStyleUtil::DashMatchCompare(preferredDict, langCode, nsDefaultStringComparator())) {
#ifdef DEBUG_DICT
printf("***** Trying preference value |%s| since it matches language code\n",
NS_ConvertUTF16toUTF8(preferredDict).get());
#endif
rv = TryDictionary (preferredDict, dictList,
DICT_COMPARE_CASE_INSENSITIVE);
}
if (NS_FAILED(rv)) {
// Use any dictionary with the required language.
#ifdef DEBUG_DICT
printf("***** Trying to find match for language code |%s|\n",
NS_ConvertUTF16toUTF8(langCode).get());
#endif
rv = TryDictionary (langCode, dictList, DICT_COMPARE_DASHMATCH);
}
// Required dictionary was not available. Try to get a dictionary
// matching at least language part of dictName.
nsAutoString langCode;
int32_t dashIdx = dictName.FindChar('-');
if (dashIdx != -1) {
langCode.Assign(Substring(dictName, 0, dashIdx));
} else {
langCode.Assign(dictName);
}
// Try dictionary.spellchecker preference, if it starts with langCode,
// so we don't just get any random dictionary matching the language.
if (!preferredDict.IsEmpty() &&
nsStyleUtil::DashMatchCompare(preferredDict, langCode, nsDefaultStringComparator())) {
#ifdef DEBUG_DICT
printf("***** Trying preference value |%s| since it matches language code\n",
NS_ConvertUTF16toUTF8(preferredDict).get());
#endif
BuildDictionaryList(preferredDict, dictList,
DICT_COMPARE_CASE_INSENSITIVE, tryDictList);
}
// Use any dictionary with the required language.
#ifdef DEBUG_DICT
printf("***** Trying to find match for language code |%s|\n",
NS_ConvertUTF16toUTF8(langCode).get());
#endif
BuildDictionaryList(langCode, dictList, DICT_COMPARE_DASHMATCH,
tryDictList);
}
// Priority 3:
// If the document didn't supply a dictionary or the setting failed,
// try the user preference next.
if (NS_FAILED(rv)) {
if (!preferredDict.IsEmpty()) {
if (!preferredDict.IsEmpty()) {
#ifdef DEBUG_DICT
printf("***** Trying preference value |%s|\n",
NS_ConvertUTF16toUTF8(preferredDict).get());
printf("***** Trying preference value |%s|\n",
NS_ConvertUTF16toUTF8(preferredDict).get());
#endif
rv = TryDictionary (preferredDict, dictList, DICT_NORMAL_COMPARE);
}
BuildDictionaryList(preferredDict, dictList, DICT_NORMAL_COMPARE,
tryDictList);
}
// Priority 4:
// As next fallback, try the current locale.
if (NS_FAILED(rv)) {
nsAutoCString utf8DictName;
LocaleService::GetInstance()->GetAppLocaleAsLangTag(utf8DictName);
nsAutoCString utf8DictName;
LocaleService::GetInstance()->GetAppLocaleAsLangTag(utf8DictName);
dictName.Assign(EmptyString());
AppendUTF8toUTF16(utf8DictName, dictName);
CopyUTF8toUTF16(utf8DictName, dictName);
#ifdef DEBUG_DICT
printf("***** Trying locale |%s|\n",
NS_ConvertUTF16toUTF8(dictName).get());
printf("***** Trying locale |%s|\n",
NS_ConvertUTF16toUTF8(dictName).get());
#endif
rv = TryDictionary (dictName, dictList, DICT_COMPARE_CASE_INSENSITIVE);
}
if (NS_FAILED(rv)) {
// Still no success.
BuildDictionaryList(dictName, dictList, DICT_COMPARE_CASE_INSENSITIVE,
tryDictList);
// Priority 5:
// If we have a current dictionary, don't try anything else.
nsAutoString currentDictionary;
rv2 = GetCurrentDictionary(currentDictionary);
// If we have a current dictionary and we don't have no item in try list,
// don't try anything else.
nsAutoString currentDictionary;
GetCurrentDictionary(currentDictionary);
if (!currentDictionary.IsEmpty() && tryDictList.IsEmpty()) {
#ifdef DEBUG_DICT
if (NS_SUCCEEDED(rv2)) {
printf("***** Retrieved current dict |%s|\n",
NS_ConvertUTF16toUTF8(currentDictionary).get());
printf("***** Retrieved current dict |%s|\n",
NS_ConvertUTF16toUTF8(currentDictionary).get());
#endif
EndUpdateDictionary();
aFetcher->mCallback->EditorSpellCheckDone();
return;
}
// Priority 6:
// Try to get current dictionary from environment variable LANG.
// LANG = language[_territory][.charset]
char* env_lang = getenv("LANG");
if (env_lang) {
nsString lang = NS_ConvertUTF8toUTF16(env_lang);
// Strip trailing charset, if there is any.
int32_t dot_pos = lang.FindChar('.');
if (dot_pos != -1) {
lang = Substring(lang, 0, dot_pos);
}
#endif
if (NS_FAILED(rv2) || currentDictionary.IsEmpty()) {
// Priority 6:
// Try to get current dictionary from environment variable LANG.
// LANG = language[_territory][.charset]
char* env_lang = getenv("LANG");
if (env_lang) {
nsString lang = NS_ConvertUTF8toUTF16(env_lang);
// Strip trailing charset, if there is any.
int32_t dot_pos = lang.FindChar('.');
if (dot_pos != -1) {
lang = Substring(lang, 0, dot_pos);
}
int32_t underScore = lang.FindChar('_');
if (underScore != -1) {
lang.Replace(underScore, 1, '-');
int32_t underScore = lang.FindChar('_');
if (underScore != -1) {
lang.Replace(underScore, 1, '-');
#ifdef DEBUG_DICT
printf("***** Trying LANG from environment |%s|\n",
NS_ConvertUTF16toUTF8(lang).get());
printf("***** Trying LANG from environment |%s|\n",
NS_ConvertUTF16toUTF8(lang).get());
#endif
nsAutoString lang2;
lang2.Assign(lang);
rv = TryDictionary(lang2, dictList, DICT_COMPARE_CASE_INSENSITIVE);
}
}
// Priority 7:
// If it does not work, pick the first one.
if (NS_FAILED(rv) && !dictList.IsEmpty()) {
nsAutoString firstInList;
firstInList.Assign(dictList[0]);
rv = TryDictionary(firstInList, dictList, DICT_NORMAL_COMPARE);
#ifdef DEBUG_DICT
printf("***** Trying first of list |%s|\n",
NS_ConvertUTF16toUTF8(dictList[0]).get());
if (NS_SUCCEEDED(rv)) {
printf ("***** Setting worked.\n");
}
#endif
}
BuildDictionaryList(lang, dictList, DICT_COMPARE_CASE_INSENSITIVE,
tryDictList);
}
}
// If an error was thrown while setting the dictionary, just
// fail silently so that the spellchecker dialog is allowed to come
// up. The user can manually reset the language to their choice on
// the dialog if it is wrong.
// Priority 7:
// If it does not work, pick the first one.
if (!dictList.IsEmpty()) {
BuildDictionaryList(dictList[0], dictList, DICT_NORMAL_COMPARE,
tryDictList);
#ifdef DEBUG_DICT
printf("***** Trying first of list |%s|\n",
NS_ConvertUTF16toUTF8(dictList[0]).get());
#endif
}
DeleteSuggestedWordList();
return NS_OK;
RefPtr<nsEditorSpellCheck> self = this;
RefPtr<DictionaryFetcher> fetcher = aFetcher;
mSpellChecker->SetCurrentDictionaryFromList(tryDictList)->Then(
AbstractThread::MainThread(),
__func__,
[self, fetcher]() {
// If an error was thrown while setting the dictionary, just
// fail silently so that the spellchecker dialog is allowed to come
// up. The user can manually reset the language to their choice on
// the dialog if it is wrong.
self->DeleteSuggestedWordList();
self->EndUpdateDictionary();
fetcher->mCallback->EditorSpellCheckDone();
});
}

Просмотреть файл

@ -70,11 +70,16 @@ protected:
bool mUpdateDictionaryRunning;
nsresult TryDictionary(const nsAString& aDictName, nsTArray<nsString>& aDictList,
enum dictCompare aCompareType);
void BuildDictionaryList(const nsAString& aDictName,
const nsTArray<nsString>& aDictList,
enum dictCompare aCompareType,
nsTArray<nsString>& aTryList);
nsresult DictionaryFetched(DictionaryFetcher* aFetchState);
void SetFallbackDictionary(DictionaryFetcher* aFetcher);
public:
void BeginUpdateDictionary() { mUpdateDictionaryRunning = true ;}
void EndUpdateDictionary() { mUpdateDictionaryRunning = false ;}

Просмотреть файл

@ -145,6 +145,7 @@ EditorBase::EditorBase()
, mDispatchInputEvent(true)
, mIsInEditAction(false)
, mHidingCaret(false)
, mSpellCheckerDictionaryUpdated(true)
{
}
@ -1344,6 +1345,11 @@ EditorBase::SyncRealTimeSpell()
GetInlineSpellChecker(enable, getter_AddRefs(spellChecker));
if (mInlineSpellChecker) {
if (!mSpellCheckerDictionaryUpdated && enable) {
mInlineSpellChecker->UpdateCurrentDictionary();
mSpellCheckerDictionaryUpdated = true;
}
// We might have a mInlineSpellChecker even if there are no dictionaries
// available since we don't destroy the mInlineSpellChecker when the last
// dictionariy is removed, but in that case spellChecker is null
@ -5215,8 +5221,10 @@ void
EditorBase::OnFocus(nsIDOMEventTarget* aFocusEventTarget)
{
InitializeSelection(aFocusEventTarget);
if (mInlineSpellChecker) {
mSpellCheckerDictionaryUpdated = false;
if (mInlineSpellChecker && CanEnableSpellCheck()) {
mInlineSpellChecker->UpdateCurrentDictionary();
mSpellCheckerDictionaryUpdated = true;
}
}

Просмотреть файл

@ -1082,6 +1082,8 @@ protected:
bool mIsInEditAction;
// Whether caret is hidden forcibly.
bool mHidingCaret;
// Whether spellchecker dictionary is initialized after focused.
bool mSpellCheckerDictionaryUpdated;
friend bool NSCanUnload(nsISupports* serviceMgr);
friend class AutoRules;

Просмотреть файл

@ -30,32 +30,40 @@ SimpleTest.waitForFocus(function() {
div.focus();
synthesizeMouseAtCenter(div, {});
synthesizeKey(" ", {});
setTimeout(function() {
synthesizeKey("a", {});
getSpellChecker().UpdateCurrentDictionary(() => {
synthesizeKey(" ", {});
setTimeout(function() {
synthesizeKey("VK_BACK_SPACE", {});
synthesizeKey("a", {});
setTimeout(function() {
synthesizeKey("VK_BACK_SPACE", {});
var sel = getSpellCheckSelection();
is(sel.rangeCount, 2, "We should have two misspelled words");
is(String(sel.getRangeAt(0)), "fivee", "Correct misspelled word");
is(String(sel.getRangeAt(1)), "sixx", "Correct misspelled word");
var sel = getSpellCheckSelection();
is(sel.rangeCount, 2, "We should have two misspelled words");
is(String(sel.getRangeAt(0)), "fivee", "Correct misspelled word");
is(String(sel.getRangeAt(1)), "sixx", "Correct misspelled word");
SimpleTest.finish();
SimpleTest.finish();
},0);
},0);
},0);
});
});
function getSpellCheckSelection() {
function getEditor() {
var Ci = SpecialPowers.Ci;
var editingSession = SpecialPowers.wrap(window)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIEditingSession);
var editor = editingSession.getEditorForWindow(window);
var selcon = editor.selectionController;
return editingSession.getEditorForWindow(window);
}
function getSpellChecker() {
return getEditor().getInlineSpellChecker(false).spellChecker;
}
function getSpellCheckSelection() {
var selcon = getEditor().selectionController;
return selcon.getSelection(selcon.SELECTION_SPELLCHECK);
}

Просмотреть файл

@ -27,37 +27,45 @@ SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(function() {
var div = document.getElementById("content");
div.focus();
synthesizeMouseAtCenter(div, {});
synthesizeKey("VK_LEFT", {});
synthesizeKey("VK_LEFT", {});
getSpellChecker().UpdateCurrentDictionary(() => {
synthesizeMouseAtCenter(div, {});
synthesizeKey("VK_LEFT", {});
synthesizeKey("VK_LEFT", {});
setTimeout(function() {
synthesizeKey("VK_BACK_SPACE", {});
setTimeout(function() {
synthesizeKey(" ", {});
synthesizeKey("VK_BACK_SPACE", {});
setTimeout(function() {
var sel = getSpellCheckSelection();
is(sel.rangeCount, 2, "We should have two misspelled words");
is(String(sel.getRangeAt(0)), "thiss", "Correct misspelled word");
is(String(sel.getRangeAt(1)), "onee", "Correct misspelled word");
synthesizeKey(" ", {});
SimpleTest.finish();
setTimeout(function() {
var sel = getSpellCheckSelection();
is(sel.rangeCount, 2, "We should have two misspelled words");
is(String(sel.getRangeAt(0)), "thiss", "Correct misspelled word");
is(String(sel.getRangeAt(1)), "onee", "Correct misspelled word");
SimpleTest.finish();
},0);
},0);
},0);
},0);
});
});
function getSpellCheckSelection() {
function getEditor() {
var Ci = SpecialPowers.Ci;
var editingSession = SpecialPowers.wrap(window)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIEditingSession);
var editor = editingSession.getEditorForWindow(window);
var selcon = editor.selectionController;
return editingSession.getEditorForWindow(window);
}
function getSpellChecker() {
return getEditor().getInlineSpellChecker(false).spellChecker;
}
function getSpellCheckSelection() {
var selcon = getEditor().selectionController;
return selcon.getSelection(selcon.SELECTION_SPELLCHECK);
}

Просмотреть файл

@ -6,6 +6,7 @@
#ifndef nsISpellChecker_h__
#define nsISpellChecker_h__
#include "mozilla/MozPromise.h"
#include "nsISupports.h"
#include "nsTArray.h"
@ -114,6 +115,13 @@ public:
* empty string, spellchecker will be disabled.
*/
NS_IMETHOD SetCurrentDictionary(const nsAString &aDictionary) = 0;
/**
* Tells the spellchecker to use a specific dictionary from list.
* @param aList a preferred dictionary list
*/
NS_IMETHOD_(RefPtr<mozilla::GenericPromise>)
SetCurrentDictionaryFromList(const nsTArray<nsString>& aList) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsISpellChecker, NS_ISPELLCHECKER_IID)

Просмотреть файл

@ -17,6 +17,11 @@ parent:
sync CheckAndSuggest(nsString aWord) returns (bool aIsMisspelled, nsString[] aSuggestions);
sync SetDictionary(nsString aDictionary) returns (bool success);
async SetDictionaryFromList(nsString[] aList, intptr_t aPromiseId);
child:
async NotifyOfCurrentDictionary(nsString aDictionary, intptr_t aPromiseId);
};
} // namespace mozilla

Просмотреть файл

@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/UniquePtr.h"
#include "RemoteSpellCheckEngineChild.h"
namespace mozilla {
@ -18,4 +19,37 @@ RemoteSpellcheckEngineChild::~RemoteSpellcheckEngineChild()
mOwner->DeleteRemoteEngine();
}
RefPtr<GenericPromise>
RemoteSpellcheckEngineChild::SetCurrentDictionaryFromList(
const nsTArray<nsString>& aList)
{
MozPromiseHolder<GenericPromise>* promiseHolder =
new MozPromiseHolder<GenericPromise>();
if (!SendSetDictionaryFromList(
aList,
reinterpret_cast<intptr_t>(promiseHolder))) {
delete promiseHolder;
return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
}
// promiseHolder will removed by receive message
return promiseHolder->Ensure(__func__);
}
mozilla::ipc::IPCResult
RemoteSpellcheckEngineChild::RecvNotifyOfCurrentDictionary(
const nsString& aDictionary,
const intptr_t& aId)
{
MozPromiseHolder<GenericPromise>* promiseHolder =
reinterpret_cast<MozPromiseHolder<GenericPromise>*>(aId);
mOwner->mCurrentDictionary = aDictionary;
if (aDictionary.IsEmpty()) {
promiseHolder->RejectIfExists(NS_ERROR_NOT_AVAILABLE, __func__);
} else {
promiseHolder->ResolveIfExists(true, __func__);
}
delete promiseHolder;
return IPC_OK();
}
} //namespace mozilla

Просмотреть файл

@ -5,6 +5,7 @@
#ifndef RemoteSpellcheckEngineChild_h_
#define RemoteSpellcheckEngineChild_h_
#include "mozilla/MozPromise.h"
#include "mozilla/PRemoteSpellcheckEngineChild.h"
#include "mozSpellChecker.h"
@ -18,6 +19,13 @@ public:
explicit RemoteSpellcheckEngineChild(mozSpellChecker *aOwner);
virtual ~RemoteSpellcheckEngineChild();
virtual mozilla::ipc::IPCResult RecvNotifyOfCurrentDictionary(
const nsString& aDictionary,
const intptr_t& aPromiseId) override;
RefPtr<GenericPromise> SetCurrentDictionaryFromList(
const nsTArray<nsString>& aList);
private:
mozSpellChecker *mOwner;
};

Просмотреть файл

@ -4,6 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "RemoteSpellCheckEngineParent.h"
#include "mozilla/Unused.h"
#include "nsISpellChecker.h"
#include "nsServiceManagerUtils.h"
@ -28,6 +29,23 @@ RemoteSpellcheckEngineParent::RecvSetDictionary(
return IPC_OK();
}
mozilla::ipc::IPCResult
RemoteSpellcheckEngineParent::RecvSetDictionaryFromList(
nsTArray<nsString>&& aList,
const intptr_t& aPromiseId)
{
for (auto& dictionary : aList) {
MOZ_ASSERT(!dictionary.IsEmpty());
nsresult rv = mSpellChecker->SetCurrentDictionary(dictionary);
if (NS_SUCCEEDED(rv)) {
Unused << SendNotifyOfCurrentDictionary(dictionary, aPromiseId);
return IPC_OK();
}
}
Unused << SendNotifyOfCurrentDictionary(EmptyString(), aPromiseId);
return IPC_OK();
}
mozilla::ipc::IPCResult
RemoteSpellcheckEngineParent::RecvCheck(
const nsString& aWord,

Просмотреть файл

@ -6,6 +6,7 @@
#include "mozilla/PRemoteSpellcheckEngineParent.h"
#include "nsCOMPtr.h"
#include "nsTArray.h"
class nsISpellChecker;
@ -23,6 +24,10 @@ public:
virtual mozilla::ipc::IPCResult RecvSetDictionary(const nsString& aDictionary,
bool* success) override;
virtual mozilla::ipc::IPCResult RecvSetDictionaryFromList(
nsTArray<nsString>&& aList,
const intptr_t& aPromiseId) override;
virtual mozilla::ipc::IPCResult RecvCheck(const nsString& aWord, bool* aIsMisspelled) override;
virtual mozilla::ipc::IPCResult RecvCheckAndSuggest(const nsString& aWord,

Просмотреть файл

@ -16,6 +16,7 @@
#include "nsXULAppAPI.h"
using mozilla::dom::ContentChild;
using mozilla::GenericPromise;
using mozilla::PRemoteSpellcheckEngineChild;
using mozilla::RemoteSpellcheckEngineChild;
@ -429,6 +430,28 @@ mozSpellChecker::SetCurrentDictionary(const nsAString &aDictionary)
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP_(RefPtr<GenericPromise>)
mozSpellChecker::SetCurrentDictionaryFromList(const nsTArray<nsString>& aList)
{
if (aList.IsEmpty()) {
return GenericPromise::CreateAndReject(NS_ERROR_INVALID_ARG, __func__);
}
if (XRE_IsContentProcess()) {
// mCurrentDictionary will be set by RemoteSpellCheckEngineChild
return mEngine->SetCurrentDictionaryFromList(aList);
}
for (auto& dictionary : aList) {
nsresult rv = SetCurrentDictionary(dictionary);
if (NS_SUCCEEDED(rv)) {
return GenericPromise::CreateAndResolve(true, __func__);
}
}
// We could not find any engine with the requested dictionary
return GenericPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__);
}
nsresult
mozSpellChecker::SetupDoc(int32_t *outBlockOffset)
{

Просмотреть файл

@ -20,7 +20,6 @@
#include "RemoteSpellCheckEngineChild.h"
namespace mozilla {
class PRemoteSpellcheckEngineChild;
class RemoteSpellcheckEngineChild;
} // namespace mozilla
@ -48,6 +47,8 @@ public:
NS_IMETHOD GetDictionaryList(nsTArray<nsString> *aDictionaryList) override;
NS_IMETHOD GetCurrentDictionary(nsAString &aDictionary) override;
NS_IMETHOD SetCurrentDictionary(const nsAString &aDictionary) override;
NS_IMETHOD_(RefPtr<mozilla::GenericPromise>)
SetCurrentDictionaryFromList(const nsTArray<nsString>& aList) override;
void DeleteRemoteEngine() {
mEngine = nullptr;
@ -71,6 +72,8 @@ protected:
nsresult GetEngineList(nsCOMArray<mozISpellCheckingEngine> *aDictionaryList);
mozilla::PRemoteSpellcheckEngineChild *mEngine;
mozilla::RemoteSpellcheckEngineChild *mEngine;
friend class mozilla::RemoteSpellcheckEngineChild;
};
#endif // mozSpellChecker_h__

0
gfx/angle/AUTHORS Executable file → Normal file
Просмотреть файл

4
gfx/angle/BUILD.gn Executable file → Normal file
Просмотреть файл

@ -319,6 +319,10 @@ static_library("libANGLE") {
defines += [ "ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ " + "\"d3dcompiler_47.dll\", \"d3dcompiler_46.dll\", \"d3dcompiler_43.dll\" }" ]
}
if (angle_enable_hlsl) {
sources += rebase_path(gles_gypi.libangle_d3d_hlsl_sources, ".", "src")
}
if (angle_enable_d3d9) {
sources += rebase_path(gles_gypi.libangle_d3d9_sources, ".", "src")
libs += [ "d3d9.lib" ]

2
gfx/angle/CONTRIBUTORS Executable file → Normal file
Просмотреть файл

@ -69,6 +69,8 @@ Intel Corporation
Jie Chen
Qiankun Miao
Bryan Bernhart
Yunchao He
Xinghua Cao
Klarälvdalens Datakonsult AB
Milian Wolff

2
gfx/angle/DEPS Executable file → Normal file
Просмотреть файл

@ -17,7 +17,7 @@ deps = {
'https://android.googlesource.com/platform/external/cherry' + '@' + 'd2e26b4d864ec2a6757e7f1174e464949ca5bf73',
'third_party/deqp/src':
'https://android.googlesource.com/platform/external/deqp' + '@' + 'f4f3d8079e7a37d7675ab93583e6438d0bca0e58',
'https://android.googlesource.com/platform/external/deqp' + '@' + '455d82c60b096e7bd83b6a2f5ed70c61e4bfa759',
'third_party/libpng':
'https://android.googlesource.com/platform/external/libpng' + '@' + '094e181e79a3d6c23fd005679025058b7df1ad6c',

2
gfx/angle/DEPS.chromium Executable file → Normal file
Просмотреть файл

@ -11,7 +11,7 @@
vars = {
'android_git': 'https://android.googlesource.com',
'deqp_revision': 'f4f3d8079e7a37d7675ab93583e6438d0bca0e58',
'deqp_revision': '455d82c60b096e7bd83b6a2f5ed70c61e4bfa759',
}
deps_os = {

0
gfx/angle/LICENSE Executable file → Normal file
Просмотреть файл

4
gfx/angle/Makefile.in Executable file → Normal file
Просмотреть файл

@ -9,6 +9,10 @@ ifdef MOZ_D3DCOMPILER_VISTA_DLL_PATH
cp -fp "$(MOZ_D3DCOMPILER_VISTA_DLL_PATH)" "$(DIST)/bin"
endif
ifdef MOZ_D3DCOMPILER_XP_CAB
expand '$(MOZ_D3DCOMPILER_XP_CAB)' -F:$(MOZ_D3DCOMPILER_XP_DLL) '$(DIST)/bin'
endif
endif
include $(topsrcdir)/config/rules.mk

0
gfx/angle/README.chromium Executable file → Normal file
Просмотреть файл

0
gfx/angle/README.md Executable file → Normal file
Просмотреть файл

0
gfx/angle/README.mozilla Executable file → Normal file
Просмотреть файл

0
gfx/angle/include/EGL/egl.h Executable file → Normal file
Просмотреть файл

0
gfx/angle/include/EGL/eglext.h Executable file → Normal file
Просмотреть файл

0
gfx/angle/include/EGL/eglplatform.h Executable file → Normal file
Просмотреть файл

0
gfx/angle/include/GLES2/gl2.h Executable file → Normal file
Просмотреть файл

10
gfx/angle/include/GLES2/gl2ext.h Executable file → Normal file
Просмотреть файл

@ -821,11 +821,13 @@ GL_APICALL void GL_APIENTRY glBlitFramebufferANGLE (GLint srcX0, GLint srcY0, GL
#endif
#endif /* GL_ANGLE_framebuffer_blit */
#ifndef GL_ANGLE_webgl_compatibility
#define GL_ANGLE_webgl_compatibility 1
typedef GLboolean(GL_APIENTRYP PFNGLENABLEEXTENSIONANGLEPROC) (const GLchar *name);
#ifndef GL_ANGLE_request_extension
#define GL_ANGLE_request_extension 1
#define GL_REQUESTABLE_EXTENSIONS_ANGLE 0x93A8
#define GL_NUM_REQUESTABLE_EXTENSIONS_ANGLE 0x93A8
typedef GLboolean(GL_APIENTRYP PFNGLREQUESTEXTENSIONANGLEPROC) (const GLchar *name);
#ifdef GL_GLEXT_PROTOTYPES
GL_APICALL GLboolean GL_APIENTRY glEnableExtensionANGLE (const GLchar *name);
GL_APICALL GLboolean GL_APIENTRY glRequestExtensionANGLE (const GLchar *name);
#endif
#endif /* GL_ANGLE_webgl_compatibility */

0
gfx/angle/include/GLES2/gl2platform.h Executable file → Normal file
Просмотреть файл

0
gfx/angle/include/GLES3/gl3.h Executable file → Normal file
Просмотреть файл

0
gfx/angle/include/GLES3/gl31.h Executable file → Normal file
Просмотреть файл

0
gfx/angle/include/GLES3/gl32.h Executable file → Normal file
Просмотреть файл

0
gfx/angle/include/GLES3/gl3platform.h Executable file → Normal file
Просмотреть файл

20
gfx/angle/include/GLSLANG/ShaderLang.h Executable file → Normal file
Просмотреть файл

@ -20,19 +20,12 @@
// and the shading language compiler.
//
namespace sh
{
// GLenum alias
typedef unsigned int GLenum;
}
// Must be included after GLenum proxy typedef
// Note: make sure to increment ANGLE_SH_VERSION when changing ShaderVars.h
#include "ShaderVars.h"
// Version number for shader translation API.
// It is incremented every time the API changes.
#define ANGLE_SH_VERSION 167
#define ANGLE_SH_VERSION 168
enum ShShaderSpec
{
@ -72,8 +65,8 @@ enum ShShaderOutput
};
// Compile options.
using ShCompileOptions = uint64_t;
// The Compile options type is defined in ShaderVars.h, to allow ANGLE to import the ShaderVars
// header without needing the ShaderLang header. This avoids some conflicts with glslang.
const ShCompileOptions SH_VALIDATE = 0;
const ShCompileOptions SH_VALIDATE_LOOP_INDEXING = UINT64_C(1) << 0;
@ -205,7 +198,12 @@ const ShCompileOptions SH_DONT_REMOVE_INVARIANT_FOR_FRAGMENT_INPUT = UINT64_C(1)
// Due to spec difference between GLSL 4.1 or lower and ESSL3, some platforms (for example, Mac OSX
// core profile) require a variable's "invariant"/"centroid" qualifiers to match between vertex and
// fragment shader. A simple solution to allow such shaders to link is to omit the two qualifiers.
// Note that the two flags only take effect on ESSL3 input shaders translated to GLSL 4.1 or lower.
// AMD driver in Linux requires invariant qualifier to match between vertex and fragment shaders,
// while ESSL3 disallows invariant qualifier in fragment shader and GLSL >= 4.2 doesn't require
// invariant qualifier to match between shaders. Remove invariant qualifier from vertex shader to
// workaround AMD driver bug.
// Note that the two flags take effect on ESSL3 input shaders translated to GLSL 4.1 or lower and to
// GLSL 4.2 or newer on Linux AMD.
// TODO(zmo): This is not a good long-term solution. Simply dropping these qualifiers may break some
// developers' content. A more complex workaround of dynamically generating, compiling, and
// re-linking shaders that use these qualifiers should be implemented.

6
gfx/angle/include/GLSLANG/ShaderVars.h Executable file → Normal file
Просмотреть файл

@ -14,11 +14,13 @@
#include <string>
#include <vector>
// Assume ShaderLang.h is included before ShaderVars.h, for sh::GLenum
// Note: make sure to increment ANGLE_SH_VERSION when changing ShaderVars.h
// This type is defined here to simplify ANGLE's integration with glslang for SPIRv.
using ShCompileOptions = uint64_t;
namespace sh
{
// GLenum alias
typedef unsigned int GLenum;
// Varying interpolation qualifier, see section 4.3.9 of the ESSL 3.00.4 spec
enum InterpolationType

0
gfx/angle/include/angle_gl.h Executable file → Normal file
Просмотреть файл

0
gfx/angle/include/angle_windowsstore.h Executable file → Normal file
Просмотреть файл

0
gfx/angle/include/export.h Executable file → Normal file
Просмотреть файл

0
gfx/angle/include/platform/Platform.h Executable file → Normal file
Просмотреть файл

3
gfx/angle/moz.build Executable file → Normal file
Просмотреть файл

@ -139,6 +139,9 @@ if CONFIG['GNU_CXX']:
'-Wno-shadow-local',
]
if CONFIG['MOZ_DIRECTX_SDK_PATH'] and not CONFIG['MOZ_HAS_WINSDK_WITH_D3D']:
LOCAL_INCLUDES += ['%' + '%s/include/' % CONFIG['MOZ_DIRECTX_SDK_PATH']]
DEFINES['_CRT_SECURE_NO_DEPRECATE'] = True
DEFINES['_HAS_EXCEPTIONS'] = 0

0
gfx/angle/src/angle.gyp Executable file → Normal file
Просмотреть файл

15
gfx/angle/src/commit.h Executable file → Normal file
Просмотреть файл

@ -1,3 +1,14 @@
#define ANGLE_COMMIT_HASH "2a250c8a0e15"
//
// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// commit.h:
// This is a default commit hash header, when git is not available.
//
#define ANGLE_COMMIT_HASH "unknown hash"
#define ANGLE_COMMIT_HASH_SIZE 12
#define ANGLE_COMMIT_DATE "2016-11-23 17:58:16 +0800"
#define ANGLE_COMMIT_DATE "unknown date"
#define ANGLE_DISABLE_PROGRAM_BINARY_LOAD

0
gfx/angle/src/commit_id.py Executable file → Normal file
Просмотреть файл

0
gfx/angle/src/common/BitSetIterator.h Executable file → Normal file
Просмотреть файл

0
gfx/angle/src/common/BitSetIterator_unittest.cpp Executable file → Normal file
Просмотреть файл

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше