зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to fx-team. a=merge
This commit is contained in:
Коммит
edb7f6086e
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="84cbd4391fb7175d5380fa72c04d68873ce77e6d"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a290b11627ec2b7c25980f5687a98da86641cfe4"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -128,7 +128,7 @@
|
|||
<!-- Stock Android things -->
|
||||
<project name="platform/external/icu4c" path="external/icu4c" revision="2bb01561780583cc37bc667f0ea79f48a122d8a2"/>
|
||||
<!-- dolphin specific things -->
|
||||
<project name="device/sprd" path="device/sprd" revision="1eb575040af22c58a16f90ecd04b6e1ebdee5c80"/>
|
||||
<project name="device/sprd" path="device/sprd" revision="a26ba0ab998133ad590102be1e5950818b86ce82"/>
|
||||
<project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="2ea7f18a7bc45e16cb97a835dc86ee64d2d6b0b3"/>
|
||||
<project name="platform/frameworks/av" path="frameworks/av" revision="fd359e3a74a658d9eaab1c683440ba5412535777"/>
|
||||
<project name="platform/hardware/akm" path="hardware/akm" revision="6d3be412647b0eab0adff8a2768736cf4eb68039"/>
|
||||
|
|
|
@ -19,11 +19,11 @@
|
|||
<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="84cbd4391fb7175d5380fa72c04d68873ce77e6d"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a290b11627ec2b7c25980f5687a98da86641cfe4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="3b3407510d6e2c60242e8b9b5f2bc1783ca0a0e4"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="a89cebcccc1e067ebdb71a93194f4ee79d71bd69"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
|
||||
<!-- Stock Android things -->
|
||||
|
|
|
@ -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="84cbd4391fb7175d5380fa72c04d68873ce77e6d"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a290b11627ec2b7c25980f5687a98da86641cfe4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1b1d86462d3150dceacff927536ded9fcc168419"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="84cbd4391fb7175d5380fa72c04d68873ce77e6d"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a290b11627ec2b7c25980f5687a98da86641cfe4"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -131,7 +131,7 @@
|
|||
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="f5f7fa2fc26b96d2cbd0af4569c0036fe034bb43"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="fbd2becab3825c49e756db5149552f85049c66e2"/>
|
||||
<project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="694cecf256122d0cb3b6a1a4efb4b5c7401db223"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="f810abaa47932079396ea3815df65fbdd83b1f94"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="c0bf1eec60644abbc5e72c251c15092b4c71b6a9"/>
|
||||
<project name="platform/development" path="development" revision="5968ff4e13e0d696ad8d972281fc27ae5a12829b"/>
|
||||
<project name="android-sdk" path="sdk" remote="b2g" revision="0951179277915335251c5e11d242e4e1a8c2236f"/>
|
||||
<project name="darwinstreamingserver" path="system/darwinstreamingserver" remote="b2g" revision="cf85968c7f85e0ec36e72c87ceb4837a943b8af6"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="84cbd4391fb7175d5380fa72c04d68873ce77e6d"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a290b11627ec2b7c25980f5687a98da86641cfe4"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -19,11 +19,11 @@
|
|||
<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="84cbd4391fb7175d5380fa72c04d68873ce77e6d"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a290b11627ec2b7c25980f5687a98da86641cfe4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="3b3407510d6e2c60242e8b9b5f2bc1783ca0a0e4"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="a89cebcccc1e067ebdb71a93194f4ee79d71bd69"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
|
||||
<!-- Stock Android things -->
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="84cbd4391fb7175d5380fa72c04d68873ce77e6d"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a290b11627ec2b7c25980f5687a98da86641cfe4"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="84cbd4391fb7175d5380fa72c04d68873ce77e6d"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a290b11627ec2b7c25980f5687a98da86641cfe4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1b1d86462d3150dceacff927536ded9fcc168419"/>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"git": {
|
||||
"git_revision": "84cbd4391fb7175d5380fa72c04d68873ce77e6d",
|
||||
"git_revision": "a290b11627ec2b7c25980f5687a98da86641cfe4",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "a7d22a159f8c412c7d8ebb371025b17563265c06",
|
||||
"revision": "dbc540265f837510772bbcfdc7e9181b280b2551",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -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="84cbd4391fb7175d5380fa72c04d68873ce77e6d"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a290b11627ec2b7c25980f5687a98da86641cfe4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1b1d86462d3150dceacff927536ded9fcc168419"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="84cbd4391fb7175d5380fa72c04d68873ce77e6d"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a290b11627ec2b7c25980f5687a98da86641cfe4"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -250,6 +250,7 @@ skip-if = e10s # Bug 653065 - Make the lightweight theme web installer ready for
|
|||
[browser_bug597218.js]
|
||||
[browser_bug609700.js]
|
||||
[browser_bug623155.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_bug623893.js]
|
||||
[browser_bug624734.js]
|
||||
[browser_bug633691.js]
|
||||
|
@ -369,6 +370,7 @@ skip-if = e10s # Bug 1093155 - tries to use context menu from browser-chrome and
|
|||
[browser_popupUI.js]
|
||||
skip-if = buildapp == 'mulet' || e10s # Bug 1100707 - test fails in e10s because it can't get accel-w to close the popup (?)
|
||||
[browser_popup_blocker.js]
|
||||
skip-if = e10s && debug # Frequent bug 1125520 failures
|
||||
[browser_printpreview.js]
|
||||
skip-if = buildapp == 'mulet' || e10s # Bug 1101973 - breaks the next test in e10s, and may be responsible for later timeout after logging "Error: Channel closing: too late to send/recv, messages will be lost"
|
||||
[browser_private_browsing_window.js]
|
||||
|
@ -428,6 +430,7 @@ skip-if = buildapp == 'mulet'
|
|||
skip-if = os == "linux" || os == "mac" # No tabs in titlebar on linux
|
||||
# Disabled on OS X because of bug 967917
|
||||
[browser_tabfocus.js]
|
||||
skip-if = e10s && debug # Bug 907326
|
||||
[browser_tabkeynavigation.js]
|
||||
skip-if = e10s
|
||||
[browser_tabopen_reflows.js]
|
||||
|
|
|
@ -61,6 +61,7 @@ skip-if = !crashreporter
|
|||
[browser_CTP_drag_drop.js]
|
||||
[browser_CTP_hide_overlay.js]
|
||||
[browser_CTP_iframe.js]
|
||||
skip-if = os == 'linux' || os == 'mac' # Bug 984821
|
||||
[browser_CTP_multi_allow.js]
|
||||
[browser_CTP_nonplugins.js]
|
||||
[browser_CTP_notificationBar.js]
|
||||
|
|
|
@ -97,7 +97,15 @@ AudioChannelAgent::InitInternal(nsIDOMWindow* aWindow, int32_t aChannelType,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mWindow = aWindow;
|
||||
if (aWindow) {
|
||||
nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(aWindow);
|
||||
if (!pWindow->IsInnerWindow()) {
|
||||
pWindow = pWindow->GetCurrentInnerWindow();
|
||||
}
|
||||
|
||||
mWindow = pWindow.forget();
|
||||
}
|
||||
|
||||
mAudioChannelType = aChannelType;
|
||||
|
||||
if (aUseWeakRef) {
|
||||
|
|
|
@ -37,6 +37,19 @@ using namespace mozilla;
|
|||
using namespace mozilla::dom;
|
||||
using namespace mozilla::hal;
|
||||
|
||||
// When a inner-window is destroyed we have to mute all the related
|
||||
// AudioChannelAgents. In order to do this we have to notify them after purging
|
||||
// AudioChannelService::mAgents.
|
||||
struct MOZ_STACK_CLASS WindowDestroyedEnumeratorData
|
||||
{
|
||||
explicit WindowDestroyedEnumeratorData(uint64_t aInnerID)
|
||||
: mInnerID(aInnerID)
|
||||
{}
|
||||
|
||||
nsTArray<nsRefPtr<AudioChannelAgent>> mAgents;
|
||||
uint64_t mInnerID;
|
||||
};
|
||||
|
||||
StaticRefPtr<AudioChannelService> gAudioChannelService;
|
||||
|
||||
// Mappings from 'mozaudiochannel' attribute strings to an enumeration.
|
||||
|
@ -775,11 +788,15 @@ AudioChannelService::WindowDestroyedEnumerator(AudioChannelAgent* aAgent,
|
|||
nsAutoPtr<AudioChannelAgentData>& aData,
|
||||
void* aPtr)
|
||||
{
|
||||
uint64_t* innerID = static_cast<uint64_t*>(aPtr);
|
||||
MOZ_ASSERT(innerID);
|
||||
auto* data = static_cast<WindowDestroyedEnumeratorData*>(aPtr);
|
||||
MOZ_ASSERT(data);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aAgent->Window());
|
||||
if (!window || window->WindowID() != *innerID) {
|
||||
if (!window->IsInnerWindow()) {
|
||||
window = window->GetCurrentInnerWindow();
|
||||
}
|
||||
|
||||
if (!window || window->WindowID() != data->mInnerID) {
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
|
@ -788,6 +805,7 @@ AudioChannelService::WindowDestroyedEnumerator(AudioChannelAgent* aAgent,
|
|||
|
||||
service->UnregisterType(aData->mChannel, aData->mElementHidden,
|
||||
CONTENT_PROCESS_ID_MAIN, aData->mWithVideo);
|
||||
data->mAgents.AppendElement(aAgent);
|
||||
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
@ -893,7 +911,11 @@ AudioChannelService::Observe(nsISupports* aSubject, const char* aTopic, const ch
|
|||
return rv;
|
||||
}
|
||||
|
||||
mAgents.Enumerate(WindowDestroyedEnumerator, &innerID);
|
||||
WindowDestroyedEnumeratorData data(innerID);
|
||||
mAgents.Enumerate(WindowDestroyedEnumerator, &data);
|
||||
for (uint32_t i = 0, len = data.mAgents.Length(); i < len; ++i) {
|
||||
data.mAgents[i]->NotifyAudioChannelStateChanged();
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
bool active = AnyAudioChannelIsActive();
|
||||
|
|
|
@ -226,6 +226,7 @@
|
|||
#include "nsLocation.h"
|
||||
#include "mozilla/dom/FontFaceSet.h"
|
||||
#include "mozilla/dom/BoxObject.h"
|
||||
#include "gfxVR.h"
|
||||
|
||||
#ifdef MOZ_MEDIA_NAVIGATOR
|
||||
#include "mozilla/MediaManager.h"
|
||||
|
@ -11375,6 +11376,10 @@ nsDocument::IsFullScreenDoc()
|
|||
return GetFullScreenElement() != nullptr;
|
||||
}
|
||||
|
||||
FullScreenOptions::FullScreenOptions()
|
||||
{
|
||||
}
|
||||
|
||||
class nsCallRequestFullScreen : public nsRunnable
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -1929,9 +1929,13 @@ nsFocusManager::Focus(nsPIDOMWindow* aWindow,
|
|||
}
|
||||
}
|
||||
|
||||
nsPresContext* presContext = presShell->GetPresContext();
|
||||
IMEStateManager::OnChangeFocus(presContext, nullptr,
|
||||
GetFocusMoveActionCause(aFlags));
|
||||
if (!mFocusedContent) {
|
||||
// When there is no focused content, IMEStateManager needs to adjust IME
|
||||
// enabled state with the document.
|
||||
nsPresContext* presContext = presShell->GetPresContext();
|
||||
IMEStateManager::OnChangeFocus(presContext, nullptr,
|
||||
GetFocusMoveActionCause(aFlags));
|
||||
}
|
||||
|
||||
if (!aWindowRaised)
|
||||
aWindow->UpdateCommands(NS_LITERAL_STRING("focus"), nullptr, 0);
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#include "nsExpirationTracker.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "prclist.h"
|
||||
#include "gfxVR.h"
|
||||
|
||||
class imgIRequest;
|
||||
class nsAString;
|
||||
|
@ -97,6 +96,10 @@ class Loader;
|
|||
class ImageLoader;
|
||||
} // namespace css
|
||||
|
||||
namespace gfx {
|
||||
class VRHMDInfo;
|
||||
} // namespace gfx
|
||||
|
||||
namespace dom {
|
||||
class AnimationTimeline;
|
||||
class AnonymousContent;
|
||||
|
@ -142,7 +145,7 @@ template<typename, typename> class CallbackObjectHolder;
|
|||
typedef CallbackObjectHolder<NodeFilter, nsIDOMNodeFilter> NodeFilterHolder;
|
||||
|
||||
struct FullScreenOptions {
|
||||
FullScreenOptions() { }
|
||||
FullScreenOptions();
|
||||
nsRefPtr<gfx::VRHMDInfo> mVRHMDDevice;
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 1004703 - ignore 'unsafe-inline' if nonce- or hash-source specified</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="testdiv">a</div>
|
||||
|
||||
<!-- first script whitelisted by 'unsafe-inline' -->
|
||||
<script type="application/javascript">
|
||||
document.getElementById('testdiv').innerHTML += 'b';
|
||||
</script>
|
||||
|
||||
<!-- second script whitelisted by hash -->
|
||||
<!-- sha256-uJXAPKP5NZxnVMZMUkDofh6a9P3UMRc1CRTevVPS/rI= -->
|
||||
<script type="application/javascript">
|
||||
document.getElementById('testdiv').innerHTML += 'c';
|
||||
</script>
|
||||
|
||||
<!-- thrid script whitelisted by nonce -->
|
||||
<script type="application/javascript" nonce="FooNonce">
|
||||
document.getElementById('testdiv').innerHTML += 'd';
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1 @@
|
|||
document.getElementById("testdiv").innerHTML = "allowed";
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* Custom *.sjs specifically for the needs of
|
||||
* Bug 921493 - CSP: test whitelisting of scheme-relative sources
|
||||
*/
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
Components.utils.importGlobalProperties(["URLSearchParams"]);
|
||||
let query = new URLSearchParams(request.queryString);
|
||||
|
||||
let scheme = query.get("scheme");
|
||||
let policy = query.get("policy");
|
||||
|
||||
let linkUrl = scheme +
|
||||
"://example.com/tests/dom/base/test/csp/file_scheme_relative_sources.js";
|
||||
|
||||
let html = "<!DOCTYPE HTML>" +
|
||||
"<html>" +
|
||||
"<head>" +
|
||||
"<title>test schemeless sources within CSP</title>" +
|
||||
"</head>" +
|
||||
"<body> " +
|
||||
"<div id='testdiv'>blocked</div>" +
|
||||
// try to load a scheme relative script
|
||||
"<script src='" + linkUrl + "'></script>" +
|
||||
// have an inline script that reports back to the parent whether
|
||||
// the script got loaded or not from within the sandboxed iframe.
|
||||
"<script type='application/javascript'>" +
|
||||
"window.onload = function() {" +
|
||||
"var inner = document.getElementById('testdiv').innerHTML;" +
|
||||
"window.parent.postMessage({ result: inner }, '*');" +
|
||||
"}" +
|
||||
"</script>" +
|
||||
"</body>" +
|
||||
"</html>";
|
||||
|
||||
response.setHeader("Cache-Control", "no-cache", false);
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
response.setHeader("Content-Security-Policy", policy, false);
|
||||
|
||||
response.write(html);
|
||||
}
|
|
@ -84,6 +84,9 @@ support-files =
|
|||
file_hash_source.html
|
||||
file_dual_header_testserver.sjs
|
||||
file_hash_source.html^headers^
|
||||
file_scheme_relative_sources.js
|
||||
file_scheme_relative_sources.sjs
|
||||
file_ignore_unsafe_inline.html
|
||||
file_self_none_as_hostname_confusion.html
|
||||
file_self_none_as_hostname_confusion.html^headers^
|
||||
file_csp_path_matching.html
|
||||
|
@ -139,6 +142,9 @@ skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || toolkit == 'and
|
|||
skip-if = e10s || buildapp == 'b2g' # http-on-opening-request observers are not available in child processes
|
||||
[test_hash_source.html]
|
||||
skip-if = e10s || buildapp == 'b2g' # can't compute hashes in child process (bug 958702)
|
||||
[test_scheme_relative_sources.html]
|
||||
skip-if = buildapp == 'b2g' #no ssl support
|
||||
[test_ignore_unsafe_inline.html]
|
||||
[test_self_none_as_hostname_confusion.html]
|
||||
[test_bug949549.html]
|
||||
[test_csp_path_matching.html]
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 1004703 - ignore 'unsafe-inline' if nonce- or hash-source specified</title>
|
||||
<!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe style="width:100%;" id="testframe"></iframe>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
/* Description of the test:
|
||||
* We load a page that contains three scripts using different policies
|
||||
* and make sure 'unsafe-inline' is ignored within script-src if hash-source
|
||||
* or nonce-source is specified.
|
||||
*
|
||||
* The expected output of each test is a sequence of chars.
|
||||
* E.g. the default char we expect is 'a', depending on what inline scripts
|
||||
* are allowed to run we also expect 'b', 'c', 'd'.
|
||||
*/
|
||||
|
||||
var POLICY_PREFIX = "default-src 'none'; script-src ";
|
||||
|
||||
var tests = [
|
||||
{
|
||||
policy: POLICY_PREFIX + "'unsafe-inline'",
|
||||
description: "'unsafe-inline' allows all scripts to execute",
|
||||
file: "file_ignore_unsafe_inline.html",
|
||||
result: "abcd",
|
||||
},
|
||||
{
|
||||
policy: POLICY_PREFIX + "'unsafe-inline' 'sha256-uJXAPKP5NZxnVMZMUkDofh6a9P3UMRc1CRTevVPS/rI='",
|
||||
description: "defining a hash should only allow one script to execute",
|
||||
file: "file_ignore_unsafe_inline.html",
|
||||
result: "ac",
|
||||
},
|
||||
{
|
||||
policy: POLICY_PREFIX + "'unsafe-inline' 'nonce-FooNonce'",
|
||||
description: "defining a nonce should only allow one script to execute",
|
||||
file: "file_ignore_unsafe_inline.html",
|
||||
result: "ad",
|
||||
},
|
||||
{
|
||||
policy: POLICY_PREFIX + "'unsafe-inline' 'sha256-uJXAPKP5NZxnVMZMUkDofh6a9P3UMRc1CRTevVPS/rI=' 'nonce-FooNonce'",
|
||||
description: "defining hash and nonce should allow two scripts to execute",
|
||||
file: "file_ignore_unsafe_inline.html",
|
||||
result: "acd",
|
||||
},
|
||||
{
|
||||
policy: POLICY_PREFIX + "'unsafe-inline' 'sha256-uJXAPKP5NZxnVMZMUkDofh6a9P3UMRc1CRTevVPS/rI=' 'nonce-FooNonce' 'unsafe-inline'",
|
||||
description: "defining hash, nonce and 'unsafe-inline' twice should still only allow two scripts to execute",
|
||||
file: "file_ignore_unsafe_inline.html",
|
||||
result: "acd",
|
||||
},
|
||||
{
|
||||
policy: "default-src 'unsafe-inline' 'sha256-uJXAPKP5NZxnVMZMUkDofh6a9P3UMRc1CRTevVPS/rI=' 'nonce-FooNonce' ",
|
||||
description: "unsafe-inline should *not* be ignored within default-src even if hash or nonce is specified",
|
||||
file: "file_ignore_unsafe_inline.html",
|
||||
result: "abcd",
|
||||
},
|
||||
];
|
||||
|
||||
var counter = 0;
|
||||
var curTest;
|
||||
|
||||
function loadNextTest() {
|
||||
if (counter == tests.length) {
|
||||
document.getElementById("testframe").removeEventListener("load", test, false);
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
curTest = tests[counter++];
|
||||
var src = "file_csp_testserver.sjs?file=";
|
||||
// append the file that should be served
|
||||
src += escape("tests/dom/base/test/csp/" + curTest.file);
|
||||
|
||||
// append the CSP that should be used to serve the file
|
||||
src += "&csp=" + escape(curTest.policy);
|
||||
|
||||
document.getElementById("testframe").addEventListener("load", test, false);
|
||||
document.getElementById("testframe").src = src;
|
||||
}
|
||||
|
||||
function test() {
|
||||
try {
|
||||
document.getElementById("testframe").removeEventListener('load', test, false);
|
||||
var testframe = document.getElementById("testframe");
|
||||
var divcontent = testframe.contentWindow.document.getElementById('testdiv').innerHTML;
|
||||
// sort the characters to make sure the result is in ascending order
|
||||
// in case handlers run out of order
|
||||
divcontent = divcontent.split('').sort().join('');
|
||||
|
||||
is(divcontent, curTest.result, curTest.description);
|
||||
}
|
||||
catch (e) {
|
||||
ok(false, "error: could not access content for test " + curTest.description + "!");
|
||||
}
|
||||
loadNextTest();
|
||||
}
|
||||
|
||||
loadNextTest();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,91 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 921493 - CSP: test whitelisting of scheme-relative sources</title>
|
||||
<!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe style="width:100%;" id="testframe"></iframe>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
/* Description of the test:
|
||||
* We load http and https pages and verify that scheme relative sources
|
||||
* are allowed unless its a downgrade from https -> http.
|
||||
*
|
||||
* Please note that the policy contains 'unsafe-inline' so we can use
|
||||
* an inline script to query the result from within the sandboxed iframe
|
||||
* and report it back to the parent document.
|
||||
*/
|
||||
|
||||
var POLICY = "default-src 'none'; script-src 'unsafe-inline' example.com;";
|
||||
|
||||
var tests = [
|
||||
{
|
||||
description: "http -> http",
|
||||
from: "http",
|
||||
to: "http",
|
||||
result: "allowed",
|
||||
},
|
||||
{
|
||||
description: "http -> https",
|
||||
from: "http",
|
||||
to: "https",
|
||||
result: "allowed",
|
||||
},
|
||||
{
|
||||
description: "https -> https",
|
||||
from: "https",
|
||||
to: "https",
|
||||
result: "allowed",
|
||||
},
|
||||
{
|
||||
description: "https -> http",
|
||||
from: "https",
|
||||
to: "http",
|
||||
result: "blocked",
|
||||
}
|
||||
];
|
||||
|
||||
var counter = 0;
|
||||
var curTest;
|
||||
|
||||
function loadNextTest() {
|
||||
if (counter == tests.length) {
|
||||
window.removeEventListener("message", receiveMessage, false);
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
curTest = tests[counter++];
|
||||
|
||||
var src = curTest.from +
|
||||
"://example.com/tests/dom/base/test/csp/file_scheme_relative_sources.sjs" +
|
||||
"?scheme=" + curTest.to +
|
||||
"&policy=" + escape(POLICY);
|
||||
|
||||
document.getElementById("testframe").src = src;
|
||||
}
|
||||
|
||||
// using a postMessage handler to report the result back from
|
||||
// within the sandboxed iframe without 'allow-same-origin'.
|
||||
window.addEventListener("message", receiveMessage, false);
|
||||
|
||||
function receiveMessage(event) {
|
||||
|
||||
is(event.data.result, curTest.result,
|
||||
"should be " + curTest.result + " in test (" + curTest.description + ")!");
|
||||
|
||||
loadNextTest();
|
||||
}
|
||||
|
||||
// get the test started
|
||||
loadNextTest();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -4,6 +4,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "BluetoothReplyRunnable.h"
|
||||
#include "BluetoothService.h"
|
||||
#include "BluetoothUtils.h"
|
||||
#include "mozilla/dom/BluetoothGattCharacteristicBinding.h"
|
||||
|
@ -12,6 +13,7 @@
|
|||
#include "mozilla/dom/bluetooth/BluetoothGattDescriptor.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothGattService.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
@ -58,6 +60,64 @@ BluetoothGattCharacteristic::~BluetoothGattCharacteristic()
|
|||
bs->UnregisterBluetoothSignalHandler(path, this);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
BluetoothGattCharacteristic::StartNotifications(ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
|
||||
if (!global) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = Promise::Create(global, aRv);
|
||||
NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
|
||||
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
BT_ENSURE_TRUE_REJECT(bs, NS_ERROR_NOT_AVAILABLE);
|
||||
BT_ENSURE_TRUE_REJECT(mService, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
nsRefPtr<BluetoothReplyRunnable> result =
|
||||
new BluetoothVoidReplyRunnable(
|
||||
nullptr /* DOMRequest */,
|
||||
promise,
|
||||
NS_LITERAL_STRING("GattClientStartNotifications"));
|
||||
bs->GattClientStartNotificationsInternal(mService->GetAppUuid(),
|
||||
mService->GetServiceId(),
|
||||
mCharId,
|
||||
result);
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
BluetoothGattCharacteristic::StopNotifications(ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
|
||||
if (!global) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = Promise::Create(global, aRv);
|
||||
NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
|
||||
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
BT_ENSURE_TRUE_REJECT(bs, NS_ERROR_NOT_AVAILABLE);
|
||||
BT_ENSURE_TRUE_REJECT(mService, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
nsRefPtr<BluetoothReplyRunnable> result =
|
||||
new BluetoothVoidReplyRunnable(
|
||||
nullptr /* DOMRequest */,
|
||||
promise,
|
||||
NS_LITERAL_STRING("GattClientStopNotifications"));
|
||||
bs->GattClientStopNotificationsInternal(mService->GetAppUuid(),
|
||||
mService->GetServiceId(),
|
||||
mCharId,
|
||||
result);
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothGattCharacteristic::HandleDescriptorsDiscovered(
|
||||
const BluetoothValue& aValue)
|
||||
|
|
|
@ -15,6 +15,12 @@
|
|||
#include "nsWrapperCache.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Promise;
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN_BLUETOOTH_NAMESPACE
|
||||
|
||||
class BluetoothGattService;
|
||||
|
@ -53,6 +59,12 @@ public:
|
|||
return mCharId.mInstanceId;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Methods (Web API Implementation)
|
||||
***************************************************************************/
|
||||
already_AddRefed<Promise> StartNotifications(ErrorResult& aRv);
|
||||
already_AddRefed<Promise> StopNotifications(ErrorResult& aRv);
|
||||
|
||||
/****************************************************************************
|
||||
* Others
|
||||
***************************************************************************/
|
||||
|
|
|
@ -953,7 +953,7 @@ public:
|
|||
const nsAString& aPinCode,
|
||||
BluetoothResultHandler* aRes) = 0;
|
||||
|
||||
virtual void SspReply(const nsAString& aBdAddr, const nsAString& aVariant,
|
||||
virtual void SspReply(const nsAString& aBdAddr, BluetoothSspVariant aVariant,
|
||||
bool aAccept, uint32_t aPasskey,
|
||||
BluetoothResultHandler* aRes) = 0;
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ BluetoothPairingHandle::SetPinCode(const nsAString& aPinCode, ErrorResult& aRv)
|
|||
nsRefPtr<Promise> promise = Promise::Create(global, aRv);
|
||||
NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
|
||||
|
||||
BT_ENSURE_TRUE_REJECT(mType.EqualsLiteral("enterpincodereq"),
|
||||
BT_ENSURE_TRUE_REJECT(mType.EqualsLiteral(PAIRING_REQ_TYPE_ENTERPINCODE),
|
||||
NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
|
@ -85,13 +85,13 @@ BluetoothPairingHandle::SetPinCode(const nsAString& aPinCode, ErrorResult& aRv)
|
|||
new BluetoothVoidReplyRunnable(nullptr /* DOMRequest */,
|
||||
promise,
|
||||
NS_LITERAL_STRING("SetPinCode"));
|
||||
bs->SetPinCodeInternal(mDeviceAddress, aPinCode, result);
|
||||
bs->PinReplyInternal(mDeviceAddress, true /* accept */, aPinCode, result);
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
BluetoothPairingHandle::SetPairingConfirmation(bool aConfirm, ErrorResult& aRv)
|
||||
BluetoothPairingHandle::Accept(ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
|
||||
if (!global) {
|
||||
|
@ -102,24 +102,79 @@ BluetoothPairingHandle::SetPairingConfirmation(bool aConfirm, ErrorResult& aRv)
|
|||
nsRefPtr<Promise> promise = Promise::Create(global, aRv);
|
||||
NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
|
||||
|
||||
BT_ENSURE_TRUE_REJECT(mType.EqualsLiteral("pairingconfirmationreq"),
|
||||
BT_ENSURE_TRUE_REJECT(mType.EqualsLiteral(PAIRING_REQ_TYPE_CONFIRMATION) ||
|
||||
mType.EqualsLiteral(PAIRING_REQ_TYPE_CONSENT),
|
||||
NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
BT_ENSURE_TRUE_REJECT(bs, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
BluetoothSspVariant variant;
|
||||
BT_ENSURE_TRUE_REJECT(GetSspVariant(variant), NS_ERROR_DOM_OPERATION_ERR);
|
||||
|
||||
nsRefPtr<BluetoothReplyRunnable> result =
|
||||
new BluetoothVoidReplyRunnable(nullptr /* DOMRequest */,
|
||||
promise,
|
||||
NS_LITERAL_STRING("Accept"));
|
||||
bs->SspReplyInternal(
|
||||
mDeviceAddress, variant, true /* aAccept */, result);
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
BluetoothPairingHandle::Reject(ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
|
||||
if (!global) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = Promise::Create(global, aRv);
|
||||
NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
|
||||
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
BT_ENSURE_TRUE_REJECT(bs, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
nsRefPtr<BluetoothReplyRunnable> result =
|
||||
new BluetoothVoidReplyRunnable(nullptr /* DOMRequest */,
|
||||
promise,
|
||||
NS_LITERAL_STRING(
|
||||
"SetPairingConfirmation"));
|
||||
NS_LITERAL_STRING("Reject"));
|
||||
|
||||
if (mType.EqualsLiteral(PAIRING_REQ_TYPE_ENTERPINCODE)) { // Pin request
|
||||
bs->PinReplyInternal(
|
||||
mDeviceAddress, false /* aAccept */, EmptyString(), result);
|
||||
} else { // Ssp request
|
||||
BluetoothSspVariant variant;
|
||||
BT_ENSURE_TRUE_REJECT(GetSspVariant(variant), NS_ERROR_DOM_OPERATION_ERR);
|
||||
|
||||
bs->SspReplyInternal(
|
||||
mDeviceAddress, variant, false /* aAccept */, result);
|
||||
}
|
||||
|
||||
bs->SetPairingConfirmationInternal(mDeviceAddress,
|
||||
aConfirm,
|
||||
result);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothPairingHandle::GetSspVariant(BluetoothSspVariant& aVariant)
|
||||
{
|
||||
if (mType.EqualsLiteral(PAIRING_REQ_TYPE_DISPLAYPASSKEY)) {
|
||||
aVariant = BluetoothSspVariant::SSP_VARIANT_PASSKEY_NOTIFICATION;
|
||||
} else if (mType.EqualsLiteral(PAIRING_REQ_TYPE_CONFIRMATION)) {
|
||||
aVariant = BluetoothSspVariant::SSP_VARIANT_PASSKEY_CONFIRMATION;
|
||||
} else if (mType.EqualsLiteral(PAIRING_REQ_TYPE_CONSENT)) {
|
||||
aVariant = BluetoothSspVariant::SSP_VARIANT_CONSENT;
|
||||
} else {
|
||||
BT_LOGR("Invalid SSP variant name: %s",
|
||||
NS_ConvertUTF16toUTF8(mType).get());
|
||||
aVariant = SSP_VARIANT_PASSKEY_CONFIRMATION; // silences compiler warning
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
BluetoothPairingHandle::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto)
|
||||
|
|
|
@ -47,11 +47,15 @@ public:
|
|||
aPasskey = mPasskey;
|
||||
}
|
||||
|
||||
// Reply to the enterpincodereq pairing request
|
||||
already_AddRefed<Promise>
|
||||
SetPinCode(const nsAString& aPinCode, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
SetPairingConfirmation(bool aConfirm, ErrorResult& aRv);
|
||||
// Accept the pairingconfirmationreq or pairingconsentreq pairing request
|
||||
already_AddRefed<Promise> Accept(ErrorResult& aRv);
|
||||
|
||||
// Reject the pairing request
|
||||
already_AddRefed<Promise> Reject(ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
BluetoothPairingHandle(nsPIDOMWindow* aOwner,
|
||||
|
@ -60,6 +64,15 @@ private:
|
|||
const nsAString& aPasskey);
|
||||
~BluetoothPairingHandle();
|
||||
|
||||
/**
|
||||
* Map mType into a BluetoothSspVariant enum value.
|
||||
*
|
||||
* @param aVariant [out] BluetoothSspVariant value mapped from mType.
|
||||
* @return a boolean value to indicate whether mType can map into a
|
||||
* BluetoothSspVariant value.
|
||||
*/
|
||||
bool GetSspVariant(BluetoothSspVariant& aVariant);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> mOwner;
|
||||
nsString mDeviceAddress;
|
||||
nsString mType;
|
||||
|
|
|
@ -236,13 +236,35 @@ public:
|
|||
BluetoothProfileManagerBase* aManager) = 0;
|
||||
|
||||
virtual void
|
||||
SetPinCodeInternal(const nsAString& aDeviceAddress, const nsAString& aPinCode,
|
||||
PinReplyInternal(const nsAString& aDeviceAddress,
|
||||
bool aAccept,
|
||||
const nsAString& aPinCode,
|
||||
BluetoothReplyRunnable* aRunnable) = 0;
|
||||
|
||||
virtual void
|
||||
SspReplyInternal(const nsAString& aDeviceAddress,
|
||||
BluetoothSspVariant aVariant,
|
||||
bool aAccept,
|
||||
BluetoothReplyRunnable* aRunnable) = 0;
|
||||
|
||||
/**
|
||||
* Legacy method used by bluez only to reply pincode request.
|
||||
*/
|
||||
virtual void
|
||||
SetPinCodeInternal(const nsAString& aDeviceAddress,
|
||||
const nsAString& aPinCode,
|
||||
BluetoothReplyRunnable* aRunnable) = 0;
|
||||
|
||||
/**
|
||||
* Legacy method used by bluez only to reply passkey entry request.
|
||||
*/
|
||||
virtual void
|
||||
SetPasskeyInternal(const nsAString& aDeviceAddress, uint32_t aPasskey,
|
||||
BluetoothReplyRunnable* aRunnable) = 0;
|
||||
|
||||
/**
|
||||
* Legacy method used by bluez only to reply pairing confirmation request.
|
||||
*/
|
||||
virtual void
|
||||
SetPairingConfirmationInternal(const nsAString& aDeviceAddress, bool aConfirm,
|
||||
BluetoothReplyRunnable* aRunnable) = 0;
|
||||
|
@ -350,6 +372,26 @@ public:
|
|||
DiscoverGattServicesInternal(const nsAString& aAppUuid,
|
||||
BluetoothReplyRunnable* aRunnable) = 0;
|
||||
|
||||
/**
|
||||
* Enable notifications of a given GATT characteristic.
|
||||
* (platform specific implementation)
|
||||
*/
|
||||
virtual void
|
||||
GattClientStartNotificationsInternal(const nsAString& aAppUuid,
|
||||
const BluetoothGattServiceId& aServId,
|
||||
const BluetoothGattId& aCharId,
|
||||
BluetoothReplyRunnable* aRunnable) = 0;
|
||||
|
||||
/**
|
||||
* Disable notifications of a given GATT characteristic.
|
||||
* (platform specific implementation)
|
||||
*/
|
||||
virtual void
|
||||
GattClientStopNotificationsInternal(const nsAString& aAppUuid,
|
||||
const BluetoothGattServiceId& aServId,
|
||||
const BluetoothGattId& aCharId,
|
||||
BluetoothReplyRunnable* aRunnable) = 0;
|
||||
|
||||
/**
|
||||
* Unregister a GATT client. (platform specific implementation)
|
||||
*/
|
||||
|
|
|
@ -583,25 +583,6 @@ Convert(const nsAString& aIn, BluetoothServiceName& aOut)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Convert(const nsAString& aIn, BluetoothSspVariant& aOut)
|
||||
{
|
||||
if (aIn.EqualsLiteral("PasskeyConfirmation")) {
|
||||
aOut = SSP_VARIANT_PASSKEY_CONFIRMATION;
|
||||
} else if (aIn.EqualsLiteral("PasskeyEntry")) {
|
||||
aOut = SSP_VARIANT_PASSKEY_ENTRY;
|
||||
} else if (aIn.EqualsLiteral("Consent")) {
|
||||
aOut = SSP_VARIANT_CONSENT;
|
||||
} else if (aIn.EqualsLiteral("PasskeyNotification")) {
|
||||
aOut = SSP_VARIANT_PASSKEY_NOTIFICATION;
|
||||
} else {
|
||||
BT_LOGR("Invalid SSP variant name: %s", NS_ConvertUTF16toUTF8(aIn).get());
|
||||
aOut = SSP_VARIANT_PASSKEY_CONFIRMATION; // silences compiler warning
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Convert(BluetoothAclState aIn, bool& aOut)
|
||||
{
|
||||
|
|
|
@ -221,9 +221,6 @@ Convert(const nsAString& aIn, BluetoothPropertyType& aOut);
|
|||
nsresult
|
||||
Convert(const nsAString& aIn, BluetoothServiceName& aOut);
|
||||
|
||||
nsresult
|
||||
Convert(const nsAString& aIn, BluetoothSspVariant& aOut);
|
||||
|
||||
nsresult
|
||||
Convert(BluetoothAclState aIn, bool& aOut);
|
||||
|
||||
|
|
|
@ -569,7 +569,7 @@ public:
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsresult SspReplyCmd(const nsAString& aBdAddr, const nsAString& aVariant,
|
||||
nsresult SspReplyCmd(const nsAString& aBdAddr, BluetoothSspVariant aVariant,
|
||||
bool aAccept, uint32_t aPasskey,
|
||||
BluetoothResultHandler* aRes)
|
||||
{
|
||||
|
@ -580,8 +580,7 @@ public:
|
|||
|
||||
nsresult rv = PackPDU(
|
||||
PackConversion<nsAString, BluetoothAddress>(aBdAddr),
|
||||
PackConversion<nsAString, BluetoothSspVariant>(aVariant),
|
||||
aAccept, aPasskey, *pdu);
|
||||
aVariant, aAccept, aPasskey, *pdu);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -2420,7 +2419,7 @@ BluetoothDaemonInterface::PinReply(const nsAString& aBdAddr, bool aAccept,
|
|||
|
||||
void
|
||||
BluetoothDaemonInterface::SspReply(const nsAString& aBdAddr,
|
||||
const nsAString& aVariant,
|
||||
BluetoothSspVariant aVariant,
|
||||
bool aAccept, uint32_t aPasskey,
|
||||
BluetoothResultHandler* aRes)
|
||||
{
|
||||
|
|
|
@ -83,7 +83,7 @@ public:
|
|||
const nsAString& aPinCode,
|
||||
BluetoothResultHandler* aRes);
|
||||
|
||||
void SspReply(const nsAString& aBdAddr, const nsAString& aVariant,
|
||||
void SspReply(const nsAString& aBdAddr, BluetoothSspVariant aVariant,
|
||||
bool aAccept, uint32_t aPasskey,
|
||||
BluetoothResultHandler* aRes);
|
||||
|
||||
|
|
|
@ -58,6 +58,8 @@ public:
|
|||
mDiscoverRunnable = nullptr;
|
||||
mUnregisterClientRunnable = nullptr;
|
||||
mReadRemoteRssiRunnable = nullptr;
|
||||
mRegisterNotificationsRunnable = nullptr;
|
||||
mDeregisterNotificationsRunnable = nullptr;
|
||||
}
|
||||
|
||||
void NotifyDiscoverCompleted(bool aSuccess)
|
||||
|
@ -98,6 +100,8 @@ public:
|
|||
nsRefPtr<BluetoothReplyRunnable> mDisconnectRunnable;
|
||||
nsRefPtr<BluetoothReplyRunnable> mDiscoverRunnable;
|
||||
nsRefPtr<BluetoothReplyRunnable> mReadRemoteRssiRunnable;
|
||||
nsRefPtr<BluetoothReplyRunnable> mRegisterNotificationsRunnable;
|
||||
nsRefPtr<BluetoothReplyRunnable> mDeregisterNotificationsRunnable;
|
||||
nsRefPtr<BluetoothReplyRunnable> mUnregisterClientRunnable;
|
||||
|
||||
/**
|
||||
|
@ -636,6 +640,151 @@ BluetoothGattManager::ReadRemoteRssi(int aClientIf,
|
|||
new ReadRemoteRssiResultHandler(client));
|
||||
}
|
||||
|
||||
class BluetoothGattManager::RegisterNotificationsResultHandler final
|
||||
: public BluetoothGattClientResultHandler
|
||||
{
|
||||
public:
|
||||
RegisterNotificationsResultHandler(BluetoothGattClient* aClient)
|
||||
: mClient(aClient)
|
||||
{
|
||||
MOZ_ASSERT(mClient);
|
||||
}
|
||||
|
||||
void RegisterNotification() override
|
||||
{
|
||||
MOZ_ASSERT(mClient->mRegisterNotificationsRunnable);
|
||||
|
||||
/**
|
||||
* Resolve the promise directly if we successfully issued this request to
|
||||
* stack.
|
||||
*
|
||||
* We resolve the promise here since bluedroid stack always returns
|
||||
* incorrect connId in |RegisterNotificationNotification| and we cannot map
|
||||
* back to the target client because of it.
|
||||
* Please see Bug 1149043 for more information.
|
||||
*/
|
||||
DispatchReplySuccess(mClient->mRegisterNotificationsRunnable);
|
||||
mClient->mRegisterNotificationsRunnable = nullptr;
|
||||
}
|
||||
|
||||
void OnError(BluetoothStatus aStatus) override
|
||||
{
|
||||
BT_WARNING(
|
||||
"BluetoothGattClientInterface::RegisterNotifications failed: %d",
|
||||
(int)aStatus);
|
||||
MOZ_ASSERT(mClient->mRegisterNotificationsRunnable);
|
||||
|
||||
DispatchReplyError(mClient->mRegisterNotificationsRunnable,
|
||||
NS_LITERAL_STRING("RegisterNotifications failed"));
|
||||
mClient->mRegisterNotificationsRunnable = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<BluetoothGattClient> mClient;
|
||||
};
|
||||
|
||||
void
|
||||
BluetoothGattManager::RegisterNotifications(
|
||||
const nsAString& aAppUuid, const BluetoothGattServiceId& aServId,
|
||||
const BluetoothGattId& aCharId, BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aRunnable);
|
||||
|
||||
ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable);
|
||||
|
||||
size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator());
|
||||
MOZ_ASSERT(index != sClients->NoIndex);
|
||||
|
||||
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
|
||||
|
||||
// Reject the request if there is an ongoing request or client is already
|
||||
// disconnected
|
||||
if (client->mRegisterNotificationsRunnable || client->mConnId <= 0) {
|
||||
DispatchReplyError(aRunnable,
|
||||
NS_LITERAL_STRING("RegisterNotifications failed"));
|
||||
return;
|
||||
}
|
||||
|
||||
client->mRegisterNotificationsRunnable = aRunnable;
|
||||
|
||||
sBluetoothGattClientInterface->RegisterNotification(
|
||||
client->mClientIf, client->mDeviceAddr, aServId, aCharId,
|
||||
new RegisterNotificationsResultHandler(client));
|
||||
}
|
||||
|
||||
class BluetoothGattManager::DeregisterNotificationsResultHandler final
|
||||
: public BluetoothGattClientResultHandler
|
||||
{
|
||||
public:
|
||||
DeregisterNotificationsResultHandler(BluetoothGattClient* aClient)
|
||||
: mClient(aClient)
|
||||
{
|
||||
MOZ_ASSERT(mClient);
|
||||
}
|
||||
|
||||
void DeregisterNotification() override
|
||||
{
|
||||
MOZ_ASSERT(mClient->mDeregisterNotificationsRunnable);
|
||||
|
||||
/**
|
||||
* Resolve the promise directly if we successfully issued this request to
|
||||
* stack.
|
||||
*
|
||||
* We resolve the promise here since bluedroid stack always returns
|
||||
* incorrect connId in |RegisterNotificationNotification| and we cannot map
|
||||
* back to the target client because of it.
|
||||
* Please see Bug 1149043 for more information.
|
||||
*/
|
||||
DispatchReplySuccess(mClient->mDeregisterNotificationsRunnable);
|
||||
mClient->mDeregisterNotificationsRunnable = nullptr;
|
||||
}
|
||||
|
||||
void OnError(BluetoothStatus aStatus) override
|
||||
{
|
||||
BT_WARNING(
|
||||
"BluetoothGattClientInterface::DeregisterNotifications failed: %d",
|
||||
(int)aStatus);
|
||||
MOZ_ASSERT(mClient->mDeregisterNotificationsRunnable);
|
||||
|
||||
DispatchReplyError(mClient->mDeregisterNotificationsRunnable,
|
||||
NS_LITERAL_STRING("DeregisterNotifications failed"));
|
||||
mClient->mDeregisterNotificationsRunnable = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<BluetoothGattClient> mClient;
|
||||
};
|
||||
|
||||
void
|
||||
BluetoothGattManager::DeregisterNotifications(
|
||||
const nsAString& aAppUuid, const BluetoothGattServiceId& aServId,
|
||||
const BluetoothGattId& aCharId, BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aRunnable);
|
||||
|
||||
ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable);
|
||||
|
||||
size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator());
|
||||
MOZ_ASSERT(index != sClients->NoIndex);
|
||||
|
||||
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
|
||||
|
||||
// Reject the request if there is an ongoing request
|
||||
if (client->mDeregisterNotificationsRunnable) {
|
||||
DispatchReplyError(aRunnable,
|
||||
NS_LITERAL_STRING("DeregisterNotifications failed"));
|
||||
return;
|
||||
}
|
||||
|
||||
client->mDeregisterNotificationsRunnable = aRunnable;
|
||||
|
||||
sBluetoothGattClientInterface->DeregisterNotification(
|
||||
client->mClientIf, client->mDeviceAddr, aServId, aCharId,
|
||||
new DeregisterNotificationsResultHandler(client));
|
||||
}
|
||||
|
||||
//
|
||||
// Notification Handlers
|
||||
//
|
||||
|
@ -999,7 +1148,25 @@ BluetoothGattManager::RegisterNotificationNotification(
|
|||
int aConnId, int aIsRegister, BluetoothGattStatus aStatus,
|
||||
const BluetoothGattServiceId& aServiceId,
|
||||
const BluetoothGattId& aCharId)
|
||||
{ }
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
BT_LOGD("aStatus = %d, aConnId = %d, aIsRegister = %d",
|
||||
aStatus, aConnId, aIsRegister);
|
||||
|
||||
/**
|
||||
* FIXME: Bug 1149043
|
||||
*
|
||||
* aConnId reported by bluedroid stack is wrong, with these limited
|
||||
* information we have, we currently cannot map back to the client from this
|
||||
* callback. Therefore, we resolve/reject the Promise for registering or
|
||||
* deregistering notifications in their result handlers instead of this
|
||||
* callback.
|
||||
* We should resolve/reject the Promise for registering or deregistering
|
||||
* notifications here if this bluedroid stack bug is fixed.
|
||||
*
|
||||
* Please see Bug 1149043 for more information.
|
||||
*/
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothGattManager::NotifyNotification(
|
||||
|
|
|
@ -46,6 +46,16 @@ public:
|
|||
const nsAString& aDeviceAddr,
|
||||
BluetoothReplyRunnable* aRunnable);
|
||||
|
||||
void RegisterNotifications(const nsAString& aAppUuid,
|
||||
const BluetoothGattServiceId& aServId,
|
||||
const BluetoothGattId& aCharId,
|
||||
BluetoothReplyRunnable* aRunnable);
|
||||
|
||||
void DeregisterNotifications(const nsAString& aAppUuid,
|
||||
const BluetoothGattServiceId& aServId,
|
||||
const BluetoothGattId& aCharId,
|
||||
BluetoothReplyRunnable* aRunnable);
|
||||
|
||||
private:
|
||||
class CleanupResultHandler;
|
||||
class CleanupResultHandlerRunnable;
|
||||
|
@ -56,6 +66,8 @@ private:
|
|||
class DisconnectResultHandler;
|
||||
class DiscoverResultHandler;
|
||||
class ReadRemoteRssiResultHandler;
|
||||
class RegisterNotificationsResultHandler;
|
||||
class DeregisterNotificationsResultHandler;
|
||||
|
||||
BluetoothGattManager();
|
||||
|
||||
|
|
|
@ -80,25 +80,6 @@ Convert(const nsAString& aIn, bt_bdaddr_t& aOut)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Convert(const nsAString& aIn, bt_ssp_variant_t& aOut)
|
||||
{
|
||||
if (aIn.EqualsLiteral("PasskeyConfirmation")) {
|
||||
aOut = BT_SSP_VARIANT_PASSKEY_CONFIRMATION;
|
||||
} else if (aIn.EqualsLiteral("PasskeyEntry")) {
|
||||
aOut = BT_SSP_VARIANT_PASSKEY_ENTRY;
|
||||
} else if (aIn.EqualsLiteral("Consent")) {
|
||||
aOut = BT_SSP_VARIANT_CONSENT;
|
||||
} else if (aIn.EqualsLiteral("PasskeyNotification")) {
|
||||
aOut = BT_SSP_VARIANT_PASSKEY_NOTIFICATION;
|
||||
} else {
|
||||
BT_LOGR("Invalid SSP variant name: %s", NS_ConvertUTF16toUTF8(aIn).get());
|
||||
aOut = BT_SSP_VARIANT_PASSKEY_CONFIRMATION; // silences compiler warning
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Convert(const uint8_t aIn[16], bt_uuid_t& aOut)
|
||||
{
|
||||
|
|
|
@ -110,9 +110,6 @@ Convert(ConvertNamedValue& aIn, bt_property_t& aOut);
|
|||
nsresult
|
||||
Convert(const nsAString& aIn, bt_bdaddr_t& aOut);
|
||||
|
||||
nsresult
|
||||
Convert(const nsAString& aIn, bt_ssp_variant_t& aOut);
|
||||
|
||||
inline nsresult
|
||||
Convert(const bt_ssp_variant_t& aIn, BluetoothSspVariant& aOut)
|
||||
{
|
||||
|
@ -131,6 +128,24 @@ Convert(const bt_ssp_variant_t& aIn, BluetoothSspVariant& aOut)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
inline nsresult
|
||||
Convert(const BluetoothSspVariant& aIn, bt_ssp_variant_t& aOut)
|
||||
{
|
||||
static const bt_ssp_variant_t sSspVariant[] = {
|
||||
CONVERT(SSP_VARIANT_PASSKEY_CONFIRMATION,
|
||||
BT_SSP_VARIANT_PASSKEY_CONFIRMATION),
|
||||
CONVERT(SSP_VARIANT_PASSKEY_ENTRY, BT_SSP_VARIANT_PASSKEY_ENTRY),
|
||||
CONVERT(SSP_VARIANT_CONSENT, BT_SSP_VARIANT_CONSENT),
|
||||
CONVERT(SSP_VARIANT_PASSKEY_NOTIFICATION,
|
||||
BT_SSP_VARIANT_PASSKEY_NOTIFICATION)
|
||||
};
|
||||
if (aIn >= MOZ_ARRAY_LENGTH(sSspVariant)) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
aOut = sSspVariant[aIn];
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
inline nsresult
|
||||
Convert(const bool& aIn, uint8_t& aOut)
|
||||
{
|
||||
|
|
|
@ -769,7 +769,7 @@ BluetoothHALInterface::PinReply(const nsAString& aBdAddr, bool aAccept,
|
|||
|
||||
void
|
||||
BluetoothHALInterface::SspReply(const nsAString& aBdAddr,
|
||||
const nsAString& aVariant,
|
||||
BluetoothSspVariant aVariant,
|
||||
bool aAccept, uint32_t aPasskey,
|
||||
BluetoothResultHandler* aRes)
|
||||
{
|
||||
|
|
|
@ -69,7 +69,7 @@ public:
|
|||
const nsAString& aPinCode,
|
||||
BluetoothResultHandler* aRes);
|
||||
|
||||
void SspReply(const nsAString& aBdAddr, const nsAString& aVariant,
|
||||
void SspReply(const nsAString& aBdAddr, BluetoothSspVariant aVariant,
|
||||
bool aAccept, uint32_t aPasskey,
|
||||
BluetoothResultHandler* aRes);
|
||||
|
||||
|
|
|
@ -768,25 +768,18 @@ private:
|
|||
};
|
||||
|
||||
void
|
||||
BluetoothServiceBluedroid::SetPinCodeInternal(
|
||||
const nsAString& aDeviceAddress, const nsAString& aPinCode,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
BluetoothServiceBluedroid::PinReplyInternal(
|
||||
const nsAString& aDeviceAddress, bool aAccept,
|
||||
const nsAString& aPinCode, BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
ENSURE_BLUETOOTH_IS_READY_VOID(aRunnable);
|
||||
|
||||
sBtInterface->PinReply(aDeviceAddress, true, aPinCode,
|
||||
new PinReplyResultHandler(aRunnable));
|
||||
sBtInterface->PinReply(aDeviceAddress, aAccept, aPinCode,
|
||||
new PinReplyResultHandler(aRunnable));
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothServiceBluedroid::SetPasskeyInternal(
|
||||
const nsAString& aDeviceAddress, uint32_t aPasskey,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
class BluetoothServiceBluedroid::SspReplyResultHandler final
|
||||
: public BluetoothResultHandler
|
||||
|
@ -811,19 +804,43 @@ private:
|
|||
};
|
||||
|
||||
void
|
||||
BluetoothServiceBluedroid::SetPairingConfirmationInternal(
|
||||
const nsAString& aDeviceAddress, bool aConfirm,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
BluetoothServiceBluedroid::SspReplyInternal(
|
||||
const nsAString& aDeviceAddress, BluetoothSspVariant aVariant,
|
||||
bool aAccept, BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
ENSURE_BLUETOOTH_IS_READY_VOID(aRunnable);
|
||||
|
||||
sBtInterface->SspReply(aDeviceAddress,
|
||||
NS_ConvertUTF8toUTF16("PasskeyConfirmation"),
|
||||
aConfirm, 0, new SspReplyResultHandler(aRunnable));
|
||||
sBtInterface->SspReply(aDeviceAddress, aVariant, aAccept, 0 /* passkey */,
|
||||
new SspReplyResultHandler(aRunnable));
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothServiceBluedroid::SetPinCodeInternal(
|
||||
const nsAString& aDeviceAddress, const nsAString& aPinCode,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
// Legacy method used by bluez only.
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothServiceBluedroid::SetPasskeyInternal(
|
||||
const nsAString& aDeviceAddress, uint32_t aPasskey,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
// Legacy method used by bluez only.
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothServiceBluedroid::SetPairingConfirmationInternal(
|
||||
const nsAString& aDeviceAddress, bool aConfirm,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
// Legacy method used by bluez only.
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BluetoothServiceBluedroid::NextBluetoothProfileController()
|
||||
{
|
||||
|
@ -1131,6 +1148,36 @@ BluetoothServiceBluedroid::DiscoverGattServicesInternal(
|
|||
gatt->Discover(aAppUuid, aRunnable);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothServiceBluedroid::GattClientStartNotificationsInternal(
|
||||
const nsAString& aAppUuid, const BluetoothGattServiceId& aServId,
|
||||
const BluetoothGattId& aCharId, BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
ENSURE_BLUETOOTH_IS_READY_VOID(aRunnable);
|
||||
|
||||
BluetoothGattManager* gatt = BluetoothGattManager::Get();
|
||||
ENSURE_GATT_MGR_IS_READY_VOID(gatt, aRunnable);
|
||||
|
||||
gatt->RegisterNotifications(aAppUuid, aServId, aCharId, aRunnable);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothServiceBluedroid::GattClientStopNotificationsInternal(
|
||||
const nsAString& aAppUuid, const BluetoothGattServiceId& aServId,
|
||||
const BluetoothGattId& aCharId, BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
ENSURE_BLUETOOTH_IS_READY_VOID(aRunnable);
|
||||
|
||||
BluetoothGattManager* gatt = BluetoothGattManager::Get();
|
||||
ENSURE_GATT_MGR_IS_READY_VOID(gatt, aRunnable);
|
||||
|
||||
gatt->DeregisterNotifications(aAppUuid, aServId, aCharId, aRunnable);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothServiceBluedroid::UnregisterGattClientInternal(
|
||||
int aClientIf, BluetoothReplyRunnable* aRunnable)
|
||||
|
|
|
@ -81,15 +81,30 @@ public:
|
|||
BluetoothReplyRunnable* aRunnable);
|
||||
|
||||
virtual void
|
||||
SetPinCodeInternal(const nsAString& aDeviceAddress, const nsAString& aPinCode,
|
||||
PinReplyInternal(const nsAString& aDeviceAddress,
|
||||
bool aAccept,
|
||||
const nsAString& aPinCode,
|
||||
BluetoothReplyRunnable* aRunnable);
|
||||
|
||||
virtual void
|
||||
SspReplyInternal(const nsAString& aDeviceAddress,
|
||||
BluetoothSspVariant aVariant,
|
||||
bool aAccept,
|
||||
BluetoothReplyRunnable* aRunnable);
|
||||
|
||||
virtual void
|
||||
SetPinCodeInternal(const nsAString& aDeviceAddress,
|
||||
const nsAString& aPinCode,
|
||||
BluetoothReplyRunnable* aRunnable);
|
||||
|
||||
virtual void
|
||||
SetPasskeyInternal(const nsAString& aDeviceAddress, uint32_t aPasskey,
|
||||
SetPasskeyInternal(const nsAString& aDeviceAddress,
|
||||
uint32_t aPasskey,
|
||||
BluetoothReplyRunnable* aRunnable);
|
||||
|
||||
virtual void
|
||||
SetPairingConfirmationInternal(const nsAString& aDeviceAddress, bool aConfirm,
|
||||
SetPairingConfirmationInternal(const nsAString& aDeviceAddress,
|
||||
bool aConfirm,
|
||||
BluetoothReplyRunnable* aRunnable);
|
||||
|
||||
virtual void
|
||||
|
@ -188,6 +203,20 @@ public:
|
|||
DiscoverGattServicesInternal(const nsAString& aAppUuid,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
||||
virtual void
|
||||
GattClientStartNotificationsInternal(
|
||||
const nsAString& aAppUuid,
|
||||
const BluetoothGattServiceId& aServId,
|
||||
const BluetoothGattId& aCharId,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
||||
virtual void
|
||||
GattClientStopNotificationsInternal(
|
||||
const nsAString& aAppUuid,
|
||||
const BluetoothGattServiceId& aServId,
|
||||
const BluetoothGattId& aCharId,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
||||
virtual void
|
||||
UnregisterGattClientInternal(int aClientIf,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
|
|
@ -4277,6 +4277,10 @@ BluetoothDBusService::UpdateNotification(ControlEventId aEventId,
|
|||
DispatchToDBusThread(task);
|
||||
}
|
||||
|
||||
//
|
||||
// Methods for BT APIv2 implementation which currently only supports bluedroid
|
||||
//
|
||||
|
||||
void
|
||||
BluetoothDBusService::ConnectGattClientInternal(
|
||||
const nsAString& aAppUuid, const nsAString& aDeviceAddress,
|
||||
|
@ -4297,6 +4301,20 @@ BluetoothDBusService::DiscoverGattServicesInternal(
|
|||
{
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDBusService::GattClientStartNotificationsInternal(
|
||||
const nsAString& aAppUuid, const BluetoothGattServiceId& aServId,
|
||||
const BluetoothGattId& aCharId, BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDBusService::GattClientStopNotificationsInternal(
|
||||
const nsAString& aAppUuid, const BluetoothGattServiceId& aServId,
|
||||
const BluetoothGattId& aCharId, BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDBusService::UnregisterGattClientInternal(
|
||||
int aClientIf, BluetoothReplyRunnable* aRunnable)
|
||||
|
@ -4309,3 +4327,17 @@ BluetoothDBusService::GattClientReadRemoteRssiInternal(
|
|||
BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDBusService::PinReplyInternal(
|
||||
const nsAString& aDeviceAddress, bool aAccept,
|
||||
const nsAString& aPinCode, BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDBusService::SspReplyInternal(
|
||||
const nsAString& aDeviceAddress, BluetoothSspVariant aVariant,
|
||||
bool aAccept, BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -94,7 +94,20 @@ public:
|
|||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
||||
virtual void
|
||||
SetPinCodeInternal(const nsAString& aDeviceAddress, const nsAString& aPinCode,
|
||||
PinReplyInternal(const nsAString& aDeviceAddress,
|
||||
bool aAccept,
|
||||
const nsAString& aPinCode,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
|
||||
virtual void
|
||||
SspReplyInternal(const nsAString& aDeviceAddress,
|
||||
BluetoothSspVariant aVariant,
|
||||
bool aAccept,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
|
||||
virtual void
|
||||
SetPinCodeInternal(const nsAString& aDeviceAddress,
|
||||
const nsAString& aPinCode,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
||||
virtual void
|
||||
|
@ -102,7 +115,8 @@ public:
|
|||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
||||
virtual void
|
||||
SetPairingConfirmationInternal(const nsAString& aDeviceAddress, bool aConfirm,
|
||||
SetPairingConfirmationInternal(const nsAString& aDeviceAddress,
|
||||
bool aConfirm,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
||||
virtual void
|
||||
|
@ -199,6 +213,20 @@ public:
|
|||
DiscoverGattServicesInternal(const nsAString& aAppUuid,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
||||
virtual void
|
||||
GattClientStartNotificationsInternal(
|
||||
const nsAString& aAppUuid,
|
||||
const BluetoothGattServiceId& aServId,
|
||||
const BluetoothGattId& aCharId,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
||||
virtual void
|
||||
GattClientStopNotificationsInternal(
|
||||
const nsAString& aAppUuid,
|
||||
const BluetoothGattServiceId& aServId,
|
||||
const BluetoothGattId& aCharId,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
||||
virtual void
|
||||
UnregisterGattClientInternal(int aClientIf,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
|
|
@ -20,6 +20,14 @@ struct ParamTraits<mozilla::dom::bluetooth::BluetoothObjectType>
|
|||
mozilla::dom::bluetooth::TYPE_INVALID>
|
||||
{ };
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::dom::bluetooth::BluetoothSspVariant>
|
||||
: public ContiguousEnumSerializer<
|
||||
mozilla::dom::bluetooth::BluetoothSspVariant,
|
||||
mozilla::dom::bluetooth::SSP_VARIANT_PASSKEY_CONFIRMATION,
|
||||
mozilla::dom::bluetooth::SSP_VARIANT_PASSKEY_NOTIFICATION>
|
||||
{ };
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::dom::bluetooth::BluetoothStatus>
|
||||
: public ContiguousEnumSerializer<
|
||||
|
|
|
@ -212,6 +212,10 @@ BluetoothParent::RecvPBluetoothRequestConstructor(
|
|||
return actor->DoRequest(aRequest.get_ConnectedDevicePropertiesRequest());
|
||||
case Request::TFetchUuidsRequest:
|
||||
return actor->DoRequest(aRequest.get_FetchUuidsRequest());
|
||||
case Request::TPinReplyRequest:
|
||||
return actor->DoRequest(aRequest.get_PinReplyRequest());
|
||||
case Request::TSspReplyRequest:
|
||||
return actor->DoRequest(aRequest.get_SspReplyRequest());
|
||||
case Request::TSetPinCodeRequest:
|
||||
return actor->DoRequest(aRequest.get_SetPinCodeRequest());
|
||||
case Request::TSetPasskeyRequest:
|
||||
|
@ -256,6 +260,12 @@ BluetoothParent::RecvPBluetoothRequestConstructor(
|
|||
return actor->DoRequest(aRequest.get_DisconnectGattClientRequest());
|
||||
case Request::TDiscoverGattServicesRequest:
|
||||
return actor->DoRequest(aRequest.get_DiscoverGattServicesRequest());
|
||||
case Request::TGattClientStartNotificationsRequest:
|
||||
return actor->DoRequest(
|
||||
aRequest.get_GattClientStartNotificationsRequest());
|
||||
case Request::TGattClientStopNotificationsRequest:
|
||||
return actor->DoRequest(
|
||||
aRequest.get_GattClientStopNotificationsRequest());
|
||||
case Request::TUnregisterGattClientRequest:
|
||||
return actor->DoRequest(aRequest.get_UnregisterGattClientRequest());
|
||||
case Request::TGattClientReadRemoteRssiRequest:
|
||||
|
@ -470,6 +480,34 @@ BluetoothRequestParent::DoRequest(const FetchUuidsRequest& aRequest)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothRequestParent::DoRequest(const PinReplyRequest& aRequest)
|
||||
{
|
||||
MOZ_ASSERT(mService);
|
||||
MOZ_ASSERT(mRequestType == Request::TPinReplyRequest);
|
||||
|
||||
mService->PinReplyInternal(aRequest.address(),
|
||||
aRequest.accept(),
|
||||
aRequest.pinCode(),
|
||||
mReplyRunnable.get());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothRequestParent::DoRequest(const SspReplyRequest& aRequest)
|
||||
{
|
||||
MOZ_ASSERT(mService);
|
||||
MOZ_ASSERT(mRequestType == Request::TSspReplyRequest);
|
||||
|
||||
mService->SspReplyInternal(aRequest.address(),
|
||||
aRequest.variant(),
|
||||
aRequest.accept(),
|
||||
mReplyRunnable.get());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothRequestParent::DoRequest(const SetPinCodeRequest& aRequest)
|
||||
{
|
||||
|
@ -733,6 +771,36 @@ BluetoothRequestParent::DoRequest(const DiscoverGattServicesRequest& aRequest)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothRequestParent::DoRequest(
|
||||
const GattClientStartNotificationsRequest& aRequest)
|
||||
{
|
||||
MOZ_ASSERT(mService);
|
||||
MOZ_ASSERT(mRequestType == Request::TGattClientStartNotificationsRequest);
|
||||
|
||||
mService->GattClientStartNotificationsInternal(aRequest.appUuid(),
|
||||
aRequest.servId(),
|
||||
aRequest.charId(),
|
||||
mReplyRunnable.get());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothRequestParent::DoRequest(
|
||||
const GattClientStopNotificationsRequest& aRequest)
|
||||
{
|
||||
MOZ_ASSERT(mService);
|
||||
MOZ_ASSERT(mRequestType == Request::TGattClientStopNotificationsRequest);
|
||||
|
||||
mService->GattClientStopNotificationsInternal(aRequest.appUuid(),
|
||||
aRequest.servId(),
|
||||
aRequest.charId(),
|
||||
mReplyRunnable.get());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothRequestParent::DoRequest(const UnregisterGattClientRequest& aRequest)
|
||||
{
|
||||
|
|
|
@ -173,6 +173,12 @@ protected:
|
|||
bool
|
||||
DoRequest(const DenyPairingConfirmationRequest& aRequest);
|
||||
|
||||
bool
|
||||
DoRequest(const PinReplyRequest& aRequest);
|
||||
|
||||
bool
|
||||
DoRequest(const SspReplyRequest& aRequest);
|
||||
|
||||
bool
|
||||
DoRequest(const ConnectRequest& aRequest);
|
||||
|
||||
|
@ -226,6 +232,12 @@ protected:
|
|||
bool
|
||||
DoRequest(const DiscoverGattServicesRequest& aRequest);
|
||||
|
||||
bool
|
||||
DoRequest(const GattClientStartNotificationsRequest& aRequest);
|
||||
|
||||
bool
|
||||
DoRequest(const GattClientStopNotificationsRequest& aRequest);
|
||||
|
||||
bool
|
||||
DoRequest(const UnregisterGattClientRequest& aRequest);
|
||||
|
||||
|
|
|
@ -208,6 +208,28 @@ BluetoothServiceChildProcess::UpdateSdpRecords(const nsAString& aDeviceAddress,
|
|||
MOZ_CRASH("This should never be called!");
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothServiceChildProcess::PinReplyInternal(
|
||||
const nsAString& aDeviceAddress, bool aAccept,
|
||||
const nsAString& aPinCode, BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
SendRequest(aRunnable,
|
||||
PinReplyRequest(nsString(aDeviceAddress),
|
||||
aAccept,
|
||||
nsString(aPinCode)));
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothServiceChildProcess::SspReplyInternal(
|
||||
const nsAString& aDeviceAddress, BluetoothSspVariant aVariant,
|
||||
bool aAccept, BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
SendRequest(aRunnable,
|
||||
SspReplyRequest(nsString(aDeviceAddress),
|
||||
aVariant,
|
||||
aAccept));
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothServiceChildProcess::SetPinCodeInternal(
|
||||
const nsAString& aDeviceAddress,
|
||||
|
@ -405,6 +427,24 @@ BluetoothServiceChildProcess::DiscoverGattServicesInternal(
|
|||
DiscoverGattServicesRequest(nsString(aAppUuid)));
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothServiceChildProcess::GattClientStartNotificationsInternal(
|
||||
const nsAString& aAppUuid, const BluetoothGattServiceId& aServId,
|
||||
const BluetoothGattId& aCharId, BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
SendRequest(aRunnable,
|
||||
GattClientStartNotificationsRequest(nsString(aAppUuid), aServId, aCharId));
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothServiceChildProcess::GattClientStopNotificationsInternal(
|
||||
const nsAString& aAppUuid, const BluetoothGattServiceId& aServId,
|
||||
const BluetoothGattId& aCharId, BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
SendRequest(aRunnable,
|
||||
GattClientStopNotificationsRequest(nsString(aAppUuid), aServId, aCharId));
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothServiceChildProcess::UnregisterGattClientInternal(
|
||||
int aClientIf, BluetoothReplyRunnable* aRunnable)
|
||||
|
|
|
@ -110,6 +110,18 @@ public:
|
|||
BluetoothReplyRunnable* aRunnable)
|
||||
override;
|
||||
|
||||
virtual void
|
||||
PinReplyInternal(const nsAString& aDeviceAddress,
|
||||
bool aAccept,
|
||||
const nsAString& aPinCode,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
||||
virtual void
|
||||
SspReplyInternal(const nsAString& aDeviceAddress,
|
||||
BluetoothSspVariant aVariant,
|
||||
bool aAccept,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
||||
virtual void
|
||||
Connect(const nsAString& aDeviceAddress,
|
||||
uint32_t aCod,
|
||||
|
@ -206,6 +218,20 @@ public:
|
|||
DiscoverGattServicesInternal(const nsAString& aAppUuid,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
||||
virtual void
|
||||
GattClientStartNotificationsInternal(
|
||||
const nsAString& aAppUuid,
|
||||
const BluetoothGattServiceId& aServId,
|
||||
const BluetoothGattId& aCharId,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
||||
virtual void
|
||||
GattClientStopNotificationsInternal(
|
||||
const nsAString& aAppUuid,
|
||||
const BluetoothGattServiceId& aServId,
|
||||
const BluetoothGattId& aCharId,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
||||
virtual void
|
||||
UnregisterGattClientInternal(int aClientIf,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
|
|
@ -8,6 +8,8 @@ using mozilla::dom::bluetooth::BluetoothGattId
|
|||
from "mozilla/dom/bluetooth/BluetoothCommon.h";
|
||||
using mozilla::dom::bluetooth::BluetoothGattServiceId
|
||||
from "mozilla/dom/bluetooth/BluetoothCommon.h";
|
||||
using mozilla::dom::bluetooth::BluetoothSspVariant
|
||||
from "mozilla/dom/bluetooth/BluetoothCommon.h";
|
||||
using mozilla::dom::bluetooth::BluetoothStatus
|
||||
from "mozilla/dom/bluetooth/BluetoothCommon.h";
|
||||
|
||||
|
@ -28,7 +30,9 @@ union BluetoothValue
|
|||
nsString[];
|
||||
uint8_t[];
|
||||
BluetoothNamedValue[];
|
||||
BluetoothGattId;
|
||||
BluetoothGattId[];
|
||||
BluetoothGattServiceId;
|
||||
BluetoothGattServiceId[];
|
||||
};
|
||||
|
||||
|
|
|
@ -64,6 +64,20 @@ struct UnpairRequest
|
|||
nsString address;
|
||||
};
|
||||
|
||||
struct PinReplyRequest
|
||||
{
|
||||
nsString address;
|
||||
bool accept;
|
||||
nsString pinCode;
|
||||
};
|
||||
|
||||
struct SspReplyRequest
|
||||
{
|
||||
nsString address;
|
||||
BluetoothSspVariant variant;
|
||||
bool accept;
|
||||
};
|
||||
|
||||
struct SetPinCodeRequest
|
||||
{
|
||||
nsString path;
|
||||
|
@ -193,6 +207,20 @@ struct DiscoverGattServicesRequest
|
|||
nsString appUuid;
|
||||
};
|
||||
|
||||
struct GattClientStartNotificationsRequest
|
||||
{
|
||||
nsString appUuid;
|
||||
BluetoothGattServiceId servId;
|
||||
BluetoothGattId charId;
|
||||
};
|
||||
|
||||
struct GattClientStopNotificationsRequest
|
||||
{
|
||||
nsString appUuid;
|
||||
BluetoothGattServiceId servId;
|
||||
BluetoothGattId charId;
|
||||
};
|
||||
|
||||
struct UnregisterGattClientRequest
|
||||
{
|
||||
int clientIf;
|
||||
|
@ -215,6 +243,8 @@ union Request
|
|||
StopDiscoveryRequest;
|
||||
PairRequest;
|
||||
UnpairRequest;
|
||||
PinReplyRequest;
|
||||
SspReplyRequest;
|
||||
SetPinCodeRequest;
|
||||
SetPasskeyRequest;
|
||||
ConfirmPairingConfirmationRequest;
|
||||
|
@ -239,6 +269,8 @@ union Request
|
|||
ConnectGattClientRequest;
|
||||
DisconnectGattClientRequest;
|
||||
DiscoverGattServicesRequest;
|
||||
GattClientStartNotificationsRequest;
|
||||
GattClientStopNotificationsRequest;
|
||||
UnregisterGattClientRequest;
|
||||
GattClientReadRemoteRssiRequest;
|
||||
};
|
||||
|
|
|
@ -753,15 +753,13 @@ function addEventHandlerForPairingRequest(aAdapter, aSpecifiedBdAddress) {
|
|||
|
||||
let device = evt.device;
|
||||
if (!aSpecifiedBdAddress || device.address == aSpecifiedBdAddress) {
|
||||
let confirm = true;
|
||||
|
||||
evt.handle.setPairingConfirmation(confirm).then(
|
||||
evt.handle.accept().then(
|
||||
function onResolve() {
|
||||
log(" - 'setPairingConfirmation' resolve.");
|
||||
log(" - 'accept' resolve.");
|
||||
cleanupPairingListener(aAdapter.pairingReqs);
|
||||
},
|
||||
function onReject() {
|
||||
log(" - 'setPairingConfirmation' reject.");
|
||||
log(" - 'accept' reject.");
|
||||
cleanupPairingListener(aAdapter.pairingReqs);
|
||||
});
|
||||
}
|
||||
|
@ -772,7 +770,15 @@ function addEventHandlerForPairingRequest(aAdapter, aSpecifiedBdAddress) {
|
|||
|
||||
let device = evt.device;
|
||||
if (!aSpecifiedBdAddress || device.address == aSpecifiedBdAddress) {
|
||||
cleanupPairingListener(aAdapter.pairingReqs);
|
||||
evt.handle.accept().then(
|
||||
function onResolve() {
|
||||
log(" - 'accept' resolve.");
|
||||
cleanupPairingListener(aAdapter.pairingReqs);
|
||||
},
|
||||
function onReject() {
|
||||
log(" - 'accept' reject.");
|
||||
cleanupPairingListener(aAdapter.pairingReqs);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
// - BluetoothPairingEvent.handle
|
||||
//
|
||||
// - BluetoothPairingHandle.setPinCode()
|
||||
// - BluetoothPairingHandle.setPairingConfirmation()
|
||||
// - BluetoothPairingHandle.accept()
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
|
@ -1425,6 +1425,8 @@ protected:
|
|||
nsTArray<WebGLRefPtr<WebGLTexture> > mBoundCubeMapTextures;
|
||||
nsTArray<WebGLRefPtr<WebGLTexture> > mBound3DTextures;
|
||||
|
||||
void ResolveTexturesForDraw() const;
|
||||
|
||||
WebGLRefPtr<WebGLProgram> mCurrentProgram;
|
||||
RefPtr<const webgl::LinkedProgramInfo> mActiveProgramLinkInfo;
|
||||
|
||||
|
|
|
@ -48,7 +48,9 @@ WebGLContext::DrawInstanced_check(const char* info)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool WebGLContext::DrawArrays_check(GLint first, GLsizei count, GLsizei primcount, const char* info)
|
||||
bool
|
||||
WebGLContext::DrawArrays_check(GLint first, GLsizei count, GLsizei primcount,
|
||||
const char* info)
|
||||
{
|
||||
if (first < 0 || count < 0) {
|
||||
ErrorInvalidValue("%s: negative first or count", info);
|
||||
|
|
|
@ -240,6 +240,7 @@ WebGLContext::BindTexture(GLenum rawTarget, WebGLTexture* newTex)
|
|||
default:
|
||||
return ErrorInvalidEnumInfo("bindTexture: target", rawTarget);
|
||||
}
|
||||
const TexTarget target(rawTarget);
|
||||
|
||||
if (newTex) {
|
||||
// silently ignore a deleted texture
|
||||
|
@ -250,29 +251,16 @@ WebGLContext::BindTexture(GLenum rawTarget, WebGLTexture* newTex)
|
|||
return ErrorInvalidOperation("bindTexture: this texture has already been bound to a different target");
|
||||
}
|
||||
|
||||
const TexTarget target(rawTarget);
|
||||
|
||||
WebGLTextureFakeBlackStatus currentTexFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded;
|
||||
if (*currentTexPtr) {
|
||||
currentTexFakeBlackStatus = (*currentTexPtr)->ResolvedFakeBlackStatus();
|
||||
}
|
||||
WebGLTextureFakeBlackStatus newTexFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded;
|
||||
if (newTex) {
|
||||
newTexFakeBlackStatus = newTex->ResolvedFakeBlackStatus();
|
||||
}
|
||||
|
||||
*currentTexPtr = newTex;
|
||||
|
||||
if (currentTexFakeBlackStatus != newTexFakeBlackStatus) {
|
||||
SetFakeBlackStatus(WebGLContextFakeBlackStatus::Unknown);
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
if (newTex)
|
||||
if (newTex) {
|
||||
SetFakeBlackStatus(WebGLContextFakeBlackStatus::Unknown);
|
||||
newTex->Bind(target);
|
||||
else
|
||||
gl->fBindTexture(target.get(), 0 /* == texturename */);
|
||||
} else {
|
||||
gl->fBindTexture(target.get(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void WebGLContext::BlendEquation(GLenum mode)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "angle/ShaderLang.h"
|
||||
#include "GLContext.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "MurmurHash3.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsTArray.h"
|
||||
|
@ -42,6 +43,18 @@ ChooseValidatorCompileOptions(const ShBuiltInResources& resources,
|
|||
options |= SH_LIMIT_EXPRESSION_COMPLEXITY;
|
||||
}
|
||||
|
||||
if (Preferences::GetBool("webgl.all-angle-options", false)) {
|
||||
return options |
|
||||
SH_VALIDATE_LOOP_INDEXING |
|
||||
SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX |
|
||||
SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX |
|
||||
SH_EMULATE_BUILT_IN_FUNCTIONS |
|
||||
SH_CLAMP_INDIRECT_ARRAY_BOUNDS |
|
||||
SH_UNFOLD_SHORT_CIRCUIT |
|
||||
SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS |
|
||||
SH_REGENERATE_STRUCT_NAMES;
|
||||
}
|
||||
|
||||
#ifndef XP_MACOSX
|
||||
// We want to do this everywhere, but to do this on Mac, we need
|
||||
// to do it only on Mac OSX > 10.6 as this causes the shader
|
||||
|
|
|
@ -146,6 +146,8 @@ GetEventMessageName(uint32_t aMessage)
|
|||
return "NS_COMPOSITION_CHANGE";
|
||||
case NS_COMPOSITION_COMMIT_AS_IS:
|
||||
return "NS_COMPOSITION_COMMIT_AS_IS";
|
||||
case NS_COMPOSITION_COMMIT:
|
||||
return "NS_COMPOSITION_COMMIT";
|
||||
default:
|
||||
return "unacceptable event message";
|
||||
}
|
||||
|
|
|
@ -30,14 +30,20 @@ helper.addMessageListener("fail", function onFail(message) {
|
|||
helper.addMessageListener("file.opened", onFileOpened);
|
||||
helper.sendAsyncMessage("file.open", "test_bug1146116.txt");
|
||||
|
||||
function getGlobal(thing) {
|
||||
return SpecialPowers.unwrap(SpecialPowers.Cu.getGlobalForObject(thing));
|
||||
}
|
||||
|
||||
function onFileOpened(message) {
|
||||
const file = message.domFile;
|
||||
const elem = document.getElementById("file");
|
||||
isnot(SpecialPowers.Cu.getGlobalForObject(elem), window,
|
||||
is(getGlobal(elem), window,
|
||||
"getGlobal() works as expected");
|
||||
isnot(getGlobal(file), window,
|
||||
"File from MessageManager is wrapped");
|
||||
SpecialPowers.wrap(elem).mozSetFileArray([file]);
|
||||
is(SpecialPowers.unwrap(SpecialPowers.Cu.getGlobalForObject(elem.files[0])),
|
||||
window, "File read back from input element is not wrapped");
|
||||
is(getGlobal(elem.files[0]), window,
|
||||
"File read back from input element is not wrapped");
|
||||
helper.addMessageListener("file.removed", onFileRemoved);
|
||||
helper.sendAsyncMessage("file.remove", null);
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "mozilla/layers/PCompositorChild.h"
|
||||
#include "mozilla/layers/SharedBufferManagerChild.h"
|
||||
#include "mozilla/net/NeckoChild.h"
|
||||
#include "mozilla/plugins/PluginInstanceParent.h"
|
||||
#include "mozilla/plugins/PluginModuleParent.h"
|
||||
|
||||
#if defined(MOZ_CONTENT_SANDBOX)
|
||||
|
@ -2672,6 +2673,26 @@ ContentChild::GetBrowserOrId(TabChild* aTabChild)
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvUpdateWindow(const uintptr_t& aChildId)
|
||||
{
|
||||
#if defined(XP_WIN)
|
||||
NS_ASSERTION(aChildId, "Expected child hwnd value for remote plugin instance.");
|
||||
mozilla::plugins::PluginInstanceParent* parentInstance =
|
||||
mozilla::plugins::PluginInstanceParent::LookupPluginInstanceByID(aChildId);
|
||||
NS_ASSERTION(parentInstance, "Expected matching plugin instance");
|
||||
if (parentInstance) {
|
||||
// sync! update call to the plugin instance that forces the
|
||||
// plugin to paint its child window.
|
||||
parentInstance->CallUpdateWindow();
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
NS_NOTREACHED("ContentChild::RecvUpdateWindow calls unexpected on this platform.");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// This code goes here rather than nsGlobalWindow.cpp because nsGlobalWindow.cpp
|
||||
// can't include ContentChild.h since it includes windows.h.
|
||||
|
||||
|
|
|
@ -384,6 +384,7 @@ public:
|
|||
const base::ProcessId& aProcessId) override;
|
||||
virtual bool RecvLoadPluginResult(const uint32_t& aPluginId,
|
||||
const bool& aResult) override;
|
||||
virtual bool RecvUpdateWindow(const uintptr_t& aChildId) override;
|
||||
|
||||
virtual bool RecvStartProfiler(const uint32_t& aEntries,
|
||||
const double& aInterval,
|
||||
|
|
|
@ -874,6 +874,27 @@ ContentParent::GetInitialProcessPriority(Element* aFrameElement)
|
|||
PROCESS_PRIORITY_FOREGROUND;
|
||||
}
|
||||
|
||||
#if defined(XP_WIN)
|
||||
extern const wchar_t* kPluginWidgetContentParentProperty;
|
||||
|
||||
/*static*/ void
|
||||
ContentParent::SendAsyncUpdate(nsIWidget* aWidget)
|
||||
{
|
||||
if (!aWidget || aWidget->Destroyed()) {
|
||||
return;
|
||||
}
|
||||
printf_stderr("TabParent::SendAsyncUpdate()\n");
|
||||
// Fire off an async request to the plugin to paint its window
|
||||
HWND hwnd = (HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW);
|
||||
NS_ASSERTION(hwnd, "Expected valid hwnd value.");
|
||||
ContentParent* cp = reinterpret_cast<ContentParent*>(
|
||||
::GetPropW(hwnd, kPluginWidgetContentParentProperty));
|
||||
if (cp && !cp->IsDestroyed()) {
|
||||
cp->SendUpdateWindow((uintptr_t)hwnd);
|
||||
}
|
||||
}
|
||||
#endif // defined(XP_WIN)
|
||||
|
||||
bool
|
||||
ContentParent::PreallocatedProcessReady()
|
||||
{
|
||||
|
|
|
@ -35,6 +35,7 @@ class nsIDumpGCAndCCLogsCallback;
|
|||
class nsIMemoryReporter;
|
||||
class nsITimer;
|
||||
class ParentIdleListener;
|
||||
class nsIWidget;
|
||||
|
||||
namespace mozilla {
|
||||
class PRemoteSpellcheckEngineParent;
|
||||
|
@ -144,6 +145,20 @@ public:
|
|||
|
||||
static void NotifyUpdatedDictionaries();
|
||||
|
||||
#if defined(XP_WIN)
|
||||
/**
|
||||
* Windows helper for firing off an update window request to a plugin
|
||||
* instance.
|
||||
*
|
||||
* aWidget - the eWindowType_plugin_ipc_chrome widget associated with
|
||||
* this plugin window.
|
||||
*/
|
||||
static void SendAsyncUpdate(nsIWidget* aWidget);
|
||||
#endif
|
||||
|
||||
// Let managees query if it is safe to send messages.
|
||||
bool IsDestroyed() { return !mIPCOpen; }
|
||||
|
||||
virtual bool RecvCreateChildProcess(const IPCTabContext& aContext,
|
||||
const hal::ProcessPriority& aPriority,
|
||||
const TabId& aOpenerTabId,
|
||||
|
|
|
@ -27,6 +27,7 @@ using class mozilla::gfx::Matrix from "mozilla/gfx/Matrix.h";
|
|||
using struct gfxSize from "gfxPoint.h";
|
||||
using CSSRect from "Units.h";
|
||||
using LayoutDeviceIntRect from "Units.h";
|
||||
using mozilla::LayoutDeviceIntPoint from "Units.h";
|
||||
using ScreenIntSize from "Units.h";
|
||||
using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
|
||||
using struct mozilla::layers::ScrollableLayerGuid from "FrameMetrics.h";
|
||||
|
@ -332,6 +333,14 @@ parent:
|
|||
|
||||
sync IsParentWindowMainWidgetVisible() returns (bool visible);
|
||||
|
||||
/**
|
||||
* Content process forward from PuppetWidget for synth mouse move
|
||||
* events.
|
||||
*
|
||||
* aPoint a synth point relative to the window
|
||||
*/
|
||||
sync SynthesizeNativeMouseMove(LayoutDeviceIntPoint aPoint);
|
||||
|
||||
/**
|
||||
* Gets the DPI of the screen corresponding to this browser.
|
||||
*/
|
||||
|
|
|
@ -582,6 +582,12 @@ child:
|
|||
|
||||
async LoadProcessScript(nsString url);
|
||||
|
||||
/**
|
||||
* Requests a full native update of a native plugin child window. This is
|
||||
* a Windows specific call.
|
||||
*/
|
||||
async UpdateWindow(uintptr_t aChildId);
|
||||
|
||||
parent:
|
||||
/**
|
||||
* Tell the parent process a new accessible document has been created.
|
||||
|
|
|
@ -31,11 +31,7 @@ sync protocol PPluginWidget {
|
|||
|
||||
parent:
|
||||
async __delete__();
|
||||
|
||||
parent:
|
||||
sync Create() returns (nsresult aResult);
|
||||
|
||||
async Destroy();
|
||||
async SetFocus(bool aRaise);
|
||||
|
||||
/**
|
||||
|
@ -45,18 +41,6 @@ parent:
|
|||
* native HWND of the plugin widget.
|
||||
*/
|
||||
sync GetNativePluginPort() returns (uintptr_t value);
|
||||
|
||||
child:
|
||||
/**
|
||||
* Event indicating the parent is shutting down.
|
||||
* aWhichSide - indicates which side intititated the shutdown.
|
||||
*/
|
||||
async ParentShutdown(uint16_t aWhichSide);
|
||||
|
||||
/**
|
||||
* Requests a full update of the plugin window.
|
||||
*/
|
||||
async UpdateWindow(uintptr_t aChildId);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -267,7 +267,8 @@ public:
|
|||
Create(nsIContentChild* aManager, const TabId& aTabId, const TabContext& aContext, uint32_t aChromeFlags);
|
||||
|
||||
bool IsRootContentDocument();
|
||||
|
||||
// Let managees query if it is safe to send messages.
|
||||
bool IsDestroyed() { return mDestroyed; }
|
||||
const TabId GetTabId() const {
|
||||
MOZ_ASSERT(mUniqueId != 0);
|
||||
return mUniqueId;
|
||||
|
|
|
@ -2233,6 +2233,17 @@ TabParent::RecvIsParentWindowMainWidgetVisible(bool* aIsVisible)
|
|||
return NS_SUCCEEDED(rv);
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvSynthesizeNativeMouseMove(const mozilla::LayoutDeviceIntPoint& aPoint)
|
||||
{
|
||||
// The widget associated with the browser window
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (widget) {
|
||||
widget->SynthesizeNativeMouseMove(aPoint);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvGetDPI(float* aValue)
|
||||
{
|
||||
|
|
|
@ -198,6 +198,7 @@ public:
|
|||
virtual bool RecvSetBackgroundColor(const nscolor& aValue) override;
|
||||
virtual bool RecvSetStatus(const uint32_t& aType, const nsString& aStatus) override;
|
||||
virtual bool RecvIsParentWindowMainWidgetVisible(bool* aIsVisible) override;
|
||||
virtual bool RecvSynthesizeNativeMouseMove(const mozilla::LayoutDeviceIntPoint& aPoint) override;
|
||||
virtual bool RecvShowTooltip(const uint32_t& aX, const uint32_t& aY, const nsString& aTooltip) override;
|
||||
virtual bool RecvHideTooltip() override;
|
||||
virtual bool RecvGetDPI(float* aValue) override;
|
||||
|
|
|
@ -29,6 +29,13 @@ couldNotProcessUnknownDirective = Couldn't process unknown directive '%1$S'
|
|||
# LOCALIZATION NOTE (ignoringUnknownOption):
|
||||
# %1$S is the option that could not be understood
|
||||
ignoringUnknownOption = Ignoring unknown option %1$S
|
||||
# LOCALIZATION NOTE (ignoringDuplicateSrc):
|
||||
# %1$S defines the duplicate src
|
||||
ignoringDuplicateSrc = Ignoring duplicate source %1$S
|
||||
# LOCALIZATION NOTE (ignoringSrcWithinScriptSrc):
|
||||
# %1$S is the ignored src
|
||||
# script-src is a directive name and should not be localized
|
||||
ignoringSrcWithinScriptSrc = Ignoring "%1$S" within script-src: nonce-source or hash-source specified
|
||||
# LOCALIZATION NOTE (reportURInotHttpsOrHttp2):
|
||||
# %1$S is the ETLD of the report URI that is not HTTP or HTTPS
|
||||
reportURInotHttpsOrHttp2 = The report URI (%1$S) should be an HTTP or HTTPS URI.
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
/*
|
||||
* ManifestProcessor
|
||||
* Implementation of processing algorithms from:
|
||||
* http://www.w3.org/2008/webapps/manifest/
|
||||
|
@ -11,347 +10,359 @@
|
|||
* or individual parts of a manifest object. A manifest is just a
|
||||
* standard JS object that has been cleaned up.
|
||||
*
|
||||
* .process(jsonText, manifestURL, docURL);
|
||||
* .process({jsonText,manifestURL,docURL});
|
||||
*
|
||||
* TODO: The constructor should accept the UA's supported orientations.
|
||||
* TODO: The constructor should accept the UA's supported display modes.
|
||||
* TODO: hook up developer tools to issueDeveloperWarning (1086997).
|
||||
* TODO: hook up developer tools to console. (1086997).
|
||||
*/
|
||||
/*globals Components*/
|
||||
/*exported EXPORTED_SYMBOLS */
|
||||
/*JSLint options in comment below: */
|
||||
/*globals Components, XPCOMUtils*/
|
||||
'use strict';
|
||||
|
||||
this.EXPORTED_SYMBOLS = ['ManifestProcessor'];
|
||||
const imports = {};
|
||||
const {
|
||||
utils: Cu,
|
||||
classes: Cc,
|
||||
interfaces: Ci
|
||||
} = Components;
|
||||
const imports = {};
|
||||
Cu.import('resource://gre/modules/Services.jsm', imports);
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Cu.importGlobalProperties(['URL']);
|
||||
const securityManager = imports.Services.scriptSecurityManager;
|
||||
const netutil = Cc['@mozilla.org/network/util;1'].getService(Ci.nsINetUtil);
|
||||
const defaultDisplayMode = 'browser';
|
||||
const displayModes = new Set([
|
||||
'fullscreen',
|
||||
'standalone',
|
||||
'minimal-ui',
|
||||
XPCOMUtils.defineLazyModuleGetter(imports, 'Services',
|
||||
'resource://gre/modules/Services.jsm');
|
||||
imports.netutil = Cc['@mozilla.org/network/util;1'].getService(Ci.nsINetUtil);
|
||||
// Helper function extracts values from manifest members
|
||||
// and reports conformance violations.
|
||||
function extractValue({
|
||||
objectName,
|
||||
object,
|
||||
property,
|
||||
expectedType,
|
||||
trim
|
||||
}, console) {
|
||||
const value = object[property];
|
||||
const isArray = Array.isArray(value);
|
||||
// We need to special-case "array", as it's not a JS primitive.
|
||||
const type = (isArray) ? 'array' : typeof value;
|
||||
if (type !== expectedType) {
|
||||
if (type !== 'undefined') {
|
||||
let msg = `Expected the ${objectName}'s ${property} `;
|
||||
msg += `member to a be a ${expectedType}.`;
|
||||
console.log(msg);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
// Trim string and returned undefined if the empty string.
|
||||
const shouldTrim = expectedType === 'string' && value && trim;
|
||||
if (shouldTrim) {
|
||||
return value.trim() || undefined;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
const displayModes = new Set(['fullscreen', 'standalone', 'minimal-ui',
|
||||
'browser'
|
||||
]);
|
||||
const orientationTypes = new Set([
|
||||
'any',
|
||||
'natural',
|
||||
'landscape',
|
||||
'portrait',
|
||||
'portrait-primary',
|
||||
'portrait-secondary',
|
||||
'landscape-primary',
|
||||
const orientationTypes = new Set(['any', 'natural', 'landscape', 'portrait',
|
||||
'portrait-primary', 'portrait-secondary', 'landscape-primary',
|
||||
'landscape-secondary'
|
||||
]);
|
||||
const {
|
||||
ConsoleAPI
|
||||
} = Cu.import('resource://gre/modules/devtools/Console.jsm');
|
||||
|
||||
this.ManifestProcessor = function ManifestProcessor() {};
|
||||
/**
|
||||
* process method: processes json text into a clean manifest
|
||||
* that conforms with the W3C specification.
|
||||
* @param jsonText - the JSON string to be processd.
|
||||
* @param manifestURL - the URL of the manifest, to resolve URLs.
|
||||
* @param docURL - the URL of the owner doc, for security checks
|
||||
*/
|
||||
this.ManifestProcessor.prototype.process = function({
|
||||
jsonText: jsonText,
|
||||
manifestURL: manifestURL,
|
||||
docLocation: docURL
|
||||
}) {
|
||||
/*
|
||||
* This helper function is used to extract values from manifest members.
|
||||
* It also reports conformance violations.
|
||||
*/
|
||||
function extractValue(obj) {
|
||||
let value = obj.object[obj.property];
|
||||
//we need to special-case "array", as it's not a JS primitive
|
||||
const type = (Array.isArray(value)) ? 'array' : typeof value;
|
||||
function ManifestProcessor() {}
|
||||
|
||||
if (type !== obj.expectedType) {
|
||||
if (type !== 'undefined') {
|
||||
let msg = `Expected the ${obj.objectName}'s ${obj.property}`;
|
||||
msg += `member to a be a ${obj.expectedType}.`;
|
||||
issueDeveloperWarning(msg);
|
||||
}
|
||||
value = undefined;
|
||||
// Static getters
|
||||
Object.defineProperties(ManifestProcessor, {
|
||||
'defaultDisplayMode': {
|
||||
get: function() {
|
||||
return 'browser';
|
||||
}
|
||||
},
|
||||
'displayModes': {
|
||||
get: function() {
|
||||
return displayModes;
|
||||
}
|
||||
},
|
||||
'orientationTypes': {
|
||||
get: function() {
|
||||
return orientationTypes;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
});
|
||||
|
||||
function issueDeveloperWarning(msg) {
|
||||
//https://bugzilla.mozilla.org/show_bug.cgi?id=1086997
|
||||
}
|
||||
ManifestProcessor.prototype = {
|
||||
|
||||
function processNameMember(manifest) {
|
||||
const obj = {
|
||||
objectName: 'manifest',
|
||||
object: manifest,
|
||||
property: 'name',
|
||||
expectedType: 'string'
|
||||
// process method: processes json text into a clean manifest
|
||||
// that conforms with the W3C specification. Takes an object
|
||||
// expecting the following dictionary items:
|
||||
// * jsonText: the JSON string to be processd.
|
||||
// * manifestURL: the URL of the manifest, to resolve URLs.
|
||||
// * docURL: the URL of the owner doc, for security checks.
|
||||
process({
|
||||
jsonText, manifestURL, docURL
|
||||
}) {
|
||||
const console = new ConsoleAPI({
|
||||
prefix: 'Web Manifest: '
|
||||
});
|
||||
let rawManifest = {};
|
||||
try {
|
||||
rawManifest = JSON.parse(jsonText);
|
||||
} catch (e) {}
|
||||
if (typeof rawManifest !== 'object' || rawManifest === null) {
|
||||
let msg = 'Manifest needs to be an object.';
|
||||
console.warn(msg);
|
||||
rawManifest = {};
|
||||
}
|
||||
const processedManifest = {
|
||||
start_url: processStartURLMember(rawManifest, manifestURL, docURL),
|
||||
display: processDisplayMember(rawManifest),
|
||||
orientation: processOrientationMember(rawManifest),
|
||||
name: processNameMember(rawManifest),
|
||||
icons: IconsProcessor.process(rawManifest, manifestURL, console),
|
||||
short_name: processShortNameMember(rawManifest),
|
||||
};
|
||||
let value = extractValue(obj);
|
||||
return (value) ? value.trim() : value;
|
||||
}
|
||||
processedManifest.scope = processScopeMember(rawManifest, manifestURL,
|
||||
docURL, processedManifest.start_url);
|
||||
return processedManifest;
|
||||
|
||||
function processShortNameMember(manifest) {
|
||||
const obj = {
|
||||
objectName: 'manifest',
|
||||
object: manifest,
|
||||
property: 'short_name',
|
||||
expectedType: 'string'
|
||||
};
|
||||
let value = extractValue(obj);
|
||||
return (value) ? value.trim() : value;
|
||||
}
|
||||
|
||||
function processOrientationMember(manifest) {
|
||||
const obj = {
|
||||
objectName: 'manifest',
|
||||
object: manifest,
|
||||
property: 'orientation',
|
||||
expectedType: 'string'
|
||||
};
|
||||
let value = extractValue(obj);
|
||||
value = (value) ? value.trim() : undefined;
|
||||
//The spec special-cases orientation to return the empty string
|
||||
return (orientationTypes.has(value)) ? value : '';
|
||||
}
|
||||
|
||||
function processDisplayMember(manifest) {
|
||||
const obj = {
|
||||
objectName: 'manifest',
|
||||
object: manifest,
|
||||
property: 'display',
|
||||
expectedType: 'string'
|
||||
};
|
||||
|
||||
let value = extractValue(obj);
|
||||
value = (value) ? value.trim() : value;
|
||||
return (displayModes.has(value)) ? value : defaultDisplayMode;
|
||||
}
|
||||
|
||||
function processScopeMember(manifest, manifestURL, docURL, startURL) {
|
||||
const spec = {
|
||||
function processNameMember(aManifest) {
|
||||
const spec = {
|
||||
objectName: 'manifest',
|
||||
object: manifest,
|
||||
object: aManifest,
|
||||
property: 'name',
|
||||
expectedType: 'string',
|
||||
trim: true
|
||||
};
|
||||
return extractValue(spec, console);
|
||||
}
|
||||
|
||||
function processShortNameMember(aManifest) {
|
||||
const spec = {
|
||||
objectName: 'manifest',
|
||||
object: aManifest,
|
||||
property: 'short_name',
|
||||
expectedType: 'string',
|
||||
trim: true
|
||||
};
|
||||
return extractValue(spec, console);
|
||||
}
|
||||
|
||||
function processOrientationMember(aManifest) {
|
||||
const spec = {
|
||||
objectName: 'manifest',
|
||||
object: aManifest,
|
||||
property: 'orientation',
|
||||
expectedType: 'string',
|
||||
trim: true
|
||||
};
|
||||
const value = extractValue(spec, console);
|
||||
if (ManifestProcessor.orientationTypes.has(value)) {
|
||||
return value;
|
||||
}
|
||||
// The spec special-cases orientation to return the empty string.
|
||||
return '';
|
||||
}
|
||||
|
||||
function processDisplayMember(aManifest) {
|
||||
const spec = {
|
||||
objectName: 'manifest',
|
||||
object: aManifest,
|
||||
property: 'display',
|
||||
expectedType: 'string',
|
||||
trim: true
|
||||
};
|
||||
const value = extractValue(spec, console);
|
||||
if (ManifestProcessor.displayModes.has(value)) {
|
||||
return value;
|
||||
}
|
||||
return ManifestProcessor.defaultDisplayMode;
|
||||
}
|
||||
|
||||
function processScopeMember(aManifest, aManifestURL, aDocURL, aStartURL) {
|
||||
const spec = {
|
||||
objectName: 'manifest',
|
||||
object: aManifest,
|
||||
property: 'scope',
|
||||
expectedType: 'string',
|
||||
dontTrim: true
|
||||
},
|
||||
value = extractValue(spec);
|
||||
let scopeURL;
|
||||
try {
|
||||
scopeURL = new URL(value, manifestURL);
|
||||
} catch (e) {
|
||||
let msg = 'The URL of scope is invalid.';
|
||||
issueDeveloperWarning(msg);
|
||||
return undefined;
|
||||
trim: false
|
||||
};
|
||||
const value = extractValue(spec, console);
|
||||
let scopeURL;
|
||||
try {
|
||||
scopeURL = new URL(value, aManifestURL);
|
||||
} catch (e) {
|
||||
let msg = 'The URL of scope is invalid.';
|
||||
console.warn(msg);
|
||||
return undefined;
|
||||
}
|
||||
if (scopeURL.origin !== aDocURL.origin) {
|
||||
let msg = 'Scope needs to be same-origin as Document.';
|
||||
console.warn(msg);
|
||||
return undefined;
|
||||
}
|
||||
// If start URL is not within scope of scope URL:
|
||||
let isSameOrigin = aStartURL && aStartURL.origin !== scopeURL.origin;
|
||||
if (isSameOrigin || !aStartURL.pathname.startsWith(scopeURL.pathname)) {
|
||||
let msg =
|
||||
'The start URL is outside the scope, so scope is invalid.';
|
||||
console.warn(msg);
|
||||
return undefined;
|
||||
}
|
||||
return scopeURL;
|
||||
}
|
||||
|
||||
if (scopeURL.origin !== docURL.origin) {
|
||||
let msg = 'Scope needs to be same-origin as Document.';
|
||||
issueDeveloperWarning(msg);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
//If start URL is not within scope of scope URL:
|
||||
if (startURL && startURL.origin !== scopeURL.origin || !startURL.pathname.startsWith(scopeURL.pathname)) {
|
||||
let msg = 'The start URL is outside the scope, so scope is invalid.';
|
||||
issueDeveloperWarning(msg);
|
||||
return undefined;
|
||||
}
|
||||
return scopeURL;
|
||||
}
|
||||
|
||||
function processStartURLMember(manifest, manifestURL, docURL) {
|
||||
const obj = {
|
||||
objectName: 'manifest',
|
||||
object: manifest,
|
||||
property: 'start_url',
|
||||
expectedType: 'string'
|
||||
};
|
||||
|
||||
let value = extractValue(obj),
|
||||
result = new URL(docURL),
|
||||
targetURI = makeURI(result),
|
||||
sameOrigin = false,
|
||||
potentialResult,
|
||||
referrerURI;
|
||||
|
||||
if (value === undefined || value === '') {
|
||||
return result;
|
||||
}
|
||||
|
||||
try {
|
||||
potentialResult = new URL(value, manifestURL);
|
||||
} catch (e) {
|
||||
issueDeveloperWarning('Invalid URL.');
|
||||
return result;
|
||||
}
|
||||
referrerURI = makeURI(potentialResult);
|
||||
try {
|
||||
securityManager.checkSameOriginURI(referrerURI, targetURI, false);
|
||||
sameOrigin = true;
|
||||
} catch (e) {}
|
||||
if (!sameOrigin) {
|
||||
let msg = 'start_url must be same origin as document.';
|
||||
issueDeveloperWarning(msg);
|
||||
} else {
|
||||
result = potentialResult;
|
||||
}
|
||||
return result;
|
||||
|
||||
//Converts a URL to a Gecko URI
|
||||
function makeURI(webURL) {
|
||||
return imports.Services.io.newURI(webURL.toString(), null, null);
|
||||
}
|
||||
}
|
||||
|
||||
//Constants used by IconsProcessor
|
||||
const onlyDecimals = /^\d+$/,
|
||||
anyRegEx = new RegExp('any', 'i');
|
||||
|
||||
function IconsProcessor() {}
|
||||
IconsProcessor.prototype.processIcons = function(manifest, baseURL) {
|
||||
const obj = {
|
||||
function processStartURLMember(aManifest, aManifestURL, aDocURL) {
|
||||
const spec = {
|
||||
objectName: 'manifest',
|
||||
object: manifest,
|
||||
property: 'icons',
|
||||
expectedType: 'array'
|
||||
},
|
||||
icons = [];
|
||||
let value = extractValue(obj);
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
//filter out icons with no "src" or src is empty string
|
||||
let processableIcons = value.filter(
|
||||
icon => icon && Object.prototype.hasOwnProperty.call(icon, 'src') && icon.src !== ''
|
||||
);
|
||||
for (let potentialIcon of processableIcons) {
|
||||
let src = processSrcMember(potentialIcon, baseURL)
|
||||
if(src !== undefined){
|
||||
let icon = {
|
||||
src: src,
|
||||
type: processTypeMember(potentialIcon),
|
||||
sizes: processSizesMember(potentialIcon),
|
||||
density: processDensityMember(potentialIcon)
|
||||
};
|
||||
icons.push(icon);
|
||||
}
|
||||
object: aManifest,
|
||||
property: 'start_url',
|
||||
expectedType: 'string',
|
||||
trim: false
|
||||
};
|
||||
let result = new URL(aDocURL);
|
||||
const value = extractValue(spec, console);
|
||||
if (value === undefined || value === '') {
|
||||
return result;
|
||||
}
|
||||
let potentialResult;
|
||||
try {
|
||||
potentialResult = new URL(value, aManifestURL);
|
||||
} catch (e) {
|
||||
console.warn('Invalid URL.');
|
||||
return result;
|
||||
}
|
||||
if (potentialResult.origin !== aDocURL.origin) {
|
||||
let msg = 'start_url must be same origin as document.';
|
||||
console.warn(msg);
|
||||
} else {
|
||||
result = potentialResult;
|
||||
}
|
||||
}
|
||||
return icons;
|
||||
|
||||
function processTypeMember(icon) {
|
||||
const charset = {},
|
||||
hadCharset = {},
|
||||
obj = {
|
||||
objectName: 'icon',
|
||||
object: icon,
|
||||
property: 'type',
|
||||
expectedType: 'string'
|
||||
};
|
||||
let value = extractValue(obj),
|
||||
isParsable = (typeof value === 'string' && value.length > 0);
|
||||
value = (isParsable) ? netutil.parseContentType(value.trim(), charset, hadCharset) : undefined;
|
||||
return (value === '') ? undefined : value;
|
||||
}
|
||||
|
||||
function processDensityMember(icon) {
|
||||
const hasDensity = Object.prototype.hasOwnProperty.call(icon, 'density'),
|
||||
rawValue = (hasDensity) ? icon.density : undefined,
|
||||
value = parseFloat(rawValue),
|
||||
result = (Number.isNaN(value) || value === +Infinity || value <= 0) ? 1.0 : value;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
};
|
||||
this.ManifestProcessor = ManifestProcessor;
|
||||
|
||||
function processSrcMember(icon, baseURL) {
|
||||
const obj = {
|
||||
objectName: 'icon',
|
||||
object: icon,
|
||||
property: 'src',
|
||||
expectedType: 'string'
|
||||
},
|
||||
value = extractValue(obj);
|
||||
let url;
|
||||
if (typeof value === 'string' && value.trim() !== '') {
|
||||
try {
|
||||
url = new URL(value, baseURL);
|
||||
} catch (e) {}
|
||||
}
|
||||
return url;
|
||||
function IconsProcessor() {}
|
||||
|
||||
// Static getters
|
||||
Object.defineProperties(IconsProcessor,{
|
||||
'onlyDecimals': {
|
||||
get: function() {
|
||||
return /^\d+$/;
|
||||
}
|
||||
|
||||
function processSizesMember(icon) {
|
||||
const sizes = new Set(),
|
||||
obj = {
|
||||
objectName: 'icon',
|
||||
object: icon,
|
||||
property: 'sizes',
|
||||
expectedType: 'string'
|
||||
};
|
||||
let value = extractValue(obj);
|
||||
value = (value) ? value.trim() : value;
|
||||
if (value) {
|
||||
//split on whitespace and filter out invalid values
|
||||
let validSizes = value.split(/\s+/).filter(isValidSizeValue);
|
||||
validSizes.forEach((size) => sizes.add(size));
|
||||
}
|
||||
return sizes;
|
||||
|
||||
/*
|
||||
* Implementation of HTML's link@size attribute checker
|
||||
*/
|
||||
function isValidSizeValue(size) {
|
||||
if (anyRegEx.test(size)) {
|
||||
return true;
|
||||
}
|
||||
size = size.toLowerCase();
|
||||
if (!size.contains('x') || size.indexOf('x') !== size.lastIndexOf('x')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//split left of x for width, after x for height
|
||||
const width = size.substring(0, size.indexOf('x'));
|
||||
const height = size.substring(size.indexOf('x') + 1, size.length);
|
||||
const isValid = !(height.startsWith('0') || width.startsWith('0') || !onlyDecimals.test(width + height));
|
||||
return isValid;
|
||||
}
|
||||
},
|
||||
'anyRegEx': {
|
||||
get: function() {
|
||||
return new RegExp('any', 'i');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
IconsProcessor.process = function(aManifest, aBaseURL, console) {
|
||||
const spec = {
|
||||
objectName: 'manifest',
|
||||
object: aManifest,
|
||||
property: 'icons',
|
||||
expectedType: 'array',
|
||||
trim: false
|
||||
};
|
||||
const icons = [];
|
||||
const value = extractValue(spec, console);
|
||||
if (Array.isArray(value)) {
|
||||
// Filter out icons whose "src" is not useful.
|
||||
value.filter(item => !!processSrcMember(item, aBaseURL))
|
||||
.map(toIconObject)
|
||||
.forEach(icon => icons.push(icon));
|
||||
}
|
||||
return icons;
|
||||
|
||||
function processIconsMember(manifest, manifestURL) {
|
||||
const iconsProcessor = new IconsProcessor();
|
||||
return iconsProcessor.processIcons(manifest, manifestURL);
|
||||
function toIconObject(aIconData) {
|
||||
return {
|
||||
src: processSrcMember(aIconData, aBaseURL),
|
||||
type: processTypeMember(aIconData),
|
||||
sizes: processSizesMember(aIconData),
|
||||
density: processDensityMember(aIconData)
|
||||
};
|
||||
}
|
||||
|
||||
//Processing starts here!
|
||||
let manifest = {};
|
||||
|
||||
try {
|
||||
manifest = JSON.parse(jsonText);
|
||||
if (typeof manifest !== 'object' || manifest === null) {
|
||||
let msg = 'Manifest needs to be an object.';
|
||||
issueDeveloperWarning(msg);
|
||||
manifest = {};
|
||||
function processTypeMember(aIcon) {
|
||||
const charset = {};
|
||||
const hadCharset = {};
|
||||
const spec = {
|
||||
objectName: 'icon',
|
||||
object: aIcon,
|
||||
property: 'type',
|
||||
expectedType: 'string',
|
||||
trim: true
|
||||
};
|
||||
let value = extractValue(spec, console);
|
||||
if (value) {
|
||||
value = imports.netutil.parseContentType(value, charset, hadCharset);
|
||||
}
|
||||
} catch (e) {
|
||||
issueDeveloperWarning(e);
|
||||
return value || undefined;
|
||||
}
|
||||
|
||||
const processedManifest = {
|
||||
start_url: processStartURLMember(manifest, manifestURL, docURL),
|
||||
display: processDisplayMember(manifest),
|
||||
orientation: processOrientationMember(manifest),
|
||||
name: processNameMember(manifest),
|
||||
icons: processIconsMember(manifest, manifestURL),
|
||||
short_name: processShortNameMember(manifest)
|
||||
};
|
||||
processedManifest.scope = processScopeMember(manifest, manifestURL, docURL, processedManifest.start_url);
|
||||
return processedManifest;
|
||||
};
|
||||
function processDensityMember(aIcon) {
|
||||
const value = parseFloat(aIcon.density);
|
||||
const validNum = Number.isNaN(value) || value === +Infinity || value <=
|
||||
0;
|
||||
return (validNum) ? 1.0 : value;
|
||||
}
|
||||
|
||||
function processSrcMember(aIcon, aBaseURL) {
|
||||
const spec = {
|
||||
objectName: 'icon',
|
||||
object: aIcon,
|
||||
property: 'src',
|
||||
expectedType: 'string',
|
||||
trim: false
|
||||
};
|
||||
const value = extractValue(spec, console);
|
||||
let url;
|
||||
if (value && value.length) {
|
||||
try {
|
||||
url = new URL(value, aBaseURL);
|
||||
} catch (e) {}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
function processSizesMember(aIcon) {
|
||||
const sizes = new Set(),
|
||||
spec = {
|
||||
objectName: 'icon',
|
||||
object: aIcon,
|
||||
property: 'sizes',
|
||||
expectedType: 'string',
|
||||
trim: true
|
||||
},
|
||||
value = extractValue(spec, console);
|
||||
if (value) {
|
||||
// Split on whitespace and filter out invalid values.
|
||||
value.split(/\s+/)
|
||||
.filter(isValidSizeValue)
|
||||
.forEach(size => sizes.add(size));
|
||||
}
|
||||
return sizes;
|
||||
// Implementation of HTML's link@size attribute checker.
|
||||
function isValidSizeValue(aSize) {
|
||||
const size = aSize.toLowerCase();
|
||||
if (IconsProcessor.anyRegEx.test(aSize)) {
|
||||
return true;
|
||||
}
|
||||
if (!size.contains('x') || size.indexOf('x') !== size.lastIndexOf('x')) {
|
||||
return false;
|
||||
}
|
||||
// Split left of x for width, after x for height.
|
||||
const widthAndHeight = size.split('x');
|
||||
const w = widthAndHeight.shift();
|
||||
const h = widthAndHeight.join('x');
|
||||
const validStarts = !w.startsWith('0') && !h.startsWith('0');
|
||||
const validDecimals = IconsProcessor.onlyDecimals.test(w + h);
|
||||
return (validStarts && validDecimals);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
const bsp = SpecialPowers.Cu.import('resource://gre/modules/ManifestProcessor.jsm'),
|
||||
processor = new bsp.ManifestProcessor(),
|
||||
manifestURL = new URL(document.location.origin + '/manifest.json'),
|
||||
docLocation = new URL('', document.location.origin),
|
||||
docURL = new URL('', document.location.origin),
|
||||
seperators = '\u2028\u2029\u0020\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000',
|
||||
lineTerminators = '\u000D\u000A\u2028\u2029',
|
||||
whiteSpace = `${seperators}${lineTerminators}`,
|
||||
|
@ -16,5 +16,5 @@ const bsp = SpecialPowers.Cu.import('resource://gre/modules/ManifestProcessor.js
|
|||
data = {
|
||||
jsonText: '{}',
|
||||
manifestURL: manifestURL,
|
||||
docLocation: docLocation
|
||||
docURL: docURL
|
||||
};
|
||||
|
|
|
@ -20,7 +20,7 @@ invalidJson.forEach((testString) => {
|
|||
var expected = `Expect to recover from invalid JSON: ${testString}`;
|
||||
data.jsonText = testString;
|
||||
var result = processor.process(data);
|
||||
SimpleTest.ok(result.start_url.href === docLocation.href, true, expected);
|
||||
SimpleTest.ok(result.start_url.href === docURL.href, true, expected);
|
||||
});
|
||||
|
||||
var validButUnhelpful = ["1", 1, "", "[{}]", "null"];
|
||||
|
@ -28,7 +28,7 @@ validButUnhelpful.forEach((testString) => {
|
|||
var expected = `Expect to recover from invalid JSON: ${testString}`;
|
||||
data.jsonText = testString;
|
||||
var result = processor.process(data);
|
||||
SimpleTest.ok(result.start_url.href === docLocation.href, true, expected);
|
||||
SimpleTest.ok(result.start_url.href === docURL.href, true, expected);
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
|
|
|
@ -21,7 +21,7 @@ typeTests.forEach((type) => {
|
|||
start_url: type
|
||||
});
|
||||
var result = processor.process(data);
|
||||
ise(result.start_url.toString(), docLocation.toString(), expected);
|
||||
ise(result.start_url.toString(), docURL.toString(), expected);
|
||||
});
|
||||
|
||||
//Not same origin
|
||||
|
@ -30,7 +30,7 @@ data.jsonText = JSON.stringify({
|
|||
start_url: 'http://not-same-origin'
|
||||
});
|
||||
var result = processor.process(data);
|
||||
ise(result.start_url.toString(), docLocation.toString(), expected);
|
||||
ise(result.start_url.toString(), docURL.toString(), expected);
|
||||
|
||||
//Empty string test
|
||||
var expected = `Expect empty string for start_url to become document's URL.`;
|
||||
|
@ -38,7 +38,7 @@ data.jsonText = JSON.stringify({
|
|||
start_url: ''
|
||||
});
|
||||
var result = processor.process(data);
|
||||
ise(result.start_url.toString(), docLocation.toString(), expected);
|
||||
ise(result.start_url.toString(), docURL.toString(), expected);
|
||||
|
||||
//Resolve URLs relative to manfiest
|
||||
var URLs = ['path', '/path', '../../path',
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче