Merge m-i to m-c, a=merge

MozReview-Commit-ID: A3wgReQAalj
This commit is contained in:
Phil Ringnalda 2016-11-17 19:21:20 -08:00
commit 61baa2aa9a
272 changed files with 2684 additions and 3765 deletions

View File

@ -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]

View File

@ -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">

View File

@ -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);

View File

@ -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) {

View File

@ -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]);

View File

@ -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}

View File

@ -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;
}

View File

@ -9,7 +9,6 @@ DIRS += ['test']
EXTRA_COMPONENTS += [
'AlertsService.js',
'B2GAboutRedirector.js',
'B2GAppMigrator.js',
'B2GPresentationDevicePrompt.js',
'BootstrapCommandLine.js',
'ContentPermissionPrompt.js',

View File

@ -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

View File

@ -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;

View File

@ -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();

View File

@ -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);
},

View File

@ -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

View File

@ -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,13 +600,8 @@ 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");
*aAppStatus = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
return NS_OK;
}
*aAppStatus = nsScriptSecurityManager::AppStatusForPrincipal(this);
// TODO: Remove GetAppStatus.
*aAppStatus = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
return NS_OK;
}

View File

@ -48,12 +48,16 @@ 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
// |uri!key1=value1&key2=value2| and returns the uri without the suffix.
MOZ_MUST_USE bool PopulateFromOrigin(const nsACString& aOrigin,
nsACString& aOriginNoSuffix);
nsACString& aOriginNoSuffix);
// Helper function to match mIsPrivateBrowsing to existing private browsing
// flags. Once all other flags are removed, this can be removed too.

View File

@ -30,8 +30,6 @@
#include "mozilla/Preferences.h"
#include "mozilla/HashFunctions.h"
#include "nsIAppsService.h"
using namespace mozilla;
static bool gIsWhitelistingTestDomains = false;

View File

@ -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

View File

@ -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);

View File

@ -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"

View File

@ -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])

View File

@ -1,2 +0,0 @@
component {05072afa-92fe-45bf-ae22-39b69c117058} AppsService.js
contract @mozilla.org/AppsService;1 {05072afa-92fe-45bf-ae22-39b69c117058}

View File

@ -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();

View File

@ -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);
},
}
/**

View File

@ -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,
});
}
};

View File

@ -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',
]

View File

@ -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();
}

View File

@ -2,4 +2,3 @@
[test_manifestSanitizer.js]
[test_manifestHelper.js]
[test_moziapplication.js]

View File

@ -69,7 +69,7 @@ ArchiveRequest::~ArchiveRequest()
}
nsresult
ArchiveRequest::PreHandleEvent(EventChainPreVisitor& aVisitor)
ArchiveRequest::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = true;
aVisitor.mParentTarget = nullptr;

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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 &&

View File

@ -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);

View File

@ -159,15 +159,23 @@ DOMIntersectionObserver::Observe(Element& aTarget)
void
DOMIntersectionObserver::Unobserve(Element& aTarget)
{
if (!mObservationTargets.Contains(&aTarget)) {
return;
if (UnlinkTarget(aTarget)) {
aTarget.UnregisterIntersectionObserver(this);
}
if (mObservationTargets.Count() == 1) {
Disconnect();
return;
}
aTarget.UnregisterIntersectionObserver(this);
mObservationTargets.RemoveEntry(&aTarget);
}
bool
DOMIntersectionObserver::UnlinkTarget(Element& aTarget)
{
if (!mObservationTargets.Contains(&aTarget)) {
return false;
}
if (mObservationTargets.Count() == 1) {
Disconnect();
return false;
}
mObservationTargets.RemoveEntry(&aTarget);
return true;
}
void
@ -192,8 +200,10 @@ DOMIntersectionObserver::Disconnect()
target->UnregisterIntersectionObserver(this);
}
mObservationTargets.Clear();
nsIDocument* document = mOwner->GetExtantDoc();
document->RemoveIntersectionObserver(this);
if (mOwner) {
nsIDocument* document = mOwner->GetExtantDoc();
document->RemoveIntersectionObserver(this);
}
mConnected = false;
}

View File

@ -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; }

View File

@ -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:

View File

@ -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.

View File

@ -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;

View File

@ -67,7 +67,6 @@
#include "TimeManager.h"
#include "DeviceStorage.h"
#include "nsStreamUtils.h"
#include "nsIAppsService.h"
#include "WidgetUtils.h"
#include "nsIPresentationService.h"

View File

@ -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.

View File

@ -803,7 +803,7 @@ public:
NS_DECL_NSIDOMDOCUMENTXBL
// nsIDOMEventTarget
virtual nsresult PreHandleEvent(
virtual nsresult GetEventTargetParent(
mozilla::EventChainPreVisitor& aVisitor) override;
virtual mozilla::EventListenerManager*
GetOrCreateListenerManager() override;

View File

@ -14,7 +14,6 @@
#include "prenv.h"
#include "nsDocShell.h"
#include "nsIAppsService.h"
#include "nsIDOMHTMLIFrameElement.h"
#include "nsIDOMHTMLFrameElement.h"
#include "nsIDOMMozBrowserFrame.h"

View File

@ -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:

View File

@ -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();

View File

@ -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;

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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);
});
});

View File

@ -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;

View File

@ -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);

View File

@ -85,6 +85,7 @@
SpecialPowers.pushPrefEnv({
"set": [
["dom.mozBrowserFramesEnabled", true],
["network.disable.ipc.security", true],
["browser.pagethumbnails.capturing_disabled", true]
]
}, runTests);

View File

@ -121,6 +121,7 @@
SpecialPowers.pushPrefEnv({
"set": [
["dom.mozBrowserFramesEnabled", true],
["network.disable.ipc.security", true],
["browser.pagethumbnails.capturing_disabled", true]
]
}, runTests);

View File

@ -115,6 +115,7 @@
SpecialPowers.pushPrefEnv({
set: [
["dom.mozBrowserFramesEnabled", true],
["network.disable.ipc.security", true],
["dom.ipc.browser_frames.oop_by_default", false],
]
}, runTests);

View File

@ -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);
});
});

View File

@ -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);
});
});

View File

@ -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");

View File

@ -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() {

View File

@ -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>

View File

@ -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]]},

View File

@ -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]]},

View File

@ -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(

View File

@ -329,7 +329,7 @@ DOMEventTargetHelper::GetEventHandler(nsIAtom* aType,
}
nsresult
DOMEventTargetHelper::PreHandleEvent(EventChainPreVisitor& aVisitor)
DOMEventTargetHelper::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = true;
aVisitor.mParentTarget = nullptr;

View File

@ -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); \
} \

View File

@ -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,29 +782,22 @@ 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);
topEtci = parentEtci;
continue;
}
}
}
nsCOMPtr<nsINode> disabledTarget = do_QueryInterface(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);

View File

@ -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.
*/

View File

@ -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]

View File

@ -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);
},

View 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>

View File

@ -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);
},

View File

@ -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);
},

View File

@ -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();
};

View File

@ -252,9 +252,9 @@ HTMLAnchorElement::IsHTMLFocusable(bool aWithMouse,
}
nsresult
HTMLAnchorElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
HTMLAnchorElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
return PreHandleEventForAnchors(aVisitor);
return GetEventTargetParentForAnchors(aVisitor);
}
nsresult

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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(

View File

@ -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

View File

@ -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;

View File

@ -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)
{

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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*

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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);
}

View File

@ -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