mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-07 16:28:38 +09:00
Merge remote-tracking branch 'origin/master' into custom
This commit is contained in:
commit
61e493cf30
69 changed files with 2727 additions and 2128 deletions
|
|
@ -1285,7 +1285,7 @@ BrowserGlue.prototype = {
|
|||
},
|
||||
|
||||
_migrateUI: function() {
|
||||
const UI_VERSION = 23;
|
||||
const UI_VERSION = 24;
|
||||
const BROWSER_DOCURL = "chrome://browser/content/browser.xul#";
|
||||
let currentUIVersion = 0;
|
||||
try {
|
||||
|
|
@ -1552,6 +1552,13 @@ BrowserGlue.prototype = {
|
|||
Services.prefs.clearUserPref("layers.acceleration.disabled");
|
||||
Services.prefs.clearUserPref("layers.acceleration.force-enabled");
|
||||
}
|
||||
|
||||
if (currentUIVersion < 24) {
|
||||
// AbortController's worker signalling was fixed so reset user prefs that
|
||||
// might have been set as workaround for web compat issues in the meantime.
|
||||
Services.prefs.clearUserPref("dom.abortController.enabled");
|
||||
}
|
||||
|
||||
|
||||
// Clear out dirty storage
|
||||
if (this._dirty) {
|
||||
|
|
|
|||
|
|
@ -3240,7 +3240,7 @@ var SessionStoreInternal = {
|
|||
// but only if restoring on demand, to prevent request flooding (since
|
||||
// reloading will override the max tabs to restore concurrently mechanism).
|
||||
// See Issue #1772
|
||||
if (restoreOnDemand) {
|
||||
if (TabRestoreQueue.prefs.restoreOnDemand) {
|
||||
let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
|
||||
switch (this._cacheBehavior) {
|
||||
case 2: // hard refresh
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@
|
|||
#include "nsUnicharUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "BatteryManager.h"
|
||||
#ifdef MOZ_GAMEPAD
|
||||
#include "mozilla/dom/GamepadServiceTest.h"
|
||||
#endif
|
||||
|
|
@ -197,8 +196,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
|
|||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPermissions)
|
||||
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(mConnection)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStorageManager)
|
||||
|
|
@ -249,13 +246,6 @@ Navigator::Invalidate()
|
|||
mNotification = nullptr;
|
||||
}
|
||||
|
||||
if (mBatteryManager) {
|
||||
mBatteryManager->Shutdown();
|
||||
mBatteryManager = nullptr;
|
||||
}
|
||||
|
||||
mBatteryPromise = nullptr;
|
||||
|
||||
if (mPowerManager) {
|
||||
mPowerManager->Shutdown();
|
||||
mPowerManager = nullptr;
|
||||
|
|
@ -1321,39 +1311,6 @@ Navigator::GetMozNotification(ErrorResult& aRv)
|
|||
return mNotification;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// Navigator::nsINavigatorBattery
|
||||
//*****************************************************************************
|
||||
|
||||
Promise*
|
||||
Navigator::GetBattery(ErrorResult& aRv)
|
||||
{
|
||||
if (mBatteryPromise) {
|
||||
return mBatteryPromise;
|
||||
}
|
||||
|
||||
if (!mWindow || !mWindow->GetDocShell()) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow);
|
||||
RefPtr<Promise> 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;
|
||||
}
|
||||
|
||||
PowerManager*
|
||||
Navigator::GetMozPower(ErrorResult& aRv)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -51,10 +51,6 @@ namespace dom {
|
|||
|
||||
class Permissions;
|
||||
|
||||
namespace battery {
|
||||
class BatteryManager;
|
||||
} // namespace battery
|
||||
|
||||
class Promise;
|
||||
|
||||
class DesktopNotificationCenter;
|
||||
|
|
@ -136,7 +132,6 @@ public:
|
|||
Permissions* GetPermissions(ErrorResult& aRv);
|
||||
// The XPCOM GetDoNotTrack is ok
|
||||
Geolocation* GetGeolocation(ErrorResult& aRv);
|
||||
Promise* GetBattery(ErrorResult& aRv);
|
||||
|
||||
static void AppName(nsAString& aAppName, bool aUsePrefOverriddenValue);
|
||||
|
||||
|
|
@ -269,8 +264,6 @@ private:
|
|||
RefPtr<Permissions> mPermissions;
|
||||
RefPtr<Geolocation> mGeolocation;
|
||||
RefPtr<DesktopNotificationCenter> mNotification;
|
||||
RefPtr<battery::BatteryManager> mBatteryManager;
|
||||
RefPtr<Promise> mBatteryPromise;
|
||||
RefPtr<PowerManager> mPowerManager;
|
||||
RefPtr<network::Connection> mConnection;
|
||||
#ifdef MOZ_AUDIO_CHANNEL_MANAGER
|
||||
|
|
|
|||
|
|
@ -419,7 +419,6 @@ EXTRA_JS_MODULES += [
|
|||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'../battery',
|
||||
'../events',
|
||||
'../media',
|
||||
'../network',
|
||||
|
|
|
|||
|
|
@ -5123,6 +5123,14 @@ nsContentUtils::TriggerLink(nsIContent *aContent, nsPresContext *aPresContext,
|
|||
fileName.SetIsVoid(true); // No actionable download attribute was found.
|
||||
}
|
||||
|
||||
// Sanitize fileNames containing control characters by replacing them with
|
||||
// underscores.
|
||||
if (!fileName.IsVoid()) {
|
||||
for (int i = 0; i < 32; i++) {
|
||||
fileName.ReplaceChar(char16_t(i), '_');
|
||||
}
|
||||
}
|
||||
|
||||
handler->OnLinkClick(aContent, aLinkURI,
|
||||
fileName.IsVoid() ? aTargetSpec.get() : EmptyString().get(),
|
||||
fileName, nullptr, nullptr, aIsTrusted, aContent->NodePrincipal());
|
||||
|
|
|
|||
|
|
@ -1,212 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include "BatteryManager.h"
|
||||
#include "Constants.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/Hal.h"
|
||||
#include "mozilla/dom/BatteryManagerBinding.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIDOMClassInfo.h"
|
||||
#include "nsIDocument.h"
|
||||
|
||||
/**
|
||||
* We have to use macros here because our leak analysis tool things we are
|
||||
* leaking strings when we have |static const nsString|. Sad :(
|
||||
*/
|
||||
#define LEVELCHANGE_EVENT_NAME NS_LITERAL_STRING("levelchange")
|
||||
#define CHARGINGCHANGE_EVENT_NAME NS_LITERAL_STRING("chargingchange")
|
||||
#define DISCHARGINGTIMECHANGE_EVENT_NAME NS_LITERAL_STRING("dischargingtimechange")
|
||||
#define CHARGINGTIMECHANGE_EVENT_NAME NS_LITERAL_STRING("chargingtimechange")
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace battery {
|
||||
|
||||
BatteryManager::BatteryManager(nsPIDOMWindowInner* aWindow)
|
||||
: DOMEventTargetHelper(aWindow)
|
||||
, mLevel(kDefaultLevel)
|
||||
, mCharging(kDefaultCharging)
|
||||
, mRemainingTime(kDefaultRemainingTime)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
BatteryManager::Init()
|
||||
{
|
||||
hal::RegisterBatteryObserver(this);
|
||||
|
||||
hal::BatteryInformation batteryInfo;
|
||||
hal::GetCurrentBatteryInformation(&batteryInfo);
|
||||
|
||||
UpdateFromBatteryInfo(batteryInfo);
|
||||
}
|
||||
|
||||
void
|
||||
BatteryManager::Shutdown()
|
||||
{
|
||||
hal::UnregisterBatteryObserver(this);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
BatteryManager::WrapObject(JSContext* aCx, JS::Handle<JSObject*> 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
|
||||
{
|
||||
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<double>::infinity();
|
||||
}
|
||||
if (Preferences::GetBool("dom.battery.test.discharging", false)) {
|
||||
return 42.0;
|
||||
}
|
||||
|
||||
if (Charging() || mRemainingTime == kUnknownRemainingTime) {
|
||||
return std::numeric_limits<double>::infinity();
|
||||
}
|
||||
|
||||
return mRemainingTime;
|
||||
}
|
||||
|
||||
double
|
||||
BatteryManager::ChargingTime() const
|
||||
{
|
||||
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<double>::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)
|
||||
{
|
||||
mLevel = aBatteryInfo.level();
|
||||
|
||||
// Round to the nearest ten percent for non-chrome and non-certified apps
|
||||
nsIDocument* doc = GetOwner() ? GetOwner()->GetDoc() : nullptr;
|
||||
uint16_t status = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
|
||||
if (doc) {
|
||||
status = doc->NodePrincipal()->GetAppStatus();
|
||||
}
|
||||
|
||||
mCharging = aBatteryInfo.charging();
|
||||
mRemainingTime = aBatteryInfo.remainingTime();
|
||||
|
||||
if (!nsContentUtils::IsChromeDoc(doc) &&
|
||||
status != nsIPrincipal::APP_STATUS_CERTIFIED)
|
||||
{
|
||||
mLevel = lround(mLevel * 10.0) / 10.0;
|
||||
if (mLevel == 1.0) {
|
||||
mRemainingTime = mCharging ? kDefaultRemainingTime : kUnknownRemainingTime;
|
||||
} else if (mRemainingTime != kUnknownRemainingTime) {
|
||||
// Round the remaining time to a multiple of 15 minutes and never zero
|
||||
const double MINUTES_15 = 15.0 * 60.0;
|
||||
mRemainingTime = fmax(lround(mRemainingTime / MINUTES_15) * MINUTES_15,
|
||||
MINUTES_15);
|
||||
}
|
||||
}
|
||||
|
||||
// Add some guards to make sure the values are coherent.
|
||||
if (mLevel == 1.0 && mCharging == true &&
|
||||
mRemainingTime != kDefaultRemainingTime) {
|
||||
mRemainingTime = kDefaultRemainingTime;
|
||||
NS_ERROR("Battery API: When charging and level at 1.0, remaining time "
|
||||
"should be 0. Please fix your backend!");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BatteryManager::Notify(const hal::BatteryInformation& aBatteryInfo)
|
||||
{
|
||||
double previousLevel = mLevel;
|
||||
bool previousCharging = mCharging;
|
||||
double previousRemainingTime = mRemainingTime;
|
||||
|
||||
UpdateFromBatteryInfo(aBatteryInfo);
|
||||
|
||||
if (previousCharging != mCharging) {
|
||||
DispatchTrustedEvent(CHARGINGCHANGE_EVENT_NAME);
|
||||
}
|
||||
|
||||
if (previousLevel != mLevel) {
|
||||
DispatchTrustedEvent(LEVELCHANGE_EVENT_NAME);
|
||||
}
|
||||
|
||||
/*
|
||||
* There are a few situations that could happen here:
|
||||
* 1. Charging state changed:
|
||||
* a. Previous remaining time wasn't unkwonw, we have to fire an event for
|
||||
* the change.
|
||||
* b. New remaining time isn't unkwonw, we have to fire an event for it.
|
||||
* 2. Charging state didn't change but remainingTime did, we have to fire
|
||||
* the event that correspond to the current charging state.
|
||||
*/
|
||||
if (mCharging != previousCharging) {
|
||||
if (previousRemainingTime != kUnknownRemainingTime) {
|
||||
DispatchTrustedEvent(previousCharging ? CHARGINGTIMECHANGE_EVENT_NAME
|
||||
: DISCHARGINGTIMECHANGE_EVENT_NAME);
|
||||
}
|
||||
if (mRemainingTime != kUnknownRemainingTime) {
|
||||
DispatchTrustedEvent(mCharging ? CHARGINGTIMECHANGE_EVENT_NAME
|
||||
: DISCHARGINGTIMECHANGE_EVENT_NAME);
|
||||
}
|
||||
} else if (previousRemainingTime != mRemainingTime) {
|
||||
DispatchTrustedEvent(mCharging ? CHARGINGTIMECHANGE_EVENT_NAME
|
||||
: DISCHARGINGTIMECHANGE_EVENT_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace battery
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_battery_BatteryManager_h
|
||||
#define mozilla_dom_battery_BatteryManager_h
|
||||
|
||||
#include "Types.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/Observer.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace hal {
|
||||
class BatteryInformation;
|
||||
} // namespace hal
|
||||
|
||||
namespace dom {
|
||||
namespace battery {
|
||||
|
||||
class BatteryManager : public DOMEventTargetHelper
|
||||
, public BatteryObserver
|
||||
{
|
||||
public:
|
||||
explicit BatteryManager(nsPIDOMWindowInner* aWindow);
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
// For IObserver.
|
||||
void Notify(const hal::BatteryInformation& aBatteryInfo) override;
|
||||
|
||||
/**
|
||||
* WebIDL Interface
|
||||
*/
|
||||
|
||||
nsPIDOMWindowInner* GetParentObject() const
|
||||
{
|
||||
return GetOwner();
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
bool Charging() const;
|
||||
|
||||
double ChargingTime() const;
|
||||
|
||||
double DischargingTime() const;
|
||||
|
||||
double Level() const;
|
||||
|
||||
IMPL_EVENT_HANDLER(chargingchange)
|
||||
IMPL_EVENT_HANDLER(chargingtimechange)
|
||||
IMPL_EVENT_HANDLER(dischargingtimechange)
|
||||
IMPL_EVENT_HANDLER(levelchange)
|
||||
|
||||
private:
|
||||
/**
|
||||
* Update the battery information stored in the battery manager object using
|
||||
* a battery information object.
|
||||
*/
|
||||
void UpdateFromBatteryInfo(const hal::BatteryInformation& aBatteryInfo);
|
||||
|
||||
/**
|
||||
* Represents the battery level, ranging from 0.0 (dead or removed?)
|
||||
* to 1.0 (fully charged)
|
||||
*/
|
||||
double mLevel;
|
||||
bool mCharging;
|
||||
/**
|
||||
* Represents the discharging time or the charging time, depending on the
|
||||
* current battery status (charging or not).
|
||||
*/
|
||||
double mRemainingTime;
|
||||
};
|
||||
|
||||
} // namespace battery
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_battery_BatteryManager_h
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_battery_Constants_h__
|
||||
#define mozilla_dom_battery_Constants_h__
|
||||
|
||||
/**
|
||||
* A set of constants that might need to be used by battery backends.
|
||||
* It's not part of BatteryManager.h to prevent those backends to include it.
|
||||
*/
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace battery {
|
||||
|
||||
static const double kDefaultLevel = 1.0;
|
||||
static const bool kDefaultCharging = true;
|
||||
static const double kDefaultRemainingTime = 0;
|
||||
static const double kUnknownRemainingTime = -1;
|
||||
|
||||
} // namespace battery
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_battery_Constants_h__
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_battery_Types_h
|
||||
#define mozilla_dom_battery_Types_h
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal {
|
||||
class BatteryInformation;
|
||||
} // namespace hal
|
||||
|
||||
template <class T>
|
||||
class Observer;
|
||||
|
||||
typedef Observer<hal::BatteryInformation> BatteryObserver;
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_battery_Types_h
|
||||
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
EXPORTS.mozilla.dom.battery += [
|
||||
'Constants.h',
|
||||
'Types.h',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'BatteryManager.cpp',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
|
||||
MOCHITEST_MANIFESTS += ['test/mochitest.ini']
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
[test_battery_basics.html]
|
||||
[test_battery_charging.html]
|
||||
[test_battery_discharging.html]
|
||||
|
|
@ -1 +0,0 @@
|
|||
[test_battery_unprivileged.html]
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Battery API</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
"use strict";
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
/** Test for Battery API **/
|
||||
ok("getBattery" in navigator, "navigator.getBattery should exist");
|
||||
ok(!("battery" in navigator), "navigator.battery should not exist");
|
||||
|
||||
navigator.getBattery().then(function (battery) {
|
||||
ok(battery.level >= 0.0 && battery.level <= 1.0, "Battery level " + battery.level + " should be in the range [0.0, 1.0]");
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.battery.test.default", true]]}, function () {
|
||||
ok(battery.charging, "Battery should be charging by default");
|
||||
is(battery.chargingTime, 0, "Battery chargingTime " + battery.chargingTime + " should be zero by default");
|
||||
is(battery.dischargingTime, Infinity, "Battery dischargingTime should be Infinity by default");
|
||||
is(battery.level, 1.0, "Battery level " + battery.level + " should be 1.0 by default");
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Battery API</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
"use strict";
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
/** Test for Battery API **/
|
||||
navigator.getBattery().then(function (battery) {
|
||||
ok(battery.level >= 0.0 && battery.level <= 1.0, "Battery level " + battery.level + " should be in the range [0.0, 1.0]");
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.battery.test.charging", true]]}, function () {
|
||||
is(battery.charging, true, "Battery should be charging");
|
||||
ok(battery.chargingTime >= 0, "Battery chargingTime " + battery.chargingTime + " should be nonnegative when charging");
|
||||
is(battery.dischargingTime, Infinity, "Battery dischargingTime should be Infinity when charging");
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Battery API</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
"use strict";
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
/** Test for Battery API **/
|
||||
navigator.getBattery().then(function (battery) {
|
||||
ok(battery.level >= 0.0 && battery.level <= 1.0, "Battery level " + battery.level + " should be in the range [0.0, 1.0]");
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.battery.test.discharging", true]]}, function () {
|
||||
is(battery.charging, false, "Battery should be discharging");
|
||||
is(battery.chargingTime, Infinity, "Battery chargingTime should be Infinity when discharging");
|
||||
ok(battery.dischargingTime > 0, "Battery dischargingTime " + battery.dischargingTime + " should be positive when discharging");
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Battery API</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
"use strict";
|
||||
|
||||
/** Test for Battery API **/
|
||||
ok(!("getBattery" in navigator), "navigator.getBattery should not exist for unprivileged web content");
|
||||
ok(!("battery" in navigator), "navigator.battery should not exist");
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -62,7 +62,6 @@ LOCAL_INCLUDES += [
|
|||
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/base',
|
||||
'/dom/battery',
|
||||
'/dom/canvas',
|
||||
'/dom/geolocation',
|
||||
'/dom/html',
|
||||
|
|
|
|||
6
dom/cache/TypeUtils.cpp
vendored
6
dom/cache/TypeUtils.cpp
vendored
|
|
@ -253,7 +253,7 @@ TypeUtils::ToResponse(const CacheResponse& aIn)
|
|||
{
|
||||
if (aIn.type() == ResponseType::Error) {
|
||||
RefPtr<InternalResponse> error = InternalResponse::NetworkError();
|
||||
RefPtr<Response> r = new Response(GetGlobalObject(), error);
|
||||
RefPtr<Response> r = new Response(GetGlobalObject(), error, nullptr);
|
||||
return r.forget();
|
||||
}
|
||||
|
||||
|
|
@ -302,7 +302,7 @@ TypeUtils::ToResponse(const CacheResponse& aIn)
|
|||
}
|
||||
MOZ_DIAGNOSTIC_ASSERT(ir);
|
||||
|
||||
RefPtr<Response> ref = new Response(GetGlobalObject(), ir);
|
||||
RefPtr<Response> ref = new Response(GetGlobalObject(), ir, nullptr);
|
||||
return ref.forget();
|
||||
}
|
||||
already_AddRefed<InternalRequest>
|
||||
|
|
@ -345,7 +345,7 @@ already_AddRefed<Request>
|
|||
TypeUtils::ToRequest(const CacheRequest& aIn)
|
||||
{
|
||||
RefPtr<InternalRequest> internalRequest = ToInternalRequest(aIn);
|
||||
RefPtr<Request> request = new Request(GetGlobalObject(), internalRequest);
|
||||
RefPtr<Request> request = new Request(GetGlobalObject(), internalRequest, nullptr);
|
||||
return request.forget();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -111,6 +111,12 @@ public:
|
|||
return mSignalMainThread;
|
||||
}
|
||||
|
||||
AbortSignal*
|
||||
GetSignalForTargetThread()
|
||||
{
|
||||
return mFollowingSignal;
|
||||
}
|
||||
|
||||
void
|
||||
Shutdown()
|
||||
{
|
||||
|
|
@ -161,7 +167,7 @@ public:
|
|||
}
|
||||
|
||||
AbortSignal*
|
||||
GetAbortSignal()
|
||||
GetAbortSignalForMainThread()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
|
@ -172,6 +178,18 @@ public:
|
|||
return mSignalProxy->GetOrCreateSignalForMainThread();
|
||||
}
|
||||
|
||||
AbortSignal*
|
||||
GetAbortSignalForTargetThread()
|
||||
{
|
||||
mPromiseProxy->GetWorkerPrivate()->AssertIsOnWorkerThread();
|
||||
|
||||
if (!mSignalProxy) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return mSignalProxy->GetSignalForTargetThread();
|
||||
}
|
||||
|
||||
void
|
||||
OnResponseAvailableInternal(InternalResponse* aResponse) override;
|
||||
|
||||
|
|
@ -205,14 +223,16 @@ class MainThreadFetchResolver final : public FetchDriverObserver
|
|||
RefPtr<Promise> mPromise;
|
||||
RefPtr<Response> mResponse;
|
||||
RefPtr<FetchObserver> mFetchObserver;
|
||||
RefPtr<AbortSignal> mSignal;
|
||||
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
|
||||
NS_DECL_OWNINGTHREAD
|
||||
public:
|
||||
MainThreadFetchResolver(Promise* aPromise, FetchObserver* aObserver)
|
||||
MainThreadFetchResolver(Promise* aPromise, FetchObserver* aObserver, AbortSignal* aSignal)
|
||||
: mPromise(aPromise)
|
||||
, mFetchObserver(aObserver)
|
||||
, mSignal(aSignal)
|
||||
{}
|
||||
|
||||
void
|
||||
|
|
@ -287,7 +307,7 @@ public:
|
|||
fetch->SetWorkerScript(spec);
|
||||
}
|
||||
|
||||
RefPtr<AbortSignal> signal = mResolver->GetAbortSignal();
|
||||
RefPtr<AbortSignal> signal = mResolver->GetAbortSignalForMainThread();
|
||||
|
||||
// ...but release it before calling Fetch, because mResolver's callback can
|
||||
// be called synchronously and they want the mutex, too.
|
||||
|
|
@ -329,10 +349,7 @@ FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
|
|||
|
||||
RefPtr<InternalRequest> r = request->GetInternalRequest();
|
||||
|
||||
RefPtr<AbortSignal> signal;
|
||||
if (aInit.mSignal.WasPassed()) {
|
||||
signal = &aInit.mSignal.Value();
|
||||
}
|
||||
RefPtr<AbortSignal> signal = request->GetSignal();
|
||||
|
||||
if (signal && signal->Aborted()) {
|
||||
// An already aborted signal should reject immediately.
|
||||
|
|
@ -373,7 +390,7 @@ FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
|
|||
}
|
||||
|
||||
RefPtr<MainThreadFetchResolver> resolver =
|
||||
new MainThreadFetchResolver(p, observer);
|
||||
new MainThreadFetchResolver(p, observer, signal);
|
||||
RefPtr<FetchDriver> fetch = new FetchDriver(r, principal, loadGroup);
|
||||
fetch->SetDocument(doc);
|
||||
resolver->SetDocument(doc);
|
||||
|
|
@ -416,7 +433,7 @@ MainThreadFetchResolver::OnResponseAvailableInternal(InternalResponse* aResponse
|
|||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> go = mPromise->GetParentObject();
|
||||
mResponse = new Response(go, aResponse);
|
||||
mResponse = new Response(go, aResponse, mSignal);
|
||||
mPromise->MaybeResolve(mResponse);
|
||||
} else {
|
||||
if (mFetchObserver) {
|
||||
|
|
@ -479,7 +496,7 @@ public:
|
|||
}
|
||||
|
||||
RefPtr<nsIGlobalObject> global = aWorkerPrivate->GlobalScope();
|
||||
RefPtr<Response> response = new Response(global, mInternalResponse);
|
||||
RefPtr<Response> response = new Response(global, mInternalResponse, mResolver->GetAbortSignalForTargetThread());
|
||||
promise->MaybeResolve(response);
|
||||
} else {
|
||||
if (mResolver->mFetchObserver) {
|
||||
|
|
@ -926,6 +943,12 @@ template <class Derived>
|
|||
already_AddRefed<Promise>
|
||||
FetchBody<Derived>::ConsumeBody(FetchConsumeType aType, ErrorResult& aRv)
|
||||
{
|
||||
RefPtr<AbortSignal> signal = DerivedClass()->GetSignal();
|
||||
if (signal && signal->Aborted()) {
|
||||
aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (BodyUsed()) {
|
||||
aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
|
||||
return nullptr;
|
||||
|
|
@ -935,7 +958,7 @@ FetchBody<Derived>::ConsumeBody(FetchConsumeType aType, ErrorResult& aRv)
|
|||
|
||||
RefPtr<Promise> promise =
|
||||
FetchBodyConsumer<Derived>::Create(DerivedClass()->GetParentObject(),
|
||||
this, aType, aRv);
|
||||
this, signal, aType, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,6 +162,9 @@ public:
|
|||
return mMimeType;
|
||||
}
|
||||
|
||||
virtual AbortSignal*
|
||||
GetSignal() const = 0;
|
||||
|
||||
protected:
|
||||
FetchBody();
|
||||
|
||||
|
|
|
|||
|
|
@ -284,6 +284,7 @@ template <class Derived>
|
|||
/* static */ already_AddRefed<Promise>
|
||||
FetchBodyConsumer<Derived>::Create(nsIGlobalObject* aGlobal,
|
||||
FetchBody<Derived>* aBody,
|
||||
AbortSignal* aSignal,
|
||||
FetchConsumeType aType,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
|
|
@ -345,6 +346,10 @@ FetchBodyConsumer<Derived>::Create(nsIGlobalObject* aGlobal,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (aSignal) {
|
||||
consumer->Follow(aSignal);
|
||||
}
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
|
|
@ -368,6 +373,8 @@ FetchBodyConsumer<Derived>::ReleaseObject()
|
|||
#ifdef DEBUG
|
||||
mBody = nullptr;
|
||||
#endif
|
||||
|
||||
Unfollow();
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
|
|
@ -684,6 +691,14 @@ FetchBodyConsumer<Derived>::Observe(nsISupports* aSubject,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
void
|
||||
FetchBodyConsumer<Derived>::Aborted()
|
||||
{
|
||||
AssertIsOnTargetThread();
|
||||
ContinueConsumeBody(NS_ERROR_DOM_ABORT_ERR, 0, nullptr);
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
NS_IMPL_ADDREF(FetchBodyConsumer<Derived>)
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "nsIInputStream.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "mozilla/dom/AbortSignal.h"
|
||||
#include "mozilla/dom/MutableBlobStorage.h"
|
||||
|
||||
class nsIThread;
|
||||
|
|
@ -34,6 +35,7 @@ template <class Derived> class FetchBody;
|
|||
template <class Derived>
|
||||
class FetchBodyConsumer final : public nsIObserver
|
||||
, public nsSupportsWeakReference
|
||||
, public AbortSignal::Follower
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
|
@ -42,6 +44,7 @@ public:
|
|||
static already_AddRefed<Promise>
|
||||
Create(nsIGlobalObject* aGlobal,
|
||||
FetchBody<Derived>* aBody,
|
||||
AbortSignal* aSignal,
|
||||
FetchConsumeType aType,
|
||||
ErrorResult& aRv);
|
||||
|
||||
|
|
@ -73,6 +76,9 @@ public:
|
|||
mConsumeBodyPump = nullptr;
|
||||
}
|
||||
|
||||
// Override AbortSignal::Follower::Aborted
|
||||
void Aborted() override;
|
||||
|
||||
private:
|
||||
FetchBodyConsumer(nsIGlobalObject* aGlobalObject,
|
||||
workers::WorkerPrivate* aWorkerPrivate,
|
||||
|
|
|
|||
|
|
@ -499,6 +499,11 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest,
|
|||
return rv;
|
||||
}
|
||||
|
||||
if (!mChannel) {
|
||||
MOZ_ASSERT(!mObserver);
|
||||
return NS_BINDING_ABORTED;
|
||||
}
|
||||
|
||||
// We should only get to the following code once.
|
||||
MOZ_ASSERT(!mPipeOutputStream);
|
||||
MOZ_ASSERT(mObserver);
|
||||
|
|
|
|||
|
|
@ -37,15 +37,18 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Request)
|
|||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
Request::Request(nsIGlobalObject* aOwner, InternalRequest* aRequest)
|
||||
Request::Request(nsIGlobalObject* aOwner, InternalRequest* aRequest, AbortSignal* aSignal)
|
||||
: FetchBody<Request>()
|
||||
, mOwner(aOwner)
|
||||
, mRequest(aRequest)
|
||||
, mSignal(aSignal)
|
||||
{
|
||||
MOZ_ASSERT(aRequest->Headers()->Guard() == HeadersGuardEnum::Immutable ||
|
||||
aRequest->Headers()->Guard() == HeadersGuardEnum::Request ||
|
||||
aRequest->Headers()->Guard() == HeadersGuardEnum::Request_no_cors);
|
||||
SetMimeType();
|
||||
|
||||
// aSignal can be null.
|
||||
}
|
||||
|
||||
Request::~Request()
|
||||
|
|
@ -286,6 +289,8 @@ Request::Constructor(const GlobalObject& aGlobal,
|
|||
RefPtr<InternalRequest> request;
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
|
||||
RefPtr<AbortSignal> signal;
|
||||
|
||||
if (aInput.IsRequest()) {
|
||||
RefPtr<Request> inputReq = &aInput.GetAsRequest();
|
||||
|
|
@ -300,6 +305,7 @@ Request::Constructor(const GlobalObject& aGlobal,
|
|||
}
|
||||
|
||||
request = inputReq->GetInternalRequest();
|
||||
signal = inputReq->GetOrCreateSignal();
|
||||
} else {
|
||||
// aInput is USVString.
|
||||
// We need to get url before we create a InternalRequest.
|
||||
|
|
@ -418,6 +424,10 @@ Request::Constructor(const GlobalObject& aGlobal,
|
|||
request->SetReferrerPolicy(aInit.mReferrerPolicy.Value());
|
||||
}
|
||||
|
||||
if (aInit.mSignal.WasPassed()) {
|
||||
signal = aInit.mSignal.Value();
|
||||
}
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global);
|
||||
if (window) {
|
||||
|
|
@ -579,7 +589,7 @@ Request::Constructor(const GlobalObject& aGlobal,
|
|||
}
|
||||
}
|
||||
|
||||
RefPtr<Request> domRequest = new Request(global, request);
|
||||
RefPtr<Request> domRequest = new Request(global, request, signal);
|
||||
domRequest->SetMimeType();
|
||||
|
||||
if (aInput.IsRequest()) {
|
||||
|
|
@ -595,7 +605,7 @@ Request::Constructor(const GlobalObject& aGlobal,
|
|||
}
|
||||
|
||||
already_AddRefed<Request>
|
||||
Request::Clone(ErrorResult& aRv) const
|
||||
Request::Clone(ErrorResult& aRv)
|
||||
{
|
||||
if (BodyUsed()) {
|
||||
aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
|
||||
|
|
@ -608,7 +618,7 @@ Request::Clone(ErrorResult& aRv) const
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<Request> request = new Request(mOwner, ir);
|
||||
RefPtr<Request> request = new Request(mOwner, ir, GetOrCreateSignal());
|
||||
return request.forget();
|
||||
}
|
||||
|
||||
|
|
@ -622,5 +632,21 @@ Request::Headers_()
|
|||
return mHeaders;
|
||||
}
|
||||
|
||||
AbortSignal*
|
||||
Request::GetOrCreateSignal()
|
||||
{
|
||||
if (!mSignal) {
|
||||
mSignal = new AbortSignal(false);
|
||||
}
|
||||
|
||||
return mSignal;
|
||||
}
|
||||
|
||||
AbortSignal*
|
||||
Request::GetSignal() const
|
||||
{
|
||||
return mSignal;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class Request final : public nsISupports
|
|||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Request)
|
||||
|
||||
public:
|
||||
Request(nsIGlobalObject* aOwner, InternalRequest* aRequest);
|
||||
Request(nsIGlobalObject* aOwner, InternalRequest* aRequest, AbortSignal* aSignal);
|
||||
|
||||
static bool
|
||||
RequestContextEnabled(JSContext* aCx, JSObject* aObj);
|
||||
|
|
@ -142,7 +142,7 @@ public:
|
|||
}
|
||||
|
||||
already_AddRefed<Request>
|
||||
Clone(ErrorResult& aRv) const;
|
||||
Clone(ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<InternalRequest>
|
||||
GetInternalRequest();
|
||||
|
|
@ -153,13 +153,22 @@ public:
|
|||
return mRequest->GetPrincipalInfo();
|
||||
}
|
||||
|
||||
AbortSignal*
|
||||
GetOrCreateSignal();
|
||||
|
||||
// This can return a null AbortSignal.
|
||||
AbortSignal*
|
||||
GetSignal() const override;
|
||||
|
||||
private:
|
||||
~Request();
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> mOwner;
|
||||
RefPtr<InternalRequest> mRequest;
|
||||
|
||||
// Lazily created.
|
||||
RefPtr<Headers> mHeaders;
|
||||
RefPtr<AbortSignal> mSignal;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
|||
|
|
@ -34,10 +34,11 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Response)
|
|||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
Response::Response(nsIGlobalObject* aGlobal, InternalResponse* aInternalResponse)
|
||||
Response::Response(nsIGlobalObject* aGlobal, InternalResponse* aInternalResponse, AbortSignal* aSignal)
|
||||
: FetchBody<Response>()
|
||||
, mOwner(aGlobal)
|
||||
, mInternalResponse(aInternalResponse)
|
||||
, mSignal(aSignal)
|
||||
{
|
||||
MOZ_ASSERT(aInternalResponse->Headers()->Guard() == HeadersGuardEnum::Immutable ||
|
||||
aInternalResponse->Headers()->Guard() == HeadersGuardEnum::Response);
|
||||
|
|
@ -53,7 +54,7 @@ Response::Error(const GlobalObject& aGlobal)
|
|||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
RefPtr<InternalResponse> error = InternalResponse::NetworkError();
|
||||
RefPtr<Response> r = new Response(global, error);
|
||||
RefPtr<Response> r = new Response(global, error, nullptr);
|
||||
return r.forget();
|
||||
}
|
||||
|
||||
|
|
@ -173,7 +174,7 @@ Response::Constructor(const GlobalObject& aGlobal,
|
|||
internalResponse->InitChannelInfo(worker->GetChannelInfo());
|
||||
}
|
||||
|
||||
RefPtr<Response> r = new Response(global, internalResponse);
|
||||
RefPtr<Response> r = new Response(global, internalResponse, nullptr);
|
||||
|
||||
if (aInit.mHeaders.WasPassed()) {
|
||||
internalResponse->Headers()->Clear();
|
||||
|
|
@ -236,7 +237,7 @@ Response::Clone(ErrorResult& aRv) const
|
|||
}
|
||||
|
||||
RefPtr<InternalResponse> ir = mInternalResponse->Clone();
|
||||
RefPtr<Response> response = new Response(mOwner, ir);
|
||||
RefPtr<Response> response = new Response(mOwner, ir, mSignal);
|
||||
return response.forget();
|
||||
}
|
||||
|
||||
|
|
@ -250,7 +251,7 @@ Response::CloneUnfiltered(ErrorResult& aRv) const
|
|||
|
||||
RefPtr<InternalResponse> clone = mInternalResponse->Clone();
|
||||
RefPtr<InternalResponse> ir = clone->Unfiltered();
|
||||
RefPtr<Response> ref = new Response(mOwner, ir);
|
||||
RefPtr<Response> ref = new Response(mOwner, ir, mSignal);
|
||||
return ref.forget();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class Response final : public nsISupports
|
|||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Response)
|
||||
|
||||
public:
|
||||
Response(nsIGlobalObject* aGlobal, InternalResponse* aInternalResponse);
|
||||
Response(nsIGlobalObject* aGlobal, InternalResponse* aInternalResponse, AbortSignal* aSignal);
|
||||
|
||||
Response(const Response& aOther) = delete;
|
||||
|
||||
|
|
@ -134,13 +134,21 @@ public:
|
|||
already_AddRefed<InternalResponse>
|
||||
GetInternalResponse() const;
|
||||
|
||||
AbortSignal*
|
||||
GetSignal() const override
|
||||
{
|
||||
return mSignal;
|
||||
}
|
||||
|
||||
private:
|
||||
~Response();
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> mOwner;
|
||||
RefPtr<InternalResponse> mInternalResponse;
|
||||
|
||||
// Lazily created
|
||||
RefPtr<Headers> mHeaders;
|
||||
RefPtr<AbortSignal> mSignal;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ DIRS += [
|
|||
'base',
|
||||
'archivereader',
|
||||
'bindings',
|
||||
'battery',
|
||||
'browser-element',
|
||||
'cache',
|
||||
'canvas',
|
||||
|
|
|
|||
|
|
@ -432,30 +432,6 @@ QuotaManagerService::PerformIdleMaintenance()
|
|||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// If we're running on battery power then skip all idle maintenance since we
|
||||
// would otherwise be doing lots of disk I/O.
|
||||
BatteryInformation batteryInfo;
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
// Android XPCShell doesn't load the AndroidBridge that is needed to make
|
||||
// GetCurrentBatteryInformation work...
|
||||
if (!QuotaManager::IsRunningXPCShellTests())
|
||||
#endif
|
||||
{
|
||||
GetCurrentBatteryInformation(&batteryInfo);
|
||||
}
|
||||
|
||||
// If we're running XPCShell because we always want to be able to test this
|
||||
// code so pretend that we're always charging.
|
||||
if (QuotaManager::IsRunningXPCShellTests()) {
|
||||
batteryInfo.level() = 100;
|
||||
batteryInfo.charging() = true;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!batteryInfo.charging())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (QuotaManager::IsRunningXPCShellTests()) {
|
||||
// We don't want user activity to impact this code if we're running tests.
|
||||
Unused << Observe(nullptr, OBSERVER_TOPIC_IDLE, nullptr);
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* http://www.w3.org/TR/battery-status/
|
||||
*
|
||||
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
interface BatteryManager : EventTarget {
|
||||
readonly attribute boolean charging;
|
||||
readonly attribute unrestricted double chargingTime;
|
||||
readonly attribute unrestricted double dischargingTime;
|
||||
readonly attribute double level;
|
||||
|
||||
attribute EventHandler onchargingchange;
|
||||
attribute EventHandler onchargingtimechange;
|
||||
attribute EventHandler ondischargingtimechange;
|
||||
attribute EventHandler onlevelchange;
|
||||
};
|
||||
|
|
@ -7,7 +7,6 @@
|
|||
* http://www.whatwg.org/specs/web-apps/current-work/#the-navigator-object
|
||||
* http://www.w3.org/TR/tracking-dnt/
|
||||
* http://www.w3.org/TR/geolocation-API/#geolocation_interface
|
||||
* http://www.w3.org/TR/battery-status/#navigatorbattery-interface
|
||||
* http://www.w3.org/TR/vibration/#vibration-interface
|
||||
* http://www.w3.org/2012/sysapps/runtime/#extension-to-the-navigator-interface-1
|
||||
* https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#navigator-interface-extension
|
||||
|
|
@ -125,13 +124,6 @@ interface NavigatorGeolocation {
|
|||
};
|
||||
Navigator implements NavigatorGeolocation;
|
||||
|
||||
// http://www.w3.org/TR/battery-status/#navigatorbattery-interface
|
||||
partial interface Navigator {
|
||||
// ChromeOnly to prevent web content from fingerprinting users' batteries.
|
||||
[Throws, ChromeOnly, Pref="dom.battery.enabled"]
|
||||
Promise<BatteryManager> getBattery();
|
||||
};
|
||||
|
||||
// http://www.w3.org/TR/vibration/#vibration-interface
|
||||
partial interface Navigator {
|
||||
// We don't support sequences in unions yet
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@ interface Request {
|
|||
readonly attribute RequestRedirect redirect;
|
||||
readonly attribute DOMString integrity;
|
||||
|
||||
[Func="AbortController::IsEnabled",
|
||||
BinaryName="getOrCreateSignal"]
|
||||
readonly attribute AbortSignal signal;
|
||||
|
||||
[Throws,
|
||||
NewObject] Request clone();
|
||||
|
||||
|
|
@ -49,7 +53,7 @@ dictionary RequestInit {
|
|||
DOMString integrity;
|
||||
|
||||
[Func="AbortController::IsEnabled"]
|
||||
AbortSignal signal;
|
||||
AbortSignal? signal;
|
||||
|
||||
[Func="FetchObserver::IsEnabled"]
|
||||
ObserverCallback observe;
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ WEBIDL_FILES = [
|
|||
'AutocompleteInfo.webidl',
|
||||
'BarProp.webidl',
|
||||
'BaseKeyframeTypes.webidl',
|
||||
'BatteryManager.webidl',
|
||||
'BeforeAfterKeyboardEvent.webidl',
|
||||
'BeforeUnloadEvent.webidl',
|
||||
'BiquadFilterNode.webidl',
|
||||
|
|
|
|||
|
|
@ -694,7 +694,7 @@ private:
|
|||
ir->SetPrincipalInfo(Move(principalInfo));
|
||||
|
||||
RefPtr<mozilla::dom::Response> response =
|
||||
new mozilla::dom::Response(mCacheCreator->Global(), ir);
|
||||
new mozilla::dom::Response(mCacheCreator->Global(), ir, nullptr);
|
||||
|
||||
mozilla::dom::RequestOrUSVString request;
|
||||
|
||||
|
|
@ -1101,14 +1101,16 @@ private:
|
|||
rv = NS_GetFinalChannelURI(channel, getter_AddRefs(finalURI));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCString filename;
|
||||
rv = finalURI->GetSpec(filename);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (principal->Subsumes(channelPrincipal)) {
|
||||
nsCString filename;
|
||||
rv = finalURI->GetSpec(filename);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!filename.IsEmpty()) {
|
||||
// This will help callers figure out what their script url resolved to in
|
||||
// case of errors.
|
||||
aLoadInfo.mURL.Assign(NS_ConvertUTF8toUTF16(filename));
|
||||
if (!filename.IsEmpty()) {
|
||||
// This will help callers figure out what their script url resolved to in
|
||||
// case of errors.
|
||||
aLoadInfo.mURL.Assign(NS_ConvertUTF8toUTF16(filename));
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILoadInfo> chanLoadInfo = channel->GetLoadInfo();
|
||||
|
|
|
|||
|
|
@ -1510,7 +1510,7 @@ private:
|
|||
if (NS_WARN_IF(!global)) {
|
||||
return false;
|
||||
}
|
||||
RefPtr<Request> request = new Request(global, internalReq);
|
||||
RefPtr<Request> request = new Request(global, internalReq, nullptr);
|
||||
|
||||
MOZ_ASSERT_IF(internalReq->IsNavigationRequest(),
|
||||
request->Redirect() == RequestRedirect::Manual);
|
||||
|
|
|
|||
|
|
@ -554,7 +554,7 @@ private:
|
|||
ir->SetPrincipalInfo(Move(mPrincipalInfo));
|
||||
}
|
||||
|
||||
RefPtr<Response> response = new Response(aCache->GetGlobalObject(), ir);
|
||||
RefPtr<Response> response = new Response(aCache->GetGlobalObject(), ir, nullptr);
|
||||
|
||||
RequestOrUSVString request;
|
||||
request.SetAsUSVString().Rebind(URL().Data(), URL().Length());
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
en_US-mozilla Hunspell Dictionary
|
||||
Generated from SCOWL Version 2017.01.22
|
||||
Tue Jan 24 22:59:28 EST 2017
|
||||
Generated from SCOWL Version 2019.10.06
|
||||
Fri Feb 7 12:44:15 EST 2020
|
||||
|
||||
http://wordlist.sourceforge.net
|
||||
|
||||
|
|
@ -95,10 +95,10 @@ released as part of Geoff Kuenning's Ispell and as such is covered by
|
|||
his BSD license. Part of SCOWL is also based on Ispell thus the
|
||||
Ispell copyright is included with the SCOWL copyright.
|
||||
|
||||
The collective work is Copyright 2000-2016 by Kevin Atkinson as well
|
||||
The collective work is Copyright 2000-2018 by Kevin Atkinson as well
|
||||
as any of the copyrights mentioned below:
|
||||
|
||||
Copyright 2000-2016 by Kevin Atkinson
|
||||
Copyright 2000-2018 by Kevin Atkinson
|
||||
|
||||
Permission to use, copy, modify, distribute and sell these word
|
||||
lists, the associated scripts, the output created from the scripts,
|
||||
|
|
@ -344,4 +344,4 @@ and Australian word list. It is under the following copyright:
|
|||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
Build Date: Tue Jan 24 22:59:28 EST 2017
|
||||
Build Date: Fri Feb 7 12:44:15 EST 2020
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
|||
en_US-custom Hunspell Dictionary
|
||||
Generated from SCOWL Version 2017.01.22
|
||||
Tue Jan 24 22:59:27 EST 2017
|
||||
Generated from SCOWL Version 2019.10.06
|
||||
Fri Feb 7 12:44:14 EST 2020
|
||||
|
||||
http://wordlist.sourceforge.net
|
||||
|
||||
|
|
@ -95,10 +95,10 @@ released as part of Geoff Kuenning's Ispell and as such is covered by
|
|||
his BSD license. Part of SCOWL is also based on Ispell thus the
|
||||
Ispell copyright is included with the SCOWL copyright.
|
||||
|
||||
The collective work is Copyright 2000-2016 by Kevin Atkinson as well
|
||||
The collective work is Copyright 2000-2018 by Kevin Atkinson as well
|
||||
as any of the copyrights mentioned below:
|
||||
|
||||
Copyright 2000-2016 by Kevin Atkinson
|
||||
Copyright 2000-2018 by Kevin Atkinson
|
||||
|
||||
Permission to use, copy, modify, distribute and sell these word
|
||||
lists, the associated scripts, the output created from the scripts,
|
||||
|
|
@ -344,5 +344,5 @@ and Australian word list. It is under the following copyright:
|
|||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
Build Date: Tue Jan 24 22:59:27 EST 2017
|
||||
Build Date: Fri Feb 7 12:44:14 EST 2020
|
||||
With Input Command: ../mk-list -v1 --accents=both en_US 60
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -14,6 +14,7 @@
|
|||
#include "FilterNodeD2D1.h"
|
||||
#include "ExtendInputEffectD2D1.h"
|
||||
#include "Tools.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
|
@ -1177,7 +1178,7 @@ DrawTargetD2D1::GetDWriteFactory()
|
|||
}
|
||||
|
||||
decltype(DWriteCreateFactory)* createDWriteFactory;
|
||||
HMODULE dwriteModule = LoadLibraryW(L"dwrite.dll");
|
||||
HMODULE dwriteModule = LoadLibrarySystem32(L"dwrite.dll");
|
||||
createDWriteFactory = (decltype(DWriteCreateFactory)*)
|
||||
GetProcAddress(dwriteModule, "DWriteCreateFactory");
|
||||
|
||||
|
|
|
|||
53
hal/Hal.cpp
53
hal/Hal.cpp
|
|
@ -264,30 +264,6 @@ private:
|
|||
bool mHasValidCache;
|
||||
};
|
||||
|
||||
class BatteryObserversManager : public CachingObserversManager<BatteryInformation>
|
||||
{
|
||||
protected:
|
||||
void EnableNotifications() {
|
||||
PROXY_IF_SANDBOXED(EnableBatteryNotifications());
|
||||
}
|
||||
|
||||
void DisableNotifications() {
|
||||
PROXY_IF_SANDBOXED(DisableBatteryNotifications());
|
||||
}
|
||||
|
||||
void GetCurrentInformationInternal(BatteryInformation* aInfo) {
|
||||
PROXY_IF_SANDBOXED(GetCurrentBatteryInformation(aInfo));
|
||||
}
|
||||
};
|
||||
|
||||
static BatteryObserversManager&
|
||||
BatteryObservers()
|
||||
{
|
||||
static BatteryObserversManager sBatteryObservers;
|
||||
AssertMainThread();
|
||||
return sBatteryObservers;
|
||||
}
|
||||
|
||||
class NetworkObserversManager : public CachingObserversManager<NetworkInformation>
|
||||
{
|
||||
protected:
|
||||
|
|
@ -356,35 +332,6 @@ ScreenConfigurationObservers()
|
|||
return sScreenConfigurationObservers;
|
||||
}
|
||||
|
||||
void
|
||||
RegisterBatteryObserver(BatteryObserver* aObserver)
|
||||
{
|
||||
AssertMainThread();
|
||||
BatteryObservers().AddObserver(aObserver);
|
||||
}
|
||||
|
||||
void
|
||||
UnregisterBatteryObserver(BatteryObserver* aObserver)
|
||||
{
|
||||
AssertMainThread();
|
||||
BatteryObservers().RemoveObserver(aObserver);
|
||||
}
|
||||
|
||||
void
|
||||
GetCurrentBatteryInformation(BatteryInformation* aInfo)
|
||||
{
|
||||
AssertMainThread();
|
||||
*aInfo = BatteryObservers().GetCurrentInformation();
|
||||
}
|
||||
|
||||
void
|
||||
NotifyBatteryChange(const BatteryInformation& aInfo)
|
||||
{
|
||||
AssertMainThread();
|
||||
BatteryObservers().CacheInformation(aInfo);
|
||||
BatteryObservers().BroadcastCachedInformation();
|
||||
}
|
||||
|
||||
bool GetScreenEnabled()
|
||||
{
|
||||
AssertMainThread();
|
||||
|
|
|
|||
24
hal/Hal.h
24
hal/Hal.h
|
|
@ -10,7 +10,6 @@
|
|||
#include "base/basictypes.h"
|
||||
#include "base/platform_thread.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/dom/battery/Types.h"
|
||||
#include "mozilla/dom/MozPowerManagerBinding.h"
|
||||
#include "mozilla/dom/network/Types.h"
|
||||
#include "mozilla/dom/power/Types.h"
|
||||
|
|
@ -87,29 +86,6 @@ void Vibrate(const nsTArray<uint32_t>& pattern,
|
|||
void CancelVibrate(nsPIDOMWindowInner* aWindow);
|
||||
void CancelVibrate(const hal::WindowIdentifier &id);
|
||||
|
||||
/**
|
||||
* Inform the battery backend there is a new battery observer.
|
||||
* @param aBatteryObserver The observer that should be added.
|
||||
*/
|
||||
void RegisterBatteryObserver(BatteryObserver* aBatteryObserver);
|
||||
|
||||
/**
|
||||
* Inform the battery backend a battery observer unregistered.
|
||||
* @param aBatteryObserver The observer that should be removed.
|
||||
*/
|
||||
void UnregisterBatteryObserver(BatteryObserver* aBatteryObserver);
|
||||
|
||||
/**
|
||||
* Returns the current battery information.
|
||||
*/
|
||||
void GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo);
|
||||
|
||||
/**
|
||||
* Notify of a change in the battery state.
|
||||
* @param aBatteryInfo The new battery information.
|
||||
*/
|
||||
void NotifyBatteryChange(const hal::BatteryInformation& aBatteryInfo);
|
||||
|
||||
/**
|
||||
* Determine whether the device's screen is currently enabled.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,325 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim set: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : */
|
||||
/* 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 <CoreFoundation/CoreFoundation.h>
|
||||
#import <IOKit/ps/IOPowerSources.h>
|
||||
#import <IOKit/ps/IOPSKeys.h>
|
||||
|
||||
#include <mozilla/Hal.h>
|
||||
#include <mozilla/dom/battery/Constants.h>
|
||||
#include <mozilla/Services.h>
|
||||
|
||||
#include <nsIObserverService.h>
|
||||
#include <nsIObserver.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#define IOKIT_FRAMEWORK_PATH "/System/Library/Frameworks/IOKit.framework/IOKit"
|
||||
|
||||
#ifndef kIOPSTimeRemainingUnknown
|
||||
#define kIOPSTimeRemainingUnknown ((CFTimeInterval)-1.0)
|
||||
#endif
|
||||
#ifndef kIOPSTimeRemainingUnlimited
|
||||
#define kIOPSTimeRemainingUnlimited ((CFTimeInterval)-2.0)
|
||||
#endif
|
||||
|
||||
using namespace mozilla::dom::battery;
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
typedef CFTimeInterval (*IOPSGetTimeRemainingEstimateFunc)(void);
|
||||
|
||||
class MacPowerInformationService
|
||||
{
|
||||
public:
|
||||
static MacPowerInformationService* GetInstance();
|
||||
static void Shutdown();
|
||||
static bool IsShuttingDown();
|
||||
|
||||
void BeginListening();
|
||||
void StopListening();
|
||||
|
||||
static void HandleChange(void *aContext);
|
||||
|
||||
~MacPowerInformationService();
|
||||
|
||||
private:
|
||||
MacPowerInformationService();
|
||||
|
||||
// The reference to the runloop that is notified of power changes.
|
||||
CFRunLoopSourceRef mRunLoopSource;
|
||||
|
||||
double mLevel;
|
||||
bool mCharging;
|
||||
double mRemainingTime;
|
||||
bool mShouldNotify;
|
||||
|
||||
friend void GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo);
|
||||
|
||||
static MacPowerInformationService* sInstance;
|
||||
static bool sShuttingDown;
|
||||
|
||||
static void* sIOKitFramework;
|
||||
static IOPSGetTimeRemainingEstimateFunc sIOPSGetTimeRemainingEstimate;
|
||||
};
|
||||
|
||||
void* MacPowerInformationService::sIOKitFramework;
|
||||
IOPSGetTimeRemainingEstimateFunc MacPowerInformationService::sIOPSGetTimeRemainingEstimate;
|
||||
|
||||
/*
|
||||
* Implementation of mozilla::hal_impl::EnableBatteryNotifications,
|
||||
* mozilla::hal_impl::DisableBatteryNotifications,
|
||||
* and mozilla::hal_impl::GetCurrentBatteryInformation.
|
||||
*/
|
||||
|
||||
void
|
||||
EnableBatteryNotifications()
|
||||
{
|
||||
if (!MacPowerInformationService::IsShuttingDown()) {
|
||||
MacPowerInformationService::GetInstance()->BeginListening();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DisableBatteryNotifications()
|
||||
{
|
||||
if (!MacPowerInformationService::IsShuttingDown()) {
|
||||
MacPowerInformationService::GetInstance()->StopListening();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
|
||||
{
|
||||
MacPowerInformationService* powerService = MacPowerInformationService::GetInstance();
|
||||
|
||||
aBatteryInfo->level() = powerService->mLevel;
|
||||
aBatteryInfo->charging() = powerService->mCharging;
|
||||
aBatteryInfo->remainingTime() = powerService->mRemainingTime;
|
||||
}
|
||||
|
||||
bool MacPowerInformationService::sShuttingDown = false;
|
||||
|
||||
/*
|
||||
* Following is the implementation of MacPowerInformationService.
|
||||
*/
|
||||
|
||||
MacPowerInformationService* MacPowerInformationService::sInstance = nullptr;
|
||||
|
||||
namespace {
|
||||
struct SingletonDestroyer final : public nsIObserver
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
private:
|
||||
~SingletonDestroyer() {}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(SingletonDestroyer, nsIObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
SingletonDestroyer::Observe(nsISupports*, const char* aTopic, const char16_t*)
|
||||
{
|
||||
MOZ_ASSERT(!strcmp(aTopic, "xpcom-shutdown"));
|
||||
MacPowerInformationService::Shutdown();
|
||||
return NS_OK;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
/* static */ MacPowerInformationService*
|
||||
MacPowerInformationService::GetInstance()
|
||||
{
|
||||
if (sInstance) {
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
sInstance = new MacPowerInformationService();
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->AddObserver(new SingletonDestroyer(), "xpcom-shutdown", false);
|
||||
}
|
||||
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
bool
|
||||
MacPowerInformationService::IsShuttingDown()
|
||||
{
|
||||
return sShuttingDown;
|
||||
}
|
||||
|
||||
void
|
||||
MacPowerInformationService::Shutdown()
|
||||
{
|
||||
sShuttingDown = true;
|
||||
delete sInstance;
|
||||
sInstance = nullptr;
|
||||
}
|
||||
|
||||
MacPowerInformationService::MacPowerInformationService()
|
||||
: mRunLoopSource(nullptr)
|
||||
, mLevel(kDefaultLevel)
|
||||
, mCharging(kDefaultCharging)
|
||||
, mRemainingTime(kDefaultRemainingTime)
|
||||
, mShouldNotify(false)
|
||||
{
|
||||
// IOPSGetTimeRemainingEstimate (and the related constants) are only available
|
||||
// on 10.7, so we test for their presence at runtime.
|
||||
sIOKitFramework = dlopen(IOKIT_FRAMEWORK_PATH, RTLD_LAZY | RTLD_LOCAL);
|
||||
if (sIOKitFramework) {
|
||||
sIOPSGetTimeRemainingEstimate =
|
||||
(IOPSGetTimeRemainingEstimateFunc)dlsym(sIOKitFramework, "IOPSGetTimeRemainingEstimate");
|
||||
} else {
|
||||
sIOPSGetTimeRemainingEstimate = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
MacPowerInformationService::~MacPowerInformationService()
|
||||
{
|
||||
MOZ_ASSERT(!mRunLoopSource,
|
||||
"The observers have not been correctly removed! "
|
||||
"(StopListening should have been called)");
|
||||
|
||||
if (sIOKitFramework) {
|
||||
dlclose(sIOKitFramework);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacPowerInformationService::BeginListening()
|
||||
{
|
||||
// Set ourselves up to be notified about changes.
|
||||
MOZ_ASSERT(!mRunLoopSource, "IOPS Notification Loop Source already set up. "
|
||||
"(StopListening should have been called)");
|
||||
|
||||
mRunLoopSource = ::IOPSNotificationCreateRunLoopSource(HandleChange, this);
|
||||
if (mRunLoopSource) {
|
||||
::CFRunLoopAddSource(::CFRunLoopGetCurrent(), mRunLoopSource,
|
||||
kCFRunLoopDefaultMode);
|
||||
|
||||
// Invoke our callback now so we have data if GetCurrentBatteryInformation is
|
||||
// called before a change happens.
|
||||
HandleChange(this);
|
||||
mShouldNotify = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacPowerInformationService::StopListening()
|
||||
{
|
||||
MOZ_ASSERT(mRunLoopSource, "IOPS Notification Loop Source not set up. "
|
||||
"(StopListening without BeginListening)");
|
||||
|
||||
::CFRunLoopRemoveSource(::CFRunLoopGetCurrent(), mRunLoopSource,
|
||||
kCFRunLoopDefaultMode);
|
||||
mRunLoopSource = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
MacPowerInformationService::HandleChange(void* aContext) {
|
||||
MacPowerInformationService* power =
|
||||
static_cast<MacPowerInformationService*>(aContext);
|
||||
|
||||
CFTypeRef data = ::IOPSCopyPowerSourcesInfo();
|
||||
if (!data) {
|
||||
::CFRelease(data);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the list of power sources.
|
||||
CFArrayRef list = ::IOPSCopyPowerSourcesList(data);
|
||||
if (!list) {
|
||||
::CFRelease(list);
|
||||
return;
|
||||
}
|
||||
|
||||
// Default values. These will be used if there are 0 sources or we can't find
|
||||
// better information.
|
||||
double level = kDefaultLevel;
|
||||
double charging = kDefaultCharging;
|
||||
double remainingTime = kDefaultRemainingTime;
|
||||
|
||||
// Look for the first battery power source to give us the information we need.
|
||||
// Usually there's only 1 available, depending on current power source.
|
||||
for (CFIndex i = 0; i < ::CFArrayGetCount(list); ++i) {
|
||||
CFTypeRef source = ::CFArrayGetValueAtIndex(list, i);
|
||||
CFDictionaryRef currPowerSourceDesc = ::IOPSGetPowerSourceDescription(data, source);
|
||||
if (!currPowerSourceDesc) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get a battery level estimate. This key is required.
|
||||
int currentCapacity = 0;
|
||||
const void* cfRef = ::CFDictionaryGetValue(currPowerSourceDesc, CFSTR(kIOPSCurrentCapacityKey));
|
||||
::CFNumberGetValue((CFNumberRef)cfRef, kCFNumberSInt32Type, ¤tCapacity);
|
||||
|
||||
// This key is also required.
|
||||
int maxCapacity = 0;
|
||||
cfRef = ::CFDictionaryGetValue(currPowerSourceDesc, CFSTR(kIOPSMaxCapacityKey));
|
||||
::CFNumberGetValue((CFNumberRef)cfRef, kCFNumberSInt32Type, &maxCapacity);
|
||||
|
||||
if (maxCapacity > 0) {
|
||||
level = static_cast<double>(currentCapacity)/static_cast<double>(maxCapacity);
|
||||
}
|
||||
|
||||
// Find out if we're charging.
|
||||
// This key is optional, we fallback to kDefaultCharging if the current power
|
||||
// source doesn't have that info.
|
||||
if(::CFDictionaryGetValueIfPresent(currPowerSourceDesc, CFSTR(kIOPSIsChargingKey), &cfRef)) {
|
||||
charging = ::CFBooleanGetValue((CFBooleanRef)cfRef);
|
||||
|
||||
// Get an estimate of how long it's going to take until we're fully charged.
|
||||
// This key is optional.
|
||||
if (charging) {
|
||||
// Default value that will be changed if we happen to find the actual
|
||||
// remaining time.
|
||||
remainingTime = level == 1.0 ? kDefaultRemainingTime : kUnknownRemainingTime;
|
||||
|
||||
if (::CFDictionaryGetValueIfPresent(currPowerSourceDesc,
|
||||
CFSTR(kIOPSTimeToFullChargeKey), &cfRef)) {
|
||||
int timeToCharge;
|
||||
::CFNumberGetValue((CFNumberRef)cfRef, kCFNumberIntType, &timeToCharge);
|
||||
if (timeToCharge != kIOPSTimeRemainingUnknown) {
|
||||
remainingTime = timeToCharge*60;
|
||||
}
|
||||
}
|
||||
} else if (sIOPSGetTimeRemainingEstimate) { // not charging
|
||||
// See if we can get a time estimate.
|
||||
CFTimeInterval estimate = sIOPSGetTimeRemainingEstimate();
|
||||
if (estimate == kIOPSTimeRemainingUnlimited || estimate == kIOPSTimeRemainingUnknown) {
|
||||
remainingTime = kUnknownRemainingTime;
|
||||
} else {
|
||||
remainingTime = estimate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
bool isNewData = level != power->mLevel || charging != power->mCharging ||
|
||||
remainingTime != power->mRemainingTime;
|
||||
|
||||
power->mRemainingTime = remainingTime;
|
||||
power->mCharging = charging;
|
||||
power->mLevel = level;
|
||||
|
||||
// Notify the observers if stuff changed.
|
||||
if (power->mShouldNotify && isNewData) {
|
||||
hal::NotifyBatteryChange(hal::BatteryInformation(power->mLevel,
|
||||
power->mCharging,
|
||||
power->mRemainingTime));
|
||||
}
|
||||
|
||||
::CFRelease(data);
|
||||
::CFRelease(list);
|
||||
}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||
/* 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/. */
|
||||
|
||||
#include "Hal.h"
|
||||
#include "mozilla/dom/battery/Constants.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
void
|
||||
EnableBatteryNotifications()
|
||||
{}
|
||||
|
||||
void
|
||||
DisableBatteryNotifications()
|
||||
{}
|
||||
|
||||
void
|
||||
GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
|
||||
{
|
||||
aBatteryInfo->level() = dom::battery::kDefaultLevel;
|
||||
aBatteryInfo->charging() = dom::battery::kDefaultCharging;
|
||||
aBatteryInfo->remainingTime() = dom::battery::kDefaultRemainingTime;
|
||||
}
|
||||
|
||||
} // hal_impl
|
||||
} // namespace mozilla
|
||||
|
|
@ -1,508 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#include "Hal.h"
|
||||
#include "HalLog.h"
|
||||
#include <dbus/dbus-glib.h>
|
||||
#include <dbus/dbus-glib-lowlevel.h>
|
||||
#include <mozilla/Attributes.h>
|
||||
#include <mozilla/dom/battery/Constants.h>
|
||||
#include "nsAutoRef.h"
|
||||
#include <cmath>
|
||||
|
||||
/*
|
||||
* Helper that manages the destruction of glib objects as soon as they leave
|
||||
* the current scope.
|
||||
*
|
||||
* We are specializing nsAutoRef class.
|
||||
*/
|
||||
|
||||
template <>
|
||||
class nsAutoRefTraits<GHashTable> : public nsPointerRefTraits<GHashTable>
|
||||
{
|
||||
public:
|
||||
static void Release(GHashTable* ptr) { g_hash_table_unref(ptr); }
|
||||
};
|
||||
|
||||
using namespace mozilla::dom::battery;
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
/**
|
||||
* This is the declaration of UPowerClient class. This class is listening and
|
||||
* communicating to upower daemon through DBus.
|
||||
* There is no header file because this class shouldn't be public.
|
||||
*/
|
||||
class UPowerClient
|
||||
{
|
||||
public:
|
||||
static UPowerClient* GetInstance();
|
||||
|
||||
void BeginListening();
|
||||
void StopListening();
|
||||
|
||||
double GetLevel();
|
||||
bool IsCharging();
|
||||
double GetRemainingTime();
|
||||
|
||||
~UPowerClient();
|
||||
|
||||
private:
|
||||
UPowerClient();
|
||||
|
||||
enum States {
|
||||
eState_Unknown = 0,
|
||||
eState_Charging,
|
||||
eState_Discharging,
|
||||
eState_Empty,
|
||||
eState_FullyCharged,
|
||||
eState_PendingCharge,
|
||||
eState_PendingDischarge
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the currently tracked device.
|
||||
* @return whether everything went ok.
|
||||
*/
|
||||
void UpdateTrackedDeviceSync();
|
||||
|
||||
/**
|
||||
* Returns a hash table with the properties of aDevice.
|
||||
* Note: the caller has to unref the hash table.
|
||||
*/
|
||||
GHashTable* GetDevicePropertiesSync(DBusGProxy* aProxy);
|
||||
void GetDevicePropertiesAsync(DBusGProxy* aProxy);
|
||||
static void GetDevicePropertiesCallback(DBusGProxy* aProxy,
|
||||
DBusGProxyCall* aCall,
|
||||
void* aData);
|
||||
|
||||
/**
|
||||
* Using the device properties (aHashTable), this method updates the member
|
||||
* variable storing the values we care about.
|
||||
*/
|
||||
void UpdateSavedInfo(GHashTable* aHashTable);
|
||||
|
||||
/**
|
||||
* Callback used by 'DeviceChanged' signal.
|
||||
*/
|
||||
static void DeviceChanged(DBusGProxy* aProxy, const gchar* aObjectPath,
|
||||
UPowerClient* aListener);
|
||||
|
||||
/**
|
||||
* Callback used by 'PropertiesChanged' signal.
|
||||
* This method is called when the the battery level changes.
|
||||
* (Only with upower >= 0.99)
|
||||
*/
|
||||
static void PropertiesChanged(DBusGProxy* aProxy, const gchar*,
|
||||
GHashTable*, char**,
|
||||
UPowerClient* aListener);
|
||||
|
||||
/**
|
||||
* Callback called when mDBusConnection gets a signal.
|
||||
*/
|
||||
static DBusHandlerResult ConnectionSignalFilter(DBusConnection* aConnection,
|
||||
DBusMessage* aMessage,
|
||||
void* aData);
|
||||
|
||||
// The DBus connection object.
|
||||
DBusGConnection* mDBusConnection;
|
||||
|
||||
// The DBus proxy object to upower.
|
||||
DBusGProxy* mUPowerProxy;
|
||||
|
||||
// The path of the tracked device.
|
||||
gchar* mTrackedDevice;
|
||||
|
||||
// The DBusGProxy for the tracked device.
|
||||
DBusGProxy* mTrackedDeviceProxy;
|
||||
|
||||
double mLevel;
|
||||
bool mCharging;
|
||||
double mRemainingTime;
|
||||
|
||||
static UPowerClient* sInstance;
|
||||
|
||||
static const guint sDeviceTypeBattery = 2;
|
||||
static const guint64 kUPowerUnknownRemainingTime = 0;
|
||||
};
|
||||
|
||||
/*
|
||||
* Implementation of mozilla::hal_impl::EnableBatteryNotifications,
|
||||
* mozilla::hal_impl::DisableBatteryNotifications,
|
||||
* and mozilla::hal_impl::GetCurrentBatteryInformation.
|
||||
*/
|
||||
|
||||
void
|
||||
EnableBatteryNotifications()
|
||||
{
|
||||
UPowerClient::GetInstance()->BeginListening();
|
||||
}
|
||||
|
||||
void
|
||||
DisableBatteryNotifications()
|
||||
{
|
||||
UPowerClient::GetInstance()->StopListening();
|
||||
}
|
||||
|
||||
void
|
||||
GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
|
||||
{
|
||||
UPowerClient* upowerClient = UPowerClient::GetInstance();
|
||||
|
||||
aBatteryInfo->level() = upowerClient->GetLevel();
|
||||
aBatteryInfo->charging() = upowerClient->IsCharging();
|
||||
aBatteryInfo->remainingTime() = upowerClient->GetRemainingTime();
|
||||
}
|
||||
|
||||
/*
|
||||
* Following is the implementation of UPowerClient.
|
||||
*/
|
||||
|
||||
UPowerClient* UPowerClient::sInstance = nullptr;
|
||||
|
||||
/* static */ UPowerClient*
|
||||
UPowerClient::GetInstance()
|
||||
{
|
||||
if (!sInstance) {
|
||||
sInstance = new UPowerClient();
|
||||
}
|
||||
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
UPowerClient::UPowerClient()
|
||||
: mDBusConnection(nullptr)
|
||||
, mUPowerProxy(nullptr)
|
||||
, mTrackedDevice(nullptr)
|
||||
, mTrackedDeviceProxy(nullptr)
|
||||
, mLevel(kDefaultLevel)
|
||||
, mCharging(kDefaultCharging)
|
||||
, mRemainingTime(kDefaultRemainingTime)
|
||||
{
|
||||
}
|
||||
|
||||
UPowerClient::~UPowerClient()
|
||||
{
|
||||
NS_ASSERTION(!mDBusConnection && !mUPowerProxy && !mTrackedDevice && !mTrackedDeviceProxy,
|
||||
"The observers have not been correctly removed! "
|
||||
"(StopListening should have been called)");
|
||||
}
|
||||
|
||||
void
|
||||
UPowerClient::BeginListening()
|
||||
{
|
||||
GError* error = nullptr;
|
||||
mDBusConnection = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
|
||||
|
||||
if (!mDBusConnection) {
|
||||
HAL_LOG("Failed to open connection to bus: %s\n", error->message);
|
||||
g_error_free(error);
|
||||
return;
|
||||
}
|
||||
|
||||
DBusConnection* dbusConnection =
|
||||
dbus_g_connection_get_connection(mDBusConnection);
|
||||
|
||||
// Make sure we do not exit the entire program if DBus connection get lost.
|
||||
dbus_connection_set_exit_on_disconnect(dbusConnection, false);
|
||||
|
||||
// Listening to signals the DBus connection is going to get so we will know
|
||||
// when it is lost and we will be able to disconnect cleanly.
|
||||
dbus_connection_add_filter(dbusConnection, ConnectionSignalFilter, this,
|
||||
nullptr);
|
||||
|
||||
mUPowerProxy = dbus_g_proxy_new_for_name(mDBusConnection,
|
||||
"org.freedesktop.UPower",
|
||||
"/org/freedesktop/UPower",
|
||||
"org.freedesktop.UPower");
|
||||
|
||||
UpdateTrackedDeviceSync();
|
||||
|
||||
/*
|
||||
* TODO: we should probably listen to DeviceAdded and DeviceRemoved signals.
|
||||
* If we do that, we would have to disconnect from those in StopListening.
|
||||
* It's not yet implemented because it requires testing hot plugging and
|
||||
* removal of a battery.
|
||||
*/
|
||||
dbus_g_proxy_add_signal(mUPowerProxy, "DeviceChanged", G_TYPE_STRING,
|
||||
G_TYPE_INVALID);
|
||||
dbus_g_proxy_connect_signal(mUPowerProxy, "DeviceChanged",
|
||||
G_CALLBACK (DeviceChanged), this, nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
UPowerClient::StopListening()
|
||||
{
|
||||
// If mDBusConnection isn't initialized, that means we are not really listening.
|
||||
if (!mDBusConnection) {
|
||||
return;
|
||||
}
|
||||
|
||||
dbus_connection_remove_filter(
|
||||
dbus_g_connection_get_connection(mDBusConnection),
|
||||
ConnectionSignalFilter, this);
|
||||
|
||||
dbus_g_proxy_disconnect_signal(mUPowerProxy, "DeviceChanged",
|
||||
G_CALLBACK (DeviceChanged), this);
|
||||
|
||||
g_free(mTrackedDevice);
|
||||
mTrackedDevice = nullptr;
|
||||
|
||||
if (mTrackedDeviceProxy) {
|
||||
dbus_g_proxy_disconnect_signal(mTrackedDeviceProxy, "PropertiesChanged",
|
||||
G_CALLBACK (PropertiesChanged), this);
|
||||
|
||||
g_object_unref(mTrackedDeviceProxy);
|
||||
mTrackedDeviceProxy = nullptr;
|
||||
}
|
||||
|
||||
g_object_unref(mUPowerProxy);
|
||||
mUPowerProxy = nullptr;
|
||||
|
||||
dbus_g_connection_unref(mDBusConnection);
|
||||
mDBusConnection = nullptr;
|
||||
|
||||
// We should now show the default values, not the latest we got.
|
||||
mLevel = kDefaultLevel;
|
||||
mCharging = kDefaultCharging;
|
||||
mRemainingTime = kDefaultRemainingTime;
|
||||
}
|
||||
|
||||
void
|
||||
UPowerClient::UpdateTrackedDeviceSync()
|
||||
{
|
||||
GType typeGPtrArray = dbus_g_type_get_collection("GPtrArray",
|
||||
DBUS_TYPE_G_OBJECT_PATH);
|
||||
GPtrArray* devices = nullptr;
|
||||
GError* error = nullptr;
|
||||
|
||||
// Reset the current tracked device:
|
||||
g_free(mTrackedDevice);
|
||||
mTrackedDevice = nullptr;
|
||||
|
||||
// Reset the current tracked device proxy:
|
||||
if (mTrackedDeviceProxy) {
|
||||
dbus_g_proxy_disconnect_signal(mTrackedDeviceProxy, "PropertiesChanged",
|
||||
G_CALLBACK (PropertiesChanged), this);
|
||||
|
||||
g_object_unref(mTrackedDeviceProxy);
|
||||
mTrackedDeviceProxy = nullptr;
|
||||
}
|
||||
|
||||
// If that fails, that likely means upower isn't installed.
|
||||
if (!dbus_g_proxy_call(mUPowerProxy, "EnumerateDevices", &error, G_TYPE_INVALID,
|
||||
typeGPtrArray, &devices, G_TYPE_INVALID)) {
|
||||
HAL_LOG("Error: %s\n", error->message);
|
||||
g_error_free(error);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We are looking for the first device that is a battery.
|
||||
* TODO: we could try to combine more than one battery.
|
||||
*/
|
||||
for (guint i=0; i<devices->len; ++i) {
|
||||
gchar* devicePath = static_cast<gchar*>(g_ptr_array_index(devices, i));
|
||||
|
||||
DBusGProxy* proxy = dbus_g_proxy_new_from_proxy(mUPowerProxy,
|
||||
"org.freedesktop.DBus.Properties",
|
||||
devicePath);
|
||||
|
||||
nsAutoRef<GHashTable> hashTable(GetDevicePropertiesSync(proxy));
|
||||
|
||||
if (g_value_get_uint(static_cast<const GValue*>(g_hash_table_lookup(hashTable, "Type"))) == sDeviceTypeBattery) {
|
||||
UpdateSavedInfo(hashTable);
|
||||
mTrackedDevice = devicePath;
|
||||
mTrackedDeviceProxy = proxy;
|
||||
break;
|
||||
}
|
||||
|
||||
g_object_unref(proxy);
|
||||
g_free(devicePath);
|
||||
}
|
||||
|
||||
if (mTrackedDeviceProxy) {
|
||||
dbus_g_proxy_add_signal(mTrackedDeviceProxy, "PropertiesChanged",
|
||||
G_TYPE_STRING,
|
||||
dbus_g_type_get_map("GHashTable", G_TYPE_STRING,
|
||||
G_TYPE_VALUE),
|
||||
G_TYPE_STRV, G_TYPE_INVALID);
|
||||
dbus_g_proxy_connect_signal(mTrackedDeviceProxy, "PropertiesChanged",
|
||||
G_CALLBACK (PropertiesChanged), this, nullptr);
|
||||
}
|
||||
|
||||
g_ptr_array_free(devices, true);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
UPowerClient::DeviceChanged(DBusGProxy* aProxy, const gchar* aObjectPath,
|
||||
UPowerClient* aListener)
|
||||
{
|
||||
if (!aListener->mTrackedDevice) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if GLIB_MAJOR_VERSION >= 2 && GLIB_MINOR_VERSION >= 16
|
||||
if (g_strcmp0(aObjectPath, aListener->mTrackedDevice)) {
|
||||
#else
|
||||
if (g_ascii_strcasecmp(aObjectPath, aListener->mTrackedDevice)) {
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
aListener->GetDevicePropertiesAsync(aListener->mTrackedDeviceProxy);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
UPowerClient::PropertiesChanged(DBusGProxy* aProxy, const gchar*, GHashTable*,
|
||||
char**, UPowerClient* aListener)
|
||||
{
|
||||
aListener->GetDevicePropertiesAsync(aListener->mTrackedDeviceProxy);
|
||||
}
|
||||
|
||||
/* static */ DBusHandlerResult
|
||||
UPowerClient::ConnectionSignalFilter(DBusConnection* aConnection,
|
||||
DBusMessage* aMessage, void* aData)
|
||||
{
|
||||
if (dbus_message_is_signal(aMessage, DBUS_INTERFACE_LOCAL, "Disconnected")) {
|
||||
static_cast<UPowerClient*>(aData)->StopListening();
|
||||
// We do not return DBUS_HANDLER_RESULT_HANDLED here because the connection
|
||||
// might be shared and some other filters might want to do something.
|
||||
}
|
||||
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
}
|
||||
|
||||
GHashTable*
|
||||
UPowerClient::GetDevicePropertiesSync(DBusGProxy* aProxy)
|
||||
{
|
||||
GError* error = nullptr;
|
||||
GHashTable* hashTable = nullptr;
|
||||
GType typeGHashTable = dbus_g_type_get_map("GHashTable", G_TYPE_STRING,
|
||||
G_TYPE_VALUE);
|
||||
if (!dbus_g_proxy_call(aProxy, "GetAll", &error, G_TYPE_STRING,
|
||||
"org.freedesktop.UPower.Device", G_TYPE_INVALID,
|
||||
typeGHashTable, &hashTable, G_TYPE_INVALID)) {
|
||||
HAL_LOG("Error: %s\n", error->message);
|
||||
g_error_free(error);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return hashTable;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
UPowerClient::GetDevicePropertiesCallback(DBusGProxy* aProxy,
|
||||
DBusGProxyCall* aCall, void* aData)
|
||||
{
|
||||
GError* error = nullptr;
|
||||
GHashTable* hashTable = nullptr;
|
||||
GType typeGHashTable = dbus_g_type_get_map("GHashTable", G_TYPE_STRING,
|
||||
G_TYPE_VALUE);
|
||||
if (!dbus_g_proxy_end_call(aProxy, aCall, &error, typeGHashTable,
|
||||
&hashTable, G_TYPE_INVALID)) {
|
||||
HAL_LOG("Error: %s\n", error->message);
|
||||
g_error_free(error);
|
||||
} else {
|
||||
sInstance->UpdateSavedInfo(hashTable);
|
||||
hal::NotifyBatteryChange(hal::BatteryInformation(sInstance->mLevel,
|
||||
sInstance->mCharging,
|
||||
sInstance->mRemainingTime));
|
||||
g_hash_table_unref(hashTable);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UPowerClient::GetDevicePropertiesAsync(DBusGProxy* aProxy)
|
||||
{
|
||||
dbus_g_proxy_begin_call(aProxy, "GetAll", GetDevicePropertiesCallback, nullptr,
|
||||
nullptr, G_TYPE_STRING,
|
||||
"org.freedesktop.UPower.Device", G_TYPE_INVALID);
|
||||
}
|
||||
|
||||
void
|
||||
UPowerClient::UpdateSavedInfo(GHashTable* aHashTable)
|
||||
{
|
||||
bool isFull = false;
|
||||
|
||||
/*
|
||||
* State values are confusing...
|
||||
* First of all, after looking at upower sources (0.9.13), it seems that
|
||||
* PendingDischarge and PendingCharge are not used.
|
||||
* In addition, FullyCharged and Empty states are not clear because we do not
|
||||
* know if the battery is actually charging or not. Those values come directly
|
||||
* from sysfs (in the Linux kernel) which have four states: "Empty", "Full",
|
||||
* "Charging" and "Discharging". In sysfs, "Empty" and "Full" are also only
|
||||
* related to the level, not to the charging state.
|
||||
* In this code, we are going to assume that Full means charging and Empty
|
||||
* means discharging because if that is not the case, the state should not
|
||||
* last a long time (actually, it should disappear at the following update).
|
||||
* It might be even very hard to see real cases where the state is Empty and
|
||||
* the battery is charging or the state is Full and the battery is discharging
|
||||
* given that plugging/unplugging the battery should have an impact on the
|
||||
* level.
|
||||
*/
|
||||
switch (g_value_get_uint(static_cast<const GValue*>(g_hash_table_lookup(aHashTable, "State")))) {
|
||||
case eState_Unknown:
|
||||
mCharging = kDefaultCharging;
|
||||
break;
|
||||
case eState_FullyCharged:
|
||||
isFull = true;
|
||||
MOZ_FALLTHROUGH;
|
||||
case eState_Charging:
|
||||
case eState_PendingCharge:
|
||||
mCharging = true;
|
||||
break;
|
||||
case eState_Discharging:
|
||||
case eState_Empty:
|
||||
case eState_PendingDischarge:
|
||||
mCharging = false;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* The battery level might be very close to 100% (like 99%) without
|
||||
* increasing. It seems that upower sets the battery state as 'full' in that
|
||||
* case so we should trust it and not even try to get the value.
|
||||
*/
|
||||
if (isFull) {
|
||||
mLevel = 1.0;
|
||||
} else {
|
||||
mLevel = round(g_value_get_double(static_cast<const GValue*>(g_hash_table_lookup(aHashTable, "Percentage"))))*0.01;
|
||||
}
|
||||
|
||||
if (isFull) {
|
||||
mRemainingTime = 0;
|
||||
} else {
|
||||
mRemainingTime = mCharging ? g_value_get_int64(static_cast<const GValue*>(g_hash_table_lookup(aHashTable, "TimeToFull")))
|
||||
: g_value_get_int64(static_cast<const GValue*>(g_hash_table_lookup(aHashTable, "TimeToEmpty")));
|
||||
|
||||
if (mRemainingTime == kUPowerUnknownRemainingTime) {
|
||||
mRemainingTime = kUnknownRemainingTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double
|
||||
UPowerClient::GetLevel()
|
||||
{
|
||||
return mLevel;
|
||||
}
|
||||
|
||||
bool
|
||||
UPowerClient::IsCharging()
|
||||
{
|
||||
return mCharging;
|
||||
}
|
||||
|
||||
double
|
||||
UPowerClient::GetRemainingTime()
|
||||
{
|
||||
return mRemainingTime;
|
||||
}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
|
|
@ -34,14 +34,6 @@ if CONFIG['OS_TARGET'] == 'Linux':
|
|||
'linux/LinuxMemory.cpp',
|
||||
'linux/LinuxPower.cpp',
|
||||
]
|
||||
if CONFIG['MOZ_ENABLE_DBUS']:
|
||||
UNIFIED_SOURCES += [
|
||||
'linux/UPowerClient.cpp',
|
||||
]
|
||||
else:
|
||||
UNIFIED_SOURCES += [
|
||||
'fallback/FallbackBattery.cpp',
|
||||
]
|
||||
elif CONFIG['OS_TARGET'] == 'WINNT':
|
||||
UNIFIED_SOURCES += [
|
||||
'fallback/FallbackAlarm.cpp',
|
||||
|
|
@ -51,13 +43,8 @@ elif CONFIG['OS_TARGET'] == 'WINNT':
|
|||
'fallback/FallbackVibration.cpp',
|
||||
'windows/WindowsSensor.cpp',
|
||||
]
|
||||
# WindowsBattery.cpp cannot be built in unified mode because it relies on HalImpl.h.
|
||||
SOURCES += [
|
||||
'windows/WindowsBattery.cpp',
|
||||
]
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
UNIFIED_SOURCES += [
|
||||
'cocoa/CocoaBattery.cpp',
|
||||
'fallback/FallbackAlarm.cpp',
|
||||
'fallback/FallbackMemory.cpp',
|
||||
'fallback/FallbackPower.cpp',
|
||||
|
|
@ -73,18 +60,9 @@ elif CONFIG['OS_TARGET'] in ('OpenBSD', 'NetBSD', 'FreeBSD', 'DragonFly'):
|
|||
'fallback/FallbackSensor.cpp',
|
||||
'fallback/FallbackVibration.cpp',
|
||||
]
|
||||
if CONFIG['MOZ_ENABLE_DBUS']:
|
||||
UNIFIED_SOURCES += [
|
||||
'linux/UPowerClient.cpp',
|
||||
]
|
||||
else:
|
||||
UNIFIED_SOURCES += [
|
||||
'fallback/FallbackBattery.cpp',
|
||||
]
|
||||
else:
|
||||
UNIFIED_SOURCES += [
|
||||
'fallback/FallbackAlarm.cpp',
|
||||
'fallback/FallbackBattery.cpp',
|
||||
'fallback/FallbackMemory.cpp',
|
||||
'fallback/FallbackPower.cpp',
|
||||
'fallback/FallbackScreenConfiguration.cpp',
|
||||
|
|
|
|||
|
|
@ -20,12 +20,6 @@ using PRTime from "prtime.h";
|
|||
namespace mozilla {
|
||||
|
||||
namespace hal {
|
||||
struct BatteryInformation {
|
||||
double level;
|
||||
bool charging;
|
||||
double remainingTime;
|
||||
};
|
||||
|
||||
struct SensorData {
|
||||
SensorType sensor;
|
||||
PRTime timestamp;
|
||||
|
|
@ -69,7 +63,6 @@ nested(upto inside_cpow) sync protocol PHal {
|
|||
manager PContent;
|
||||
|
||||
child:
|
||||
async NotifyBatteryChange(BatteryInformation aBatteryInfo);
|
||||
async NotifyNetworkChange(NetworkInformation aNetworkInfo);
|
||||
async NotifyWakeLockChange(WakeLockInformation aWakeLockInfo);
|
||||
async NotifyScreenConfigurationChange(ScreenConfiguration aScreenOrientation);
|
||||
|
|
@ -80,11 +73,6 @@ parent:
|
|||
async Vibrate(uint32_t[] pattern, uint64_t[] id, PBrowser browser);
|
||||
async CancelVibrate(uint64_t[] id, PBrowser browser);
|
||||
|
||||
async EnableBatteryNotifications();
|
||||
async DisableBatteryNotifications();
|
||||
sync GetCurrentBatteryInformation()
|
||||
returns (BatteryInformation aBatteryInfo);
|
||||
|
||||
async EnableNetworkNotifications();
|
||||
async DisableNetworkNotifications();
|
||||
sync GetCurrentNetworkInformation()
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
#include "mozilla/hal_sandbox/PHalParent.h"
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
#include "mozilla/dom/battery/Types.h"
|
||||
#include "mozilla/dom/network/Types.h"
|
||||
#include "mozilla/dom/ScreenOrientation.h"
|
||||
#include "mozilla/EnumeratedRange.h"
|
||||
|
|
@ -69,24 +68,6 @@ CancelVibrate(const WindowIdentifier &id)
|
|||
Hal()->SendCancelVibrate(newID.AsArray(), TabChild::GetFrom(newID.GetWindow()));
|
||||
}
|
||||
|
||||
void
|
||||
EnableBatteryNotifications()
|
||||
{
|
||||
Hal()->SendEnableBatteryNotifications();
|
||||
}
|
||||
|
||||
void
|
||||
DisableBatteryNotifications()
|
||||
{
|
||||
Hal()->SendDisableBatteryNotifications();
|
||||
}
|
||||
|
||||
void
|
||||
GetCurrentBatteryInformation(BatteryInformation* aBatteryInfo)
|
||||
{
|
||||
Hal()->SendGetCurrentBatteryInformation(aBatteryInfo);
|
||||
}
|
||||
|
||||
void
|
||||
EnableNetworkNotifications()
|
||||
{
|
||||
|
|
@ -376,7 +357,6 @@ bool SystemServiceIsRunning(const char* aSvcName)
|
|||
}
|
||||
|
||||
class HalParent : public PHalParent
|
||||
, public BatteryObserver
|
||||
, public NetworkObserver
|
||||
, public ISensorObserver
|
||||
, public WakeLockObserver
|
||||
|
|
@ -390,7 +370,6 @@ public:
|
|||
{
|
||||
// NB: you *must* unconditionally unregister your observer here,
|
||||
// if it *may* be registered below.
|
||||
hal::UnregisterBatteryObserver(this);
|
||||
hal::UnregisterNetworkObserver(this);
|
||||
hal::UnregisterScreenConfigurationObserver(this);
|
||||
for (auto sensor : MakeEnumeratedRange(NUM_SENSOR_TYPE)) {
|
||||
|
|
@ -431,30 +410,6 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvEnableBatteryNotifications() override {
|
||||
// We give all content battery-status permission.
|
||||
hal::RegisterBatteryObserver(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvDisableBatteryNotifications() override {
|
||||
hal::UnregisterBatteryObserver(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvGetCurrentBatteryInformation(BatteryInformation* aBatteryInfo) override {
|
||||
// We give all content battery-status permission.
|
||||
hal::GetCurrentBatteryInformation(aBatteryInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Notify(const BatteryInformation& aBatteryInfo) override {
|
||||
Unused << SendNotifyBatteryChange(aBatteryInfo);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvEnableNetworkNotifications() override {
|
||||
// We give all content access to this network-status information.
|
||||
|
|
@ -768,12 +723,6 @@ public:
|
|||
sHalChildDestroyed = true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvNotifyBatteryChange(const BatteryInformation& aBatteryInfo) override {
|
||||
hal::NotifyBatteryChange(aBatteryInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvNotifySensorChange(const hal::SensorData &aSensorData) override;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,190 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#include "Hal.h"
|
||||
#include "HalImpl.h"
|
||||
#include "nsITimer.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/battery/Constants.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
|
||||
using namespace mozilla::dom::battery;
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
static nsCOMPtr<nsITimer> sUpdateTimer;
|
||||
|
||||
/* Power Event API is Vista or later */
|
||||
static decltype(RegisterPowerSettingNotification)* sRegisterPowerSettingNotification = nullptr;
|
||||
static decltype(UnregisterPowerSettingNotification)* sUnregisterPowerSettingNotification = nullptr;
|
||||
static HPOWERNOTIFY sPowerHandle = nullptr;
|
||||
static HPOWERNOTIFY sCapacityHandle = nullptr;
|
||||
static HWND sHWnd = nullptr;
|
||||
|
||||
static void
|
||||
UpdateHandler(nsITimer* aTimer, void* aClosure) {
|
||||
NS_ASSERTION(!IsVistaOrLater(),
|
||||
"We shouldn't call this function for Vista or later version!");
|
||||
|
||||
static hal::BatteryInformation sLastInfo;
|
||||
hal::BatteryInformation currentInfo;
|
||||
|
||||
hal_impl::GetCurrentBatteryInformation(¤tInfo);
|
||||
if (sLastInfo.level() != currentInfo.level() ||
|
||||
sLastInfo.charging() != currentInfo.charging() ||
|
||||
sLastInfo.remainingTime() != currentInfo.remainingTime()) {
|
||||
hal::NotifyBatteryChange(currentInfo);
|
||||
sLastInfo = currentInfo;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
LRESULT CALLBACK
|
||||
BatteryWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||
if (msg != WM_POWERBROADCAST || wParam != PBT_POWERSETTINGCHANGE) {
|
||||
return DefWindowProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
hal::BatteryInformation currentInfo;
|
||||
|
||||
// Since we need update remainingTime, we cannot use LPARAM.
|
||||
hal_impl::GetCurrentBatteryInformation(¤tInfo);
|
||||
|
||||
hal::NotifyBatteryChange(currentInfo);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
EnableBatteryNotifications()
|
||||
{
|
||||
if (IsVistaOrLater()) {
|
||||
// RegisterPowerSettingNotification is from Vista or later.
|
||||
// Use this API if available.
|
||||
HMODULE hUser32 = GetModuleHandleW(L"USER32.DLL");
|
||||
if (!sRegisterPowerSettingNotification)
|
||||
sRegisterPowerSettingNotification = (decltype(RegisterPowerSettingNotification)*)
|
||||
GetProcAddress(hUser32, "RegisterPowerSettingNotification");
|
||||
if (!sUnregisterPowerSettingNotification)
|
||||
sUnregisterPowerSettingNotification = (decltype(UnregisterPowerSettingNotification)*)
|
||||
GetProcAddress(hUser32, "UnregisterPowerSettingNotification");
|
||||
|
||||
if (!sRegisterPowerSettingNotification ||
|
||||
!sUnregisterPowerSettingNotification) {
|
||||
NS_ASSERTION(false, "Canot find PowerSettingNotification functions.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create custom window to watch battery event
|
||||
// If we can get Gecko's window handle, this is unnecessary.
|
||||
|
||||
if (sHWnd == nullptr) {
|
||||
WNDCLASSW wc;
|
||||
HMODULE hSelf = GetModuleHandle(nullptr);
|
||||
|
||||
if (!GetClassInfoW(hSelf, L"MozillaBatteryClass", &wc)) {
|
||||
ZeroMemory(&wc, sizeof(WNDCLASSW));
|
||||
wc.hInstance = hSelf;
|
||||
wc.lpfnWndProc = BatteryWindowProc;
|
||||
wc.lpszClassName = L"MozillaBatteryClass";
|
||||
RegisterClassW(&wc);
|
||||
}
|
||||
|
||||
sHWnd = CreateWindowW(L"MozillaBatteryClass", L"Battery Watcher",
|
||||
0, 0, 0, 0, 0,
|
||||
nullptr, nullptr, hSelf, nullptr);
|
||||
}
|
||||
|
||||
if (sHWnd == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
sPowerHandle =
|
||||
sRegisterPowerSettingNotification(sHWnd,
|
||||
&GUID_ACDC_POWER_SOURCE,
|
||||
DEVICE_NOTIFY_WINDOW_HANDLE);
|
||||
sCapacityHandle =
|
||||
sRegisterPowerSettingNotification(sHWnd,
|
||||
&GUID_BATTERY_PERCENTAGE_REMAINING,
|
||||
DEVICE_NOTIFY_WINDOW_HANDLE);
|
||||
} else
|
||||
{
|
||||
// for Windows XP. If we remove Windows XP support,
|
||||
// we should remove timer-based power notification
|
||||
sUpdateTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
|
||||
if (sUpdateTimer) {
|
||||
sUpdateTimer->InitWithFuncCallback(UpdateHandler,
|
||||
nullptr,
|
||||
Preferences::GetInt("dom.battery.timer",
|
||||
30000 /* 30s */),
|
||||
nsITimer::TYPE_REPEATING_SLACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DisableBatteryNotifications()
|
||||
{
|
||||
if (IsVistaOrLater()) {
|
||||
if (sPowerHandle) {
|
||||
sUnregisterPowerSettingNotification(sPowerHandle);
|
||||
sPowerHandle = nullptr;
|
||||
}
|
||||
|
||||
if (sCapacityHandle) {
|
||||
sUnregisterPowerSettingNotification(sCapacityHandle);
|
||||
sCapacityHandle = nullptr;
|
||||
}
|
||||
|
||||
if (sHWnd) {
|
||||
DestroyWindow(sHWnd);
|
||||
sHWnd = nullptr;
|
||||
}
|
||||
} else
|
||||
{
|
||||
if (sUpdateTimer) {
|
||||
sUpdateTimer->Cancel();
|
||||
sUpdateTimer = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
|
||||
{
|
||||
SYSTEM_POWER_STATUS status;
|
||||
if (!GetSystemPowerStatus(&status)) {
|
||||
aBatteryInfo->level() = kDefaultLevel;
|
||||
aBatteryInfo->charging() = kDefaultCharging;
|
||||
aBatteryInfo->remainingTime() = kDefaultRemainingTime;
|
||||
return;
|
||||
}
|
||||
|
||||
aBatteryInfo->level() =
|
||||
status.BatteryLifePercent == 255 ? kDefaultLevel
|
||||
: ((double)status.BatteryLifePercent) / 100.0;
|
||||
aBatteryInfo->charging() = (status.ACLineStatus != 0);
|
||||
if (status.ACLineStatus != 0) {
|
||||
if (aBatteryInfo->level() == 1.0) {
|
||||
// GetSystemPowerStatus API may returns -1 for BatteryFullLifeTime.
|
||||
// So, if battery is 100%, set kDefaultRemainingTime at force.
|
||||
aBatteryInfo->remainingTime() = kDefaultRemainingTime;
|
||||
} else {
|
||||
aBatteryInfo->remainingTime() =
|
||||
status.BatteryFullLifeTime == (DWORD)-1 ? kUnknownRemainingTime
|
||||
: status.BatteryFullLifeTime;
|
||||
}
|
||||
} else {
|
||||
aBatteryInfo->remainingTime() =
|
||||
status.BatteryLifeTime == (DWORD)-1 ? kUnknownRemainingTime
|
||||
: status.BatteryLifeTime;
|
||||
}
|
||||
}
|
||||
|
||||
} // hal_impl
|
||||
} // mozilla
|
||||
|
|
@ -3823,7 +3823,7 @@ IonBuilder::improveTypesAtTypeOfCompare(MCompare* ins, bool trueBranch, MTest* t
|
|||
tmp.addType(TypeSet::PrimitiveType(ValueTypeFromMIRType(subject->type())), alloc_->lifoAlloc());
|
||||
}
|
||||
|
||||
if (inputTypes->unknown())
|
||||
if (inputTypes->unknown() || inputTypes->hasType(TypeSet::MagicArgType()))
|
||||
return true;
|
||||
|
||||
// Note: we cannot remove the AnyObject type in the false branch,
|
||||
|
|
@ -3905,7 +3905,7 @@ IonBuilder::improveTypesAtNullOrUndefinedCompare(MCompare* ins, bool trueBranch,
|
|||
tmp.addType(TypeSet::PrimitiveType(ValueTypeFromMIRType(subject->type())), alloc_->lifoAlloc());
|
||||
}
|
||||
|
||||
if (inputTypes->unknown())
|
||||
if (inputTypes->unknown() || inputTypes->hasType(TypeSet::MagicArgType()))
|
||||
return true;
|
||||
|
||||
TemporaryTypeSet* type;
|
||||
|
|
@ -3969,7 +3969,7 @@ IonBuilder::improveTypesAtTest(MDefinition* ins, bool trueBranch, MTest* test)
|
|||
tmp.addType(TypeSet::PrimitiveType(ValueTypeFromMIRType(subject->type())), alloc_->lifoAlloc());
|
||||
}
|
||||
|
||||
if (oldType->unknown())
|
||||
if (oldType->unknown() || oldType->hasType(TypeSet::MagicArgType()))
|
||||
return true;
|
||||
|
||||
TemporaryTypeSet* type = nullptr;
|
||||
|
|
@ -4049,7 +4049,7 @@ IonBuilder::improveTypesAtTest(MDefinition* ins, bool trueBranch, MTest* test)
|
|||
}
|
||||
|
||||
// If ins does not have a typeset we return as we cannot optimize.
|
||||
if (oldType->unknown())
|
||||
if (oldType->unknown() || oldType->hasType(TypeSet::MagicArgType()))
|
||||
return true;
|
||||
|
||||
// Decide either to set or remove.
|
||||
|
|
|
|||
|
|
@ -71,8 +71,12 @@ Sink(MIRGenerator* mir, MIRGraph& graph)
|
|||
for (MUseIterator i(ins->usesBegin()), e(ins->usesEnd()); i != e; i++) {
|
||||
hasUses = true;
|
||||
MNode* consumerNode = (*i)->consumer();
|
||||
if (consumerNode->isResumePoint())
|
||||
if (consumerNode->isResumePoint()) {
|
||||
if (!consumerNode->toResumePoint()->isRecoverableOperand(*i)) {
|
||||
hasLiveUses = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
MDefinition* consumer = consumerNode->toDefinition();
|
||||
if (consumer->isRecoveredOnBailout())
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ elif CONFIG['OS_TARGET'] in ('OpenBSD', 'FreeBSD', 'NetBSD'):
|
|||
DEFINES[CONFIG['OS_TARGET'].upper()] = True
|
||||
elif CONFIG['OS_ARCH'] == 'WINNT':
|
||||
DEFINES['_WINDOWS'] = True
|
||||
elif CONFIG['OS_ARCH'] == 'SunOS':
|
||||
DEFINES['__USE_DRAFT6_PROTOTYPES__'] = True
|
||||
|
||||
DEFINES['_PR_PTHREADS'] = True
|
||||
DEFINES['NET_SSL'] = True
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@
|
|||
*/
|
||||
|
||||
#ifndef SYSV
|
||||
#if defined( hpux ) || defined( SOLARIS ) || defined ( sgi ) || defined( SVR4 )
|
||||
#if defined( hpux ) || defined(XP_SOLARIS) || defined ( sgi ) || defined( SVR4 )
|
||||
#define SYSV
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -191,7 +191,7 @@
|
|||
*/
|
||||
#if !defined(NSLDAPI_CONNECT_MUST_NOT_BE_INTERRUPTED) && \
|
||||
( defined(AIX) || defined(IRIX) || defined(HPUX) || defined(SUNOS4) \
|
||||
|| defined(SOLARIS) || defined(OSF1) ||defined(freebsd))
|
||||
|| defined(XP_SOLARIS) || defined(OSF1) ||defined(freebsd))
|
||||
#define NSLDAPI_CONNECT_MUST_NOT_BE_INTERRUPTED
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -43,16 +43,11 @@
|
|||
#include "ldap-int.h"
|
||||
#include "disptmpl.h"
|
||||
|
||||
#if defined(_WINDOWS) || defined(aix) || defined(SCOOS) || defined(OSF1) || defined(SOLARIS)
|
||||
#if defined(_WINDOWS) || defined(aix) || defined(SCOOS) || defined(OSF1) || defined(XP_SOLARIS)
|
||||
#include <time.h> /* for struct tm and ctime */
|
||||
#endif
|
||||
|
||||
|
||||
/* This is totally lame, since it should be coming from time.h, but isn't. */
|
||||
#if defined(SOLARIS)
|
||||
char *ctime_r(const time_t *, char *, int);
|
||||
#endif
|
||||
|
||||
static int do_entry2text( LDAP *ld, char *buf, char *base, LDAPMessage *entry,
|
||||
struct ldap_disptmpl *tmpl, char **defattrs, char ***defvals,
|
||||
writeptype writeproc, void *writeparm, char *eol, int rdncount,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ this.EXPORTED_SYMBOLS = ["getFolderProperties", "getSpecialFolderString",
|
|||
|
||||
Components.utils.import("resource:///modules/mailServices.js");
|
||||
Components.utils.import("resource:///modules/iteratorUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
/**
|
||||
* Returns a string representation of a folder's "special" type.
|
||||
|
|
@ -169,8 +170,18 @@ function allAccountsSorted(aExcludeIMAccounts) {
|
|||
return a.incomingServer.type != "im";
|
||||
});
|
||||
}
|
||||
|
||||
// Sort the accounts else will respect the order in mail.accountmanager.accounts
|
||||
if (!Services.prefs.getBoolPref("mail.accountmanager.accounts.ordered", false)) {
|
||||
accountList = accountList.sort(compareAccounts);
|
||||
}
|
||||
|
||||
return accountList.sort(compareAccounts);
|
||||
// Set "Local Folders" as always the first displayed account
|
||||
if (Services.prefs.getBoolPref("mail.accountmanager.localfolderfirst", false)) {
|
||||
accountList.unshift(accountList.splice(accountList.findIndex(item => item.key === "account1"), 1)[0]);
|
||||
}
|
||||
|
||||
return accountList;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -431,6 +431,8 @@ pref("mail.default_sendlater_uri", "mailbox://nobody@Local%20Folders/Unsent%20Me
|
|||
|
||||
pref("mail.smtpservers", "");
|
||||
pref("mail.accountmanager.accounts", "");
|
||||
pref("mail.accountmanager.accounts.ordered", false);
|
||||
pref("mail.accountmanager.localfolderfirst", false);
|
||||
|
||||
// Last used account key value
|
||||
pref("mail.account.lastKey", 0);
|
||||
|
|
|
|||
|
|
@ -4736,15 +4736,10 @@ pref("dom.vibrator.enabled", true);
|
|||
pref("dom.vibrator.max_vibrate_ms", 10000);
|
||||
pref("dom.vibrator.max_vibrate_list_len", 128);
|
||||
|
||||
// Battery API
|
||||
// Disabled by default to reduce private data exposure.
|
||||
pref("dom.battery.enabled", false);
|
||||
|
||||
// Abort API
|
||||
pref("dom.abortController.enabled", true);
|
||||
|
||||
// Push
|
||||
|
||||
pref("dom.push.enabled", false);
|
||||
|
||||
pref("dom.push.loglevel", "error");
|
||||
|
|
|
|||
|
|
@ -579,6 +579,12 @@ NS_IMETHODIMP
|
|||
nsBaseChannel::SetContentDispositionFilename(const nsAString &aContentDispositionFilename)
|
||||
{
|
||||
mContentDispositionFilename = new nsString(aContentDispositionFilename);
|
||||
|
||||
// For safety reasons ensure the filename doesn't contain null characters and
|
||||
// replace them with underscores. We may later pass the extension to system
|
||||
// MIME APIs that expect null terminated strings.
|
||||
mContentDispositionFilename->ReplaceChar(char16_t(0), '_');
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -562,6 +562,12 @@ NS_IMETHODIMP
|
|||
HttpBaseChannel::SetContentDispositionFilename(const nsAString& aContentDispositionFilename)
|
||||
{
|
||||
mContentDispositionFilename = new nsString(aContentDispositionFilename);
|
||||
|
||||
// For safety reasons ensure the filename doesn't contain null characters and
|
||||
// replace them with underscores. We may later pass the extension to system
|
||||
// MIME APIs that expect null terminated strings.
|
||||
mContentDispositionFilename->ReplaceChar(char16_t(0), '_');
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2517,6 +2517,27 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
|
|||
/* cookie too small */
|
||||
return (NULL);
|
||||
}
|
||||
#if defined(__Userspace__)
|
||||
/*
|
||||
* Recover the AF_CONN addresses within the cookie.
|
||||
* This needs to be done in the buffer provided for later processing
|
||||
* of the cookie and in the mbuf chain for HMAC validation.
|
||||
*/
|
||||
if ((cookie->addr_type == SCTP_CONN_ADDRESS) && (src->sa_family == AF_CONN)) {
|
||||
struct sockaddr_conn *sconnp = (struct sockaddr_conn *)src;
|
||||
|
||||
memcpy(cookie->address, &sconnp->sconn_addr , sizeof(void *));
|
||||
m_copyback(m, cookie_offset + offsetof(struct sctp_state_cookie, address),
|
||||
(int)sizeof(void *), (caddr_t)&sconnp->sconn_addr);
|
||||
}
|
||||
if ((cookie->laddr_type == SCTP_CONN_ADDRESS) && (dst->sa_family == AF_CONN)) {
|
||||
struct sockaddr_conn *sconnp = (struct sockaddr_conn *)dst;
|
||||
|
||||
memcpy(cookie->laddress, &sconnp->sconn_addr , sizeof(void *));
|
||||
m_copyback(m, cookie_offset + offsetof(struct sctp_state_cookie, laddress),
|
||||
(int)sizeof(void *), (caddr_t)&sconnp->sconn_addr);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* split off the signature into its own mbuf (since it should not be
|
||||
* calculated in the sctp_hmac_m() call).
|
||||
|
|
|
|||
|
|
@ -6492,6 +6492,27 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
|||
(uint8_t *)inp->sctp_ep.secret_key[(int)(inp->sctp_ep.current_secret_number)],
|
||||
SCTP_SECRET_SIZE, m_cookie, sizeof(struct sctp_paramhdr),
|
||||
(uint8_t *)signature, SCTP_SIGNATURE_SIZE);
|
||||
#if defined(__Userspace__)
|
||||
/*
|
||||
* Don't put AF_CONN addresses on the wire, in case this is critical
|
||||
* for the application. However, they are protected by the HMAC and
|
||||
* need to be reconstructed before checking the HMAC.
|
||||
* Clearing is only done in the mbuf chain, since the local stc is
|
||||
* not used anymore.
|
||||
*/
|
||||
if (stc.addr_type == SCTP_CONN_ADDRESS) {
|
||||
const void *p = NULL;
|
||||
|
||||
m_copyback(m_cookie, sizeof(struct sctp_paramhdr) + offsetof(struct sctp_state_cookie, address),
|
||||
(int)sizeof(void *), (caddr_t)&p);
|
||||
}
|
||||
if (stc.laddr_type == SCTP_CONN_ADDRESS) {
|
||||
const void *p = NULL;
|
||||
|
||||
m_copyback(m_cookie, sizeof(struct sctp_paramhdr) + offsetof(struct sctp_state_cookie, laddress),
|
||||
(int)sizeof(void *), (caddr_t)&p);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* We sifa 0 here to NOT set IP_DF if its IPv4, we ignore the return
|
||||
* here since the timer will drive a retranmission.
|
||||
|
|
|
|||
95
netwerk/test/gtest/TestBase64Stream.cpp
Normal file
95
netwerk/test/gtest/TestBase64Stream.cpp
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "mozilla/Base64.h"
|
||||
#include "nsIInputStream.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
// An input stream whose ReadSegments method calls aWriter with writes of size
|
||||
// aStep from the provided aInput in order to test edge-cases related to small
|
||||
// buffers.
|
||||
class TestStream final : public nsIInputStream {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS;
|
||||
|
||||
TestStream(const nsACString& aInput, uint32_t aStep)
|
||||
: mInput(aInput), mStep(aStep) {}
|
||||
|
||||
NS_IMETHOD Close() override { MOZ_CRASH("This should not be called"); }
|
||||
|
||||
NS_IMETHOD Available(uint64_t* aLength) override {
|
||||
*aLength = mInput.Length() - mPos;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD Read(char* aBuffer, uint32_t aCount,
|
||||
uint32_t* aReadCount) override {
|
||||
MOZ_CRASH("This should not be called");
|
||||
}
|
||||
|
||||
NS_IMETHOD ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
||||
uint32_t aCount, uint32_t* aResult) override {
|
||||
*aResult = 0;
|
||||
|
||||
if (mPos == mInput.Length()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
while (aCount > 0) {
|
||||
uint32_t amt = std::min(mStep, (uint32_t)(mInput.Length() - mPos));
|
||||
|
||||
uint32_t read = 0;
|
||||
nsresult rv =
|
||||
aWriter(this, aClosure, mInput.get() + mPos, *aResult, amt, &read);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
*aResult += read;
|
||||
aCount -= read;
|
||||
mPos += read;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD IsNonBlocking(bool* aNonBlocking) override {
|
||||
*aNonBlocking = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
~TestStream() = default;
|
||||
|
||||
nsCString mInput;
|
||||
const uint32_t mStep;
|
||||
uint32_t mPos = 0;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(TestStream, nsIInputStream)
|
||||
|
||||
// Test the base64 encoder with writer buffer sizes between 1 byte and the
|
||||
// entire length of "Hello World!" in order to exercise various edge cases.
|
||||
TEST(TestBase64Stream, Run)
|
||||
{
|
||||
nsCString input;
|
||||
input.AssignLiteral("Hello World!");
|
||||
|
||||
for (uint32_t step = 1; step <= input.Length(); ++step) {
|
||||
RefPtr<TestStream> ts = new TestStream(input, step);
|
||||
|
||||
nsAutoString encodedData;
|
||||
nsresult rv = Base64EncodeInputStream(ts, encodedData, input.Length());
|
||||
ASSERT_TRUE(NS_SUCCEEDED(rv));
|
||||
|
||||
EXPECT_TRUE(encodedData.EqualsLiteral("SGVsbG8gV29ybGQh"));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'TestBase64Stream.cpp',
|
||||
'TestProtocolProxyService.cpp',
|
||||
'TestStandardURL.cpp',
|
||||
]
|
||||
|
|
|
|||
|
|
@ -2616,6 +2616,7 @@ NS_VISIBILITY_DEFAULT PRBool nspr_use_zone_allocator = PR_FALSE;
|
|||
#ifdef CAIRO_HAS_DWRITE_FONT
|
||||
|
||||
#include <dwrite.h>
|
||||
#include "nsWindowsHelpers.h"
|
||||
|
||||
#ifdef DEBUG_DWRITE_STARTUP
|
||||
|
||||
|
|
@ -2644,7 +2645,7 @@ static DWORD WINAPI InitDwriteBG(LPVOID lpdwThreadParam)
|
|||
{
|
||||
SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_BEGIN);
|
||||
LOGREGISTRY(L"loading dwrite.dll");
|
||||
HMODULE dwdll = LoadLibraryW(L"dwrite.dll");
|
||||
HMODULE dwdll = LoadLibrarySystem32(L"dwrite.dll");
|
||||
if (dwdll) {
|
||||
decltype(DWriteCreateFactory)* createDWriteFactory = (decltype(DWriteCreateFactory)*)
|
||||
GetProcAddress(dwdll, "DWriteCreateFactory");
|
||||
|
|
|
|||
|
|
@ -1181,9 +1181,12 @@ nsExternalAppHandler::nsExternalAppHandler(nsIMIMEInfo * aMIMEInfo,
|
|||
mTempFileExtension = char16_t('.');
|
||||
AppendUTF8toUTF16(aTempFileExtension, mTempFileExtension);
|
||||
|
||||
// replace platform specific path separator and illegal characters to avoid any confusion
|
||||
mSuggestedFileName.ReplaceChar(KNOWN_PATH_SEPARATORS FILE_ILLEGAL_CHARACTERS, '_');
|
||||
mTempFileExtension.ReplaceChar(KNOWN_PATH_SEPARATORS FILE_ILLEGAL_CHARACTERS, '_');
|
||||
// Replace platform specific path separator and illegal characters to avoid any confusion
|
||||
mSuggestedFileName.ReplaceChar(KNOWN_PATH_SEPARATORS, '_');
|
||||
mSuggestedFileName.ReplaceChar(FILE_ILLEGAL_CHARACTERS, ' ');
|
||||
mSuggestedFileName.ReplaceChar(char16_t(0), '_');
|
||||
mTempFileExtension.ReplaceChar(KNOWN_PATH_SEPARATORS, '_');
|
||||
mTempFileExtension.ReplaceChar(FILE_ILLEGAL_CHARACTERS, ' ');
|
||||
|
||||
// Remove unsafe bidi characters which might have spoofing implications (bug 511521).
|
||||
const char16_t unsafeBidiCharacters[] = {
|
||||
|
|
|
|||
|
|
@ -108,30 +108,51 @@ EncodeInputStream_Encoder(nsIInputStream* aStream,
|
|||
EncodeInputStream_State<T>* state =
|
||||
static_cast<EncodeInputStream_State<T>*>(aClosure);
|
||||
|
||||
// We always consume all data.
|
||||
*aWriteCount = aCount;
|
||||
|
||||
// If we have any data left from last time, encode it now.
|
||||
uint32_t countRemaining = aCount;
|
||||
const unsigned char* src = (const unsigned char*)aFromSegment;
|
||||
if (state->charsOnStack) {
|
||||
MOZ_ASSERT(state->charsOnStack == 1 || state->charsOnStack == 2);
|
||||
|
||||
// Not enough data to compose a triple.
|
||||
if (state->charsOnStack == 1 && countRemaining == 1) {
|
||||
state->charsOnStack = 2;
|
||||
state->c[1] = src[0];
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint32_t consumed = 0;
|
||||
unsigned char firstSet[4];
|
||||
if (state->charsOnStack == 1) {
|
||||
firstSet[0] = state->c[0];
|
||||
firstSet[1] = src[0];
|
||||
firstSet[2] = (countRemaining > 1) ? src[1] : '\0';
|
||||
firstSet[2] = src[1];
|
||||
firstSet[3] = '\0';
|
||||
consumed = 2;
|
||||
} else /* state->charsOnStack == 2 */ {
|
||||
firstSet[0] = state->c[0];
|
||||
firstSet[1] = state->c[1];
|
||||
firstSet[2] = src[0];
|
||||
firstSet[3] = '\0';
|
||||
consumed = 1;
|
||||
}
|
||||
|
||||
Encode(firstSet, 3, state->buffer);
|
||||
state->buffer += 4;
|
||||
countRemaining -= (3 - state->charsOnStack);
|
||||
src += (3 - state->charsOnStack);
|
||||
countRemaining -= consumed;
|
||||
src += consumed;
|
||||
state->charsOnStack = 0;
|
||||
|
||||
// Bail if there is nothing left.
|
||||
if (!countRemaining) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// Encode the bulk of the
|
||||
// Encode as many full triplets as possible.
|
||||
uint32_t encodeLength = countRemaining - countRemaining % 3;
|
||||
MOZ_ASSERT(encodeLength % 3 == 0,
|
||||
"Should have an exact number of triplets!");
|
||||
|
|
@ -140,9 +161,6 @@ EncodeInputStream_Encoder(nsIInputStream* aStream,
|
|||
src += encodeLength;
|
||||
countRemaining -= encodeLength;
|
||||
|
||||
// We must consume all data, so if there's some data left stash it
|
||||
*aWriteCount = aCount;
|
||||
|
||||
if (countRemaining) {
|
||||
// We should never have a full triplet left at this point.
|
||||
MOZ_ASSERT(countRemaining < 3, "We should have encoded more!");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue