import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1243546 - Add mach command for external-media-tests - r=gps (8c74584251)
- Bug 1239987 - Remove marionette-transport dependency from build environment; r=gps (b5e6166e61)
- Bug 1250748 - Remove the 20s countdown timer from mach first run; r=chmanchester (8755a9b3e0)
- Bug 1238996 - Release marionette-driver 1.2, marionette-transport 1.1, and marionette-client 2.1; r=automatedtester (746bc487a4)
- Bug 1243739 - Bump versions of marionette-driver, marionette-client and marionette-transport. r=ato (c87d6e57f8)
- Bug 1243739: Update marionette-driver dependecy for marionette-transport. r=ato (582a2f8d8e)
- Bug 1239987 - Merge marionette-transport into marionette-driver; r=automatedtester (254ed0727c)
- Bug 1239330 - Support AddonManager.installTemporaryAddon() in marionette_driver.addons, r=ato (1f132b1cb3)
- Bug 1230622 - Docs: Suggest people use wptserve instead of mozhttpd. r=jgraham (8b1c669740)
- Bug 1174497 - [mozprofile] bump version and release to pypi; r=wlach (0360927850)
- Bug 1014760 - Version bump mozbase modules that depend on mozlog 3.0, r=me (d16b10a25f)
- Bug 1189858 - [mozprofile] remove the manifest parser required dependency. r=ahal (b181c379ce)
- Bug 1189858 - fix typos in pip extra dependency declaration (587697be0d)
- Bug 1199115 - Release mozprofile 0.27. r=jgraham DONTBUILD (a1e1452486)
- Bug 1233534 - [mozprofile] bump version to 0.28. r=ahal (6e17f001dd)
- Bug 1256401 - Part 2: Remove references to b2gdroid. r=fabrice (1486bf8669)
- Bug 1112920 - Assert against pending exceptions in AutoJSAPI::InitInternal. v1 r=luke,r=smaug (fa9b99c835)
- Fix the asset for bug 1112920 to not touch uninitialized memory. Totally my fault, since I moved it above the mCx assignment, and now we have a CLOSED TREE. (f404994a66)
- Logging patch for bug 1256008. r=khuey (dcb846a987)
- Bug 1255817 part 1. Make AutoJSAPI always take ownership of error reporting. r=bholley (638b9ca3fe)
- Bug 1257306. Simplify the implementation of AutoSafeJSContext (and therefore AutoJSContext, since AutoSafeJSContext will no longer be an AutoJSContext). r=bholley (58b655ad7a)
- Bug 1245951 - "Unused method in WebSocket". r=smaug (b2f8937893)
- Bug 1227136 - crash in mozilla::net::WebSocketChannel::StartWebsocketData, r=bagder, r=baku (5249e56b52)
- Bug 1252751 - Improve the security model between webSocket and sandboxed iframe, r=smaug (9a6c0be275)
- Bug 1250234. Make WebSocket::CreateAndDispatchMessageEvent properly report JS exceptions it might be producing. r=khuey (eaae502684)
- Bug 1255840. Get rid of the AutoJSAPI usage in IDBFactory. r=khuey (d0a965d1aa)
- Bug 1151112 - 'Sending message that cannot be cloned. Are you trying to send an XPCOM object?' seen when unlocking phone. r=ferjm (7ba4294750)
- Bug 1253834 - add AllChildrenIterator::Get(), r=bz (5c1ab2f7f2)
- Bug 1249443 - add AllChildrenIterator::GetPreviousChild, r=bz (812f61db28)
- Bug 1249443 - add AllChildrenIterator::Phase, r=bz (9106ec6dbb)
- Bug 1095236 - Simplify browser_test_new_window_from_content.js to use BrowserTestUtils. r=mrbkap (b8fcea4ad1)
- Bug 1095236 - Test that windows opened from content with dialog=1 still open. r=mrbkap. (db67a80e2b)
- Bug 1210482 - regression tests for 1194897 in which window.[location|menu|personal|status|tool]bar.visible broke for e10s, we're testing these behave appropiately both in content and chrome. r=mconley (a17099181c)
- Bug 1251897 - DocAccessible constructor doesn't have to take root element as an argument, r=davidb (77ef52ac2a)
This commit is contained in:
2024-02-21 09:53:18 +08:00
parent fe9be1dd79
commit c0ffcde3a8
66 changed files with 732 additions and 724 deletions
+2 -3
View File
@@ -14,9 +14,8 @@ using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
DocAccessibleWrap::
DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell) :
DocAccessible(aDocument, aRootContent, aPresShell), mActivated(false)
DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
DocAccessible(aDocument, aPresShell), mActivated(false)
{
}
+1 -2
View File
@@ -19,8 +19,7 @@ namespace a11y {
class DocAccessibleWrap : public DocAccessible
{
public:
DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell);
DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
virtual ~DocAccessibleWrap();
bool mActivated;
+2 -4
View File
@@ -471,17 +471,15 @@ DocManager::CreateDocOrRootAccessible(nsIDocument* aDocument)
// We only create root accessibles for the true root, otherwise create a
// doc accessible.
nsIContent *rootElm = nsCoreUtils::GetRoleContent(aDocument);
RefPtr<DocAccessible> docAcc = isRootDoc ?
new RootAccessibleWrap(aDocument, rootElm, presShell) :
new DocAccessibleWrap(aDocument, rootElm, presShell);
new RootAccessibleWrap(aDocument, presShell) :
new DocAccessibleWrap(aDocument, presShell);
// Cache the document accessible into document cache.
mDocAccessibleCache.Put(aDocument, docAcc);
// Initialize the document accessible.
docAcc->Init();
docAcc->SetRoleMapEntry(aria::GetRoleMap(aDocument));
// Bind the document to the tree.
if (isRootDoc) {
+3 -4
View File
@@ -76,9 +76,8 @@ static const uint32_t kRelationAttrsLen = ArrayLength(kRelationAttrs);
// Constructor/desctructor
DocAccessible::
DocAccessible(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell) :
HyperTextAccessibleWrap(aRootContent, this),
DocAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell) :
HyperTextAccessibleWrap(nullptr, this),
// XXX aaronl should we use an algorithm for the initial cache size?
mAccessibleCache(kDefaultCacheLength),
mNodeToAccessibleMap(kDefaultCacheLength),
@@ -1493,7 +1492,7 @@ DocAccessible::DoInitialUpdate()
// miss the notification (since content tree change notifications are ignored
// prior to initial update). Make sure the content element is valid.
nsIContent* contentElm = nsCoreUtils::GetRoleContent(mDocumentNode);
if (mContent != contentElm) {
if (contentElm) {
mContent = contentElm;
SetRoleMapEntry(aria::GetRoleMap(mContent));
}
+1 -2
View File
@@ -50,8 +50,7 @@ class DocAccessible : public HyperTextAccessibleWrap,
public:
DocAccessible(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell);
DocAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell);
// nsIScrollPositionListener
virtual void ScrollPositionWillChange(nscoord aX, nscoord aY) override {}
+2 -3
View File
@@ -59,9 +59,8 @@ NS_IMPL_ISUPPORTS_INHERITED0(RootAccessible, DocAccessible)
// Constructor/destructor
RootAccessible::
RootAccessible(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell) :
DocAccessibleWrap(aDocument, aRootContent, aPresShell)
RootAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell) :
DocAccessibleWrap(aDocument, aPresShell)
{
mType = eRootType;
}
+1 -2
View File
@@ -22,8 +22,7 @@ class RootAccessible : public DocAccessibleWrap,
NS_DECL_ISUPPORTS_INHERITED
public:
RootAccessible(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell);
RootAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell);
// nsIDOMEventListener
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) override;
+1 -2
View File
@@ -14,8 +14,7 @@ namespace a11y {
class DocAccessibleWrap : public DocAccessible
{
public:
DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell);
DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
virtual ~DocAccessibleWrap();
};
+2 -3
View File
@@ -10,9 +10,8 @@
using namespace mozilla::a11y;
DocAccessibleWrap::
DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell) :
DocAccessible(aDocument, aRootContent, aPresShell)
DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
DocAccessible(aDocument, aPresShell)
{
}
+1 -2
View File
@@ -18,8 +18,7 @@ namespace a11y {
class RootAccessibleWrap : public RootAccessible
{
public:
RootAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell);
RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
virtual ~RootAccessibleWrap();
Class GetNativeType ();
+2 -3
View File
@@ -16,9 +16,8 @@
using namespace mozilla::a11y;
RootAccessibleWrap::
RootAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell) :
RootAccessible(aDocument, aRootContent, aPresShell)
RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
RootAccessible(aDocument, aPresShell)
{
}
@@ -25,9 +25,8 @@ using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
DocAccessibleWrap::
DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell) :
DocAccessible(aDocument, aRootContent, aPresShell), mHWND(nullptr)
DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
DocAccessible(aDocument, aPresShell), mHWND(nullptr)
{
}
+1 -2
View File
@@ -15,8 +15,7 @@ namespace a11y {
class DocAccessibleWrap : public DocAccessible
{
public:
DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell);
DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
virtual ~DocAccessibleWrap();
DECL_IUNKNOWN_INHERITED
@@ -15,9 +15,8 @@ using namespace mozilla::a11y;
// Constructor/desctructor
RootAccessibleWrap::
RootAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell) :
RootAccessible(aDocument, aRootContent, aPresShell)
RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
RootAccessible(aDocument, aPresShell)
{
}
+1 -2
View File
@@ -14,8 +14,7 @@ namespace a11y {
class RootAccessibleWrap : public RootAccessible
{
public:
RootAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell);
RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
virtual ~RootAccessibleWrap();
// RootAccessible
+1 -2
View File
@@ -351,8 +351,7 @@ setUpdateTrackingId();
});
}
syncPrefDefault(AppConstants.MOZ_B2GDROID ? 'app.update.url.android'
: 'app.update.url');
syncPrefDefault('app.update.url');
syncPrefDefault('app.update.channel');
})();
-4
View File
@@ -230,10 +230,6 @@ var shell = {
},
bootstrap: function() {
#ifdef MOZ_B2GDROID
Cc["@mozilla.org/b2g/b2gdroid-setup;1"]
.getService(Ci.nsIObserver).observe(window, "shell-startup", null);
#endif
window.performance.mark('gecko-shell-bootstrap');
-5
View File
@@ -16,15 +16,12 @@ contract @mozilla.org/updates/update-prompt;1 {88b3eb21-d072-4e3b-886d-f89d8c49f
category system-update-provider MozillaProvider @mozilla.org/updates/update-prompt;1,{88b3eb21-d072-4e3b-886d-f89d8c49fe59}
#endif
# On b2gdroid we want to use the android implementation of the directory service.
#ifndef MOZ_B2GDROID
#ifdef MOZ_B2G
# DirectoryProvider.js
component {9181eb7c-6f87-11e1-90b1-4f59d80dd2e5} DirectoryProvider.js
contract @mozilla.org/b2g/directory-provider;1 {9181eb7c-6f87-11e1-90b1-4f59d80dd2e5}
category xpcom-directory-providers b2g-directory-provider @mozilla.org/b2g/directory-provider;1
#endif
#endif
# ActivitiesGlue.js
component {3a54788b-48cc-4ab4-93d6-0d6a8ef74f8e} ActivitiesGlue.js
@@ -94,7 +91,6 @@ contract @mozilla.org/fxaccounts/fxaccounts-ui-glue;1 {51875c14-91d7-4b8c-b65d-3
component {710322af-e6ae-4b0c-b2c9-1474a87b077e} HelperAppDialog.js
contract @mozilla.org/helperapplauncherdialog;1 {710322af-e6ae-4b0c-b2c9-1474a87b077e}
#ifndef MOZ_B2GDROID
#ifndef MOZ_WIDGET_GONK
component {c83c02c0-5d43-4e3e-987f-9173b313e880} SimulatorScreen.js
contract @mozilla.org/simulator-screen;1 {c83c02c0-5d43-4e3e-987f-9173b313e880}
@@ -108,7 +104,6 @@ component {385993fe-8710-4621-9fb1-00a09d8bec37} CommandLine.js
contract @mozilla.org/commandlinehandler/general-startup;1?type=b2gcmds {385993fe-8710-4621-9fb1-00a09d8bec37}
category command-line-handler m-b2gcmds @mozilla.org/commandlinehandler/general-startup;1?type=b2gcmds
#endif
#endif
# BootstrapCommandLine.js
component {fd663ec8-cf3f-4c2b-aacb-17a6915ccb44} BootstrapCommandLine.js
+1 -1
View File
@@ -43,7 +43,7 @@ EXTRA_PP_COMPONENTS += [
'B2GComponents.manifest',
]
if CONFIG['MOZ_B2G'] and not CONFIG['MOZ_B2GDROID']:
if CONFIG['MOZ_B2G']:
EXTRA_PP_COMPONENTS += [
'DirectoryProvider.js',
'RecoveryService.js',
+2 -10
View File
@@ -2,15 +2,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# For b2gdroid, gaia ends up in the assets/gaia folder in the APK.
GAIA_PATH := $(if MOZ_B2GDROID,gaia/assets/gaia,gaia/profile)
# For b2gdroid, we disable the screen timeout since this is managed by android.
# We also limit the app set to the production ones.
GAIA_OPTIONS := $(if MOZ_B2GDROID, \
GAIA_DISTRIBUTION_DIR=distros/b2gdroid \
NO_LOCK_SCREEN=1 \
)
GAIA_PATH := gaia/profile
GENERATED_DIRS += $(DIST)/bin/$(GAIA_PATH)
@@ -18,5 +10,5 @@ include $(topsrcdir)/config/rules.mk
libs::
+$(MAKE) -j1 -C $(GAIADIR) clean
+$(GAIA_OPTIONS) $(MAKE) -j1 -C $(GAIADIR) profile
+$(MAKE) -j1 -C $(GAIADIR) profile
(cd $(GAIADIR)/profile && tar $(TAR_CREATE_FLAGS) - .) | (cd $(ABS_DIST)/bin/$(GAIA_PATH) && tar -xf -)
+13 -15
View File
@@ -4,19 +4,17 @@
# 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/.
if not CONFIG['MOZ_B2GDROID']:
# b2gdroid does not build a runner executable, but it does build gaia; see Makefile.in.
Program(CONFIG['MOZ_APP_NAME'])
Program(CONFIG['MOZ_APP_NAME'])
if CONFIG['OS_ARCH'] == 'WINNT':
SOURCES += [
'run-b2g.cpp',
]
DEFINES['B2G_NAME'] = 'L"%s-bin%s"' % (PROGRAM, CONFIG['BIN_SUFFIX'])
DEFINES['GAIA_PATH'] = 'L"gaia\\\\profile"'
else:
SOURCES += [
'run-b2g.c',
]
DEFINES['B2G_NAME'] = '"%s-bin%s"' % (PROGRAM, CONFIG['BIN_SUFFIX'])
DEFINES['GAIA_PATH'] = '"gaia/profile"'
if CONFIG['OS_ARCH'] == 'WINNT':
SOURCES += [
'run-b2g.cpp',
]
DEFINES['B2G_NAME'] = 'L"%s-bin%s"' % (PROGRAM, CONFIG['BIN_SUFFIX'])
DEFINES['GAIA_PATH'] = 'L"gaia\\\\profile"'
else:
SOURCES += [
'run-b2g.c',
]
DEFINES['B2G_NAME'] = '"%s-bin%s"' % (PROGRAM, CONFIG['BIN_SUFFIX'])
DEFINES['GAIA_PATH'] = '"gaia/profile"'
+7 -11
View File
@@ -20,6 +20,8 @@ If you would like to use a different directory, hit CTRL+c and set the
MOZBUILD_STATE_PATH environment variable to the directory you would like to
use and re-run mach. For this change to take effect forever, you'll likely
want to export this environment variable from your shell's init scripts.
Press ENTER/RETURN to continue or CTRL+c to abort.
'''.lstrip()
@@ -41,6 +43,7 @@ SEARCH_PATHS = [
'config',
'dom/bindings',
'dom/bindings/parser',
'dom/media/test/external',
'layout/tools/reftest',
'other-licenses/ply',
'testing',
@@ -49,7 +52,6 @@ SEARCH_PATHS = [
'testing/luciddream',
'testing/marionette/client',
'testing/marionette/client/marionette/runner/mixins/browsermob-proxy-py',
'testing/marionette/transport',
'testing/marionette/driver',
'testing/mozbase/mozcrash',
'testing/mozbase/mozdebug',
@@ -83,6 +85,7 @@ SEARCH_PATHS = [
MACH_MODULES = [
'build/valgrind/mach_commands.py',
'dom/bindings/mach_commands.py',
'dom/media/test/external/mach_commands.py',
'layout/tools/reftest/mach_commands.py',
'python/mach_commands.py',
'python/mach/mach/commands/commandinfo.py',
@@ -188,26 +191,19 @@ def bootstrap(topsrcdir, mozilla_dir=None):
if state_env_dir:
if not os.path.exists(state_env_dir):
print('Creating global state directory from environment variable: %s'
% state_env_dir)
% state_env_dir)
os.makedirs(state_env_dir, mode=0o770)
print('Please re-run mach.')
sys.exit(1)
state_dir = state_env_dir
else:
if not os.path.exists(state_user_dir):
print(STATE_DIR_FIRST_RUN.format(userdir=state_user_dir))
try:
for i in range(20, -1, -1):
time.sleep(1)
sys.stdout.write('%d ' % i)
sys.stdout.flush()
sys.stdin.readline()
except KeyboardInterrupt:
sys.exit(1)
print('\nCreating default state directory: %s' % state_user_dir)
os.mkdir(state_user_dir)
print('Please re-run mach.')
sys.exit(1)
os.makedirs(state_user_dir, mode=0o770)
state_dir = state_user_dir
return state_dir
-1
View File
@@ -1,4 +1,3 @@
marionette_transport.pth:testing/marionette/transport
marionette_driver.pth:testing/marionette/driver
browsermobproxy.pth:testing/marionette/client/marionette/runner/mixins/browsermob-proxy-py
wptserve.pth:testing/web-platform/tests/tools/wptserve
-4
View File
@@ -3974,10 +3974,6 @@ esac
BUILD_BACKENDS="$BUILD_BACKENDS FasterMake"
if test -n "$MOZ_B2GDROID"; then
AC_DEFINE(MOZ_B2GDROID)
fi
AC_SUBST(MOZ_BUILD_APP)
AC_SUBST(MOZ_PHOENIX)
AC_SUBST(MOZ_XULRUNNER)
-123
View File
@@ -1,123 +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/. */
const { interfaces: Ci, utils: Cu } = Components;
this.EXPORTED_SYMBOLS = ["AndroidUtils"];
Cu.import("resource://gre/modules/AppsUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Messaging",
"resource://gre/modules/Messaging.jsm");
let appsRegistry = null;
function debug() {
//dump("-*- AndroidUtils " + Array.slice(arguments) + "\n");
}
// Helper functions to manage Android native apps. We keep them in the
// registry with a `kind` equals to "android-native" and we also store
// the package name and class name in the registry.
// Communication with the android side happens through json messages.
this.AndroidUtils = {
init: function(aRegistry) {
appsRegistry = aRegistry;
Services.obs.addObserver(this, "Android:Apps:Installed", false);
Services.obs.addObserver(this, "Android:Apps:Uninstalled", false);
},
uninit: function() {
Services.obs.removeObserver(this, "Android:Apps:Installed");
Services.obs.removeObserver(this, "Android:Apps:Uninstalled");
},
getOriginAndManifestURL: function(aPackageName) {
let origin = "android://" + aPackageName.toLowerCase();
let manifestURL = origin + "/manifest.webapp";
return [origin, manifestURL];
},
getPackageAndClassFromManifestURL: function(aManifestURL) {
debug("getPackageAndClassFromManifestURL " + aManifestURL);
let app = appsRegistry.getAppByManifestURL(aManifestURL);
if (!app) {
debug("No app for " + aManifestURL);
return [];
}
return [app.android_packagename, app.android_classname];
},
buildAndroidAppData: function(aApp) {
// Use the package and class name to get a unique origin.
// We put the version with the normal case as part of the manifest url.
let [origin, manifestURL] =
this.getOriginAndManifestURL(aApp.packagename);
// TODO: Bug 1204557 to improve the icons support.
let manifest = {
name: aApp.name,
icons: { "96": aApp.icon }
}
debug("Origin is " + origin);
let appData = {
app: {
installOrigin: origin,
origin: origin,
manifest: manifest,
manifestURL: manifestURL,
manifestHash: AppsUtils.computeHash(JSON.stringify(manifest)),
appStatus: Ci.nsIPrincipal.APP_STATUS_INSTALLED,
removable: aApp.removable,
android_packagename: aApp.packagename,
android_classname: aApp.classname
},
isBrowser: false,
isPackage: false
};
return appData;
},
installAndroidApps: function() {
return Messaging.sendRequestForResult({ type: "Apps:GetList" }).then(
aApps => {
debug("Got " + aApps.apps.length + " android apps.");
let promises = [];
aApps.apps.forEach(app => {
debug("App is " + app.name + " removable? " + app.removable);
let p = new Promise((aResolveInstall, aRejectInstall) => {
let appData = this.buildAndroidAppData(app);
appsRegistry.confirmInstall(appData, null, aResolveInstall);
});
promises.push(p);
});
// Wait for all apps to be installed.
return Promise.all(promises);
}
).then(appsRegistry._saveApps.bind(appsRegistry));
},
observe: function(aSubject, aTopic, aData) {
let data;
try {
data = JSON.parse(aData);
} catch(e) {
debug(e);
return;
}
if (aTopic == "Android:Apps:Installed") {
let appData = this.buildAndroidAppData(data);
appsRegistry.confirmInstall(appData);
} else if (aTopic == "Android:Apps:Uninstalled") {
let [origin, manifestURL] =
this.getOriginAndManifestURL(data.packagename);
appsRegistry.uninstall(manifestURL);
}
},
}
+5 -14
View File
@@ -260,11 +260,6 @@ this.DOMApplicationRegistry = {
this.getFullAppByManifestURL.bind(this));
MessageBroadcaster.init(this.getAppByManifestURL);
if (AppConstants.MOZ_B2GDROID) {
Cu.import("resource://gre/modules/AndroidUtils.jsm");
AndroidUtils.init(this);
}
},
// loads the current registry, that could be empty on first run.
@@ -530,7 +525,7 @@ this.DOMApplicationRegistry = {
// Installs a 3rd party app.
installPreinstalledApp: function installPreinstalledApp(aId) {
if (!AppConstants.MOZ_B2GDROID && AppConstants.platform !== "gonk") {
if (AppConstants.platform !== "gonk") {
return false;
}
@@ -799,14 +794,10 @@ this.DOMApplicationRegistry = {
}
}
if (AppConstants.MOZ_B2GDROID || AppConstants.MOZ_B2G) {
if (AppConstants.MOZ_B2G) {
yield this.installSystemApps();
}
if (AppConstants.MOZ_B2GDROID) {
yield AndroidUtils.installAndroidApps();
}
// At first run, install preloaded apps and set up their permissions.
for (let id in this.webapps) {
let isPreinstalled = this.installPreinstalledApp(id);
@@ -1319,7 +1310,7 @@ this.DOMApplicationRegistry = {
this.registryReady.then( () => {
switch (aMessage.name) {
case "Webapps:Install": {
if (AppConstants.platform == "android" && !AppConstants.MOZ_B2GDROID) {
if (AppConstants.platform == "android") {
Services.obs.notifyObservers(mm, "webapps-runtime-install", JSON.stringify(msg));
} else {
this.doInstall(msg, mm);
@@ -1330,7 +1321,7 @@ this.DOMApplicationRegistry = {
this.getSelf(msg, mm);
break;
case "Webapps:Uninstall":
if (AppConstants.platform == "android" && !AppConstants.MOZ_B2GDROID) {
if (AppConstants.platform == "android") {
Services.obs.notifyObservers(mm, "webapps-runtime-uninstall", JSON.stringify(msg));
} else {
this.doUninstall(msg, mm);
@@ -1352,7 +1343,7 @@ this.DOMApplicationRegistry = {
this.getNotInstalled(msg, mm);
break;
case "Webapps:InstallPackage": {
if (AppConstants.platform == "android" && !AppConstants.MOZ_B2GDROID) {
if (AppConstants.platform == "android") {
Services.obs.notifyObservers(mm, "webapps-runtime-install-package", JSON.stringify(msg));
} else {
this.doInstallPackage(msg, mm);
-5
View File
@@ -45,11 +45,6 @@ EXTRA_JS_MODULES += [
'UserCustomizations.jsm',
]
if CONFIG['MOZ_B2GDROID']:
EXTRA_JS_MODULES += [
'AndroidUtils.jsm',
]
EXTRA_PP_JS_MODULES += [
'AppsUtils.jsm',
'ImportExport.jsm',
+121 -23
View File
@@ -215,7 +215,7 @@ ExplicitChildIterator::Seek(nsIContent* aChildToFind)
}
nsIContent*
ExplicitChildIterator::Get()
ExplicitChildIterator::Get() const
{
MOZ_ASSERT(!mIsFirst);
@@ -311,27 +311,60 @@ ExplicitChildIterator::GetPreviousChild()
return mChild;
}
nsIContent*
AllChildrenIterator::Get() const
{
switch (mPhase) {
case eAtBeforeKid: {
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
MOZ_ASSERT(frame, "No frame at eAtBeforeKid phase");
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
MOZ_ASSERT(beforeFrame, "No content before frame at eAtBeforeKid phase");
return beforeFrame->GetContent();
}
case eAtExplicitKids:
return ExplicitChildIterator::Get();
case eAtAnonKids:
return mAnonKids[mAnonKidsIdx];
case eAtAfterKid: {
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
MOZ_ASSERT(frame, "No frame at eAtAfterKid phase");
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame);
MOZ_ASSERT(afterFrame, "No content before frame at eAtBeforeKid phase");
return afterFrame->GetContent();
}
default:
return nullptr;
}
}
bool
AllChildrenIterator::Seek(nsIContent* aChildToFind)
{
if (mPhase == eNeedBeforeKid) {
mPhase = eNeedExplicitKids;
if (mPhase == eAtBegin || mPhase == eAtBeforeKid) {
mPhase = eAtExplicitKids;
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
if (frame) {
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
if (beforeFrame) {
if (beforeFrame->GetContent() == aChildToFind) {
mPhase = eAtBeforeKid;
return true;
}
}
}
}
if (mPhase == eNeedExplicitKids) {
if (mPhase == eAtExplicitKids) {
if (ExplicitChildIterator::Seek(aChildToFind)) {
return true;
}
mPhase = eNeedAnonKids;
mPhase = eAtAnonKids;
}
nsIContent* child = nullptr;
@@ -345,59 +378,124 @@ AllChildrenIterator::Seek(nsIContent* aChildToFind)
nsIContent*
AllChildrenIterator::GetNextChild()
{
if (mPhase == eNeedBeforeKid) {
mPhase = eNeedExplicitKids;
if (mPhase == eAtBegin) {
mPhase = eAtExplicitKids;
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
if (frame) {
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
if (beforeFrame) {
mPhase = eAtBeforeKid;
return beforeFrame->GetContent();
}
}
}
if (mPhase == eNeedExplicitKids) {
if (mPhase == eAtBeforeKid) {
// Advance into our explicit kids.
mPhase = eAtExplicitKids;
}
if (mPhase == eAtExplicitKids) {
nsIContent* kid = ExplicitChildIterator::GetNextChild();
if (kid) {
return kid;
}
mPhase = eNeedAnonKids;
mPhase = eAtAnonKids;
}
if (mPhase == eNeedAnonKids) {
if (mPhase == eAtAnonKids) {
if (mAnonKids.IsEmpty()) {
MOZ_ASSERT(mAnonKidsIdx == UINT32_MAX);
nsIAnonymousContentCreator* ac =
do_QueryFrame(mOriginalContent->GetPrimaryFrame());
if (ac) {
ac->AppendAnonymousContentTo(mAnonKids, mFlags);
}
mAnonKidsIdx = 0;
}
if (!mAnonKids.IsEmpty()) {
nsIContent* nextKid = mAnonKids[0];
mAnonKids.RemoveElementAt(0);
if (mAnonKids.IsEmpty()) {
mPhase = eNeedAfterKid;
else {
if (mAnonKidsIdx == UINT32_MAX) {
mAnonKidsIdx = 0;
}
else {
mAnonKidsIdx++;
}
return nextKid;
}
mPhase = eNeedAfterKid;
}
if (mAnonKidsIdx < mAnonKids.Length()) {
return mAnonKids[mAnonKidsIdx];
}
if (mPhase == eNeedAfterKid) {
mPhase = eDone;
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
if (frame) {
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame);
if (afterFrame) {
mPhase = eAtAfterKid;
return afterFrame->GetContent();
}
}
}
mPhase = eAtEnd;
return nullptr;
}
nsIContent*
AllChildrenIterator::GetPreviousChild()
{
if (mPhase == eAtEnd) {
MOZ_ASSERT(mAnonKidsIdx == mAnonKids.Length());
mPhase = eAtAnonKids;
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
if (frame) {
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame);
if (afterFrame) {
mPhase = eAtAfterKid;
return afterFrame->GetContent();
}
}
}
if (mPhase == eAtAfterKid) {
mPhase = eAtAnonKids;
}
if (mPhase == eAtAnonKids) {
if (mAnonKids.IsEmpty()) {
nsIAnonymousContentCreator* ac =
do_QueryFrame(mOriginalContent->GetPrimaryFrame());
if (ac) {
ac->AppendAnonymousContentTo(mAnonKids, mFlags);
mAnonKidsIdx = mAnonKids.Length();
}
}
// If 0 then it turns into UINT32_MAX, which indicates the iterator is
// before the anonymous children.
--mAnonKidsIdx;
if (mAnonKidsIdx < mAnonKids.Length()) {
return mAnonKids[mAnonKidsIdx];
}
mPhase = eAtExplicitKids;
}
if (mPhase == eAtExplicitKids) {
nsIContent* kid = ExplicitChildIterator::GetPreviousChild();
if (kid) {
return kid;
}
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
if (frame) {
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
if (beforeFrame) {
mPhase = eAtBeforeKid;
return beforeFrame->GetContent();
}
}
}
mPhase = eAtBegin;
return nullptr;
}
+37 -17
View File
@@ -89,7 +89,7 @@ public:
// Returns the current target of this iterator (which might be an explicit
// child of the node, fallback content of an insertion point or
// a node distributed to an insertion point.
nsIContent* Get();
nsIContent* Get() const;
// The inverse of GetNextChild. Properly steps in and out of insertion
// points.
@@ -170,26 +170,27 @@ protected:
};
/**
* AllChildrenIterator returns the children of a element including before /
* after content and optionally XBL children. It assumes that no mutation of
* the DOM or frame tree takes place during iteration, and will break horribly
* if that is not true. The iterator can be initialized to start at the end by
* providing false for aStartAtBeginning in order to start iterating in reverse
* from the last child.
* AllChildrenIterator traverses the children of an element including before /
* after content and optionally XBL children. The iterator can be initialized
* to start at the end by providing false for aStartAtBeginning in order to
* start iterating in reverse from the last child.
*
* Note: it assumes that no mutation of the DOM or frame tree takes place during
* iteration, and will break horribly if that is not true.
*/
class AllChildrenIterator : private FlattenedChildIterator
{
public:
AllChildrenIterator(nsIContent* aNode, uint32_t aFlags, bool aStartAtBeginning = true) :
FlattenedChildIterator(aNode, aFlags, aStartAtBeginning),
mOriginalContent(aNode), mFlags(aFlags),
mPhase(eNeedBeforeKid) {}
mOriginalContent(aNode), mAnonKidsIdx(aStartAtBeginning ? UINT32_MAX : 0),
mFlags(aFlags), mPhase(aStartAtBeginning ? eAtBegin : eAtEnd) { }
AllChildrenIterator(AllChildrenIterator&& aOther)
: FlattenedChildIterator(Move(aOther)),
mOriginalContent(aOther.mOriginalContent),
mAnonKids(Move(aOther.mAnonKids)), mFlags(aOther.mFlags),
mPhase(aOther.mPhase)
mAnonKids(Move(aOther.mAnonKids)), mAnonKidsIdx(aOther.mAnonKidsIdx),
mFlags(aOther.mFlags), mPhase(aOther.mPhase)
#ifdef DEBUG
, mMutationGuard(aOther.mMutationGuard)
#endif
@@ -199,23 +200,42 @@ public:
~AllChildrenIterator() { MOZ_ASSERT(!mMutationGuard.Mutated(0)); }
#endif
// Returns the current target the iterator is at, or null if the iterator
// doesn't point to any child node (either eAtBegin or eAtEnd phase).
nsIContent* Get() const;
// Seeks the given node in children of a parent element, starting from
// the current iterator's position, and sets the iterator at the given child
// node if it was found.
bool Seek(nsIContent* aChildToFind);
nsIContent* GetNextChild();
nsIContent* GetPreviousChild();
nsIContent* Parent() const { return mOriginalContent; }
private:
enum IteratorPhase
{
eNeedBeforeKid,
eNeedExplicitKids,
eNeedAnonKids,
eNeedAfterKid,
eDone
eAtBegin,
eAtBeforeKid,
eAtExplicitKids,
eAtAnonKids,
eAtAfterKid,
eAtEnd
};
IteratorPhase Phase() const { return mPhase; }
private:
nsIContent* mOriginalContent;
// mAnonKids is an array of native anonymous children, mAnonKidsIdx is index
// in the array. If mAnonKidsIdx < mAnonKids.Length() and mPhase is
// eAtAnonKids then the iterator points at a child at mAnonKidsIdx index. If
// mAnonKidsIdx == mAnonKids.Length() then the iterator is somewhere after
// the last native anon child. If mAnonKidsIdx == UINT32_MAX then the iterator
// is somewhere before the first native anon child.
nsTArray<nsIContent*> mAnonKids;
uint32_t mAnonKidsIdx;
uint32_t mFlags;
IteratorPhase mPhase;
#ifdef DEBUG
+101 -39
View File
@@ -303,7 +303,6 @@ FindJSContext(nsIGlobalObject* aGlobalObject)
AutoJSAPI::AutoJSAPI()
: mCx(nullptr)
, mOwnErrorReporting(false)
, mOldAutoJSAPIOwnsErrorReporting(false)
, mIsMainThread(false) // For lack of anything better
{
@@ -311,27 +310,39 @@ AutoJSAPI::AutoJSAPI()
AutoJSAPI::~AutoJSAPI()
{
if (mOwnErrorReporting) {
ReportException();
// We need to do this _after_ processing the existing exception, because the
// JS engine can throw while doing that, and uses this bit to determine what
// to do in that case: squelch the exception if the bit is set, otherwise
// call the error reporter. Calling WarningOnlyErrorReporter with a
// non-warning will assert, so we need to make sure we do the former.
JS::ContextOptionsRef(cx()).setAutoJSAPIOwnsErrorReporting(mOldAutoJSAPIOwnsErrorReporting);
if (!mCx) {
// No need to do anything here: we never managed to Init, so can't have an
// exception on our (nonexistent) JSContext. We also don't need to restore
// any state on it.
return;
}
ReportException();
// We need to do this _after_ processing the existing exception, because the
// JS engine can throw while doing that, and uses this bit to determine what
// to do in that case: squelch the exception if the bit is set, otherwise
// call the error reporter. Calling WarningOnlyErrorReporter with a
// non-warning will assert, so we need to make sure we do the former.
JS::ContextOptionsRef(cx()).setAutoJSAPIOwnsErrorReporting(mOldAutoJSAPIOwnsErrorReporting);
if (mOldErrorReporter.isSome()) {
JS_SetErrorReporter(JS_GetRuntime(cx()), mOldErrorReporter.value());
}
}
void
WarningOnlyErrorReporter(JSContext* aCx, const char* aMessage,
JSErrorReport* aRep);
void
AutoJSAPI::InitInternal(JSObject* aGlobal, JSContext* aCx, bool aIsMainThread)
{
MOZ_ASSERT(aCx);
MOZ_ASSERT(aIsMainThread == NS_IsMainThread());
#ifdef DEBUG
bool haveException = JS_IsExceptionPending(aCx);
#endif // DEBUG
mCx = aCx;
mIsMainThread = aIsMainThread;
@@ -350,16 +361,81 @@ AutoJSAPI::InitInternal(JSObject* aGlobal, JSContext* aCx, bool aIsMainThread)
JSRuntime* rt = JS_GetRuntime(aCx);
mOldErrorReporter.emplace(JS_GetErrorReporter(rt));
if (aIsMainThread) {
JS_SetErrorReporter(rt, xpc::SystemErrorReporter);
mOldAutoJSAPIOwnsErrorReporting = JS::ContextOptionsRef(aCx).autoJSAPIOwnsErrorReporting();
JS::ContextOptionsRef(aCx).setAutoJSAPIOwnsErrorReporting(true);
JS_SetErrorReporter(rt, WarningOnlyErrorReporter);
#ifdef DEBUG
if (haveException) {
JS::Rooted<JS::Value> exn(aCx);
JS_GetPendingException(aCx, &exn);
JS_ClearPendingException(aCx);
if (exn.isObject()) {
JS::Rooted<JSObject*> exnObj(aCx, &exn.toObject());
nsAutoJSString stack, filename, name, message;
int32_t line;
JS::Rooted<JS::Value> tmp(aCx);
if (!JS_GetProperty(aCx, exnObj, "filename", &tmp)) {
JS_ClearPendingException(aCx);
}
if (tmp.isUndefined()) {
if (!JS_GetProperty(aCx, exnObj, "fileName", &tmp)) {
JS_ClearPendingException(aCx);
}
}
if (!filename.init(aCx, tmp)) {
JS_ClearPendingException(aCx);
}
if (!JS_GetProperty(aCx, exnObj, "stack", &tmp) ||
!stack.init(aCx, tmp)) {
JS_ClearPendingException(aCx);
}
if (!JS_GetProperty(aCx, exnObj, "name", &tmp) ||
!name.init(aCx, tmp)) {
JS_ClearPendingException(aCx);
}
if (!JS_GetProperty(aCx, exnObj, "message", &tmp) ||
!message.init(aCx, tmp)) {
JS_ClearPendingException(aCx);
}
if (!JS_GetProperty(aCx, exnObj, "lineNumber", &tmp) ||
!JS::ToInt32(aCx, tmp, &line)) {
JS_ClearPendingException(aCx);
line = 0;
}
printf_stderr("PREEXISTING EXCEPTION OBJECT: '%s: %s'\n%s:%d\n%s\n",
NS_ConvertUTF16toUTF8(name).get(),
NS_ConvertUTF16toUTF8(message).get(),
NS_ConvertUTF16toUTF8(filename).get(), line,
NS_ConvertUTF16toUTF8(stack).get());
} else {
// It's a primitive... not much we can do other than stringify it.
nsAutoJSString exnStr;
if (!exnStr.init(aCx, exn)) {
JS_ClearPendingException(aCx);
}
printf_stderr("PREEXISTING EXCEPTION PRIMITIVE: %s\n",
NS_ConvertUTF16toUTF8(exnStr).get());
}
MOZ_ASSERT(false, "We had an exception; we should not have");
}
#endif // DEBUG
}
AutoJSAPI::AutoJSAPI(nsIGlobalObject* aGlobalObject,
bool aIsMainThread,
JSContext* aCx)
: mOwnErrorReporting(false)
, mOldAutoJSAPIOwnsErrorReporting(false)
: mOldAutoJSAPIOwnsErrorReporting(false)
, mIsMainThread(aIsMainThread)
{
MOZ_ASSERT(aGlobalObject);
@@ -476,19 +552,11 @@ WarningOnlyErrorReporter(JSContext* aCx, const char* aMessage, JSErrorReport* aR
void
AutoJSAPI::TakeOwnershipOfErrorReporting()
{
MOZ_ASSERT(!mOwnErrorReporting);
mOwnErrorReporting = true;
JSRuntime *rt = JS_GetRuntime(cx());
mOldAutoJSAPIOwnsErrorReporting = JS::ContextOptionsRef(cx()).autoJSAPIOwnsErrorReporting();
JS::ContextOptionsRef(cx()).setAutoJSAPIOwnsErrorReporting(true);
JS_SetErrorReporter(rt, WarningOnlyErrorReporter);
}
void
AutoJSAPI::ReportException()
{
MOZ_ASSERT(OwnsErrorReporting(), "This is not our exception to report!");
if (!HasException()) {
return;
}
@@ -757,18 +825,6 @@ danger::AutoCxPusher::IsStackTop() const
AutoJSContext::AutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
: mCx(nullptr)
{
Init(false MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT);
}
AutoJSContext::AutoJSContext(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
: mCx(nullptr)
{
Init(aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT);
}
void
AutoJSContext::Init(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
{
JS::AutoSuppressGCAnalysis nogc;
MOZ_ASSERT(!mCx, "mCx should not be initialized!");
@@ -776,9 +832,7 @@ AutoJSContext::Init(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
nsXPConnect *xpc = nsXPConnect::XPConnect();
if (!aSafe) {
mCx = xpc->GetCurrentJSContext();
}
mCx = xpc->GetCurrentJSContext();
if (!mCx) {
mJSAPI.Init();
@@ -814,9 +868,17 @@ ThreadsafeAutoJSContext::operator JSContext*() const
}
AutoSafeJSContext::AutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
: AutoJSContext(true MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
, mAc(mCx, xpc::UnprivilegedJunkScope())
: AutoJSAPI()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
DebugOnly<bool> ok = Init(xpc::UnprivilegedJunkScope());
MOZ_ASSERT(ok,
"This is quite odd. We should have crashed in the "
"xpc::NativeGlobal() call if xpc::UnprivilegedJunkScope() "
"returned null, and inited correctly otherwise!");
}
ThreadsafeAutoSafeJSContext::ThreadsafeAutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
+8 -11
View File
@@ -272,7 +272,7 @@ public:
// process incremental, we allow consumers to opt-in to the new behavior
// while keeping the old behavior as the default.
void TakeOwnershipOfErrorReporting();
bool OwnsErrorReporting() { return mOwnErrorReporting; }
bool OwnsErrorReporting() { return true; }
// If HasException, report it. Otherwise, a no-op. This must be
// called only if OwnsErrorReporting().
void ReportException();
@@ -317,7 +317,6 @@ private:
JSContext *mCx;
// Track state between the old and new error reporting modes.
bool mOwnErrorReporting;
bool mOldAutoJSAPIOwnsErrorReporting;
// Whether we're mainthread or not; set when we're initialized.
bool mIsMainThread;
@@ -439,13 +438,6 @@ public:
operator JSContext*() const;
protected:
explicit AutoJSContext(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
// We need this Init() method because we can't use delegating constructor for
// the moment. It is a C++11 feature and we do not require C++11 to be
// supported to be able to compile Gecko.
void Init(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
JSContext* mCx;
dom::AutoJSAPI mJSAPI;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
@@ -473,11 +465,16 @@ private:
*
* Note - This is deprecated. Please use AutoJSAPI instead.
*/
class MOZ_RAII AutoSafeJSContext : public AutoJSContext {
class MOZ_RAII AutoSafeJSContext : public dom::AutoJSAPI {
public:
explicit AutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
operator JSContext*() const
{
return cx();
}
private:
JSAutoCompartment mAc;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
/**
+88 -37
View File
@@ -21,6 +21,7 @@
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerRunnable.h"
#include "mozilla/dom/WorkerScope.h"
#include "nsGlobalWindow.h"
#include "nsIScriptGlobalObject.h"
#include "nsIDOMWindow.h"
#include "nsIDocument.h"
@@ -150,18 +151,11 @@ public:
bool isBinary);
// ConnectionCloseEvents: 'error' event if needed, then 'close' event.
// - These must not be dispatched while we are still within an incoming call
// from JS (ex: close()). Set 'sync' to false in that case to dispatch in a
// separate new event.
nsresult ScheduleConnectionCloseEvents(nsISupports* aContext,
nsresult aStatusCode,
bool sync);
// 2nd half of ScheduleConnectionCloseEvents, sometimes run in its own event.
nsresult aStatusCode);
// 2nd half of ScheduleConnectionCloseEvents, run in its own event.
void DispatchConnectionCloseEvents();
// Dispatch a runnable to the right thread.
nsresult DispatchRunnable(nsIRunnable* aRunnable);
nsresult UpdateURI();
void AddRefObject();
@@ -520,14 +514,11 @@ WebSocketImpl::CloseConnection(uint16_t aReasonCode,
mWebSocket->SetReadyState(WebSocket::CLOSING);
// Can be called from Cancel() or Init() codepaths, so need to dispatch
// onerror/onclose asynchronously
ScheduleConnectionCloseEvents(
nullptr,
(aReasonCode == nsIWebSocketChannel::CLOSE_NORMAL ||
aReasonCode == nsIWebSocketChannel::CLOSE_GOING_AWAY) ?
NS_OK : NS_ERROR_FAILURE,
false);
NS_OK : NS_ERROR_FAILURE);
return NS_OK;
}
@@ -801,14 +792,12 @@ WebSocketImpl::OnStop(nsISupports* aContext, nsresult aStatusCode)
MOZ_ASSERT(mWebSocket->ReadyState() != WebSocket::CLOSED,
"Shouldn't already be CLOSED when OnStop called");
// called by network stack, not JS, so can dispatch JS events synchronously
return ScheduleConnectionCloseEvents(aContext, aStatusCode, true);
return ScheduleConnectionCloseEvents(aContext, aStatusCode);
}
nsresult
WebSocketImpl::ScheduleConnectionCloseEvents(nsISupports* aContext,
nsresult aStatusCode,
bool sync)
nsresult aStatusCode)
{
AssertIsOnTargetThread();
@@ -828,11 +817,7 @@ WebSocketImpl::ScheduleConnectionCloseEvents(nsISupports* aContext,
mOnCloseScheduled = true;
if (sync) {
DispatchConnectionCloseEvents();
} else {
NS_DispatchToCurrentThread(new CallDispatchConnectionCloseEvents(this));
}
NS_DispatchToCurrentThread(new CallDispatchConnectionCloseEvents(this));
}
return NS_OK;
@@ -1602,11 +1587,85 @@ WebSocketImpl::Init(JSContext* aCx,
if (globalObject) {
principal = globalObject->PrincipalOrNull();
}
nsCOMPtr<nsPIDOMWindow> innerWindow;
while (true) {
bool isNullPrincipal = true;
if (principal) {
nsresult rv = principal->GetIsNullPrincipal(&isNullPrincipal);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
}
if (!isNullPrincipal) {
break;
}
if (!innerWindow) {
innerWindow = do_QueryInterface(globalObject);
if (NS_WARN_IF(!innerWindow)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
}
nsCOMPtr<nsPIDOMWindow> parentWindow =
innerWindow->GetScriptableParent();
if (NS_WARN_IF(!parentWindow)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
nsCOMPtr<nsPIDOMWindow> currentInnerWindow =
parentWindow->GetCurrentInnerWindow();
if (NS_WARN_IF(!currentInnerWindow)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
// We are at the top. Let's see if we have an opener window.
if (innerWindow == currentInnerWindow) {
ErrorResult error;
parentWindow =
nsGlobalWindow::Cast(innerWindow)->GetOpenerWindow(error);
if (NS_WARN_IF(error.Failed())) {
error.SuppressException();
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
if (!parentWindow) {
break;
}
currentInnerWindow = parentWindow->GetCurrentInnerWindow();
if (NS_WARN_IF(!currentInnerWindow)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
MOZ_ASSERT(currentInnerWindow != innerWindow);
}
innerWindow = currentInnerWindow;
nsCOMPtr<nsIDocument> document = innerWindow->GetExtantDoc();
if (NS_WARN_IF(!document)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
principal = document->NodePrincipal();
}
}
if (principal) {
principal->GetURI(getter_AddRefs(originURI));
}
if (originURI) {
bool originIsHttps = false;
aRv = originURI->SchemeIs("https", &originIsHttps);
@@ -1832,16 +1891,8 @@ WebSocket::CreateAndDispatchMessageEvent(const nsACString& aData,
}
}
return CreateAndDispatchMessageEvent(jsapi.cx(), aData, aIsBinary);
}
nsresult
WebSocket::CreateAndDispatchMessageEvent(JSContext* aCx,
const nsACString& aData,
bool aIsBinary)
{
MOZ_ASSERT(mImpl);
AssertIsOnTargetThread();
jsapi.TakeOwnershipOfErrorReporting();
JSContext* cx = jsapi.cx();
nsresult rv = CheckInnerWindowCorrectness();
if (NS_FAILED(rv)) {
@@ -1851,19 +1902,19 @@ WebSocket::CreateAndDispatchMessageEvent(JSContext* aCx,
uint16_t messageType = nsIWebSocketEventListener::TYPE_STRING;
// Create appropriate JS object for message
JS::Rooted<JS::Value> jsData(aCx);
JS::Rooted<JS::Value> jsData(cx);
if (aIsBinary) {
if (mBinaryType == dom::BinaryType::Blob) {
messageType = nsIWebSocketEventListener::TYPE_BLOB;
nsresult rv = nsContentUtils::CreateBlobBuffer(aCx, GetOwner(), aData,
nsresult rv = nsContentUtils::CreateBlobBuffer(cx, GetOwner(), aData,
&jsData);
NS_ENSURE_SUCCESS(rv, rv);
} else if (mBinaryType == dom::BinaryType::Arraybuffer) {
messageType = nsIWebSocketEventListener::TYPE_ARRAYBUFFER;
JS::Rooted<JSObject*> arrayBuf(aCx);
nsresult rv = nsContentUtils::CreateArrayBuffer(aCx, aData,
JS::Rooted<JSObject*> arrayBuf(cx);
nsresult rv = nsContentUtils::CreateArrayBuffer(cx, aData,
arrayBuf.address());
NS_ENSURE_SUCCESS(rv, rv);
jsData.setObject(*arrayBuf);
@@ -1875,7 +1926,7 @@ WebSocket::CreateAndDispatchMessageEvent(JSContext* aCx,
// JS string
NS_ConvertUTF8toUTF16 utf16Data(aData);
JSString* jsString;
jsString = JS_NewUCStringCopyN(aCx, utf16Data.get(), utf16Data.Length());
jsString = JS_NewUCStringCopyN(cx, utf16Data.get(), utf16Data.Length());
NS_ENSURE_TRUE(jsString, NS_ERROR_FAILURE);
jsData.setString(jsString);
-3
View File
@@ -138,9 +138,6 @@ private: // constructor && distructor
nsresult CreateAndDispatchSimpleEvent(const nsAString& aName);
nsresult CreateAndDispatchMessageEvent(const nsACString& aData,
bool aIsBinary);
nsresult CreateAndDispatchMessageEvent(JSContext* aCx,
const nsACString& aData,
bool aIsBinary);
nsresult CreateAndDispatchCloseEvent(bool aWasClean,
uint16_t aCode,
const nsAString& aReason);
+1 -1
View File
@@ -853,10 +853,10 @@ public:
protected:
explicit nsGlobalWindow(nsGlobalWindow *aOuterWindow);
nsPIDOMWindow* GetOpenerWindowOuter();
nsPIDOMWindow* GetOpenerWindow(mozilla::ErrorResult& aError);
// Initializes the mWasOffline member variable
void InitWasOffline();
public:
nsPIDOMWindow* GetOpenerWindow(mozilla::ErrorResult& aError);
void GetOpener(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval,
mozilla::ErrorResult& aError);
already_AddRefed<nsPIDOMWindow> GetOpener() override;
@@ -198,13 +198,6 @@ DeviceStorageStatics::InitDirs()
NS_NewLocalFile(path, /* aFollowLinks */ true,
getter_AddRefs(mDirs[TYPE_SDCARD]));
}
#ifdef MOZ_B2GDROID
if (NS_SUCCEEDED(mozilla::AndroidBridge::GetExternalPublicDirectory(
NS_LITERAL_STRING(DEVICESTORAGE_APPS), path))) {
NS_NewLocalFile(path, /* aFollowLinks */ true,
getter_AddRefs(mDirs[TYPE_APPS]));
}
#endif
#elif defined (XP_UNIX)
dirService->Get(NS_UNIX_XDG_PICTURES_DIR,
@@ -239,10 +232,8 @@ DeviceStorageStatics::InitDirs()
}
#endif // !MOZ_WIDGET_ANDROID
#ifndef MOZ_B2GDROID
dirService->Get(NS_APP_USER_PROFILE_50_DIR, NS_GET_IID(nsIFile),
getter_AddRefs(mDirs[TYPE_APPS]));
#endif
if (mDirs[TYPE_APPS]) {
mDirs[TYPE_APPS]->AppendRelativeNativePath(NS_LITERAL_CSTRING("webapps"));
+3 -1
View File
@@ -28,6 +28,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "checkRenamed",
"resource://gre/modules/identity/IdentityUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "objectCopy",
"resource://gre/modules/identity/IdentityUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "makeMessageObject",
"resource://gre/modules/identity/IdentityUtils.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
"@mozilla.org/uuid-generator;1",
@@ -639,7 +641,7 @@ nsDOMIdentity.prototype = {
this._log("DOMIdentityMessage: " + JSON.stringify(message));
return message;
return makeMessageObject(message);
},
/**
+4 -12
View File
@@ -727,25 +727,17 @@ IDBFactory::OpenInternal(nsIPrincipal* aPrincipal,
}
}
AutoJSAPI autoJS;
RefPtr<IDBOpenDBRequest> request;
if (mWindow) {
AutoJSContext cx;
if (NS_WARN_IF(!autoJS.Init(mWindow, cx))) {
IDB_REPORT_INTERNAL_ERR();
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
return nullptr;
}
JS::Rooted<JSObject*> scriptOwner(cx,
static_cast<nsGlobalWindow*>(mWindow.get())->FastGetGlobalJSObject());
JS::Rooted<JSObject*> scriptOwner(nsContentUtils::RootingCxForThread(),
nsGlobalWindow::Cast(mWindow.get())->FastGetGlobalJSObject());
MOZ_ASSERT(scriptOwner);
request = IDBOpenDBRequest::CreateForWindow(this, mWindow, scriptOwner);
} else {
autoJS.Init(mOwningObject.get());
JS::Rooted<JSObject*> scriptOwner(autoJS.cx(), mOwningObject);
JS::Rooted<JSObject*> scriptOwner(nsContentUtils::RootingCxForThread(),
mOwningObject);
request = IDBOpenDBRequest::CreateForJS(this, scriptOwner);
if (!request) {
+3 -1
View File
@@ -9,6 +9,9 @@ support-files =
worker_bug1004814.js
geo_leak_test.html
[browser_test_toolbars_visibility.js]
support-files =
test_new_window_from_content_child.html
[browser_bug1008941_dismissGeolocationHanger.js]
skip-if = buildapp == 'mulet'
[browser_test__content.js]
@@ -28,7 +31,6 @@ skip-if= buildapp == 'mulet'
skip-if = (toolkit == 'android' || buildapp == 'b2g' || buildapp == 'mulet')
support-files =
test_new_window_from_content_child.html
test_new_window_from_content_child.js
[browser_webapps_permissions.js]
# TODO: Re-enable permissions tests on Mac, bug 795334
skip-if = buildapp != "b2g"
@@ -35,10 +35,7 @@
each preference.
*/
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const kXULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const kContentDoc = "http://www.example.com/browser/dom/tests/browser/test_new_window_from_content_child.html";
@@ -91,117 +88,8 @@ registerCleanupFunction(function() {
Services.prefs.setIntPref(kNewWindowPrefKey, originalNewWindowPref);
Services.prefs.setIntPref(kNewWindowRestrictionPrefKey,
originalNewWindowRestrictionPref);
// If there are any content tabs leftover, make sure they're not going to
// block exiting with onbeforeunload.
for (let tab of gBrowser.tabs) {
let browser = gBrowser.getBrowserForTab(tab);
if (browser.contentDocument.location == kContentDoc) {
closeTab(tab);
}
}
});
/**
* WindowOpenListener is a very simple nsIWindowMediatorListener that
* listens for a new window opening to aExpectedURI. It has two Promises
* attached to it - openPromise and closePromise. As you'd expect,
* openPromise resolves when the window is opened, and closePromise
* resolves if and when a window with the same URI closes. There is
* no attempt to make sure that it's the same window opening and
* closing - we just use the URI.
*
* @param aExpectedURI the URI to watch for in a new window.
* @return nsIWindowMediatorListener
*/
function WindowOpenListener(aExpectedURI) {
this._openDeferred = Promise.defer();
this._closeDeferred = Promise.defer();
this._expectedURI = aExpectedURI;
}
WindowOpenListener.prototype = {
get openPromise() {
return this._openDeferred.promise;
},
get closePromise() {
return this._closeDeferred.promise;
},
onOpenWindow: function(aXULWindow) {
let domWindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
let location = domWindow.document.location;
if (location == this._expectedURI) {
let deferred = this._openDeferred;
domWindow.addEventListener("load", function onWindowLoad() {
domWindow.removeEventListener("load", onWindowLoad);
deferred.resolve(domWindow);
})
}
},
onCloseWindow: function(aXULWindow) {
this._closeDeferred.resolve();
},
onWindowTitleChange: function(aXULWindow, aNewTitle) {},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowMediatorListener])
};
/**
* Adds the testing tab, and injects our frame script which
* allows us to send click events to links and other things.
*
* @return a Promise that resolves once the tab is loaded and ready.
*/
function loadAndSelectTestTab() {
let tab = gBrowser.addTab(kContentDoc);
gBrowser.selectedTab = tab;
let browser = gBrowser.getBrowserForTab(tab);
browser.messageManager.loadFrameScript(kContentScript, false);
let deferred = Promise.defer();
browser.addEventListener("DOMContentLoaded", function onBrowserLoad(aEvent) {
browser.removeEventListener("DOMContentLoaded", onBrowserLoad);
deferred.resolve(tab);
});
return deferred.promise;
}
/**
* Clears the onbeforeunload event handler from the testing tab,
* and then closes the tab.
*
* @param aTab the testing tab to close.
* @param a Promise that resolves once the tab has been closed.
*/
function closeTab(aTab) {
let deferred = Promise.defer();
let browserMM = gBrowser.getBrowserForTab(aTab).messageManager;
browserMM.sendAsyncMessage("TEST:allow-unload");
browserMM.addMessageListener("TEST:allow-unload:done", function(aMessage) {
gBrowser.removeTab(aTab);
deferred.resolve();
})
return deferred.promise;
}
/**
* Sends a click event on some item into a tab.
*
* @param aTab the tab to send the click event to
* @param aItemId the item within the tab content to click.
*/
function clickInTab(aTab, aItemId) {
let browserMM = gBrowser.getBrowserForTab(aTab).messageManager;
browserMM.sendAsyncMessage("TEST:click-item", {
details: aItemId,
});
}
/**
* For some expectation when a link is clicked, creates and
* returns a Promise that resolves when that expectation is
@@ -213,62 +101,38 @@ function clickInTab(aTab, aItemId) {
* occurred - for example, if a new window was opened, this function
* closes it before resolving.
*
* @param aTab the tab with the test document
* @param aBrowser the <xul:browser> with the test document
* @param aExpectation one of kSameTab, kNewWin, or kNewTab.
* @return a Promise that resolves when the expectation is fulfilled,
* and cleaned up after.
*/
function prepareForResult(aTab, aExpectation) {
let deferred = Promise.defer();
let browser = gBrowser.getBrowserForTab(aTab);
function prepareForResult(aBrowser, aExpectation) {
switch(aExpectation) {
case kSameTab:
// We expect about:blank to be loaded in the current tab. In order
// to prevent us needing to reload the document and content script
// after browsing away, we'll detect the attempt by using onbeforeunload,
// and then cancel the unload. It's a hack, but it's also a pretty
// cheap way of detecting when we're browsing away in the test tab.
// The onbeforeunload event handler is set in the content script automatically.
browser.addEventListener("DOMWillOpenModalDialog", function onModalDialog() {
browser.removeEventListener("DOMWillOpenModalDialog", onModalDialog, true);
executeSoon(() => {
let stack = browser.parentNode;
let dialogs = stack.getElementsByTagNameNS(kXULNS, "tabmodalprompt");
dialogs[0].ui.button1.click()
deferred.resolve();
})
}, true);
return Task.spawn(function*() {
yield BrowserTestUtils.browserLoaded(aBrowser);
is(aBrowser.currentURI.spec, "about:robots", "Should be at about:robots");
// Now put the browser back where it came from
yield BrowserTestUtils.loadURI(aBrowser, kContentDoc);
yield BrowserTestUtils.browserLoaded(aBrowser);
});
break;
case kNewWin:
let listener = new WindowOpenListener("about:blank");
Services.wm.addListener(listener);
info("Waiting for a new about:blank window");
listener.openPromise.then(function(aWindow) {
info("Got the new about:blank window - closing it.");
executeSoon(() => {
aWindow.close();
});
listener.closePromise.then(() => {
info("New about:blank window closed!");
Services.wm.removeListener(listener);
deferred.resolve();
});
return Task.spawn(function*() {
let newWin = yield BrowserTestUtils.waitForNewWindow();
let newBrowser = newWin.gBrowser.selectedBrowser;
yield BrowserTestUtils.browserLoaded(newBrowser);
is(newBrowser.currentURI.spec, "about:robots", "Should be at about:robots");
yield BrowserTestUtils.closeWindow(newWin);
});
break;
case kNewTab:
gBrowser.tabContainer.addEventListener("TabOpen", function onTabOpen(aEvent) {
let newTab = aEvent.target;
let newBrowser = gBrowser.getBrowserForTab(newTab);
if (newBrowser.contentDocument.location.href == "about:blank") {
gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen);
executeSoon(() => {
gBrowser.removeTab(newTab);
deferred.resolve();
})
}
})
return Task.spawn(function*() {
let newTab = yield BrowserTestUtils.waitForNewTab(gBrowser);
is(newTab.linkedBrowser.currentURI.spec, "about:robots",
"Should be at about:robots");
yield BrowserTestUtils.removeTab(newTab);
});
break;
default:
ok(false, "prepareForResult can't handle an expectation of " + aExpectation)
@@ -283,14 +147,16 @@ function prepareForResult(aTab, aExpectation) {
* perform as specified in the supplied aMatrix (kWinOpenDefault,
* for example).
*
* @param aLinkId the id of the link within the testing page to test.
* @param aLinkSelector a selector for the link within the testing page to click.
* @param aMatrix a testing matrix for the
* browser.link.open_newwindow and browser.link.open_newwindow.restriction
* prefs to test against. See kWinOpenDefault for an example.
*/
function testLinkWithMatrix(aLinkId, aMatrix) {
return Task.spawn(function* () {
let tab = yield loadAndSelectTestTab();
function testLinkWithMatrix(aLinkSelector, aMatrix) {
return BrowserTestUtils.withNewTab({
gBrowser,
url: kContentDoc,
}, function*(browser) {
// This nested for-loop is unravelling the matrix const
// we set up, and gives us three things through each tick
// of the inner loop:
@@ -298,7 +164,6 @@ function testLinkWithMatrix(aLinkId, aMatrix) {
// 2) newWindowRestPref: a browser.link.open_newwindow.restriction pref to try
// 3) expectation: what we expect the click outcome on this link to be,
// which will either be kSameTab, kNewWin or kNewTab.
for (let newWindowPref in aMatrix) {
let expectations = aMatrix[newWindowPref];
for (let i = 0; i < expectations.length; ++i) {
@@ -307,28 +172,31 @@ function testLinkWithMatrix(aLinkId, aMatrix) {
Services.prefs.setIntPref("browser.link.open_newwindow", newWindowPref);
Services.prefs.setIntPref("browser.link.open_newwindow.restriction", newWindowRestPref);
info("Clicking on " + aLinkId);
info("Clicking on " + aLinkSelector);
info("Testing with browser.link.open_newwindow = " + newWindowPref + " and " +
"browser.link.open_newwindow.restriction = " + newWindowRestPref);
info("Expecting: " + expectation);
let resultPromise = prepareForResult(tab, expectation);
clickInTab(tab, aLinkId);
let resultPromise = prepareForResult(browser, expectation);
BrowserTestUtils.synthesizeMouseAtCenter(aLinkSelector, {}, browser);
yield resultPromise;
ok(true, "Got expectation: " + expectation);
info("Got expectation: " + expectation);
}
}
yield closeTab(tab);
});
}
add_task(function* test_window_open_with_defaults() {
yield testLinkWithMatrix("winOpenDefault", kWinOpenDefault);
yield testLinkWithMatrix("#winOpenDefault", kWinOpenDefault);
});
add_task(function* test_window_open_with_non_defaults() {
yield testLinkWithMatrix("winOpenNonDefault", kWinOpenNonDefault);
yield testLinkWithMatrix("#winOpenNonDefault", kWinOpenNonDefault);
});
add_task(function* test_window_open_dialog() {
yield testLinkWithMatrix("#winOpenDialog", kWinOpenNonDefault);
});
add_task(function* test_target__blank() {
yield testLinkWithMatrix("targetBlank", kTargetBlank);
yield testLinkWithMatrix("#targetBlank", kTargetBlank);
});
@@ -0,0 +1,187 @@
// Tests that toolbars have proper visibility when opening a new window
// in either content or chrome context.
const CONTENT_PAGE = "http://www.example.com/browser/dom/tests/browser/test_new_window_from_content_child.html";
/**
* This function retrieves the visibility state of the toolbars of a
* window within the content context.
*
* @param aBrowser (<xul:browser>)
* The browser to query for toolbar visibility states
* @returns Promise
* A promise that resolves when the toolbar state is retrieved
* within the content context, which value is an object that holds
* the visibility state of the toolbars
*/
function getToolbarsFromBrowserContent(aBrowser) {
return ContentTask.spawn(aBrowser, {}, function*() {
return {
toolbar: content.toolbar.visible,
menubar: content.menubar.visible,
personalbar: content.personalbar.visible,
statusbar: content.statusbar.visible,
locationbar: content.locationbar.visible,
};
});
}
/**
* This function retrieves the visibility state of the toolbars of a
* window within the chrome context.
*
* @param win
* the chrome privileged window
* @returns object
* an object that holds the visibility state of the toolbars
*/
function getToolbarsFromWindowChrome(win) {
return {
toolbar: win.toolbar.visible,
menubar: win.menubar.visible,
personalbar: win.personalbar.visible,
statusbar: win.statusbar.visible,
locationbar: win.locationbar.visible,
}
}
/**
* Tests toolbar visibility when opening a window with default parameters.
*
* @param toolbars
* the visibility state of the toolbar elements
*/
function testDefaultToolbars(toolbars) {
ok(toolbars.locationbar,
"locationbar should be visible on default window.open()");
ok(toolbars.menubar,
"menubar be visible on default window.open()");
ok(toolbars.personalbar,
"personalbar should be visible on default window.open()");
ok(toolbars.statusbar,
"statusbar should be visible on default window.open()");
ok(toolbars.toolbar,
"toolbar should be visible on default window.open()");
}
/**
* Tests toolbar visibility when opening a window with non default parameters
* on the content context.
*
* Ensure that locationbar can't be hidden in the content context, see bug#337344.
*
* @param toolbars
* the visibility state of the toolbar elements
*/
function testNonDefaultContentToolbars(toolbars) {
// Locationbar should always be visible on content context
ok(toolbars.locationbar,
"locationbar should be visible even with location=no");
ok(!toolbars.menubar,
"menubar shouldn't be visible when menubar=no");
ok(!toolbars.personalbar,
"personalbar shouldn't be visible when personalbar=no");
// statusbar will report visible=true even when it's hidden because of bug#55820
todo(!toolbars.statusbar,
"statusbar shouldn't be visible when status=no");
ok(!toolbars.toolbar,
"toolbar shouldn't be visible when toolbar=no");
}
/**
* Tests toolbar visibility when opening a window with non default parameters
* on the chrome context.
*
* @param toolbars
* the visibility state of the toolbar elements
*/
function testNonDefaultChromeToolbars(toolbars) {
// None of the toolbars should be visible if hidden with chrome privileges
ok(!toolbars.locationbar,
"locationbar should be visible on default window.open()");
ok(!toolbars.menubar,
"menubar be visible on default window.open()");
ok(!toolbars.personalbar,
"personalbar should be visible on default window.open()");
ok(!toolbars.statusbar,
"statusbar should be visible on default window.open()");
ok(!toolbars.toolbar,
"toolbar should be visible on default window.open()");
}
/**
* Ensure that toolbars of a window opened in the content context have the
* correct visibility.
*
* A window opened with default parameters should have all toolbars visible.
*
* A window opened with "location=no, personalbar=no, toolbar=no, scrollbars=no,
* menubar=no, status=no", should only have location visible.
*/
add_task(function*() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: CONTENT_PAGE,
}, function*(browser) {
// First, call the default window.open() which will open a new tab
let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser);
yield BrowserTestUtils.synthesizeMouseAtCenter("#winOpenDefault", {}, browser);
let tab = yield newTabPromise;
// Check that all toolbars are visible
let toolbars = yield getToolbarsFromBrowserContent(gBrowser.selectedBrowser);
testDefaultToolbars(toolbars);
// Cleanup
yield BrowserTestUtils.removeTab(tab);
// Now let's open a window with toolbars hidden
let winPromise = BrowserTestUtils.waitForNewWindow();
yield BrowserTestUtils.synthesizeMouseAtCenter("#winOpenNonDefault", {}, browser);
let popupWindow = yield winPromise;
let popupBrowser = popupWindow.gBrowser.selectedBrowser;
yield BrowserTestUtils.browserLoaded(popupBrowser);
// Test toolbars visibility
let popupToolbars = yield getToolbarsFromBrowserContent(popupBrowser);
testNonDefaultContentToolbars(popupToolbars);
// Cleanup
yield BrowserTestUtils.closeWindow(popupWindow);
});
});
/**
* Ensure that toolbars of a window opened in the chrome context have the
* correct visibility.
*
* A window opened with default parameters should have all toolbars visible.
*
* A window opened with "location=no, personalbar=no, toolbar=no, scrollbars=no,
* menubar=no, status=no", should not have any toolbar visible.
*/
add_task(function* () {
// First open a default window from this chrome context
let defaultWindowPromise = BrowserTestUtils.waitForNewWindow();
window.open("about:robots", "_blank");
let defaultWindow = yield defaultWindowPromise;
// Check that all toolbars are visible
let toolbars = getToolbarsFromWindowChrome(defaultWindow);
testDefaultToolbars(toolbars);
// Now lets open a window with toolbars hidden from this chrome context
let features = "location=no, personalbar=no, toolbar=no, scrollbars=no, menubar=no, status=no";
let popupWindowPromise = BrowserTestUtils.waitForNewWindow();
window.open("about:robots", "_blank", features);
let popupWindow = yield popupWindowPromise;
// Test none of the tooolbars are visible
let hiddenToolbars = getToolbarsFromWindowChrome(popupWindow);
testNonDefaultChromeToolbars(hiddenToolbars);
// Cleanup
yield BrowserTestUtils.closeWindow(defaultWindow);
yield BrowserTestUtils.closeWindow(popupWindow);
});
@@ -5,19 +5,15 @@
</head>
<body>
<p><a id="winOpenDefault" href="#" onclick="return openWindow();">Open a new window via window.open with default features.</a></p>
<p><a id="winOpenNonDefault" href="#" onclick="return openWindow('resizable=no, toolbar=no, scrollbars=no, menubar=no, status=no, directories=no, height=100, width=500');">Open a new window via window.open with non-default features.</a></p>
<p><a id="targetBlank" href="about:blank" target="_blank">Open a new window via target="_blank".</a></p>
<p><a id="winOpenNonDefault" href="#" onclick="return openWindow('resizable=no, location=no, personalbar=no, toolbar=no, scrollbars=no, menubar=no, status=no, directories=no, height=100, width=500');">Open a new window via window.open with non-default features.</a></p>
<p><a id="winOpenDialog" href="#" onclick="return openWindow('dialog=yes');">Open a new window via window.open with dialog=1.</a></p>
<p><a id="targetBlank" href="about:robots" target="_blank">Open a new window via target="_blank".</a></p>
</body>
</html>
<script>
function openWindow(aFeatures="") {
window.open("about:blank", "_blank", aFeatures);
window.open("about:robots", "_blank", aFeatures);
return false;
}
window.onbeforeunload = function(aEvent) {
return "We should not browse away from this document.";
}
</script>
</script>
@@ -1,19 +0,0 @@
// A hacky mechanism for catching and detecting that we're attempting
// to browse away is by setting the onbeforeunload event handler. We
// detect this dialog opening in the parent test script, and dismiss
// it.
function handleClickItem(aMessage) {
let itemId = aMessage.data.details;
content.console.log("Getting item with ID: " + itemId);
let item = content.document.getElementById(itemId);
item.click();
}
function handleAllowUnload(aMessage) {
content.onbeforeunload = null;
sendSyncMessage("TEST:allow-unload:done");
}
addMessageListener("TEST:click-item", handleClickItem);
addMessageListener("TEST:allow-unload", handleAllowUnload);
+1 -1
View File
@@ -297,7 +297,7 @@ mozJSComponentLoader::ReallyInit()
// results in getting the wrong value.
// But we don't want that on Firefox Mulet as it break most Firefox JSMs...
// Also disable on debug builds to break js components that rely on this.
#if defined(MOZ_B2G) && !defined(MOZ_MULET) && !defined(MOZ_B2GDROID) && !defined(DEBUG)
#if defined(MOZ_B2G) && !defined(MOZ_MULET) && !defined(DEBUG)
mReuseLoaderGlobal = true;
#endif
-6
View File
@@ -1199,17 +1199,11 @@ InitSystemMetrics()
sSystemMetrics->AppendElement(nsGkAtoms::swipe_animation_enabled);
}
// On b2gdroid, make it so that we always have a physical home button from
// gecko's point of view, event if it's just the Android home button remapped.
#ifdef MOZ_B2GDROID
sSystemMetrics->AppendElement(nsGkAtoms::physical_home_button);
#else
rv = LookAndFeel::GetInt(LookAndFeel::eIntID_PhysicalHomeButton,
&metricResult);
if (NS_SUCCEEDED(rv) && metricResult) {
sSystemMetrics->AppendElement(nsGkAtoms::physical_home_button);
}
#endif
#ifdef XP_WIN
if (NS_SUCCEEDED(
@@ -2854,18 +2854,15 @@ WebSocketChannel::StartWebsocketData()
mDataStarted = 1;
}
LOG(("WebSocketChannel::StartWebsocketData Notifying Listener %p\n",
mListenerMT ? mListenerMT->mListener.get() : nullptr));
if (mListenerMT) {
mListenerMT->mListener->OnStart(mListenerMT->mContext);
}
rv = mSocketIn->AsyncWait(this, 0, 0, mSocketThread);
if (NS_FAILED(rv)) {
LOG(("WebSocketChannel::StartWebsocketData mSocketIn->AsyncWait() failed "
"with error %0x%08x\n", rv));
return rv;
"with error 0x%08x", rv));
return mSocketThread->Dispatch(
NS_NewRunnableMethodWithArgs<nsresult>(this,
&WebSocketChannel::AbortSession,
rv),
NS_DISPATCH_NORMAL);
}
if (mPingInterval) {
@@ -2873,10 +2870,19 @@ WebSocketChannel::StartWebsocketData()
NS_NewRunnableMethod(this, &WebSocketChannel::StartPinging),
NS_DISPATCH_NORMAL);
if (NS_FAILED(rv)) {
LOG(("WebSocketChannel::StartWebsocketData Could not start pinging, "
"rv=0x%08x", rv));
return rv;
}
}
LOG(("WebSocketChannel::StartWebsocketData Notifying Listener %p",
mListenerMT ? mListenerMT->mListener.get() : nullptr));
if (mListenerMT) {
mListenerMT->mListener->OnStart(mListenerMT->mContext);
}
return NS_OK;
}
@@ -1,6 +1,5 @@
-r mozbase_requirements.txt
../tools/wptserve
../marionette/transport
../marionette/driver
../marionette/marionette/runner/mixins/browsermob-proxy-py
../marionette
@@ -2,7 +2,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
__version__ = '2.0.0'
__version__ = '2.2.0'
from .marionette_test import (
CommonTestCase,
@@ -3,6 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import os
import unittest
from marionette import MarionetteTestCase
from marionette_driver.addons import Addons, AddonInstallException
@@ -14,7 +15,6 @@ class TestAddons(MarionetteTestCase):
def setUp(self):
MarionetteTestCase.setUp(self)
self.addons = Addons(self.marionette)
self.addon_path = os.path.join(here, 'mn-restartless.xpi')
@property
@@ -32,19 +32,27 @@ class TestAddons(MarionetteTestCase):
return addons
def test_install_and_remove_unsigned_addon(self):
self.addons.signature_required = False
def test_install_and_remove_temporary_unsigned_addon(self):
addon_path = os.path.join(here, 'mn-restartless-unsigned.xpi')
addon_id = self.addons.install(self.addon_path)
addon_id = self.addons.install(addon_path, temp=True)
self.assertIn(addon_id, self.all_addon_ids)
self.addons.uninstall(addon_id)
self.assertNotIn(addon_id, self.all_addon_ids)
self.addons.signature_required = True
def test_install_unsigned_addon_with_signature_required(self):
self.signature_required = True
def test_install_unsigned_addon(self):
addon_path = os.path.join(here, 'mn-restartless-unsigned.xpi')
with self.assertRaises(AddonInstallException):
self.addons.install(self.addon_path)
self.addons.install(addon_path)
@unittest.skip("need to get the test extension signed")
def test_install_and_remove_signed_addon(self):
addon_path = os.path.join(here, 'mn-restartless-signed.xpi')
addon_id = self.addons.install(addon_path)
self.assertIn(addon_id, self.all_addon_ids)
self.addons.uninstall(addon_id)
self.assertNotIn(addon_id, self.all_addon_ids)
+1 -1
View File
@@ -1,4 +1,4 @@
marionette-driver >= 1.1.1
marionette-driver >= 1.3.0
browsermob-proxy >= 0.6.0
manifestparser >= 1.1
wptserve >= 1.3.0
@@ -2,7 +2,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
__version__ = '1.1.1'
__version__ = '1.3.0'
from marionette_driver import (
addons,
@@ -37,25 +37,8 @@ class Addons(object):
def __init__(self, marionette):
self._mn = marionette
self._signature_required = True
def on_restart():
self.signature_required = self._signature_required
self._mn.restart_handlers.append(on_restart)
@property
def signature_required(self):
"""
Whether or not addons must be signed.
"""
return self._signature_required
@signature_required.setter
def signature_required(self, val):
self._mn.set_pref('xpinstall.signatures.required', val)
self._signature_required = val
def install(self, path):
def install(self, path, temp=False):
"""Install an addon.
If the addon is restartless, it can be used right away. Otherwise
@@ -63,6 +46,9 @@ class Addons(object):
will be needed.
:param path: A file path to the extension to be installed.
:param temp: Install a temporary addon. Temporary addons will
automatically be uninstalled on shutdown and do not need
to be signed, though they must be restartless.
:returns: The addon ID string of the newly installed addon.
:raises: :exc:`AddonInstallException`
"""
@@ -77,18 +63,29 @@ class Addons(object):
onInstallFailed: function(install) {
marionetteScriptFinished([null, install.error]);
},
onInstalled: function(addon) {
marionetteScriptFinished([addon.id, 0]);
}
}
let file = new FileUtils.File(arguments[0]);
AddonManager.getInstallForFile(file, function(aInstall) {
if (aInstall.error != 0) {
marionetteScriptFinished([null, aInstall.error]);
}
aInstall.addListener(listener);
aInstall.install();
});
""", script_args=[path], debug_script=True)
let temp = arguments[1];
if (!temp) {
AddonManager.getInstallForFile(file, function(aInstall) {
if (aInstall.error != 0) {
marionetteScriptFinished([null, aInstall.error]);
}
aInstall.addListener(listener);
aInstall.install();
});
} else {
AddonManager.addAddonListener(listener);
AddonManager.installTemporaryAddon(file);
}
""", script_args=[path, temp], debug_script=True)
if status:
if status in ADDON_INSTALL_ERRORS:
@@ -15,12 +15,12 @@ from contextlib import contextmanager
from decorators import do_crash_check
from keys import Keys
import marionette_transport as transport
from mozrunner import B2GEmulatorRunner
import geckoinstance
import errors
import transport
WEBELEMENT_KEY = "ELEMENT"
W3C_WEBELEMENT_KEY = "element-6066-11e4-a52e-4f735466cecf"
@@ -563,7 +563,6 @@ class Marionette(object):
self.device_serial = device_serial
self.adb_host = adb_host
self.adb_port = adb_port
self.restart_handlers = []
startup_timeout = startup_timeout or self.DEFAULT_STARTUP_TIMEOUT
@@ -1111,11 +1110,6 @@ class Marionette(object):
self.start_session(session_id=self.session_id)
self._reset_timeouts()
# Give consumers who depended on the old session a
# chance to re-initialize and/or restore state.
for handler in self.restart_handlers:
handler()
def absolute_url(self, relative_url):
'''
Returns an absolute url for files served from Marionette's www directory.
@@ -1,2 +1 @@
marionette-transport == 1.0.0
mozrunner >= 6.9
@@ -1,7 +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/
__version__ = '1.0.0'
from transport import *
-53
View File
@@ -1,53 +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/.
import os
import re
from setuptools import setup, find_packages
THIS_DIR = os.path.dirname(os.path.realpath(__name__))
def read(*parts):
with open(os.path.join(THIS_DIR, *parts)) as f:
return f.read()
def get_version():
return re.findall("__version__ = '([\d\.]+)'",
read('marionette_transport', '__init__.py'), re.M)[0]
long_description = \
"""Marionette_ is a Mozilla project to enable remote automation in Gecko-based
projects, including desktop Firefox, mobile Firefox, and Firefox OS. It is
inspired by `Selenium Webdriver`_.
This package defines the transport layer used by a Marionette client to
communicate with the Marionette server embedded in Gecko. It has no entry
points; rather it's designed to be used by a Marionette client implementation.
.. _Marionette: https://developer.mozilla.org/en/Marionette
.. _`Selenium Webdriver`: http://www.seleniumhq.org/projects/webdriver/"""
setup(name='marionette-transport',
version=get_version(),
description="Transport layer for Marionette client",
long_description=long_description,
classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
keywords='mozilla',
author='Mozilla Automation and Tools Team',
author_email='tools@lists.mozilla.org',
url='https://developer.mozilla.org/en-US/docs/Marionette',
license='MPL',
packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
package_data={},
include_package_data=False,
zip_safe=False,
entry_points="""
""",
install_requires=[],
)
+7 -3
View File
@@ -1,9 +1,13 @@
Serving up content to be consumed by the browser
================================================
I know, right? ANOTHER Python HTTP server? In all seriousness, we
weren't able to find anything out there that was fast enough, flexible
enough, and easy-to-use enough for our needs. So we created our own.
.. warning:: The mozhttpd module is considered obsolete. For new code,
please use wptserve_ which can do everything mozhttpd does
and more.
.. _wptserve: https://pypi.python.org/pypi/wptserve
:mod:`mozhttpd` --- Simple webserver
------------------------------------
+1 -1
View File
@@ -5,7 +5,7 @@
from setuptools import setup
PACKAGE_NAME = 'mozcrash'
PACKAGE_VERSION = '0.14'
PACKAGE_VERSION = '0.15'
# dependencies
deps = ['mozfile >= 1.0',
+1 -1
View File
@@ -5,7 +5,7 @@
from setuptools import setup
PACKAGE_NAME = 'mozdevice'
PACKAGE_VERSION = '0.45'
PACKAGE_VERSION = '0.46'
deps = ['mozfile >= 1.0',
'mozlog >= 3.0',
+1 -1
View File
@@ -4,7 +4,7 @@
from setuptools import setup
PACKAGE_VERSION = '0.26'
PACKAGE_VERSION = '0.27'
deps = ['mozinfo',
'mozlog >= 3.0',
@@ -11,7 +11,6 @@ import zipfile
from xml.dom import minidom
import mozfile
from manifestparser import ManifestParser
from mozlog.unstructured import getLogger
# Needed for the AMO's rest API - https://developer.mozilla.org/en/addons.mozilla.org_%28AMO%29_API_Developers%27_Guide/The_generic_AMO_API
@@ -185,6 +184,14 @@ class AddonManager(object):
Installs addons from a manifest
:param filepath: path to the manifest of addons to install
"""
try:
from manifestparser import ManifestParser
except ImportError:
module_logger.critical(
"Installing addons from manifest requires the"
" manifestparser package to be installed.")
raise
manifest = ManifestParser()
manifest.read(filepath)
addons = manifest.get()
+3 -4
View File
@@ -6,14 +6,12 @@ import sys
from setuptools import setup
PACKAGE_NAME = 'mozprofile'
PACKAGE_VERSION = '0.23'
PACKAGE_VERSION = '0.28'
# we only support python 2 right now
assert sys.version_info[0] == 2
deps = ['manifestparser >= 0.6',
'mozfile >= 1.0',
'mozlog >= 3.0']
deps = ['mozfile >= 1.0', 'mozlog >= 3.0']
setup(name=PACKAGE_NAME,
version=PACKAGE_VERSION,
@@ -36,6 +34,7 @@ setup(name=PACKAGE_NAME,
include_package_data=True,
zip_safe=False,
install_requires=deps,
extras_require={'manifest': ['manifestparser >= 0.6']},
tests_require=['mozhttpd'],
entry_points="""
# -*- Entry points: -*-
+1 -1
View File
@@ -6,7 +6,7 @@ import sys
from setuptools import setup, find_packages
PACKAGE_NAME = 'mozrunner'
PACKAGE_VERSION = '6.7'
PACKAGE_VERSION = '6.8'
desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
+1 -1
View File
@@ -4,7 +4,7 @@
from setuptools import setup
PACKAGE_VERSION = '1.2'
PACKAGE_VERSION = '1.3'
dependencies = ['mozdevice >= 0.44',
'mozfile >= 1.0',
-1
View File
@@ -566,7 +566,6 @@ stage-marionette: make-stage-dir
$(NSINSTALL) -D $(MARIONETTE_DIR)/transport
$(NSINSTALL) -D $(MARIONETTE_DIR)/driver
@(cd $(topsrcdir)/testing/marionette/client && tar --exclude marionette/tests $(TAR_CREATE_FLAGS) - *) | (cd $(MARIONETTE_DIR)/ && tar -xf -)
@(cd $(topsrcdir)/testing/marionette/transport && tar $(TAR_CREATE_FLAGS) - *) | (cd $(MARIONETTE_DIR)/transport && tar -xf -)
@(cd $(topsrcdir)/testing/marionette/driver && tar $(TAR_CREATE_FLAGS) - *) | (cd $(MARIONETTE_DIR)/driver && tar -xf -)
$(PYTHON) $(topsrcdir)/testing/marionette/client/marionette/tests/print-manifest-dirs.py \
$(topsrcdir) \