diff --git a/.gitignore b/.gitignore index 840c622109..3ded48f0ae 100644 --- a/.gitignore +++ b/.gitignore @@ -10,10 +10,14 @@ TAGS tags ID .DS_Store* +*.pdb # Vim swap files. .*.sw[a-z] +# Emacs directory variable files. +**/.dir-locals.el + # User files that may appear at the root /.mozconfig* /mozconfig @@ -51,8 +55,8 @@ parser/html/java/javaparser/ .settings/ # Python virtualenv artifacts. -python/psutil/*.so -python/psutil/*.pyd +python/psutil/**/*.so +python/psutil/**/*.pyd python/psutil/build/ # Ignore chrome.manifest files from the devtools loader diff --git a/.lldbinit b/.lldbinit index 54515de8ff..b5cc7e7f11 100644 --- a/.lldbinit +++ b/.lldbinit @@ -5,7 +5,7 @@ # and in the accompanying Python scripts, see python/lldbutils/README.txt. # ----------------------------------------------------------------------------- -# Import the module that defines complex Goanna debugging commands. This assumes +# Import the module that defines complex Gecko debugging commands. This assumes # you are either running lldb from the top level source directory, the objdir, # or the dist/bin directory. (.lldbinit files in the objdir and dist/bin set # topsrcdir appropriately.) diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py index 332911ab74..ea98ca6a5c 100644 --- a/.ycm_extra_conf.py +++ b/.ycm_extra_conf.py @@ -6,6 +6,10 @@ import imp import os from StringIO import StringIO import shlex +import sys + +old_bytecode = sys.dont_write_bytecode +sys.dont_write_bytecode = True path = os.path.join(os.path.dirname(__file__), 'mach') @@ -15,13 +19,22 @@ if not os.path.exists(path): path = os.path.join(config.topsrcdir, 'mach') mach_module = imp.load_module('_mach', open(path), path, ('', 'r', imp.PY_SOURCE)) +sys.dont_write_bytecode = old_bytecode + def FlagsForFile(filename): mach = mach_module.get_mach() out = StringIO() out.encoding = None mach.run(['compileflags', filename], stdout=out, stderr=out) + flag_list = shlex.split(out.getvalue()) + + # This flag is added by Fennec for android build and causes ycmd to fail to parse the file. + # Removing this flag is a workaround until ycmd starts to handle this flag properly. + # https://github.com/Valloric/YouCompleteMe/issues/1490 + final_flags = [x for x in flag_list if not x.startswith('-march=armv')] + return { - 'flags': shlex.split(out.getvalue()), + 'flags': final_flags, 'do_cache': True } diff --git a/browser/app/jar.mn b/browser/app/jar.mn new file mode 100644 index 0000000000..d5c482ce74 --- /dev/null +++ b/browser/app/jar.mn @@ -0,0 +1,3 @@ +browser.jar: +% resource app % + defaults/permissions (permissions) diff --git a/browser/app/moz.build b/browser/app/moz.build index c40fe170c9..630a6a2889 100644 --- a/browser/app/moz.build +++ b/browser/app/moz.build @@ -89,3 +89,5 @@ if CONFIG['MOZ_LINKER']: if CONFIG['HAVE_CLOCK_MONOTONIC']: OS_LIBS += CONFIG['REALTIME_LIBS'] + +JAR_MANIFESTS += ['jar.mn'] diff --git a/browser/app/permissions b/browser/app/permissions new file mode 100644 index 0000000000..3a1cf63fc6 --- /dev/null +++ b/browser/app/permissions @@ -0,0 +1,20 @@ +# This file has default permissions for the permission manager. +# The file-format is strict: +# * matchtype \t type \t permission \t host +# * Only "host" is supported for matchtype +# * type is a string that identifies the type of permission (e.g. "cookie") +# * permission is an integer between 1 and 15 +# See nsPermissionManager.cpp for more... + +# UITour +host uitour 1 www.mozilla.org +host uitour 1 support.mozilla.org +host uitour 1 about:home + +# XPInstall +host install 1 addons.mozilla.org +host install 1 marketplace.firefox.com + +# Remote troubleshooting +host remote-troubleshooting 1 input.mozilla.org +host remote-troubleshooting 1 support.mozilla.org diff --git a/browser/app/profile/palemoon.js b/browser/app/profile/palemoon.js index 56fa823f01..21dccda133 100644 --- a/browser/app/profile/palemoon.js +++ b/browser/app/profile/palemoon.js @@ -392,6 +392,9 @@ pref("browser.search.official", true); pref("browser.sessionhistory.max_entries", 50); +// Built-in default permissions. +pref("permissions.manager.defaultsUrl", "resource://app/defaults/permissions"); + // handle links targeting new windows // 1=current window/tab, 2=new window, 3=new tab in most recent window pref("browser.link.open_newwindow", 3); diff --git a/caps/BasePrincipal.cpp b/caps/BasePrincipal.cpp index 5255e7086f..ed053ab8bc 100644 --- a/caps/BasePrincipal.cpp +++ b/caps/BasePrincipal.cpp @@ -145,12 +145,6 @@ OriginAttributes::PopulateFromOrigin(const nsACString& aOrigin, return PopulateFromSuffix(Substring(origin, pos)); } -void -OriginAttributes::CookieJar(nsACString& aStr) -{ - mozilla::GetJarPrefix(mAppId, mInBrowser, aStr); -} - BasePrincipal::BasePrincipal() {} @@ -248,7 +242,7 @@ BasePrincipal::GetJarPrefix(nsACString& aJarPrefix) { MOZ_ASSERT(AppId() != nsIScriptSecurityManager::UNKNOWN_APP_ID); - mOriginAttributes.CookieJar(aJarPrefix); + mozilla::GetJarPrefix(mOriginAttributes.mAppId, mOriginAttributes.mInBrowser, aJarPrefix); return NS_OK; } @@ -268,13 +262,6 @@ BasePrincipal::GetOriginSuffix(nsACString& aOriginAttributes) return NS_OK; } -NS_IMETHODIMP -BasePrincipal::GetCookieJar(nsACString& aCookieJar) -{ - mOriginAttributes.CookieJar(aCookieJar); - return NS_OK; -} - NS_IMETHODIMP BasePrincipal::GetAppStatus(uint16_t* aAppStatus) { diff --git a/caps/BasePrincipal.h b/caps/BasePrincipal.h index 13e814388a..2f91b45606 100644 --- a/caps/BasePrincipal.h +++ b/caps/BasePrincipal.h @@ -48,8 +48,6 @@ public: void CreateSuffix(nsACString& aStr) const; bool PopulateFromSuffix(const nsACString& aStr); - void CookieJar(nsACString& aStr); - // Populates the attributes from a string like // |uri!key1=value1&key2=value2| and returns the uri without the suffix. bool PopulateFromOrigin(const nsACString& aOrigin, @@ -83,7 +81,6 @@ public: NS_IMETHOD GetJarPrefix(nsACString& aJarPrefix) final; NS_IMETHOD GetOriginAttributes(JSContext* aCx, JS::MutableHandle aVal) final; NS_IMETHOD GetOriginSuffix(nsACString& aOriginSuffix) final; - NS_IMETHOD GetCookieJar(nsACString& aCookieJar) final; NS_IMETHOD GetAppStatus(uint16_t* aAppStatus) final; NS_IMETHOD GetAppId(uint32_t* aAppStatus) final; NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement) final; diff --git a/caps/nsIPrincipal.idl b/caps/nsIPrincipal.idl index c31ce72f0e..98bfff2f03 100644 --- a/caps/nsIPrincipal.idl +++ b/caps/nsIPrincipal.idl @@ -20,7 +20,7 @@ interface nsIContentSecurityPolicy; [ptr] native JSPrincipals(JSPrincipals); [ptr] native PrincipalArray(nsTArray >); -[scriptable, builtinclass, uuid(49c2faf0-b6de-4640-8d0f-e0217baa8627)] +[scriptable, builtinclass, uuid(7a9aa074-7565-4567-af2f-9e3704c7af9e)] interface nsIPrincipal : nsISerializable { /** @@ -195,30 +195,6 @@ interface nsIPrincipal : nsISerializable */ readonly attribute AUTF8String originSuffix; - /** - * Opaque string token representing the "cookie jar" associated with this - * principal. Cookie jars are intended to be a tag associated with persistent - * data (like cookies, localStorage data, etc) such that all data associated - * with a given cookie jar can be quickly located and (for example) deleted. - * Code from many origins may share a given cookie jar, so callers still need - * to consult .origin (or equivalent) to compartmentalize data - the cookie - * jar should _only_ be used as a tag in the manner described above. - * - * If two principals are in different cookie jars, they must be cross-origin. - * As such, the information making up the cookie jar token must be contained - * in the originAttributes (i.e. cookieJar must be a function of / derivable - * from originAttributes). Long term, the intention is for the cookie jar - * identifier to simply be an origin attribute. But we don't have that - * attribute yet, and we also need to concatenate the appId and inBrowser - * attributes until those go away. - * - * This getter is designed to hide these details from consumers so that they - * don't need to be updated when we swap out the implementation. For that - * reason, callers should treat the string as opaque and not rely on the - * current format. - */ - readonly attribute ACString cookieJar; - /** * The base domain of the codebase URI to which this principal pertains * (generally the document URI), handling null principals and diff --git a/caps/nsIScriptSecurityManager.idl b/caps/nsIScriptSecurityManager.idl index 099f5d5dc0..cdf26e95fb 100644 --- a/caps/nsIScriptSecurityManager.idl +++ b/caps/nsIScriptSecurityManager.idl @@ -26,7 +26,7 @@ class DomainPolicyClone; [ptr] native JSObjectPtr(JSObject); [ptr] native DomainPolicyClonePtr(mozilla::dom::DomainPolicyClone); -[scriptable, uuid(f4c578b8-5bac-4ba1-9582-f1140e09a3b4)] +[scriptable, uuid(50418f5c-b0d8-42c3-ba5d-efffb6927e1c)] interface nsIScriptSecurityManager : nsISupports { /** @@ -201,6 +201,20 @@ interface nsIScriptSecurityManager : nsISupports [implicit_jscontext] nsIPrincipal createNullPrincipal(in jsval originAttributes); + /** + * Creates an expanded principal whose capabilities are the union of the + * given principals. An expanded principal has an asymmetric privilege + * relationship with its sub-principals (that is to say, it subsumes the + * sub-principals, but the sub-principals do not subsume it), even if + * there's only one. This presents a legitimate use-case for making an + * expanded principal around a single sub-principal, which we do frequently. + * + * Expanded principals cannot have origin attributes themselves, but rather + * have them through their sub-principals - so we don't accept them here. + */ + nsIPrincipal createExpandedPrincipal([array, size_is(aLength)] in nsIPrincipal aPrincipalArray, + [optional] in unsigned long aLength); + /** * Returns OK if aSourceURI and target have the same "origin" * (scheme, host, and port). diff --git a/caps/nsPrincipal.cpp b/caps/nsPrincipal.cpp index d9609c388a..5f215655a0 100644 --- a/caps/nsPrincipal.cpp +++ b/caps/nsPrincipal.cpp @@ -14,6 +14,7 @@ #include "pratom.h" #include "nsIURI.h" #include "nsIURL.h" +#include "nsIStandardURL.h" #include "nsIURIWithPrincipal.h" #include "nsJSPrincipals.h" #include "nsIEffectiveTLDService.h" @@ -127,6 +128,31 @@ nsPrincipal::GetOriginForURI(nsIURI* aURI, nsACString& aOrigin) } } + // We want the invariant that prinA.origin == prinB.origin i.f.f. + // prinA.equals(prinB). However, this requires that we impose certain constraints + // on the behavior and origin semantics of principals, and in particular, forbid + // creating origin strings for principals whose equality constraints are not + // expressible as strings (i.e. object equality). Moreover, we want to forbid URIs + // containing the magic "^" we use as a separating character for origin + // attributes. + // + // These constraints can generally be achieved by restricting .origin to + // nsIStandardURL-based URIs, but there are a few other URI schemes that we need + // to handle. + bool isBehaved; + if ((NS_SUCCEEDED(origin->SchemeIs("about", &isBehaved)) && isBehaved) || + (NS_SUCCEEDED(origin->SchemeIs("moz-safe-about", &isBehaved)) && isBehaved) || + (NS_SUCCEEDED(origin->SchemeIs("indexeddb", &isBehaved)) && isBehaved)) { + rv = origin->GetAsciiSpec(aOrigin); + NS_ENSURE_SUCCESS(rv, rv); + // These URIs could technically contain a '^', but they never should. + if (NS_WARN_IF(aOrigin.FindChar('^', 0) != -1)) { + aOrigin.Truncate(); + return NS_ERROR_FAILURE; + } + return NS_OK; + } + int32_t port; if (NS_SUCCEEDED(rv) && !isChrome) { rv = origin->GetPort(&port); @@ -144,6 +170,14 @@ nsPrincipal::GetOriginForURI(nsIURI* aURI, nsACString& aOrigin) aOrigin.Append(hostPort); } else { + // If we reached this branch, we can only create an origin if we have a nsIStandardURL. + // So, we query to a nsIStandardURL, and fail if we aren't an instance of an nsIStandardURL + // nsIStandardURLs have the good property of escaping the '^' character in their specs, + // which means that we can be sure that the caret character (which is reserved for delimiting + // the end of the spec, and the beginning of the origin attributes) is not present in the + // origin string + nsCOMPtr standardURL = do_QueryInterface(origin); + NS_ENSURE_TRUE(standardURL, NS_ERROR_FAILURE); rv = origin->GetAsciiSpec(aOrigin); NS_ENSURE_SUCCESS(rv, rv); } diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index 8522046b29..1a1109eb56 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -1,5 +1,5 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim: set ts=4 et sw=4 tw=80: */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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/. */ @@ -1077,6 +1077,21 @@ nsScriptSecurityManager::CreateNullPrincipal(JS::Handle aOriginAttrib return NS_OK; } +NS_IMETHODIMP +nsScriptSecurityManager::CreateExpandedPrincipal(nsIPrincipal** aPrincipalArray, uint32_t aLength, + nsIPrincipal** aResult) +{ + nsTArray> principals; + principals.SetCapacity(aLength); + for (uint32_t i = 0; i < aLength; ++i) { + principals.AppendElement(aPrincipalArray[i]); + } + + nsCOMPtr p = new nsExpandedPrincipal(principals); + p.forget(aResult); + return NS_OK; +} + NS_IMETHODIMP nsScriptSecurityManager::GetAppCodebasePrincipal(nsIURI* aURI, uint32_t aAppId, diff --git a/caps/tests/unit/test_origin.js b/caps/tests/unit/test_origin.js index ef462719e7..bfeb535fa2 100644 --- a/caps/tests/unit/test_origin.js +++ b/caps/tests/unit/test_origin.js @@ -20,9 +20,6 @@ function checkCrossOrigin(a, b) { do_check_false(a.subsumesConsideringDomain(b)); do_check_false(b.subsumes(a)); do_check_false(b.subsumesConsideringDomain(a)); - do_check_eq(a.cookieJar === b.cookieJar, - a.originAttributes.appId == b.originAttributes.appId && - a.originAttributes.inBrowser == b.originAttributes.inBrowser); } function checkOriginAttributes(prin, attrs, suffix) { @@ -50,7 +47,7 @@ function run_test() { var nullPrin = Cu.getObjectPrincipal(new Cu.Sandbox(null)); do_check_true(/^moz-nullprincipal:\{([0-9]|[a-z]|\-){36}\}$/.test(nullPrin.origin)); checkOriginAttributes(nullPrin); - var ep = Cu.getObjectPrincipal(new Cu.Sandbox([exampleCom, nullPrin, exampleOrg])); + var ep = ssm.createExpandedPrincipal([exampleCom, nullPrin, exampleOrg]); checkOriginAttributes(ep); checkCrossOrigin(exampleCom, exampleOrg); checkCrossOrigin(exampleOrg, nullPrin); diff --git a/dom/base/ChromeUtils.cpp b/dom/base/ChromeUtils.cpp index a9c2b907d4..79faea1886 100644 --- a/dom/base/ChromeUtils.cpp +++ b/dom/base/ChromeUtils.cpp @@ -10,15 +10,6 @@ namespace mozilla { namespace dom { -/* static */ void -ChromeUtils::OriginAttributesToCookieJar(GlobalObject& aGlobal, - const OriginAttributesDictionary& aAttrs, - nsCString& aCookieJar) -{ - OriginAttributes attrs(aAttrs); - attrs.CookieJar(aCookieJar); -} - /* static */ void ChromeUtils::OriginAttributesToSuffix(dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs, diff --git a/dom/base/ChromeUtils.h b/dom/base/ChromeUtils.h index fcd02f3799..47717ede4a 100644 --- a/dom/base/ChromeUtils.h +++ b/dom/base/ChromeUtils.h @@ -40,11 +40,6 @@ public: class ChromeUtils : public ThreadSafeChromeUtils { public: - static void - OriginAttributesToCookieJar(dom::GlobalObject& aGlobal, - const dom::OriginAttributesDictionary& aAttrs, - nsCString& aCookieJar); - static void OriginAttributesToSuffix(dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs, diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index d7507b90c3..4dfae25c21 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -176,6 +176,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGeolocation) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotification) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryPromise) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPowerManager) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCellBroadcast) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIccManager) @@ -241,6 +242,8 @@ Navigator::Invalidate() mBatteryManager = nullptr; } + mBatteryPromise = nullptr; + #ifdef MOZ_B2G_FM if (mFMRadio) { mFMRadio->Shutdown(); @@ -1385,8 +1388,37 @@ Navigator::GetMozFMRadio(ErrorResult& aRv) // Navigator::nsINavigatorBattery //***************************************************************************** -battery::BatteryManager* +Promise* Navigator::GetBattery(ErrorResult& aRv) +{ + if (mBatteryPromise) { + return mBatteryPromise; + } + + if (!mWindow || !mWindow->GetDocShell()) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + nsCOMPtr go = do_QueryInterface(mWindow); + nsRefPtr batteryPromise = Promise::Create(go, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + mBatteryPromise = batteryPromise; + + if (!mBatteryManager) { + mBatteryManager = new battery::BatteryManager(mWindow); + mBatteryManager->Init(); + } + + mBatteryPromise->MaybeResolve(mBatteryManager); + + return mBatteryPromise; +} + +battery::BatteryManager* +Navigator::GetDeprecatedBattery(ErrorResult& aRv) { if (!mBatteryManager) { if (!mWindow) { diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h index be0500b0c1..09d82421f2 100644 --- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -156,7 +156,8 @@ public: Permissions* GetPermissions(ErrorResult& aRv); // The XPCOM GetDoNotTrack is ok Geolocation* GetGeolocation(ErrorResult& aRv); - battery::BatteryManager* GetBattery(ErrorResult& aRv); + Promise* GetBattery(ErrorResult& aRv); + battery::BatteryManager* GetDeprecatedBattery(ErrorResult& aRv); static already_AddRefed GetDataStores(nsPIDOMWindow* aWindow, const nsAString& aName, @@ -351,6 +352,7 @@ private: nsRefPtr mGeolocation; nsRefPtr mNotification; nsRefPtr mBatteryManager; + nsRefPtr mBatteryPromise; #ifdef MOZ_B2G_FM nsRefPtr mFMRadio; #endif diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 23bf207fc0..31ca8c58cd 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -51,6 +51,7 @@ #include "mozilla/dom/TextDecoder.h" #include "mozilla/dom/TouchEvent.h" #include "mozilla/dom/ShadowRoot.h" +#include "mozilla/dom/WorkerPrivate.h" #include "mozilla/EventDispatcher.h" #include "mozilla/EventListenerManager.h" #include "mozilla/EventStateManager.h" @@ -8050,3 +8051,22 @@ nsContentUtils::SetFetchReferrerURIWithPolicy(nsIPrincipal* aPrincipal, net::ReferrerPolicy referrerPolicy = aDoc->GetReferrerPolicy(); return aChannel->SetReferrerWithPolicy(referrerURI, referrerPolicy); } + +// static +bool +nsContentUtils::PushEnabled(JSContext* aCx, JSObject* aObj) +{ + if (NS_IsMainThread()) { + return Preferences::GetBool("dom.push.enabled", false); + } + + using namespace workers; + + // Otherwise, check the pref via the WorkerPrivate + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); + if (!workerPrivate) { + return false; + } + + return workerPrivate->PushEnabled(); +} diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 2258cf2408..ecef01185a 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -2489,6 +2489,8 @@ public: nsIDocument* aDoc, nsIHttpChannel* aChannel); + static bool PushEnabled(JSContext* aCx, JSObject* aObj); + private: static bool InitializeEventTable(); diff --git a/dom/base/nsPerformance.cpp b/dom/base/nsPerformance.cpp index 21e2327c41..a5fc9a6403 100644 --- a/dom/base/nsPerformance.cpp +++ b/dom/base/nsPerformance.cpp @@ -744,13 +744,7 @@ nsPerformance::InsertUserEntry(PerformanceEntry* aEntry) // If we have no URI, just put in "none". uri.AssignLiteral("none"); } - PERFLOG("Performance Entry: %s|%s|%s|%f|%f|%" PRIu64 "\n", - uri.get(), - NS_ConvertUTF16toUTF8(aEntry->GetEntryType()).get(), - NS_ConvertUTF16toUTF8(aEntry->GetName()).get(), - aEntry->StartTime(), - aEntry->Duration(), - static_cast(PR_Now() / PR_USEC_PER_MSEC)); + PerformanceBase::LogEntry(aEntry, uri); } PerformanceBase::InsertUserEntry(aEntry); @@ -979,6 +973,18 @@ PerformanceBase::ClearMeasures(const Optional& aName) ClearUserEntries(aName, NS_LITERAL_STRING("measure")); } +void +PerformanceBase::LogEntry(PerformanceEntry* aEntry, const nsACString& aOwner) const +{ + PERFLOG("Performance Entry: %s|%s|%s|%f|%f|%" PRIu64 "\n", + aOwner.BeginReading(), + NS_ConvertUTF16toUTF8(aEntry->GetEntryType()).get(), + NS_ConvertUTF16toUTF8(aEntry->GetName()).get(), + aEntry->StartTime(), + aEntry->Duration(), + static_cast(PR_Now() / PR_USEC_PER_MSEC)); +} + void PerformanceBase::InsertUserEntry(PerformanceEntry* aEntry) { diff --git a/dom/base/nsPerformance.h b/dom/base/nsPerformance.h index c4d7a7a451..d4e7fb6e6b 100644 --- a/dom/base/nsPerformance.h +++ b/dom/base/nsPerformance.h @@ -350,6 +350,8 @@ protected: return mResourceEntries.Length() >= mResourceTimingBufferSize; } + void LogEntry(PerformanceEntry* aEntry, const nsACString& aOwner) const; + private: nsTArray> mUserEntries; nsTArray> mResourceEntries; diff --git a/dom/battery/BatteryManager.cpp b/dom/battery/BatteryManager.cpp index bc9928c232..f72736f164 100644 --- a/dom/battery/BatteryManager.cpp +++ b/dom/battery/BatteryManager.cpp @@ -10,6 +10,7 @@ #include "mozilla/DOMEventTargetHelper.h" #include "mozilla/Hal.h" #include "mozilla/dom/BatteryManagerBinding.h" +#include "mozilla/Preferences.h" #include "nsIDOMClassInfo.h" /** @@ -56,10 +57,37 @@ BatteryManager::WrapObject(JSContext* aCx, JS::Handle aGivenProto) return BatteryManagerBinding::Wrap(aCx, this, aGivenProto); } +bool +BatteryManager::Charging() const +{ + MOZ_ASSERT(NS_IsMainThread()); + // For testing, unable to report the battery status information + if (Preferences::GetBool("dom.battery.test.default", false)) { + return true; + } + if (Preferences::GetBool("dom.battery.test.charging", false)) { + return true; + } + if (Preferences::GetBool("dom.battery.test.discharging", false)) { + return false; + } + + return mCharging; +} + double BatteryManager::DischargingTime() const { - if (mCharging || mRemainingTime == kUnknownRemainingTime) { + MOZ_ASSERT(NS_IsMainThread()); + // For testing, unable to report the battery status information + if (Preferences::GetBool("dom.battery.test.default", false)) { + return std::numeric_limits::infinity(); + } + if (Preferences::GetBool("dom.battery.test.discharging", false)) { + return 42.0; + } + + if (Charging() || mRemainingTime == kUnknownRemainingTime) { return std::numeric_limits::infinity(); } @@ -69,13 +97,34 @@ BatteryManager::DischargingTime() const double BatteryManager::ChargingTime() const { - if (!mCharging || mRemainingTime == kUnknownRemainingTime) { + MOZ_ASSERT(NS_IsMainThread()); + // For testing, unable to report the battery status information + if (Preferences::GetBool("dom.battery.test.default", false)) { + return 0.0; + } + if (Preferences::GetBool("dom.battery.test.charging", false)) { + return 42.0; + } + + if (!Charging() || mRemainingTime == kUnknownRemainingTime) { return std::numeric_limits::infinity(); } return mRemainingTime; } +double +BatteryManager::Level() const +{ + MOZ_ASSERT(NS_IsMainThread()); + // For testing, unable to report the battery status information + if (Preferences::GetBool("dom.battery.test.default")) { + return 1.0; + } + + return mLevel; +} + void BatteryManager::UpdateFromBatteryInfo(const hal::BatteryInformation& aBatteryInfo) { diff --git a/dom/battery/BatteryManager.h b/dom/battery/BatteryManager.h index 0ef526ce0a..2660d642da 100644 --- a/dom/battery/BatteryManager.h +++ b/dom/battery/BatteryManager.h @@ -46,19 +46,13 @@ public: virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; - bool Charging() const - { - return mCharging; - } + bool Charging() const; double ChargingTime() const; double DischargingTime() const; - double Level() const - { - return mLevel; - } + double Level() const; IMPL_EVENT_HANDLER(chargingchange) IMPL_EVENT_HANDLER(chargingtimechange) diff --git a/dom/battery/test/marionette/manifest.ini b/dom/battery/test/marionette/manifest.ini index b74ec64e76..87ce1a3a55 100644 --- a/dom/battery/test/marionette/manifest.ini +++ b/dom/battery/test/marionette/manifest.ini @@ -9,3 +9,9 @@ qemu = true [test_battery_status_full.js] [test_battery_status_not_charging.js] [test_battery_status_unknown.js] +[test_deprecated_battery_level.js] +[test_deprecated_battery_status_charging.js] +[test_deprecated_battery_status_discharging.js] +[test_deprecated_battery_status_full.js] +[test_deprecated_battery_status_not_charging.js] +[test_deprecated_battery_status_unknown.js] diff --git a/dom/battery/test/marionette/test_battery_level.js b/dom/battery/test/marionette/test_battery_level.js index b344a26e61..74b1ec70a7 100644 --- a/dom/battery/test/marionette/test_battery_level.js +++ b/dom/battery/test/marionette/test_battery_level.js @@ -3,15 +3,18 @@ MARIONETTE_TIMEOUT = 10000; -let battery = window.navigator.battery; +let battery = null; function verifyInitialState() { - ok(battery, "battery"); - is(battery.level, 0.5, "battery.level"); - runEmulatorCmd("power display", function (result) { - is(result.pop(), "OK", "power display successful"); - ok(result.indexOf("capacity: 50") !== -1, "power capacity"); - setUp(); + window.navigator.getBattery().then(function (b) { + battery = b; + ok(battery, "battery"); + is(battery.level, 0.5, "battery.level"); + runEmulatorCmd("power display", function (result) { + is(result.pop(), "OK", "power display successful"); + ok(result.indexOf("capacity: 50") !== -1, "power capacity"); + setUp(); + }); }); } @@ -29,10 +32,10 @@ function changeCapacity(capacity, changeExpected, nextFunction) { log("Changing power capacity to " + capacity); if (changeExpected) { battery.onlevelchange = function (event) { - battery.onlevelchange = unexpectedEvent; - is(event.type, "levelchange", "event.type"); - is(battery.level, capacity / 100, "battery.level"); - nextFunction(); + battery.onlevelchange = unexpectedEvent; + is(event.type, "levelchange", "event.type"); + is(battery.level, capacity / 100, "battery.level"); + nextFunction(); }; runEmulatorCmd("power capacity " + capacity); } diff --git a/dom/battery/test/marionette/test_battery_status_charging.js b/dom/battery/test/marionette/test_battery_status_charging.js index 2d7469d9f3..714f73d10e 100644 --- a/dom/battery/test/marionette/test_battery_status_charging.js +++ b/dom/battery/test/marionette/test_battery_status_charging.js @@ -3,17 +3,20 @@ MARIONETTE_TIMEOUT = 10000; -let battery = window.navigator.battery; +let battery = null; let fromStatus = "charging"; let fromCharging = true; function verifyInitialState() { - ok(battery, "battery"); - ok(battery.charging, "battery.charging"); - runEmulatorCmd("power display", function (result) { - is(result.pop(), "OK", "power display successful"); - ok(result.indexOf("status: Charging") !== -1, "power status charging"); - setUp(); + window.navigator.getBattery().then(function (b) { + battery = b; + ok(battery, "battery"); + ok(battery.charging, "battery.charging"); + runEmulatorCmd("power display", function (result) { + is(result.pop(), "OK", "power display successful"); + ok(result.indexOf("status: Charging") !== -1, "power status charging"); + setUp(); + }); }); } diff --git a/dom/battery/test/marionette/test_battery_status_discharging.js b/dom/battery/test/marionette/test_battery_status_discharging.js index b6a45f2b84..972c034927 100644 --- a/dom/battery/test/marionette/test_battery_status_discharging.js +++ b/dom/battery/test/marionette/test_battery_status_discharging.js @@ -3,17 +3,20 @@ MARIONETTE_TIMEOUT = 10000; -let battery = window.navigator.battery; +let battery = null; let fromStatus = "discharging"; let fromCharging = false; function verifyInitialState() { - ok(battery, "battery"); - ok(battery.charging, "battery.charging"); - runEmulatorCmd("power display", function (result) { - is(result.pop(), "OK", "power display successful"); - ok(result.indexOf("status: Charging") !== -1, "power status charging"); - setUp(); + window.navigator.getBattery().then(function (b) { + battery = b; + ok(battery, "battery"); + ok(battery.charging, "battery.charging"); + runEmulatorCmd("power display", function (result) { + is(result.pop(), "OK", "power display successful"); + ok(result.indexOf("status: Charging") !== -1, "power status charging"); + setUp(); + }); }); } diff --git a/dom/battery/test/marionette/test_battery_status_full.js b/dom/battery/test/marionette/test_battery_status_full.js index 80d0fa1129..a636a6eaca 100644 --- a/dom/battery/test/marionette/test_battery_status_full.js +++ b/dom/battery/test/marionette/test_battery_status_full.js @@ -8,12 +8,15 @@ let fromStatus = "full"; let fromCharging = true; function verifyInitialState() { - ok(battery, "battery"); - ok(battery.charging, "battery.charging"); - runEmulatorCmd("power display", function (result) { - is(result.pop(), "OK", "power display successful"); - ok(result.indexOf("status: Charging") !== -1, "power status charging"); - setUp(); + window.navigator.getBattery().then(function (b) { + battery = b; + ok(battery, "battery"); + ok(battery.charging, "battery.charging"); + runEmulatorCmd("power display", function (result) { + is(result.pop(), "OK", "power display successful"); + ok(result.indexOf("status: Charging") !== -1, "power status charging"); + setUp(); + }); }); } diff --git a/dom/battery/test/marionette/test_battery_status_not_charging.js b/dom/battery/test/marionette/test_battery_status_not_charging.js index 113017f76e..9b7b38eeb7 100644 --- a/dom/battery/test/marionette/test_battery_status_not_charging.js +++ b/dom/battery/test/marionette/test_battery_status_not_charging.js @@ -8,12 +8,15 @@ let fromStatus = "not-charging"; let fromCharging = false; function verifyInitialState() { - ok(battery, "battery"); - ok(battery.charging, "battery.charging"); - runEmulatorCmd("power display", function (result) { - is(result.pop(), "OK", "power display successful"); - ok(result.indexOf("status: Charging") !== -1, "power status charging"); - setUp(); + window.navigator.getBattery().then(function (b) { + battery = b; + ok(battery, "battery"); + ok(battery.charging, "battery.charging"); + runEmulatorCmd("power display", function (result) { + is(result.pop(), "OK", "power display successful"); + ok(result.indexOf("status: Charging") !== -1, "power status charging"); + setUp(); + }); }); } diff --git a/dom/battery/test/marionette/test_battery_status_unknown.js b/dom/battery/test/marionette/test_battery_status_unknown.js index 42a315a04c..a86581e381 100644 --- a/dom/battery/test/marionette/test_battery_status_unknown.js +++ b/dom/battery/test/marionette/test_battery_status_unknown.js @@ -8,12 +8,15 @@ let fromStatus = "unknown"; let fromCharging = false; function verifyInitialState() { - ok(battery, "battery"); - ok(battery.charging, "battery.charging"); - runEmulatorCmd("power display", function (result) { - is(result.pop(), "OK", "power display successful"); - ok(result.indexOf("status: Charging") !== -1, "power status charging"); - setUp(); + window.navigator.getBattery().then(function (b) { + battery = b; + ok(battery, "battery"); + ok(battery.charging, "battery.charging"); + runEmulatorCmd("power display", function (result) { + is(result.pop(), "OK", "power display successful"); + ok(result.indexOf("status: Charging") !== -1, "power status charging"); + setUp(); + }); }); } diff --git a/dom/battery/test/marionette/test_deprecated_battery_level.js b/dom/battery/test/marionette/test_deprecated_battery_level.js new file mode 100644 index 0000000000..b344a26e61 --- /dev/null +++ b/dom/battery/test/marionette/test_deprecated_battery_level.js @@ -0,0 +1,68 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +MARIONETTE_TIMEOUT = 10000; + +let battery = window.navigator.battery; + +function verifyInitialState() { + ok(battery, "battery"); + is(battery.level, 0.5, "battery.level"); + runEmulatorCmd("power display", function (result) { + is(result.pop(), "OK", "power display successful"); + ok(result.indexOf("capacity: 50") !== -1, "power capacity"); + setUp(); + }); +} + +function unexpectedEvent(event) { + ok(false, "Unexpected " + event.type + " event"); +} + +function setUp() { + battery.onchargingchange = unexpectedEvent; + battery.onlevelchange = unexpectedEvent; + levelUp(); +} + +function changeCapacity(capacity, changeExpected, nextFunction) { + log("Changing power capacity to " + capacity); + if (changeExpected) { + battery.onlevelchange = function (event) { + battery.onlevelchange = unexpectedEvent; + is(event.type, "levelchange", "event.type"); + is(battery.level, capacity / 100, "battery.level"); + nextFunction(); + }; + runEmulatorCmd("power capacity " + capacity); + } + else { + runEmulatorCmd("power capacity " + capacity, function () { + is(battery.level, capacity / 100, "battery.level"); + nextFunction(); + }); + } +} + +function levelUp() { + changeCapacity("90", true, levelDown); +} + +function levelDown() { + changeCapacity("10", true, levelSame); +} + +function levelSame() { + changeCapacity("10", false, cleanUp); +} + +function cleanUp() { + battery.onchargingchange = null; + battery.onlevelchange = function () { + battery.onlevelchange = null; + finish(); + }; + runEmulatorCmd("power capacity 50"); +} + +verifyInitialState(); diff --git a/dom/battery/test/marionette/test_deprecated_battery_status_charging.js b/dom/battery/test/marionette/test_deprecated_battery_status_charging.js new file mode 100644 index 0000000000..2d7469d9f3 --- /dev/null +++ b/dom/battery/test/marionette/test_deprecated_battery_status_charging.js @@ -0,0 +1,85 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +MARIONETTE_TIMEOUT = 10000; + +let battery = window.navigator.battery; +let fromStatus = "charging"; +let fromCharging = true; + +function verifyInitialState() { + ok(battery, "battery"); + ok(battery.charging, "battery.charging"); + runEmulatorCmd("power display", function (result) { + is(result.pop(), "OK", "power display successful"); + ok(result.indexOf("status: Charging") !== -1, "power status charging"); + setUp(); + }); +} + +function unexpectedEvent(event) { + ok(false, "Unexpected " + event.type + " event"); +} + +function setUp() { + battery.onchargingchange = unexpectedEvent; + battery.onlevelchange = unexpectedEvent; + toDischarging(); +} + +function resetStatus(charging, nextFunction) { + log("Resetting power status to " + fromStatus); + if (charging !== fromCharging) { + battery.onchargingchange = function () { + battery.onchargingchange = unexpectedEvent; + nextFunction(); + }; + runEmulatorCmd("power status " + fromStatus); + } + else { + runEmulatorCmd("power status " + fromStatus, nextFunction); + } +} + +function changeStatus(toStatus, toCharging, nextFunction) { + log("Changing power status to " + toStatus); + if (fromCharging !== toCharging) { + battery.onchargingchange = function (event) { + battery.onchargingchange = unexpectedEvent; + is(event.type, "chargingchange", "event type"); + is(battery.charging, toCharging, "battery.charging"); + resetStatus(toCharging, nextFunction); + }; + runEmulatorCmd("power status " + toStatus); + } + else { + runEmulatorCmd("power status " + toStatus, function () { + is(battery.charging, toCharging, "battery.charging"); + resetStatus(toCharging, nextFunction); + }); + } +} + +function toDischarging() { + changeStatus("discharging", false, toFull); +} + +function toFull() { + changeStatus("full", true, toNotCharging); +} + +function toNotCharging() { + changeStatus("not-charging", false, toUnknown); +} + +function toUnknown() { + changeStatus("unknown", false, cleanUp); +} + +function cleanUp() { + battery.onchargingchange = null; + battery.onlevelchange = null; + finish(); +} + +verifyInitialState(); diff --git a/dom/battery/test/marionette/test_deprecated_battery_status_discharging.js b/dom/battery/test/marionette/test_deprecated_battery_status_discharging.js new file mode 100644 index 0000000000..b6a45f2b84 --- /dev/null +++ b/dom/battery/test/marionette/test_deprecated_battery_status_discharging.js @@ -0,0 +1,93 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +MARIONETTE_TIMEOUT = 10000; + +let battery = window.navigator.battery; +let fromStatus = "discharging"; +let fromCharging = false; + +function verifyInitialState() { + ok(battery, "battery"); + ok(battery.charging, "battery.charging"); + runEmulatorCmd("power display", function (result) { + is(result.pop(), "OK", "power display successful"); + ok(result.indexOf("status: Charging") !== -1, "power status charging"); + setUp(); + }); +} + +function unexpectedEvent(event) { + ok(false, "Unexpected " + event.type + " event"); +} + +function setUp() { + battery.onchargingchange = function () { + battery.onchargingchange = unexpectedEvent; + toCharging(); + }; + battery.onlevelchange = unexpectedEvent; + log("Changing power status to " + fromStatus); + runEmulatorCmd("power status " + fromStatus); +} + +function resetStatus(charging, nextFunction) { + log("Resetting power status to " + fromStatus); + if (charging !== fromCharging) { + battery.onchargingchange = function () { + battery.onchargingchange = unexpectedEvent; + nextFunction(); + }; + runEmulatorCmd("power status " + fromStatus); + } + else { + runEmulatorCmd("power status " + fromStatus, nextFunction); + } +} + +function changeStatus(toStatus, toCharging, nextFunction) { + log("Changing power status to " + toStatus); + if (fromCharging !== toCharging) { + battery.onchargingchange = function (event) { + battery.onchargingchange = unexpectedEvent; + is(event.type, "chargingchange", "event type"); + is(battery.charging, toCharging, "battery.charging"); + resetStatus(toCharging, nextFunction); + }; + runEmulatorCmd("power status " + toStatus); + } + else { + runEmulatorCmd("power status " + toStatus, function () { + is(battery.charging, toCharging, "battery.charging"); + resetStatus(toCharging, nextFunction); + }); + } +} + +function toCharging() { + changeStatus("charging", true, toFull); +} + +function toFull() { + changeStatus("full", true, toNotCharging); +} + +function toNotCharging() { + changeStatus("not-charging", false, toUnknown); +} + +function toUnknown() { + changeStatus("unknown", false, cleanUp); +} + +function cleanUp() { + battery.onchargingchange = function () { + battery.onchargingchange = null; + finish(); + }; + battery.onlevelchange = null; + log("Resetting power status to charging"); + runEmulatorCmd("power status charging"); +} + +verifyInitialState(); diff --git a/dom/battery/test/marionette/test_deprecated_battery_status_full.js b/dom/battery/test/marionette/test_deprecated_battery_status_full.js new file mode 100644 index 0000000000..80d0fa1129 --- /dev/null +++ b/dom/battery/test/marionette/test_deprecated_battery_status_full.js @@ -0,0 +1,87 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +MARIONETTE_TIMEOUT = 10000; + +let battery = window.navigator.battery; +let fromStatus = "full"; +let fromCharging = true; + +function verifyInitialState() { + ok(battery, "battery"); + ok(battery.charging, "battery.charging"); + runEmulatorCmd("power display", function (result) { + is(result.pop(), "OK", "power display successful"); + ok(result.indexOf("status: Charging") !== -1, "power status charging"); + setUp(); + }); +} + +function unexpectedEvent(event) { + ok(false, "Unexpected " + event.type + " event"); +} + +function setUp() { + battery.onchargingchange = unexpectedEvent; + battery.onlevelchange = unexpectedEvent; + log("Changing power status to " + fromStatus); + runEmulatorCmd("power status " + fromStatus, toCharging); +} + +function resetStatus(charging, nextFunction) { + log("Resetting power status to " + fromStatus); + if (charging !== fromCharging) { + battery.onchargingchange = function () { + battery.onchargingchange = unexpectedEvent; + nextFunction(); + }; + runEmulatorCmd("power status " + fromStatus); + } + else { + runEmulatorCmd("power status " + fromStatus, nextFunction); + } +} + +function changeStatus(toStatus, toCharging, nextFunction) { + log("Changing power status to " + toStatus); + if (fromCharging !== toCharging) { + battery.onchargingchange = function (event) { + battery.onchargingchange = unexpectedEvent; + is(event.type, "chargingchange", "event type"); + is(battery.charging, toCharging, "battery.charging"); + resetStatus(toCharging, nextFunction); + }; + runEmulatorCmd("power status " + toStatus); + } + else { + runEmulatorCmd("power status " + toStatus, function () { + is(battery.charging, toCharging, "battery.charging"); + resetStatus(toCharging, nextFunction); + }); + } +} + +function toCharging() { + changeStatus("charging", true, toDischarging); +} + +function toDischarging() { + changeStatus("discharging", false, toNotCharging); +} + +function toNotCharging() { + changeStatus("not-charging", false, toUnknown); +} + +function toUnknown() { + changeStatus("unknown", false, cleanUp); +} + +function cleanUp() { + battery.onchargingchange = null; + battery.onlevelchange = null; + log("Resetting power status to charging"); + runEmulatorCmd("power status charging", finish); +} + +verifyInitialState(); diff --git a/dom/battery/test/marionette/test_deprecated_battery_status_not_charging.js b/dom/battery/test/marionette/test_deprecated_battery_status_not_charging.js new file mode 100644 index 0000000000..113017f76e --- /dev/null +++ b/dom/battery/test/marionette/test_deprecated_battery_status_not_charging.js @@ -0,0 +1,93 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +MARIONETTE_TIMEOUT = 10000; + +let battery = window.navigator.battery; +let fromStatus = "not-charging"; +let fromCharging = false; + +function verifyInitialState() { + ok(battery, "battery"); + ok(battery.charging, "battery.charging"); + runEmulatorCmd("power display", function (result) { + is(result.pop(), "OK", "power display successful"); + ok(result.indexOf("status: Charging") !== -1, "power status charging"); + setUp(); + }); +} + +function unexpectedEvent(event) { + ok(false, "Unexpected " + event.type + " event"); +} + +function setUp() { + battery.onchargingchange = function () { + battery.onchargingchange = unexpectedEvent; + toCharging(); + }; + battery.onlevelchange = unexpectedEvent; + log("Changing power status to " + fromStatus); + runEmulatorCmd("power status " + fromStatus); +} + +function resetStatus(charging, nextFunction) { + log("Resetting power status to " + fromStatus); + if (charging !== fromCharging) { + battery.onchargingchange = function () { + battery.onchargingchange = unexpectedEvent; + nextFunction(); + }; + runEmulatorCmd("power status " + fromStatus); + } + else { + runEmulatorCmd("power status " + fromStatus, nextFunction); + } +} + +function changeStatus(toStatus, toCharging, nextFunction) { + log("Changing power status to " + toStatus); + if (fromCharging !== toCharging) { + battery.onchargingchange = function (event) { + battery.onchargingchange = unexpectedEvent; + is(event.type, "chargingchange", "event type"); + is(battery.charging, toCharging, "battery.charging"); + resetStatus(toCharging, nextFunction); + }; + runEmulatorCmd("power status " + toStatus); + } + else { + runEmulatorCmd("power status " + toStatus, function () { + is(battery.charging, toCharging, "battery.charging"); + resetStatus(toCharging, nextFunction); + }); + } +} + +function toCharging() { + changeStatus("charging", true, toDischarging); +} + +function toDischarging() { + changeStatus("discharging", false, toFull); +} + +function toFull() { + changeStatus("full", true, toUnknown); +} + +function toUnknown() { + changeStatus("unknown", false, cleanUp); +} + +function cleanUp() { + battery.onchargingchange = function () { + battery.onchargingchange = null; + finish(); + }; + battery.onlevelchange = null; + log("Resetting power status to charging"); + runEmulatorCmd("power status charging"); +} + +verifyInitialState(); diff --git a/dom/battery/test/marionette/test_deprecated_battery_unknown.js b/dom/battery/test/marionette/test_deprecated_battery_unknown.js new file mode 100644 index 0000000000..42a315a04c --- /dev/null +++ b/dom/battery/test/marionette/test_deprecated_battery_unknown.js @@ -0,0 +1,93 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +MARIONETTE_TIMEOUT = 10000; + +let battery = window.navigator.battery; +let fromStatus = "unknown"; +let fromCharging = false; + +function verifyInitialState() { + ok(battery, "battery"); + ok(battery.charging, "battery.charging"); + runEmulatorCmd("power display", function (result) { + is(result.pop(), "OK", "power display successful"); + ok(result.indexOf("status: Charging") !== -1, "power status charging"); + setUp(); + }); +} + +function unexpectedEvent(event) { + ok(false, "Unexpected " + event.type + " event"); +} + +function setUp() { + battery.onchargingchange = function () { + battery.onchargingchange = unexpectedEvent; + toCharging(); + }; + battery.onlevelchange = unexpectedEvent; + log("Changing power status to " + fromStatus); + runEmulatorCmd("power status " + fromStatus); +} + +function resetStatus(charging, nextFunction) { + log("Resetting power status to " + fromStatus); + if (charging !== fromCharging) { + battery.onchargingchange = function () { + battery.onchargingchange = unexpectedEvent; + nextFunction(); + }; + runEmulatorCmd("power status " + fromStatus); + } + else { + runEmulatorCmd("power status " + fromStatus, nextFunction); + } +} + +function changeStatus(toStatus, toCharging, nextFunction) { + log("Changing power status to " + toStatus); + if (fromCharging !== toCharging) { + battery.onchargingchange = function (event) { + battery.onchargingchange = unexpectedEvent; + is(event.type, "chargingchange", "event type"); + is(battery.charging, toCharging, "battery.charging"); + resetStatus(toCharging, nextFunction); + }; + runEmulatorCmd("power status " + toStatus); + } + else { + runEmulatorCmd("power status " + toStatus, function () { + is(battery.charging, toCharging, "battery.charging"); + resetStatus(toCharging, nextFunction); + }); + } +} + +function toCharging() { + changeStatus("charging", true, toDischarging); +} + +function toDischarging() { + changeStatus("discharging", false, toFull); +} + +function toFull() { + changeStatus("full", true, toNotCharging); +} + +function toNotCharging() { + changeStatus("not-charging", false, cleanUp); +} + +function cleanUp() { + battery.onchargingchange = function () { + battery.onchargingchange = null; + finish(); + }; + battery.onlevelchange = null; + log("Resetting power status to charging"); + runEmulatorCmd("power status charging"); +} + +verifyInitialState(); diff --git a/dom/battery/test/mochitest.ini b/dom/battery/test/mochitest.ini index 242a02a867..92334129fa 100644 --- a/dom/battery/test/mochitest.ini +++ b/dom/battery/test/mochitest.ini @@ -1,2 +1,8 @@ [test_battery_basics.html] skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) +[test_battery_charging.html] +skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) +[test_battery_discharging.html] +skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) +[test_deprecated_battery_basics.html] +skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) diff --git a/dom/battery/test/test_battery_basics.html b/dom/battery/test/test_battery_basics.html index 14b334481e..825d2affeb 100644 --- a/dom/battery/test/test_battery_basics.html +++ b/dom/battery/test/test_battery_basics.html @@ -12,20 +12,23 @@
 
 
diff --git a/dom/battery/test/test_battery_charging.html b/dom/battery/test/test_battery_charging.html new file mode 100644 index 0000000000..f95d4252c6 --- /dev/null +++ b/dom/battery/test/test_battery_charging.html @@ -0,0 +1,33 @@ + + + + Test for Battery API + + + + +

