Merge m-c to fx-team, a=merge

This commit is contained in:
Wes Kocher 2015-10-16 12:31:52 -07:00
commit bb6d209428
106 changed files with 2669 additions and 1650 deletions

View File

@ -287,8 +287,12 @@ this.EventManager.prototype = {
case Events.DOCUMENT_LOAD_COMPLETE:
{
let position = this.contentControl.vc.position;
// Check if position is in the subtree of the DOCUMENT_LOAD_COMPLETE
// event's dialog accesible or accessible document
let subtreeRoot = aEvent.accessible.role === Roles.DIALOG ?
aEvent.accessible : aEvent.accessibleDocument;
if (aEvent.accessible === aEvent.accessibleDocument ||
(position && Utils.isInSubtree(position, aEvent.accessible))) {
(position && Utils.isInSubtree(position, subtreeRoot))) {
// Do not automove into the document if the virtual cursor is already
// positioned inside it.
break;

View File

@ -345,6 +345,21 @@ this.Utils = { // jshint ignore:line
isInSubtree: function isInSubtree(aAccessible, aSubTreeRoot) {
let acc = aAccessible;
// If aSubTreeRoot is an accessible document, we will only walk up the
// ancestry of documents and skip everything else.
if (aSubTreeRoot instanceof Ci.nsIAccessibleDocument) {
while (acc) {
let parentDoc = acc instanceof Ci.nsIAccessibleDocument ?
acc.parentDocument : acc.document;
if (parentDoc === aSubTreeRoot) {
return true;
}
acc = parentDoc;
}
return false;
}
while (acc) {
if (acc == aSubTreeRoot) {
return true;

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8999f0ba6326d815c8366e3c1155b7e4e9763b40"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="f75a7e01912cee313fed92ff2089586f507b2ba5"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8999f0ba6326d815c8366e3c1155b7e4e9763b40"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="f75a7e01912cee313fed92ff2089586f507b2ba5"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
@ -135,7 +135,7 @@
<project groups="invensense" name="platform/hardware/invensense" path="hardware/invensense" revision="e6d9ab28b4f4e7684f6c07874ee819c9ea0002a2"/>
<project name="platform/hardware/ril" path="hardware/ril" revision="865ce3b4a2ba0b3a31421ca671f4d6c5595f8690"/>
<project name="kernel/common" path="kernel" revision="b698c5aa4e9393dfd70d0ea7a0bf93b333b54750"/>
<project name="platform/system/core" path="system/core" revision="4776448ebcd3f07d58b91503c478da9b54cb58a0"/>
<project name="platform/system/core" path="system/core" revision="1b888e1ae54c358246f13e4fb915ce43cde00691"/>
<project name="u-boot" path="u-boot" revision="f1502910977ac88f43da7bf9277c3523ad4b0b2f"/>
<project name="vendor/sprd/gps" path="vendor/sprd/gps" revision="7d6e1269be7186b2073fa568958b357826692c4b"/>
<project name="vendor/sprd/open-source" path="vendor/sprd/open-source" revision="295ff253b74353751a99aafd687196a28c84a58e"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="8999f0ba6326d815c8366e3c1155b7e4e9763b40"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="f75a7e01912cee313fed92ff2089586f507b2ba5"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="4ace9aaee0e048dfda11bb787646c59982a3dc80"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8999f0ba6326d815c8366e3c1155b7e4e9763b40"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="f75a7e01912cee313fed92ff2089586f507b2ba5"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0c28789b9957913be975eb002a22323f93585d4c"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8999f0ba6326d815c8366e3c1155b7e4e9763b40"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="f75a7e01912cee313fed92ff2089586f507b2ba5"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8999f0ba6326d815c8366e3c1155b7e4e9763b40"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="f75a7e01912cee313fed92ff2089586f507b2ba5"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="8999f0ba6326d815c8366e3c1155b7e4e9763b40"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="f75a7e01912cee313fed92ff2089586f507b2ba5"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="4ace9aaee0e048dfda11bb787646c59982a3dc80"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8999f0ba6326d815c8366e3c1155b7e4e9763b40"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="f75a7e01912cee313fed92ff2089586f507b2ba5"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>

View File

@ -1,9 +1,9 @@
{
"git": {
"git_revision": "8999f0ba6326d815c8366e3c1155b7e4e9763b40",
"git_revision": "f75a7e01912cee313fed92ff2089586f507b2ba5",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "983b7ecb17c67b9fb511f400bb5b28b9069eea00",
"revision": "f51f8770b9665f44e57e9e09faee2b967a80abf1",
"repo_path": "integration/gaia-central"
}

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8999f0ba6326d815c8366e3c1155b7e4e9763b40"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="f75a7e01912cee313fed92ff2089586f507b2ba5"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>

View File

@ -18,7 +18,7 @@
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8999f0ba6326d815c8366e3c1155b7e4e9763b40"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="f75a7e01912cee313fed92ff2089586f507b2ba5"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0c28789b9957913be975eb002a22323f93585d4c"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8999f0ba6326d815c8366e3c1155b7e4e9763b40"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="f75a7e01912cee313fed92ff2089586f507b2ba5"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>

View File

@ -756,6 +756,7 @@ html|*#fullscreen-exit-button {
opacity: 0;
visibility: hidden;
pointer-events: none;
-moz-stack-sizing: ignore;
}
#addon-progress-notification {

View File

@ -505,7 +505,7 @@ StructuredCloneHolder::WriteFullySerializableObjects(JSContext* aCx,
// Handle Key cloning
{
CryptoKey* key;
CryptoKey* key = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(CryptoKey, aObj, key))) {
MOZ_ASSERT(NS_IsMainThread());
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_WEBCRYPTO_KEY, 0) &&
@ -516,7 +516,7 @@ StructuredCloneHolder::WriteFullySerializableObjects(JSContext* aCx,
#ifdef MOZ_WEBRTC
{
// Handle WebRTC Certificate cloning
RTCCertificate* cert;
RTCCertificate* cert = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(RTCCertificate, aObj, cert))) {
MOZ_ASSERT(NS_IsMainThread());
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_RTC_CERTIFICATE, 0) &&
@ -536,7 +536,7 @@ StructuredCloneHolder::WriteFullySerializableObjects(JSContext* aCx,
#ifdef MOZ_NFC
{
MozNDEFRecord* ndefRecord;
MozNDEFRecord* ndefRecord = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(MozNDEFRecord, aObj, ndefRecord))) {
MOZ_ASSERT(NS_IsMainThread());
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_NFC_NDEF, 0) &&

View File

@ -35,6 +35,8 @@ namespace {
static BluetoothA2dpInterface* sBtA2dpInterface;
} // namespace
const int BluetoothA2dpManager::MAX_NUM_CLIENTS = 1;
NS_IMETHODIMP
BluetoothA2dpManager::Observe(nsISupports* aSubject,
const char* aTopic,
@ -86,40 +88,52 @@ AvStatusToSinkString(BluetoothA2dpConnectionState aState, nsAString& aString)
}
}
class BluetoothA2dpManager::InitResultHandler final
: public BluetoothA2dpResultHandler
class BluetoothA2dpManager::RegisterModuleResultHandler final
: public BluetoothSetupResultHandler
{
public:
InitResultHandler(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
RegisterModuleResultHandler(BluetoothA2dpInterface* aInterface,
BluetoothProfileResultHandler* aRes)
: mInterface(aInterface)
, mRes(aRes)
{ }
void OnError(BluetoothStatus aStatus) override
{
BT_WARNING("BluetoothA2dpInterface::Init failed: %d",
MOZ_ASSERT(NS_IsMainThread());
BT_WARNING("BluetoothSetupInterface::RegisterModule failed for A2DP: %d",
(int)aStatus);
mInterface->SetNotificationHandler(nullptr);
if (mRes) {
mRes->OnError(NS_ERROR_FAILURE);
}
}
void Init() override
void RegisterModule() override
{
MOZ_ASSERT(NS_IsMainThread());
sBtA2dpInterface = mInterface;
if (mRes) {
mRes->Init();
}
}
private:
BluetoothA2dpInterface* mInterface;
nsRefPtr<BluetoothProfileResultHandler> mRes;
};
class BluetoothA2dpManager::OnErrorProfileResultHandlerRunnable final
class BluetoothA2dpManager::InitProfileResultHandlerRunnable final
: public nsRunnable
{
public:
OnErrorProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
nsresult aRv)
InitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
nsresult aRv)
: mRes(aRes)
, mRv(aRv)
{
@ -128,7 +142,13 @@ public:
NS_IMETHOD Run() override
{
mRes->OnError(mRv);
MOZ_ASSERT(NS_IsMainThread());
if (NS_SUCCEEDED(mRv)) {
mRes->Init();
} else {
mRes->OnError(mRv);
}
return NS_OK;
}
@ -147,32 +167,64 @@ private:
void
BluetoothA2dpManager::InitA2dpInterface(BluetoothProfileResultHandler* aRes)
{
BluetoothInterface* btInf = BluetoothInterface::GetInstance();
MOZ_ASSERT(NS_IsMainThread());
if (sBtA2dpInterface) {
BT_LOGR("Bluetooth A2DP interface is already initalized.");
nsRefPtr<nsRunnable> r =
new InitProfileResultHandlerRunnable(aRes, NS_OK);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch A2DP Init runnable");
}
return;
}
auto btInf = BluetoothInterface::GetInstance();
if (NS_WARN_IF(!btInf)) {
// If there's no HFP interface, we dispatch a runnable
// If there's no Bluetooth interface, we dispatch a runnable
// that calls the profile result handler.
nsRefPtr<nsRunnable> r =
new OnErrorProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch HFP OnError runnable");
BT_LOGR("Failed to dispatch A2DP OnError runnable");
}
return;
}
sBtA2dpInterface = btInf->GetBluetoothA2dpInterface();
if (NS_WARN_IF(!sBtA2dpInterface)) {
// If there's no HFP interface, we dispatch a runnable
auto setupInterface = btInf->GetBluetoothSetupInterface();
if (NS_WARN_IF(!setupInterface)) {
// If there's no Setup interface, we dispatch a runnable
// that calls the profile result handler.
nsRefPtr<nsRunnable> r =
new OnErrorProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch HFP OnError runnable");
BT_LOGR("Failed to dispatch A2DP OnError runnable");
}
return;
}
BluetoothA2dpManager* a2dpManager = BluetoothA2dpManager::Get();
sBtA2dpInterface->Init(a2dpManager, new InitResultHandler(aRes));
auto a2dpInterface = btInf->GetBluetoothA2dpInterface();
if (NS_WARN_IF(!a2dpInterface)) {
// If there's no A2DP interface, we dispatch a runnable
// that calls the profile result handler.
nsRefPtr<nsRunnable> r =
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch A2DP OnError runnable");
}
return;
}
// Set notification handler _before_ registering the module. It could
// happen that we receive notifications, before the result handler runs.
a2dpInterface->SetNotificationHandler(BluetoothA2dpManager::Get());
setupInterface->RegisterModule(
SETUP_SERVICE_ID_A2DP, 0, MAX_NUM_CLIENTS,
new RegisterModuleResultHandler(a2dpInterface, aRes));
}
BluetoothA2dpManager::~BluetoothA2dpManager()
@ -227,19 +279,22 @@ BluetoothA2dpManager::Get()
return sBluetoothA2dpManager;
}
class BluetoothA2dpManager::CleanupResultHandler final
: public BluetoothA2dpResultHandler
class BluetoothA2dpManager::UnregisterModuleResultHandler final
: public BluetoothSetupResultHandler
{
public:
CleanupResultHandler(BluetoothProfileResultHandler* aRes)
UnregisterModuleResultHandler(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
{ }
void OnError(BluetoothStatus aStatus) override
{
BT_WARNING("BluetoothA2dpInterface::Cleanup failed: %d",
MOZ_ASSERT(NS_IsMainThread());
BT_WARNING("BluetoothSetupInterface::UnregisterModule failed for A2DP: %d",
(int)aStatus);
sBtA2dpInterface->SetNotificationHandler(nullptr);
sBtA2dpInterface = nullptr;
if (mRes) {
@ -247,8 +302,11 @@ public:
}
}
void Cleanup() override
void UnregisterModule() override
{
MOZ_ASSERT(NS_IsMainThread());
sBtA2dpInterface->SetNotificationHandler(nullptr);
sBtA2dpInterface = nullptr;
if (mRes) {
@ -260,26 +318,33 @@ private:
nsRefPtr<BluetoothProfileResultHandler> mRes;
};
class BluetoothA2dpManager::CleanupResultHandlerRunnable final
class BluetoothA2dpManager::DeinitProfileResultHandlerRunnable final
: public nsRunnable
{
public:
CleanupResultHandlerRunnable(BluetoothProfileResultHandler* aRes)
DeinitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
nsresult aRv)
: mRes(aRes)
{ }
, mRv(aRv)
{
MOZ_ASSERT(mRes);
}
NS_IMETHOD Run() override
{
sBtA2dpInterface = nullptr;
MOZ_ASSERT(NS_IsMainThread());
if (mRes) {
if (NS_SUCCEEDED(mRv)) {
mRes->Deinit();
} else {
mRes->OnError(mRv);
}
return NS_OK;
}
private:
nsRefPtr<BluetoothProfileResultHandler> mRes;
nsresult mRv;
};
// static
@ -288,16 +353,45 @@ BluetoothA2dpManager::DeinitA2dpInterface(BluetoothProfileResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
if (sBtA2dpInterface) {
sBtA2dpInterface->Cleanup(new CleanupResultHandler(aRes));
} else if (aRes) {
// We dispatch a runnable here to make the profile resource handler
// behave as if A2DP was initialized.
nsRefPtr<nsRunnable> r = new CleanupResultHandlerRunnable(aRes);
if (!sBtA2dpInterface) {
BT_LOGR("Bluetooth A2DP interface has not been initalized.");
nsRefPtr<nsRunnable> r =
new DeinitProfileResultHandlerRunnable(aRes, NS_OK);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch cleanup-result-handler runnable");
BT_LOGR("Failed to dispatch A2DP Deinit runnable");
}
return;
}
auto btInf = BluetoothInterface::GetInstance();
if (NS_WARN_IF(!btInf)) {
// If there's no backend interface, we dispatch a runnable
// that calls the profile result handler.
nsRefPtr<nsRunnable> r =
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch A2DP OnError runnable");
}
return;
}
auto setupInterface = btInf->GetBluetoothSetupInterface();
if (NS_WARN_IF(!setupInterface)) {
// If there's no Setup interface, we dispatch a runnable
// that calls the profile result handler.
nsRefPtr<nsRunnable> r =
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch A2DP OnError runnable");
}
return;
}
setupInterface->UnregisterModule(
SETUP_SERVICE_ID_A2DP,
new UnregisterModuleResultHandler(aRes));
}
void

View File

@ -17,6 +17,8 @@ class BluetoothA2dpManager : public BluetoothProfileManagerBase
, public BluetoothA2dpNotificationHandler
{
public:
static const int MAX_NUM_CLIENTS;
BT_DECL_PROFILE_MGR_BASE
virtual void GetName(nsACString& aName)
{
@ -47,12 +49,12 @@ protected:
virtual ~BluetoothA2dpManager();
private:
class CleanupResultHandler;
class CleanupResultHandlerRunnable;
class ConnectResultHandler;
class DeinitProfileResultHandlerRunnable;
class DisconnectResultHandler;
class InitResultHandler;
class OnErrorProfileResultHandlerRunnable;
class InitProfileResultHandlerRunnable;
class RegisterModuleResultHandler;
class UnregisterModuleResultHandler;
BluetoothA2dpManager();

View File

@ -35,6 +35,8 @@ namespace {
static BluetoothAvrcpInterface* sBtAvrcpInterface;
} // namespace
const int BluetoothAvrcpManager::MAX_NUM_CLIENTS = 1;
/*
* This function maps attribute id and returns corresponding values
*/
@ -118,18 +120,27 @@ BluetoothAvrcpManager::Reset()
mPlayStatus = ControlPlayStatus::PLAYSTATUS_STOPPED;
}
class BluetoothAvrcpManager::InitResultHandler final
: public BluetoothAvrcpResultHandler
class BluetoothAvrcpManager::RegisterModuleResultHandler final
: public BluetoothSetupResultHandler
{
public:
InitResultHandler(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
{ }
RegisterModuleResultHandler(BluetoothAvrcpInterface* aInterface,
BluetoothProfileResultHandler* aRes)
: mInterface(aInterface)
, mRes(aRes)
{
MOZ_ASSERT(mInterface);
}
void OnError(BluetoothStatus aStatus) override
{
BT_WARNING("BluetoothAvrcpInterface::Init failed: %d",
MOZ_ASSERT(NS_IsMainThread());
BT_WARNING("BluetoothSetupInterface::RegisterModule failed for AVRCP: %d",
(int)aStatus);
mInterface->SetNotificationHandler(nullptr);
if (mRes) {
if (aStatus == STATUS_UNSUPPORTED) {
/* Not all versions of Bluedroid support AVRCP. So if the
@ -143,23 +154,28 @@ public:
}
}
void Init() override
void RegisterModule() override
{
MOZ_ASSERT(NS_IsMainThread());
sBtAvrcpInterface = mInterface;
if (mRes) {
mRes->Init();
}
}
private:
BluetoothAvrcpInterface* mInterface;
nsRefPtr<BluetoothProfileResultHandler> mRes;
};
class BluetoothAvrcpManager::OnErrorProfileResultHandlerRunnable final
class BluetoothAvrcpManager::InitProfileResultHandlerRunnable final
: public nsRunnable
{
public:
OnErrorProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
nsresult aRv)
InitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
nsresult aRv)
: mRes(aRes)
, mRv(aRv)
{
@ -168,7 +184,13 @@ public:
NS_IMETHOD Run() override
{
mRes->OnError(mRv);
MOZ_ASSERT(NS_IsMainThread());
if (NS_SUCCEEDED(mRv)) {
mRes->Init();
} else {
mRes->OnError(mRv);
}
return NS_OK;
}
@ -184,32 +206,64 @@ private:
void
BluetoothAvrcpManager::InitAvrcpInterface(BluetoothProfileResultHandler* aRes)
{
BluetoothInterface* btInf = BluetoothInterface::GetInstance();
if (NS_WARN_IF(!btInf)) {
// If there's no HFP interface, we dispatch a runnable
// that calls the profile result handler.
MOZ_ASSERT(NS_IsMainThread());
if (sBtAvrcpInterface) {
BT_LOGR("Bluetooth AVRCP interface is already initalized.");
nsRefPtr<nsRunnable> r =
new OnErrorProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
new InitProfileResultHandlerRunnable(aRes, NS_OK);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch HFP OnError runnable");
BT_LOGR("Failed to dispatch AVRCP Init runnable");
}
return;
}
sBtAvrcpInterface = btInf->GetBluetoothAvrcpInterface();
if (NS_WARN_IF(!sBtAvrcpInterface)) {
auto btInf = BluetoothInterface::GetInstance();
if (NS_WARN_IF(!btInf)) {
// If there's no Bluetooth interface, we dispatch a runnable
// that calls the profile result handler.
nsRefPtr<nsRunnable> r =
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch AVRCP OnError runnable");
}
return;
}
auto setupInterface = btInf->GetBluetoothSetupInterface();
if (NS_WARN_IF(!setupInterface)) {
// If there's no Setup interface, we dispatch a runnable
// that calls the profile result handler.
nsRefPtr<nsRunnable> r =
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch AVRCP OnError runnable");
}
return;
}
auto avrcpInterface = btInf->GetBluetoothAvrcpInterface();
if (NS_WARN_IF(!avrcpInterface)) {
// If there's no AVRCP interface, we dispatch a runnable
// that calls the profile result handler.
nsRefPtr<nsRunnable> r =
new OnErrorProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch HFP OnError runnable");
BT_LOGR("Failed to dispatch AVRCP OnError runnable");
}
return;
}
BluetoothAvrcpManager* avrcpManager = BluetoothAvrcpManager::Get();
sBtAvrcpInterface->Init(avrcpManager, new InitResultHandler(aRes));
// Set notification handler _before_ registering the module. It could
// happen that we receive notifications, before the result handler runs.
avrcpInterface->SetNotificationHandler(BluetoothAvrcpManager::Get());
setupInterface->RegisterModule(
SETUP_SERVICE_ID_AVRCP, 0, MAX_NUM_CLIENTS,
new RegisterModuleResultHandler(avrcpInterface, aRes));
}
BluetoothAvrcpManager::~BluetoothAvrcpManager()
@ -245,37 +299,36 @@ BluetoothAvrcpManager::Get()
return sBluetoothAvrcpManager;
}
class BluetoothAvrcpManager::CleanupResultHandler final
: public BluetoothAvrcpResultHandler
class BluetoothAvrcpManager::UnregisterModuleResultHandler final
: public BluetoothSetupResultHandler
{
public:
CleanupResultHandler(BluetoothProfileResultHandler* aRes)
UnregisterModuleResultHandler(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
{ }
void OnError(BluetoothStatus aStatus) override
{
BT_WARNING("BluetoothAvrcpInterface::Cleanup failed: %d",
MOZ_ASSERT(NS_IsMainThread());
BT_WARNING("BluetoothSetupInterface::UnregisterModule failed for AVRCP: %d",
(int)aStatus);
sBtAvrcpInterface->SetNotificationHandler(nullptr);
sBtAvrcpInterface = nullptr;
if (mRes) {
if (aStatus == STATUS_UNSUPPORTED) {
/* Not all versions of Bluedroid support AVRCP. So if the
* cleanup fails with STATUS_UNSUPPORTED, we still signal
* success.
*/
mRes->Deinit();
} else {
mRes->OnError(NS_ERROR_FAILURE);
}
mRes->OnError(NS_ERROR_FAILURE);
}
}
void Cleanup() override
void UnregisterModule() override
{
MOZ_ASSERT(NS_IsMainThread());
sBtAvrcpInterface->SetNotificationHandler(nullptr);
sBtAvrcpInterface = nullptr;
if (mRes) {
mRes->Deinit();
}
@ -285,25 +338,33 @@ private:
nsRefPtr<BluetoothProfileResultHandler> mRes;
};
class BluetoothAvrcpManager::CleanupResultHandlerRunnable final
class BluetoothAvrcpManager::DeinitProfileResultHandlerRunnable final
: public nsRunnable
{
public:
CleanupResultHandlerRunnable(BluetoothProfileResultHandler* aRes)
DeinitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
nsresult aRv)
: mRes(aRes)
, mRv(aRv)
{
MOZ_ASSERT(mRes);
}
NS_IMETHOD Run() override
{
mRes->Deinit();
MOZ_ASSERT(NS_IsMainThread());
if (NS_SUCCEEDED(mRv)) {
mRes->Deinit();
} else {
mRes->OnError(mRv);
}
return NS_OK;
}
private:
nsRefPtr<BluetoothProfileResultHandler> mRes;
nsresult mRv;
};
// static
@ -312,16 +373,45 @@ BluetoothAvrcpManager::DeinitAvrcpInterface(BluetoothProfileResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
if (sBtAvrcpInterface) {
sBtAvrcpInterface->Cleanup(new CleanupResultHandler(aRes));
} else if (aRes) {
// We dispatch a runnable here to make the profile resource handler
// behave as if AVRCP was initialized.
nsRefPtr<nsRunnable> r = new CleanupResultHandlerRunnable(aRes);
if (!sBtAvrcpInterface) {
BT_LOGR("Bluetooth AVRCP interface has not been initalized.");
nsRefPtr<nsRunnable> r =
new DeinitProfileResultHandlerRunnable(aRes, NS_OK);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch cleanup-result-handler runnable");
BT_LOGR("Failed to dispatch AVRCP Deinit runnable");
}
return;
}
auto btInf = BluetoothInterface::GetInstance();
if (NS_WARN_IF(!btInf)) {
// If there's no backend interface, we dispatch a runnable
// that calls the profile result handler.
nsRefPtr<nsRunnable> r =
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch AVRCP OnError runnable");
}
return;
}
auto setupInterface = btInf->GetBluetoothSetupInterface();
if (NS_WARN_IF(!setupInterface)) {
// If there's no Setup interface, we dispatch a runnable
// that calls the profile result handler.
nsRefPtr<nsRunnable> r =
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch AVRCP OnError runnable");
}
return;
}
setupInterface->UnregisterModule(
SETUP_SERVICE_ID_AVRCP,
new UnregisterModuleResultHandler(aRes));
}
void

View File

@ -17,6 +17,8 @@ class BluetoothAvrcpManager : public BluetoothProfileManagerBase
, public BluetoothAvrcpNotificationHandler
{
public:
static const int MAX_NUM_CLIENTS;
BT_DECL_PROFILE_MGR_BASE
virtual void GetName(nsACString& aName)
{
@ -60,12 +62,12 @@ protected:
virtual ~BluetoothAvrcpManager();
private:
class CleanupResultHandler;
class CleanupResultHandlerRunnable;
class ConnectRunnable;
class DeinitProfileResultHandlerRunnable;
class DisconnectRunnable;
class InitResultHandler;
class OnErrorProfileResultHandlerRunnable;
class InitProfileResultHandlerRunnable;
class RegisterModuleResultHandler;
class UnregisterModuleResultHandler;
BluetoothAvrcpManager();

View File

@ -15,8 +15,6 @@ using namespace mozilla::ipc;
// A2DP module
//
const int BluetoothDaemonA2dpModule::MAX_NUM_CLIENTS = 1;
BluetoothA2dpNotificationHandler*
BluetoothDaemonA2dpModule::sNotificationHandler;
@ -235,109 +233,13 @@ BluetoothDaemonA2dpInterface::BluetoothDaemonA2dpInterface(
BluetoothDaemonA2dpInterface::~BluetoothDaemonA2dpInterface()
{ }
class BluetoothDaemonA2dpInterface::InitResultHandler final
: public BluetoothSetupResultHandler
{
public:
InitResultHandler(BluetoothA2dpResultHandler* aRes)
: mRes(aRes)
{
MOZ_ASSERT(mRes);
}
void OnError(BluetoothStatus aStatus) override
{
MOZ_ASSERT(NS_IsMainThread());
mRes->OnError(aStatus);
}
void RegisterModule() override
{
MOZ_ASSERT(NS_IsMainThread());
mRes->Init();
}
private:
nsRefPtr<BluetoothA2dpResultHandler> mRes;
};
void
BluetoothDaemonA2dpInterface::Init(
BluetoothA2dpNotificationHandler* aNotificationHandler,
BluetoothA2dpResultHandler* aRes)
BluetoothDaemonA2dpInterface::SetNotificationHandler(
BluetoothA2dpNotificationHandler* aNotificationHandler)
{
// Set notification handler _before_ registering the module. It could
// happen that we receive notifications, before the result handler runs.
MOZ_ASSERT(mModule);
mModule->SetNotificationHandler(aNotificationHandler);
InitResultHandler* res;
if (aRes) {
res = new InitResultHandler(aRes);
} else {
// We don't need a result handler if the caller is not interested.
res = nullptr;
}
nsresult rv = mModule->RegisterModule(BluetoothDaemonA2dpModule::SERVICE_ID,
0x00, BluetoothDaemonA2dpModule::MAX_NUM_CLIENTS, res);
if (NS_FAILED(rv) && aRes) {
DispatchError(aRes, rv);
}
}
class BluetoothDaemonA2dpInterface::CleanupResultHandler final
: public BluetoothSetupResultHandler
{
public:
CleanupResultHandler(BluetoothDaemonA2dpModule* aModule,
BluetoothA2dpResultHandler* aRes)
: mModule(aModule)
, mRes(aRes)
{
MOZ_ASSERT(mModule);
}
void OnError(BluetoothStatus aStatus) override
{
MOZ_ASSERT(NS_IsMainThread());
if (mRes) {
mRes->OnError(aStatus);
}
}
void UnregisterModule() override
{
MOZ_ASSERT(NS_IsMainThread());
// Clear notification handler _after_ module has been
// unregistered. While unregistering the module, we might
// still receive notifications.
mModule->SetNotificationHandler(nullptr);
if (mRes) {
mRes->Cleanup();
}
}
private:
BluetoothDaemonA2dpModule* mModule;
nsRefPtr<BluetoothA2dpResultHandler> mRes;
};
void
BluetoothDaemonA2dpInterface::Cleanup(
BluetoothA2dpResultHandler* aRes)
{
nsresult rv = mModule->UnregisterModule(
BluetoothDaemonA2dpModule::SERVICE_ID,
new CleanupResultHandler(mModule, aRes));
if (NS_FAILED(rv)) {
DispatchError(aRes, rv);
}
}
/* Connect / Disconnect */

View File

@ -30,18 +30,9 @@ public:
OPCODE_DISCONNECT = 0x02
};
static const int MAX_NUM_CLIENTS;
virtual nsresult Send(DaemonSocketPDU* aPDU,
DaemonSocketResultHandler* aRes) = 0;
virtual nsresult RegisterModule(uint8_t aId, uint8_t aMode,
uint32_t aMaxNumClients,
BluetoothSetupResultHandler* aRes) = 0;
virtual nsresult UnregisterModule(uint8_t aId,
BluetoothSetupResultHandler* aRes) = 0;
void SetNotificationHandler(
BluetoothA2dpNotificationHandler* aNotificationHandler);
@ -129,17 +120,12 @@ protected:
class BluetoothDaemonA2dpInterface final
: public BluetoothA2dpInterface
{
class CleanupResultHandler;
class InitResultHandler;
public:
BluetoothDaemonA2dpInterface(BluetoothDaemonA2dpModule* aModule);
~BluetoothDaemonA2dpInterface();
void Init(
BluetoothA2dpNotificationHandler* aNotificationHandler,
BluetoothA2dpResultHandler* aRes) override;
void Cleanup(BluetoothA2dpResultHandler* aRes) override;
void SetNotificationHandler(
BluetoothA2dpNotificationHandler* aNotificationHandler) override;
/* Connect / Disconnect */

View File

@ -15,8 +15,6 @@ using namespace mozilla::ipc;
// AVRCP module
//
const int BluetoothDaemonAvrcpModule::MAX_NUM_CLIENTS = 1;
BluetoothAvrcpNotificationHandler*
BluetoothDaemonAvrcpModule::sNotificationHandler;
@ -805,115 +803,13 @@ BluetoothDaemonAvrcpInterface::BluetoothDaemonAvrcpInterface(
BluetoothDaemonAvrcpInterface::~BluetoothDaemonAvrcpInterface()
{ }
class BluetoothDaemonAvrcpInterface::InitResultHandler final
: public BluetoothSetupResultHandler
{
public:
InitResultHandler(BluetoothAvrcpResultHandler* aRes)
: mRes(aRes)
{
MOZ_ASSERT(mRes);
}
void OnError(BluetoothStatus aStatus) override
{
MOZ_ASSERT(NS_IsMainThread());
mRes->OnError(aStatus);
}
void RegisterModule() override
{
MOZ_ASSERT(NS_IsMainThread());
mRes->Init();
}
private:
nsRefPtr<BluetoothAvrcpResultHandler> mRes;
};
void
BluetoothDaemonAvrcpInterface::Init(
BluetoothAvrcpNotificationHandler* aNotificationHandler,
BluetoothAvrcpResultHandler* aRes)
BluetoothDaemonAvrcpInterface::SetNotificationHandler(
BluetoothAvrcpNotificationHandler* aNotificationHandler)
{
MOZ_ASSERT(mModule);
// Set notification handler _before_ registering the module. It could
// happen that we receive notifications, before the result handler runs.
mModule->SetNotificationHandler(aNotificationHandler);
InitResultHandler* res;
if (aRes) {
res = new InitResultHandler(aRes);
} else {
// We don't need a result handler if the caller is not interested.
res = nullptr;
}
nsresult rv = mModule->RegisterModule(
BluetoothDaemonAvrcpModule::SERVICE_ID,
BluetoothDaemonAvrcpModule::MAX_NUM_CLIENTS, 0x00, res);
if (NS_FAILED(rv) && aRes) {
DispatchError(aRes, rv);
}
}
class BluetoothDaemonAvrcpInterface::CleanupResultHandler final
: public BluetoothSetupResultHandler
{
public:
CleanupResultHandler(BluetoothDaemonAvrcpModule* aModule,
BluetoothAvrcpResultHandler* aRes)
: mModule(aModule)
, mRes(aRes)
{
MOZ_ASSERT(mModule);
}
void OnError(BluetoothStatus aStatus) override
{
MOZ_ASSERT(NS_IsMainThread());
if (mRes) {
mRes->OnError(aStatus);
}
}
void UnregisterModule() override
{
MOZ_ASSERT(NS_IsMainThread());
// Clear notification handler _after_ module has been
// unregistered. While unregistering the module, we might
// still receive notifications.
mModule->SetNotificationHandler(nullptr);
if (mRes) {
mRes->Cleanup();
}
}
private:
BluetoothDaemonAvrcpModule* mModule;
nsRefPtr<BluetoothAvrcpResultHandler> mRes;
};
void
BluetoothDaemonAvrcpInterface::Cleanup(
BluetoothAvrcpResultHandler* aRes)
{
MOZ_ASSERT(mModule);
nsresult rv = mModule->UnregisterModule(
BluetoothDaemonAvrcpModule::SERVICE_ID,
new CleanupResultHandler(mModule, aRes));
if (NS_FAILED(rv)) {
DispatchError(aRes, rv);
}
}
void

View File

@ -62,18 +62,9 @@ public:
#endif
};
static const int MAX_NUM_CLIENTS;
virtual nsresult Send(DaemonSocketPDU* aPDU,
DaemonSocketResultHandler* aRes) = 0;
virtual nsresult RegisterModule(uint8_t aId, uint8_t aMode,
uint32_t aMaxNumClients,
BluetoothSetupResultHandler* aRes) = 0;
virtual nsresult UnregisterModule(uint8_t aId,
BluetoothSetupResultHandler* aRes) = 0;
void SetNotificationHandler(
BluetoothAvrcpNotificationHandler* aNotificationHandler);
@ -305,10 +296,8 @@ public:
BluetoothDaemonAvrcpInterface(BluetoothDaemonAvrcpModule* aModule);
~BluetoothDaemonAvrcpInterface();
void Init(BluetoothAvrcpNotificationHandler* aNotificationHandler,
BluetoothAvrcpResultHandler* aRes) override;
void Cleanup(BluetoothAvrcpResultHandler* aRes) override;
void SetNotificationHandler(
BluetoothAvrcpNotificationHandler* aNotificationHandler) override;
void GetPlayStatusRsp(ControlPlayStatus aPlayStatus,
uint32_t aSongLen, uint32_t aSongPos,

View File

@ -15,8 +15,6 @@ using namespace mozilla::ipc;
// GATT module
//
const int BluetoothDaemonGattModule::MAX_NUM_CLIENTS = 1;
BluetoothGattNotificationHandler*
BluetoothDaemonGattModule::sNotificationHandler;
@ -2010,6 +2008,7 @@ BluetoothDaemonGattInterface::BluetoothDaemonGattInterface(
BluetoothDaemonGattInterface::~BluetoothDaemonGattInterface()
{ }
#if 0
class BluetoothDaemonGattInterface::InitResultHandler final
: public BluetoothSetupResultHandler
{
@ -2057,8 +2056,8 @@ BluetoothDaemonGattInterface::Init(
}
nsresult rv = mModule->RegisterModule(
BluetoothDaemonGattModule::SERVICE_ID, 0x00,
BluetoothDaemonGattModule::MAX_NUM_CLIENTS, res);
SETUP_SERVICE_ID_GATT, 0x00, BluetoothDaemonGattModule::MAX_NUM_CLIENTS,
res);
if (NS_FAILED(rv) && aRes) {
DispatchError(aRes, rv);
@ -2110,12 +2109,21 @@ BluetoothDaemonGattInterface::Cleanup(
BluetoothGattResultHandler* aRes)
{
nsresult rv = mModule->UnregisterModule(
BluetoothDaemonGattModule::SERVICE_ID,
new CleanupResultHandler(mModule, aRes));
SETUP_SERVICE_ID_GATT, new CleanupResultHandler(mModule, aRes));
if (NS_FAILED(rv)) {
DispatchError(aRes, rv);
}
}
#endif
void
BluetoothDaemonGattInterface::SetNotificationHandler(
BluetoothGattNotificationHandler* aNotificationHandler)
{
MOZ_ASSERT(mModule);
mModule->SetNotificationHandler(aNotificationHandler);
}
/* Register / Unregister */
void

View File

@ -64,18 +64,9 @@ public:
// TODO: Add L support
};
static const int MAX_NUM_CLIENTS;
virtual nsresult Send(DaemonSocketPDU* aPDU,
DaemonSocketResultHandler* aRes) = 0;
virtual nsresult RegisterModule(uint8_t aId, uint8_t aMode,
uint32_t aMaxNumClients,
BluetoothSetupResultHandler* aRes) = 0;
virtual nsresult UnregisterModule(uint8_t aId,
BluetoothSetupResultHandler* aRes) = 0;
void SetNotificationHandler(
BluetoothGattNotificationHandler* aNotificationHandler);
@ -798,9 +789,8 @@ public:
BluetoothDaemonGattInterface(BluetoothDaemonGattModule* aModule);
~BluetoothDaemonGattInterface();
void Init(BluetoothGattNotificationHandler* aNotificationHandler,
BluetoothGattResultHandler* aRes) override;
void Cleanup(BluetoothGattResultHandler* aRes) override;
void SetNotificationHandler(
BluetoothGattNotificationHandler* aNotificationHandler) override;
/* Register / Unregister */
void RegisterClient(const BluetoothUuid& aUuid,

View File

@ -1409,115 +1409,12 @@ BluetoothDaemonHandsfreeInterface::BluetoothDaemonHandsfreeInterface(
BluetoothDaemonHandsfreeInterface::~BluetoothDaemonHandsfreeInterface()
{ }
class BluetoothDaemonHandsfreeInterface::InitResultHandler final
: public BluetoothSetupResultHandler
void BluetoothDaemonHandsfreeInterface::SetNotificationHandler(
BluetoothHandsfreeNotificationHandler* aNotificationHandler)
{
public:
InitResultHandler(BluetoothHandsfreeResultHandler* aRes)
: mRes(aRes)
{
MOZ_ASSERT(mRes);
}
MOZ_ASSERT(mModule);
void OnError(BluetoothStatus aStatus) override
{
MOZ_ASSERT(NS_IsMainThread());
mRes->OnError(aStatus);
}
void RegisterModule() override
{
MOZ_ASSERT(NS_IsMainThread());
mRes->Init();
}
private:
nsRefPtr<BluetoothHandsfreeResultHandler> mRes;
};
void
BluetoothDaemonHandsfreeInterface::Init(
BluetoothHandsfreeNotificationHandler* aNotificationHandler,
int aMaxNumClients, BluetoothHandsfreeResultHandler* aRes)
{
// Set notification handler _before_ registering the module. It could
// happen that we receive notifications, before the result handler runs.
mModule->SetNotificationHandler(aNotificationHandler);
InitResultHandler* res;
if (aRes) {
res = new InitResultHandler(aRes);
} else {
// We don't need a result handler if the caller is not interested.
res = nullptr;
}
nsresult rv = mModule->RegisterModule(
BluetoothDaemonHandsfreeModule::SERVICE_ID, MODE_NARROWBAND_SPEECH,
aMaxNumClients, res);
if (NS_FAILED(rv) && aRes) {
DispatchError(aRes, rv);
}
}
class BluetoothDaemonHandsfreeInterface::CleanupResultHandler final
: public BluetoothSetupResultHandler
{
public:
CleanupResultHandler(BluetoothDaemonHandsfreeModule* aModule,
BluetoothHandsfreeResultHandler* aRes)
: mModule(aModule)
, mRes(aRes)
{
MOZ_ASSERT(mModule);
}
void OnError(BluetoothStatus aStatus) override
{
MOZ_ASSERT(NS_IsMainThread());
BT_LOGR("%s:%d", __func__, __LINE__);
if (mRes) {
mRes->OnError(aStatus);
}
}
void UnregisterModule() override
{
MOZ_ASSERT(NS_IsMainThread());
BT_LOGR("%s:%d", __func__, __LINE__);
// Clear notification handler _after_ module has been
// unregistered. While unregistering the module, we might
// still receive notifications.
mModule->SetNotificationHandler(nullptr);
if (mRes) {
mRes->Cleanup();
}
}
private:
BluetoothDaemonHandsfreeModule* mModule;
nsRefPtr<BluetoothHandsfreeResultHandler> mRes;
};
void
BluetoothDaemonHandsfreeInterface::Cleanup(
BluetoothHandsfreeResultHandler* aRes)
{
BT_LOGR("%s:%d", __func__, __LINE__);
nsresult rv = mModule->UnregisterModule(
BluetoothDaemonHandsfreeModule::SERVICE_ID,
new CleanupResultHandler(mModule, aRes));
BT_LOGR("%s:%d", __func__, __LINE__);
if (NS_FAILED(rv)) {
DispatchError(aRes, rv);
}
}
/* Connect / Disconnect */

View File

@ -46,13 +46,6 @@ public:
virtual nsresult Send(DaemonSocketPDU* aPDU,
DaemonSocketResultHandler* aRes) = 0;
virtual nsresult RegisterModule(uint8_t aId, uint8_t aMode,
uint32_t aMaxNumClients,
BluetoothSetupResultHandler* aRes) = 0;
virtual nsresult UnregisterModule(uint8_t aId,
BluetoothSetupResultHandler* aRes) = 0;
void SetNotificationHandler(
BluetoothHandsfreeNotificationHandler* aNotificationHandler);
@ -400,23 +393,12 @@ protected:
class BluetoothDaemonHandsfreeInterface final
: public BluetoothHandsfreeInterface
{
class CleanupResultHandler;
class InitResultHandler;
enum {
MODE_HEADSET = 0x00,
MODE_NARROWBAND_SPEECH = 0x01,
MODE_NARRAWBAND_WIDEBAND_SPEECH = 0x02
};
public:
BluetoothDaemonHandsfreeInterface(BluetoothDaemonHandsfreeModule* aModule);
~BluetoothDaemonHandsfreeInterface();
void Init(
BluetoothHandsfreeNotificationHandler* aNotificationHandler,
int aMaxNumClients, BluetoothHandsfreeResultHandler* aRes) override;
void Cleanup(BluetoothHandsfreeResultHandler* aRes) override;
void SetNotificationHandler(
BluetoothHandsfreeNotificationHandler* aNotificationHandler) override;
/* Connect / Disconnect */

View File

@ -841,6 +841,35 @@ Convert(BluetoothScanMode aIn, int32_t& aOut)
return NS_OK;
}
nsresult
Convert(BluetoothSetupServiceId aIn, uint8_t& aOut)
{
static const uint8_t sServiceId[] = {
[SETUP_SERVICE_ID_SETUP] = 0x00,
[SETUP_SERVICE_ID_CORE] = 0x01,
[SETUP_SERVICE_ID_SOCKET] = 0x02,
[SETUP_SERVICE_ID_HID] = 0x03,
[SETUP_SERVICE_ID_PAN] = 0x04,
[SETUP_SERVICE_ID_HANDSFREE] = 0x05,
[SETUP_SERVICE_ID_A2DP] = 0x06,
[SETUP_SERVICE_ID_HEALTH] = 0x07,
[SETUP_SERVICE_ID_AVRCP] = 0x08,
[SETUP_SERVICE_ID_GATT] = 0x09,
[SETUP_SERVICE_ID_HANDSFREE_CLIENT] = 0x0a,
[SETUP_SERVICE_ID_MAP_CLIENT] = 0x0b,
[SETUP_SERVICE_ID_AVRCP_CONTROLLER] = 0x0c,
[SETUP_SERVICE_ID_A2DP_SINK] = 0x0d
};
if (MOZ_HAL_IPC_CONVERT_WARN_IF(
aIn >= MOZ_ARRAY_LENGTH(sServiceId),
BluetoothServiceSetupId, uint8_t)) {
aOut = 0; // silences compiler warning
return NS_ERROR_ILLEGAL_VALUE;
}
aOut = sServiceId[aIn];
return NS_OK;
}
nsresult
Convert(BluetoothSspVariant aIn, uint8_t& aOut)
{
@ -1267,6 +1296,12 @@ PackPDU(BluetoothScanMode aIn, DaemonSocketPDU& aPDU)
return PackPDU(PackConversion<BluetoothScanMode, int32_t>(aIn), aPDU);
}
nsresult
PackPDU(BluetoothSetupServiceId aIn, DaemonSocketPDU& aPDU)
{
return PackPDU(PackConversion<BluetoothSetupServiceId, uint8_t>(aIn), aPDU);
}
nsresult
PackPDU(const BluetoothServiceName& aIn, DaemonSocketPDU& aPDU)
{

View File

@ -97,12 +97,6 @@ struct BluetoothAvrcpEventParamPair {
const BluetoothAvrcpNotificationParam& mParam;
};
struct BluetoothConfigurationParameter {
uint8_t mType;
uint16_t mLength;
nsAutoArrayPtr<uint8_t> mValue;
};
//
// Conversion
//
@ -236,6 +230,9 @@ Convert(BluetoothPropertyType aIn, uint8_t& aOut);
nsresult
Convert(BluetoothScanMode aIn, uint8_t& aOut);
nsresult
Convert(BluetoothSetupServiceId aIn, uint8_t& aOut);
nsresult
Convert(BluetoothSocketType aIn, uint8_t& aOut);
@ -335,6 +332,9 @@ PackPDU(BluetoothPropertyType aIn, DaemonSocketPDU& aPDU);
nsresult
PackPDU(const BluetoothServiceName& aIn, DaemonSocketPDU& aPDU);
nsresult
PackPDU(BluetoothSetupServiceId aIn, DaemonSocketPDU& aPDU);
nsresult
PackPDU(BluetoothSocketType aIn, DaemonSocketPDU& aPDU);

View File

@ -39,24 +39,14 @@ static const int sRetryInterval = 100; // ms
//
// Each |BluetoothDaemon*Module| class implements an individual
// module of the HAL protocol. Each class contains the abstract
// methods
// method
//
// - |Send|,
// - |RegisterModule|, and
// - |UnregisterModule|.
// - |Send|.
//
// Module classes use |Send| to send out command PDUs. The socket
// in |BluetoothDaemonProtocol| is required for sending. The abstract
// method hides all these internal details from the modules.
//
// |RegisterModule| is required during module initialization, when
// modules must register themselves at the daemon. The register command
// is not part of the module itself, but contained in the Setup module
// (id of 0x00). The abstract method |RegisterModule| allows modules to
// call into the Setup module for generating the register command.
//
// |UnregisterModule| works like |RegisterModule|, but for cleanups.
//
// |BluetoothDaemonProtocol| also handles PDU receiving. It implements
// the method |Handle| from |DaemonSocketIOConsumer|. The socket
// connections of type |DaemonSocket| invoke this method
@ -66,11 +56,9 @@ static const int sRetryInterval = 100; // ms
// |HandleSvc|. Further PDU processing is module-dependent.
//
// To summarize the interface between |BluetoothDaemonProtocol| and
// modules; the former implements the abstract methods
// modules; the former implements the abstract method
//
// - |Send|,
// - |RegisterModule|, and
// - |UnregisterModule|,
//
// which allow modules to send out data. Each module implements the
// method
@ -95,12 +83,6 @@ public:
void SetConnection(DaemonSocket* aConnection);
nsresult RegisterModule(uint8_t aId, uint8_t aMode, uint32_t aMaxNumClients,
BluetoothSetupResultHandler* aRes) override;
nsresult UnregisterModule(uint8_t aId,
BluetoothSetupResultHandler* aRes) override;
// Outgoing PDUs
//
@ -153,22 +135,6 @@ BluetoothDaemonProtocol::SetConnection(DaemonSocket* aConnection)
mConnection = aConnection;
}
nsresult
BluetoothDaemonProtocol::RegisterModule(uint8_t aId, uint8_t aMode,
uint32_t aMaxNumClients,
BluetoothSetupResultHandler* aRes)
{
return BluetoothDaemonSetupModule::RegisterModuleCmd(aId, aMode,
aMaxNumClients, aRes);
}
nsresult
BluetoothDaemonProtocol::UnregisterModule(uint8_t aId,
BluetoothSetupResultHandler* aRes)
{
return BluetoothDaemonSetupModule::UnregisterModuleCmd(aId, aRes);
}
nsresult
BluetoothDaemonProtocol::Send(DaemonSocketPDU* aPDU,
DaemonSocketResultHandler* aRes)
@ -422,7 +388,9 @@ public:
if (!mRegisteredSocketModule) {
mRegisteredSocketModule = true;
// Init, step 5: Register Socket module
mInterface->mProtocol->RegisterModuleCmd(0x02, 0x00,
mInterface->mProtocol->RegisterModuleCmd(
SETUP_SERVICE_ID_SOCKET,
0x00,
BluetoothDaemonSocketModule::MAX_NUM_CLIENTS, this);
} else if (mRes) {
// Init, step 6: Signal success to caller
@ -556,7 +524,7 @@ private:
if (!mUnregisteredCoreModule) {
mUnregisteredCoreModule = true;
// Cleanup, step 2: Unregister Core module
mInterface->mProtocol->UnregisterModuleCmd(0x01, this);
mInterface->mProtocol->UnregisterModuleCmd(SETUP_SERVICE_ID_CORE, this);
} else {
// Cleanup, step 3: Close command channel
mInterface->mCmdChannel->Close();
@ -600,7 +568,7 @@ BluetoothDaemonInterface::Cleanup(BluetoothResultHandler* aRes)
// Cleanup, step 1: Unregister Socket module
nsresult rv = mProtocol->UnregisterModuleCmd(
0x02, new CleanupResultHandler(this));
SETUP_SERVICE_ID_SOCKET, new CleanupResultHandler(this));
if (NS_FAILED(rv)) {
DispatchError(aRes, rv);
return;
@ -889,9 +857,21 @@ BluetoothDaemonInterface::DispatchError(BluetoothResultHandler* aRes,
DispatchError(aRes, status);
}
// Profile Interfaces
// Service Interfaces
//
BluetoothSetupInterface*
BluetoothDaemonInterface::GetBluetoothSetupInterface()
{
if (mSetupInterface) {
return mSetupInterface;
}
mSetupInterface = new BluetoothDaemonSetupInterface(mProtocol);
return mSetupInterface;
}
BluetoothSocketInterface*
BluetoothDaemonInterface::GetBluetoothSocketInterface()
{
@ -1002,7 +982,9 @@ BluetoothDaemonInterface::OnConnectSuccess(int aIndex)
// Init, step 4: Register Core module
nsresult rv = mProtocol->RegisterModuleCmd(
0x01, 0x00, BluetoothDaemonCoreModule::MAX_NUM_CLIENTS,
SETUP_SERVICE_ID_CORE,
0x00,
BluetoothDaemonCoreModule::MAX_NUM_CLIENTS,
new InitResultHandler(this, res));
if (NS_FAILED(rv) && res) {
DispatchError(res, STATUS_FAIL);

View File

@ -27,6 +27,7 @@ class BluetoothDaemonAvrcpInterface;
class BluetoothDaemonGattInterface;
class BluetoothDaemonHandsfreeInterface;
class BluetoothDaemonProtocol;
class BluetoothDaemonSetupInterface;
class BluetoothDaemonSocketInterface;
class BluetoothDaemonInterface final
@ -125,8 +126,9 @@ public:
void ReadEnergyInfo(BluetoothResultHandler* aRes) override;
/* Profile Interfaces */
/* Service Interfaces */
BluetoothSetupInterface* GetBluetoothSetupInterface() override;
BluetoothSocketInterface* GetBluetoothSocketInterface() override;
BluetoothHandsfreeInterface* GetBluetoothHandsfreeInterface() override;
BluetoothA2dpInterface* GetBluetoothA2dpInterface() override;
@ -162,6 +164,7 @@ private:
nsTArray<nsRefPtr<BluetoothResultHandler> > mResultHandlerQ;
nsAutoPtr<BluetoothDaemonSetupInterface> mSetupInterface;
nsAutoPtr<BluetoothDaemonSocketInterface> mSocketInterface;
nsAutoPtr<BluetoothDaemonHandsfreeInterface> mHandsfreeInterface;
nsAutoPtr<BluetoothDaemonA2dpInterface> mA2dpInterface;

View File

@ -9,6 +9,8 @@
BEGIN_BLUETOOTH_NAMESPACE
using namespace mozilla::ipc;
//
// Setup module
//
@ -54,7 +56,7 @@ BluetoothDaemonSetupModule::HandleSvc(const DaemonSocketPDUHeader& aHeader,
nsresult
BluetoothDaemonSetupModule::RegisterModuleCmd(
uint8_t aId, uint8_t aMode, uint32_t aMaxNumClients,
BluetoothSetupServiceId aId, uint8_t aMode, uint32_t aMaxNumClients,
BluetoothSetupResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
@ -81,7 +83,7 @@ BluetoothDaemonSetupModule::RegisterModuleCmd(
nsresult
BluetoothDaemonSetupModule::UnregisterModuleCmd(
uint8_t aId, BluetoothSetupResultHandler* aRes)
BluetoothSetupServiceId aId, BluetoothSetupResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
@ -167,4 +169,77 @@ BluetoothDaemonSetupModule::ConfigurationRsp(
UnpackPDUInitOp(aPDU));
}
//
// Setup interface
//
BluetoothDaemonSetupInterface::BluetoothDaemonSetupInterface(
BluetoothDaemonSetupModule* aModule)
: mModule(aModule)
{ }
BluetoothDaemonSetupInterface::~BluetoothDaemonSetupInterface()
{ }
void
BluetoothDaemonSetupInterface::RegisterModule(
BluetoothSetupServiceId aId, uint8_t aMode, uint32_t aMaxNumClients,
BluetoothSetupResultHandler* aRes)
{
MOZ_ASSERT(mModule);
nsresult rv = mModule->RegisterModuleCmd(aId, aMode, aMaxNumClients, aRes);
if (NS_FAILED(rv)) {
DispatchError(aRes, rv);
}
}
void
BluetoothDaemonSetupInterface::UnregisterModule(
BluetoothSetupServiceId aId,
BluetoothSetupResultHandler* aRes)
{
MOZ_ASSERT(mModule);
nsresult rv = mModule->UnregisterModuleCmd(aId, aRes);
if (NS_FAILED(rv)) {
DispatchError(aRes, rv);
}
}
void
BluetoothDaemonSetupInterface::Configuration(
const BluetoothConfigurationParameter* aParam, uint8_t aLen,
BluetoothSetupResultHandler* aRes)
{
MOZ_ASSERT(mModule);
nsresult rv = mModule->ConfigurationCmd(aParam, aLen, aRes);
if (NS_FAILED(rv)) {
DispatchError(aRes, rv);
}
}
void
BluetoothDaemonSetupInterface::DispatchError(
BluetoothSetupResultHandler* aRes, BluetoothStatus aStatus)
{
DaemonResultRunnable1<BluetoothSetupResultHandler, void,
BluetoothStatus, BluetoothStatus>::Dispatch(
aRes, &BluetoothSetupResultHandler::OnError,
ConstantInitOp1<BluetoothStatus>(aStatus));
}
void
BluetoothDaemonSetupInterface::DispatchError(
BluetoothSetupResultHandler* aRes, nsresult aRv)
{
BluetoothStatus status;
if (NS_WARN_IF(NS_FAILED(Convert(aRv, status)))) {
status = STATUS_FAIL;
}
DispatchError(aRes, status);
}
END_BLUETOOTH_NAMESPACE

View File

@ -37,11 +37,11 @@ public:
// Commands
//
nsresult RegisterModuleCmd(uint8_t aId, uint8_t aMode,
nsresult RegisterModuleCmd(BluetoothSetupServiceId aId, uint8_t aMode,
uint32_t aMaxNumClients,
BluetoothSetupResultHandler* aRes);
nsresult UnregisterModuleCmd(uint8_t aId,
nsresult UnregisterModuleCmd(BluetoothSetupServiceId aId,
BluetoothSetupResultHandler* aRes);
nsresult ConfigurationCmd(const BluetoothConfigurationParameter* aParam,
@ -86,6 +86,32 @@ private:
BluetoothSetupResultHandler* aRes);
};
class BluetoothDaemonSetupInterface final
: public BluetoothSetupInterface
{
public:
BluetoothDaemonSetupInterface(BluetoothDaemonSetupModule* aModule);
~BluetoothDaemonSetupInterface();
void RegisterModule(BluetoothSetupServiceId aId, uint8_t aMode,
uint32_t aMaxNumClients,
BluetoothSetupResultHandler* aRes) override;
void UnregisterModule(BluetoothSetupServiceId aId,
BluetoothSetupResultHandler* aRes) override;
void Configuration(const BluetoothConfigurationParameter* aParam,
uint8_t aLen,
BluetoothSetupResultHandler* aRes) override;
private:
void DispatchError(BluetoothSetupResultHandler* aRes,
BluetoothStatus aStatus);
void DispatchError(BluetoothSetupResultHandler* aRes, nsresult aRv);
BluetoothDaemonSetupModule* mModule;
};
END_BLUETOOTH_NAMESPACE
#endif // mozilla_dom_bluetooth_bluedroid_BluetoothDaemonSetupInterface_h

View File

@ -37,6 +37,8 @@ namespace {
static BluetoothGattInterface* sBluetoothGattInterface;
} // namespace
const int BluetoothGattManager::MAX_NUM_CLIENTS = 1;
bool BluetoothGattManager::mInShutdown = false;
static StaticAutoPtr<nsTArray<nsRefPtr<BluetoothGattClient> > > sClients;
@ -376,52 +378,126 @@ BluetoothGattManager::Get()
return sBluetoothGattManager;
}
class BluetoothGattManager::InitGattResultHandler final
: public BluetoothGattResultHandler
class BluetoothGattManager::RegisterModuleResultHandler final
: public BluetoothSetupResultHandler
{
public:
InitGattResultHandler(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
RegisterModuleResultHandler(BluetoothGattInterface* aInterface,
BluetoothProfileResultHandler* aRes)
: mInterface(aInterface)
, mRes(aRes)
{ }
void OnError(BluetoothStatus aStatus) override
{
BT_WARNING("BluetoothGattInterface::Init failed: %d",
MOZ_ASSERT(NS_IsMainThread());
BT_WARNING("BluetoothSetupInterface::RegisterModule failed for GATT: %d",
(int)aStatus);
mInterface->SetNotificationHandler(nullptr);
if (mRes) {
mRes->OnError(NS_ERROR_FAILURE);
}
}
void Init() override
void RegisterModule() override
{
MOZ_ASSERT(NS_IsMainThread());
sBluetoothGattInterface = mInterface;
if (mRes) {
mRes->Init();
}
}
private:
BluetoothGattInterface* mInterface;
nsRefPtr<BluetoothProfileResultHandler> mRes;
};
class BluetoothGattManager::InitProfileResultHandlerRunnable final
: public nsRunnable
{
public:
InitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
nsresult aRv)
: mRes(aRes)
, mRv(aRv)
{
MOZ_ASSERT(mRes);
}
NS_IMETHOD Run() override
{
MOZ_ASSERT(NS_IsMainThread());
if (NS_SUCCEEDED(mRv)) {
mRes->Init();
} else {
mRes->OnError(mRv);
}
return NS_OK;
}
private:
nsRefPtr<BluetoothProfileResultHandler> mRes;
nsresult mRv;
};
// static
void
BluetoothGattManager::InitGattInterface(BluetoothProfileResultHandler* aRes)
{
BluetoothInterface* btInf = BluetoothInterface::GetInstance();
if (!btInf) {
BT_LOGR("Error: Bluetooth interface not available");
if (aRes) {
aRes->OnError(NS_ERROR_FAILURE);
MOZ_ASSERT(NS_IsMainThread());
if (sBluetoothGattInterface) {
BT_LOGR("Bluetooth GATT interface is already initalized.");
nsRefPtr<nsRunnable> r =
new InitProfileResultHandlerRunnable(aRes, NS_OK);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch GATT Init runnable");
}
return;
}
sBluetoothGattInterface = btInf->GetBluetoothGattInterface();
if (!sBluetoothGattInterface) {
BT_LOGR("Error: Bluetooth GATT interface not available");
if (aRes) {
aRes->OnError(NS_ERROR_FAILURE);
auto btInf = BluetoothInterface::GetInstance();
if (NS_WARN_IF(!btInf)) {
// If there's no Bluetooth interface, we dispatch a runnable
// that calls the profile result handler.
nsRefPtr<nsRunnable> r =
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch GATT OnError runnable");
}
return;
}
auto setupInterface = btInf->GetBluetoothSetupInterface();
if (NS_WARN_IF(!setupInterface)) {
// If there's no Setup interface, we dispatch a runnable
// that calls the profile result handler.
nsRefPtr<nsRunnable> r =
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch GATT OnError runnable");
}
return;
}
auto gattInterface = btInf->GetBluetoothGattInterface();
if (NS_WARN_IF(!gattInterface)) {
// If there's no GATT interface, we dispatch a runnable
// that calls the profile result handler.
nsRefPtr<nsRunnable> r =
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch GATT OnError runnable");
}
return;
}
@ -434,30 +510,43 @@ BluetoothGattManager::InitGattInterface(BluetoothProfileResultHandler* aRes)
sServers = new nsTArray<nsRefPtr<BluetoothGattServer> >;
}
BluetoothGattManager* gattManager = BluetoothGattManager::Get();
sBluetoothGattInterface->Init(gattManager,
new InitGattResultHandler(aRes));
// Set notification handler _before_ registering the module. It could
// happen that we receive notifications, before the result handler runs.
gattInterface->SetNotificationHandler(BluetoothGattManager::Get());
setupInterface->RegisterModule(
SETUP_SERVICE_ID_GATT, 0, MAX_NUM_CLIENTS,
new RegisterModuleResultHandler(gattInterface, aRes));
}
class BluetoothGattManager::CleanupResultHandler final
: public BluetoothGattResultHandler
class BluetoothGattManager::UnregisterModuleResultHandler final
: public BluetoothSetupResultHandler
{
public:
CleanupResultHandler(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
UnregisterModuleResultHandler(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
{ }
void OnError(BluetoothStatus aStatus) override
{
BT_WARNING("BluetoothGattInterface::Cleanup failed: %d",
MOZ_ASSERT(NS_IsMainThread());
BT_WARNING("BluetoothSetupInterface::UnregisterModule failed for GATT: %d",
(int)aStatus);
sBluetoothGattInterface->SetNotificationHandler(nullptr);
sBluetoothGattInterface = nullptr;
if (mRes) {
mRes->OnError(NS_ERROR_FAILURE);
}
}
void Cleanup() override
void UnregisterModule() override
{
MOZ_ASSERT(NS_IsMainThread());
sBluetoothGattInterface->SetNotificationHandler(nullptr);
sBluetoothGattInterface = nullptr;
sClients = nullptr;
sServers = nullptr;
@ -471,24 +560,33 @@ private:
nsRefPtr<BluetoothProfileResultHandler> mRes;
};
class BluetoothGattManager::CleanupResultHandlerRunnable final
class BluetoothGattManager::DeinitProfileResultHandlerRunnable final
: public nsRunnable
{
public:
CleanupResultHandlerRunnable(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
DeinitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
nsresult aRv)
: mRes(aRes)
, mRv(aRv)
{
MOZ_ASSERT(mRes);
}
NS_IMETHOD Run() override
{
mRes->Deinit();
MOZ_ASSERT(NS_IsMainThread());
if (NS_SUCCEEDED(mRv)) {
mRes->Deinit();
} else {
mRes->OnError(mRv);
}
return NS_OK;
}
private:
nsRefPtr<BluetoothProfileResultHandler> mRes;
nsresult mRv;
};
// static
@ -497,16 +595,45 @@ BluetoothGattManager::DeinitGattInterface(BluetoothProfileResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
if (sBluetoothGattInterface) {
sBluetoothGattInterface->Cleanup(new CleanupResultHandler(aRes));
} else if (aRes) {
// We dispatch a runnable here to make the profile resource handler
// behave as if GATT was initialized.
nsRefPtr<nsRunnable> r = new CleanupResultHandlerRunnable(aRes);
if (!sBluetoothGattInterface) {
BT_LOGR("Bluetooth GATT interface has not been initalized.");
nsRefPtr<nsRunnable> r =
new DeinitProfileResultHandlerRunnable(aRes, NS_OK);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch cleanup-result-handler runnable");
BT_LOGR("Failed to dispatch GATT Deinit runnable");
}
return;
}
auto btInf = BluetoothInterface::GetInstance();
if (NS_WARN_IF(!btInf)) {
// If there's no backend interface, we dispatch a runnable
// that calls the profile result handler.
nsRefPtr<nsRunnable> r =
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch GATT OnError runnable");
}
return;
}
auto setupInterface = btInf->GetBluetoothSetupInterface();
if (NS_WARN_IF(!setupInterface)) {
// If there's no Setup interface, we dispatch a runnable
// that calls the profile result handler.
nsRefPtr<nsRunnable> r =
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch GATT OnError runnable");
}
return;
}
setupInterface->UnregisterModule(
SETUP_SERVICE_ID_GATT,
new UnregisterModuleResultHandler(aRes));
}
class BluetoothGattManager::RegisterClientResultHandler final

View File

@ -20,6 +20,8 @@ class BluetoothGattManager final : public nsIObserver
, public BluetoothGattNotificationHandler
{
public:
static const int MAX_NUM_CLIENTS;
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
@ -165,9 +167,16 @@ public:
private:
~BluetoothGattManager();
#if 0
class CleanupResultHandler;
class CleanupResultHandlerRunnable;
class InitGattResultHandler;
#endif
class DeinitProfileResultHandlerRunnable;
class InitProfileResultHandlerRunnable;
class RegisterModuleResultHandler;
class UnregisterModuleResultHandler;
class RegisterClientResultHandler;
class UnregisterClientResultHandler;
class StartLeScanResultHandler;

View File

@ -276,12 +276,12 @@ BluetoothHfpManager::Init()
return true;
}
class BluetoothHfpManager::CleanupInitResultHandler final
: public BluetoothHandsfreeResultHandler
class BluetoothHfpManager::RegisterModuleResultHandler final
: public BluetoothSetupResultHandler
{
public:
CleanupInitResultHandler(BluetoothHandsfreeInterface* aInterface,
BluetoothProfileResultHandler* aRes)
RegisterModuleResultHandler(BluetoothHandsfreeInterface* aInterface,
BluetoothProfileResultHandler* aRes)
: mInterface(aInterface)
, mRes(aRes)
{
@ -290,68 +290,40 @@ public:
void OnError(BluetoothStatus aStatus) override
{
BT_WARNING("BluetoothHandsfreeInterface::Init failed: %d", (int)aStatus);
MOZ_ASSERT(NS_IsMainThread());
BT_WARNING("BluetoothSetupInterface::RegisterModule failed for HFP: %d",
(int)aStatus);
mInterface->SetNotificationHandler(nullptr);
if (mRes) {
mRes->OnError(NS_ERROR_FAILURE);
}
}
void Init() override
void RegisterModule() override
{
MOZ_ASSERT(NS_IsMainThread());
sBluetoothHfpInterface = mInterface;
if (mRes) {
mRes->Init();
}
}
void Cleanup() override
{
sBluetoothHfpInterface = nullptr;
/* During re-initialization, a previouly initialized
* |BluetoothHandsfreeInterface| has now been cleaned
* up, so we start initialization.
*/
RunInit();
}
void RunInit()
{
BluetoothHfpManager* hfpManager = BluetoothHfpManager::Get();
mInterface->Init(hfpManager, BluetoothHfpManager::MAX_NUM_CLIENTS, this);
}
private:
BluetoothHandsfreeInterface* mInterface;
nsRefPtr<BluetoothProfileResultHandler> mRes;
};
class BluetoothHfpManager::InitResultHandlerRunnable final
class BluetoothHfpManager::InitProfileResultHandlerRunnable final
: public nsRunnable
{
public:
InitResultHandlerRunnable(CleanupInitResultHandler* aRes)
: mRes(aRes)
{
MOZ_ASSERT(mRes);
}
NS_IMETHOD Run() override
{
mRes->RunInit();
return NS_OK;
}
private:
nsRefPtr<CleanupInitResultHandler> mRes;
};
class BluetoothHfpManager::OnErrorProfileResultHandlerRunnable final
: public nsRunnable
{
public:
OnErrorProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
nsresult aRv)
InitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
nsresult aRv)
: mRes(aRes)
, mRv(aRv)
{
@ -360,7 +332,13 @@ public:
NS_IMETHOD Run() override
{
mRes->OnError(mRv);
MOZ_ASSERT(NS_IsMainThread());
if (NS_SUCCEEDED(mRv)) {
mRes->Init();
} else {
mRes->OnError(mRv);
}
return NS_OK;
}
@ -373,45 +351,64 @@ private:
void
BluetoothHfpManager::InitHfpInterface(BluetoothProfileResultHandler* aRes)
{
BluetoothInterface* btInf = BluetoothInterface::GetInstance();
MOZ_ASSERT(NS_IsMainThread());
if (sBluetoothHfpInterface) {
BT_LOGR("Bluetooth Handsfree interface is already initalized.");
nsRefPtr<nsRunnable> r =
new InitProfileResultHandlerRunnable(aRes, NS_OK);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch HFP Init runnable");
}
return;
}
auto btInf = BluetoothInterface::GetInstance();
if (NS_WARN_IF(!btInf)) {
// If there's no backend interface, we dispatch a runnable
// that calls the profile result handler.
nsRefPtr<nsRunnable> r =
new OnErrorProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch HFP OnError runnable");
}
return;
}
BluetoothHandsfreeInterface *interface =
btInf->GetBluetoothHandsfreeInterface();
auto setupInterface = btInf->GetBluetoothSetupInterface();
if (NS_WARN_IF(!setupInterface)) {
// If there's no Setup interface, we dispatch a runnable
// that calls the profile result handler.
nsRefPtr<nsRunnable> r =
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch HFP OnError runnable");
}
return;
}
auto interface = btInf->GetBluetoothHandsfreeInterface();
if (NS_WARN_IF(!interface)) {
// If there's no HFP interface, we dispatch a runnable
// that calls the profile result handler.
nsRefPtr<nsRunnable> r =
new OnErrorProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch HFP OnError runnable");
}
return;
}
nsRefPtr<CleanupInitResultHandler> res =
new CleanupInitResultHandler(interface, aRes);
// Set notification handler _before_ registering the module. It could
// happen that we receive notifications, before the result handler runs.
interface->SetNotificationHandler(BluetoothHfpManager::Get());
if (sBluetoothHfpInterface) {
// Cleanup an initialized HFP before initializing again.
sBluetoothHfpInterface->Cleanup(res);
} else {
// If there's no HFP interface to cleanup first, we dispatch
// a runnable that calls the profile result handler.
nsRefPtr<nsRunnable> r = new InitResultHandlerRunnable(res);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch HFP init runnable");
}
}
setupInterface->RegisterModule(
SETUP_SERVICE_ID_HANDSFREE, MODE_NARROWBAND_SPEECH, MAX_NUM_CLIENTS,
new RegisterModuleResultHandler(interface, aRes));
}
BluetoothHfpManager::~BluetoothHfpManager()
@ -432,18 +429,22 @@ BluetoothHfpManager::~BluetoothHfpManager()
hal::UnregisterBatteryObserver(this);
}
class BluetoothHfpManager::CleanupResultHandler final
: public BluetoothHandsfreeResultHandler
class BluetoothHfpManager::UnregisterModuleResultHandler final
: public BluetoothSetupResultHandler
{
public:
CleanupResultHandler(BluetoothProfileResultHandler* aRes)
UnregisterModuleResultHandler(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
{ }
void OnError(BluetoothStatus aStatus) override
{
BT_WARNING("BluetoothHandsfreeInterface::Cleanup failed: %d", (int)aStatus);
MOZ_ASSERT(NS_IsMainThread());
BT_WARNING("BluetoothSetupInterface::UnregisterModule failed for HFP: %d",
(int)aStatus);
sBluetoothHfpInterface->SetNotificationHandler(nullptr);
sBluetoothHfpInterface = nullptr;
if (mRes) {
@ -451,9 +452,13 @@ public:
}
}
void Cleanup() override
void UnregisterModule() override
{
MOZ_ASSERT(NS_IsMainThread());
sBluetoothHfpInterface->SetNotificationHandler(nullptr);
sBluetoothHfpInterface = nullptr;
if (mRes) {
mRes->Deinit();
}
@ -463,40 +468,80 @@ private:
nsRefPtr<BluetoothProfileResultHandler> mRes;
};
class BluetoothHfpManager::DeinitResultHandlerRunnable final
class BluetoothHfpManager::DeinitProfileResultHandlerRunnable final
: public nsRunnable
{
public:
DeinitResultHandlerRunnable(BluetoothProfileResultHandler* aRes)
DeinitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
nsresult aRv)
: mRes(aRes)
, mRv(aRv)
{
MOZ_ASSERT(mRes);
}
NS_IMETHOD Run() override
{
mRes->Deinit();
MOZ_ASSERT(NS_IsMainThread());
if (NS_SUCCEEDED(mRv)) {
mRes->Deinit();
} else {
mRes->OnError(mRv);
}
return NS_OK;
}
private:
nsRefPtr<BluetoothProfileResultHandler> mRes;
nsresult mRv;
};
// static
void
BluetoothHfpManager::DeinitHfpInterface(BluetoothProfileResultHandler* aRes)
{
if (sBluetoothHfpInterface) {
sBluetoothHfpInterface->Cleanup(new CleanupResultHandler(aRes));
} else if (aRes) {
// We dispatch a runnable here to make the profile resource handler
// behave as if HFP was initialized.
nsRefPtr<nsRunnable> r = new DeinitResultHandlerRunnable(aRes);
MOZ_ASSERT(NS_IsMainThread());
if (!sBluetoothHfpInterface) {
BT_LOGR("Bluetooth Handsfree interface has not been initialized.");
nsRefPtr<nsRunnable> r =
new DeinitProfileResultHandlerRunnable(aRes, NS_OK);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch cleanup-result-handler runnable");
BT_LOGR("Failed to dispatch HFP Deinit runnable");
}
return;
}
auto btInf = BluetoothInterface::GetInstance();
if (NS_WARN_IF(!btInf)) {
// If there's no backend interface, we dispatch a runnable
// that calls the profile result handler.
nsRefPtr<nsRunnable> r =
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch HFP OnError runnable");
}
return;
}
auto setupInterface = btInf->GetBluetoothSetupInterface();
if (NS_WARN_IF(!setupInterface)) {
// If there's no Setup interface, we dispatch a runnable
// that calls the profile result handler.
nsRefPtr<nsRunnable> r =
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch HFP OnError runnable");
}
return;
}
setupInterface->UnregisterModule(
SETUP_SERVICE_ID_HANDSFREE,
new UnregisterModuleResultHandler(aRes));
}
//static

View File

@ -73,6 +73,12 @@ class BluetoothHfpManager : public BluetoothHfpManagerBase
, public BluetoothHandsfreeNotificationHandler
, public BatteryObserver
{
enum {
MODE_HEADSET = 0x00,
MODE_NARROWBAND_SPEECH = 0x01,
MODE_NARRAWBAND_WIDEBAND_SPEECH = 0x02
};
public:
BT_DECL_HFP_MGR_BASE
@ -151,21 +157,20 @@ private:
class ConnectResultHandler;
class CopsResponseResultHandler;
class ClccResponseResultHandler;
class CleanupInitResultHandler;
class CleanupResultHandler;
class CloseScoRunnable;
class CloseScoTask;
class DeinitResultHandlerRunnable;
class DeinitProfileResultHandlerRunnable;
class DeviceStatusNotificationResultHandler;
class DisconnectAudioResultHandler;
class DisconnectResultHandler;
class FormattedAtResponseResultHandler;
class GetVolumeTask;
class InitResultHandlerRunnable;
class InitProfileResultHandlerRunnable;
class MainThreadTask;
class OnErrorProfileResultHandlerRunnable;
class PhoneStateChangeResultHandler;
class RegisterModuleResultHandler;
class RespondToBLDNTask;
class UnregisterModuleResultHandler;
class VolumeControlResultHandler;
friend class BluetoothHfpManagerObserver;

View File

@ -9,6 +9,7 @@
#include "mozilla/Compiler.h"
#include "mozilla/Observer.h"
#include "nsAutoPtr.h"
#include "nsPrintfCString.h"
#include "nsString.h"
#include "nsTArray.h"
@ -325,6 +326,23 @@ enum BluetoothBondState {
BOND_STATE_BONDED
};
enum BluetoothSetupServiceId {
SETUP_SERVICE_ID_SETUP,
SETUP_SERVICE_ID_CORE,
SETUP_SERVICE_ID_SOCKET,
SETUP_SERVICE_ID_HID,
SETUP_SERVICE_ID_PAN,
SETUP_SERVICE_ID_HANDSFREE,
SETUP_SERVICE_ID_A2DP,
SETUP_SERVICE_ID_HEALTH,
SETUP_SERVICE_ID_AVRCP,
SETUP_SERVICE_ID_GATT,
SETUP_SERVICE_ID_HANDSFREE_CLIENT,
SETUP_SERVICE_ID_MAP_CLIENT,
SETUP_SERVICE_ID_AVRCP_CONTROLLER,
SETUP_SERVICE_ID_A2DP_SINK
};
/* Physical transport for GATT connections to remote dual-mode devices */
enum BluetoothTransport {
TRANSPORT_AUTO, /* No preference of physical transport */
@ -480,6 +498,12 @@ struct BluetoothAddress {
};
struct BluetoothConfigurationParameter {
uint8_t mType;
uint16_t mLength;
nsAutoArrayPtr<uint8_t> mValue;
};
struct BluetoothUuid {
uint8_t mUuid[16];

View File

@ -39,6 +39,12 @@ void
BluetoothSetupResultHandler::Configuration()
{ }
// Interface
//
BluetoothSetupInterface::~BluetoothSetupInterface()
{ }
//
// Socket Interface
//
@ -181,14 +187,6 @@ BluetoothHandsfreeResultHandler::OnError(BluetoothStatus aStatus)
BT_WARNING("Received error code %d", (int)aStatus);
}
void
BluetoothHandsfreeResultHandler::Init()
{ }
void
BluetoothHandsfreeResultHandler::Cleanup()
{ }
void
BluetoothHandsfreeResultHandler::Connect()
{ }
@ -295,14 +293,6 @@ BluetoothA2dpResultHandler::OnError(BluetoothStatus aStatus)
BT_WARNING("Received error code %d", (int)aStatus);
}
void
BluetoothA2dpResultHandler::Init()
{ }
void
BluetoothA2dpResultHandler::Cleanup()
{ }
void
BluetoothA2dpResultHandler::Connect()
{ }
@ -400,14 +390,6 @@ BluetoothAvrcpResultHandler::OnError(BluetoothStatus aStatus)
BT_WARNING("Received error code %d", (int)aStatus);
}
void
BluetoothAvrcpResultHandler::Init()
{ }
void
BluetoothAvrcpResultHandler::Cleanup()
{ }
void
BluetoothAvrcpResultHandler::GetPlayStatusRsp()
{ }
@ -679,14 +661,6 @@ BluetoothGattResultHandler::OnError(BluetoothStatus aStatus)
BT_WARNING("Received error code %d", (int)aStatus);
}
void
BluetoothGattResultHandler::Init()
{ }
void
BluetoothGattResultHandler::Cleanup()
{ }
void
BluetoothGattResultHandler::RegisterClient()
{ }

View File

@ -30,6 +30,25 @@ protected:
virtual ~BluetoothSetupResultHandler() { }
};
class BluetoothSetupInterface
{
public:
virtual void RegisterModule(BluetoothSetupServiceId aId,
uint8_t aMode,
uint32_t aMaxNumClients,
BluetoothSetupResultHandler* aRes) = 0;
virtual void UnregisterModule(BluetoothSetupServiceId aId,
BluetoothSetupResultHandler* aRes) = 0;
virtual void Configuration(const BluetoothConfigurationParameter* aParam,
uint8_t aLen,
BluetoothSetupResultHandler* aRes) = 0;
protected:
virtual ~BluetoothSetupInterface();
};
//
// Socket Interface
//
@ -155,9 +174,6 @@ class BluetoothHandsfreeResultHandler
public:
virtual void OnError(BluetoothStatus aStatus);
virtual void Init();
virtual void Cleanup();
virtual void Connect();
virtual void Disconnect();
virtual void ConnectAudio();
@ -186,10 +202,8 @@ protected:
class BluetoothHandsfreeInterface
{
public:
virtual void Init(
BluetoothHandsfreeNotificationHandler* aNotificationHandler,
int aMaxNumClients, BluetoothHandsfreeResultHandler* aRes) = 0;
virtual void Cleanup(BluetoothHandsfreeResultHandler* aRes) = 0;
virtual void SetNotificationHandler(
BluetoothHandsfreeNotificationHandler* aNotificationHandler) = 0;
/* Connect / Disconnect */
@ -295,8 +309,6 @@ class BluetoothA2dpResultHandler
public:
virtual void OnError(BluetoothStatus aStatus);
virtual void Init();
virtual void Cleanup();
virtual void Connect();
virtual void Disconnect();
@ -307,9 +319,8 @@ protected:
class BluetoothA2dpInterface
{
public:
virtual void Init(BluetoothA2dpNotificationHandler* aNotificationHandler,
BluetoothA2dpResultHandler* aRes) = 0;
virtual void Cleanup(BluetoothA2dpResultHandler* aRes) = 0;
virtual void SetNotificationHandler(
BluetoothA2dpNotificationHandler* aNotificationHandler) = 0;
virtual void Connect(const BluetoothAddress& aBdAddr,
BluetoothA2dpResultHandler* aRes) = 0;
@ -382,9 +393,6 @@ class BluetoothAvrcpResultHandler
public:
virtual void OnError(BluetoothStatus aStatus);
virtual void Init();
virtual void Cleanup();
virtual void GetPlayStatusRsp();
virtual void ListPlayerAppAttrRsp();
@ -409,9 +417,8 @@ protected:
class BluetoothAvrcpInterface
{
public:
virtual void Init(BluetoothAvrcpNotificationHandler* aNotificationHandler,
BluetoothAvrcpResultHandler* aRes) = 0;
virtual void Cleanup(BluetoothAvrcpResultHandler* aRes) = 0;
virtual void SetNotificationHandler(
BluetoothAvrcpNotificationHandler* aNotificationHandler) = 0;
virtual void GetPlayStatusRsp(ControlPlayStatus aPlayStatus,
uint32_t aSongLen, uint32_t aSongPos,
@ -663,9 +670,6 @@ class BluetoothGattResultHandler
public:
virtual void OnError(BluetoothStatus aStatus);
virtual void Init();
virtual void Cleanup();
virtual void RegisterClient();
virtual void UnregisterClient();
@ -723,9 +727,8 @@ protected:
class BluetoothGattInterface
{
public:
virtual void Init(BluetoothGattNotificationHandler* aNotificationHandler,
BluetoothGattResultHandler* aRes) = 0;
virtual void Cleanup(BluetoothGattResultHandler* aRes) = 0;
virtual void SetNotificationHandler(
BluetoothGattNotificationHandler* aNotificationHandler) = 0;
/* Register / Unregister */
virtual void RegisterClient(const BluetoothUuid& aUuid,
@ -1111,6 +1114,7 @@ public:
/* Profile Interfaces */
virtual BluetoothSetupInterface* GetBluetoothSetupInterface() = 0;
virtual BluetoothSocketInterface* GetBluetoothSocketInterface() = 0;
virtual BluetoothHandsfreeInterface* GetBluetoothHandsfreeInterface() = 0;
virtual BluetoothA2dpInterface* GetBluetoothA2dpInterface() = 0;

View File

@ -998,7 +998,7 @@ BrowserElementParent.prototype = {
try {
let nfcContentHelper =
Cc["@mozilla.org/nfc/content-helper;1"].getService(Ci.nsINfcBrowserAPI);
nfcContentHelper.setFocusApp(tabId, isFocus);
nfcContentHelper.setFocusTab(tabId, isFocus);
} catch(e) {
// Not all platforms support NFC
}

View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<script>
function boom()
{
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
ctx.setTransform(0.2988847856952777, 26589683732.25, -562949953421312, 5, 4503599627370495, -2735897607.139075);
ctx.bezierCurveTo(-1023, -4611686018427388000, 4194303, -536870911, 45139.65058316886, 35184372088833);
ctx.setLineDash([1.2307692307692308]);
ctx.setTransform(0, 2097152, 0.0005128205128205128, 305943.4982061649, -49282.263290019946, 3);
ctx.clip("evenodd");
ctx.scale(-2.3882113703861325, -2);
ctx.isPointInStroke(2, 86124313031369.77);
}
</script>
</head>
<body onload="boom();"></body>
</html>

View File

@ -22,6 +22,7 @@ load 896047-2.html
load 916128-1.html
load 934939-1.html
load 1099143-1.html
load 1161277-1.html
load 1183363.html
load 1190705.html

View File

@ -50,6 +50,7 @@
#include "nsIContentViewer.h"
#include "nsFrameManager.h"
#include "nsITabChild.h"
#include "nsPluginFrame.h"
#include "nsIDOMXULElement.h"
#include "nsIDOMKeyEvent.h"
@ -2125,11 +2126,11 @@ EventStateManager::DispatchLegacyMouseScrollEvents(nsIFrame* aTargetFrame,
// Ignore mouse wheel transaction for computing legacy mouse wheel
// events' delta value.
nsIScrollableFrame* scrollTarget =
nsIFrame* scrollFrame =
ComputeScrollTarget(aTargetFrame, aEvent,
COMPUTE_LEGACY_MOUSE_SCROLL_EVENT_TARGET);
nsIFrame* scrollFrame = do_QueryFrame(scrollTarget);
nsIScrollableFrame* scrollTarget = do_QueryFrame(scrollFrame);
nsPresContext* pc =
scrollFrame ? scrollFrame->PresContext() : aTargetFrame->PresContext();
@ -2315,7 +2316,7 @@ EventStateManager::SendPixelScrollEvent(nsIFrame* aTargetFrame,
aState.mDefaultPreventedByContent = event.mFlags.mDefaultPreventedByContent;
}
nsIScrollableFrame*
nsIFrame*
EventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
WidgetWheelEvent* aEvent,
ComputeScrollTargetOptions aOptions)
@ -2327,7 +2328,7 @@ EventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
// Overload ComputeScrollTarget method to allow passing "test" dx and dy when looking
// for which scrollbarmediators to activate when two finger down on trackpad
// and before any actual motion
nsIScrollableFrame*
nsIFrame*
EventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
double aDirectionX,
double aDirectionY,
@ -2346,9 +2347,18 @@ EventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
// hasn't moved.
nsIFrame* lastScrollFrame = WheelTransaction::GetTargetFrame();
if (lastScrollFrame) {
nsIScrollableFrame* frameToScroll =
if (aOptions & INCLUDE_PLUGIN_AS_TARGET) {
nsPluginFrame* pluginFrame = do_QueryFrame(lastScrollFrame);
if (pluginFrame &&
pluginFrame->WantsToHandleWheelEventAsDefaultAction()) {
return lastScrollFrame;
}
}
nsIScrollableFrame* scrollableFrame =
lastScrollFrame->GetScrollTargetFrame();
if (frameToScroll) {
if (scrollableFrame) {
nsIFrame* frameToScroll = do_QueryFrame(scrollableFrame);
MOZ_ASSERT(frameToScroll);
return frameToScroll;
}
}
@ -2366,17 +2376,31 @@ EventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
bool checkIfScrollableY =
aDirectionY && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS);
nsIScrollableFrame* frameToScroll = nullptr;
nsIFrame* scrollFrame =
!(aOptions & START_FROM_PARENT) ? aTargetFrame :
GetParentFrameToScroll(aTargetFrame);
for (; scrollFrame; scrollFrame = GetParentFrameToScroll(scrollFrame)) {
// Check whether the frame wants to provide us with a scrollable view.
frameToScroll = scrollFrame->GetScrollTargetFrame();
if (!frameToScroll) {
nsIScrollableFrame* scrollableFrame = scrollFrame->GetScrollTargetFrame();
if (!scrollableFrame) {
// If the frame is a plugin frame, then, the plugin content may handle
// wheel events. Only when the caller computes the scroll target for
// default action handling, we should assume the plugin frame as
// scrollable if the plugin wants to handle wheel events as default
// action.
if (aOptions & INCLUDE_PLUGIN_AS_TARGET) {
nsPluginFrame* pluginFrame = do_QueryFrame(scrollFrame);
if (pluginFrame &&
pluginFrame->WantsToHandleWheelEventAsDefaultAction()) {
return scrollFrame;
}
}
continue;
}
nsIFrame* frameToScroll = do_QueryFrame(scrollableFrame);
MOZ_ASSERT(frameToScroll);
// Don't scroll vertically by mouse-wheel on a single-line text control.
if (checkIfScrollableY) {
if (!CanVerticallyScrollFrameWithWheel(scrollFrame)) {
@ -2388,7 +2412,7 @@ EventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
return frameToScroll;
}
ScrollbarStyles ss = frameToScroll->GetScrollbarStyles();
ScrollbarStyles ss = scrollableFrame->GetScrollbarStyles();
bool hiddenForV = (NS_STYLE_OVERFLOW_HIDDEN == ss.mVertical);
bool hiddenForH = (NS_STYLE_OVERFLOW_HIDDEN == ss.mHorizontal);
if ((hiddenForV && hiddenForH) ||
@ -2399,8 +2423,8 @@ EventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
// For default action, we should climb up the tree if cannot scroll it
// by the event actually.
bool canScroll =
WheelHandlingUtils::CanScrollOn(frameToScroll, aDirectionX, aDirectionY);
bool canScroll = WheelHandlingUtils::CanScrollOn(scrollableFrame,
aDirectionX, aDirectionY);
// Comboboxes need special care.
nsIComboboxControlFrame* comboBox = do_QueryFrame(scrollFrame);
if (comboBox) {
@ -2464,24 +2488,9 @@ EventStateManager::DoScrollText(nsIScrollableFrame* aScrollableFrame,
nsIFrame* scrollFrame = do_QueryFrame(aScrollableFrame);
MOZ_ASSERT(scrollFrame);
nsWeakFrame scrollFrameWeak(scrollFrame);
nsIFrame* lastScrollFrame = WheelTransaction::GetTargetFrame();
if (!lastScrollFrame) {
WheelTransaction::BeginTransaction(scrollFrame, aEvent);
} else if (lastScrollFrame != scrollFrame) {
WheelTransaction::EndTransaction();
WheelTransaction::BeginTransaction(scrollFrame, aEvent);
} else {
WheelTransaction::UpdateTransaction(aEvent);
}
// When the scroll event will not scroll any views, UpdateTransaction
// fired MozMouseScrollFailed event which is for automated testing.
// In the event handler, the target frame might be destroyed. Then,
// we should not try scrolling anything.
if (!scrollFrameWeak.IsAlive()) {
WheelTransaction::EndTransaction();
if (!WheelTransaction::WillHandleDefaultAction(aEvent, scrollFrameWeak)) {
return;
}
@ -3078,8 +3087,8 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
ScrollbarsForWheel::MayInactivate();
WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
nsIScrollableFrame* scrollTarget =
ComputeScrollTarget(aTargetFrame, wheelEvent,
COMPUTE_DEFAULT_ACTION_TARGET);
do_QueryFrame(ComputeScrollTarget(aTargetFrame, wheelEvent,
COMPUTE_DEFAULT_ACTION_TARGET));
if (scrollTarget) {
scrollTarget->ScrollSnap();
}
@ -3097,13 +3106,27 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
// Check if the frame to scroll before checking the default action
// because if the scroll target is a plugin, the default action should be
// chosen by the plugin rather than by our prefs.
nsIFrame* frameToScroll = nullptr;
nsPluginFrame* pluginFrame = nullptr;
// When APZ is enabled, the actual scroll animation might be handled by
// the compositor.
WheelPrefs::Action action;
if (wheelEvent->mFlags.mHandledByAPZ) {
action = WheelPrefs::ACTION_NONE;
} else {
action = WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent);
frameToScroll = ComputeScrollTarget(aTargetFrame, wheelEvent,
COMPUTE_DEFAULT_ACTION_TARGET);
pluginFrame = do_QueryFrame(frameToScroll);
if (pluginFrame) {
MOZ_ASSERT(pluginFrame->WantsToHandleWheelEventAsDefaultAction());
action = WheelPrefs::ACTION_SEND_TO_PLUGIN;
} else {
action = WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent);
}
}
switch (action) {
case WheelPrefs::ACTION_SCROLL: {
@ -3117,10 +3140,7 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
break;
}
nsIScrollableFrame* scrollTarget =
ComputeScrollTarget(aTargetFrame, wheelEvent,
COMPUTE_DEFAULT_ACTION_TARGET);
nsIScrollableFrame* scrollTarget = do_QueryFrame(frameToScroll);
ScrollbarsForWheel::SetActiveScrollTarget(scrollTarget);
nsIFrame* rootScrollFrame = !aTargetFrame ? nullptr :
@ -3164,6 +3184,23 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
DoScrollZoom(aTargetFrame, intDelta);
break;
}
case WheelPrefs::ACTION_SEND_TO_PLUGIN:
MOZ_ASSERT(pluginFrame);
if (wheelEvent->mMessage != eWheel ||
(!wheelEvent->deltaX && !wheelEvent->deltaY)) {
break;
}
MOZ_ASSERT(static_cast<void*>(frameToScroll) ==
static_cast<void*>(pluginFrame));
if (!WheelTransaction::WillHandleDefaultAction(wheelEvent,
frameToScroll)) {
break;
}
pluginFrame->HandleWheelEventAsDefaultAction(wheelEvent);
break;
case WheelPrefs::ACTION_NONE:
default:
bool allDeltaOverflown = false;
@ -5312,12 +5349,12 @@ EventStateManager::DeltaAccumulator::InitLineOrPageDelta(
// eMouseScrollEventClass (DOMMouseScroll) but not be used for scrolling
// of default action. The transaction should be used only for the default
// action.
nsIScrollableFrame* scrollTarget =
nsIFrame* frame =
aESM->ComputeScrollTarget(aTargetFrame, aEvent,
COMPUTE_LEGACY_MOUSE_SCROLL_EVENT_TARGET);
nsIFrame* frame = do_QueryFrame(scrollTarget);
nsPresContext* pc =
frame ? frame->PresContext() : aTargetFrame->PresContext();
nsIScrollableFrame* scrollTarget = do_QueryFrame(frame);
nsSize scrollAmount = aESM->GetScrollAmount(pc, aEvent, scrollTarget);
nsIntSize scrollAmountInCSSPixels(
nsPresContext::AppUnitsToIntCSSPixels(scrollAmount.width),

View File

@ -461,7 +461,10 @@ protected:
ACTION_SCROLL,
ACTION_HISTORY,
ACTION_ZOOM,
ACTION_LAST = ACTION_ZOOM
ACTION_LAST = ACTION_ZOOM,
// Following actions are used only by internal processing. So, cannot
// specified by prefs.
ACTION_SEND_TO_PLUGIN
};
Action ComputeActionFor(WidgetWheelEvent* aEvent);
@ -617,10 +620,11 @@ protected:
// COMPUTE_*.
enum
{
PREFER_MOUSE_WHEEL_TRANSACTION = 1,
PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS = 2,
PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS = 4,
START_FROM_PARENT = 8
PREFER_MOUSE_WHEEL_TRANSACTION = 0x00000001,
PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS = 0x00000002,
PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS = 0x00000004,
START_FROM_PARENT = 0x00000008,
INCLUDE_PLUGIN_AS_TARGET = 0x00000010
};
enum ComputeScrollTargetOptions
{
@ -630,10 +634,13 @@ protected:
// Default action prefers the scrolled element immediately before if it's
// still under the mouse cursor. Otherwise, it prefers the nearest
// scrollable ancestor which will be scrolled actually.
// When this is specified, the result may be nsPluginFrame. In such case,
// the frame doesn't have nsIScrollableFrame interface.
COMPUTE_DEFAULT_ACTION_TARGET =
(PREFER_MOUSE_WHEEL_TRANSACTION |
PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS |
PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS),
PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS |
INCLUDE_PLUGIN_AS_TARGET),
// Look for the nearest scrollable ancestor which can be scrollable with
// aEvent.
COMPUTE_SCROLLABLE_ANCESTOR_ALONG_X_AXIS =
@ -641,15 +648,15 @@ protected:
COMPUTE_SCROLLABLE_ANCESTOR_ALONG_Y_AXIS =
(PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS | START_FROM_PARENT)
};
nsIScrollableFrame* ComputeScrollTarget(nsIFrame* aTargetFrame,
WidgetWheelEvent* aEvent,
ComputeScrollTargetOptions aOptions);
nsIFrame* ComputeScrollTarget(nsIFrame* aTargetFrame,
WidgetWheelEvent* aEvent,
ComputeScrollTargetOptions aOptions);
nsIScrollableFrame* ComputeScrollTarget(nsIFrame* aTargetFrame,
double aDirectionX,
double aDirectionY,
WidgetWheelEvent* aEvent,
ComputeScrollTargetOptions aOptions);
nsIFrame* ComputeScrollTarget(nsIFrame* aTargetFrame,
double aDirectionX,
double aDirectionY,
WidgetWheelEvent* aEvent,
ComputeScrollTargetOptions aOptions);
/**
* GetScrollAmount() returns the scroll amount in app uints of one line or

View File

@ -17,6 +17,7 @@
#include "nsIPresShell.h"
#include "nsIScrollableFrame.h"
#include "nsITimer.h"
#include "nsPluginFrame.h"
#include "nsPresContext.h"
#include "prtime.h"
#include "Units.h"
@ -45,6 +46,18 @@ WheelHandlingUtils::CanScrollInRange(nscoord aMin, nscoord aValue, nscoord aMax,
static_cast<double>(aMin) < aValue;
}
/* static */ bool
WheelHandlingUtils::CanScrollOn(nsIFrame* aFrame,
double aDirectionX, double aDirectionY)
{
nsIScrollableFrame* scrollableFrame = do_QueryFrame(aFrame);
if (scrollableFrame) {
return CanScrollOn(scrollableFrame, aDirectionX, aDirectionY);
}
nsPluginFrame* pluginFrame = do_QueryFrame(aFrame);
return pluginFrame && pluginFrame->WantsToHandleWheelEventAsDefaultAction();
}
/* static */ bool
WheelHandlingUtils::CanScrollOn(nsIScrollableFrame* aScrollFrame,
double aDirectionX, double aDirectionY)
@ -108,10 +121,14 @@ WheelTransaction::BeginTransaction(nsIFrame* aTargetFrame,
/* static */ bool
WheelTransaction::UpdateTransaction(WidgetWheelEvent* aEvent)
{
nsIScrollableFrame* sf = GetTargetFrame()->GetScrollTargetFrame();
NS_ENSURE_TRUE(sf, false);
nsIFrame* scrollToFrame = GetTargetFrame();
nsIScrollableFrame* scrollableFrame = scrollToFrame->GetScrollTargetFrame();
if (scrollableFrame) {
scrollToFrame = do_QueryFrame(scrollableFrame);
}
if (!WheelHandlingUtils::CanScrollOn(sf, aEvent->deltaX, aEvent->deltaY)) {
if (!WheelHandlingUtils::CanScrollOn(scrollToFrame,
aEvent->deltaX, aEvent->deltaY)) {
OnFailToScrollTarget();
// We should not modify the transaction state when the view will not be
// scrolled actually.
@ -159,6 +176,32 @@ WheelTransaction::EndTransaction()
}
}
/* static */ bool
WheelTransaction::WillHandleDefaultAction(WidgetWheelEvent* aWheelEvent,
nsWeakFrame& aTargetWeakFrame)
{
nsIFrame* lastTargetFrame = GetTargetFrame();
if (!lastTargetFrame) {
BeginTransaction(aTargetWeakFrame.GetFrame(), aWheelEvent);
} else if (lastTargetFrame != aTargetWeakFrame.GetFrame()) {
EndTransaction();
BeginTransaction(aTargetWeakFrame.GetFrame(), aWheelEvent);
} else {
UpdateTransaction(aWheelEvent);
}
// When the wheel event will not be handled with any frames,
// UpdateTransaction() fires MozMouseScrollFailed event which is for
// automated testing. In the event handler, the target frame might be
// destroyed. Then, the caller shouldn't try to handle the default action.
if (!aTargetWeakFrame.IsAlive()) {
EndTransaction();
return false;
}
return true;
}
/* static */ void
WheelTransaction::OnEvent(WidgetEvent* aEvent)
{
@ -497,9 +540,9 @@ ScrollbarsForWheel::TemporarilyActivateAllPossibleScrollTargets(
const DeltaValues *dir = &directions[i];
nsWeakFrame* scrollTarget = &sActivatedScrollTargets[i];
MOZ_ASSERT(!*scrollTarget, "scroll target still temporarily activated!");
nsIScrollableFrame* target =
nsIScrollableFrame* target = do_QueryFrame(
aESM->ComputeScrollTarget(aTargetFrame, dir->deltaX, dir->deltaY, aEvent,
EventStateManager::COMPUTE_DEFAULT_ACTION_TARGET);
EventStateManager::COMPUTE_DEFAULT_ACTION_TARGET));
nsIScrollbarMediator* scrollbarMediator = do_QueryFrame(target);
if (scrollbarMediator) {
nsIFrame* targetFrame = do_QueryFrame(target);

View File

@ -53,6 +53,14 @@ struct DeltaValues
class WheelHandlingUtils
{
public:
/**
* Returns true if aFrame is a scrollable frame and it can be scrolled to
* either aDirectionX or aDirectionY along each axis. Or if aFrame is a
* plugin frame (in this case, aDirectionX and aDirectionY are ignored).
* Otherwise, false.
*/
static bool CanScrollOn(nsIFrame* aFrame,
double aDirectionX, double aDirectionY);
/**
* Returns true if the scrollable frame can be scrolled to either aDirectionX
* or aDirectionY along each axis. Otherwise, false.
@ -117,13 +125,22 @@ class WheelTransaction
{
public:
static nsIFrame* GetTargetFrame() { return sTargetFrame; }
static void BeginTransaction(nsIFrame* aTargetFrame,
WidgetWheelEvent* aEvent);
// Be careful, UpdateTransaction may fire a DOM event, therefore, the target
// frame might be destroyed in the event handler.
static bool UpdateTransaction(WidgetWheelEvent* aEvent);
static void MayEndTransaction();
static void EndTransaction();
/**
* WillHandleDefaultAction() is called before handling aWheelEvent on
* aTargetFrame.
*
* @return false if the caller cannot continue to handle the default
* action. Otherwise, true.
*/
static bool WillHandleDefaultAction(WidgetWheelEvent* aWheelEvent,
nsWeakFrame& aTargetWeakFrame);
static bool WillHandleDefaultAction(WidgetWheelEvent* aWheelEvent,
nsIFrame* aTargetFrame)
{
nsWeakFrame targetWeakFrame(aTargetFrame);
return WillHandleDefaultAction(aWheelEvent, targetWeakFrame);
}
static void OnEvent(WidgetEvent* aEvent);
static void Shutdown();
static uint32_t GetTimeoutTime();
@ -135,6 +152,14 @@ public:
protected:
static const uint32_t kScrollSeriesTimeout = 80; // in milliseconds
static void BeginTransaction(nsIFrame* aTargetFrame,
WidgetWheelEvent* aEvent);
// Be careful, UpdateTransaction may fire a DOM event, therefore, the target
// frame might be destroyed in the event handler.
static bool UpdateTransaction(WidgetWheelEvent* aEvent);
static void MayEndTransaction();
static nsIntPoint GetScreenPoint(WidgetGUIEvent* aEvent);
static void OnFailToScrollTarget();
static void OnTimeout(nsITimer* aTimer, void* aClosure);

View File

@ -4714,17 +4714,43 @@ HTMLMediaElement::MaybeCreateAudioChannelAgent()
return true;
}
bool
HTMLMediaElement::IsPlayingThroughTheAudioChannel() const
{
// Are we paused or muted
if (mPaused || Muted()) {
return false;
}
// The volume should not be ~0
if (std::fabs(Volume()) <= 1e-7) {
return false;
}
// A loop always is playing
if (HasAttr(kNameSpaceID_None, nsGkAtoms::loop)) {
return true;
}
// If we are actually playing...
if (mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA &&
!IsPlaybackEnded()) {
return true;
}
// If we are seeking, we consider it as playing
if (mPlayingThroughTheAudioChannelBeforeSeek) {
return true;
}
return false;
}
void
HTMLMediaElement::UpdateAudioChannelPlayingState()
{
bool playingThroughTheAudioChannel =
(!mPaused &&
!Muted() &&
std::fabs(Volume()) > 1e-7 &&
(HasAttr(kNameSpaceID_None, nsGkAtoms::loop) ||
(mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA &&
!IsPlaybackEnded()) ||
mPlayingThroughTheAudioChannelBeforeSeek));
bool playingThroughTheAudioChannel = IsPlayingThroughTheAudioChannel();
if (playingThroughTheAudioChannel != mPlayingThroughTheAudioChannel) {
mPlayingThroughTheAudioChannel = playingThroughTheAudioChannel;

View File

@ -1065,6 +1065,9 @@ protected:
// next block of audio samples) preceeding seek target.
void Seek(double aTime, SeekTarget::Type aSeekType, ErrorResult& aRv);
// A method to check if we are playing through the AudioChannel.
bool IsPlayingThroughTheAudioChannel() const;
// Update the audio channel playing state
void UpdateAudioChannelPlayingState();

View File

@ -90,6 +90,9 @@ MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder)
void
MediaDecoderReader::InitializationTask()
{
if (!mDecoder) {
return;
}
if (mDecoder->CanonicalDurationOrNull()) {
mDuration.Connect(mDecoder->CanonicalDurationOrNull());
}
@ -101,7 +104,6 @@ MediaDecoderReader::InitializationTask()
MediaDecoderReader::~MediaDecoderReader()
{
MOZ_ASSERT(mShutdown);
MOZ_ASSERT(!mDecoder);
ResetDecode();
MOZ_COUNT_DTOR(MediaDecoderReader);
}

View File

@ -8,7 +8,6 @@
#include "mozilla/Preferences.h"
#include "nsPrintfCString.h"
#include "nsSize.h"
#include "ImageContainer.h"
#include "Layers.h"
#include "MediaData.h"
#include "MediaInfo.h"
@ -60,19 +59,22 @@ TrackTypeToStr(TrackInfo::TrackType aTrack)
}
MediaFormatReader::MediaFormatReader(AbstractMediaDecoder* aDecoder,
MediaDataDemuxer* aDemuxer)
MediaDataDemuxer* aDemuxer,
VideoFrameContainer* aVideoFrameContainer,
layers::LayersBackend aLayersBackend)
: MediaDecoderReader(aDecoder)
, mAudio(this, MediaData::AUDIO_DATA, Preferences::GetUint("media.audio-decode-ahead", 2))
, mVideo(this, MediaData::VIDEO_DATA, Preferences::GetUint("media.video-decode-ahead", 2))
, mDemuxer(aDemuxer)
, mDemuxerInitDone(false)
, mLastReportedNumDecodedFrames(0)
, mLayersBackendType(layers::LayersBackend::LAYERS_NONE)
, mLayersBackendType(aLayersBackend)
, mInitDone(false)
, mSeekable(false)
, mIsEncrypted(false)
, mTrackDemuxersMayBlock(false)
, mHardwareAccelerationDisabled(false)
, mVideoFrameContainer(aVideoFrameContainer)
{
MOZ_ASSERT(aDemuxer);
MOZ_COUNT_CTOR(MediaFormatReader);
@ -147,6 +149,9 @@ MediaFormatReader::InitLayersBackendType()
// Extract the layer manager backend type so that platform decoders
// can determine whether it's worthwhile using hardware accelerated
// video decoding.
if (!mDecoder) {
return;
}
MediaDecoderOwner* owner = mDecoder->GetOwner();
if (!owner) {
NS_WARNING("MediaFormatReader without a decoder owner, can't get HWAccel");
@ -277,7 +282,7 @@ MediaFormatReader::OnDemuxerInitDone(nsresult)
// To decode, we need valid video and a place to put it.
bool videoActive = !!mDemuxer->GetNumberTracks(TrackInfo::kVideoTrack) &&
mDecoder->GetImageContainer();
GetImageContainer();
if (videoActive) {
// We currently only handle the first video track.
@ -309,7 +314,7 @@ MediaFormatReader::OnDemuxerInitDone(nsresult)
mIsEncrypted = crypto && crypto->IsEncrypted();
if (crypto && crypto->IsEncrypted()) {
if (mDecoder && crypto && crypto->IsEncrypted()) {
#ifdef MOZ_EME
// Try and dispatch 'encrypted'. Won't go if ready state still HAVE_NOTHING.
for (uint32_t i = 0; i < crypto->mInitDatas.Length(); i++) {
@ -404,7 +409,7 @@ MediaFormatReader::EnsureDecodersCreated()
mVideo.mCallback,
mHardwareAccelerationDisabled ? LayersBackend::LAYERS_NONE :
mLayersBackendType,
mDecoder->GetImageContainer());
GetImageContainer());
NS_ENSURE_TRUE(mVideo.mDecoder != nullptr, false);
}
@ -1337,7 +1342,9 @@ MediaFormatReader::OnVideoSkipCompleted(uint32_t aSkipped)
MOZ_ASSERT(OnTaskQueue());
LOG("Skipping succeeded, skipped %u frames", aSkipped);
mSkipRequest.Complete();
mDecoder->NotifyDecodedFrames(aSkipped, 0, aSkipped);
if (mDecoder) {
mDecoder->NotifyDecodedFrames(aSkipped, 0, aSkipped);
}
MOZ_ASSERT(!mVideo.mError); // We have flushed the decoder, no frame could
// have been decoded (and as such errored)
NotifyDecodingRequested(TrackInfo::kVideoTrack);
@ -1349,7 +1356,9 @@ MediaFormatReader::OnVideoSkipFailed(MediaTrackDemuxer::SkipFailureHolder aFailu
MOZ_ASSERT(OnTaskQueue());
LOG("Skipping failed, skipped %u frames", aFailure.mSkipped);
mSkipRequest.Complete();
mDecoder->NotifyDecodedFrames(aFailure.mSkipped, 0, aFailure.mSkipped);
if (mDecoder) {
mDecoder->NotifyDecodedFrames(aFailure.mSkipped, 0, aFailure.mSkipped);
}
MOZ_ASSERT(mVideo.HasPromise());
switch (aFailure.mFailure) {
case DemuxerFailureReason::END_OF_STREAM:
@ -1574,10 +1583,8 @@ void MediaFormatReader::ReleaseMediaResourcesInternal()
MOZ_ASSERT(OnTaskQueue());
// Before freeing a video codec, all video buffers needed to be released
// even from graphics pipeline.
VideoFrameContainer* container =
mDecoder ? mDecoder->GetVideoFrameContainer() : nullptr;
if (container) {
container->ClearCurrentFrame();
if (mVideoFrameContainer) {
mVideoFrameContainer->ClearCurrentFrame();
}
if (mVideo.mDecoder) {
mVideo.mDecoder->Shutdown();
@ -1643,4 +1650,11 @@ MediaFormatReader::ForceZeroStartTime() const
return !mDemuxer->ShouldComputeStartTime();
}
layers::ImageContainer*
MediaFormatReader::GetImageContainer()
{
return mVideoFrameContainer
? mVideoFrameContainer->GetImageContainer() : nullptr;
}
} // namespace mozilla

View File

@ -25,7 +25,10 @@ class MediaFormatReader final : public MediaDecoderReader
typedef media::Interval<int64_t> ByteInterval;
public:
MediaFormatReader(AbstractMediaDecoder* aDecoder, MediaDataDemuxer* aDemuxer);
MediaFormatReader(AbstractMediaDecoder* aDecoder,
MediaDataDemuxer* aDemuxer,
VideoFrameContainer* aVideoFrameContainer = nullptr,
layers::LayersBackend aLayersBackend = layers::LayersBackend::LAYERS_NONE);
virtual ~MediaFormatReader();
@ -424,6 +427,9 @@ private:
// Pending decoders initialization.
MozPromiseRequestHolder<MediaDataDecoder::InitPromise::AllPromiseType> mDecodersInitRequest;
nsRefPtr<VideoFrameContainer> mVideoFrameContainer;
layers::ImageContainer* GetImageContainer();
#ifdef MOZ_EME
nsRefPtr<CDMProxy> mCDMProxy;
#endif

View File

@ -47,7 +47,10 @@ MP4Decoder::MP4Decoder(MediaDecoderOwner* aOwner)
MediaDecoderStateMachine* MP4Decoder::CreateStateMachine()
{
MediaDecoderReader* reader = new MediaFormatReader(this, new MP4Demuxer(GetResource()));
MediaDecoderReader* reader =
new MediaFormatReader(this,
new MP4Demuxer(GetResource()),
GetVideoFrameContainer());
return new MediaDecoderStateMachine(this, reader);
}

View File

@ -46,7 +46,8 @@ MediaSourceDecoder::CreateStateMachine()
{
MOZ_ASSERT(NS_IsMainThread());
mDemuxer = new MediaSourceDemuxer();
nsRefPtr<MediaFormatReader> reader = new MediaFormatReader(this, mDemuxer);
nsRefPtr<MediaFormatReader> reader =
new MediaFormatReader(this, mDemuxer, GetVideoFrameContainer());
return new MediaDecoderStateMachine(this, reader);
}

View File

@ -427,6 +427,9 @@ GonkVideoDecoderManager::codecReserved()
format->setString("mime", mMimeType.get());
format->setInt32("width", mVideoWidth);
format->setInt32("height", mVideoHeight);
// Set the "moz-use-undequeued-bufs" to use the undeque buffers to accelerate
// the video decoding.
format->setInt32("moz-use-undequeued-bufs", 1);
if (mNativeWindow != nullptr) {
surface = new Surface(mNativeWindow->getBufferQueue());
}

View File

@ -18,7 +18,7 @@ MediaDecoderStateMachine* WebMDecoder::CreateStateMachine()
bool useFormatDecoder =
Preferences::GetBool("media.format-reader.webm", true);
nsRefPtr<MediaDecoderReader> reader = useFormatDecoder ?
static_cast<MediaDecoderReader*>(new MediaFormatReader(this, new WebMDemuxer(GetResource()))) :
static_cast<MediaDecoderReader*>(new MediaFormatReader(this, new WebMDemuxer(GetResource()), GetVideoFrameContainer())) :
new WebMReader(this);
return new MediaDecoderStateMachine(this, reader);
}

View File

@ -97,8 +97,8 @@ NfcContentHelper.prototype = {
return cpmm.sendSyncMessage("NFC:QueryInfo")[0].rfState;
},
setFocusApp: function setFocusApp(tabId, isFocus) {
cpmm.sendAsyncMessage("NFC:SetFocusApp", {
setFocusTab: function setFocusTab(tabId, isFocus) {
cpmm.sendAsyncMessage("NFC:SetFocusTab", {
tabId: tabId,
isFocus: isFocus
});

View File

@ -79,7 +79,7 @@ const NFC_IPC_MSG_ENTRIES = [
"NFC:NotifyUserAcceptedP2P",
"NFC:NotifySendFileStatus",
"NFC:ChangeRFState",
"NFC:SetFocusApp"] }
"NFC:SetFocusTab"] }
];
// Should be consistent with NfcRequestType defined in NfcOptions.webidl.
@ -148,7 +148,7 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
eventListeners: {},
focusApp: NFC.SYSTEM_APP_ID,
focusId: NFC.SYSTEM_APP_ID,
init: function init(nfc) {
this.nfc = nfc;
@ -214,7 +214,7 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
});
},
notifyFocusApp: function notifyFocusApp(options) {
notifyFocusTab: function notifyFocusTab(options) {
let tabId = this.getFocusTabId();
options.tabId = tabId;
@ -231,29 +231,29 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
},
getFocusTabId: function getFocusTabId() {
return this.eventListeners[this.focusApp] ? this.focusApp
: NFC.SYSTEM_APP_ID;
return this.eventListeners[this.focusId] ? this.focusId
: NFC.SYSTEM_APP_ID;
},
setFocusApp: function setFocusApp(id, isFocus) {
setFocusTab: function setFocusTab(id, isFocus) {
// if calling setNFCFocus(true) on the browser-element which is already
// focused, or calling setNFCFocus(false) on the browser-element which has
// lost focus already, ignore.
if (isFocus == (id == this.focusApp)) {
if (isFocus == (id == this.focusId)) {
return;
}
if (this.focusApp != NFC.SYSTEM_APP_ID) {
this.onFocusChanged(this.focusApp, false);
if (this.focusId != NFC.SYSTEM_APP_ID) {
this.onFocusChanged(this.focusId, false);
}
if (isFocus) {
// Now we only support one focus app.
this.focusApp = id;
this.onFocusChanged(this.focusApp, true);
} else if (this.focusApp == id){
// Set focusApp to SystemApp means currently there is no foreground app.
this.focusApp = NFC.SYSTEM_APP_ID;
this.focusId = id;
this.onFocusChanged(this.focusId, true);
} else if (this.focusId == id){
// Set focusId to SystemApp means currently there is no foreground app.
this.focusId = NFC.SYSTEM_APP_ID;
}
},
@ -325,17 +325,17 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
onTagFound: function onTagFound(message) {
message.event = NFC.TAG_EVENT_FOUND;
this.notifyFocusApp(message);
this.notifyFocusTab(message);
delete message.event;
},
onTagLost: function onTagLost(sessionToken) {
this.notifyFocusApp({ event: NFC.TAG_EVENT_LOST,
this.notifyFocusTab({ event: NFC.TAG_EVENT_LOST,
sessionToken: sessionToken });
},
onPeerEvent: function onPeerEvent(eventType, sessionToken) {
this.notifyFocusApp({ event: eventType,
this.notifyFocusTab({ event: eventType,
sessionToken: sessionToken });
},
@ -348,13 +348,13 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
}
},
onFocusChanged: function onFocusChanged(focusApp, focus) {
let target = this.eventListeners[focusApp];
onFocusChanged: function onFocusChanged(focusId, focus) {
let target = this.eventListeners[focusId];
if (!target) {
return;
}
this.notifyDOMEvent(target, { tabId: this.focusApp,
this.notifyDOMEvent(target, { tabId: this.focusId,
event: NFC.FOCUS_CHANGED,
focus: focus });
},
@ -386,8 +386,8 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
}
switch (message.name) {
case "NFC:SetFocusApp":
this.setFocusApp(message.data.tabId, message.data.isFocus);
case "NFC:SetFocusTab":
this.setFocusTab(message.data.tabId, message.data.isFocus);
return null;
case "NFC:AddEventListener":
this.addEventListener(message.target, message.data.tabId);

View File

@ -115,12 +115,12 @@ interface nsINfcRequestCallback : nsISupports
void notifyError(in DOMString errorMsg);
};
[scriptable, uuid(2dbc73d4-ba16-4c89-bce5-3c22cee6b50a)]
[scriptable, uuid(9f86c799-6959-4ad2-bdd6-6fbf49b52d1c)]
interface nsINfcBrowserAPI : nsISupports
{
const int32_t SYSTEM_APP_ID = 0;
void setFocusApp(in uint64_t tabId,
void setFocusTab(in uint64_t tabId,
in boolean isFocus);
};

View File

@ -69,6 +69,12 @@ static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
#ifdef XP_WIN
#include <wtypes.h>
#include <winuser.h>
#ifndef WM_MOUSEHWHEEL
#define WM_MOUSEHWHEEL (0x020E)
#endif
#ifndef SPI_GETWHEELSCROLLCHARS
#define SPI_GETWHEELSCROLLCHARS (0x006C)
#endif
#endif
#ifdef XP_MACOSX
@ -2049,21 +2055,24 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent)
// we can get synthetic events from the EventStateManager... these
// have no pluginEvent
NPEvent pluginEvent;
if (anEvent.mClass == eMouseEventClass) {
if (anEvent.mClass == eMouseEventClass ||
anEvent.mClass == eWheelEventClass) {
if (!pPluginEvent) {
// XXX Should extend this list to synthesize events for more event
// types
pluginEvent.event = 0;
const WidgetMouseEvent* mouseEvent = anEvent.AsMouseEvent();
bool initWParamWithCurrentState = true;
switch (anEvent.mMessage) {
case eMouseMove:
case eMouseMove: {
pluginEvent.event = WM_MOUSEMOVE;
break;
}
case eMouseDown: {
static const int downMsgs[] =
{ WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
static const int dblClickMsgs[] =
{ WM_LBUTTONDBLCLK, WM_MBUTTONDBLCLK, WM_RBUTTONDBLCLK };
const WidgetMouseEvent* mouseEvent = anEvent.AsMouseEvent();
if (mouseEvent->clickCount == 2) {
pluginEvent.event = dblClickMsgs[mouseEvent->button];
} else {
@ -2074,16 +2083,99 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent)
case eMouseUp: {
static const int upMsgs[] =
{ WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
const WidgetMouseEvent* mouseEvent = anEvent.AsMouseEvent();
pluginEvent.event = upMsgs[mouseEvent->button];
break;
}
// For plugins which don't support high-resolution scroll, we should
// generate legacy resolution wheel messages. I.e., the delta value
// should be WHEEL_DELTA * n.
case eWheel: {
const WidgetWheelEvent* wheelEvent = anEvent.AsWheelEvent();
int32_t delta = 0;
if (wheelEvent->lineOrPageDeltaY) {
switch (wheelEvent->deltaMode) {
case nsIDOMWheelEvent::DOM_DELTA_PAGE:
pluginEvent.event = WM_MOUSEWHEEL;
delta = -WHEEL_DELTA * wheelEvent->lineOrPageDeltaY;
break;
case nsIDOMWheelEvent::DOM_DELTA_LINE: {
UINT linesPerWheelDelta = 0;
if (NS_WARN_IF(!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
&linesPerWheelDelta, 0))) {
// Use system default scroll amount, 3, when
// SPI_GETWHEELSCROLLLINES isn't available.
linesPerWheelDelta = 3;
}
if (!linesPerWheelDelta) {
break;
}
pluginEvent.event = WM_MOUSEWHEEL;
delta = -WHEEL_DELTA / linesPerWheelDelta *
wheelEvent->lineOrPageDeltaY;
break;
}
case nsIDOMWheelEvent::DOM_DELTA_PIXEL:
default:
// We don't support WM_GESTURE with this path.
MOZ_ASSERT(!pluginEvent.event);
break;
}
} else if (wheelEvent->lineOrPageDeltaX) {
switch (wheelEvent->deltaMode) {
case nsIDOMWheelEvent::DOM_DELTA_PAGE:
pluginEvent.event = WM_MOUSEHWHEEL;
delta = -WHEEL_DELTA * wheelEvent->lineOrPageDeltaX;
break;
case nsIDOMWheelEvent::DOM_DELTA_LINE: {
pluginEvent.event = WM_MOUSEHWHEEL;
UINT charsPerWheelDelta = 0;
// FYI: SPI_GETWHEELSCROLLCHARS is available on Vista or later.
if (::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0,
&charsPerWheelDelta, 0)) {
// Use system default scroll amount, 3, when
// SPI_GETWHEELSCROLLCHARS isn't available.
charsPerWheelDelta = 3;
}
if (!charsPerWheelDelta) {
break;
}
delta =
WHEEL_DELTA / charsPerWheelDelta * wheelEvent->lineOrPageDeltaX;
break;
}
case nsIDOMWheelEvent::DOM_DELTA_PIXEL:
default:
// We don't support WM_GESTURE with this path.
MOZ_ASSERT(!pluginEvent.event);
break;
}
}
if (!pluginEvent.event) {
break;
}
initWParamWithCurrentState = false;
int32_t modifiers =
(wheelEvent->IsControl() ? MK_CONTROL : 0) |
(wheelEvent->IsShift() ? MK_SHIFT : 0) |
(wheelEvent->IsLeftButtonPressed() ? MK_LBUTTON : 0) |
(wheelEvent->IsMiddleButtonPressed() ? MK_MBUTTON : 0) |
(wheelEvent->IsRightButtonPressed() ? MK_RBUTTON : 0) |
(wheelEvent->Is4thButtonPressed() ? MK_XBUTTON1 : 0) |
(wheelEvent->Is5thButtonPressed() ? MK_XBUTTON2 : 0);
pluginEvent.wParam = MAKEWPARAM(modifiers, delta);
pPluginEvent = &pluginEvent;
break;
}
// don't synthesize anything for eMouseDoubleClick, since that
// is a synthetic event generated on mouse-up, and Windows WM_*DBLCLK
// messages are sent on mouse-down
default:
break;
}
if (pluginEvent.event) {
if (pluginEvent.event && initWParamWithCurrentState) {
pPluginEvent = &pluginEvent;
pluginEvent.wParam =
(::GetKeyState(VK_CONTROL) ? MK_CONTROL : 0) |
@ -2105,7 +2197,8 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent)
anEvent.mMessage == eMouseDoubleClick ||
anEvent.mMessage == eMouseOver ||
anEvent.mMessage == eMouseOut ||
anEvent.mMessage == eMouseMove,
anEvent.mMessage == eMouseMove ||
anEvent.mMessage == eWheel,
"Incorrect event type for coordinate translation");
nsPoint pt =
nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mPluginFrame) -

View File

@ -7,6 +7,9 @@
#ifndef mozilla_dom_plugins_NPEventWindows_h
#define mozilla_dom_plugins_NPEventWindows_h 1
#ifndef WM_MOUSEHWHEEL
#define WM_MOUSEHWHEEL (0x020E)
#endif
#include "npapi.h"
namespace mozilla {
@ -92,6 +95,9 @@ struct ParamTraits<mozilla::plugins::NPRemoteEvent>
case WM_MBUTTONDBLCLK:
case WM_RBUTTONDBLCLK:
case WM_MOUSEWHEEL:
case WM_MOUSEHWHEEL:
case WM_SETFOCUS:
case WM_KILLFOCUS:
break;

View File

@ -616,7 +616,7 @@ TCPControlChannel.prototype = {
return;
}
if (!this._listener) {
this._pendingOffer = offer;
this._pendingOffer = aOffer;
return;
}
DEBUG && log("TCPControlChannel - notify offer: "

View File

@ -143,8 +143,17 @@ StrokeOptionsToPaint(SkPaint& aPaint, const StrokeOptions &aOptions)
for (uint32_t i = 0; i < dashCount; i++) {
pattern[i] = SkFloatToScalar(aOptions.mDashPattern[i % aOptions.mDashLength]);
if (!pattern[i])
pattern[i] = SK_ScalarNearlyZero;
// bugs 1002466 & 1214309 - Dash intervals that are (close to) zero
// are skipped, ignoring other stroke settings. Nudge the dash interval
// to be just large enough that it is not interpreted as degenerate.
// Ideally this value would just be SK_ScalarNearlyZero, the smallest
// reasonable value that is not zero. But error in FP operations may
// cause dash intervals to result in a value less than this and still
// be skipped. To give some headroom to allow the value to still come
// out greater-than-but-still-close-to SK_ScalarNearlyZero, fudge it
// upward by *33/32.
if (pattern[i] == 0)
pattern[i] = SkScalarMulDiv(SK_ScalarNearlyZero, 33, 32);
}
SkDashPathEffect* dash = SkDashPathEffect::Create(&pattern.front(),

View File

@ -173,6 +173,10 @@ SkPathContainsPoint(const SkPath& aPath, const Point& aPoint, const Matrix& aTra
bool
PathSkia::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const
{
if (!mPath.isFinite()) {
return false;
}
return SkPathContainsPoint(mPath, aPoint, aTransform);
}
@ -181,6 +185,10 @@ PathSkia::StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
const Point &aPoint,
const Matrix &aTransform) const
{
if (!mPath.isFinite()) {
return false;
}
SkPaint paint;
StrokeOptionsToPaint(paint, aStrokeOptions);

View File

@ -8,6 +8,7 @@
#include "Layers.h" // for Layer, etc
#include "gfx2DGlue.h"
#include "gfxPlatform.h" // for gfxPlatform
#include "mozilla/Atomics.h"
#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
#include "mozilla/layers/CompositableForwarder.h"
#include "mozilla/layers/ISurfaceAllocator.h"
@ -101,7 +102,9 @@ public:
TextureChild()
: mForwarder(nullptr)
, mMonitor("TextureChild")
, mTextureClient(nullptr)
, mDestroyed(false)
, mMainThreadOnly(false)
, mIPCOpen(false)
{
@ -118,7 +121,10 @@ public:
void WaitForCompositorRecycle()
{
mWaitForRecycle = mTextureClient;
{
MonitorAutoLock mon(mMonitor);
mWaitForRecycle = mDestroyed ? nullptr : mTextureClient;
}
RECYCLE_LOG("[CLIENT] Wait for recycle %p\n", mWaitForRecycle.get());
SendClientRecycle();
}
@ -148,10 +154,19 @@ private:
Release();
}
void SetTextureClient(TextureClient* aTextureClient) {
MonitorAutoLock mon(mMonitor);
mTextureClient = aTextureClient;
}
RefPtr<CompositableForwarder> mForwarder;
RefPtr<TextureClient> mWaitForRecycle;
// Monitor protecting mTextureClient.
Monitor mMonitor;
TextureClient* mTextureClient;
UniquePtr<KeepAlive> mKeep;
Atomic<bool> mDestroyed;
bool mMainThreadOnly;
bool mIPCOpen;
@ -210,7 +225,7 @@ TextureClient::AddFlags(TextureFlags aFlags)
MOZ_ASSERT(!IsSharedWithCompositor() ||
((GetFlags() & TextureFlags::RECYCLE) && !IsAddedToCompositableClient()));
mFlags |= aFlags;
if (mValid && mActor && mActor->IPCOpen()) {
if (mValid && mActor && !mActor->mDestroyed && mActor->IPCOpen()) {
mActor->SendRecycleTexture(mFlags);
}
}
@ -221,7 +236,7 @@ TextureClient::RemoveFlags(TextureFlags aFlags)
MOZ_ASSERT(!IsSharedWithCompositor() ||
((GetFlags() & TextureFlags::RECYCLE) && !IsAddedToCompositableClient()));
mFlags &= ~aFlags;
if (mValid && mActor && mActor->IPCOpen()) {
if (mValid && mActor && !mActor->mDestroyed && mActor->IPCOpen()) {
mActor->SendRecycleTexture(mFlags);
}
}
@ -234,7 +249,7 @@ TextureClient::RecycleTexture(TextureFlags aFlags)
mAddedToCompositableClient = false;
if (mFlags != aFlags) {
mFlags = aFlags;
if (mValid && mActor && mActor->IPCOpen()) {
if (mValid && mActor && !mActor->mDestroyed && mActor->IPCOpen()) {
mActor->SendRecycleTexture(mFlags);
}
}
@ -276,10 +291,10 @@ bool
TextureClient::InitIPDLActor(CompositableForwarder* aForwarder)
{
MOZ_ASSERT(aForwarder && aForwarder->GetMessageLoop() == mAllocator->GetMessageLoop());
if (mActor && mActor->GetForwarder() == aForwarder) {
if (mActor && !mActor->mDestroyed && mActor->GetForwarder() == aForwarder) {
return true;
}
MOZ_ASSERT(!mActor, "Cannot use a texture on several IPC channels.");
MOZ_ASSERT(!mActor || mActor->mDestroyed, "Cannot use a texture on several IPC channels.");
SurfaceDescriptor desc;
if (!ToSurfaceDescriptor(desc)) {
@ -562,6 +577,9 @@ TextureClient::KeepUntilFullDeallocation(UniquePtr<KeepAlive> aKeep, bool aMainT
void TextureClient::ForceRemove(bool sync)
{
if (mActor && mActor->mDestroyed) {
mActor = nullptr;
}
if (mValid && mActor) {
FinalizeOnIPDLThread();
if (sync || GetFlags() & TextureFlags::DEALLOCATE_CLIENT) {
@ -613,15 +631,20 @@ void
TextureClient::Finalize()
{
MOZ_ASSERT(!IsLocked());
// Always make a temporary strong reference to the actor before we use it,
// in case TextureChild::ActorDestroy might null mActor concurrently.
RefPtr<TextureChild> actor = mActor;
if (actor) {
if (actor->mDestroyed) {
actor = nullptr;
return;
}
// The actor has a raw pointer to us, actor->mTextureClient.
// Null it before RemoveTexture calls to avoid invalid actor->mTextureClient
// when calling TextureChild::ActorDestroy()
actor->mTextureClient = nullptr;
actor->SetTextureClient(nullptr);
// `actor->mWaitForRecycle` may not be null, as we may be being called from setting
// this RefPtr to null! Clearing it here will double-Release() it.

View File

@ -18,7 +18,7 @@
#include "nsRect.h" // for mozilla::gfx::IntRect
#include "nsIFile.h" // for nsIFile
#include "nsDirectoryServiceDefs.h" // for NS_OS_TMP_DIR
#include "prprf.h" // for PR_snprintf
#include "mozilla/Snprintf.h"
#include "FPSCounter.h"
namespace mozilla {
@ -209,7 +209,7 @@ FPSCounter::WriteFrameTimeStamps(PRFileDesc* fd)
{
const int bufferSize = 256;
char buffer[bufferSize];
int writtenCount = PR_snprintf(buffer, bufferSize, "FPS Data for: %s\n", mFPSName);
int writtenCount = snprintf_literal(buffer, "FPS Data for: %s\n", mFPSName);
MOZ_ASSERT(writtenCount >= 0);
PR_Write(fd, buffer, writtenCount);
@ -224,7 +224,7 @@ FPSCounter::WriteFrameTimeStamps(PRFileDesc* fd)
while (HasNext(startTimeStamp)) {
TimeDuration duration = previousSample - nextTimeStamp;
writtenCount = PR_snprintf(buffer, bufferSize, "%f,\n", duration.ToMilliseconds());
writtenCount = snprintf_literal(buffer, "%f,\n", duration.ToMilliseconds());
MOZ_ASSERT(writtenCount >= 0);
PR_Write(fd, buffer, writtenCount);
@ -309,8 +309,8 @@ FPSCounter::PrintHistogram(std::map<int, int>& aHistogram)
int fps = iter->first;
int count = iter->second;
length += PR_snprintf(buffer + length, kBufferLength - length,
"FPS: %d = %d. ", fps, count);
length += snprintf(buffer + length, kBufferLength - length,
"FPS: %d = %d. ", fps, count);
NS_ASSERTION(length >= kBufferLength, "Buffer overrun while printing FPS histogram.");
}

View File

@ -94,9 +94,11 @@ bool SkDashPathEffect::asPoints(PointData* results,
// TODO: make this test for horizontal & vertical lines more robust
bool isXAxis = true;
if (SK_Scalar1 == tangent.fX || -SK_Scalar1 == tangent.fX) {
if (SkScalarNearlyEqual(SK_Scalar1, tangent.fX) ||
SkScalarNearlyEqual(-SK_Scalar1, tangent.fX)) {
results->fSize.set(SkScalarHalf(fIntervals[0]), SkScalarHalf(rec.getWidth()));
} else if (SK_Scalar1 == tangent.fY || -SK_Scalar1 == tangent.fY) {
} else if (SkScalarNearlyEqual(SK_Scalar1, tangent.fY) ||
SkScalarNearlyEqual(-SK_Scalar1, tangent.fY)) {
results->fSize.set(SkScalarHalf(rec.getWidth()), SkScalarHalf(fIntervals[0]));
isXAxis = false;
} else if (SkPaint::kRound_Cap != rec.getCap()) {

View File

@ -8,7 +8,7 @@
#include <string.h>
#include "nsColor.h"
#include "nsColorNames.h"
#include "prprf.h"
#include "mozilla/Snprintf.h"
#include "nsString.h"
#include "mozilla/ArrayUtils.h"
@ -71,7 +71,7 @@ void RunColorTests() {
rgb = NS_RGB(r, g, b);
}
char cbuf[50];
PR_snprintf(cbuf, sizeof(cbuf), "%02x%02x%02x", r, g, b);
snprintf_literal(cbuf, "%02x%02x%02x", r, g, b);
nscolor hexrgb;
ASSERT_TRUE(NS_HexToRGB(NS_ConvertASCIItoUTF16(cbuf), &hexrgb)) <<
"hex conversion to color of '" << cbuf << "'";

View File

@ -1107,6 +1107,9 @@ OOMTest(JSContext* cx, unsigned argc, Value* vp)
return true;
}
MOZ_ASSERT(!cx->isExceptionPending());
cx->runtime()->hadOutOfMemory = false;
RootedFunction function(cx, &args[0].toObject().as<JSFunction>());
bool verbose = EnvVarIsDefined("OOM_VERBOSE");

View File

@ -0,0 +1,8 @@
if (!('oomTest' in this))
quit();
try {
gcparam("maxBytes", gcparam("gcBytes"));
newGlobal("");
} catch (e) {};
oomTest(function() {})

View File

@ -0,0 +1,7 @@
if (!('oomTest' in this) || helperThreadCount() === 0)
quit();
enableSPSProfiling();
var s = newGlobal();
s.offThreadCompileScript('oomTest(() => {});');
s.runOffThreadScript();

View File

@ -39,7 +39,7 @@ probes::EnterScript(JSContext* cx, JSScript* script, JSFunction* maybeFun,
JSRuntime* rt = cx->runtime();
if (rt->spsProfiler.enabled()) {
if (!rt->spsProfiler.enter(script, maybeFun))
if (!rt->spsProfiler.enter(cx, script, maybeFun))
return false;
MOZ_ASSERT_IF(!fp->script()->isGenerator(), !fp->hasPushedSPSFrame());
fp->setPushedSPSFrame();

View File

@ -188,11 +188,13 @@ SPSProfiler::markEvent(const char* event)
}
bool
SPSProfiler::enter(JSScript* script, JSFunction* maybeFun)
SPSProfiler::enter(JSContext* cx, JSScript* script, JSFunction* maybeFun)
{
const char* str = profileString(script, maybeFun);
if (str == nullptr)
if (str == nullptr) {
ReportOutOfMemory(cx);
return false;
}
#ifdef DEBUG
// In debug builds, assert the JS pseudo frames already on the stack

View File

@ -173,7 +173,7 @@ class SPSProfiler
* - exit: this function has ceased execution, and no further
* entries/exits will be made
*/
bool enter(JSScript* script, JSFunction* maybeFun);
bool enter(JSContext* cx, JSScript* script, JSFunction* maybeFun);
void exit(JSScript* script, JSFunction* maybeFun);
void updatePC(JSScript* script, jsbytecode* pc) {
if (enabled() && *size_ - 1 < max_) {

View File

@ -136,7 +136,9 @@ class nsDisplayListBuilder {
public:
typedef mozilla::gfx::Matrix4x4 Matrix4x4;
Preserves3DContext() {}
Preserves3DContext()
: mAccumulatedRectLevels(0)
{}
Preserves3DContext(const Preserves3DContext &aOther)
: mAccumulatedTransform()
, mAccumulatedRect()

View File

@ -12,6 +12,7 @@
#include "gfxMatrix.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/BasicEvents.h"
#include "mozilla/MouseEvents.h"
#ifdef XP_WIN
// This is needed for DoublePassRenderingEvent.
#include "mozilla/plugins/PluginMessageUtils.h"
@ -1846,6 +1847,48 @@ nsPluginFrame::HandleEvent(nsPresContext* aPresContext,
return rv;
}
void
nsPluginFrame::HandleWheelEventAsDefaultAction(WidgetWheelEvent* aWheelEvent)
{
MOZ_ASSERT(WantsToHandleWheelEventAsDefaultAction());
MOZ_ASSERT(!aWheelEvent->mFlags.mDefaultPrevented);
if (NS_WARN_IF(!mInstanceOwner) ||
NS_WARN_IF(aWheelEvent->mMessage != eWheel)) {
return;
}
// If the wheel event has native message, it should may be handled by
// HandleEvent() in the future. In such case, we should do nothing here.
if (NS_WARN_IF(!!aWheelEvent->mPluginEvent)) {
return;
}
mInstanceOwner->ProcessEvent(*aWheelEvent);
// We need to assume that the event is always consumed/handled by the
// plugin. There is no way to know if it's actually consumed/handled.
aWheelEvent->mViewPortIsOverscrolled = false;
aWheelEvent->overflowDeltaX = 0;
aWheelEvent->overflowDeltaY = 0;
}
bool
nsPluginFrame::WantsToHandleWheelEventAsDefaultAction() const
{
#ifdef XP_WIN
if (!mInstanceOwner) {
return false;
}
NPWindow* window = nullptr;
mInstanceOwner->GetWindow(window);
// On Windows, only when the plugin is windowless, we need to send wheel
// events as default action.
return window->type == NPWindowTypeDrawable;
#else
return false;
#endif
}
nsresult
nsPluginFrame::GetPluginInstance(nsNPAPIPluginInstance** aPluginInstance)
{

View File

@ -9,6 +9,7 @@
#define nsPluginFrame_h___
#include "mozilla/Attributes.h"
#include "mozilla/EventForwards.h"
#include "nsIObjectFrame.h"
#include "nsFrame.h"
#include "nsRegion.h"
@ -205,6 +206,19 @@ public:
*/
void SetScrollVisibility(bool aState);
/**
* HandleWheelEventAsDefaultAction() handles eWheel event as default action.
* This should be called only when WantsToHandleWheelEventAsDefaultAction()
* returns true.
*/
void HandleWheelEventAsDefaultAction(mozilla::WidgetWheelEvent* aEvent);
/**
* WantsToHandleWheelEventAsDefaultAction() returns true if the plugin
* may want to handle wheel events as default action.
*/
bool WantsToHandleWheelEventAsDefaultAction() const;
protected:
explicit nsPluginFrame(nsStyleContext* aContext);
virtual ~nsPluginFrame();

File diff suppressed because it is too large Load Diff

View File

@ -56,6 +56,17 @@
// Keyword used iff gfx.font_rendering.opentype_svg.enabled is true:
#define VARIANT_OPENTYPE_SVG_KEYWORD 0x40000000
// Variants that can consume more than one token
#define VARIANT_MULTIPLE_TOKENS \
(VARIANT_COLOR | /* rgb(...), hsl(...), etc. */ \
VARIANT_COUNTER | /* counter(...), counters(...) */ \
VARIANT_ATTR | /* attr(...) */ \
VARIANT_GRADIENT | /* linear-gradient(...), etc. */ \
VARIANT_TIMING_FUNCTION | /* cubic-bezier(...), steps(...) */ \
VARIANT_IMAGE_RECT | /* -moz-image-rect(...) */ \
VARIANT_CALC | /* calc(...) */ \
VARIANT_ELEMENT) /* -moz-element(...) */
// Common combinations of variants
#define VARIANT_AL (VARIANT_AUTO | VARIANT_LENGTH)
#define VARIANT_LP (VARIANT_LENGTH | VARIANT_PERCENT)

View File

@ -99,6 +99,7 @@ var validGradientAndElementValues = [
"linear-gradient(red -99px, yellow, green, blue 120%)",
"linear-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
"linear-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
"linear-gradient(red, green calc(50% + 20px), blue)",
"linear-gradient(to top, red, blue)",
"linear-gradient(to bottom, red, blue)",
@ -382,6 +383,10 @@ var invalidGradientAndElementValues = [
"-moz-linear-gradient(10 10px -45deg, red, blue) repeat",
"-moz-linear-gradient(10px 10 -45deg, red, blue) repeat",
"linear-gradient(red -99, yellow, green, blue 120%)",
/* Invalid color, calc() or -moz-image-rect() function */
"linear-gradient(red, rgb(0, rubbish, 0) 50%, red)",
"linear-gradient(red, red calc(50% + rubbish), red)",
"linear-gradient(to top calc(50% + rubbish), red, blue)",
/* Old syntax */
"-moz-linear-gradient(10px 10px, 20px, 30px 30px, 40px, from(blue), to(red))",
"-moz-radial-gradient(20px 20px, 10px 10px, from(green), to(#ff00ff))",
@ -667,7 +672,7 @@ var gCSSProperties = {
subproperties: [ "animation-name", "animation-duration", "animation-timing-function", "animation-delay", "animation-direction", "animation-fill-mode", "animation-iteration-count", "animation-play-state" ],
initial_values: [ "none none 0s 0s ease normal running 1.0", "none", "0s", "ease", "normal", "running", "1.0" ],
other_values: [ "none none 0s 0s cubic-bezier(0.25, 0.1, 0.25, 1.0) normal running 1.0", "bounce 1s linear 2s", "bounce 1s 2s linear", "bounce linear 1s 2s", "linear bounce 1s 2s", "linear 1s bounce 2s", "linear 1s 2s bounce", "1s bounce linear 2s", "1s bounce 2s linear", "1s 2s bounce linear", "1s linear bounce 2s", "1s linear 2s bounce", "1s 2s linear bounce", "bounce linear 1s", "bounce 1s linear", "linear bounce 1s", "linear 1s bounce", "1s bounce linear", "1s linear bounce", "1s 2s bounce", "1s bounce 2s", "bounce 1s 2s", "1s 2s linear", "1s linear 2s", "linear 1s 2s", "bounce 1s", "1s bounce", "linear 1s", "1s linear", "1s 2s", "2s 1s", "bounce", "linear", "1s", "height", "2s", "ease-in-out", "2s ease-in", "opacity linear", "ease-out 2s", "2s color, 1s bounce, 500ms height linear, 1s opacity 4s cubic-bezier(0.0, 0.1, 1.0, 1.0)", "1s \\32bounce linear 2s", "1s -bounce linear 2s", "1s -\\32bounce linear 2s", "1s \\32 0bounce linear 2s", "1s -\\32 0bounce linear 2s", "1s \\2bounce linear 2s", "1s -\\2bounce linear 2s", "2s, 1s bounce", "1s bounce, 2s", "2s all, 1s bounce", "1s bounce, 2s all", "1s bounce, 2s none", "2s none, 1s bounce", "2s bounce, 1s all", "2s all, 1s bounce" ],
invalid_values: [ "2s inherit", "inherit 2s", "2s bounce, 1s inherit", "2s inherit, 1s bounce", "2s initial", "2s all,, 1s bounce", "2s all, , 1s bounce" ]
invalid_values: [ "2s inherit", "inherit 2s", "2s bounce, 1s inherit", "2s inherit, 1s bounce", "2s initial", "2s all,, 1s bounce", "2s all, , 1s bounce", "bounce 1s cubic-bezier(0, rubbish) 2s", "bounce 1s steps(rubbish) 2s" ]
},
"animation-delay": {
domProp: "animationDelay",
@ -921,7 +926,7 @@ var gCSSProperties = {
"2px 2px calc(2px + 1%) 2px",
"1px 2px 2px 2px / 2px 2px calc(2px + 1%) 2px",
],
invalid_values: [ "2px -2px", "inherit 2px", "inherit / 2px", "2px inherit", "2px / inherit", "2px 2px 2px 2px 2px", "1px / 2px 2px 2px 2px 2px", "2", "2 2", "2px 2px 2px 2px / 2px 2px 2 2px" ]
invalid_values: [ "2px -2px", "inherit 2px", "inherit / 2px", "2px inherit", "2px / inherit", "2px 2px 2px 2px 2px", "1px / 2px 2px 2px 2px 2px", "2", "2 2", "2px 2px 2px 2px / 2px 2px 2 2px", "2px calc(0px + rubbish)" ]
},
"border-bottom-left-radius": {
domProp: "borderBottomLeftRadius",
@ -940,7 +945,7 @@ var gCSSProperties = {
"calc(25px*3)",
"calc(3*25px + 50%)",
],
invalid_values: [ "-1px", "4px -2px", "inherit 2px", "2px inherit", "2", "2px 2", "2 2px" ]
invalid_values: [ "-1px", "4px -2px", "inherit 2px", "2px inherit", "2", "2px 2", "2 2px", "2px calc(0px + rubbish)" ]
},
"border-bottom-right-radius": {
domProp: "borderBottomRightRadius",
@ -959,7 +964,7 @@ var gCSSProperties = {
"calc(25px*3)",
"calc(3*25px + 50%)",
],
invalid_values: [ "-1px", "4px -2px", "inherit 2px", "2px inherit", "2", "2px 2", "2 2px" ]
invalid_values: [ "-1px", "4px -2px", "inherit 2px", "2px inherit", "2", "2px 2", "2 2px", "2px calc(0px + rubbish)" ]
},
"border-top-left-radius": {
domProp: "borderTopLeftRadius",
@ -978,7 +983,7 @@ var gCSSProperties = {
"calc(25px*3)",
"calc(3*25px + 50%)",
],
invalid_values: [ "-1px", "4px -2px", "inherit 2px", "2px inherit", "2", "2px 2", "2 2px" ]
invalid_values: [ "-1px", "4px -2px", "inherit 2px", "2px inherit", "2", "2px 2", "2 2px", "2px calc(0px + rubbish)" ]
},
"border-top-right-radius": {
domProp: "borderTopRightRadius",
@ -997,7 +1002,7 @@ var gCSSProperties = {
"calc(25px*3)",
"calc(3*25px + 50%)",
],
invalid_values: [ "-1px", "4px -2px", "inherit 2px", "2px inherit", "2", "2px 2", "2 2px" ]
invalid_values: [ "-1px", "4px -2px", "inherit 2px", "2px inherit", "2", "2px 2", "2 2px", "2px calc(0px + rubbish)" ]
},
"-moz-border-right-colors": {
domProp: "MozBorderRightColors",
@ -1136,7 +1141,7 @@ var gCSSProperties = {
initial_values: [ "auto", "auto auto" ],
other_values: [ "3", "20px", "2 10px", "10px 2", "2 auto", "auto 2", "auto 50px", "50px auto" ],
invalid_values: [ "5%", "-1px", "-1", "3 5", "10px 4px", "10 2px 5in", "30px -1",
"auto 3 5px", "5 auto 20px", "auto auto auto" ]
"auto 3 5px", "5 auto 20px", "auto auto auto", "calc(50px + rubbish) 2" ]
},
"-moz-column-count": {
domProp: "MozColumnCount",
@ -1802,7 +1807,8 @@ var gCSSProperties = {
],
invalid_values: ["red", "auto", "none", "0.5 0.5", "40px #0000ff",
"border", "center red", "right diagonal",
"#00ffff bottom"]
"#00ffff bottom", "0px calc(0px + rubbish)",
"0px 0px calc(0px + rubbish)"]
},
"perspective-origin": {
domProp: "perspectiveOrigin",
@ -1977,6 +1983,9 @@ var gCSSProperties = {
"url(404.png) padding-box green padding-box",
"transparent padding-box url(404.png) border-box",
"transparent padding-box url(404.png) padding-box",
/* error inside functions */
"-moz-image-rect(url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==), rubbish, 50%, 30%, 0) transparent",
"-moz-element(#a rubbish) black",
]
},
"background-attachment": {
@ -2073,7 +2082,8 @@ var gCSSProperties = {
"top 20%", "bottom 20%", "50% left", "top 50%",
"50% bottom 10%", "right 10% 50%", "left right",
"top bottom", "left 10% right",
"top 20px bottom 20px", "left left" ],
"top 20px bottom 20px", "left left",
"0px calc(0px + rubbish)"],
quirks_values: {
"20 20": "20px 20px",
"10 5px": "10px 5px",
@ -2119,7 +2129,7 @@ var gCSSProperties = {
"calc(-20px) calc(-50%)",
"calc(-20%) calc(-50%)"
],
invalid_values: [ "contain contain", "cover cover", "cover auto", "auto cover", "contain cover", "cover contain", "-5px 3px", "3px -5px", "auto -5px", "-5px auto", "5 3" ]
invalid_values: [ "contain contain", "cover cover", "cover auto", "auto cover", "contain cover", "cover contain", "-5px 3px", "3px -5px", "auto -5px", "-5px auto", "5 3", "10px calc(10px + rubbish)" ]
},
"border": {
domProp: "border",
@ -2203,7 +2213,7 @@ var gCSSProperties = {
subproperties: [ "border-left-color", "border-left-style", "border-left-width" ],
initial_values: [ "none", "medium", "currentColor", "thin", "none medium currentcolor" ],
other_values: [ "solid", "green", "medium solid", "green solid", "10px solid", "thick solid", "5px green none" ],
invalid_values: [ "5%", "5", "5 solid green" ]
invalid_values: [ "5%", "5", "5 solid green", "calc(5px + rubbish) green solid", "5px rgb(0, rubbish, 0) solid" ]
},
"border-left-color": {
domProp: "borderLeftColor",
@ -2296,7 +2306,7 @@ var gCSSProperties = {
type: CSS_TYPE_LONGHAND,
initial_values: [ "0", "0 0", "0px", "0 0px", "calc(0px)", "calc(0px) calc(0em)", "calc(2em - 2em) calc(3px + 7px - 10px)", "calc(-5px)", "calc(-5px) calc(-5px)" ],
other_values: [ "3px", "4em 2px", "4em 0", "0px 2px", "calc(7px)", "0 calc(7px)", "calc(7px) 0", "calc(0px) calc(7px)", "calc(7px) calc(0px)", "7px calc(0px)", "calc(0px) 7px", "7px calc(0px)", "3px calc(2em)" ],
invalid_values: [ "0%", "0 0%", "-5px", "-5px -5px", "0 -5px", "-5px 0" ],
invalid_values: [ "0%", "0 0%", "-5px", "-5px -5px", "0 -5px", "-5px 0", "0 calc(0px + rubbish)" ],
quirks_values: {
"2px 5": "2px 5px",
"7": "7px",
@ -2411,7 +2421,7 @@ var gCSSProperties = {
"calc(2px) calc(2px) calc(2px)",
"calc(2px) calc(2px) calc(2px) calc(2px)"
],
invalid_values: [ "3% 3%", "1px 1px 1px 1px 1px", "2px 2px, none", "red 2px 2px blue", "inherit, 2px 2px", "2px 2px, inherit", "2px 2px -5px", "inset 4px 4px black inset", "inset inherit", "inset none", "3 3", "3px 3", "3 3px", "3px 3px 3", "3px 3px 3px 3" ]
invalid_values: [ "3% 3%", "1px 1px 1px 1px 1px", "2px 2px, none", "red 2px 2px blue", "inherit, 2px 2px", "2px 2px, inherit", "2px 2px -5px", "inset 4px 4px black inset", "inset inherit", "inset none", "3 3", "3px 3", "3 3px", "3px 3px 3", "3px 3px 3px 3", "3px calc(3px + rubbish)", "3px 3px calc(3px + rubbish)", "3px 3px 3px calc(3px + rubbish)", "3px 3px 3px 3px rgb(0, rubbish, 0)" ]
},
"caption-side": {
domProp: "captionSide",
@ -2455,7 +2465,7 @@ var gCSSProperties = {
/* XXX needs to be on pseudo-elements */
initial_values: [ "normal", "none" ],
other_values: [ '""', "''", '"hello"', "url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==)", "url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==')", 'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==")', 'counter(foo)', 'counter(bar, upper-roman)', 'counters(foo, ".")', "counters(bar, '-', lower-greek)", "'-' counter(foo) '.'", "attr(title)", "open-quote", "close-quote", "no-open-quote", "no-close-quote", "close-quote attr(title) counters(foo, '.', upper-alpha)", "counter(foo, none)", "counters(bar, '.', none)", "attr(\\32)", "attr(\\2)", "attr(-\\2)", "attr(-\\32)", "counter(\\2)", "counters(\\32, '.')", "counter(-\\32, upper-roman)", "counters(-\\2, '-', lower-greek)", "counter(\\()", "counters(a\\+b, '.')", "counter(\\}, upper-alpha)", "-moz-alt-content", "counter(foo, symbols('*'))", "counter(foo, symbols(numeric '0' '1'))", "counters(foo, '.', symbols('*'))", "counters(foo, '.', symbols(numeric '0' '1'))" ],
invalid_values: [ 'counters(foo)', 'counter(foo, ".")', 'attr("title")', "attr('title')", "attr(2)", "attr(-2)", "counter(2)", "counters(-2, '.')", "-moz-alt-content 'foo'", "'foo' -moz-alt-content" ]
invalid_values: [ 'counters(foo)', 'counter(foo, ".")', 'attr("title")', "attr('title')", "attr(2)", "attr(-2)", "counter(2)", "counters(-2, '.')", "-moz-alt-content 'foo'", "'foo' -moz-alt-content", "counter(one, two, three) 'foo'" ]
},
"counter-increment": {
domProp: "counterIncrement",
@ -3393,7 +3403,7 @@ var gCSSProperties = {
initial_values: [ "none" ],
other_values: [ "underline", "overline", "line-through", "blink", "blink line-through underline", "underline overline line-through blink", "-moz-anchor-decoration", "blink -moz-anchor-decoration",
"underline red solid", "underline #ff0000", "solid underline", "red underline", "#ff0000 underline", "dotted underline" ],
invalid_values: [ "none none", "underline none", "none underline", "blink none", "none blink", "line-through blink line-through", "underline overline line-through blink none", "underline overline line-throuh blink blink" ]
invalid_values: [ "none none", "underline none", "none underline", "blink none", "none blink", "line-through blink line-through", "underline overline line-through blink none", "underline overline line-throuh blink blink", "rgb(0, rubbish, 0) underline" ]
},
"text-decoration-color": {
domProp: "textDecorationColor",
@ -3464,7 +3474,7 @@ var gCSSProperties = {
"calc(2px) calc(2px) calc(2px)",
],
invalid_values: [ "3% 3%", "2px 2px -5px", "2px 2px 2px 2px", "2px 2px, none", "none, 2px 2px", "inherit, 2px 2px", "2px 2px, inherit", "2 2px", "2px 2", "2px 2px 2", "2px 2px 2px 2",
"calc(2px) calc(2px) calc(2px) calc(2px)"
"calc(2px) calc(2px) calc(2px) calc(2px)", "3px 3px calc(3px + rubbish)"
]
},
"text-transform": {
@ -3501,7 +3511,7 @@ var gCSSProperties = {
subproperties: [ "transition-property", "transition-duration", "transition-timing-function", "transition-delay" ],
initial_values: [ "all 0s ease 0s", "all", "0s", "0s 0s", "ease" ],
other_values: [ "all 0s cubic-bezier(0.25, 0.1, 0.25, 1.0) 0s", "width 1s linear 2s", "width 1s 2s linear", "width linear 1s 2s", "linear width 1s 2s", "linear 1s width 2s", "linear 1s 2s width", "1s width linear 2s", "1s width 2s linear", "1s 2s width linear", "1s linear width 2s", "1s linear 2s width", "1s 2s linear width", "width linear 1s", "width 1s linear", "linear width 1s", "linear 1s width", "1s width linear", "1s linear width", "1s 2s width", "1s width 2s", "width 1s 2s", "1s 2s linear", "1s linear 2s", "linear 1s 2s", "width 1s", "1s width", "linear 1s", "1s linear", "1s 2s", "2s 1s", "width", "linear", "1s", "height", "2s", "ease-in-out", "2s ease-in", "opacity linear", "ease-out 2s", "2s color, 1s width, 500ms height linear, 1s opacity 4s cubic-bezier(0.0, 0.1, 1.0, 1.0)", "1s \\32width linear 2s", "1s -width linear 2s", "1s -\\32width linear 2s", "1s \\32 0width linear 2s", "1s -\\32 0width linear 2s", "1s \\2width linear 2s", "1s -\\2width linear 2s", "2s, 1s width", "1s width, 2s", "2s all, 1s width", "1s width, 2s all", "2s all, 1s width", "2s width, 1s all" ],
invalid_values: [ "1s width, 2s none", "2s none, 1s width", "2s inherit", "inherit 2s", "2s width, 1s inherit", "2s inherit, 1s width", "2s initial", "1s width,,2s color", "1s width, ,2s color" ]
invalid_values: [ "1s width, 2s none", "2s none, 1s width", "2s inherit", "inherit 2s", "2s width, 1s inherit", "2s inherit, 1s width", "2s initial", "1s width,,2s color", "1s width, ,2s color", "bounce 1s cubic-bezier(0, rubbish) 2s", "bounce 1s steps(rubbish) 2s" ]
},
"transition-delay": {
domProp: "transitionDelay",
@ -3798,7 +3808,7 @@ var gCSSProperties = {
prerequisites: { "color": "blue" },
initial_values: [ "black", "#000", "#000000", "rgb(0,0,0)", "rgba(0,0,0,1)" ],
other_values: [ "green", "#fc3", "url('#myserver')", "url(foo.svg#myserver)", 'url("#myserver") green', "none", "currentColor", "context-fill", "context-stroke" ],
invalid_values: [ "000000", "ff00ff" ]
invalid_values: [ "000000", "ff00ff", "url('#myserver') rgb(0, rubbish, 0)" ]
},
"fill-opacity": {
domProp: "fillOpacity",
@ -4088,7 +4098,8 @@ var gCSSProperties = {
"1px 2 3px",
"1px 2 3 4px",
"-1",
"1 -1"
"1 -1",
"0 1 calc(0px + rubbish)",
]
},
"flex-basis": {
@ -5313,6 +5324,7 @@ if (IsCSSPropertyPrefEnabled("layout.css.clip-path-shapes.enabled")) {
"circle(farthest-side closest-side)",
"circle(20% 20%)",
"circle(at farthest-side)",
"circle(calc(20px + rubbish))",
"ellipse(at)",
"ellipse(at 20% 20% 30%)",
@ -5324,6 +5336,7 @@ if (IsCSSPropertyPrefEnabled("layout.css.clip-path-shapes.enabled")) {
"ellipse(farthest-side)",
"ellipse(20%)",
"ellipse(at farthest-side farthest-side)",
"ellipse(at top left calc(20px + rubbish))",
"polygon(at)",
"polygon(at 20% 20% 30%)",
@ -5345,6 +5358,8 @@ if (IsCSSPropertyPrefEnabled("layout.css.clip-path-shapes.enabled")) {
"inset(1px at 3px)",
"inset(1px round 1px // 2px)",
"inset(1px round)",
"inset(1px calc(2px + rubbish))",
"inset(1px round 2px calc(3px + rubbish))",
],
unbalanced_values: [
"polygon(30% 30%",
@ -5787,6 +5802,7 @@ if (IsCSSPropertyPrefEnabled("layout.css.grid.enabled")) {
"subgrid repeat(1, )",
"subgrid repeat(2, (40px))",
"subgrid repeat(2, foo)",
"40px calc(0px + rubbish)",
],
unbalanced_values: [
"(foo] 40px",

View File

@ -732,7 +732,7 @@ nsHttpHandler::InitUserAgentComponents()
#endif
#if defined(ANDROID) || defined(FXOS_SIMULATOR)
#ifdef ANDROID
nsCOMPtr<nsIPropertyBag2> infoService = do_GetService("@mozilla.org/system-info;1");
MOZ_ASSERT(infoService, "Could not find a system info service");
nsresult rv;
@ -753,15 +753,35 @@ nsHttpHandler::InitUserAgentComponents()
}
}
#endif
// Add the `Mobile` or `Tablet` token when running on device or in the
// b2g desktop simulator.
// Add the `Mobile` or `Tablet` or `TV` token when running on device.
bool isTablet;
rv = infoService->GetPropertyAsBool(NS_LITERAL_STRING("tablet"), &isTablet);
if (NS_SUCCEEDED(rv) && isTablet)
if (NS_SUCCEEDED(rv) && isTablet) {
mCompatDevice.AssignLiteral("Tablet");
else
mCompatDevice.AssignLiteral("Mobile");
#endif
} else {
bool isTV;
rv = infoService->GetPropertyAsBool(NS_LITERAL_STRING("tv"), &isTV);
if (NS_SUCCEEDED(rv) && isTV) {
mCompatDevice.AssignLiteral("TV");
} else {
mCompatDevice.AssignLiteral("Mobile");
}
}
#endif // ANDROID
#ifdef FXOS_SIMULATOR
{
// Add the `Mobile` or `Tablet` or `TV` token when running in the b2g
// desktop simulator via preference.
nsCString deviceType;
nsresult rv = Preferences::GetCString("devtools.useragent.device_type", &deviceType);
if (NS_SUCCEEDED(rv)) {
mCompatDevice.Assign(deviceType);
} else {
mCompatDevice.AssignLiteral("Mobile");
}
}
#endif // FXOS_SIMULATOR
#if defined(MOZ_WIDGET_GONK)
// Device model identifier should be a simple token, which can be composed

View File

@ -1 +1 @@
NSPR_4_10_9_RTM
NSPR_4_10_10_RC1

View File

@ -10,4 +10,3 @@
*/
#error "Do not include this header file."

2
nsprpub/configure vendored
View File

@ -2489,7 +2489,7 @@ test -n "$target_alias" &&
MOD_MAJOR_VERSION=4
MOD_MINOR_VERSION=10
MOD_PATCH_VERSION=9
MOD_PATCH_VERSION=10
NSPR_MODNAME=nspr20
_HAVE_PTHREADS=
USE_PTHREADS=

View File

@ -16,7 +16,7 @@ dnl = Defaults
dnl ========================================================
MOD_MAJOR_VERSION=4
MOD_MINOR_VERSION=10
MOD_PATCH_VERSION=9
MOD_PATCH_VERSION=10
NSPR_MODNAME=nspr20
_HAVE_PTHREADS=
USE_PTHREADS=

View File

@ -93,6 +93,9 @@ PR_IMPLEMENT(void) PL_InitArenaPool(
pool->mask = PR_BITMASK(PR_CeilingLog2(align));
pool->first.next = NULL;
/* Set all three addresses in pool->first to the same dummy value.
* These addresses are only compared with each other, but never
* dereferenced. */
pool->first.base = pool->first.avail = pool->first.limit =
(PRUword)PL_ARENA_ALIGN(pool, &pool->first + 1);
pool->current = &pool->first;
@ -144,10 +147,14 @@ PR_IMPLEMENT(void *) PL_ArenaAllocate(PLArenaPool *pool, PRUint32 nb)
{
PLArena *a;
char *rp; /* returned pointer */
PRUint32 nbOld;
PR_ASSERT((nb & pool->mask) == 0);
nbOld = nb;
nb = (PRUword)PL_ARENA_ALIGN(pool, nb); /* force alignment */
if (nb < nbOld)
return NULL;
/* attempt to allocate from arenas at pool->current */
{
@ -208,6 +215,7 @@ PR_IMPLEMENT(void *) PL_ArenaAllocate(PLArenaPool *pool, PRUint32 nb)
PL_MAKE_MEM_NOACCESS((void*)a->avail, a->limit - a->avail);
rp = (char *)a->avail;
a->avail += nb;
PR_ASSERT(a->avail <= a->limit);
/* the newly allocated arena is linked after pool->current
* and becomes pool->current */
a->next = pool->current->next;
@ -230,6 +238,8 @@ PR_IMPLEMENT(void *) PL_ArenaGrow(
{
void *newp;
if (PR_UINT32_MAX - size < incr)
return NULL;
PL_ARENA_ALLOCATE(newp, pool, size + incr);
if (newp)
memcpy(newp, p, size);

View File

@ -137,34 +137,39 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
#define PL_ARENA_ALLOCATE(p, pool, nb) \
PR_BEGIN_MACRO \
PLArena *_a = (pool)->current; \
PRUint32 _nb = PL_ARENA_ALIGN(pool, nb); \
PRUint32 _nb = PL_ARENA_ALIGN(pool, (PRUint32)nb); \
PRUword _p = _a->avail; \
PRUword _q = _p + _nb; \
if (_q > _a->limit) { \
if (_nb < (PRUint32)nb) { \
_p = 0; \
} else if (_nb > (_a->limit - _a->avail)) { \
_p = (PRUword)PL_ArenaAllocate(pool, _nb); \
} else { \
_a->avail = _q; \
_a->avail += _nb; \
} \
p = (void *)_p; \
PL_MAKE_MEM_UNDEFINED(p, nb); \
PL_ArenaCountAllocation(pool, nb); \
if (p) { \
PL_MAKE_MEM_UNDEFINED(p, (PRUint32)nb); \
PL_ArenaCountAllocation(pool, (PRUint32)nb); \
} \
PR_END_MACRO
#define PL_ARENA_GROW(p, pool, size, incr) \
PR_BEGIN_MACRO \
PLArena *_a = (pool)->current; \
PRUint32 _incr = PL_ARENA_ALIGN(pool, incr); \
PRUword _p = _a->avail; \
PRUword _q = _p + _incr; \
if (_p == (PRUword)(p) + PL_ARENA_ALIGN(pool, size) && \
_q <= _a->limit) { \
PL_MAKE_MEM_UNDEFINED((unsigned char *)(p) + size, incr); \
_a->avail = _q; \
PL_ArenaCountInplaceGrowth(pool, size, incr); \
PRUint32 _incr = PL_ARENA_ALIGN(pool, (PRUint32)incr); \
if (_incr < (PRUint32)incr) { \
p = NULL; \
} else if (_a->avail == (PRUword)(p) + PL_ARENA_ALIGN(pool, size) && \
_incr <= (_a->limit - _a->avail)) { \
PL_MAKE_MEM_UNDEFINED((unsigned char *)(p) + size, (PRUint32)incr); \
_a->avail += _incr; \
PL_ArenaCountInplaceGrowth(pool, size, (PRUint32)incr); \
} else { \
p = PL_ArenaGrow(pool, p, size, incr); \
p = PL_ArenaGrow(pool, p, size, (PRUint32)incr); \
} \
if (p) {\
PL_ArenaCountGrowth(pool, size, (PRUint32)incr); \
} \
PL_ArenaCountGrowth(pool, size, incr); \
PR_END_MACRO
#define PL_ARENA_MARK(pool) ((void *) (pool)->current->avail)

View File

@ -508,7 +508,7 @@
#error "Unknown MIPS endianness."
#endif
#ifdef _ABI64
#if _MIPS_SIM == _ABI64
#define IS_64

View File

@ -31,10 +31,10 @@ PR_BEGIN_EXTERN_C
** The format of the version string is
** "<major version>.<minor version>[.<patch level>] [<Beta>]"
*/
#define PR_VERSION "4.10.9"
#define PR_VERSION "4.10.10"
#define PR_VMAJOR 4
#define PR_VMINOR 10
#define PR_VPATCH 9
#define PR_VPATCH 10
#define PR_BETA PR_FALSE
/*

View File

@ -20,10 +20,10 @@
#include <stdlib.h>
/*
* This release (4.10.7) is backward compatible with the
* This release (4.10.10) is backward compatible with the
* 4.0.x, 4.1.x, 4.2.x, 4.3.x, 4.4.x, 4.5.x, 4.6.x, 4.7.x,
* 4.8.x, 4.9.x, 4.10, 4.10.1, 4.10.2, 4.10.3, 4.10.4,
* 4.10.5, 4.10.6, 4.10.7 and 4.10.8 releases.
* 4.10.5, 4.10.6, 4.10.7, 4.10.8, 4.10.9 releases.
* It, of course, is compatible with itself.
*/
static char *compatible_version[] = {
@ -39,7 +39,7 @@ static char *compatible_version[] = {
"4.9", "4.9.1", "4.9.2", "4.9.3", "4.9.4", "4.9.5",
"4.9.6",
"4.10", "4.10.1", "4.10.2", "4.10.3", "4.10.4",
"4.10.5", "4.10.6", "4.10.7", "4.10.8",
"4.10.5", "4.10.6", "4.10.7", "4.10.8", "4.10.9",
PR_VERSION
};
@ -55,7 +55,7 @@ static char *incompatible_version[] = {
"3.0", "3.0.1",
"3.1", "3.1.1", "3.1.2", "3.1.3",
"3.5", "3.5.1",
"4.10.10",
"4.10.11",
"4.11", "4.11.1",
"10.0", "11.1", "12.14.20"
};

View File

@ -1 +1 @@
NSS_3_20_RTM
NSS_3_20_1_RC0

View File

@ -10,3 +10,4 @@
*/
#error "Do not include this header file."

View File

@ -33,10 +33,10 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
*/
#define NSS_VERSION "3.20" _NSS_ECC_STRING _NSS_CUSTOMIZED
#define NSS_VERSION "3.20.1" _NSS_ECC_STRING _NSS_CUSTOMIZED
#define NSS_VMAJOR 3
#define NSS_VMINOR 20
#define NSS_VPATCH 0
#define NSS_VPATCH 1
#define NSS_VBUILD 0
#define NSS_BETA PR_FALSE

View File

@ -25,10 +25,10 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
*/
#define SOFTOKEN_VERSION "3.20" SOFTOKEN_ECC_STRING
#define SOFTOKEN_VERSION "3.20.1" SOFTOKEN_ECC_STRING
#define SOFTOKEN_VMAJOR 3
#define SOFTOKEN_VMINOR 20
#define SOFTOKEN_VPATCH 0
#define SOFTOKEN_VPATCH 1
#define SOFTOKEN_VBUILD 0
#define SOFTOKEN_BETA PR_FALSE

View File

@ -19,10 +19,10 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <Beta>]"
*/
#define NSSUTIL_VERSION "3.20"
#define NSSUTIL_VERSION "3.20.1"
#define NSSUTIL_VMAJOR 3
#define NSSUTIL_VMINOR 20
#define NSSUTIL_VPATCH 0
#define NSSUTIL_VPATCH 1
#define NSSUTIL_VBUILD 0
#define NSSUTIL_BETA PR_FALSE

View File

@ -951,6 +951,33 @@ sec_asn1d_parse_more_length (sec_asn1d_state *state,
return count;
}
/*
* Helper function for sec_asn1d_prepare_for_contents.
* Checks that a value representing a number of bytes consumed can be
* subtracted from a remaining length. If so, returns PR_TRUE.
* Otherwise, sets the error SEC_ERROR_BAD_DER, indicates that there was a
* decoding error in the given SEC_ASN1DecoderContext, and returns PR_FALSE.
*/
static PRBool
sec_asn1d_check_and_subtract_length (unsigned long *remaining,
unsigned long consumed,
SEC_ASN1DecoderContext *cx)
{
PORT_Assert(remaining);
PORT_Assert(cx);
if (!remaining || !cx) {
PORT_SetError (SEC_ERROR_INVALID_ARGS);
cx->status = decodeError;
return PR_FALSE;
}
if (*remaining < consumed) {
PORT_SetError (SEC_ERROR_BAD_DER);
cx->status = decodeError;
return PR_FALSE;
}
*remaining -= consumed;
return PR_TRUE;
}
static void
sec_asn1d_prepare_for_contents (sec_asn1d_state *state)
@ -958,6 +985,7 @@ sec_asn1d_prepare_for_contents (sec_asn1d_state *state)
SECItem *item;
PLArenaPool *poolp;
unsigned long alloc_len;
sec_asn1d_state *parent;
#ifdef DEBUG_ASN1D_STATES
{
@ -966,6 +994,63 @@ sec_asn1d_prepare_for_contents (sec_asn1d_state *state)
}
#endif
/**
* The maximum length for a child element should be constrained to the
* length remaining in the first definite length element in the ancestor
* stack. If there is no definite length element in the ancestor stack,
* there's nothing to constrain the length of the child, so there's no
* further processing necessary.
*
* It's necessary to walk the ancestor stack, because it's possible to have
* definite length children that are part of an indefinite length element,
* which is itself part of an indefinite length element, and which is
* ultimately part of a definite length element. A simple example of this
* would be the handling of constructed OCTET STRINGs in BER encoding.
*
* This algorithm finds the first definite length element in the ancestor
* stack, if any, and if so, ensures that the length of the child element
* is consistent with the number of bytes remaining in the constraining
* ancestor element (that is, after accounting for any other sibling
* elements that may have been read).
*
* It's slightly complicated by the need to account both for integer
* underflow and overflow, as well as ensure that for indefinite length
* encodings, there's also enough space for the End-of-Contents (EOC)
* octets (Tag = 0x00, Length = 0x00, or two bytes).
*/
/* Determine the maximum length available for this element by finding the
* first definite length ancestor, if any. */
parent = sec_asn1d_get_enclosing_construct(state);
while (parent && parent->indefinite) {
parent = sec_asn1d_get_enclosing_construct(parent);
}
/* If parent is null, state is either the outermost state / at the top of
* the stack, or the outermost state uses indefinite length encoding. In
* these cases, there's nothing external to constrain this element, so
* there's nothing to check. */
if (parent) {
unsigned long remaining = parent->pending;
parent = state;
do {
if (!sec_asn1d_check_and_subtract_length(
&remaining, parent->consumed, state->top) ||
/* If parent->indefinite is true, parent->contents_length is
* zero and this is a no-op. */
!sec_asn1d_check_and_subtract_length(
&remaining, parent->contents_length, state->top) ||
/* If parent->indefinite is true, then ensure there is enough
* space for an EOC tag of 2 bytes. */
(parent->indefinite && !sec_asn1d_check_and_subtract_length(
&remaining, 2, state->top))) {
/* This element is larger than its enclosing element, which is
* invalid. */
return;
}
} while ((parent = sec_asn1d_get_enclosing_construct(parent)) &&
parent->indefinite);
}
/*
* XXX I cannot decide if this allocation should exclude the case
* where state->endofcontents is true -- figure it out!
@ -1007,21 +1092,6 @@ sec_asn1d_prepare_for_contents (sec_asn1d_state *state)
*/
state->pending = state->contents_length;
/* If this item has definite length encoding, and
** is enclosed by a definite length constructed type,
** make sure it isn't longer than the remaining space in that
** constructed type.
*/
if (state->contents_length > 0) {
sec_asn1d_state *parent = sec_asn1d_get_enclosing_construct(state);
if (parent && !parent->indefinite &&
state->consumed + state->contents_length > parent->pending) {
PORT_SetError (SEC_ERROR_BAD_DER);
state->top->status = decodeError;
return;
}
}
/*
* An EXPLICIT is nothing but an outer header, which we have
* already parsed and accepted. Now we need to do the inner
@ -1720,10 +1790,107 @@ sec_asn1d_next_substring (sec_asn1d_state *state)
if (state->pending == 0)
done = PR_TRUE;
} else {
PRBool preallocatedString;
sec_asn1d_state *temp_state;
PORT_Assert (state->indefinite);
item = (SECItem *)(child->dest);
if (item != NULL && item->data != NULL) {
/**
* At this point, there's three states at play:
* child: The element that was just parsed
* state: The currently processed element
* 'parent' (aka state->parent): The enclosing construct
* of state, or NULL if this is the top-most element.
*
* This state handles both substrings of a constructed string AND
* child elements of items whose template type was that of
* SEC_ASN1_ANY, SEC_ASN1_SAVE, SEC_ASN1_ANY_CONTENTS, SEC_ASN1_SKIP
* template, as described in sec_asn1d_prepare_for_contents. For
* brevity, these will be referred to as 'string' and 'any' types.
*
* This leads to the following possibilities:
* 1: This element is an indefinite length string, part of a
* definite length string.
* 2: This element is an indefinite length string, part of an
* indefinite length string.
* 3: This element is an indefinite length any, part of a
* definite length any.
* 4: This element is an indefinite length any, part of an
* indefinite length any.
* 5: This element is an indefinite length any and does not
* meet any of the above criteria. Note that this would include
* an indefinite length string type matching an indefinite
* length any template.
*
* In Cases #1 and #3, the definite length 'parent' element will
* have allocated state->dest based on the parent elements definite
* size. During the processing of 'child', sec_asn1d_parse_leaf will
* have copied the (string, any) data directly into the offset of
* dest, as appropriate, so there's no need for this class to still
* store the child - it's already been processed.
*
* In Cases #2 and #4, dest will be set to the parent element's dest,
* but dest->data will not have been allocated yet, due to the
* indefinite length encoding. In this situation, it's necessary to
* hold onto child (and all other children) until the EOC, at which
* point, it becomes possible to compute 'state's overall length. Once
* 'state' has a computed length, this can then be fed to 'parent' (via
* this state), and then 'parent' can similarly compute the length of
* all of its children up to the EOC, which will ultimately transit to
* sec_asn1d_concat_substrings, determine the overall size needed,
* allocate, and copy the contents (of all of parent's children, which
* would include 'state', just as 'state' will have copied all of its
* children via sec_asn1d_concat_substrings)
*
* The final case, Case #5, will manifest in that item->data and
* item->len will be NULL/0, respectively, since this element was
* indefinite-length encoded. In that case, both the tag and length will
* already exist in state's subitems, via sec_asn1d_record_any_header,
* and so the contents (aka 'child') should be added to that list of
* items to concatenate in sec_asn1d_concat_substrings once the EOC
* is encountered.
*
* To distinguish #2/#4 from #1/#3, it's sufficient to walk the ancestor
* tree. If the current type is a string type, then the enclosing
* construct will be that same type (#1/#2). If the current type is an
* any type, then the enclosing construct is either an any type (#3/#4)
* or some other type (#5). Since this is BER, this nesting relationship
* between 'state' and 'parent' may go through several levels of
* constructed encoding, so continue walking the ancestor chain until a
* clear determination can be made.
*
* The variable preallocatedString is used to indicate Case #1/#3,
* indicating an in-place copy has already occurred, and Cases #2, #4,
* and #5 all have the same behaviour of adding a new substring.
*/
preallocatedString = PR_FALSE;
temp_state = state;
while (temp_state && item == temp_state->dest && temp_state->indefinite) {
sec_asn1d_state *parent = sec_asn1d_get_enclosing_construct(temp_state);
if (!parent || parent->underlying_kind != temp_state->underlying_kind) {
/* Case #5 - Either this is a top-level construct or it is part
* of some other element (e.g. a SEQUENCE), in which case, a
* new item should be allocated. */
break;
}
if (!parent->indefinite) {
/* Cases #1 / #3 - A definite length ancestor exists, for which
* this is a substring that has already copied into dest. */
preallocatedString = PR_TRUE;
break;
}
if (!parent->substring) {
/* Cases #2 / #4 - If the parent is not a substring, but is
* indefinite, then there's nothing further up that may have
* preallocated dest, thus child will not have already
* been copied in place, therefore it's necessary to save child
* as a subitem. */
break;
}
temp_state = parent;
}
if (item != NULL && item->data != NULL && !preallocatedString) {
/*
* Save the string away for later concatenation.
*/

View File

@ -186,6 +186,8 @@ tests:
allowed_build_tasks:
tasks/builds/b2g_emulator_ics_opt.yml:
task: tasks/tests/b2g_emulator_crashtest.yml
tasks/builds/b2g_emulator_x86_kk_opt.yml:
task: tasks/tests/b2g_emulator_crashtest.yml
gaia-build:
allowed_build_tasks:
tasks/builds/b2g_desktop_opt.yml:

View File

@ -32,7 +32,9 @@ task:
extra:
chunks:
total: 5
treeherderEnv:
- production
- staging
treeherder:
groupName: Reftest
groupSymbol: tc-R

View File

@ -9,12 +9,3 @@
[calc(2 * 2px) (standards)]
expected: FAIL
[1px calc(2) (quirks)]
expected: FAIL
[1px calc(2) (almost standards)]
expected: FAIL
[1px calc(2) (standards)]
expected: FAIL

Some files were not shown because too many files have changed in this diff Show More