mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Merge m-i to m-c, a=merge
MozReview-Commit-ID: A3wgReQAalj
This commit is contained in:
commit
61baa2aa9a
@ -18,7 +18,6 @@ support-files =
|
||||
[browser_caching_attributes.js]
|
||||
[browser_caching_description.js]
|
||||
[browser_caching_name.js]
|
||||
skip-if = e10s
|
||||
[browser_caching_relations.js]
|
||||
[browser_caching_states.js]
|
||||
[browser_caching_value.js]
|
||||
@ -33,14 +32,12 @@ skip-if = e10s
|
||||
# Tree update tests
|
||||
[browser_treeupdate_ariadialog.js]
|
||||
[browser_treeupdate_ariaowns.js]
|
||||
skip-if = e10s
|
||||
[browser_treeupdate_canvas.js]
|
||||
[browser_treeupdate_cssoverflow.js]
|
||||
[browser_treeupdate_doc.js]
|
||||
[browser_treeupdate_gencontent.js]
|
||||
[browser_treeupdate_hidden.js]
|
||||
[browser_treeupdate_imagemap.js]
|
||||
skip-if = e10s
|
||||
[browser_treeupdate_list.js]
|
||||
[browser_treeupdate_list_editabledoc.js]
|
||||
[browser_treeupdate_listener.js]
|
||||
|
@ -52,7 +52,7 @@
|
||||
gQueue.push(new synthEscapeKey("ml_marmalade", new focusChecker("menulist")));
|
||||
if (!MAC) {
|
||||
// On Windows, items get selected during navigation.
|
||||
let expectedItem = WIN ? "ml_tangerine" : "ml_marmalade";
|
||||
let expectedItem = WIN ? "ml_strawberry" : "ml_marmalade";
|
||||
gQueue.push(new synthDownKey("menulist", new nofocusChecker(expectedItem)));
|
||||
gQueue.push(new synthOpenComboboxKey("menulist", new focusChecker(expectedItem)));
|
||||
gQueue.push(new synthEnterKey(expectedItem, new focusChecker("menulist")));
|
||||
@ -174,6 +174,7 @@ if (!MAC) {
|
||||
<menupopup>
|
||||
<menuitem id="ml_tangerine" label="tangerine trees"/>
|
||||
<menuitem id="ml_marmalade" label="marmalade skies"/>
|
||||
<menuitem id="ml_strawberry" label="strawberry fields"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
<menulist id="emenulist" editable="true">
|
||||
|
@ -413,7 +413,6 @@ pref("dom.mozApps.single_variant_sourcedir", "/persist/svoperapps");
|
||||
|
||||
// WebSettings
|
||||
pref("dom.mozSettings.enabled", true);
|
||||
pref("dom.mozPermissionSettings.enabled", true);
|
||||
|
||||
// controls if we want camera support
|
||||
pref("device.camera.enabled", true);
|
||||
|
@ -18,10 +18,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger",
|
||||
"@mozilla.org/system-message-internal;1",
|
||||
"nsISystemMessagesInternal");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "appsService",
|
||||
"@mozilla.org/AppsService;1",
|
||||
"nsIAppsService");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy",
|
||||
"resource://gre/modules/SystemAppProxy.jsm");
|
||||
|
||||
@ -144,33 +140,6 @@ var AlertsHelper = {
|
||||
|
||||
registerAppListener: function(uid, listener) {
|
||||
this._listeners[uid] = listener;
|
||||
|
||||
appsService.getManifestFor(listener.manifestURL).then((manifest) => {
|
||||
let app = appsService.getAppByManifestURL(listener.manifestURL);
|
||||
let helper = new ManifestHelper(manifest, app.origin, app.manifestURL);
|
||||
let getNotificationURLFor = function(messages) {
|
||||
if (!messages) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (let i = 0; i < messages.length; i++) {
|
||||
let message = messages[i];
|
||||
if (message === kNotificationSystemMessageName) {
|
||||
return helper.fullLaunchPath();
|
||||
} else if (typeof message === "object" &&
|
||||
kNotificationSystemMessageName in message) {
|
||||
return helper.resolveURL(message[kNotificationSystemMessageName]);
|
||||
}
|
||||
}
|
||||
|
||||
// No message found...
|
||||
return null;
|
||||
}
|
||||
|
||||
listener.target = getNotificationURLFor(manifest.messages);
|
||||
|
||||
// Bug 816944 - Support notification messages for entry_points.
|
||||
});
|
||||
},
|
||||
|
||||
deserializeStructuredClone: function(dataString) {
|
||||
@ -222,14 +191,6 @@ var AlertsHelper = {
|
||||
send(null, null);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have a manifest URL, get the icon and title from the manifest
|
||||
// to prevent spoofing.
|
||||
appsService.getManifestFor(manifestURL).then((manifest) => {
|
||||
let app = appsService.getAppByManifestURL(manifestURL);
|
||||
let helper = new ManifestHelper(manifest, app.origin, manifestURL);
|
||||
send(helper.name, helper.iconURLForSize(kNotificationIconSize));
|
||||
});
|
||||
},
|
||||
|
||||
showAlertNotification: function(aMessage) {
|
||||
|
@ -1,152 +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/. */
|
||||
|
||||
'use strict';
|
||||
|
||||
function debug(s) {
|
||||
dump("-*- B2GAppMigrator.js: " + s + "\n");
|
||||
}
|
||||
const DEBUG = false;
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
const kMigrationMessageName = "webapps-before-update-merge";
|
||||
|
||||
const kIDBDirType = "indexedDBPDir";
|
||||
const kProfileDirType = "ProfD";
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "appsService",
|
||||
"@mozilla.org/AppsService;1",
|
||||
"nsIAppsService");
|
||||
|
||||
function B2GAppMigrator() {
|
||||
}
|
||||
|
||||
B2GAppMigrator.prototype = {
|
||||
classID: Components.ID('{7211ece0-b458-4635-9afc-f8d7f376ee95}'),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
executeBrowserMigration: function() {
|
||||
if (DEBUG) debug("Executing Browser Migration");
|
||||
// The browser db file and directory names are hashed the same way
|
||||
// everywhere, so it should be the same on all systems. We should
|
||||
// be able to just hardcode it.
|
||||
let browserDBDirName = "2959517650brreosw";
|
||||
let browserDBFileName = browserDBDirName + ".sqlite";
|
||||
|
||||
// Storage directories need to be prefixed with the local id of
|
||||
// the app
|
||||
let browserLocalAppId = appsService.getAppLocalIdByManifestURL("app://browser.gaiamobile.org/manifest.webapp");
|
||||
let browserAppStorageDirName = browserLocalAppId + "+f+app+++browser.gaiamobile.org";
|
||||
|
||||
// On the phone, the browser db will only be in the old IDB
|
||||
// directory, since it only existed up until v2.0. On desktop, it
|
||||
// will exist in the profile directory.
|
||||
//
|
||||
// Uses getDir with filename appending to make sure we don't
|
||||
// create extra directories along the way if they don't already
|
||||
// exist.
|
||||
let browserDBFile = FileUtils.getDir(kIDBDirType,
|
||||
["storage",
|
||||
"persistent",
|
||||
browserAppStorageDirName,
|
||||
"idb"], false, true);
|
||||
browserDBFile.append(browserDBFileName);
|
||||
let browserDBDir = FileUtils.getDir(kIDBDirType,
|
||||
["storage",
|
||||
"persistent",
|
||||
browserAppStorageDirName,
|
||||
"idb",
|
||||
browserDBDirName
|
||||
], false, true);
|
||||
|
||||
if (!browserDBFile.exists()) {
|
||||
if (DEBUG) debug("Browser DB " + browserDBFile.path + " does not exist, trying profile location");
|
||||
browserDBFile = FileUtils.getDir(kProfileDirType,
|
||||
["storage",
|
||||
"persistent",
|
||||
browserAppStorageDirName,
|
||||
"idb"], false, true);
|
||||
browserDBFile.append(browserDBFileName);
|
||||
if (!browserDBFile.exists()) {
|
||||
if (DEBUG) debug("Browser DB " + browserDBFile.path + " does not exist. Cannot copy browser db.");
|
||||
return;
|
||||
}
|
||||
// If we have confirmed we have a DB file, we should also have a
|
||||
// directory.
|
||||
browserDBDir = FileUtils.getDir(kProfileDirType,
|
||||
["storage",
|
||||
"persistent",
|
||||
browserAppStorageDirName,
|
||||
"idb",
|
||||
browserDBDirName
|
||||
], false, true);
|
||||
}
|
||||
|
||||
let systemLocalAppId = appsService.getAppLocalIdByManifestURL("app://system.gaiamobile.org/manifest.webapp");
|
||||
let systemAppStorageDirName = systemLocalAppId + "+f+app+++system.gaiamobile.org";
|
||||
|
||||
// This check futureproofs the system DB storage directory. It
|
||||
// currently exists outside of the profile but will most likely
|
||||
// move into the profile at some point.
|
||||
let systemDBDir = FileUtils.getDir(kIDBDirType,
|
||||
["storage",
|
||||
"persistent",
|
||||
systemAppStorageDirName,
|
||||
"idb"], false, true);
|
||||
|
||||
if (!systemDBDir.exists()) {
|
||||
if (DEBUG) debug("System DB directory " + systemDBDir.path + " does not exist, trying profile location");
|
||||
systemDBDir = FileUtils.getDir(kProfileDirType,
|
||||
["storage",
|
||||
"persistent",
|
||||
systemAppStorageDirName,
|
||||
"idb"], false, true);
|
||||
if (!systemDBDir.exists()) {
|
||||
if (DEBUG) debug("System DB directory " + systemDBDir.path + " does not exist. Cannot copy browser db.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
debug("Browser DB file exists, copying");
|
||||
debug("Browser local id: " + browserLocalAppId + "");
|
||||
debug("System local id: " + systemLocalAppId + "");
|
||||
debug("Browser DB file path: " + browserDBFile.path + "");
|
||||
debug("Browser DB dir path: " + browserDBDir.path + "");
|
||||
debug("System DB directory path: " + systemDBDir.path + "");
|
||||
}
|
||||
|
||||
try {
|
||||
browserDBFile.copyTo(systemDBDir, browserDBFileName);
|
||||
} catch (e) {
|
||||
debug("File copy caused error! " + e.name);
|
||||
}
|
||||
try {
|
||||
browserDBDir.copyTo(systemDBDir, browserDBDirName);
|
||||
} catch (e) {
|
||||
debug("Dir copy caused error! " + e.name);
|
||||
}
|
||||
if (DEBUG) debug("Browser DB copied successfully");
|
||||
},
|
||||
|
||||
observe: function(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case kMigrationMessageName:
|
||||
this.executeBrowserMigration();
|
||||
break;
|
||||
default:
|
||||
debug("Unhandled topic: " + topic);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([B2GAppMigrator]);
|
@ -91,10 +91,6 @@ component {fd663ec8-cf3f-4c2b-aacb-17a6915ccb44} BootstrapCommandLine.js
|
||||
contract @mozilla.org/commandlinehandler/general-startup;1?type=b2gbootstrap {fd663ec8-cf3f-4c2b-aacb-17a6915ccb44}
|
||||
category command-line-handler m-b2gbootstrap @mozilla.org/commandlinehandler/general-startup;1?type=b2gbootstrap
|
||||
|
||||
# B2GAppMigrator.js
|
||||
component {7211ece0-b458-4635-9afc-f8d7f376ee95} B2GAppMigrator.js
|
||||
contract @mozilla.org/app-migrator;1 {7211ece0-b458-4635-9afc-f8d7f376ee95}
|
||||
|
||||
# B2GPresentationDevicePrompt.js
|
||||
component {4a300c26-e99b-4018-ab9b-c48cf9bc4de1} B2GPresentationDevicePrompt.js
|
||||
contract @mozilla.org/presentation-device/prompt;1 {4a300c26-e99b-4018-ab9b-c48cf9bc4de1}
|
||||
|
@ -25,7 +25,6 @@ const ALLOW_MULTIPLE_REQUESTS = ["audio-capture", "video-capture"];
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||
Cu.import("resource://gre/modules/PermissionsInstaller.jsm");
|
||||
Cu.import("resource://gre/modules/PermissionsTable.jsm");
|
||||
|
||||
var permissionManager = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);
|
||||
@ -183,43 +182,6 @@ ContentPermissionPrompt.prototype = {
|
||||
return false;
|
||||
},
|
||||
|
||||
handledByApp: function handledByApp(request, typesInfo) {
|
||||
if (request.principal.appId == Ci.nsIScriptSecurityManager.NO_APP_ID ||
|
||||
request.principal.appId == Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID) {
|
||||
// This should not really happen
|
||||
request.cancel();
|
||||
return true;
|
||||
}
|
||||
|
||||
let appsService = Cc["@mozilla.org/AppsService;1"]
|
||||
.getService(Ci.nsIAppsService);
|
||||
let app = appsService.getAppByLocalId(request.principal.appId);
|
||||
|
||||
// Check each permission if it's denied by permission manager with app's
|
||||
// URL.
|
||||
let notDenyAppPrincipal = function(type) {
|
||||
let url = Services.io.newURI(app.origin, null, null);
|
||||
let principal =
|
||||
secMan.createCodebasePrincipal(url,
|
||||
{appId: request.principal.appId});
|
||||
let result = Services.perms.testExactPermissionFromPrincipal(principal,
|
||||
type.access);
|
||||
|
||||
if (result == Ci.nsIPermissionManager.ALLOW_ACTION ||
|
||||
result == Ci.nsIPermissionManager.PROMPT_ACTION) {
|
||||
type.deny = false;
|
||||
}
|
||||
return !type.deny;
|
||||
}
|
||||
// Cancel the entire request if one of the requested permissions is denied
|
||||
if (!typesInfo.every(notDenyAppPrincipal)) {
|
||||
request.cancel();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
handledByPermissionType: function handledByPermissionType(request, typesInfo) {
|
||||
for (let i in typesInfo) {
|
||||
if (permissionSpecificChecker.hasOwnProperty(typesInfo[i].permission) &&
|
||||
@ -271,8 +233,7 @@ ContentPermissionPrompt.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.handledByApp(request, typesInfo) ||
|
||||
this.handledByPermissionType(request, typesInfo)) {
|
||||
if (this.handledByPermissionType(request, typesInfo)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,6 @@ DIRS += ['test']
|
||||
EXTRA_COMPONENTS += [
|
||||
'AlertsService.js',
|
||||
'B2GAboutRedirector.js',
|
||||
'B2GAppMigrator.js',
|
||||
'B2GPresentationDevicePrompt.js',
|
||||
'BootstrapCommandLine.js',
|
||||
'ContentPermissionPrompt.js',
|
||||
|
@ -148,7 +148,6 @@
|
||||
@RESPATH@/components/docshell.xpt
|
||||
@RESPATH@/components/dom.xpt
|
||||
@RESPATH@/components/dom_activities.xpt
|
||||
@RESPATH@/components/dom_apps.xpt
|
||||
@RESPATH@/components/dom_audiochannel.xpt
|
||||
@RESPATH@/components/dom_base.xpt
|
||||
@RESPATH@/components/dom_system.xpt
|
||||
@ -178,7 +177,6 @@
|
||||
@RESPATH@/components/dom_range.xpt
|
||||
@RESPATH@/components/dom_security.xpt
|
||||
@RESPATH@/components/dom_settings.xpt
|
||||
@RESPATH@/components/dom_permissionsettings.xpt
|
||||
@RESPATH@/components/dom_sidebar.xpt
|
||||
@RESPATH@/components/dom_cellbroadcast.xpt
|
||||
@RESPATH@/components/dom_icc.xpt
|
||||
@ -335,10 +333,6 @@
|
||||
@RESPATH@/components/PhoneNumberService.manifest
|
||||
@RESPATH@/components/NotificationStorage.js
|
||||
@RESPATH@/components/NotificationStorage.manifest
|
||||
@RESPATH@/components/PermissionSettings.js
|
||||
@RESPATH@/components/PermissionSettings.manifest
|
||||
@RESPATH@/components/PermissionPromptService.js
|
||||
@RESPATH@/components/PermissionPromptService.manifest
|
||||
@RESPATH@/components/FeedProcessor.manifest
|
||||
@RESPATH@/components/FeedProcessor.js
|
||||
@RESPATH@/components/BrowserFeeds.manifest
|
||||
@ -538,8 +532,6 @@
|
||||
@RESPATH@/components/TelemetryStartup.manifest
|
||||
@RESPATH@/components/XULStore.js
|
||||
@RESPATH@/components/XULStore.manifest
|
||||
@RESPATH@/components/AppsService.js
|
||||
@RESPATH@/components/AppsService.manifest
|
||||
@RESPATH@/components/Push.js
|
||||
@RESPATH@/components/Push.manifest
|
||||
@RESPATH@/components/PushComponents.js
|
||||
@ -802,7 +794,6 @@ bin/libfreebl_32int64_3.so
|
||||
@RESPATH@/components/HelperAppDialog.js
|
||||
@RESPATH@/components/DownloadsUI.js
|
||||
@RESPATH@/components/SystemMessageGlue.js
|
||||
@RESPATH@/components/B2GAppMigrator.js
|
||||
@RESPATH@/components/B2GPresentationDevicePrompt.js
|
||||
@RESPATH@/components/PresentationRequestUIGlue.js
|
||||
|
||||
|
@ -5013,6 +5013,14 @@
|
||||
this._getTabForContentWindow(event.target.top) :
|
||||
this.getTabForBrowser(event.originalTarget);
|
||||
|
||||
// Focus window for beforeunload dialog so it is seen but don't
|
||||
// steal focus from other applications.
|
||||
if (event.detail &&
|
||||
event.detail.tabPrompt &&
|
||||
event.detail.inPermitUnload &&
|
||||
Services.focus.activeWindow)
|
||||
window.focus();
|
||||
|
||||
// Don't need to act if the tab is already selected:
|
||||
if (tabForEvent.selected)
|
||||
return;
|
||||
|
@ -64,13 +64,19 @@ const PAGECONTENT_TRANSLATED =
|
||||
"</iframe>" +
|
||||
"</div></body></html>";
|
||||
|
||||
function openSelectPopup(selectPopup, withMouse, selector = "select", win = window)
|
||||
function openSelectPopup(selectPopup, mode = "key", selector = "select", win = window)
|
||||
{
|
||||
let popupShownPromise = BrowserTestUtils.waitForEvent(selectPopup, "popupshown");
|
||||
|
||||
if (withMouse) {
|
||||
return Promise.all([popupShownPromise,
|
||||
BrowserTestUtils.synthesizeMouseAtCenter(selector, { }, win.gBrowser.selectedBrowser)]);
|
||||
if (mode == "click" || mode == "mousedown") {
|
||||
let mousePromise;
|
||||
if (mode == "click") {
|
||||
mousePromise = BrowserTestUtils.synthesizeMouseAtCenter(selector, { }, win.gBrowser.selectedBrowser);
|
||||
} else {
|
||||
mousePromise = BrowserTestUtils.synthesizeMouse(selector, 5, 5, { type: "mousedown" }, win.gBrowser.selectedBrowser);
|
||||
}
|
||||
|
||||
return Promise.all([popupShownPromise, mousePromise]);
|
||||
}
|
||||
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", { altKey: true, code: "ArrowDown" }, win);
|
||||
@ -165,7 +171,7 @@ function* doSelectTests(contentType, dtd)
|
||||
is((yield getChangeEvents()), 1, "After closed - number of change events");
|
||||
|
||||
// Opening and closing the popup without changing the value should not fire a change event.
|
||||
yield openSelectPopup(selectPopup, true);
|
||||
yield openSelectPopup(selectPopup, "click");
|
||||
yield hideSelectPopup(selectPopup, "escape");
|
||||
is((yield getInputEvents()), 1, "Open and close with no change - number of input events");
|
||||
is((yield getChangeEvents()), 1, "Open and close with no change - number of change events");
|
||||
@ -174,7 +180,7 @@ function* doSelectTests(contentType, dtd)
|
||||
is((yield getInputEvents()), 1, "Tab away from select with no change - number of input events");
|
||||
is((yield getChangeEvents()), 1, "Tab away from select with no change - number of change events");
|
||||
|
||||
yield openSelectPopup(selectPopup, true);
|
||||
yield openSelectPopup(selectPopup, "click");
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", { code: "ArrowDown" });
|
||||
yield hideSelectPopup(selectPopup, "escape");
|
||||
is((yield getInputEvents()), isWindows ? 2 : 1, "Open and close with change - number of input events");
|
||||
@ -208,7 +214,7 @@ add_task(function*() {
|
||||
let selectPopup = menulist.menupopup;
|
||||
|
||||
// First, try it when a different <select> element than the one that is open is removed
|
||||
yield openSelectPopup(selectPopup, true, "#one");
|
||||
yield openSelectPopup(selectPopup, "click", "#one");
|
||||
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
|
||||
content.document.body.removeChild(content.document.getElementById("two"));
|
||||
@ -222,7 +228,7 @@ add_task(function*() {
|
||||
yield hideSelectPopup(selectPopup);
|
||||
|
||||
// Next, try it when the same <select> element than the one that is open is removed
|
||||
yield openSelectPopup(selectPopup, true, "#three");
|
||||
yield openSelectPopup(selectPopup, "click", "#three");
|
||||
|
||||
let popupHiddenPromise = BrowserTestUtils.waitForEvent(selectPopup, "popuphidden");
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
|
||||
@ -233,7 +239,7 @@ add_task(function*() {
|
||||
ok(true, "Popup hidden when select is removed");
|
||||
|
||||
// Finally, try it when the tab is closed while the select popup is open.
|
||||
yield openSelectPopup(selectPopup, true, "#one");
|
||||
yield openSelectPopup(selectPopup, "click", "#one");
|
||||
|
||||
popupHiddenPromise = BrowserTestUtils.waitForEvent(selectPopup, "popuphidden");
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
@ -251,7 +257,7 @@ add_task(function*() {
|
||||
let selectPopup = menulist.menupopup;
|
||||
|
||||
// First, get the position of the select popup when no translations have been applied.
|
||||
yield openSelectPopup(selectPopup, false);
|
||||
yield openSelectPopup(selectPopup);
|
||||
|
||||
let rect = selectPopup.getBoundingClientRect();
|
||||
let expectedX = rect.left;
|
||||
@ -292,7 +298,7 @@ add_task(function*() {
|
||||
});
|
||||
});
|
||||
|
||||
yield openSelectPopup(selectPopup, false);
|
||||
yield openSelectPopup(selectPopup);
|
||||
|
||||
expectedX += step[2];
|
||||
expectedY += step[3];
|
||||
@ -363,7 +369,7 @@ add_task(function* test_event_order() {
|
||||
|
||||
for (let mode of ["enter", "click"]) {
|
||||
let expected = mode == "enter" ? expectedEnter : expectedClick;
|
||||
yield openSelectPopup(selectPopup, true, mode == "enter" ? "#one" : "#two");
|
||||
yield openSelectPopup(selectPopup, "click", mode == "enter" ? "#one" : "#two");
|
||||
|
||||
let eventsPromise = ContentTask.spawn(browser, [mode, expected], function*([contentMode, contentExpected]) {
|
||||
return new Promise((resolve) => {
|
||||
@ -416,6 +422,38 @@ function* performLargePopupTests(win)
|
||||
let selectPopup = win.document.getElementById("ContentSelectDropdown").menupopup;
|
||||
let browserRect = browser.getBoundingClientRect();
|
||||
|
||||
// Check if a drag-select works and scrolls the list.
|
||||
yield openSelectPopup(selectPopup, "mousedown", "select", win);
|
||||
|
||||
let scrollPos = selectPopup.scrollBox.scrollTop;
|
||||
let popupRect = selectPopup.getBoundingClientRect();
|
||||
|
||||
// First, check that scrolling does not occur when the mouse is moved over the
|
||||
// anchor button but not the popup yet.
|
||||
EventUtils.synthesizeMouseAtPoint(popupRect.left + 5, popupRect.top - 10, { type: "mousemove" }, win);
|
||||
is(selectPopup.scrollBox.scrollTop, scrollPos, "scroll position after mousemove over button");
|
||||
|
||||
EventUtils.synthesizeMouseAtPoint(popupRect.left + 20, popupRect.top + 10, { type: "mousemove" }, win);
|
||||
|
||||
// Dragging above the popup scrolls it up.
|
||||
EventUtils.synthesizeMouseAtPoint(popupRect.left + 20, popupRect.top - 20, { type: "mousemove" }, win);
|
||||
ok(selectPopup.scrollBox.scrollTop < scrollPos - 5, "scroll position at drag up");
|
||||
|
||||
// Dragging below the popup scrolls it down.
|
||||
scrollPos = selectPopup.scrollBox.scrollTop;
|
||||
EventUtils.synthesizeMouseAtPoint(popupRect.left + 20, popupRect.bottom + 20, { type: "mousemove" }, win);
|
||||
ok(selectPopup.scrollBox.scrollTop > scrollPos + 5, "scroll position at drag down");
|
||||
|
||||
// Releasing the mouse button and moving the mouse does not change the scroll position.
|
||||
scrollPos = selectPopup.scrollBox.scrollTop;
|
||||
EventUtils.synthesizeMouseAtPoint(popupRect.left + 20, popupRect.bottom + 25, { type: "mouseup" }, win);
|
||||
is(selectPopup.scrollBox.scrollTop, scrollPos, "scroll position at mouseup");
|
||||
|
||||
EventUtils.synthesizeMouseAtPoint(popupRect.left + 20, popupRect.bottom + 20, { type: "mousemove" }, win);
|
||||
is(selectPopup.scrollBox.scrollTop, scrollPos, "scroll position at mouseup again");
|
||||
|
||||
yield hideSelectPopup(selectPopup, "escape", win);
|
||||
|
||||
let positions = [
|
||||
"margin-top: 300px;",
|
||||
"position: fixed; bottom: 100px;",
|
||||
@ -423,8 +461,8 @@ function* performLargePopupTests(win)
|
||||
];
|
||||
|
||||
let position;
|
||||
while (true) {
|
||||
yield openSelectPopup(selectPopup, false, "select", win);
|
||||
while (positions.length) {
|
||||
yield openSelectPopup(selectPopup, "key", "select", win);
|
||||
|
||||
let rect = selectPopup.getBoundingClientRect();
|
||||
ok(rect.top >= browserRect.top, "Popup top position in within browser area");
|
||||
@ -443,14 +481,11 @@ function* performLargePopupTests(win)
|
||||
yield hideSelectPopup(selectPopup, "enter", win);
|
||||
|
||||
position = positions.shift();
|
||||
if (!position) {
|
||||
break;
|
||||
}
|
||||
|
||||
let contentPainted = BrowserTestUtils.contentPainted(browser);
|
||||
yield ContentTask.spawn(browser, position, function*(contentPosition) {
|
||||
let select = content.document.getElementById("one");
|
||||
select.setAttribute("style", contentPosition);
|
||||
select.setAttribute("style", contentPosition || "");
|
||||
});
|
||||
yield contentPainted;
|
||||
}
|
||||
@ -511,7 +546,7 @@ add_task(function* test_mousemove_correcttarget() {
|
||||
|
||||
// The popup should be closed when fullscreen mode is entered or exited.
|
||||
for (let steps = 0; steps < 2; steps++) {
|
||||
yield openSelectPopup(selectPopup, true);
|
||||
yield openSelectPopup(selectPopup, "click");
|
||||
let popupHiddenPromise = BrowserTestUtils.waitForEvent(selectPopup, "popuphidden");
|
||||
let sizeModeChanged = BrowserTestUtils.waitForEvent(window, "sizemodechange");
|
||||
BrowserFullScreen();
|
||||
|
@ -262,7 +262,9 @@ const CustomizableWidgets = [
|
||||
let elementCount = tabsFragment.childElementCount;
|
||||
separator.hidden = !elementCount;
|
||||
while (--elementCount >= 0) {
|
||||
tabsFragment.children[elementCount].classList.add("subviewbutton", "cui-withicon");
|
||||
let element = tabsFragment.children[elementCount];
|
||||
CustomizableUI.addShortcut(element);
|
||||
element.classList.add("subviewbutton", "cui-withicon");
|
||||
}
|
||||
recentlyClosedTabs.appendChild(tabsFragment);
|
||||
|
||||
@ -272,7 +274,9 @@ const CustomizableWidgets = [
|
||||
elementCount = windowsFragment.childElementCount;
|
||||
separator.hidden = !elementCount;
|
||||
while (--elementCount >= 0) {
|
||||
windowsFragment.children[elementCount].classList.add("subviewbutton", "cui-withicon");
|
||||
let element = windowsFragment.children[elementCount];
|
||||
CustomizableUI.addShortcut(element);
|
||||
element.classList.add("subviewbutton", "cui-withicon");
|
||||
}
|
||||
recentlyClosedWindows.appendChild(windowsFragment);
|
||||
},
|
||||
|
@ -189,7 +189,6 @@
|
||||
@RESPATH@/components/directory.xpt
|
||||
@RESPATH@/components/docshell.xpt
|
||||
@RESPATH@/components/dom.xpt
|
||||
@RESPATH@/components/dom_apps.xpt
|
||||
@RESPATH@/components/dom_base.xpt
|
||||
@RESPATH@/components/dom_system.xpt
|
||||
@RESPATH@/components/dom_canvas.xpt
|
||||
@ -209,7 +208,6 @@
|
||||
@RESPATH@/components/dom_range.xpt
|
||||
@RESPATH@/components/dom_security.xpt
|
||||
@RESPATH@/components/dom_settings.xpt
|
||||
@RESPATH@/components/dom_permissionsettings.xpt
|
||||
@RESPATH@/components/dom_sidebar.xpt
|
||||
@RESPATH@/components/dom_storage.xpt
|
||||
@RESPATH@/components/dom_stylesheets.xpt
|
||||
@ -505,15 +503,11 @@
|
||||
@RESPATH@/components/messageWakeupService.manifest
|
||||
@RESPATH@/components/SettingsManager.js
|
||||
@RESPATH@/components/SettingsManager.manifest
|
||||
@RESPATH@/components/AppsService.js
|
||||
@RESPATH@/components/AppsService.manifest
|
||||
@RESPATH@/components/recording-cmdline.js
|
||||
@RESPATH@/components/recording-cmdline.manifest
|
||||
@RESPATH@/components/htmlMenuBuilder.js
|
||||
@RESPATH@/components/htmlMenuBuilder.manifest
|
||||
|
||||
@RESPATH@/components/PermissionSettings.js
|
||||
@RESPATH@/components/PermissionSettings.manifest
|
||||
@RESPATH@/components/NotificationStorage.js
|
||||
@RESPATH@/components/NotificationStorage.manifest
|
||||
@RESPATH@/components/Push.js
|
||||
|
@ -192,6 +192,18 @@ OriginAttributes::CreateSuffix(nsACString& aStr) const
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
OriginAttributes::CreateAnonymizedSuffix(nsACString& aStr) const
|
||||
{
|
||||
OriginAttributes attrs = *this;
|
||||
|
||||
if (!attrs.mFirstPartyDomain.IsEmpty()) {
|
||||
attrs.mFirstPartyDomain.AssignLiteral("_anonymizedFirstPartyDomain_");
|
||||
}
|
||||
|
||||
attrs.CreateSuffix(aStr);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class MOZ_STACK_CLASS PopulateFromSuffixIterator final
|
||||
@ -588,14 +600,9 @@ BasePrincipal::GetOriginSuffix(nsACString& aOriginAttributes)
|
||||
NS_IMETHODIMP
|
||||
BasePrincipal::GetAppStatus(uint16_t* aAppStatus)
|
||||
{
|
||||
if (AppId() == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
|
||||
NS_WARNING("Asking for app status on a principal with an unknown app id");
|
||||
// TODO: Remove GetAppStatus.
|
||||
*aAppStatus = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*aAppStatus = nsScriptSecurityManager::AppStatusForPrincipal(this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -48,6 +48,10 @@ public:
|
||||
// |!key1=value1&key2=value2|. If there are no non-default attributes, this
|
||||
// returns an empty string.
|
||||
void CreateSuffix(nsACString& aStr) const;
|
||||
|
||||
// Don't use this method for anything else than debugging!
|
||||
void CreateAnonymizedSuffix(nsACString& aStr) const;
|
||||
|
||||
MOZ_MUST_USE bool PopulateFromSuffix(const nsACString& aStr);
|
||||
|
||||
// Populates the attributes from a string like
|
||||
|
@ -30,8 +30,6 @@
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/HashFunctions.h"
|
||||
|
||||
#include "nsIAppsService.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
static bool gIsWhitelistingTestDomains = false;
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
#include "xpcpublic.h"
|
||||
#include "XPCWrapper.h"
|
||||
#include "nsIAppsService.h"
|
||||
#include "nsIInputStreamChannel.h"
|
||||
#include "nsILoadContext.h"
|
||||
#include "nsIServiceManager.h"
|
||||
@ -56,7 +55,6 @@
|
||||
#include "nsIChromeRegistry.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
#include "mozIApplication.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include <stdint.h>
|
||||
@ -241,68 +239,6 @@ nsScriptSecurityManager::SecurityHashURI(nsIURI* aURI)
|
||||
return NS_SecurityHashURI(aURI);
|
||||
}
|
||||
|
||||
uint16_t
|
||||
nsScriptSecurityManager::AppStatusForPrincipal(nsIPrincipal *aPrin)
|
||||
{
|
||||
uint32_t appId = aPrin->GetAppId();
|
||||
|
||||
// After bug 1238160, the principal no longer knows how to answer "is this a
|
||||
// browser element", which is really what this code path wants. Currently,
|
||||
// desktop is the only platform where we intend to disable isolation on a
|
||||
// browser frame, so non-desktop should be able to assume that
|
||||
// inIsolatedMozBrowser is true for all mozbrowser frames. Additionally,
|
||||
// apps are no longer used on desktop, so appId is always NO_APP_ID. We use
|
||||
// a release assertion in nsFrameLoader::OwnerIsIsolatedMozBrowserFrame so
|
||||
// that platforms with apps can assume inIsolatedMozBrowser is true for all
|
||||
// mozbrowser frames.
|
||||
bool inIsolatedMozBrowser = aPrin->GetIsInIsolatedMozBrowserElement();
|
||||
|
||||
NS_WARNING_ASSERTION(
|
||||
appId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
|
||||
"Asking for app status on a principal with an unknown app id");
|
||||
|
||||
// Installed apps have a valid app id (not NO_APP_ID or UNKNOWN_APP_ID)
|
||||
// and they are not inside a mozbrowser.
|
||||
if (appId == nsIScriptSecurityManager::NO_APP_ID ||
|
||||
appId == nsIScriptSecurityManager::UNKNOWN_APP_ID ||
|
||||
inIsolatedMozBrowser)
|
||||
{
|
||||
return nsIPrincipal::APP_STATUS_NOT_INSTALLED;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
|
||||
NS_ENSURE_TRUE(appsService, nsIPrincipal::APP_STATUS_NOT_INSTALLED);
|
||||
|
||||
nsCOMPtr<mozIApplication> app;
|
||||
appsService->GetAppByLocalId(appId, getter_AddRefs(app));
|
||||
NS_ENSURE_TRUE(app, nsIPrincipal::APP_STATUS_NOT_INSTALLED);
|
||||
|
||||
uint16_t status = nsIPrincipal::APP_STATUS_INSTALLED;
|
||||
NS_ENSURE_SUCCESS(app->GetAppStatus(&status),
|
||||
nsIPrincipal::APP_STATUS_NOT_INSTALLED);
|
||||
|
||||
nsString appOrigin;
|
||||
NS_ENSURE_SUCCESS(app->GetOrigin(appOrigin),
|
||||
nsIPrincipal::APP_STATUS_NOT_INSTALLED);
|
||||
nsCOMPtr<nsIURI> appURI;
|
||||
NS_ENSURE_SUCCESS(NS_NewURI(getter_AddRefs(appURI), appOrigin),
|
||||
nsIPrincipal::APP_STATUS_NOT_INSTALLED);
|
||||
|
||||
// The app could contain a cross-origin iframe - make sure that the content
|
||||
// is actually same-origin with the app.
|
||||
MOZ_ASSERT(inIsolatedMozBrowser == false, "Checked this above");
|
||||
nsAutoCString suffix;
|
||||
PrincipalOriginAttributes attrs;
|
||||
NS_ENSURE_TRUE(attrs.PopulateFromOrigin(NS_ConvertUTF16toUTF8(appOrigin), suffix),
|
||||
nsIPrincipal::APP_STATUS_NOT_INSTALLED);
|
||||
attrs.mAppId = appId;
|
||||
attrs.mInIsolatedMozBrowser = false;
|
||||
nsCOMPtr<nsIPrincipal> appPrin = BasePrincipal::CreateCodebasePrincipal(appURI, attrs);
|
||||
NS_ENSURE_TRUE(appPrin, nsIPrincipal::APP_STATUS_NOT_INSTALLED);
|
||||
return aPrin->Equals(appPrin) ? status
|
||||
: nsIPrincipal::APP_STATUS_NOT_INSTALLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* GetChannelResultPrincipal will return the principal that the resource
|
||||
* returned by this channel will use. For example, if the resource is in
|
||||
|
@ -67,8 +67,6 @@ public:
|
||||
static bool SecurityCompareURIs(nsIURI* aSourceURI, nsIURI* aTargetURI);
|
||||
static uint32_t SecurityHashURI(nsIURI* aURI);
|
||||
|
||||
static uint16_t AppStatusForPrincipal(nsIPrincipal *aPrin);
|
||||
|
||||
static nsresult
|
||||
ReportError(JSContext* cx, const nsAString& messageTag,
|
||||
nsIURI* aSource, nsIURI* aTarget);
|
||||
|
@ -192,7 +192,6 @@
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "nsDOMNavigationTiming.h"
|
||||
#include "nsISecurityUITelemetry.h"
|
||||
#include "nsIAppsService.h"
|
||||
#include "nsDSURIContentListener.h"
|
||||
#include "nsDocShellLoadTypes.h"
|
||||
#include "nsDocShellTransferableHooks.h"
|
||||
|
@ -1,114 +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/. */
|
||||
|
||||
"use strict"
|
||||
|
||||
function debug(s) {
|
||||
//dump("-*- AppsService.js: " + s + "\n");
|
||||
}
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
|
||||
const APPS_SERVICE_CID = Components.ID("{05072afa-92fe-45bf-ae22-39b69c117058}");
|
||||
|
||||
function AppsService()
|
||||
{
|
||||
debug("AppsService Constructor");
|
||||
this.inParent = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
|
||||
.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
|
||||
debug("inParent: " + this.inParent);
|
||||
if (!this.inParent) {
|
||||
Cu.import("resource://gre/modules/AppsServiceChild.jsm");
|
||||
}
|
||||
}
|
||||
|
||||
AppsService.prototype = {
|
||||
|
||||
isInvalidId: function(localId) {
|
||||
return (localId == Ci.nsIScriptSecurityManager.NO_APP_ID ||
|
||||
localId == Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID);
|
||||
},
|
||||
|
||||
getAppByManifestURL: function getAppByManifestURL(aManifestURL) {
|
||||
debug("GetAppByManifestURL( " + aManifestURL + " )");
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
|
||||
getManifestFor: function getManifestFor(aManifestURL) {
|
||||
debug("getManifestFor(" + aManifestURL + ")");
|
||||
if (this.inParent) {
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
} else {
|
||||
return Promise.reject(
|
||||
new Error("Calling getManifestFor() from child is not supported"));
|
||||
}
|
||||
},
|
||||
|
||||
getAppLocalIdByManifestURL: function getAppLocalIdByManifestURL(aManifestURL) {
|
||||
debug("getAppLocalIdByManifestURL( " + aManifestURL + " )");
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
|
||||
getAppLocalIdByStoreId: function getAppLocalIdByStoreId(aStoreId) {
|
||||
debug("getAppLocalIdByStoreId( " + aStoreId + " )");
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
|
||||
getAppByLocalId: function getAppByLocalId(aLocalId) {
|
||||
debug("getAppByLocalId( " + aLocalId + " )");
|
||||
if (this.isInvalidId(aLocalId)) {
|
||||
return null;
|
||||
}
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
|
||||
getManifestURLByLocalId: function getManifestURLByLocalId(aLocalId) {
|
||||
debug("getManifestURLByLocalId( " + aLocalId + " )");
|
||||
if (this.isInvalidId(aLocalId)) {
|
||||
return null;
|
||||
}
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
|
||||
getCoreAppsBasePath: function getCoreAppsBasePath() {
|
||||
debug("getCoreAppsBasePath()");
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
|
||||
getWebAppsBasePath: function getWebAppsBasePath() {
|
||||
debug("getWebAppsBasePath()");
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
|
||||
areAnyAppsInstalled: function() {
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
|
||||
getAppInfo: function getAppInfo(aAppId) {
|
||||
debug("getAppInfo()");
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
|
||||
getScopeByLocalId: function(aLocalId) {
|
||||
debug("getScopeByLocalId( " + aLocalId + " )");
|
||||
if (this.isInvalidId(aLocalId)) {
|
||||
return null;
|
||||
}
|
||||
// TODO : implement properly!
|
||||
// We just return null for now to not break PushService.jsm
|
||||
return null;
|
||||
},
|
||||
|
||||
classID : APPS_SERVICE_CID,
|
||||
QueryInterface : XPCOMUtils.generateQI([Ci.nsIAppsService])
|
||||
}
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AppsService])
|
@ -1,2 +0,0 @@
|
||||
component {05072afa-92fe-45bf-ae22-39b69c117058} AppsService.js
|
||||
contract @mozilla.org/AppsService;1 {05072afa-92fe-45bf-ae22-39b69c117058}
|
@ -1,408 +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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const Cu = Components.utils;
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
// This module exposes a subset of the functionalities of the parent DOM
|
||||
// Registry to content processes, to be used from the AppsService component.
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["DOMApplicationRegistry", "WrappedManifestCache"];
|
||||
|
||||
Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function debug(s) {
|
||||
//dump("-*- AppsServiceChild.jsm: " + s + "\n");
|
||||
}
|
||||
|
||||
const APPS_IPC_MSG_NAMES = [
|
||||
"Webapps:AddApp",
|
||||
"Webapps:RemoveApp",
|
||||
"Webapps:UpdateApp",
|
||||
"Webapps:CheckForUpdate:Return:KO",
|
||||
"Webapps:FireEvent",
|
||||
"Webapps:UpdateState"
|
||||
];
|
||||
|
||||
// A simple cache for the wrapped manifests.
|
||||
this.WrappedManifestCache = {
|
||||
_cache: { },
|
||||
|
||||
// Gets an entry from the cache, and populates the cache if needed.
|
||||
get: function mcache_get(aManifestURL, aManifest, aWindow, aInnerWindowID) {
|
||||
if (!aManifest) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(aManifestURL in this._cache)) {
|
||||
this._cache[aManifestURL] = { };
|
||||
}
|
||||
|
||||
let winObjs = this._cache[aManifestURL];
|
||||
if (!(aInnerWindowID in winObjs)) {
|
||||
winObjs[aInnerWindowID] = Cu.cloneInto(aManifest, aWindow);
|
||||
}
|
||||
|
||||
return winObjs[aInnerWindowID];
|
||||
},
|
||||
|
||||
// Invalidates an entry in the cache.
|
||||
evict: function mcache_evict(aManifestURL, aInnerWindowID) {
|
||||
debug("Evicting manifest " + aManifestURL + " window ID " +
|
||||
aInnerWindowID);
|
||||
if (aManifestURL in this._cache) {
|
||||
let winObjs = this._cache[aManifestURL];
|
||||
if (aInnerWindowID in winObjs) {
|
||||
delete winObjs[aInnerWindowID];
|
||||
}
|
||||
|
||||
if (Object.keys(winObjs).length == 0) {
|
||||
delete this._cache[aManifestURL];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
// Clear the cache on memory pressure.
|
||||
this._cache = { };
|
||||
Cu.forceGC();
|
||||
},
|
||||
|
||||
init: function() {
|
||||
Services.obs.addObserver(this, "memory-pressure", false);
|
||||
}
|
||||
};
|
||||
|
||||
this.WrappedManifestCache.init();
|
||||
|
||||
|
||||
// DOMApplicationRegistry keeps a cache containing a list of apps in the device.
|
||||
// This information is updated with the data received from the main process and
|
||||
// it is queried by the DOM objects to set their state.
|
||||
// This module handle all the messages broadcasted from the parent process,
|
||||
// including DOM events, which are dispatched to the corresponding DOM objects.
|
||||
|
||||
this.DOMApplicationRegistry = {
|
||||
// DOMApps will hold a list of arrays of weak references to
|
||||
// mozIDOMApplication objects indexed by manifest URL.
|
||||
DOMApps: {},
|
||||
|
||||
ready: false,
|
||||
webapps: null,
|
||||
|
||||
init: function init() {
|
||||
this.cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
|
||||
.getService(Ci.nsISyncMessageSender);
|
||||
|
||||
APPS_IPC_MSG_NAMES.forEach((function(aMsgName) {
|
||||
this.cpmm.addMessageListener(aMsgName, this);
|
||||
}).bind(this));
|
||||
|
||||
this.webapps = { };
|
||||
// We need a fast mapping from localId -> app, so we add an index.
|
||||
// We also add the manifest to the app object.
|
||||
this.localIdIndex = { };
|
||||
for (let id in this.webapps) {
|
||||
let app = this.webapps[id];
|
||||
this.localIdIndex[app.localId] = app;
|
||||
app.manifest = list.manifests[id];
|
||||
}
|
||||
|
||||
Services.obs.addObserver(this, "xpcom-shutdown", false);
|
||||
},
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
// cpmm.addMessageListener causes the DOMApplicationRegistry object to
|
||||
// live forever if we don't clean up properly.
|
||||
this.webapps = null;
|
||||
this.DOMApps = null;
|
||||
|
||||
APPS_IPC_MSG_NAMES.forEach((aMsgName) => {
|
||||
this.cpmm.removeMessageListener(aMsgName, this);
|
||||
});
|
||||
},
|
||||
|
||||
receiveMessage: function receiveMessage(aMessage) {
|
||||
debug("Received " + aMessage.name + " message.");
|
||||
let msg = aMessage.data;
|
||||
switch (aMessage.name) {
|
||||
case "Webapps:AddApp":
|
||||
this.webapps[msg.id] = msg.app;
|
||||
this.localIdIndex[msg.app.localId] = msg.app;
|
||||
if (msg.manifest) {
|
||||
this.webapps[msg.id].manifest = msg.manifest;
|
||||
}
|
||||
break;
|
||||
case "Webapps:RemoveApp":
|
||||
delete this.DOMApps[this.webapps[msg.id].manifestURL];
|
||||
delete this.localIdIndex[this.webapps[msg.id].localId];
|
||||
delete this.webapps[msg.id];
|
||||
break;
|
||||
case "Webapps:UpdateApp":
|
||||
let app = this.webapps[msg.oldId];
|
||||
if (!app) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg.app) {
|
||||
for (let prop in msg.app) {
|
||||
app[prop] = msg.app[prop];
|
||||
}
|
||||
}
|
||||
|
||||
this.webapps[msg.newId] = app;
|
||||
this.localIdIndex[app.localId] = app;
|
||||
delete this.webapps[msg.oldId];
|
||||
|
||||
let apps = this.DOMApps[msg.app.manifestURL];
|
||||
if (!apps) {
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < apps.length; i++) {
|
||||
let domApp = apps[i].get();
|
||||
if (!domApp || domApp._window === null) {
|
||||
apps.splice(i, 1);
|
||||
continue;
|
||||
}
|
||||
domApp._proxy = new Proxy(domApp, {
|
||||
get: function(target, prop) {
|
||||
if (!DOMApplicationRegistry.webapps[msg.newId]) {
|
||||
return;
|
||||
}
|
||||
return DOMApplicationRegistry.webapps[msg.newId][prop];
|
||||
},
|
||||
set: function(target, prop, val) {
|
||||
if (!DOMApplicationRegistry.webapps[msg.newId]) {
|
||||
return;
|
||||
}
|
||||
DOMApplicationRegistry.webapps[msg.newId][prop] = val;
|
||||
return;
|
||||
},
|
||||
});
|
||||
}
|
||||
break;
|
||||
case "Webapps:FireEvent":
|
||||
this._fireEvent(aMessage);
|
||||
break;
|
||||
case "Webapps:UpdateState":
|
||||
this._updateState(msg);
|
||||
break;
|
||||
case "Webapps:CheckForUpdate:Return:KO":
|
||||
let DOMApps = this.DOMApps[msg.manifestURL];
|
||||
if (!DOMApps || !msg.requestID) {
|
||||
return;
|
||||
}
|
||||
DOMApps.forEach((DOMApp) => {
|
||||
let domApp = DOMApp.get();
|
||||
if (domApp && msg.requestID) {
|
||||
domApp._fireRequestResult(aMessage, true /* aIsError */);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* mozIDOMApplication management
|
||||
*/
|
||||
|
||||
// Every time a DOM app is created, we save a weak reference to it that will
|
||||
// be used to dispatch events and fire request results.
|
||||
addDOMApp: function(aApp, aManifestURL, aId) {
|
||||
let weakRef = Cu.getWeakReference(aApp);
|
||||
|
||||
if (!this.DOMApps[aManifestURL]) {
|
||||
this.DOMApps[aManifestURL] = [];
|
||||
}
|
||||
|
||||
let apps = this.DOMApps[aManifestURL];
|
||||
|
||||
// Get rid of dead weak references.
|
||||
for (let i = 0; i < apps.length; i++) {
|
||||
let app = apps[i].get();
|
||||
if (!app || app._window === null) {
|
||||
apps.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
apps.push(weakRef);
|
||||
|
||||
// Each DOM app contains a proxy object used to build their state. We
|
||||
// return the handler for this proxy object with traps to get and set
|
||||
// app properties kept in the DOMApplicationRegistry app cache.
|
||||
return {
|
||||
get: function(target, prop) {
|
||||
if (!DOMApplicationRegistry.webapps[aId]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (prop in DOMApplicationRegistry.webapps[aId]) {
|
||||
return DOMApplicationRegistry.webapps[aId][prop];
|
||||
}
|
||||
return null;
|
||||
},
|
||||
set: function(target, prop, val) {
|
||||
if (!DOMApplicationRegistry.webapps[aId]) {
|
||||
return;
|
||||
}
|
||||
DOMApplicationRegistry.webapps[aId][prop] = val;
|
||||
return;
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
_fireEvent: function(aMessage) {
|
||||
let msg = aMessage.data;
|
||||
debug("_fireEvent " + JSON.stringify(msg));
|
||||
if (!this.DOMApps || !msg.manifestURL || !msg.eventType) {
|
||||
return;
|
||||
}
|
||||
|
||||
let DOMApps = this.DOMApps[msg.manifestURL];
|
||||
if (!DOMApps) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The parent might ask childs to trigger more than one event in one
|
||||
// shot, so in order to avoid needless IPC we allow an array for the
|
||||
// 'eventType' IPC message field.
|
||||
if (!Array.isArray(msg.eventType)) {
|
||||
msg.eventType = [msg.eventType];
|
||||
}
|
||||
|
||||
DOMApps.forEach((DOMApp) => {
|
||||
let domApp = DOMApp.get();
|
||||
if (!domApp) {
|
||||
return;
|
||||
}
|
||||
msg.eventType.forEach((aEventType) => {
|
||||
if ('on' + aEventType in domApp) {
|
||||
domApp._fireEvent(aEventType);
|
||||
}
|
||||
});
|
||||
|
||||
if (msg.requestID) {
|
||||
aMessage.data.result = msg.manifestURL;
|
||||
domApp._fireRequestResult(aMessage);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_updateState: function(aMessage) {
|
||||
if (!this.DOMApps || !aMessage.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
let app = this.webapps[aMessage.id];
|
||||
if (!app) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aMessage.app) {
|
||||
for (let prop in aMessage.app) {
|
||||
app[prop] = aMessage.app[prop];
|
||||
}
|
||||
}
|
||||
|
||||
if ("error" in aMessage) {
|
||||
app.downloadError = aMessage.error;
|
||||
}
|
||||
|
||||
if (aMessage.manifest) {
|
||||
app.manifest = aMessage.manifest;
|
||||
// Evict the wrapped manifest cache for all the affected DOM objects.
|
||||
let DOMApps = this.DOMApps[app.manifestURL];
|
||||
if (!DOMApps) {
|
||||
return;
|
||||
}
|
||||
DOMApps.forEach((DOMApp) => {
|
||||
let domApp = DOMApp.get();
|
||||
if (!domApp) {
|
||||
return;
|
||||
}
|
||||
WrappedManifestCache.evict(app.manifestURL, domApp.innerWindowID);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
getAll: function(aCallback) {
|
||||
debug("getAll()\n");
|
||||
if (!aCallback || typeof aCallback !== "function") {
|
||||
return;
|
||||
}
|
||||
|
||||
let res = [];
|
||||
for (let id in this.webapps) {
|
||||
res.push(this.webapps[id]);
|
||||
}
|
||||
aCallback(res);
|
||||
},
|
||||
|
||||
getAdditionalLanguages: function(aManifestURL) {
|
||||
for (let id in this.webapps) {
|
||||
if (this.webapps[id].manifestURL == aManifestURL) {
|
||||
return this.webapps[id].additionalLanguages || {};
|
||||
}
|
||||
}
|
||||
return {};
|
||||
},
|
||||
|
||||
/**
|
||||
* nsIAppsService API
|
||||
*/
|
||||
getAppByManifestURL: function getAppByManifestURL(aManifestURL) {
|
||||
debug("getAppByManifestURL " + aManifestURL);
|
||||
return AppsUtils.getAppByManifestURL(this.webapps, aManifestURL);
|
||||
},
|
||||
|
||||
getAppLocalIdByManifestURL: function getAppLocalIdByManifestURL(aManifestURL) {
|
||||
debug("getAppLocalIdByManifestURL " + aManifestURL);
|
||||
return AppsUtils.getAppLocalIdByManifestURL(this.webapps, aManifestURL);
|
||||
},
|
||||
|
||||
getAppLocalIdByStoreId: function(aStoreId) {
|
||||
debug("getAppLocalIdByStoreId:" + aStoreId);
|
||||
return AppsUtils.getAppLocalIdByStoreId(this.webapps, aStoreId);
|
||||
},
|
||||
|
||||
getAppByLocalId: function getAppByLocalId(aLocalId) {
|
||||
debug("getAppByLocalId " + aLocalId + " - ready: " + this.ready);
|
||||
let app = this.localIdIndex[aLocalId];
|
||||
if (!app) {
|
||||
debug("Ouch, No app!");
|
||||
return null;
|
||||
}
|
||||
|
||||
return new mozIApplication(app);
|
||||
},
|
||||
|
||||
getManifestURLByLocalId: function getManifestURLByLocalId(aLocalId) {
|
||||
debug("getManifestURLByLocalId " + aLocalId);
|
||||
return AppsUtils.getManifestURLByLocalId(this.webapps, aLocalId);
|
||||
},
|
||||
|
||||
getCoreAppsBasePath: function getCoreAppsBasePath() {
|
||||
debug("getCoreAppsBasePath() not yet supported on child!");
|
||||
return null;
|
||||
},
|
||||
|
||||
getWebAppsBasePath: function getWebAppsBasePath() {
|
||||
debug("getWebAppsBasePath() not yet supported on child!");
|
||||
return null;
|
||||
},
|
||||
|
||||
areAnyAppsInstalled: function() {
|
||||
return AppsUtils.areAnyAppsInstalled(this.webapps);
|
||||
},
|
||||
|
||||
getAppInfo: function getAppInfo(aAppId) {
|
||||
return AppsUtils.getAppInfo(this.webapps, aAppId);
|
||||
}
|
||||
}
|
||||
|
||||
DOMApplicationRegistry.init();
|
@ -19,14 +19,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "appsService",
|
||||
"@mozilla.org/AppsService;1",
|
||||
"nsIAppsService");
|
||||
|
||||
// Shared code for AppsServiceChild.jsm, Webapps.jsm and Webapps.js
|
||||
// Shared code for Webapps.jsm and Webapps.js
|
||||
|
||||
this.EXPORTED_SYMBOLS =
|
||||
["AppsUtils", "ManifestHelper", "isAbsoluteURI", "mozIApplication"];
|
||||
["AppsUtils", "ManifestHelper", "isAbsoluteURI"];
|
||||
|
||||
function debug(s) {
|
||||
//dump("-*- AppsUtils.jsm: " + s + "\n");
|
||||
@ -39,46 +35,6 @@ this.isAbsoluteURI = function(aURI) {
|
||||
Services.io.newURI(aURI, null, bar).prePath != bar.prePath;
|
||||
}
|
||||
|
||||
this.mozIApplication = function(aApp) {
|
||||
_setAppProperties(this, aApp);
|
||||
}
|
||||
|
||||
mozIApplication.prototype = {
|
||||
hasPermission: function(aPermission) {
|
||||
// This helper checks an URI inside |aApp|'s origin and part of |aApp| has a
|
||||
// specific permission. It is not checking if browsers inside |aApp| have such
|
||||
// permission.
|
||||
let perm = Services.perms.testExactPermissionFromPrincipal(this.principal,
|
||||
aPermission);
|
||||
return (perm === Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
},
|
||||
|
||||
get principal() {
|
||||
if (this._principal) {
|
||||
return this._principal;
|
||||
}
|
||||
|
||||
this._principal = null;
|
||||
|
||||
try {
|
||||
this._principal = Services.scriptSecurityManager.createCodebasePrincipal(
|
||||
Services.io.newURI(this.origin, null, null),
|
||||
{appId: this.localId});
|
||||
} catch(e) {
|
||||
dump("Could not create app principal " + e + "\n");
|
||||
}
|
||||
|
||||
return this._principal;
|
||||
},
|
||||
|
||||
QueryInterface: function(aIID) {
|
||||
if (aIID.equals(Ci.mozIApplication) ||
|
||||
aIID.equals(Ci.nsISupports))
|
||||
return this;
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
function _setAppProperties(aObj, aApp) {
|
||||
aObj.name = aApp.name;
|
||||
aObj.csp = aApp.csp;
|
||||
@ -220,21 +176,6 @@ this.AppsUtils = {
|
||||
return aPagePath.substr(pathPos, pathLen);
|
||||
},
|
||||
|
||||
getAppByManifestURL: function getAppByManifestURL(aApps, aManifestURL) {
|
||||
debug("getAppByManifestURL " + aManifestURL);
|
||||
// This could be O(1) if |webapps| was a dictionary indexed on manifestURL
|
||||
// which should be the unique app identifier.
|
||||
// It's currently O(n).
|
||||
for (let id in aApps) {
|
||||
let app = aApps[id];
|
||||
if (app.manifestURL == aManifestURL) {
|
||||
return new mozIApplication(app);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
getManifestFor: function getManifestFor(aManifestURL) {
|
||||
debug("getManifestFor(" + aManifestURL + ")");
|
||||
return DOMApplicationRegistry.getManifestFor(aManifestURL);
|
||||
@ -262,18 +203,6 @@ this.AppsUtils = {
|
||||
return Ci.nsIScriptSecurityManager.NO_APP_ID;
|
||||
},
|
||||
|
||||
getAppByLocalId: function getAppByLocalId(aApps, aLocalId) {
|
||||
debug("getAppByLocalId " + aLocalId);
|
||||
for (let id in aApps) {
|
||||
let app = aApps[id];
|
||||
if (app.localId == aLocalId) {
|
||||
return new mozIApplication(app);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
getManifestURLByLocalId: function getManifestURLByLocalId(aApps, aLocalId) {
|
||||
debug("getManifestURLByLocalId " + aLocalId);
|
||||
for (let id in aApps) {
|
||||
@ -702,15 +631,6 @@ this.AppsUtils = {
|
||||
computeObjectHash: function(aObject) {
|
||||
return this.computeHash(JSON.stringify(aObject));
|
||||
},
|
||||
|
||||
getAppManifestURLFromWindow: function(aWindow) {
|
||||
let appId = aWindow.document.nodePrincipal.appId;
|
||||
if (appId === Ci.nsIScriptSecurityManager.NO_APP_ID) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return appsService.getManifestURLByLocalId(appId);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,210 +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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||
Cu.import("resource://gre/modules/PermissionSettings.jsm");
|
||||
Cu.import("resource://gre/modules/PermissionsTable.jsm");
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["PermissionsInstaller"];
|
||||
const UNKNOWN_ACTION = Ci.nsIPermissionManager.UNKNOWN_ACTION;
|
||||
const ALLOW_ACTION = Ci.nsIPermissionManager.ALLOW_ACTION;
|
||||
const DENY_ACTION = Ci.nsIPermissionManager.DENY_ACTION;
|
||||
const PROMPT_ACTION = Ci.nsIPermissionManager.PROMPT_ACTION;
|
||||
|
||||
// Permission access flags
|
||||
const READONLY = "readonly";
|
||||
const CREATEONLY = "createonly";
|
||||
const READCREATE = "readcreate";
|
||||
const READWRITE = "readwrite";
|
||||
|
||||
const PERM_TO_STRING = ["unknown", "allow", "deny", "prompt"];
|
||||
|
||||
function debug(aMsg) {
|
||||
//dump("-*-*- PermissionsInstaller.jsm : " + aMsg + "\n");
|
||||
}
|
||||
|
||||
this.PermissionsInstaller = {
|
||||
/**
|
||||
* Install permissisions or remove deprecated permissions upon re-install.
|
||||
* @param object aApp
|
||||
* The just-installed app configuration.
|
||||
* The properties used are manifestURL, origin and manifest.
|
||||
* @param boolean aIsReinstall
|
||||
* Indicates the app was just re-installed
|
||||
* @param function aOnError
|
||||
* A function called if an error occurs
|
||||
* @returns void
|
||||
**/
|
||||
installPermissions: function installPermissions(aApp, aIsReinstall,
|
||||
aOnError) {
|
||||
try {
|
||||
let newManifest =
|
||||
new ManifestHelper(aApp.manifest, aApp.origin, aApp.manifestURL);
|
||||
if (!newManifest.permissions && !aIsReinstall) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aIsReinstall) {
|
||||
// Compare the original permissions against the new permissions
|
||||
// Remove any deprecated Permissions
|
||||
|
||||
if (newManifest.permissions) {
|
||||
// Expand permission names.
|
||||
let newPermNames = [];
|
||||
for (let permName in newManifest.permissions) {
|
||||
let expandedPermNames =
|
||||
expandPermissions(permName,
|
||||
newManifest.permissions[permName].access);
|
||||
newPermNames = newPermNames.concat(expandedPermNames);
|
||||
}
|
||||
|
||||
newPermNames.push("indexedDB");
|
||||
|
||||
// Add the appcache related permissions.
|
||||
if (newManifest.appcache_path) {
|
||||
newPermNames = newPermNames.concat(["offline-app", "pin-app"]);
|
||||
}
|
||||
|
||||
for (let idx in AllPossiblePermissions) {
|
||||
let permName = AllPossiblePermissions[idx];
|
||||
let index = newPermNames.indexOf(permName);
|
||||
if (index == -1) {
|
||||
// See if the permission was installed previously.
|
||||
let permValue =
|
||||
PermissionSettingsModule.getPermission(permName,
|
||||
aApp.manifestURL,
|
||||
aApp.origin,
|
||||
false);
|
||||
if (permValue == "unknown" || permValue == "deny") {
|
||||
// All 'deny' permissions should be preserved
|
||||
continue;
|
||||
}
|
||||
// Remove the deprecated permission
|
||||
PermissionSettingsModule.removePermission(permName,
|
||||
aApp.manifestURL,
|
||||
aApp.origin,
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check to see if the 'webapp' is app/privileged/certified.
|
||||
let appStatus;
|
||||
switch (AppsUtils.getAppManifestStatus(aApp.manifest)) {
|
||||
case Ci.nsIPrincipal.APP_STATUS_CERTIFIED:
|
||||
appStatus = "certified";
|
||||
break;
|
||||
case Ci.nsIPrincipal.APP_STATUS_PRIVILEGED:
|
||||
appStatus = "privileged";
|
||||
break;
|
||||
case Ci.nsIPrincipal.APP_STATUS_INSTALLED:
|
||||
appStatus = "app";
|
||||
break;
|
||||
default:
|
||||
// Cannot determine app type, abort install by throwing an error.
|
||||
throw new Error("PermissionsInstaller.jsm: " +
|
||||
"Cannot determine the app's status. Install cancelled.");
|
||||
break;
|
||||
}
|
||||
|
||||
this._setPermission("indexedDB", "allow", aApp);
|
||||
|
||||
// Add the appcache related permissions. We allow it for all kinds of
|
||||
// apps.
|
||||
if (newManifest.appcache_path) {
|
||||
this._setPermission("offline-app", "allow", aApp);
|
||||
this._setPermission("pin-app", "allow", aApp);
|
||||
}
|
||||
|
||||
for (let permName in newManifest.permissions) {
|
||||
if (!PermissionsTable[permName]) {
|
||||
Cu.reportError("PermissionsInstaller.jsm: '" + permName + "'" +
|
||||
" is not a valid Webapps permission name.");
|
||||
dump("PermissionsInstaller.jsm: '" + permName + "'" +
|
||||
" is not a valid Webapps permission name.");
|
||||
continue;
|
||||
}
|
||||
|
||||
let expandedPermNames =
|
||||
expandPermissions(permName,
|
||||
newManifest.permissions[permName].access);
|
||||
for (let idx in expandedPermNames) {
|
||||
|
||||
let isPromptPermission =
|
||||
PermissionsTable[permName][appStatus] === PROMPT_ACTION;
|
||||
|
||||
// We silently upgrade the permission to whatever the permission
|
||||
// is for certified apps (ALLOW or PROMPT) only if the
|
||||
// following holds true:
|
||||
// * The app is preinstalled
|
||||
// * The permission that would be granted is PROMPT
|
||||
// * The app is privileged
|
||||
let permission =
|
||||
aApp.isPreinstalled && isPromptPermission &&
|
||||
appStatus === "privileged"
|
||||
? PermissionsTable[permName]["certified"]
|
||||
: PermissionsTable[permName][appStatus];
|
||||
|
||||
let permValue = PERM_TO_STRING[permission];
|
||||
if (isPromptPermission) {
|
||||
// If the permission is prompt, keep the current value. This will
|
||||
// work even on a system update, with the caveat that if a
|
||||
// ALLOW/DENY permission is changed to PROMPT then the system should
|
||||
// inform the user that he can now change a permission that he could
|
||||
// not change before.
|
||||
permValue =
|
||||
PermissionSettingsModule.getPermission(expandedPermNames[idx],
|
||||
aApp.manifestURL,
|
||||
aApp.origin,
|
||||
false,
|
||||
aApp.isCachedPackage);
|
||||
if (permValue === "unknown") {
|
||||
permValue = PERM_TO_STRING[permission];
|
||||
}
|
||||
}
|
||||
|
||||
this._setPermission(expandedPermNames[idx], permValue, aApp);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ex) {
|
||||
dump("Caught webapps install permissions error for " + aApp.origin +
|
||||
" : " + ex + "\n");
|
||||
Cu.reportError(ex);
|
||||
if (aOnError) {
|
||||
aOnError();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set a permission value.
|
||||
* @param string aPermName
|
||||
* The permission name.
|
||||
* @param string aPermValue
|
||||
* The permission value.
|
||||
* @param object aApp
|
||||
* The just-installed app configuration.
|
||||
* The properties used are manifestURL, origin, appId, isCachedPackage.
|
||||
* @returns void
|
||||
**/
|
||||
_setPermission: function setPermission(aPermName, aPermValue, aApp) {
|
||||
PermissionSettingsModule.addPermission({
|
||||
type: aPermName,
|
||||
origin: aApp.origin,
|
||||
manifestURL: aApp.manifestURL,
|
||||
value: aPermValue,
|
||||
browserFlag: false,
|
||||
localId: aApp.localId,
|
||||
isCachedPackage: aApp.isCachedPackage,
|
||||
});
|
||||
}
|
||||
};
|
@ -6,14 +6,7 @@
|
||||
|
||||
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'AppsService.js',
|
||||
'AppsService.manifest',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'AppsServiceChild.jsm',
|
||||
'PermissionsInstaller.jsm',
|
||||
'PermissionsTable.jsm',
|
||||
]
|
||||
|
||||
|
@ -1,64 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
var {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource:///modules/AppsUtils.jsm");
|
||||
|
||||
add_test(() => {
|
||||
let app = {
|
||||
name: "TestApp",
|
||||
csp: "aCsp",
|
||||
installOrigin: "http://installorigin.com",
|
||||
origin: "http://www.example.com",
|
||||
installTime: Date.now(),
|
||||
manifestURL: "http://www.example.com/manifest.webapp",
|
||||
appStatus: Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED,
|
||||
removable: false,
|
||||
id: 123,
|
||||
localId: 123,
|
||||
basePath: "/",
|
||||
progress: 1.0,
|
||||
installState: "installed",
|
||||
downloadAvailable: false,
|
||||
downloading: false,
|
||||
lastUpdateCheck: Date.now(),
|
||||
updateTime: Date.now(),
|
||||
etag: "aEtag",
|
||||
packageEtag: "aPackageEtag",
|
||||
manifestHash: "aManifestHash",
|
||||
packageHash: "aPackageHash",
|
||||
staged: false,
|
||||
installerAppId: 345,
|
||||
installerIsBrowser: false,
|
||||
storeId: "aStoreId",
|
||||
storeVersion: 1,
|
||||
role: "aRole",
|
||||
kind: "aKind",
|
||||
enabled: true,
|
||||
sideloaded: false
|
||||
};
|
||||
|
||||
let mozapp = new mozIApplication(app);
|
||||
|
||||
Object.keys(app).forEach((key) => {
|
||||
if (key == "principal") {
|
||||
return;
|
||||
}
|
||||
Assert.equal(app[key], mozapp[key],
|
||||
"app[" + key + "] should be equal to mozapp[" + key + "]");
|
||||
});
|
||||
|
||||
Assert.ok(mozapp.principal, "app principal should exist");
|
||||
let expectedPrincipalOrigin = app.origin + "^appId=" + app.localId;
|
||||
Assert.equal(mozapp.principal.origin, expectedPrincipalOrigin,
|
||||
"app principal origin ok");
|
||||
Assert.equal(mozapp.principal.appId, app.localId, "app principal appId ok");
|
||||
Assert.equal(mozapp.principal.isInIsolatedMozBrowserElement, false,
|
||||
"app principal isInIsolatedMozBrowserElement ok");
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
@ -2,4 +2,3 @@
|
||||
|
||||
[test_manifestSanitizer.js]
|
||||
[test_manifestHelper.js]
|
||||
[test_moziapplication.js]
|
||||
|
@ -69,7 +69,7 @@ ArchiveRequest::~ArchiveRequest()
|
||||
}
|
||||
|
||||
nsresult
|
||||
ArchiveRequest::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
ArchiveRequest::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mCanHandle = true;
|
||||
aVisitor.mParentTarget = nullptr;
|
||||
|
@ -38,7 +38,8 @@ public:
|
||||
ArchiveReader* aReader);
|
||||
|
||||
// nsIDOMEventTarget
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult GetEventTargetParent(
|
||||
EventChainPreVisitor& aVisitor) override;
|
||||
|
||||
public:
|
||||
// This is called by the DOMArchiveRequestEvent
|
||||
|
@ -346,7 +346,7 @@ Attr::RemoveChildAt(uint32_t aIndex, bool aNotify)
|
||||
}
|
||||
|
||||
nsresult
|
||||
Attr::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
Attr::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mCanHandle = true;
|
||||
return NS_OK;
|
||||
|
@ -54,7 +54,7 @@ public:
|
||||
// nsIDOMAttr interface
|
||||
NS_DECL_NSIDOMATTR
|
||||
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
|
||||
|
||||
// nsIAttribute interface
|
||||
void SetMap(nsDOMAttributeMap *aMap) override;
|
||||
|
@ -174,6 +174,13 @@ ChromeUtils::FillNonDefaultOriginAttributes(dom::GlobalObject& aGlobal,
|
||||
ChromeUtils::IsOriginAttributesEqual(dom::GlobalObject& aGlobal,
|
||||
const dom::OriginAttributesDictionary& aA,
|
||||
const dom::OriginAttributesDictionary& aB)
|
||||
{
|
||||
return IsOriginAttributesEqual(aA, aB);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
ChromeUtils::IsOriginAttributesEqual(const dom::OriginAttributesDictionary& aA,
|
||||
const dom::OriginAttributesDictionary& aB)
|
||||
{
|
||||
return aA.mAddonId == aB.mAddonId &&
|
||||
aA.mAppId == aB.mAppId &&
|
||||
|
@ -88,6 +88,10 @@ public:
|
||||
const dom::OriginAttributesDictionary& aA,
|
||||
const dom::OriginAttributesDictionary& aB);
|
||||
|
||||
static bool
|
||||
IsOriginAttributesEqual(const dom::OriginAttributesDictionary& aA,
|
||||
const dom::OriginAttributesDictionary& aB);
|
||||
|
||||
static bool
|
||||
IsOriginAttributesEqualIgnoringAddonId(const dom::OriginAttributesDictionary& aA,
|
||||
const dom::OriginAttributesDictionary& aB);
|
||||
|
@ -158,16 +158,24 @@ DOMIntersectionObserver::Observe(Element& aTarget)
|
||||
|
||||
void
|
||||
DOMIntersectionObserver::Unobserve(Element& aTarget)
|
||||
{
|
||||
if (UnlinkTarget(aTarget)) {
|
||||
aTarget.UnregisterIntersectionObserver(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
DOMIntersectionObserver::UnlinkTarget(Element& aTarget)
|
||||
{
|
||||
if (!mObservationTargets.Contains(&aTarget)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (mObservationTargets.Count() == 1) {
|
||||
Disconnect();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
aTarget.UnregisterIntersectionObserver(this);
|
||||
mObservationTargets.RemoveEntry(&aTarget);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
@ -192,8 +200,10 @@ DOMIntersectionObserver::Disconnect()
|
||||
target->UnregisterIntersectionObserver(this);
|
||||
}
|
||||
mObservationTargets.Clear();
|
||||
if (mOwner) {
|
||||
nsIDocument* document = mOwner->GetExtantDoc();
|
||||
document->RemoveIntersectionObserver(this);
|
||||
}
|
||||
mConnected = false;
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,9 @@ protected:
|
||||
class DOMIntersectionObserver final : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
virtual ~DOMIntersectionObserver() { }
|
||||
virtual ~DOMIntersectionObserver() {
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
public:
|
||||
DOMIntersectionObserver(already_AddRefed<nsPIDOMWindowInner>&& aOwner,
|
||||
@ -142,7 +144,9 @@ public:
|
||||
void Observe(Element& aTarget);
|
||||
void Unobserve(Element& aTarget);
|
||||
|
||||
bool UnlinkTarget(Element& aTarget);
|
||||
void Disconnect();
|
||||
|
||||
void TakeRecords(nsTArray<RefPtr<DOMIntersectionObserverEntry>>& aRetVal);
|
||||
|
||||
mozilla::dom::IntersectionCallback* IntersectionCallback() { return mCallback; }
|
||||
|
@ -2991,7 +2991,7 @@ Element::CheckHandleEventForLinksPrecondition(EventChainVisitor& aVisitor,
|
||||
}
|
||||
|
||||
nsresult
|
||||
Element::PreHandleEventForLinks(EventChainPreVisitor& aVisitor)
|
||||
Element::GetEventTargetParentForLinks(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
// Optimisation: return early if this event doesn't interest us.
|
||||
// IMPORTANT: this switch and the switch below it must be kept in sync!
|
||||
@ -3013,8 +3013,9 @@ Element::PreHandleEventForLinks(EventChainPreVisitor& aVisitor)
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// We do the status bar updates in PreHandleEvent so that the status bar gets
|
||||
// updated even if the event is consumed before we have a chance to set it.
|
||||
// We do the status bar updates in GetEventTargetParent so that the status bar
|
||||
// gets updated even if the event is consumed before we have a chance to set
|
||||
// it.
|
||||
switch (aVisitor.mEvent->mMessage) {
|
||||
// Set the status bar similarly for mouseover and focus
|
||||
case eMouseOver:
|
||||
|
@ -773,6 +773,14 @@ public:
|
||||
(aRetargetToElement ? CAPTURE_RETARGETTOELEMENT : 0));
|
||||
}
|
||||
}
|
||||
|
||||
void SetCaptureAlways(bool aRetargetToElement)
|
||||
{
|
||||
nsIPresShell::SetCapturingContent(this,
|
||||
CAPTURE_PREVENTDRAG | CAPTURE_IGNOREALLOWED |
|
||||
(aRetargetToElement ? CAPTURE_RETARGETTOELEMENT : 0));
|
||||
}
|
||||
|
||||
void ReleaseCapture()
|
||||
{
|
||||
if (nsIPresShell::GetCapturingContent() == this) {
|
||||
@ -1346,7 +1354,7 @@ protected:
|
||||
/**
|
||||
* Handle status bar updates before they can be cancelled.
|
||||
*/
|
||||
nsresult PreHandleEventForLinks(EventChainPreVisitor& aVisitor);
|
||||
nsresult GetEventTargetParentForLinks(EventChainPreVisitor& aVisitor);
|
||||
|
||||
/**
|
||||
* Handle default actions for link event if the event isn't consumed yet.
|
||||
|
@ -675,7 +675,7 @@ FindChromeAccessOnlySubtreeOwner(nsIContent* aContent)
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
//FIXME! Document how this event retargeting works, Bug 329124.
|
||||
aVisitor.mCanHandle = true;
|
||||
|
@ -67,7 +67,6 @@
|
||||
#include "TimeManager.h"
|
||||
#include "DeviceStorage.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsIAppsService.h"
|
||||
#include "WidgetUtils.h"
|
||||
#include "nsIPresentationService.h"
|
||||
|
||||
|
@ -7604,7 +7604,7 @@ nsDocument::GetExistingListenerManager() const
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDocument::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
nsDocument::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mCanHandle = true;
|
||||
// FIXME! This is a hack to make middle mouse paste working also in Editor.
|
||||
|
@ -803,7 +803,7 @@ public:
|
||||
NS_DECL_NSIDOMDOCUMENTXBL
|
||||
|
||||
// nsIDOMEventTarget
|
||||
virtual nsresult PreHandleEvent(
|
||||
virtual nsresult GetEventTargetParent(
|
||||
mozilla::EventChainPreVisitor& aVisitor) override;
|
||||
virtual mozilla::EventListenerManager*
|
||||
GetOrCreateListenerManager() override;
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "prenv.h"
|
||||
|
||||
#include "nsDocShell.h"
|
||||
#include "nsIAppsService.h"
|
||||
#include "nsIDOMHTMLIFrameElement.h"
|
||||
#include "nsIDOMHTMLFrameElement.h"
|
||||
#include "nsIDOMMozBrowserFrame.h"
|
||||
|
@ -46,7 +46,7 @@ public:
|
||||
virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
|
||||
virtual EventStates IntrinsicState() const override;
|
||||
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override
|
||||
virtual nsresult GetEventTargetParent(EventChainPreVisitor& aVisitor) override
|
||||
{
|
||||
MOZ_ASSERT(IsInNativeAnonymousSubtree());
|
||||
if (aVisitor.mEvent->mMessage == eLoad ||
|
||||
@ -54,7 +54,7 @@ public:
|
||||
// Don't propagate the events to the parent.
|
||||
return NS_OK;
|
||||
}
|
||||
return nsXMLElement::PreHandleEvent(aVisitor);
|
||||
return nsXMLElement::GetEventTargetParent(aVisitor);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -3312,9 +3312,10 @@ nsGlobalWindow::WillHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGlobalWindow::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
nsGlobalWindow::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
NS_PRECONDITION(IsInnerWindow(), "PreHandleEvent is used on outer window!?");
|
||||
NS_PRECONDITION(IsInnerWindow(),
|
||||
"GetEventTargetParent is used on outer window!?");
|
||||
EventMessage msg = aVisitor.mEvent->mMessage;
|
||||
|
||||
aVisitor.mCanHandle = true;
|
||||
@ -3547,7 +3548,7 @@ nsGlobalWindow::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
} else if (aVisitor.mEvent->mMessage == eLoad &&
|
||||
aVisitor.mEvent->IsTrusted()) {
|
||||
// This is page load event since load events don't propagate to |window|.
|
||||
// @see nsDocument::PreHandleEvent.
|
||||
// @see nsDocument::GetEventTargetParent.
|
||||
mIsDocumentLoaded = true;
|
||||
|
||||
nsCOMPtr<Element> element = GetOuterWindow()->GetFrameElementInternal();
|
||||
|
@ -976,7 +976,7 @@ public:
|
||||
// Overloaded from nsINode
|
||||
virtual already_AddRefed<nsIURI> GetBaseURI(bool aTryUseXHRDocBaseURI = false) const override;
|
||||
|
||||
virtual nsresult PreHandleEvent(
|
||||
virtual nsresult GetEventTargetParent(
|
||||
mozilla::EventChainPreVisitor& aVisitor) override;
|
||||
|
||||
virtual bool IsPurple() = 0;
|
||||
|
@ -1242,7 +1242,7 @@ nsINode::RemoveEventListener(const nsAString& aType,
|
||||
NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsINode)
|
||||
|
||||
nsresult
|
||||
nsINode::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
nsINode::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
// This is only here so that we can use the NS_DECL_NSIDOMTARGET macro
|
||||
NS_ABORT();
|
||||
|
@ -97,7 +97,7 @@ nsInProcessTabChildGlobal::nsInProcessTabChildGlobal(nsIDocShell* aShell,
|
||||
mozilla::HoldJSObjects(this);
|
||||
|
||||
// If owner corresponds to an <iframe mozbrowser>, we'll have to tweak our
|
||||
// PreHandleEvent implementation.
|
||||
// GetEventTargetParent implementation.
|
||||
nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwner);
|
||||
if (browserFrame) {
|
||||
mIsBrowserFrame = browserFrame->GetReallyIsBrowser();
|
||||
@ -251,7 +251,7 @@ nsInProcessTabChildGlobal::GetOwnerContent()
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsInProcessTabChildGlobal::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
nsInProcessTabChildGlobal::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mForceContentDispatch = true;
|
||||
aVisitor.mCanHandle = true;
|
||||
|
@ -96,7 +96,7 @@ public:
|
||||
JS::Handle<JSObject *> aCpows,
|
||||
nsIPrincipal* aPrincipal) override;
|
||||
|
||||
virtual nsresult PreHandleEvent(
|
||||
virtual nsresult GetEventTargetParent(
|
||||
mozilla::EventChainPreVisitor& aVisitor) override;
|
||||
NS_IMETHOD AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
@ -167,7 +167,7 @@ protected:
|
||||
bool mLoadingScript;
|
||||
|
||||
// Is this the message manager for an in-process <iframe mozbrowser>? This
|
||||
// affects where events get sent, so it affects PreHandleEvent.
|
||||
// affects where events get sent, so it affects GetEventTargetParent.
|
||||
bool mIsBrowserFrame;
|
||||
bool mPreventEventsEscaping;
|
||||
|
||||
|
@ -297,6 +297,15 @@ nsNodeUtils::LastRelease(nsINode* aNode)
|
||||
NodeWillBeDestroyed, (aNode));
|
||||
}
|
||||
|
||||
if (aNode->IsElement()) {
|
||||
Element* elem = aNode->AsElement();
|
||||
FragmentOrElement::nsDOMSlots* domSlots =
|
||||
static_cast<FragmentOrElement::nsDOMSlots*>(slots);
|
||||
for (auto& reg : domSlots->mRegisteredIntersectionObservers) {
|
||||
reg.observer->UnlinkTarget(*elem);
|
||||
}
|
||||
}
|
||||
|
||||
delete slots;
|
||||
aNode->mSlots = nullptr;
|
||||
}
|
||||
|
@ -180,7 +180,7 @@ nsWindowRoot::GetContextForEventHandlers(nsresult* aRv)
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsWindowRoot::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
nsWindowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mCanHandle = true;
|
||||
aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119
|
||||
|
@ -95,7 +95,8 @@ Test swapFrameLoaders with different frame types and remoteness
|
||||
add_task(function*() {
|
||||
yield new Promise(resolve => {
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ "set": [["dom.mozBrowserFramesEnabled", true]] },
|
||||
{ "set": [["dom.mozBrowserFramesEnabled", true],
|
||||
["network.disable.ipc.security", true]] },
|
||||
resolve);
|
||||
});
|
||||
});
|
||||
|
@ -24,6 +24,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1022229
|
||||
chunk in iframe_main as well. */
|
||||
/*
|
||||
SpecialPowers.Services.prefs.setBoolPref("dom.mozBrowserFramesEnabled", true);
|
||||
SpecialPowers.Services.prefs.setBoolPref("network.disable.ipc.security", true);
|
||||
SpecialPowers.Services.prefs.setBoolPref("dom.ipc.browser_frames.oop_by_default", false);
|
||||
SpecialPowers.addPermission("browser", true, document);
|
||||
SpecialPowers.wrap(ifr).mozbrowser = true;
|
||||
|
@ -133,6 +133,7 @@
|
||||
"set": [
|
||||
["dom.ipc.browser_frames.oop_by_default", true],
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["network.disable.ipc.security", true],
|
||||
["browser.pagethumbnails.capturing_disabled", true]
|
||||
]
|
||||
}, runTests);
|
||||
|
@ -85,6 +85,7 @@
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["network.disable.ipc.security", true],
|
||||
["browser.pagethumbnails.capturing_disabled", true]
|
||||
]
|
||||
}, runTests);
|
||||
|
@ -121,6 +121,7 @@
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["network.disable.ipc.security", true],
|
||||
["browser.pagethumbnails.capturing_disabled", true]
|
||||
]
|
||||
}, runTests);
|
||||
|
@ -115,6 +115,7 @@
|
||||
SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["network.disable.ipc.security", true],
|
||||
["dom.ipc.browser_frames.oop_by_default", false],
|
||||
]
|
||||
}, runTests);
|
||||
|
@ -13,7 +13,8 @@
|
||||
add_task(function*() {
|
||||
yield new Promise(resolve => {
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ "set": [["dom.mozBrowserFramesEnabled", true]] },
|
||||
{ "set": [["dom.mozBrowserFramesEnabled", true],
|
||||
["network.disable.ipc.security", true]] },
|
||||
resolve);
|
||||
});
|
||||
});
|
||||
|
@ -13,7 +13,8 @@
|
||||
add_task(function*() {
|
||||
yield new Promise(resolve => {
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ "set": [["dom.mozBrowserFramesEnabled", true]] },
|
||||
{ "set": [["dom.mozBrowserFramesEnabled", true],
|
||||
["network.disable.ipc.security", true]] },
|
||||
resolve);
|
||||
});
|
||||
});
|
||||
|
@ -10,6 +10,12 @@
|
||||
<body>
|
||||
<iframe id="target-iframe"></iframe>
|
||||
<script type="application/javascript">
|
||||
|
||||
add_task(function*() {
|
||||
yield SpecialPowers.pushPrefEnv(
|
||||
{ "set": [["network.disable.ipc.security", true]] });
|
||||
});
|
||||
|
||||
add_task(function*() {
|
||||
let iframe = document.querySelector("#target-iframe");
|
||||
|
||||
|
@ -62,7 +62,8 @@ const browserElementTestHelpers = {
|
||||
},
|
||||
|
||||
setEnabledPref: function(value) {
|
||||
this._setPref('dom.mozBrowserFramesEnabled', value);
|
||||
this._setPrefs(['dom.mozBrowserFramesEnabled', value],
|
||||
['network.disable.ipc.security', value]);
|
||||
},
|
||||
|
||||
setupAccessibleCaretPref: function() {
|
||||
|
@ -52,7 +52,8 @@
|
||||
SpecialPowers.addPermission("browser", true, document);
|
||||
SpecialPowers.pushPrefEnv({set: [
|
||||
["dom.ipc.browser_frames.oop_by_default", true],
|
||||
["dom.mozBrowserFramesEnabled", true]
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["network.disable.ipc.security", true]
|
||||
]}, runTest);
|
||||
});
|
||||
</script>
|
||||
|
@ -469,6 +469,7 @@ var gTestRunner = runTest();
|
||||
SpecialPowers.addPermission("browser", true, gTestUri);
|
||||
|
||||
SpecialPowers.pushPrefEnv({'set': [["dom.mozBrowserFramesEnabled", true],
|
||||
["network.disable.ipc.security", true],
|
||||
["device.storage.enabled", true],
|
||||
["device.storage.testing", true],
|
||||
["device.storage.prompt.testing", false]]},
|
||||
|
@ -586,6 +586,7 @@ let gTestRunner = runTest();
|
||||
SpecialPowers.addPermission("browser", true, gTestUri);
|
||||
|
||||
SpecialPowers.pushPrefEnv({'set': [["dom.mozBrowserFramesEnabled", true],
|
||||
["network.disable.ipc.security", true],
|
||||
["device.storage.enabled", true],
|
||||
["device.storage.testing", true],
|
||||
["device.storage.prompt.testing", false]]},
|
||||
|
@ -46,15 +46,6 @@ DOMDownloadManagerImpl.prototype = {
|
||||
this.initDOMRequestHelper(aWindow,
|
||||
["Downloads:Added",
|
||||
"Downloads:Removed"]);
|
||||
|
||||
// Get the manifest URL if this is an installed app
|
||||
let appsService = Cc["@mozilla.org/AppsService;1"]
|
||||
.getService(Ci.nsIAppsService);
|
||||
let principal = aWindow.document.nodePrincipal;
|
||||
// This returns the empty string if we're not an installed app. Coerce to
|
||||
// null.
|
||||
this._manifestURL = appsService.getManifestURLByLocalId(principal.appId) ||
|
||||
null;
|
||||
},
|
||||
|
||||
uninit: function() {
|
||||
@ -164,7 +155,7 @@ DOMDownloadManagerImpl.prototype = {
|
||||
path: computedPath,
|
||||
contentType: aAdoptDownloadDict.contentType,
|
||||
startTime: aAdoptDownloadDict.startTime.valueOf() || Date.now(),
|
||||
sourceAppManifestURL: this._manifestURL
|
||||
sourceAppManifestURL: ""
|
||||
};
|
||||
|
||||
DownloadsIPC.adoptDownload(jsonDownload).then(
|
||||
|
@ -329,7 +329,7 @@ DOMEventTargetHelper::GetEventHandler(nsIAtom* aType,
|
||||
}
|
||||
|
||||
nsresult
|
||||
DOMEventTargetHelper::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
DOMEventTargetHelper::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mCanHandle = true;
|
||||
aVisitor.mParentTarget = nullptr;
|
||||
|
@ -248,10 +248,10 @@ NS_DEFINE_STATIC_IID_ACCESSOR(DOMEventTargetHelper,
|
||||
|
||||
/* Use this macro to declare functions that forward the behavior of this
|
||||
* interface to another object.
|
||||
* This macro doesn't forward PreHandleEvent because sometimes subclasses
|
||||
* This macro doesn't forward GetEventTargetParent because sometimes subclasses
|
||||
* want to override it.
|
||||
*/
|
||||
#define NS_FORWARD_NSIDOMEVENTTARGET_NOPREHANDLEEVENT(_to) \
|
||||
#define NS_FORWARD_NSIDOMEVENTTARGET_NOGETEVENTTARGETPARENT(_to) \
|
||||
NS_IMETHOD AddEventListener(const nsAString & type, nsIDOMEventListener *listener, bool useCapture, bool wantsUntrusted, uint8_t _argc) { \
|
||||
return _to AddEventListener(type, listener, useCapture, wantsUntrusted, _argc); \
|
||||
} \
|
||||
|
@ -131,12 +131,6 @@ static bool IsEventTargetChrome(EventTarget* aEventTarget,
|
||||
}
|
||||
|
||||
|
||||
#define NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH (1 << 0)
|
||||
#define NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT (1 << 1)
|
||||
#define NS_TARGET_CHAIN_MAY_HAVE_MANAGER (1 << 2)
|
||||
#define NS_TARGET_CHAIN_CHECKED_IF_CHROME (1 << 3)
|
||||
#define NS_TARGET_CHAIN_IS_CHROME_CONTENT (1 << 4)
|
||||
|
||||
// EventTargetChainItem represents a single item in the event target chain.
|
||||
class EventTargetChainItem
|
||||
{
|
||||
@ -144,8 +138,7 @@ private:
|
||||
explicit EventTargetChainItem(EventTarget* aTarget);
|
||||
public:
|
||||
EventTargetChainItem()
|
||||
: mFlags(0)
|
||||
, mItemFlags(0)
|
||||
: mItemFlags(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -153,7 +146,8 @@ public:
|
||||
EventTarget* aTarget,
|
||||
EventTargetChainItem* aChild = nullptr)
|
||||
{
|
||||
MOZ_ASSERT(!aChild || &aChain.ElementAt(aChain.Length() - 1) == aChild);
|
||||
// The last item which can handle the event must be aChild.
|
||||
MOZ_ASSERT(GetLastCanHandleEventTarget(aChain) == aChild);
|
||||
return new (aChain.AppendElement()) EventTargetChainItem(aTarget);
|
||||
}
|
||||
|
||||
@ -165,6 +159,38 @@ public:
|
||||
aChain.RemoveElementAt(lastIndex);
|
||||
}
|
||||
|
||||
static EventTargetChainItem* GetFirstCanHandleEventTarget(
|
||||
nsTArray<EventTargetChainItem>& aChain)
|
||||
{
|
||||
return &aChain[GetFirstCanHandleEventTargetIdx(aChain)];
|
||||
}
|
||||
|
||||
static uint32_t GetFirstCanHandleEventTargetIdx(nsTArray<EventTargetChainItem>& aChain)
|
||||
{
|
||||
// aChain[i].PreHandleEventOnly() = true only when the target element wants
|
||||
// PreHandleEvent and set mCanHandle=false. So we find the first element
|
||||
// which can handle the event.
|
||||
for (uint32_t i = 0; i < aChain.Length(); ++i) {
|
||||
if (!aChain[i].PreHandleEventOnly()) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static EventTargetChainItem* GetLastCanHandleEventTarget(
|
||||
nsTArray<EventTargetChainItem>& aChain)
|
||||
{
|
||||
// Fine the last item which can handle the event.
|
||||
for (int32_t i = aChain.Length() - 1; i >= 0; --i) {
|
||||
if (!aChain[i].PreHandleEventOnly()) {
|
||||
return &aChain[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool IsValid()
|
||||
{
|
||||
NS_WARNING_ASSERTION(!!(mTarget), "Event target is not valid!");
|
||||
@ -183,44 +209,52 @@ public:
|
||||
|
||||
void SetForceContentDispatch(bool aForce)
|
||||
{
|
||||
if (aForce) {
|
||||
mFlags |= NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH;
|
||||
} else {
|
||||
mFlags &= ~NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH;
|
||||
}
|
||||
mFlags.mForceContentDispatch = aForce;
|
||||
}
|
||||
|
||||
bool ForceContentDispatch()
|
||||
{
|
||||
return !!(mFlags & NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH);
|
||||
return mFlags.mForceContentDispatch;
|
||||
}
|
||||
|
||||
void SetWantsWillHandleEvent(bool aWants)
|
||||
{
|
||||
if (aWants) {
|
||||
mFlags |= NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT;
|
||||
} else {
|
||||
mFlags &= ~NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT;
|
||||
}
|
||||
mFlags.mWantsWillHandleEvent = aWants;
|
||||
}
|
||||
|
||||
bool WantsWillHandleEvent()
|
||||
{
|
||||
return !!(mFlags & NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT);
|
||||
return mFlags.mWantsWillHandleEvent;
|
||||
}
|
||||
|
||||
void SetWantsPreHandleEvent(bool aWants)
|
||||
{
|
||||
mFlags.mWantsPreHandleEvent = aWants;
|
||||
}
|
||||
|
||||
bool WantsPreHandleEvent()
|
||||
{
|
||||
return mFlags.mWantsPreHandleEvent;
|
||||
}
|
||||
|
||||
void SetPreHandleEventOnly(bool aWants)
|
||||
{
|
||||
mFlags.mPreHandleEventOnly = aWants;
|
||||
}
|
||||
|
||||
bool PreHandleEventOnly()
|
||||
{
|
||||
return mFlags.mPreHandleEventOnly;
|
||||
}
|
||||
|
||||
void SetMayHaveListenerManager(bool aMayHave)
|
||||
{
|
||||
if (aMayHave) {
|
||||
mFlags |= NS_TARGET_CHAIN_MAY_HAVE_MANAGER;
|
||||
} else {
|
||||
mFlags &= ~NS_TARGET_CHAIN_MAY_HAVE_MANAGER;
|
||||
}
|
||||
mFlags.mMayHaveManager = aMayHave;
|
||||
}
|
||||
|
||||
bool MayHaveListenerManager()
|
||||
{
|
||||
return !!(mFlags & NS_TARGET_CHAIN_MAY_HAVE_MANAGER);
|
||||
return mFlags.mMayHaveManager;
|
||||
}
|
||||
|
||||
EventTarget* CurrentTarget()
|
||||
@ -240,10 +274,15 @@ public:
|
||||
ELMCreationDetector& aCd);
|
||||
|
||||
/**
|
||||
* Resets aVisitor object and calls PreHandleEvent.
|
||||
* Resets aVisitor object and calls GetEventTargetParent.
|
||||
* Copies mItemFlags and mItemData to the current EventTargetChainItem.
|
||||
*/
|
||||
void PreHandleEvent(EventChainPreVisitor& aVisitor);
|
||||
void GetEventTargetParent(EventChainPreVisitor& aVisitor);
|
||||
|
||||
/**
|
||||
* Calls PreHandleEvent for those items which called SetWantsPreHandleEvent.
|
||||
*/
|
||||
void PreHandleEvent(EventChainVisitor& aVisitor);
|
||||
|
||||
/**
|
||||
* If the current item in the event target chain has an event listener
|
||||
@ -288,7 +327,34 @@ public:
|
||||
|
||||
private:
|
||||
nsCOMPtr<EventTarget> mTarget;
|
||||
uint16_t mFlags;
|
||||
|
||||
class EventTargetChainFlags
|
||||
{
|
||||
public:
|
||||
explicit EventTargetChainFlags()
|
||||
{
|
||||
SetRawFlags(0);
|
||||
}
|
||||
// Cached flags for each EventTargetChainItem which are set when calling
|
||||
// GetEventTargetParent to create event target chain. They are used to
|
||||
// manage or speedup event dispatching.
|
||||
bool mForceContentDispatch : 1;
|
||||
bool mWantsWillHandleEvent : 1;
|
||||
bool mMayHaveManager : 1;
|
||||
bool mChechedIfChrome : 1;
|
||||
bool mIsChromeContent : 1;
|
||||
bool mWantsPreHandleEvent : 1;
|
||||
bool mPreHandleEventOnly : 1;
|
||||
private:
|
||||
typedef uint32_t RawFlags;
|
||||
void SetRawFlags(RawFlags aRawFlags)
|
||||
{
|
||||
static_assert(sizeof(EventTargetChainFlags) <= sizeof(RawFlags),
|
||||
"EventTargetChainFlags must not be bigger than the RawFlags");
|
||||
memcpy(this, &aRawFlags, sizeof(EventTargetChainFlags));
|
||||
}
|
||||
} mFlags;
|
||||
|
||||
uint16_t mItemFlags;
|
||||
nsCOMPtr<nsISupports> mItemData;
|
||||
// Event retargeting must happen whenever mNewTarget is non-null.
|
||||
@ -298,36 +364,48 @@ private:
|
||||
|
||||
bool IsCurrentTargetChrome()
|
||||
{
|
||||
if (!(mFlags & NS_TARGET_CHAIN_CHECKED_IF_CHROME)) {
|
||||
mFlags |= NS_TARGET_CHAIN_CHECKED_IF_CHROME;
|
||||
if (!mFlags.mChechedIfChrome) {
|
||||
mFlags.mChechedIfChrome = true;
|
||||
if (IsEventTargetChrome(mTarget)) {
|
||||
mFlags |= NS_TARGET_CHAIN_IS_CHROME_CONTENT;
|
||||
mFlags.mIsChromeContent = true;
|
||||
}
|
||||
}
|
||||
return !!(mFlags & NS_TARGET_CHAIN_IS_CHROME_CONTENT);
|
||||
return mFlags.mIsChromeContent;
|
||||
}
|
||||
};
|
||||
|
||||
EventTargetChainItem::EventTargetChainItem(EventTarget* aTarget)
|
||||
: mTarget(aTarget)
|
||||
, mFlags(0)
|
||||
, mItemFlags(0)
|
||||
{
|
||||
MOZ_ASSERT(!aTarget || mTarget == aTarget->GetTargetForEventTargetChain());
|
||||
}
|
||||
|
||||
void
|
||||
EventTargetChainItem::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
EventTargetChainItem::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.Reset();
|
||||
Unused << mTarget->PreHandleEvent(aVisitor);
|
||||
Unused << mTarget->GetEventTargetParent(aVisitor);
|
||||
SetForceContentDispatch(aVisitor.mForceContentDispatch);
|
||||
SetWantsWillHandleEvent(aVisitor.mWantsWillHandleEvent);
|
||||
SetMayHaveListenerManager(aVisitor.mMayHaveListenerManager);
|
||||
SetWantsPreHandleEvent(aVisitor.mWantsPreHandleEvent);
|
||||
SetPreHandleEventOnly(aVisitor.mWantsPreHandleEvent && !aVisitor.mCanHandle);
|
||||
mItemFlags = aVisitor.mItemFlags;
|
||||
mItemData = aVisitor.mItemData;
|
||||
}
|
||||
|
||||
void
|
||||
EventTargetChainItem::PreHandleEvent(EventChainVisitor& aVisitor)
|
||||
{
|
||||
if (!WantsPreHandleEvent()) {
|
||||
return;
|
||||
}
|
||||
aVisitor.mItemFlags = mItemFlags;
|
||||
aVisitor.mItemData = mItemData;
|
||||
Unused << mTarget->PreHandleEvent(aVisitor);
|
||||
}
|
||||
|
||||
void
|
||||
EventTargetChainItem::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
{
|
||||
@ -346,12 +424,17 @@ EventTargetChainItem::HandleEventTargetChain(
|
||||
// Save the target so that it can be restored later.
|
||||
nsCOMPtr<EventTarget> firstTarget = aVisitor.mEvent->mTarget;
|
||||
uint32_t chainLength = aChain.Length();
|
||||
uint32_t firstCanHandleEventTargetIdx =
|
||||
EventTargetChainItem::GetFirstCanHandleEventTargetIdx(aChain);
|
||||
|
||||
// Capture
|
||||
aVisitor.mEvent->mFlags.mInCapturePhase = true;
|
||||
aVisitor.mEvent->mFlags.mInBubblingPhase = false;
|
||||
for (uint32_t i = chainLength - 1; i > 0; --i) {
|
||||
for (uint32_t i = chainLength - 1; i > firstCanHandleEventTargetIdx; --i) {
|
||||
EventTargetChainItem& item = aChain[i];
|
||||
if (item.PreHandleEventOnly()) {
|
||||
continue;
|
||||
}
|
||||
if ((!aVisitor.mEvent->mFlags.mNoContentDispatch ||
|
||||
item.ForceContentDispatch()) &&
|
||||
!aVisitor.mEvent->PropagationStopped()) {
|
||||
@ -373,7 +456,7 @@ EventTargetChainItem::HandleEventTargetChain(
|
||||
|
||||
// Target
|
||||
aVisitor.mEvent->mFlags.mInBubblingPhase = true;
|
||||
EventTargetChainItem& targetItem = aChain[0];
|
||||
EventTargetChainItem& targetItem = aChain[firstCanHandleEventTargetIdx];
|
||||
if (!aVisitor.mEvent->PropagationStopped() &&
|
||||
(!aVisitor.mEvent->mFlags.mNoContentDispatch ||
|
||||
targetItem.ForceContentDispatch())) {
|
||||
@ -385,8 +468,11 @@ EventTargetChainItem::HandleEventTargetChain(
|
||||
|
||||
// Bubble
|
||||
aVisitor.mEvent->mFlags.mInCapturePhase = false;
|
||||
for (uint32_t i = 1; i < chainLength; ++i) {
|
||||
for (uint32_t i = firstCanHandleEventTargetIdx + 1; i < chainLength; ++i) {
|
||||
EventTargetChainItem& item = aChain[i];
|
||||
if (item.PreHandleEventOnly()) {
|
||||
continue;
|
||||
}
|
||||
EventTarget* newTarget = item.GetNewTarget();
|
||||
if (newTarget) {
|
||||
// Item is at anonymous boundary. Need to retarget for the current item
|
||||
@ -472,6 +558,28 @@ EventTargetChainItemForChromeTarget(nsTArray<EventTargetChainItem>& aChain,
|
||||
return etci;
|
||||
}
|
||||
|
||||
/* static */ EventTargetChainItem*
|
||||
MayRetargetToChromeIfCanNotHandleEvent(
|
||||
nsTArray<EventTargetChainItem>& aChain, EventChainPreVisitor& aPreVisitor,
|
||||
EventTargetChainItem* aTargetEtci, EventTargetChainItem* aChildEtci,
|
||||
nsINode* aContent)
|
||||
{
|
||||
if (!aPreVisitor.mWantsPreHandleEvent) {
|
||||
// Keep EventTargetChainItem if we need to call PreHandleEvent on it.
|
||||
EventTargetChainItem::DestroyLast(aChain, aTargetEtci);
|
||||
}
|
||||
if (aPreVisitor.mAutomaticChromeDispatch && aContent) {
|
||||
// Event target couldn't handle the event. Try to propagate to chrome.
|
||||
EventTargetChainItem* chromeTargetEtci =
|
||||
EventTargetChainItemForChromeTarget(aChain, aContent, aChildEtci);
|
||||
if (chromeTargetEtci) {
|
||||
chromeTargetEtci->GetEventTargetParent(aPreVisitor);
|
||||
return chromeTargetEtci;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
EventDispatcher::Dispatch(nsISupports* aTarget,
|
||||
nsPresContext* aPresContext,
|
||||
@ -632,21 +740,24 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
|
||||
aEvent->mFlags.mIsBeingDispatched = true;
|
||||
|
||||
// Create visitor object and start event dispatching.
|
||||
// PreHandleEvent for the original target.
|
||||
// GetEventTargetParent for the original target.
|
||||
nsEventStatus status = aEventStatus ? *aEventStatus : nsEventStatus_eIgnore;
|
||||
EventChainPreVisitor preVisitor(aPresContext, aEvent, aDOMEvent, status,
|
||||
isInAnon);
|
||||
targetEtci->PreHandleEvent(preVisitor);
|
||||
targetEtci->GetEventTargetParent(preVisitor);
|
||||
|
||||
if (!preVisitor.mCanHandle && preVisitor.mAutomaticChromeDispatch && content) {
|
||||
// Event target couldn't handle the event. Try to propagate to chrome.
|
||||
EventTargetChainItem::DestroyLast(chain, targetEtci);
|
||||
targetEtci = EventTargetChainItemForChromeTarget(chain, content);
|
||||
NS_ENSURE_STATE(targetEtci);
|
||||
MOZ_ASSERT(&chain[0] == targetEtci);
|
||||
targetEtci->PreHandleEvent(preVisitor);
|
||||
if (!preVisitor.mCanHandle) {
|
||||
targetEtci = MayRetargetToChromeIfCanNotHandleEvent(chain, preVisitor,
|
||||
targetEtci, nullptr,
|
||||
content);
|
||||
}
|
||||
if (preVisitor.mCanHandle) {
|
||||
if (!preVisitor.mCanHandle) {
|
||||
// The original target and chrome target (mAutomaticChromeDispatch=true)
|
||||
// can not handle the event but we still have to call their PreHandleEvent.
|
||||
for (uint32_t i = 0; i < chain.Length(); ++i) {
|
||||
chain[i].PreHandleEvent(preVisitor);
|
||||
}
|
||||
} else {
|
||||
// At least the original target can handle the event.
|
||||
// Setting the retarget to the |target| simplifies retargeting code.
|
||||
nsCOMPtr<EventTarget> t = do_QueryInterface(aEvent->mTarget);
|
||||
@ -671,30 +782,23 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
|
||||
parentEtci->SetNewTarget(preVisitor.mEventTargetAtParent);
|
||||
}
|
||||
|
||||
parentEtci->PreHandleEvent(preVisitor);
|
||||
parentEtci->GetEventTargetParent(preVisitor);
|
||||
if (preVisitor.mCanHandle) {
|
||||
topEtci = parentEtci;
|
||||
} else {
|
||||
EventTargetChainItem::DestroyLast(chain, parentEtci);
|
||||
parentEtci = nullptr;
|
||||
if (preVisitor.mAutomaticChromeDispatch && content) {
|
||||
// Even if the current target can't handle the event, try to
|
||||
// propagate to chrome.
|
||||
nsCOMPtr<nsINode> disabledTarget = do_QueryInterface(parentTarget);
|
||||
if (disabledTarget) {
|
||||
parentEtci = EventTargetChainItemForChromeTarget(chain,
|
||||
disabledTarget,
|
||||
topEtci);
|
||||
if (parentEtci) {
|
||||
parentEtci->PreHandleEvent(preVisitor);
|
||||
if (preVisitor.mCanHandle) {
|
||||
chain[0].SetNewTarget(parentTarget);
|
||||
parentEtci = MayRetargetToChromeIfCanNotHandleEvent(chain,
|
||||
preVisitor,
|
||||
parentEtci,
|
||||
topEtci,
|
||||
disabledTarget);
|
||||
if (parentEtci && preVisitor.mCanHandle) {
|
||||
EventTargetChainItem* item =
|
||||
EventTargetChainItem::GetFirstCanHandleEventTarget(chain);
|
||||
item->SetNewTarget(parentTarget);
|
||||
topEtci = parentEtci;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -707,7 +811,11 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
|
||||
targets[i] = chain[i].CurrentTarget()->GetTargetForDOMEvent();
|
||||
}
|
||||
} else {
|
||||
// Event target chain is created. Handle the chain.
|
||||
// Event target chain is created. PreHandle the chain.
|
||||
for (uint32_t i = 0; i < chain.Length(); ++i) {
|
||||
chain[i].PreHandleEvent(preVisitor);
|
||||
}
|
||||
// Handle the chain.
|
||||
EventChainPostVisitor postVisitor(preVisitor);
|
||||
EventTargetChainItem::HandleEventTargetChain(chain, postVisitor,
|
||||
aCallback, cd);
|
||||
|
@ -31,14 +31,14 @@ class EventTarget;
|
||||
* About event dispatching:
|
||||
* When either EventDispatcher::Dispatch or
|
||||
* EventDispatcher::DispatchDOMEvent is called an event target chain is
|
||||
* created. EventDispatcher creates the chain by calling PreHandleEvent
|
||||
* created. EventDispatcher creates the chain by calling GetEventTargetParent
|
||||
* on each event target and the creation continues until either the mCanHandle
|
||||
* member of the EventChainPreVisitor object is false or the mParentTarget
|
||||
* does not point to a new target. The event target chain is created in the
|
||||
* heap.
|
||||
*
|
||||
* If the event needs retargeting, mEventTargetAtParent must be set in
|
||||
* PreHandleEvent.
|
||||
* GetEventTargetParent.
|
||||
*
|
||||
* The capture, target and bubble phases of the event dispatch are handled
|
||||
* by iterating through the event target chain. Iteration happens twice,
|
||||
@ -86,7 +86,7 @@ public:
|
||||
|
||||
/**
|
||||
* Bits for items in the event target chain.
|
||||
* Set in PreHandleEvent() and used in PostHandleEvent().
|
||||
* Set in GetEventTargetParent() and used in PostHandleEvent().
|
||||
*
|
||||
* @note These bits are different for each item in the event target chain.
|
||||
* It is up to the Pre/PostHandleEvent implementation to decide how to
|
||||
@ -98,7 +98,7 @@ public:
|
||||
|
||||
/**
|
||||
* Data for items in the event target chain.
|
||||
* Set in PreHandleEvent() and used in PostHandleEvent().
|
||||
* Set in GetEventTargetParent() and used in PostHandleEvent().
|
||||
*
|
||||
* @note This data is different for each item in the event target chain.
|
||||
* It is up to the Pre/PostHandleEvent implementation to decide how to
|
||||
@ -123,6 +123,7 @@ public:
|
||||
, mOriginalTargetIsInAnon(aIsInAnon)
|
||||
, mWantsWillHandleEvent(false)
|
||||
, mMayHaveListenerManager(true)
|
||||
, mWantsPreHandleEvent(false)
|
||||
, mParentTarget(nullptr)
|
||||
, mEventTargetAtParent(nullptr)
|
||||
{
|
||||
@ -137,13 +138,14 @@ public:
|
||||
mForceContentDispatch = false;
|
||||
mWantsWillHandleEvent = false;
|
||||
mMayHaveListenerManager = true;
|
||||
mWantsPreHandleEvent = false;
|
||||
mParentTarget = nullptr;
|
||||
mEventTargetAtParent = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Member that must be set in PreHandleEvent by event targets. If set to false,
|
||||
* indicates that this event target will not be handling the event and
|
||||
* Member that must be set in GetEventTargetParent by event targets. If set to
|
||||
* false, indicates that this event target will not be handling the event and
|
||||
* construction of the event target chain is complete. The target that sets
|
||||
* mCanHandle to false is NOT included in the event target chain.
|
||||
*/
|
||||
@ -170,7 +172,7 @@ public:
|
||||
|
||||
/**
|
||||
* true if the original target of the event is inside anonymous content.
|
||||
* This is set before calling PreHandleEvent on event targets.
|
||||
* This is set before calling GetEventTargetParent on event targets.
|
||||
*/
|
||||
bool mOriginalTargetIsInAnon;
|
||||
|
||||
@ -182,10 +184,16 @@ public:
|
||||
|
||||
/**
|
||||
* If it is known that the current target doesn't have a listener manager
|
||||
* when PreHandleEvent is called, set this to false.
|
||||
* when GetEventTargetParent is called, set this to false.
|
||||
*/
|
||||
bool mMayHaveListenerManager;
|
||||
|
||||
/**
|
||||
* Whether or not nsIDOMEventTarget::PreHandleEvent will be called. Default is
|
||||
* false;
|
||||
*/
|
||||
bool mWantsPreHandleEvent;
|
||||
|
||||
/**
|
||||
* Parent item in the event target chain.
|
||||
*/
|
||||
|
@ -183,3 +183,4 @@ skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
|
||||
[test_paste_image.html]
|
||||
[test_wheel_default_action.html]
|
||||
[test_bug687787.html]
|
||||
[test_bug1305458.html]
|
||||
|
@ -152,7 +152,8 @@ var tests = [
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ "set": [["dom.beforeAfterKeyboardEvent.enabled", true],
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["dom.ipc.tabs.disabled", false]] },
|
||||
["dom.ipc.tabs.disabled", false],
|
||||
["network.disable.ipc.security", true]] },
|
||||
runTests);
|
||||
},
|
||||
|
||||
|
50
dom/events/test/test_bug1305458.html
Normal file
50
dom/events/test/test_bug1305458.html
Normal file
@ -0,0 +1,50 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1305458
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1305458</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<style>
|
||||
input[type=number] {
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
input[type=number]:focus,
|
||||
input[type=number]:hover {
|
||||
-moz-appearance: number-input;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body onload="doTest()">
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1305458">Mozilla Bug 1305458</a>
|
||||
<input id="test_input" type="number">
|
||||
<div id="test_div">bar</div>
|
||||
<script>
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
var change_count = 0;
|
||||
function doTest() {
|
||||
let input = document.getElementById("test_input");
|
||||
let div = document.getElementById("test_div");
|
||||
input.addEventListener("change", () => {
|
||||
++change_count;
|
||||
}, false);
|
||||
// mouse hover
|
||||
input.focus();
|
||||
synthesizeMouse(input, 1, 1, {type: "mousemove"});
|
||||
synthesizeKey("1", {});
|
||||
input.blur();
|
||||
is(change_count, 1, "input should fire change when blur");
|
||||
|
||||
input.focus();
|
||||
synthesizeMouse(div, 1, 1, {type: "mousemove"});
|
||||
synthesizeKey("1", {});
|
||||
input.blur();
|
||||
is(change_count, 2, "input should fire change when blur");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -107,6 +107,7 @@ var tests = [
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ "set": [["dom.beforeAfterKeyboardEvent.enabled", true],
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["network.disable.ipc.security", true],
|
||||
["dom.ipc.tabs.disabled", false]] },
|
||||
runTests);
|
||||
},
|
||||
|
@ -166,6 +166,7 @@ var tests = [
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ "set": [["dom.beforeAfterKeyboardEvent.enabled", true],
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["network.disable.ipc.security", true],
|
||||
["dom.ipc.tabs.disabled", false]] },
|
||||
runTests);
|
||||
},
|
||||
|
@ -17,7 +17,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=77992
|
||||
<script type="text/js-worker" id="worker-src">
|
||||
// Simply returns the event timestamp
|
||||
onmessage = function(evt) {
|
||||
postMessage(evt.timeStamp);
|
||||
postMessage(evt.timeStamp + performance.timeOrigin);
|
||||
}
|
||||
</script>
|
||||
<script type="text/js-worker" id="shared-worker-src">
|
||||
@ -25,7 +25,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=77992
|
||||
onconnect = function(evt) {
|
||||
var port = evt.ports[0];
|
||||
port.onmessage = function(messageEvt) {
|
||||
port.postMessage(messageEvt.timeStamp);
|
||||
port.postMessage(messageEvt.timeStamp + performance.timeOrigin);
|
||||
};
|
||||
};
|
||||
</script>
|
||||
@ -57,9 +57,9 @@ function testRegularEvents() {
|
||||
finishTests();
|
||||
return;
|
||||
}
|
||||
var timeBeforeEvent = window.performance.now();
|
||||
window.addEventListener("load", function(evt) {
|
||||
var timeAfterEvent = window.performance.now();
|
||||
var timeBeforeEvent = performance.now();
|
||||
addEventListener("load", function(evt) {
|
||||
var timeAfterEvent = performance.now();
|
||||
ok(evt.timeStamp > timeBeforeEvent &&
|
||||
evt.timeStamp < timeAfterEvent,
|
||||
"Event timestamp (" + evt.timeStamp + ") is in expected range: (" +
|
||||
@ -71,18 +71,18 @@ function testRegularEvents() {
|
||||
function testWorkerEvents() {
|
||||
var blob = new Blob([ document.getElementById("worker-src").textContent ],
|
||||
{ type: "text/javascript" });
|
||||
var worker = new Worker(window.URL.createObjectURL(blob));
|
||||
var worker = new Worker(URL.createObjectURL(blob));
|
||||
worker.onmessage = function(evt) {
|
||||
var timeAfterEvent = window.performance.now();
|
||||
ok(evt.data > timeBeforeEvent &&
|
||||
evt.data < timeAfterEvent,
|
||||
var timeAfterEvent = performance.now() + performance.timeOrigin;
|
||||
ok(evt.data >= timeBeforeEvent &&
|
||||
evt.data <= timeAfterEvent,
|
||||
"Event timestamp in dedicated worker (" + evt.data +
|
||||
") is in expected range: (" +
|
||||
timeBeforeEvent + ", " + timeAfterEvent + ")");
|
||||
worker.terminate();
|
||||
testSharedWorkerEvents();
|
||||
};
|
||||
var timeBeforeEvent = window.performance.now();
|
||||
var timeBeforeEvent = performance.now() + performance.timeOrigin;
|
||||
worker.postMessage("");
|
||||
}
|
||||
|
||||
@ -92,16 +92,16 @@ function testSharedWorkerEvents() {
|
||||
{ type: "text/javascript" });
|
||||
// Delay creation of worker slightly so it is easier to distinguish
|
||||
// shared worker creation time from this document's navigation start
|
||||
window.setTimeout(function() {
|
||||
var timeBeforeWorkerCreation = window.performance.now();
|
||||
var worker = new SharedWorker(window.URL.createObjectURL(blob));
|
||||
setTimeout(function() {
|
||||
var timeBeforeEvent = performance.now() + performance.timeOrigin;
|
||||
var worker = new SharedWorker(URL.createObjectURL(blob));
|
||||
worker.port.onmessage = function(evt) {
|
||||
var timeAfterEvent = window.performance.now();
|
||||
ok(evt.data > 0 &&
|
||||
evt.data < timeAfterEvent - timeBeforeWorkerCreation,
|
||||
var timeAfterEvent = performance.now() + performance.timeOrigin;
|
||||
ok(evt.data >= timeBeforeEvent &&
|
||||
evt.data <= timeAfterEvent,
|
||||
"Event timestamp in shared worker (" + evt.data +
|
||||
") is in expected range: (0, " +
|
||||
(timeAfterEvent - timeBeforeWorkerCreation) + ")");
|
||||
timeBeforeEvent + ", " + timeAfterEvent + ")");
|
||||
worker.port.close();
|
||||
finishTests();
|
||||
};
|
||||
|
@ -252,9 +252,9 @@ HTMLAnchorElement::IsHTMLFocusable(bool aWithMouse,
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLAnchorElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
HTMLAnchorElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
return PreHandleEventForAnchors(aVisitor);
|
||||
return GetEventTargetParentForAnchors(aVisitor);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -58,7 +58,8 @@ public:
|
||||
bool aNullParent = true) override;
|
||||
virtual bool IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, int32_t *aTabIndex) override;
|
||||
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult GetEventTargetParent(
|
||||
EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult PostHandleEvent(
|
||||
EventChainPostVisitor& aVisitor) override;
|
||||
virtual bool IsLink(nsIURI** aURI) const override;
|
||||
|
@ -81,9 +81,9 @@ HTMLAreaElement::SetTarget(const nsAString& aValue)
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLAreaElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
HTMLAreaElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
return PreHandleEventForAnchors(aVisitor);
|
||||
return GetEventTargetParentForAnchors(aVisitor);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -44,7 +44,8 @@ public:
|
||||
// nsIDOMHTMLAreaElement
|
||||
NS_DECL_NSIDOMHTMLAREAELEMENT
|
||||
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult GetEventTargetParent(
|
||||
EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult PostHandleEvent(EventChainPostVisitor& aVisitor) override;
|
||||
virtual bool IsLink(nsIURI** aURI) const override;
|
||||
virtual void GetLinkTarget(nsAString& aTarget) override;
|
||||
|
@ -207,7 +207,7 @@ HTMLButtonElement::IsDisabledForEvents(EventMessage aMessage)
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLButtonElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
HTMLButtonElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mCanHandle = false;
|
||||
if (IsDisabledForEvents(aVisitor.mEvent->mMessage)) {
|
||||
@ -235,7 +235,7 @@ HTMLButtonElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::PreHandleEvent(aVisitor);
|
||||
return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -57,7 +57,8 @@ public:
|
||||
virtual void FieldSetDisabledChanged(bool aNotify) override;
|
||||
|
||||
// nsIDOMEventTarget
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult GetEventTargetParent(
|
||||
EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult PostHandleEvent(
|
||||
EventChainPostVisitor& aVisitor) override;
|
||||
|
||||
|
@ -570,7 +570,7 @@ HTMLCanvasElement::CopyInnerTo(Element* aDest)
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult HTMLCanvasElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
nsresult HTMLCanvasElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
if (aVisitor.mEvent->mClass == eMouseEventClass) {
|
||||
WidgetMouseEventBase* evt = (WidgetMouseEventBase*)aVisitor.mEvent;
|
||||
@ -588,7 +588,7 @@ nsresult HTMLCanvasElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
aVisitor.mCanHandle = true;
|
||||
}
|
||||
}
|
||||
return nsGenericHTMLElement::PreHandleEvent(aVisitor);
|
||||
return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
|
||||
}
|
||||
|
||||
nsChangeHint
|
||||
|
@ -308,7 +308,8 @@ public:
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
nsresult CopyInnerTo(mozilla::dom::Element* aDest);
|
||||
|
||||
virtual nsresult PreHandleEvent(mozilla::EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult GetEventTargetParent(
|
||||
mozilla::EventChainPreVisitor& aVisitor) override;
|
||||
|
||||
/*
|
||||
* Helpers called by various users of Canvas
|
||||
|
@ -70,7 +70,7 @@ HTMLFieldSetElement::IsDisabledForEvents(EventMessage aMessage)
|
||||
|
||||
// nsIContent
|
||||
nsresult
|
||||
HTMLFieldSetElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
HTMLFieldSetElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
// Do not process any DOM events if the element is disabled.
|
||||
aVisitor.mCanHandle = false;
|
||||
@ -78,7 +78,7 @@ HTMLFieldSetElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return nsGenericHTMLFormElement::PreHandleEvent(aVisitor);
|
||||
return nsGenericHTMLFormElement::GetEventTargetParent(aVisitor);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -40,7 +40,8 @@ public:
|
||||
NS_DECL_NSIDOMHTMLFIELDSETELEMENT
|
||||
|
||||
// nsIContent
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult GetEventTargetParent(
|
||||
EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify) override;
|
||||
|
||||
|
@ -491,7 +491,7 @@ HTMLFormElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLFormElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
HTMLFormElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mWantsWillHandleEvent = true;
|
||||
if (aVisitor.mEvent->mOriginalTarget == static_cast<nsIContent*>(this)) {
|
||||
@ -515,7 +515,7 @@ HTMLFormElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
mGeneratingReset = true;
|
||||
}
|
||||
}
|
||||
return nsGenericHTMLElement::PreHandleEvent(aVisitor);
|
||||
return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -93,7 +93,8 @@ public:
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult) override;
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult GetEventTargetParent(
|
||||
EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult WillHandleEvent(
|
||||
EventChainPostVisitor& aVisitor) override;
|
||||
virtual nsresult PostHandleEvent(
|
||||
|
@ -437,7 +437,7 @@ HTMLImageElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLImageElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
HTMLImageElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
// We handle image element with attribute ismap in its corresponding frame
|
||||
// element. Set mMultipleActionsPrevented here to prevent the click event
|
||||
@ -446,7 +446,7 @@ HTMLImageElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
if (mouseEvent && mouseEvent->IsLeftClickEvent() && IsMap()) {
|
||||
mouseEvent->mFlags.mMultipleActionsPrevented = true;
|
||||
}
|
||||
return nsGenericHTMLElement::PreHandleEvent(aVisitor);
|
||||
return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -70,7 +70,8 @@ public:
|
||||
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
|
||||
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
|
||||
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult GetEventTargetParent(
|
||||
EventChainPreVisitor& aVisitor) override;
|
||||
|
||||
bool IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, int32_t *aTabIndex) override;
|
||||
|
||||
|
@ -151,6 +151,8 @@ namespace dom {
|
||||
#define NS_CONTROL_TYPE(bits) ((bits) & ~( \
|
||||
NS_OUTER_ACTIVATE_EVENT | NS_ORIGINAL_CHECKED_VALUE | NS_NO_CONTENT_DISPATCH | \
|
||||
NS_ORIGINAL_INDETERMINATE_VALUE))
|
||||
#define NS_PRE_HANDLE_BLUR_EVENT (1 << 13)
|
||||
#define NS_PRE_HANDLE_INPUT_EVENT (1 << 14)
|
||||
|
||||
// whether textfields should be selected once focused:
|
||||
// -1: no, 1: yes, 0: uninitialized
|
||||
@ -3743,7 +3745,7 @@ HTMLInputElement::IsDisabledForEvents(EventMessage aMessage)
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
HTMLInputElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
// Do not process any DOM events if the element is disabled
|
||||
aVisitor.mCanHandle = false;
|
||||
@ -3760,7 +3762,7 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
|
||||
//FIXME Allow submission etc. also when there is no prescontext, Bug 329509.
|
||||
if (!aVisitor.mPresContext) {
|
||||
return nsGenericHTMLElement::PreHandleEvent(aVisitor);
|
||||
return nsGenericHTMLFormElementWithState::GetEventTargetParent(aVisitor);
|
||||
}
|
||||
//
|
||||
// Web pages expect the value of a radio button or checkbox to be set
|
||||
@ -3870,23 +3872,16 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
|
||||
// Fire onchange (if necessary), before we do the blur, bug 357684.
|
||||
if (aVisitor.mEvent->mMessage == eBlur) {
|
||||
// Experimental mobile types rely on the system UI to prevent users to not
|
||||
// set invalid values but we have to be extra-careful. Especially if the
|
||||
// option has been enabled on desktop.
|
||||
if (IsExperimentalMobileType(mType)) {
|
||||
nsAutoString aValue;
|
||||
GetNonFileValueInternal(aValue);
|
||||
nsresult rv =
|
||||
SetValueInternal(aValue, nsTextEditorState::eSetValue_Internal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
FireChangeEventIfNeeded();
|
||||
// We set NS_PRE_HANDLE_BLUR_EVENT here and handle it in PreHandleEvent to
|
||||
// prevent breaking event target chain creation.
|
||||
aVisitor.mWantsPreHandleEvent = true;
|
||||
aVisitor.mItemFlags |= NS_PRE_HANDLE_BLUR_EVENT;
|
||||
}
|
||||
|
||||
if (mType == NS_FORM_INPUT_RANGE &&
|
||||
(aVisitor.mEvent->mMessage == eFocus ||
|
||||
aVisitor.mEvent->mMessage == eBlur)) {
|
||||
// Just as nsGenericHTMLFormElementWithState::PreHandleEvent calls
|
||||
// Just as nsGenericHTMLFormElementWithState::GetEventTargetParent calls
|
||||
// nsIFormControlFrame::SetFocus, we handle focus here.
|
||||
nsIFrame* frame = GetPrimaryFrame();
|
||||
if (frame) {
|
||||
@ -3974,10 +3969,11 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv = nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
|
||||
nsresult rv = nsGenericHTMLFormElementWithState::GetEventTargetParent(aVisitor);
|
||||
|
||||
// We do this after calling the base class' PreHandleEvent so that
|
||||
// nsIContent::PreHandleEvent doesn't reset any change we make to mCanHandle.
|
||||
// We do this after calling the base class' GetEventTargetParent so that
|
||||
// nsIContent::GetEventTargetParent doesn't reset any change we make to
|
||||
// mCanHandle.
|
||||
if (mType == NS_FORM_INPUT_NUMBER &&
|
||||
aVisitor.mEvent->IsTrusted() &&
|
||||
aVisitor.mEvent->mOriginalTarget != this) {
|
||||
@ -3992,18 +3988,10 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
}
|
||||
if (textControl && aVisitor.mEvent->mOriginalTarget == textControl) {
|
||||
if (aVisitor.mEvent->mMessage == eEditorInput) {
|
||||
// Propogate the anon text control's new value to our HTMLInputElement:
|
||||
nsAutoString value;
|
||||
numberControlFrame->GetValueOfAnonTextControl(value);
|
||||
numberControlFrame->HandlingInputEvent(true);
|
||||
nsWeakFrame weakNumberControlFrame(numberControlFrame);
|
||||
rv = SetValueInternal(value,
|
||||
nsTextEditorState::eSetValue_BySetUserInput |
|
||||
nsTextEditorState::eSetValue_Notify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (weakNumberControlFrame.IsAlive()) {
|
||||
numberControlFrame->HandlingInputEvent(false);
|
||||
}
|
||||
aVisitor.mWantsPreHandleEvent = true;
|
||||
// We set NS_PRE_HANDLE_INPUT_EVENT here and handle it in PreHandleEvent
|
||||
// to prevent breaking event target chain creation.
|
||||
aVisitor.mItemFlags |= NS_PRE_HANDLE_INPUT_EVENT;
|
||||
}
|
||||
else if (aVisitor.mEvent->mMessage == eFormChange) {
|
||||
// We cancel the DOM 'change' event that is fired for any change to our
|
||||
@ -4041,6 +4029,49 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLInputElement::PreHandleEvent(EventChainVisitor& aVisitor)
|
||||
{
|
||||
if (!aVisitor.mPresContext) {
|
||||
return nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
|
||||
}
|
||||
nsresult rv;
|
||||
if (aVisitor.mItemFlags & NS_PRE_HANDLE_BLUR_EVENT) {
|
||||
MOZ_ASSERT(aVisitor.mEvent->mMessage == eBlur);
|
||||
// Experimental mobile types rely on the system UI to prevent users to not
|
||||
// set invalid values but we have to be extra-careful. Especially if the
|
||||
// option has been enabled on desktop.
|
||||
if (IsExperimentalMobileType(mType)) {
|
||||
nsAutoString aValue;
|
||||
GetNonFileValueInternal(aValue);
|
||||
rv = SetValueInternal(aValue, nsTextEditorState::eSetValue_Internal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
FireChangeEventIfNeeded();
|
||||
}
|
||||
rv = nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
|
||||
if (aVisitor.mItemFlags & NS_PRE_HANDLE_INPUT_EVENT) {
|
||||
nsNumberControlFrame* numberControlFrame = do_QueryFrame(GetPrimaryFrame());
|
||||
MOZ_ASSERT(aVisitor.mEvent->mMessage == eEditorInput);
|
||||
MOZ_ASSERT(numberControlFrame);
|
||||
MOZ_ASSERT(numberControlFrame->GetAnonTextControl() ==
|
||||
aVisitor.mEvent->mOriginalTarget);
|
||||
// Propogate the anon text control's new value to our HTMLInputElement:
|
||||
nsAutoString value;
|
||||
numberControlFrame->GetValueOfAnonTextControl(value);
|
||||
numberControlFrame->HandlingInputEvent(true);
|
||||
nsWeakFrame weakNumberControlFrame(numberControlFrame);
|
||||
rv = SetValueInternal(value,
|
||||
nsTextEditorState::eSetValue_BySetUserInput |
|
||||
nsTextEditorState::eSetValue_Notify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (weakNumberControlFrame.IsAlive()) {
|
||||
numberControlFrame->HandlingInputEvent(false);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLInputElement::StartRangeThumbDrag(WidgetGUIEvent* aEvent)
|
||||
{
|
||||
|
@ -186,7 +186,9 @@ public:
|
||||
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
|
||||
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
|
||||
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult GetEventTargetParent(
|
||||
EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult PreHandleEvent(EventChainVisitor& aVisitor) override;
|
||||
virtual nsresult PostHandleEvent(
|
||||
EventChainPostVisitor& aVisitor) override;
|
||||
void PostHandleEventForRangeThumb(EventChainPostVisitor& aVisitor);
|
||||
|
@ -421,9 +421,9 @@ HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLLinkElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
HTMLLinkElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
return PreHandleEventForAnchors(aVisitor);
|
||||
return GetEventTargetParentForAnchors(aVisitor);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -46,7 +46,8 @@ public:
|
||||
void UpdateImport();
|
||||
|
||||
// nsIDOMEventTarget
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult GetEventTargetParent(
|
||||
EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult PostHandleEvent(
|
||||
EventChainPostVisitor& aVisitor) override;
|
||||
|
||||
|
@ -252,7 +252,7 @@ HTMLMenuItemElement::SetChecked(bool aChecked)
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLMenuItemElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
HTMLMenuItemElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
if (aVisitor.mEvent->mMessage == eMouseClick) {
|
||||
|
||||
@ -283,7 +283,7 @@ HTMLMenuItemElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
aVisitor.mItemFlags |= mType;
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::PreHandleEvent(aVisitor);
|
||||
return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -36,7 +36,8 @@ public:
|
||||
// nsIDOMHTMLMenuItemElement
|
||||
NS_DECL_NSIDOMHTMLMENUITEMELEMENT
|
||||
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult GetEventTargetParent(
|
||||
EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult PostHandleEvent(
|
||||
EventChainPostVisitor& aVisitor) override;
|
||||
|
||||
|
@ -48,7 +48,7 @@ NS_IMPL_STRING_ATTR(HTMLOptGroupElement, Label, label)
|
||||
|
||||
|
||||
nsresult
|
||||
HTMLOptGroupElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
HTMLOptGroupElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mCanHandle = false;
|
||||
// Do not process any DOM events if the element is disabled
|
||||
@ -66,7 +66,7 @@ HTMLOptGroupElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::PreHandleEvent(aVisitor);
|
||||
return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
|
||||
}
|
||||
|
||||
Element*
|
||||
|
@ -35,7 +35,8 @@ public:
|
||||
virtual void RemoveChildAt(uint32_t aIndex, bool aNotify) override;
|
||||
|
||||
// nsIContent
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult GetEventTargetParent(
|
||||
EventChainPreVisitor& aVisitor) override;
|
||||
|
||||
virtual EventStates IntrinsicState() const override;
|
||||
|
||||
|
@ -1447,14 +1447,14 @@ HTMLSelectElement::IsDisabledForEvents(EventMessage aMessage)
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLSelectElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
HTMLSelectElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mCanHandle = false;
|
||||
if (IsDisabledForEvents(aVisitor.mEvent->mMessage)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
|
||||
return nsGenericHTMLFormElementWithState::GetEventTargetParent(aVisitor);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -278,7 +278,8 @@ public:
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// nsIContent
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult GetEventTargetParent(
|
||||
EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult PostHandleEvent(
|
||||
EventChainPostVisitor& aVisitor) override;
|
||||
|
||||
|
@ -503,7 +503,7 @@ HTMLTextAreaElement::IsDisabledForEvents(EventMessage aMessage)
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLTextAreaElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
HTMLTextAreaElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mCanHandle = false;
|
||||
if (IsDisabledForEvents(aVisitor.mEvent->mMessage)) {
|
||||
@ -531,11 +531,22 @@ HTMLTextAreaElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
aVisitor.mEvent->mFlags.mNoContentDispatch = false;
|
||||
}
|
||||
|
||||
// Fire onchange (if necessary), before we do the blur, bug 370521.
|
||||
if (aVisitor.mEvent->mMessage == eBlur) {
|
||||
FireChangeEventIfNeeded();
|
||||
// Set mWantsPreHandleEvent and fire change event in PreHandleEvent to
|
||||
// prevent it breaks event target chain creation.
|
||||
aVisitor.mWantsPreHandleEvent = true;
|
||||
}
|
||||
|
||||
return nsGenericHTMLFormElementWithState::GetEventTargetParent(aVisitor);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLTextAreaElement::PreHandleEvent(EventChainVisitor& aVisitor)
|
||||
{
|
||||
if (aVisitor.mEvent->mMessage == eBlur) {
|
||||
// Fire onchange (if necessary), before we do the blur, bug 370521.
|
||||
FireChangeEventIfNeeded();
|
||||
}
|
||||
return nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,9 @@ public:
|
||||
int32_t aModType) const override;
|
||||
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
|
||||
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult GetEventTargetParent(
|
||||
EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult PreHandleEvent(EventChainVisitor& aVisitor) override;
|
||||
virtual nsresult PostHandleEvent(
|
||||
EventChainPostVisitor& aVisitor) override;
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user