+ +
+
+
+ + diff --git a/dom/battery/test/test_battery_discharging.html b/dom/battery/test/test_battery_discharging.html new file mode 100644 index 0000000000..cff4ced67a --- /dev/null +++ b/dom/battery/test/test_battery_discharging.html @@ -0,0 +1,33 @@ + + + + Test for Battery API + + + + +

+ +
+
+
+ + diff --git a/dom/battery/test/test_deprecated_battery_basics.html b/dom/battery/test/test_deprecated_battery_basics.html new file mode 100644 index 0000000000..a75267c7d4 --- /dev/null +++ b/dom/battery/test/test_deprecated_battery_basics.html @@ -0,0 +1,32 @@ + + + + Test for Battery API + + + + +

+ +
+
+
+ + diff --git a/dom/fetch/Request.cpp b/dom/fetch/Request.cpp index bd409e29b1..0347ad90aa 100644 --- a/dom/fetch/Request.cpp +++ b/dom/fetch/Request.cpp @@ -14,6 +14,7 @@ #include "mozilla/dom/Fetch.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/URL.h" +#include "mozilla/dom/WorkerPrivate.h" #include "mozilla/dom/workers/bindings/URL.h" #include "WorkerPrivate.h" @@ -42,6 +43,25 @@ Request::~Request() { } +// static +bool +Request::RequestContextEnabled(JSContext* aCx, JSObject* aObj) +{ + if (NS_IsMainThread()) { + return Preferences::GetBool("dom.requestcontext.enabled", false); + } + + using namespace workers; + + // Otherwise, check the pref via the WorkerPrivate + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); + if (!workerPrivate) { + return false; + } + + return workerPrivate->RequestContextEnabled(); +} + already_AddRefed Request::GetInternalRequest() { diff --git a/dom/fetch/Request.h b/dom/fetch/Request.h index 280d9ee503..98bf3c303d 100644 --- a/dom/fetch/Request.h +++ b/dom/fetch/Request.h @@ -34,6 +34,9 @@ class Request final : public nsISupports public: Request(nsIGlobalObject* aOwner, InternalRequest* aRequest); + static bool + RequestContextEnabled(JSContext* aCx, JSObject* aObj); + JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override { diff --git a/dom/push/PushManager.cpp b/dom/push/PushManager.cpp index 33d96b2476..df767b0764 100644 --- a/dom/push/PushManager.cpp +++ b/dom/push/PushManager.cpp @@ -129,23 +129,6 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PushSubscription) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END -// PushManager -// static -bool -PushManager::Enabled(JSContext* aCx, JSObject* aObj) -{ - if (NS_IsMainThread()) { - return Preferences::GetBool("dom.push.enabled", false); - } - - // XXXnsm: As of this patch it seems like Push will be enabled before or with - // ServiceWorkers, so this seems OK for now. - ServiceWorkerGlobalScope* scope = nullptr; - nsresult rv = UnwrapObject(aObj, scope); - return NS_SUCCEEDED(rv); -} - PushManager::PushManager(nsIGlobalObject* aGlobal, const nsAString& aScope) : mGlobal(aGlobal), mScope(aScope) { diff --git a/dom/push/PushManager.h b/dom/push/PushManager.h index 212884206a..ecc42b8796 100644 --- a/dom/push/PushManager.h +++ b/dom/push/PushManager.h @@ -106,9 +106,6 @@ public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PushManager) - static bool - Enabled(JSContext* aCx, JSObject* aObj); - explicit PushManager(nsIGlobalObject* aGlobal, const nsAString& aScope); nsIGlobalObject* diff --git a/dom/push/test/worker.js b/dom/push/test/worker.js index 8367d1e504..cdc611aff0 100644 --- a/dom/push/test/worker.js +++ b/dom/push/test/worker.js @@ -7,7 +7,11 @@ function handlePush(event) { self.clients.matchAll().then(function(result) { if (event instanceof PushEvent && - event.data instanceof PushMessageData) { + event.data instanceof PushMessageData && + event.data.text === undefined && + event.data.json === undefined && + event.data.arrayBuffer === undefined && + event.data.blob === undefined) { result[0].postMessage({type: "finished", okay: "yes"}); return; diff --git a/dom/tests/mochitest/fetch/fetch_test_framework.js b/dom/tests/mochitest/fetch/fetch_test_framework.js index b6dd514705..92889fd2ce 100644 --- a/dom/tests/mochitest/fetch/fetch_test_framework.js +++ b/dom/tests/mochitest/fetch/fetch_test_framework.js @@ -2,7 +2,8 @@ function testScript(script) { function setupPrefs() { return new Promise(function(resolve, reject) { SpecialPowers.pushPrefEnv({ - "set": [["dom.serviceWorkers.enabled", true], + "set": [["dom.requestcontext.enabled", true], + ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true], ["dom.serviceWorkers.exemptFromPerDomainMax", true]] }, resolve); diff --git a/dom/tests/mochitest/fetch/mochitest.ini b/dom/tests/mochitest/fetch/mochitest.ini index a5cacd29f4..dc7c8c556e 100644 --- a/dom/tests/mochitest/fetch/mochitest.ini +++ b/dom/tests/mochitest/fetch/mochitest.ini @@ -35,6 +35,7 @@ skip-if = e10s || buildapp == 'b2g' # Bug 1173163 for e10s, bug 1137683 for b2g [test_formdataparsing_sw_reroute.html] skip-if = buildapp == 'b2g' # Bug 1137683 [test_request.html] +[test_request_context.html] [test_request_sw_reroute.html] skip-if = buildapp == 'b2g' # Bug 1137683 [test_response.html] diff --git a/dom/tests/mochitest/fetch/test_request_context.html b/dom/tests/mochitest/fetch/test_request_context.html new file mode 100644 index 0000000000..07c99e2f0c --- /dev/null +++ b/dom/tests/mochitest/fetch/test_request_context.html @@ -0,0 +1,19 @@ + + + + + Make sure that Request.context is not exposed by default + + + + + + + + diff --git a/dom/webidl/ChromeUtils.webidl b/dom/webidl/ChromeUtils.webidl index f40cc34c39..78610738e6 100644 --- a/dom/webidl/ChromeUtils.webidl +++ b/dom/webidl/ChromeUtils.webidl @@ -10,15 +10,6 @@ */ [ChromeOnly, Exposed=(Window,System)] interface ChromeUtils : ThreadSafeChromeUtils { - /** - * A helper that converts OriginAttributesDictionary to cookie jar opaque - * identfier. - * - * @param originAttrs The originAttributes from the caller. - */ - static ByteString - originAttributesToCookieJar(optional OriginAttributesDictionary originAttrs); - /** * A helper that converts OriginAttributesDictionary to a opaque suffix string. * diff --git a/dom/webidl/Navigator.webidl b/dom/webidl/Navigator.webidl index e47dafb8db..24fa963735 100644 --- a/dom/webidl/Navigator.webidl +++ b/dom/webidl/Navigator.webidl @@ -124,14 +124,15 @@ interface NavigatorGeolocation { Navigator implements NavigatorGeolocation; // http://www.w3.org/TR/battery-status/#navigatorbattery-interface -[NoInterfaceObject] -interface NavigatorBattery { - // XXXbz Per spec this should be non-nullable, but we return null in - // torn-down windows. See bug 884925. - [Throws, Pref="dom.battery.enabled"] - readonly attribute BatteryManager? battery; +partial interface Navigator { + [Throws, Pref="dom.battery.enabled"] + Promise getBattery(); + // Deprecated. Use getBattery() instead. + // XXXbz Per spec this should be non-nullable, but we return null in + // torn-down windows. See bug 884925. + [Throws, Pref="dom.battery.enabled", BinaryName="deprecatedBattery"] + readonly attribute BatteryManager? battery; }; -Navigator implements NavigatorBattery; // https://wiki.mozilla.org/WebAPI/DataStore [NoInterfaceObject, diff --git a/dom/webidl/PushEvent.webidl b/dom/webidl/PushEvent.webidl index 806b786a59..a14af42a7c 100644 --- a/dom/webidl/PushEvent.webidl +++ b/dom/webidl/PushEvent.webidl @@ -7,7 +7,9 @@ * https://w3c.github.io/push-api/ */ -[Constructor(DOMString type, optional PushEventInit eventInitDict), Exposed=ServiceWorker] +[Constructor(DOMString type, optional PushEventInit eventInitDict), + Func="nsContentUtils::PushEnabled", + Exposed=ServiceWorker] interface PushEvent : ExtendableEvent { readonly attribute PushMessageData data; }; @@ -16,4 +18,4 @@ typedef USVString PushMessageDataInit; dictionary PushEventInit : ExtendableEventInit { PushMessageDataInit data; -}; \ No newline at end of file +}; diff --git a/dom/webidl/PushManager.webidl b/dom/webidl/PushManager.webidl index a1ae9d4fdf..a6658e7266 100644 --- a/dom/webidl/PushManager.webidl +++ b/dom/webidl/PushManager.webidl @@ -22,7 +22,7 @@ interface PushManagerImpl { [Func="ServiceWorkerRegistration::WebPushMethodHider"] void setScope(DOMString scope); }; -[Exposed=(Window,Worker), Func="mozilla::dom::PushManager::Enabled"] +[Exposed=(Window,Worker), Func="nsContentUtils::PushEnabled"] interface PushManager { [ChromeOnly, Throws, Exposed=Window] void setPushManagerImpl(PushManagerImpl store); diff --git a/dom/webidl/PushMessageData.webidl b/dom/webidl/PushMessageData.webidl index 16bd0ca87f..f2604a1a0e 100644 --- a/dom/webidl/PushMessageData.webidl +++ b/dom/webidl/PushMessageData.webidl @@ -7,11 +7,14 @@ * https://w3c.github.io/push-api/ */ -[Exposed=ServiceWorker] +[Func="nsContentUtils::PushEnabled", + Exposed=ServiceWorker] interface PushMessageData { - ArrayBuffer arrayBuffer(); - Blob blob(); - object json(); - USVString text(); -}; \ No newline at end of file + // FIXME(nsm): Bug 1149195. + // These methods will be exposed once encryption is supported. + // ArrayBuffer arrayBuffer(); + // Blob blob(); + // object json(); + // USVString text(); +}; diff --git a/dom/webidl/PushSubscription.webidl b/dom/webidl/PushSubscription.webidl index 37b7776234..e8efdaa90c 100644 --- a/dom/webidl/PushSubscription.webidl +++ b/dom/webidl/PushSubscription.webidl @@ -9,7 +9,7 @@ interface Principal; -[Exposed=(Window,Worker), Func="mozilla::dom::PushManager::Enabled", +[Exposed=(Window,Worker), Func="nsContentUtils::PushEnabled", ChromeConstructor(DOMString pushEndpoint, DOMString scope)] interface PushSubscription { diff --git a/dom/webidl/Request.webidl b/dom/webidl/Request.webidl index 077e13889e..dfaf2c398c 100644 --- a/dom/webidl/Request.webidl +++ b/dom/webidl/Request.webidl @@ -17,6 +17,7 @@ interface Request { readonly attribute USVString url; [SameObject] readonly attribute Headers headers; + [Func="mozilla::dom::Request::RequestContextEnabled"] readonly attribute RequestContext context; readonly attribute DOMString referrer; readonly attribute RequestMode mode; @@ -41,6 +42,8 @@ dictionary RequestInit { RequestCache cache; }; +// Gecko currently does not ship RequestContext, so please don't use it in IDL +// that is exposed to script. enum RequestContext { "audio", "beacon", "cspreport", "download", "embed", "eventsource", "favicon", "fetch", "font", "form", "frame", "hyperlink", "iframe", "image", "imageset", "import", diff --git a/dom/webidl/ServiceWorkerRegistration.webidl b/dom/webidl/ServiceWorkerRegistration.webidl index 2f220a8eaa..c82f217147 100644 --- a/dom/webidl/ServiceWorkerRegistration.webidl +++ b/dom/webidl/ServiceWorkerRegistration.webidl @@ -28,7 +28,7 @@ interface ServiceWorkerRegistration : EventTarget { partial interface ServiceWorkerRegistration { #ifndef MOZ_SIMPLEPUSH - [Throws, Exposed=(Window,Worker), Func="mozilla::dom::PushManager::Enabled"] + [Throws, Exposed=(Window,Worker), Func="nsContentUtils::PushEnabled"] readonly attribute PushManager pushManager; #endif }; diff --git a/dom/workers/Performance.cpp b/dom/workers/Performance.cpp index d01fb56134..ec60b859b7 100644 --- a/dom/workers/Performance.cpp +++ b/dom/workers/Performance.cpp @@ -64,6 +64,16 @@ Performance::GetPerformanceTimingFromString(const nsAString& aProperty) return 0; } +void +Performance::InsertUserEntry(PerformanceEntry* aEntry) +{ + if (mWorkerPrivate->PerformanceLoggingEnabled()) { + PerformanceBase::LogEntry(aEntry, + NS_ConvertUTF16toUTF8(mWorkerPrivate->ScriptURL())); + } + PerformanceBase::InsertUserEntry(aEntry); +} + DOMHighResTimeStamp Performance::DeltaFromNavigationStart(DOMHighResTimeStamp aTime) { diff --git a/dom/workers/Performance.h b/dom/workers/Performance.h index 59fb3288b9..ab18b078ea 100644 --- a/dom/workers/Performance.h +++ b/dom/workers/Performance.h @@ -26,6 +26,8 @@ public: private: ~Performance(); + void InsertUserEntry(PerformanceEntry* aEntry) override; + WorkerPrivate* mWorkerPrivate; public: diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index 6a89508770..8a426fdc1e 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -158,6 +158,7 @@ static_assert(MAX_WORKERS_PER_DOMAIN >= 1, #define PREF_DOM_CACHES_ENABLED "dom.caches.enabled" #define PREF_DOM_CACHES_TESTING_ENABLED "dom.caches.testing.enabled" +#define PREF_WORKERS_PERFORMANCE_LOGGING_ENABLED "dom.performance.enable_user_timing_logging" #define PREF_DOM_WORKERNOTIFICATION_ENABLED "dom.webnotifications.enabled" #define PREF_WORKERS_LATEST_JS_VERSION "dom.workers.latestJSVersion" #define PREF_INTL_ACCEPT_LANGUAGES "intl.accept_languages" @@ -165,6 +166,8 @@ static_assert(MAX_WORKERS_PER_DOMAIN >= 1, #define PREF_SERVICEWORKERS_TESTING_ENABLED "dom.serviceWorkers.testing.enabled" #define PREF_INTERCEPTION_ENABLED "dom.serviceWorkers.interception.enabled" #define PREF_INTERCEPTION_OPAQUE_ENABLED "dom.serviceWorkers.interception.opaque.enabled" +#define PREF_PUSH_ENABLED "dom.push.enabled" +#define PREF_REQUESTCONTEXT_ENABLED "dom.requestcontext.enabled" namespace { @@ -1910,10 +1913,22 @@ RuntimeService::Init() WorkerPrefChanged, PREF_DOM_CACHES_TESTING_ENABLED, reinterpret_cast(WORKERPREF_DOM_CACHES_TESTING))) || + NS_FAILED(Preferences::RegisterCallbackAndCall( + WorkerPrefChanged, + PREF_WORKERS_PERFORMANCE_LOGGING_ENABLED, + reinterpret_cast(WORKERPREF_PERFORMANCE_LOGGING_ENABLED))) || NS_FAILED(Preferences::RegisterCallbackAndCall( WorkerPrefChanged, PREF_SERVICEWORKERS_TESTING_ENABLED, reinterpret_cast(WORKERPREF_SERVICEWORKERS_TESTING))) || + NS_FAILED(Preferences::RegisterCallbackAndCall( + WorkerPrefChanged, + PREF_PUSH_ENABLED, + reinterpret_cast(WORKERPREF_PUSH))) || + NS_FAILED(Preferences::RegisterCallbackAndCall( + WorkerPrefChanged, + PREF_REQUESTCONTEXT_ENABLED, + reinterpret_cast(WORKERPREF_REQUESTCONTEXT))) || NS_FAILED(Preferences::RegisterCallback(LoadRuntimeOptions, PREF_JS_OPTIONS_PREFIX, nullptr)) || @@ -2117,6 +2132,10 @@ RuntimeService::Cleanup() WorkerPrefChanged, PREF_DOM_CACHES_TESTING_ENABLED, reinterpret_cast(WORKERPREF_DOM_CACHES_TESTING))) || + NS_FAILED(Preferences::UnregisterCallback( + WorkerPrefChanged, + PREF_WORKERS_PERFORMANCE_LOGGING_ENABLED, + reinterpret_cast(WORKERPREF_PERFORMANCE_LOGGING_ENABLED))) || NS_FAILED(Preferences::UnregisterCallback( WorkerPrefChanged, PREF_INTERCEPTION_OPAQUE_ENABLED, @@ -2137,6 +2156,14 @@ RuntimeService::Cleanup() WorkerPrefChanged, PREF_DOM_WORKERNOTIFICATION_ENABLED, reinterpret_cast(WORKERPREF_DOM_WORKERNOTIFICATION))) || + NS_FAILED(Preferences::UnregisterCallback( + WorkerPrefChanged, + PREF_PUSH_ENABLED, + reinterpret_cast(WORKERPREF_PUSH))) || + NS_FAILED(Preferences::UnregisterCallback( + WorkerPrefChanged, + PREF_REQUESTCONTEXT_ENABLED, + reinterpret_cast(WORKERPREF_REQUESTCONTEXT))) || #if DUMP_CONTROLLED_BY_PREF NS_FAILED(Preferences::UnregisterCallback( WorkerPrefChanged, @@ -2675,6 +2702,7 @@ RuntimeService::WorkerPrefChanged(const char* aPrefName, void* aClosure) case WORKERPREF_DOM_CACHES: case WORKERPREF_DOM_CACHES_TESTING: case WORKERPREF_DOM_WORKERNOTIFICATION: + case WORKERPREF_PERFORMANCE_LOGGING_ENABLED: #ifdef DUMP_CONTROLLED_BY_PREF case WORKERPREF_DUMP: #endif @@ -2682,6 +2710,8 @@ RuntimeService::WorkerPrefChanged(const char* aPrefName, void* aClosure) case WORKERPREF_INTERCEPTION_OPAQUE_ENABLED: case WORKERPREF_SERVICEWORKERS: case WORKERPREF_SERVICEWORKERS_TESTING: + case WORKERPREF_PUSH: + case WORKERPREF_REQUESTCONTEXT: sDefaultPreferences[key] = Preferences::GetBool(aPrefName, false); break; diff --git a/dom/workers/ServiceWorkerEvents.h b/dom/workers/ServiceWorkerEvents.h index f9fd279089..2d3b80cdcd 100644 --- a/dom/workers/ServiceWorkerEvents.h +++ b/dom/workers/ServiceWorkerEvents.h @@ -20,6 +20,7 @@ #endif #include "nsProxyRelease.h" +#include "nsContentUtils.h" class nsIInterceptedChannel; diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index 35dd537b0f..a65c67f48e 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -1318,6 +1318,27 @@ public: return mPreferences[WORKERPREF_DOM_CACHES_TESTING]; } + bool + PerformanceLoggingEnabled() const + { + AssertIsOnWorkerThread(); + return mPreferences[WORKERPREF_PERFORMANCE_LOGGING_ENABLED]; + } + + bool + PushEnabled() const + { + AssertIsOnWorkerThread(); + return mPreferences[WORKERPREF_PUSH]; + } + + bool + RequestContextEnabled() const + { + AssertIsOnWorkerThread(); + return mPreferences[WORKERPREF_REQUESTCONTEXT]; + } + bool OnLine() const { diff --git a/dom/workers/Workers.h b/dom/workers/Workers.h index da62d3f2c4..19bb033838 100644 --- a/dom/workers/Workers.h +++ b/dom/workers/Workers.h @@ -205,6 +205,9 @@ enum WorkerPreference WORKERPREF_DOM_CACHES_TESTING, // dom.caches.testing.enabled WORKERPREF_SERVICEWORKERS_TESTING, // dom.serviceWorkers.testing.enabled WORKERPREF_INTERCEPTION_OPAQUE_ENABLED, // dom.serviceWorkers.interception.opaque.enabled + WORKERPREF_PERFORMANCE_LOGGING_ENABLED, // dom.performance.enable_user_timing_logging + WORKERPREF_PUSH, // dom.push.enabled + WORKERPREF_REQUESTCONTEXT, // dom.requestcontext.enabled WORKERPREF_COUNT }; diff --git a/dom/workers/test/serviceworkers/test_request_context.js b/dom/workers/test/serviceworkers/test_request_context.js index 19bce75359..829a6e3416 100644 --- a/dom/workers/test/serviceworkers/test_request_context.js +++ b/dom/workers/test/serviceworkers/test_request_context.js @@ -68,6 +68,7 @@ onload = function() { ["dom.caches.enabled", true], ["dom.image.picture.enabled", true], ["dom.image.srcset.enabled", true], + ["dom.requestcontext.enabled", true], ["dom.serviceWorkers.exemptFromPerDomainMax", true], ["dom.serviceWorkers.interception.enabled", true], ["dom.serviceWorkers.enabled", true], diff --git a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js index 823ca05f31..be5e74d716 100644 --- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js +++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js @@ -48,8 +48,6 @@ var ecmaGlobals = "Number", "Object", "Proxy", - "PushEvent", - "PushMessageData", "RangeError", "ReferenceError", "Reflect", @@ -168,9 +166,13 @@ var interfaceNamesInGlobalScope = // IMPORTANT: Do not change this list without review from a DOM peer! "Promise", // IMPORTANT: Do not change this list without review from a DOM peer! - "PushManager", + { name: "PushEvent", b2g: false, android: false, release: false }, // IMPORTANT: Do not change this list without review from a DOM peer! - "PushSubscription", + { name: "PushManager", b2g: false, android: false, release: false }, +// IMPORTANT: Do not change this list without review from a DOM peer! + { name: "PushMessageData", b2g: false, android: false, release: false }, +// IMPORTANT: Do not change this list without review from a DOM peer! + { name: "PushSubscription", b2g: false, android: false, release: false }, // IMPORTANT: Do not change this list without review from a DOM peer! "Request", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/workers/test/test_worker_interfaces.js b/dom/workers/test/test_worker_interfaces.js index a1498d57ae..45fe833f9b 100644 --- a/dom/workers/test/test_worker_interfaces.js +++ b/dom/workers/test/test_worker_interfaces.js @@ -157,6 +157,10 @@ var interfaceNamesInGlobalScope = "PerformanceMeasure", // IMPORTANT: Do not change this list without review from a DOM peer! "Promise", +// IMPORTANT: Do not change this list without review from a DOM peer! + { name: "PushManager", b2g: false, android: false, release: false }, +// IMPORTANT: Do not change this list without review from a DOM peer! + { name: "PushSubscription", b2g: false, android: false, release: false }, // IMPORTANT: Do not change this list without review from a DOM peer! "Request", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/extensions/cookie/nsPermissionManager.cpp b/extensions/cookie/nsPermissionManager.cpp index ad748b07d0..21a19a5c61 100644 --- a/extensions/cookie/nsPermissionManager.cpp +++ b/extensions/cookie/nsPermissionManager.cpp @@ -37,6 +37,8 @@ #include "mozilla/net/NeckoMessageUtils.h" #include "mozilla/Preferences.h" #include "nsReadLine.h" +#include "mozilla/Telemetry.h" +#include "nsIConsoleService.h" static nsPermissionManager *gPermissionManager = nullptr; @@ -67,6 +69,18 @@ ChildProcess() return nullptr; } +static void +LogToConsole(const nsAString& aMsg) +{ + nsCOMPtr console(do_GetService("@mozilla.org/consoleservice;1")); + if (!console) { + NS_WARNING("Failed to log message to console."); + return; + } + + nsAutoString msg(aMsg); + console->LogStringMessage(msg.get()); +} #define ENSURE_NOT_CHILD_PROCESS_(onError) \ PR_BEGIN_MACRO \ @@ -473,29 +487,52 @@ nsPermissionManager::InitDB(bool aRemoveFile) // cache a connection to the hosts database rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn)); - NS_ENSURE_SUCCESS(rv, rv); + if (rv == NS_ERROR_FILE_CORRUPTED) { + LogToConsole(NS_LITERAL_STRING("permissions.sqlite is corrupted! Try again!")); + + // Add telemetry probe + mozilla::Telemetry::Accumulate(mozilla::Telemetry::PERMISSIONS_SQL_CORRUPTED, 1); + + // delete corrupted permissions.sqlite and try again + rv = permissionsFile->Remove(false); + NS_ENSURE_SUCCESS(rv, rv); + LogToConsole(NS_LITERAL_STRING("Corrupted permissions.sqlite has been removed.")); + + rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn)); + NS_ENSURE_SUCCESS(rv, rv); + LogToConsole(NS_LITERAL_STRING("OpenDatabase to permissions.sqlite is successful!")); + } bool ready; mDBConn->GetConnectionReady(&ready); if (!ready) { + LogToConsole(NS_LITERAL_STRING("Fail to get connection to permissions.sqlite! Try again!")); + // delete and try again rv = permissionsFile->Remove(false); NS_ENSURE_SUCCESS(rv, rv); + LogToConsole(NS_LITERAL_STRING("Defective permissions.sqlite has been removed.")); + + // Add telemetry probe + mozilla::Telemetry::Accumulate(mozilla::Telemetry::DEFECTIVE_PERMISSIONS_SQL_REMOVED, 1); rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn)); NS_ENSURE_SUCCESS(rv, rv); + LogToConsole(NS_LITERAL_STRING("OpenDatabase to permissions.sqlite is successful!")); mDBConn->GetConnectionReady(&ready); if (!ready) return NS_ERROR_UNEXPECTED; } + LogToConsole(NS_LITERAL_STRING("Get a connection to permissions.sqlite.")); + bool tableExists = false; mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts"), &tableExists); if (!tableExists) { rv = CreateTable(); NS_ENSURE_SUCCESS(rv, rv); - + LogToConsole(NS_LITERAL_STRING("DB table(moz_hosts) is created!")); } else { // table already exists; check the schema version before reading int32_t dbSchemaVersion; diff --git a/js/src/jit-test/tests/debug/bug1147939.js b/js/src/jit-test/tests/debug/bug1147939.js new file mode 100644 index 0000000000..a2bd2cf798 --- /dev/null +++ b/js/src/jit-test/tests/debug/bug1147939.js @@ -0,0 +1,8 @@ +// |jit-test| error: TypeError +var g = newGlobal(); +g.debuggeeGlobal = this; +g.eval("(" + function () { + dbg = new Debugger(debuggeeGlobal); + dbg.onExceptionUnwind = Map; +} + ")();"); +throw new Error("oops"); diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 5f35ca5c7e..d0a3483d3a 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -1367,7 +1367,13 @@ FindStartPC(JSContext* cx, const FrameIter& iter, int spindex, int skipStackHits if (spindex == JSDVG_SEARCH_STACK) { size_t index = iter.numFrameSlots(); - MOZ_ASSERT(index >= size_t(parser.stackDepthAtPC(current))); + + // The decompiler may be called from inside functions that are not + // called from script, but via the C++ API directly, such as + // Invoke. In that case, the youngest script frame may have a + // completely unrelated pc and stack depth, so we give up. + if (index < size_t(parser.stackDepthAtPC(current))) + return true; // We search from fp->sp to base to find the most recently calculated // value matching v under assumption that it is the value that caused diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 4c53653071..7483d0b1d9 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -3430,7 +3430,7 @@ pref("intl.imm.vertical_writing.always_assume_not_supported", false); // We cannot retrieve active IME name with IMM32 API if a TIP of TSF is active. // This pref can specify active IME name when Japanese TIP is active. // For example: -// Google Japanese Input: "Google 日本語入力 IMM32 モジュール" +// Google Japanese Input: "Google ?¥æœ¬èªžå…¥??IMM32 ?¢ã‚¸?¥ãƒ¼?? // ATOK 2011: "ATOK 2011" (similarly, e.g., ATOK 2013 is "ATOK 2013") pref("intl.imm.japanese.assume_active_tip_name_as", ""); @@ -5196,4 +5196,7 @@ pref("dom.fetch.enabled", true); // Turn rewriting of youtube embeds on/off pref("plugins.rewrite_youtube_embeds", true); +// Expose Request.context. Currently disabled since the spec is in flux. +pref("dom.requestcontext.enabled", false); + pref("devtools.serviceWorkers.testing.enabled", false); diff --git a/testing/web-platform/meta/battery-status/battery-interface-idlharness.html.ini b/testing/web-platform/meta/battery-status/battery-interface-idlharness.html.ini new file mode 100644 index 0000000000..9dfb5b93b0 --- /dev/null +++ b/testing/web-platform/meta/battery-status/battery-interface-idlharness.html.ini @@ -0,0 +1,52 @@ +[battery-interface-idlharness.html] + type: testharness + [Navigator interface: operation getBattery()] + expected: FAIL + + [BatteryManager must be primary interface of navigator.getBattery()] + expected: FAIL + + [Stringification of navigator.getBattery()] + expected: FAIL + + [BatteryManager interface: navigator.getBattery() must inherit property "charging" with the proper type (0)] + expected: FAIL + + [BatteryManager interface: navigator.getBattery() must inherit property "chargingTime" with the proper type (1)] + expected: FAIL + + [BatteryManager interface: navigator.getBattery() must inherit property "dischargingTime" with the proper type (2)] + expected: FAIL + + [BatteryManager interface: navigator.getBattery() must inherit property "level" with the proper type (3)] + expected: FAIL + + [BatteryManager interface: navigator.getBattery() must inherit property "onchargingchange" with the proper type (4)] + expected: FAIL + + [BatteryManager interface: navigator.getBattery() must inherit property "onchargingtimechange" with the proper type (5)] + expected: FAIL + + [BatteryManager interface: navigator.getBattery() must inherit property "ondischargingtimechange" with the proper type (6)] + expected: FAIL + + [BatteryManager interface: navigator.getBattery() must inherit property "onlevelchange" with the proper type (7)] + expected: FAIL + + [EventTarget interface: navigator.getBattery() must inherit property "addEventListener" with the proper type (0)] + expected: FAIL + + [EventTarget interface: calling addEventListener(DOMString,EventListener,boolean) on navigator.getBattery() with too few arguments must throw TypeError] + expected: FAIL + + [EventTarget interface: navigator.getBattery() must inherit property "removeEventListener" with the proper type (1)] + expected: FAIL + + [EventTarget interface: calling removeEventListener(DOMString,EventListener,boolean) on navigator.getBattery() with too few arguments must throw TypeError] + expected: FAIL + + [EventTarget interface: navigator.getBattery() must inherit property "dispatchEvent" with the proper type (2)] + expected: FAIL + + [EventTarget interface: calling dispatchEvent(Event) on navigator.getBattery() with too few arguments must throw TypeError] + expected: FAIL diff --git a/testing/web-platform/meta/battery-status/battery-interface.html.ini b/testing/web-platform/meta/battery-status/battery-interface.html.ini index db9af28909..751db42b6c 100644 --- a/testing/web-platform/meta/battery-status/battery-interface.html.ini +++ b/testing/web-platform/meta/battery-status/battery-interface.html.ini @@ -1,6 +1,37 @@ [battery-interface.html] type: testharness - expected: ERROR - [getBattery is present on navigator] + [onchargingchange: treat object as null] expected: FAIL + [onchargingchange: treat object with non-callable call property as null] + expected: FAIL + + [onchargingchange: treat array as null] + expected: FAIL + + [onchargingtimechange: treat object as null] + expected: FAIL + + [onchargingtimechange: treat object with non-callable call property as null] + expected: FAIL + + [onchargingtimechange: treat array as null] + expected: FAIL + + [ondischargingtimechange: treat object as null] + expected: FAIL + + [ondischargingtimechange: treat object with non-callable call property as null] + expected: FAIL + + [ondischargingtimechange: treat array as null] + expected: FAIL + + [onlevelchange: treat object as null] + expected: FAIL + + [onlevelchange: treat object with non-callable call property as null] + expected: FAIL + + [onlevelchange: treat array as null] + expected: FAIL diff --git a/testing/web-platform/meta/battery-status/battery-promise.html.ini b/testing/web-platform/meta/battery-status/battery-promise.html.ini deleted file mode 100644 index b3528619c0..0000000000 --- a/testing/web-platform/meta/battery-status/battery-promise.html.ini +++ /dev/null @@ -1,8 +0,0 @@ -[battery-promise.html] - type: testharness - [navigator.getBattery() return BatteryManager] - expected: FAIL - - [navigator.getBattery() shall always return the same promise] - expected: FAIL - diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 2dffe92a8a..95d855bd87 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -6783,5 +6783,15 @@ "high": "100", "n_buckets": "20", "description": "Proportion (%) of reschedulings of the main process to another CPU during the execution of code inside a JS compartment. Updated while we are measuring jank." + }, + "PERMISSIONS_SQL_CORRUPTED": { + "expires_in_version": "never", + "kind": "count", + "description": "Record the permissions.sqlite init failure" + }, + "DEFECTIVE_PERMISSIONS_SQL_REMOVED": { + "expires_in_version": "never", + "kind": "count", + "description": "Record the removal of defective permissions.sqlite" } } diff --git a/toolkit/devtools/server/tests/unit/test_originAttributesToCookieJar.js b/toolkit/devtools/server/tests/unit/test_originAttributesToCookieJar.js deleted file mode 100644 index e460570759..0000000000 --- a/toolkit/devtools/server/tests/unit/test_originAttributesToCookieJar.js +++ /dev/null @@ -1,26 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -Cu.import("resource://gre/modules/Services.jsm"); -var ssm = Services.scriptSecurityManager; - -function run_test() { - const appId = 12; - var browserAttrs = {appId: appId, inBrowser: true}; - - // ChromeUtils.originAttributesToCookieJar should return the same value with - // the cookieJar of the principal created from the same origin attribute. - var cookieJar_1 = ChromeUtils.originAttributesToCookieJar(browserAttrs); - var dummy = Services.io.newURI("http://example.com", null, null); - var cookieJar_2 = ssm.createCodebasePrincipal(dummy, browserAttrs).cookieJar; - do_check_eq(cookieJar_1, cookieJar_2); - - // App and mozbrowser shouldn't have the same cookieJar identifier. - var appAttrs = {appId: appId, inBrowser: false}; - var cookieJar_3 = ChromeUtils.originAttributesToCookieJar(appAttrs); - do_check_neq(cookieJar_1, cookieJar_3); - - // If the attribute is null the cookieJar identifier should be empty. - var cookieJar_4 = ChromeUtils.originAttributesToCookieJar(); - do_check_eq(cookieJar_4, ""); -} diff --git a/toolkit/devtools/server/tests/unit/xpcshell.ini b/toolkit/devtools/server/tests/unit/xpcshell.ini index 16e2de8f2e..db72e69de9 100644 --- a/toolkit/devtools/server/tests/unit/xpcshell.ini +++ b/toolkit/devtools/server/tests/unit/xpcshell.ini @@ -81,7 +81,6 @@ support-files = [test_eval-03.js] [test_eval-04.js] [test_eval-05.js] -[test_originAttributesToCookieJar.js] [test_promises_actor_attach.js] [test_promises_actor_exist.js] [test_promises_actor_list_promises.js] diff --git a/toolkit/modules/Battery.jsm b/toolkit/modules/Battery.jsm index 486a4f70d6..2b0f9abcb7 100644 --- a/toolkit/modules/Battery.jsm +++ b/toolkit/modules/Battery.jsm @@ -5,12 +5,12 @@ "use strict"; -/** This module wraps around navigator.battery (https://developer.mozilla.org/en-US/docs/Web/API/Navigator.battery). +/** This module wraps around navigator.getBattery (https://developer.mozilla.org/en-US/docs/Web/API/Navigator.getBattery). * and provides a framework for spoofing battery values in test code. * To spoof the battery values, set `Debugging.fake = true` after exporting this with a BackstagePass, - * after which you can spoof a property yb setting the relevant property of the Battery object. + * after which you can spoof a property yb setting the relevant property of the BatteryManager object. */ -this.EXPORTED_SYMBOLS = ["Battery"]; +this.EXPORTED_SYMBOLS = ["GetBattery", "Battery"]; const Ci = Components.interfaces; const Cc = Components.classes; @@ -40,6 +40,17 @@ this.Debugging = { fake: false } +this.GetBattery = function () { + return new Services.appShell.hiddenDOMWindow.Promise(function (resolve, reject) { + // Return fake values if spoofing is enabled, otherwise fetch the real values from the BatteryManager API + if (Debugging.fake) { + resolve(gFakeBattery); + return; + } + Services.appShell.hiddenDOMWindow.navigator.getBattery().then(resolve, reject); + }); +}; + this.Battery = {}; for (let k of ["charging", "chargingTime", "dischargingTime", "level"]) { @@ -54,9 +65,9 @@ for (let k of ["charging", "chargingTime", "dischargingTime", "level"]) { }, set: function(fakeSetting) { if (!Debugging.fake) { - throw new Error("Tried to set fake battery value when battery spoofing was disabled"); + throw new Error("Tried to set fake battery value when battery spoofing was disabled"); } gFakeBattery[prop] = fakeSetting; } }) -} \ No newline at end of file +} diff --git a/toolkit/modules/BrowserUtils.jsm b/toolkit/modules/BrowserUtils.jsm index ffd3157b94..eb20647a2b 100644 --- a/toolkit/modules/BrowserUtils.jsm +++ b/toolkit/modules/BrowserUtils.jsm @@ -210,37 +210,6 @@ this.BrowserUtils = { return "_blank"; }, - onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) { - // Don't modify non-default targets or targets that aren't in top-level app - // tab docshells (isAppTab will be false for app tab subframes). - if (originalTarget != "" || !isAppTab) - return originalTarget; - - // External links from within app tabs should always open in new tabs - // instead of replacing the app tab's page (Bug 575561) - let linkHost; - let docHost; - try { - linkHost = linkURI.host; - docHost = linkNode.ownerDocument.documentURIObject.host; - } catch(e) { - // nsIURI.host can throw for non-nsStandardURL nsIURIs. - // If we fail to get either host, just return originalTarget. - return originalTarget; - } - - if (docHost == linkHost) - return originalTarget; - - // Special case: ignore "www" prefix if it is part of host string - let [longHost, shortHost] = - linkHost.length > docHost.length ? [linkHost, docHost] : [docHost, linkHost]; - if (longHost == "www." + shortHost) - return originalTarget; - - return "_blank"; - }, - /** * Map the plugin's name to a filtered version more suitable for UI. * diff --git a/toolkit/modules/secondscreen/RokuApp.jsm b/toolkit/modules/secondscreen/RokuApp.jsm index 15a9ce2801..bbafca6931 100644 --- a/toolkit/modules/secondscreen/RokuApp.jsm +++ b/toolkit/modules/secondscreen/RokuApp.jsm @@ -11,10 +11,6 @@ const { classes: Cc, interfaces: Ci, utils: Cu } = Components; Cu.import("resource://gre/modules/Services.jsm"); -const WEBRTC_PLAYER_NAME = "WebRTC Player"; -const MIRROR_PORT = 8011; -const JSON_MESSAGE_TERMINATOR = "\r\n"; - function log(msg) { //Services.console.logStringMessage(msg); } @@ -34,7 +30,6 @@ function RokuApp(service) { this.app = "Firefox Nightly"; #endif this.mediaAppID = -1; - this.mirrorAppID = -1; } RokuApp.prototype = { @@ -54,8 +49,6 @@ RokuApp.prototype = { for (let app of apps) { if (app.textContent == this.app) { this.mediaAppID = app.id; - } else if (app.textContent == WEBRTC_PLAYER_NAME) { - this.mirrorAppID = app.id } } } @@ -145,44 +138,6 @@ RokuApp.prototype = { callback(); } } - }, - - mirror: function(callback, win, viewport, mirrorStartedCallback, contentWindow) { - if (this.mirrorAppID == -1) { - // The status function may not have been called yet if mirrorAppID is -1 - this.status(this._createRemoteMirror.bind(this, callback, win, viewport, mirrorStartedCallback, contentWindow)); - } else { - this._createRemoteMirror(callback, win, viewport, mirrorStartedCallback, contentWindow); - } - }, - - _createRemoteMirror: function(callback, win, viewport, mirrorStartedCallback, contentWindow) { - if (this.mirrorAppID == -1) { - // TODO: Inform user to install Roku WebRTC Player Channel. - log("RokuApp: Failed to find Mirror App ID."); - } else { - let url = this.resourceURL + "launch/" + this.mirrorAppID; - let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest); - xhr.open("POST", url, true); - xhr.overrideMimeType("text/plain"); - - xhr.addEventListener("load", (function() { - // 204 seems to be returned if the channel is already running - if ((xhr.status == 200) || (xhr.status == 204)) { - this.remoteMirror = new RemoteMirror(this.resourceURL, win, viewport, mirrorStartedCallback, contentWindow); - } - }).bind(this), false); - - xhr.addEventListener("error", function() { - log("RokuApp: XHR Failed to launch application: " + WEBRTC_PLAYER_NAME); - }, false); - - xhr.send(null); - } - - if (callback) { - callback(); - } } } @@ -278,131 +233,3 @@ RemoteMedia.prototype = { return this._status; } } - -function RemoteMirror(url, win, viewport, mirrorStartedCallback, contentWindow) { - this._serverURI = Services.io.newURI(url , null, null); - this._window = win; - this._iceCandidates = []; - this.mirrorStarted = mirrorStartedCallback; - - // This code insures the generated tab mirror is not wider than 1280 nor taller than 720 - // Better dimensions should be chosen after the Roku Channel is working. - let windowId = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).outerWindowID; - const MAX_WIDTH = 1280; - const MAX_HEIGHT = 720; - - let constraints = { - video: { - mediaSource: "browser", - browserWindow: windowId, - scrollWithPage: true, - advanced: [ - { - width: { min: 0, max: MAX_WIDTH }, - height: { min: 0, max: MAX_HEIGHT } - }, - { aspectRatio: MAX_WIDTH/MAX_HEIGHT } - ] - } - }; - - this._window.navigator.mozGetUserMedia(constraints, this._onReceiveGUMStream.bind(this), function() {}); -} - -RemoteMirror.prototype = { - _sendOffer: function(offer) { - if (!this._baseSocket) { - this._baseSocket = Cc["@mozilla.org/tcp-socket;1"].createInstance(Ci.nsIDOMTCPSocket); - } - this._jsonOffer = JSON.stringify(offer); - this._socket = this._baseSocket.open(this._serverURI.host, MIRROR_PORT, { useSecureTransport: false, binaryType: "string" }); - this._socket.onopen = this._onSocketOpen.bind(this); - this._socket.ondata = this._onSocketData.bind(this); - this._socket.onerror = this._onSocketError.bind(this); - }, - - _onReceiveGUMStream: function(stream) { - this._pc = new this._window.mozRTCPeerConnection; - this._pc.addStream(stream); - this._pc.onicecandidate = (evt => { - // Usually the last candidate is null, expected? - if (!evt.candidate) { - return; - } - let jsonCandidate = JSON.stringify(evt.candidate); - this._iceCandidates.push(jsonCandidate); - this._sendIceCandidates(); - }); - - this._pc.createOffer(offer => { - this._pc.setLocalDescription( - new this._window.mozRTCSessionDescription(offer), - () => this._sendOffer(offer), - () => log("RemoteMirror: Failed to set local description.")); - }, - () => log("RemoteMirror: Failed to create offer.")); - }, - - _stopMirror: function() { - if (this._socket) { - this._socket.close(); - this._socket = null; - } - if (this._pc) { - this._pc.close(); - this._pc = null; - } - this._jsonOffer = null; - this._iceCandidates = []; - }, - - _onSocketData: function(response) { - if (response.type == "data") { - response.data.split(JSON_MESSAGE_TERMINATOR).forEach(data => { - if (data) { - let parsedData = JSON.parse(data); - if (parsedData.type == "answer") { - this._pc.setRemoteDescription( - new this._window.mozRTCSessionDescription(parsedData), - () => this.mirrorStarted(this._stopMirror.bind(this)), - () => log("RemoteMirror: Failed to set remote description.")); - } else { - this._pc.addIceCandidate(new this._window.mozRTCIceCandidate(parsedData)) - } - } else { - log("RemoteMirror: data is null"); - } - }); - } else if (response.type == "error") { - log("RemoteMirror: Got socket error."); - this._stopMirror(); - } else { - log("RemoteMirror: Got unhandled socket event: " + response.type); - } - }, - - _onSocketError: function(err) { - log("RemoteMirror: Error socket.onerror: " + (err.data ? err.data : "NO DATA")); - this._stopMirror(); - }, - - _onSocketOpen: function() { - this._open = true; - if (this._jsonOffer) { - let jsonOffer = this._jsonOffer + JSON_MESSAGE_TERMINATOR; - this._socket.send(jsonOffer, jsonOffer.length); - this._jsonOffer = null; - this._sendIceCandidates(); - } - }, - - _sendIceCandidates: function() { - if (this._socket && this._open) { - this._iceCandidates.forEach(value => { - value = value + JSON_MESSAGE_TERMINATOR; - this._socket.send(value, value.length); - }); - this._iceCandidates = []; - } - } -}; diff --git a/toolkit/modules/tests/browser/browser_Battery.js b/toolkit/modules/tests/browser/browser_Battery.js index d9aa088365..9a4c4f8fba 100644 --- a/toolkit/modules/tests/browser/browser_Battery.js +++ b/toolkit/modules/tests/browser/browser_Battery.js @@ -6,8 +6,11 @@ let imported = Components.utils.import("resource://gre/modules/Battery.jsm", thi Cu.import("resource://gre/modules/Services.jsm", this); function test() { + waitForExplicitFinish(); + is(imported.Debugging.fake, false, "Battery spoofing is initially false") + // begin deprecated battery API testing for (let k of ["charging", "chargingTime", "dischargingTime", "level"]) { Assert.throws(() => Battery[k] = 10, "Setting battery " + k + "preference without spoofing enabled should throw"); ok(Battery[k] == Services.appShell.hiddenDOMWindow.navigator.battery[k], "Battery "+ k + " is correctly set"); @@ -27,4 +30,36 @@ function test() { ok(!Battery.charging, "Test for charging setter"); is(Battery.dischargingTime, 50, "Test for dischargingTime setter"); is(Battery.level, 0.7, "Test for level setter"); -} \ No newline at end of file + + imported.Debugging.fake = false; + // end deprecated battery API testing + + GetBattery().then(function (battery) { + for (let k of ["charging", "chargingTime", "dischargingTime", "level"]) { + let backup = battery[k]; + battery[k] = "__magic__"; + is(battery[k], backup, "Setting battery " + k + "preference without spoofing enabled should fail"); + } + + imported.Debugging.fake = true; + + // reload again to get the fake one + GetBattery().then(function (battery) { + battery.charging = true; + battery.chargingTime = 100; + battery.level = 0.5; + ok(battery.charging, "Test for charging setter"); + is(battery.chargingTime, 100, "Test for chargingTime setter"); + is(battery.level, 0.5, "Test for level setter"); + + battery.charging = false; + battery.dischargingTime = 50; + battery.level = 0.7; + ok(!battery.charging, "Test for charging setter"); + is(battery.dischargingTime, 50, "Test for dischargingTime setter"); + is(battery.level, 0.7, "Test for level setter"); + + finish(); + }); + }); +}