merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2015-04-13 12:00:00 +02:00
commit ede9c4f220
290 changed files with 8306 additions and 1587 deletions

View File

@ -1124,8 +1124,23 @@ pref("dom.mozSettings.allowForceReadOnly", false);
// RequestSync API is enabled by default on B2G.
pref("dom.requestSync.enabled", true);
// Use vsync aligned rendering
// Only enable for kit kat and above devices
// kit kat == 19, L = 21, 20 is kit-kat for wearables
// 15 is for the ICS emulators which will fallback to software vsync
#if ANDROID_VERSION == 19 || ANDROID_VERSION == 21 || ANDROID_VERSION == 15
pref("gfx.vsync.hw-vsync.enabled", true);
pref("gfx.vsync.compositor", true);
pref("gfx.touch.resample", true);
#else
pref("gfx.vsync.hw-vsync.enabled", false);
pref("gfx.vsync.compositor", false);
pref("gfx.touch.resample", false);
#endif
// Bug 1147753 - Weird issues with vsync refresh driver on L devices
// so disable them on L, but enable on KK and ICS
#if ANDROID_VERSION == 19 || ANDROID_VERSION == 15
pref("gfx.vsync.refreshdriver", true);
#else
pref("gfx.vsync.refreshdriver", false);
#endif

View File

@ -51,6 +51,7 @@ MOZ_APP_ID={3c2e2abc-06d4-11e1-ac3b-374f68613e61}
MOZ_TIME_MANAGER=1
MOZ_SIMPLEPUSH=1
MOZ_PAY=1
MOZ_TOOLKIT_SEARCH=
MOZ_PLACES=

View File

@ -1017,6 +1017,7 @@ pref("urlclassifier.downloadAllowTable", "goog-downloadwhite-digest256");
#endif
pref("browser.geolocation.warning.infoURL", "https://www.mozilla.org/%LOCALE%/firefox/geolocation/");
pref("browser.push.warning.infoURL", "https://www.mozilla.org/%LOCALE%/firefox/push/");
pref("browser.EULA.version", 3);
pref("browser.rights.version", 3);
@ -1716,9 +1717,6 @@ pref("loop.contacts.gravatars.promo", true);
pref("loop.browserSharing.showInfoBar", true);
pref("loop.contextInConverations.enabled", false);
// serverURL to be assigned by services team
pref("services.push.serverURL", "wss://push.services.mozilla.com/");
pref("social.sidebar.unload_timeout_ms", 10000);
// activation from inside of share panel is possible if activationPanelEnabled
@ -1883,6 +1881,7 @@ pref("dom.ipc.reportProcessHangs", true);
// Enable ReadingList browser UI by default.
pref("browser.readinglist.enabled", true);
pref("browser.readinglist.sidebarEverOpened", false);
// Enable the readinglist engine by default.
pref("readinglist.scheduler.enabled", true);
pref("readinglist.server", "https://readinglist.services.mozilla.com/v1");

View File

@ -780,6 +780,7 @@
<image id="default-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="identity-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="geo-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="push-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="addons-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="indexedDB-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="password-notification-icon" class="notification-anchor-icon" role="button"/>

View File

@ -12,7 +12,7 @@ support-files =
[browser_newtab_bug725996.js]
[browser_newtab_bug734043.js]
[browser_newtab_bug735987.js]
skip-if = os == "mac" # Intermittent failures, bug 898317
skip-if = (os == 'mac' && os_version == '10.10') # bug 1122478 - newtab drag-drop tests fail on OS X 10.10
[browser_newtab_bug752841.js]
[browser_newtab_bug765628.js]
[browser_newtab_bug876313.js]
@ -21,9 +21,9 @@ skip-if = os == "mac" # Intermittent failures, bug 898317
[browser_newtab_bug998387.js]
[browser_newtab_disable.js]
[browser_newtab_drag_drop.js]
skip-if = os == "win" && debug || (os == 'mac' && os_version == '10.10') # bug 1097056; test fails in --run-by-dir mode on win8 x64 debug; Bug 1122479 - newtab drag-drop tests fail on OS X 10.10
skip-if = os == "win" || (os == 'mac' && os_version == '10.10') # Bug 1152810 - can't do simulateDrop(0,0) on Windows; Bug 1122478 - newtab drag-drop tests fail on OS X 10.10
[browser_newtab_drag_drop_ext.js]
skip-if = (os == 'mac' && os_version == '10.10') # bug 1122479 - newtab drag-drop tests fail on OS X 10.10
skip-if = (os == 'mac' && os_version == '10.10') # bug 1122478 - newtab drag-drop tests fail on OS X 10.10
[browser_newtab_drop_preview.js]
[browser_newtab_enhanced.js]
[browser_newtab_focus.js]

View File

@ -495,33 +495,81 @@ function simulateExternalDrop(aDestIndex) {
* @param aCallback The function that is called when we're done.
*/
function startAndCompleteDragOperation(aSource, aDest, aCallback) {
// Start by pressing the left mouse button.
synthesizeNativeMouseLDown(aSource);
// The implementation of this function varies by platform because each
// platform has particular quirks that we need to deal with
// Move the mouse in 5px steps until the drag operation starts.
let offset = 0;
let interval = setInterval(() => {
synthesizeNativeMouseDrag(aSource, offset += 5);
}, 10);
// When the drag operation has started we'll move
// the dragged element to its target position.
aSource.addEventListener("dragstart", function onDragStart() {
aSource.removeEventListener("dragstart", onDragStart);
clearInterval(interval);
// Place the cursor above the drag target.
synthesizeNativeMouseMove(aDest);
});
// As soon as the dragged element hovers the target, we'll drop it.
aDest.addEventListener("dragenter", function onDragEnter() {
aDest.removeEventListener("dragenter", onDragEnter);
// Finish the drop operation.
if (isMac) {
// On OS X once the drag starts, Cocoa manages the drag session and
// gives us a limited amount of time to complete the drag operation. In
// some cases as soon as the first mouse-move event is received (the one
// that starts the drag session), Cocoa becomes blind to subsequent mouse
// events and completes the drag session all by itself. Therefore it is
// important that the first mouse-move we send is already positioned at
// the destination.
synthesizeNativeMouseLDown(aSource);
synthesizeNativeMouseDrag(aDest);
// In some tests, aSource and aDest are at the same position, so to ensure
// a drag session is created (instead of it just turning into a click) we
// move the mouse 10 pixels away and then back.
synthesizeNativeMouseDrag(aDest, 10);
synthesizeNativeMouseDrag(aDest);
// Finally, release the drag and have it run the callback when done.
synthesizeNativeMouseLUp(aDest);
aCallback();
});
} else if (isWindows) {
// on Windows once the drag is initiated, Windows doesn't spin our
// message loop at all, so with async event synthesization the async
// messages never get processed while a drag is in progress. So if
// we did a mousedown followed by a mousemove, we would never be able
// to successfully dispatch the mouseup. Instead, we just skip the move
// entirely, so and just generate the up at the destination. This way
// Windows does the drag and also terminates it right away. Note that
// this only works for tests where aSource and aDest are sufficiently
// far to trigger a drag, otherwise it may just end up doing a click.
synthesizeNativeMouseLDown(aSource);
synthesizeNativeMouseLUp(aDest);
aCallback();
} else if (isLinux) {
// Start by pressing the left mouse button.
synthesizeNativeMouseLDown(aSource);
// Move the mouse in 5px steps until the drag operation starts.
// Note that we need to do this with pauses in between otherwise the
// synthesized events get coalesced somewhere in the guts of GTK. In order
// to successfully initiate a drag session in the case where aSource and
// aDest are at the same position, we synthesize a bunch of drags until
// we know the drag session has started, and then move to the destination.
let offset = 0;
let interval = setInterval(() => {
synthesizeNativeMouseDrag(aSource, offset += 5);
}, 10);
// When the drag operation has started we'll move
// the dragged element to its target position.
aSource.addEventListener("dragstart", function onDragStart() {
aSource.removeEventListener("dragstart", onDragStart);
clearInterval(interval);
// Place the cursor above the drag target.
synthesizeNativeMouseMove(aDest);
});
// As soon as the dragged element hovers the target, we'll drop it.
// Note that we need to actually wait for the dragenter event here, because
// the mousemove synthesization is "more async" than the mouseup
// synthesization - they use different gdk APIs. If we don't wait, the
// up could get processed before the moves, dropping the item in the
// wrong position.
aDest.addEventListener("dragenter", function onDragEnter() {
aDest.removeEventListener("dragenter", onDragEnter);
// Finish the drop operation.
synthesizeNativeMouseLUp(aDest, null);
aCallback();
});
} else {
throw "Unsupported platform";
}
}
/**

View File

@ -2393,6 +2393,42 @@ ContentPermissionPrompt.prototype = {
}
},
_promptPush : function(aRequest) {
var browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
var requestingURI = aRequest.principal.URI;
var message = browserBundle.formatStringFromName("push.enablePush",
[requestingURI.host], 1);
var actions = [
{
stringId: "push.alwaysAllow",
action: Ci.nsIPermissionManager.ALLOW_ACTION,
expireType: null,
callback: function() {}
},
{
stringId: "push.allowForSession",
action: Ci.nsIPermissionManager.ALLOW_ACTION,
expireType: Ci.nsIPermissionManager.EXPIRE_SESSION,
callback: function() {}
},
{
stringId: "push.alwaysBlock",
action: Ci.nsIPermissionManager.DENY_ACTION,
expireType: null,
callback: function() {}
}]
var options = {
learnMoreURL: Services.urlFormatter.formatURLPref("browser.push.warning.infoURL"),
};
this._showPrompt(aRequest, message, "push", actions, "push",
"push-notification-icon", options);
},
_promptGeo : function(aRequest) {
var secHistogram = Services.telemetry.getHistogramById("SECURITY_UI");
var requestingURI = aRequest.principal.URI;
@ -2517,7 +2553,6 @@ ContentPermissionPrompt.prototype = {
},
prompt: function CPP_prompt(request) {
// Only allow exactly one permission rquest here.
let types = request.types.QueryInterface(Ci.nsIArray);
if (types.length != 1) {
@ -2529,6 +2564,7 @@ ContentPermissionPrompt.prototype = {
const kFeatureKeys = { "geolocation" : "geo",
"desktop-notification" : "desktop-notification",
"pointerLock" : "pointerLock",
"push" : "push"
};
// Make sure that we support the request.
@ -2579,6 +2615,9 @@ ContentPermissionPrompt.prototype = {
case "pointerLock":
this._promptPointerLock(request, autoAllow);
break;
case "push":
this._promptPush(request);
break;
}
},

View File

@ -336,7 +336,16 @@ let PermissionDefaults = {
let value = (aValue != this.DENY);
Services.prefs.setBoolPref("full-screen-api.enabled", value);
},
get push() {
if (!Services.prefs.getBoolPref("dom.push.enabled")) {
return this.DENY;
}
return this.UNKNOWN;
},
set push(aValue) {
let value = (aValue != this.DENY);
Services.prefs.setBoolPref("dom.push.enabled", value);
},
get camera() this.UNKNOWN,
get microphone() this.UNKNOWN
};
@ -378,12 +387,12 @@ let AboutPermissions = {
* Potential future additions: "sts/use", "sts/subd"
*/
_supportedPermissions: ["password", "cookie", "geo", "indexedDB", "popup",
"fullscreen", "camera", "microphone"],
"fullscreen", "camera", "microphone", "push"],
/**
* Permissions that don't have a global "Allow" option.
*/
_noGlobalAllow: ["geo", "indexedDB", "fullscreen", "camera", "microphone"],
_noGlobalAllow: ["geo", "indexedDB", "fullscreen", "camera", "microphone", "push"],
/**
* Permissions that don't have a global "Deny" option.
@ -408,9 +417,11 @@ let AboutPermissions = {
Services.prefs.addObserver("signon.rememberSignons", this, false);
Services.prefs.addObserver("network.cookie.", this, false);
Services.prefs.addObserver("geo.enabled", this, false);
Services.prefs.addObserver("dom.push.enabled", this, false);
Services.prefs.addObserver("dom.indexedDB.enabled", this, false);
Services.prefs.addObserver("dom.disable_open_during_load", this, false);
Services.prefs.addObserver("full-screen-api.enabled", this, false);
Services.prefs.addObserver("dom.push.enabled", this, false);
Services.obs.addObserver(this, "perm-changed", false);
Services.obs.addObserver(this, "passwordmgr-storage-changed", false);
@ -429,9 +440,11 @@ let AboutPermissions = {
Services.prefs.removeObserver("signon.rememberSignons", this, false);
Services.prefs.removeObserver("network.cookie.", this, false);
Services.prefs.removeObserver("geo.enabled", this, false);
Services.prefs.removeObserver("dom.push.enabled", this, false);
Services.prefs.removeObserver("dom.indexedDB.enabled", this, false);
Services.prefs.removeObserver("dom.disable_open_during_load", this, false);
Services.prefs.removeObserver("full-screen-api.enabled", this, false);
Services.prefs.removeObserver("dom.push.enabled", this, false);
Services.obs.removeObserver(this, "perm-changed");
Services.obs.removeObserver(this, "passwordmgr-storage-changed");

View File

@ -252,8 +252,28 @@
</menulist>
</hbox>
</vbox>
</hbox>
</hbox>
<!-- Push Notifications -->
<hbox id="push-pref-item"
class="pref-item" align="top">
<image class="pref-icon" type="push"/>
<vbox>
<label class="pref-title" value="&push.label;"/>
<hbox align="center">
<menulist id="push-menulist"
class="pref-menulist"
type="push"
oncommand="AboutPermissions.onPermissionCommand(event);">
<menupopup>
<menuitem id="push-0" value="0" label="&permission.alwaysAsk;"/>
<menuitem id="push-1" value="1" label="&permission.allow;"/>
<menuitem id="push-2" value="2" label="&permission.block;"/>
</menupopup>
</menulist>
</hbox>
</vbox>
</hbox>
</vbox>
</hbox>

View File

@ -23,6 +23,7 @@ const TEST_PERMS = {
"password": PERM_ALLOW,
"cookie": PERM_ALLOW,
"geo": PERM_UNKNOWN,
"push": PERM_DENY,
"indexedDB": PERM_UNKNOWN,
"popup": PERM_DENY,
"fullscreen" : PERM_UNKNOWN,
@ -37,7 +38,7 @@ const NO_GLOBAL_ALLOW = [
];
// number of managed permissions in the interface
const TEST_PERMS_COUNT = 8;
const TEST_PERMS_COUNT = 9;
function test() {
waitForExplicitFinish();

View File

@ -366,6 +366,15 @@ webNotifications.neverShow=Always Block Notifications
webNotifications.neverShow.accesskey=N
webNotifications.showFromSite=Would you like to show notifications from %S?
# Push Notifications
push.allowForSession=Allow for Session
push.allowForSession.accesskey=S
push.alwaysAllow=Always Allow Push Notifications
push.alwaysAllow.accesskey=A
push.alwaysBlock=Always Block Push Notifications
push.alwaysBlock.accesskey=B
push.enablePush=Would you like to allow Push Notifications for %S?
# Pointer lock UI
pointerLock.allow2=Hide pointer

View File

@ -42,5 +42,7 @@
<!ENTITY popup.label "Open Pop-up Windows">
<!ENTITY fullscreen.label "Fullscreen">
<!ENTITY push.label "Receive Push Notifications">
<!ENTITY camera.label "Use the Camera">
<!ENTITY microphone.label "Use the Microphone">

View File

@ -18,4 +18,4 @@ permission.geo.label = Access Your Location
permission.indexedDB.label = Maintain Offline Storage
permission.fullscreen.label = Enter Fullscreen
permission.pointerLock.label = Hide the Mouse Pointer
permission.push.label = Receive Push Notifications

View File

@ -190,5 +190,9 @@ let gPermissionObject = {
"pointerLock": {
exactHostMatch: true
},
"push": {
exactHostMatch: true
}
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 606 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

@ -33,6 +33,8 @@ browser.jar:
skin/classic/browser/fullscreen-darknoise.png
skin/classic/browser/Geolocation-16.png
skin/classic/browser/Geolocation-64.png
skin/classic/browser/Push-16.png
skin/classic/browser/Push-64.png
skin/classic/browser/heartbeat-icon.svg (../shared/heartbeat-icon.svg)
skin/classic/browser/heartbeat-star-lit.svg (../shared/heartbeat-star-lit.svg)
skin/classic/browser/heartbeat-star-off.svg (../shared/heartbeat-star-off.svg)

View File

@ -79,6 +79,9 @@
.pref-icon[type="geo"] {
list-style-image: url(chrome://browser/skin/Geolocation-64.png);
}
.pref-icon[type="push"] {
list-style-image: url(chrome://browser/skin/Push-64.png);
}
.pref-icon[type="indexedDB"] {
list-style-image: url(chrome://global/skin/icons/question-64.png);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 666 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -35,6 +35,10 @@ browser.jar:
skin/classic/browser/Geolocation-16@2x.png
skin/classic/browser/Geolocation-64.png
skin/classic/browser/Geolocation-64@2x.png
skin/classic/browser/Push-16.png
skin/classic/browser/Push-16@2x.png
skin/classic/browser/Push-64.png
skin/classic/browser/Push-64@2x.png
skin/classic/browser/heartbeat-icon.svg (../shared/heartbeat-icon.svg)
skin/classic/browser/heartbeat-star-lit.svg (../shared/heartbeat-star-lit.svg)
skin/classic/browser/heartbeat-star-off.svg (../shared/heartbeat-star-off.svg)

View File

@ -89,6 +89,9 @@
.pref-icon[type="geo"] {
list-style-image: url(chrome://browser/skin/Geolocation-64.png);
}
.pref-icon[type="push"] {
list-style-image: url(chrome://browser/skin/Push-64.png);
}
.pref-icon[type="indexedDB"] {
list-style-image: url(chrome://global/skin/icons/question-64.png);
}

View File

@ -14,6 +14,10 @@
list-style-image: url(chrome://browser/skin/Geolocation-64.png);
}
.popup-notification-icon[popupid="push"] {
list-style-image: url(chrome://browser/skin/Push-64.png);
}
.popup-notification-icon[popupid="xpinstall-disabled"],
.popup-notification-icon[popupid="addon-progress"],
.popup-notification-icon[popupid="addon-install-blocked"],
@ -119,6 +123,10 @@
list-style-image: url(chrome://browser/skin/Geolocation-16.png);
}
#push-notification-icon {
list-style-image: url(chrome://browser/skin/Push-16.png);
}
#addons-notification-icon {
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
}
@ -290,6 +298,10 @@
list-style-image: url(chrome://browser/skin/Geolocation-16@2x.png);
}
#push-notification-icon {
list-style-image: url(chrome://browser/skin/Push-16@2x.png);
}
.indexedDB-notification-icon,
#indexedDB-notification-icon {
list-style-image: url(chrome://global/skin/icons/question-32.png);
@ -396,6 +408,10 @@
list-style-image: url(chrome://browser/skin/Geolocation-64@2x.png);
}
.popup-notification-icon[popupid="push"] {
list-style-image: url(chrome://browser/skin/Push-64@2x.png);
}
.popup-notification-icon[popupid="web-notifications"] {
list-style-image: url(chrome://browser/skin/notification-64@2x.png);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@ -32,6 +32,8 @@ browser.jar:
skin/classic/browser/fullscreen-darknoise.png
skin/classic/browser/Geolocation-16.png
skin/classic/browser/Geolocation-64.png
skin/classic/browser/Push-16.png
skin/classic/browser/Push-64.png
skin/classic/browser/heartbeat-icon.svg (../shared/heartbeat-icon.svg)
skin/classic/browser/heartbeat-star-lit.svg (../shared/heartbeat-star-lit.svg)
skin/classic/browser/heartbeat-star-off.svg (../shared/heartbeat-star-off.svg)

View File

@ -82,6 +82,9 @@
.pref-icon[type="geo"] {
list-style-image: url(chrome://browser/skin/Geolocation-64.png);
}
.pref-icon[type="push"] {
list-style-image: url(chrome://browser/skin/Push-64.png);
}
.pref-icon[type="indexedDB"] {
list-style-image: url(chrome://global/skin/icons/question-64.png);
}

View File

@ -3942,6 +3942,7 @@ MOZ_ANDROID_MLS_STUMBLER=
MOZ_ANDROID_SHARE_OVERLAY=
ACCESSIBILITY=1
MOZ_TIME_MANAGER=
MOZ_SIMPLEPUSH=
MOZ_PAY=
MOZ_AUDIO_CHANNEL_MANAGER=
NSS_NO_LIBPKIX=
@ -7525,6 +7526,15 @@ if test -n "$MOZ_B2G_CAMERA"; then
fi
AC_SUBST(MOZ_B2G_CAMERA)
dnl ========================================================
dnl = Enable Support for SimplePush (Gonk usually)
dnl This will disable the Push API.
dnl ========================================================
if test -n "$MOZ_SIMPLEPUSH"; then
AC_DEFINE(MOZ_SIMPLEPUSH)
fi
AC_SUBST(MOZ_SIMPLEPUSH)
dnl ========================================================
dnl = Enable Support for Payment API
dnl ========================================================

View File

@ -200,8 +200,6 @@
#include "nsIBrowserSearchService.h"
#endif
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
#if defined(DEBUG_bryner) || defined(DEBUG_chb)
//#define DEBUG_DOCSHELL_FOCUS
#define DEBUG_PAGE_CACHE
@ -222,9 +220,6 @@ static bool gAddedPreferencesVarCache = false;
bool nsDocShell::sUseErrorPages = false;
// Number of documents currently loading
static int32_t gNumberOfDocumentsLoading = 0;
// Global count of existing docshells.
static int32_t gDocShellCount = 0;
@ -255,18 +250,6 @@ static PRLogModuleInfo* gDocShellLeakLog;
const char kBrandBundleURL[] = "chrome://branding/locale/brand.properties";
const char kAppstringsBundleURL[] = "chrome://global/locale/appstrings.properties";
static void
FavorPerformanceHint(bool aPerfOverStarvation)
{
nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
if (appShell) {
appShell->FavorPerformanceHint(
aPerfOverStarvation,
Preferences::GetUint("docshell.event_starvation_delay_hint",
NS_EVENT_STARVATION_DELAY_HINT));
}
}
//*****************************************************************************
// <a ping> support
//*****************************************************************************
@ -7541,14 +7524,6 @@ nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
mIsExecutingOnLoadHandler = false;
mEODForCurrentDocument = true;
// If all documents have completed their loading
// favor native event dispatch priorities
// over performance
if (--gNumberOfDocumentsLoading == 0) {
// Hint to use normal native event dispatch priorities
FavorPerformanceHint(false);
}
}
/* Check if the httpChannel has any cache-control related response headers,
* like no-store, no-cache. If so, update SHEntry so that
@ -8678,12 +8653,6 @@ nsDocShell::RestoreFromHistory()
mSavingOldViewer = false;
mEODForCurrentDocument = false;
// Tell the event loop to favor plevents over user events, see comments
// in CreateContentViewer.
if (++gNumberOfDocumentsLoading == 1) {
FavorPerformanceHint(true);
}
if (oldCv && newCv) {
newCv->SetMinFontSize(minFontSize);
newCv->SetTextZoom(textZoom);
@ -9096,16 +9065,6 @@ nsDocShell::CreateContentViewer(const nsACString& aContentType,
}
}
// Give hint to native plevent dispatch mechanism. If a document
// is loading the native plevent dispatch mechanism should favor
// performance over normal native event dispatch priorities.
if (++gNumberOfDocumentsLoading == 1) {
// Hint to favor performance for the plevent notification mechanism.
// We want the pages to load as fast as possible even if its means
// native messages might be starved.
FavorPerformanceHint(true);
}
if (onLocationChangeNeeded) {
FireOnLocationChange(this, aRequest, mCurrentURI, 0);
}

View File

@ -42,7 +42,7 @@ public:
void Notify(const hal::SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo) override;
// Implementing hal::SystemClockChangeObserver
void Notify(const int64_t& aClockDeltaMS);
void Notify(const int64_t& aClockDeltaMS) override;
private:
virtual ~AlarmHalService();

View File

@ -201,7 +201,6 @@ nsContentSink::Init(nsIDocument* aDoc,
if (sEnablePerfMode != 0) {
mDynamicLowerValue = sEnablePerfMode == 1;
FavorPerformanceHint(!mDynamicLowerValue, 0);
}
return NS_OK;
@ -1408,15 +1407,6 @@ nsContentSink::DidProcessATokenImpl()
//----------------------------------------------------------------------
void
nsContentSink::FavorPerformanceHint(bool perfOverStarvation, uint32_t starvationDelay)
{
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
if (appShell)
appShell->FavorPerformanceHint(perfOverStarvation, starvationDelay);
}
void
nsContentSink::BeginUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
{
@ -1494,12 +1484,6 @@ nsContentSink::DropParserAndPerfHint(void)
// reference.
nsRefPtr<nsParserBase> kungFuDeathGrip(mParser.forget());
if (mDynamicLowerValue) {
// Reset the performance hint which was set to FALSE
// when mDynamicLowerValue was set.
FavorPerformanceHint(true, 0);
}
if (!mRunsToCompletion) {
mDocument->UnblockOnload(true);
}
@ -1537,7 +1521,6 @@ nsContentSink::WillParseImpl(void)
(currentTime - lastEventTime) < uint32_t(sInteractiveTime));
if (mDynamicLowerValue != newDynLower) {
FavorPerformanceHint(!newDynLower, 0);
mDynamicLowerValue = newDynLower;
}
}

View File

@ -239,8 +239,6 @@ public:
static void NotifyDocElementCreated(nsIDocument* aDoc);
protected:
void
FavorPerformanceHint(bool perfOverStarvation, uint32_t starvationDelay);
inline int32_t GetNotificationInterval()
{

View File

@ -973,6 +973,18 @@ nsFrameLoader::SwapWithOtherRemoteLoader(nsFrameLoader* aOther,
return rv;
}
nsCOMPtr<nsIBrowserDOMWindow> otherBrowserDOMWindow =
aOther->mRemoteBrowser->GetBrowserDOMWindow();
nsCOMPtr<nsIBrowserDOMWindow> browserDOMWindow =
mRemoteBrowser->GetBrowserDOMWindow();
if (!otherBrowserDOMWindow || !browserDOMWindow) {
return NS_ERROR_NOT_IMPLEMENTED;
}
aOther->mRemoteBrowser->SetBrowserDOMWindow(browserDOMWindow);
mRemoteBrowser->SetBrowserDOMWindow(otherBrowserDOMWindow);
// Native plugin windows used by this remote content need to be reparented.
const nsTArray<mozilla::plugins::PPluginWidgetParent*>& plugins =
aOther->mRemoteBrowser->ManagedPPluginWidgetParent();

View File

@ -922,6 +922,18 @@ DOMInterfaces = {
'headerFile': 'HTMLPropertiesCollection.h',
},
'PushEvent': {
'headerFile': 'ServiceWorkerEvents.h',
'nativeType': 'mozilla::dom::workers::PushEvent',
'workers': True
},
'PushMessageData': {
'headerFile': 'ServiceWorkerEvents.h',
'nativeType': 'mozilla::dom::workers::PushMessageData',
'workers': True
},
'Range': {
'nativeType': 'nsRange',
'binaryNames': {

View File

@ -111,6 +111,10 @@ if CONFIG['MOZ_BUILD_APP'] in ['browser', 'mobile/android', 'xulrunner']:
# This is needed for Window.webidl
DEFINES['HAVE_SIDEBAR'] = True
if CONFIG['MOZ_SIMPLEPUSH']:
DEFINES['MOZ_SIMPLEPUSH'] = True
PYTHON_UNIT_TESTS += [
'mozwebidlcodegen/test/test_mozwebidlcodegen.py',
]

View File

@ -1,5 +1,9 @@
function handleRequest(request, response) {
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Vary", request.getHeader("WhatToVary"));
response.write(request.getHeader("WhatToVary"));
var header = "no WhatToVary header";
if (request.hasHeader("WhatToVary")) {
header = request.getHeader("WhatToVary");
response.setHeader("Vary", header);
}
response.write(header);
}

View File

@ -6587,6 +6587,9 @@ private:
virtual void
SendResults() override;
virtual void
ActorDestroy(ActorDestroyReason aWhy) override;
};
class OpenDatabaseOp::VersionChangeOp final
@ -17660,6 +17663,18 @@ OpenDatabaseOp::SendResults()
FinishSendResults();
}
void
OpenDatabaseOp::ActorDestroy(ActorDestroyReason aWhy)
{
AssertIsOnBackgroundThread();
NoteActorDestroyed();
if (mDatabase && aWhy != Deletion) {
mDatabase->Invalidate();
}
}
void
OpenDatabaseOp::ConnectionClosedCallback()
{

View File

@ -33,7 +33,7 @@ interface nsIServiceWorkerInfo : nsISupports
readonly attribute DOMString waitingCacheName;
};
[scriptable, builtinclass, uuid(861b55e9-d6ac-47cf-a528-8590e9b44de6)]
[scriptable, builtinclass, uuid(3cd3acce-8c80-4fcc-9265-067ebe8cab92)]
interface nsIServiceWorkerManager : nsISupports
{
/**
@ -121,6 +121,9 @@ interface nsIServiceWorkerManager : nsISupports
// This is meant to be used only by about:serviceworkers. It returns an array
// of nsIServiceWorkerInfo.
nsIArray getAllRegistrations();
void sendPushEvent(in ACString scope, in DOMString data);
void sendPushSubscriptionChangedEvent(in ACString scope);
};
%{ C++

View File

@ -179,6 +179,7 @@
#include "mozilla/dom/time/DateCacheCleaner.h"
#include "mozilla/dom/voicemail/VoicemailIPCService.h"
#include "mozilla/net/NeckoMessageUtils.h"
#include "mozilla/widget/PuppetBidiKeyboard.h"
#include "mozilla/RemoteSpellCheckEngineChild.h"
#include "GMPServiceChild.h"
@ -200,6 +201,7 @@ using namespace mozilla::ipc;
using namespace mozilla::layers;
using namespace mozilla::net;
using namespace mozilla::jsipc;
using namespace mozilla::widget;
#if defined(MOZ_WIDGET_GONK)
using namespace mozilla::system;
#endif
@ -793,12 +795,14 @@ ContentChild::InitXPCOM()
if (NS_FAILED(svc->RegisterListener(mConsoleListener)))
NS_WARNING("Couldn't register console listener for child process");
bool isOffline;
bool isOffline, isLangRTL;
ClipboardCapabilities clipboardCaps;
DomainPolicyClone domainPolicy;
SendGetXPCOMProcessAttributes(&isOffline, &mAvailableDictionaries, &clipboardCaps, &domainPolicy);
SendGetXPCOMProcessAttributes(&isOffline, &isLangRTL, &mAvailableDictionaries,
&clipboardCaps, &domainPolicy);
RecvSetOffline(isOffline);
RecvBidiKeyboardNotify(isLangRTL);
if (domainPolicy.active()) {
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
@ -1222,6 +1226,18 @@ ContentChild::RecvSpeakerManagerNotify()
return false;
}
bool
ContentChild::RecvBidiKeyboardNotify(const bool& aIsLangRTL)
{
// bidi is always of type PuppetBidiKeyboard* (because in the child, the only
// possible implementation of nsIBidiKeyboard is PuppetBidiKeyboard).
PuppetBidiKeyboard* bidi = static_cast<PuppetBidiKeyboard*>(nsContentUtils::GetBidiKeyboard());
if (bidi) {
bidi->SetIsLangRTL(aIsLangRTL);
}
return true;
}
static CancelableTask* sFirstIdleTask;
static void FirstIdle(void)
@ -2897,6 +2913,9 @@ NS_EXPORT void
AfterNuwaFork()
{
SetCurrentProcessPrivileges(base::PRIVILEGES_DEFAULT);
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
mozilla::SandboxEarlyInit(XRE_GetProcessType(), /* isNuwa: */ false);
#endif
}
#endif // MOZ_NUWA_PROCESS

View File

@ -299,6 +299,8 @@ public:
virtual bool RecvSpeakerManagerNotify() override;
virtual bool RecvBidiKeyboardNotify(const bool& isLangRTL) override;
virtual bool RecvNotifyVisited(const URIParams& aURI) override;
// auto remove when alertfinished is received.
nsresult AddRemoteAlertObserver(const nsString& aData, nsIObserver* aObserver);

View File

@ -151,6 +151,8 @@
#include "private/pprio.h"
#include "ContentProcessManager.h"
#include "nsIBidiKeyboard.h"
#if defined(ANDROID) || defined(LINUX)
#include "nsSystemInfo.h"
#endif
@ -2817,11 +2819,11 @@ ContentParent::RecvAddNewProcess(const uint32_t& aPid,
}
// Update offline settings.
bool isOffline;
bool isOffline, isLangRTL;
InfallibleTArray<nsString> unusedDictionaries;
ClipboardCapabilities clipboardCaps;
DomainPolicyClone domainPolicy;
RecvGetXPCOMProcessAttributes(&isOffline, &unusedDictionaries,
RecvGetXPCOMProcessAttributes(&isOffline, &isLangRTL, &unusedDictionaries,
&clipboardCaps, &domainPolicy);
mozilla::unused << content->SendSetOffline(isOffline);
MOZ_ASSERT(!clipboardCaps.supportsSelectionClipboard() &&
@ -3164,6 +3166,7 @@ ContentParent::RecvGetProcessAttributes(ContentParentId* aCpId,
bool
ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
bool* aIsLangRTL,
InfallibleTArray<nsString>* dictionaries,
ClipboardCapabilities* clipboardCaps,
DomainPolicyClone* domainPolicy)
@ -3173,6 +3176,13 @@ ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
DebugOnly<nsresult> rv = io->GetOffline(aIsOffline);
MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting offline?");
nsIBidiKeyboard* bidi = nsContentUtils::GetBidiKeyboard();
*aIsLangRTL = false;
if (bidi) {
bidi->IsLangRTL(aIsLangRTL);
}
nsCOMPtr<nsISpellChecker> spellChecker(do_GetService(NS_SPELLCHECKER_CONTRACTID));
MOZ_ASSERT(spellChecker, "No spell checker?");

View File

@ -535,6 +535,7 @@ private:
bool* aIsForApp,
bool* aIsForBrowser) override;
virtual bool RecvGetXPCOMProcessAttributes(bool* aIsOffline,
bool* aIsLangRTL,
InfallibleTArray<nsString>* dictionaries,
ClipboardCapabilities* clipboardCaps,
DomainPolicyClone* domainPolicy)

View File

@ -456,6 +456,12 @@ child:
async SpeakerManagerNotify();
/**
* Communication between the PuppetBidiKeyboard and the actual
* BidiKeyboard hosted by the parent
*/
async BidiKeyboardNotify(bool isLangRTL);
async DataStoreNotify(uint32_t aAppId, nsString aName,
nsString aManifestURL);
@ -616,7 +622,7 @@ parent:
sync GetProcessAttributes()
returns (ContentParentId cpId, bool isForApp, bool isForBrowser);
sync GetXPCOMProcessAttributes()
returns (bool isOffline, nsString[] dictionaries,
returns (bool isOffline, bool isLangRTL, nsString[] dictionaries,
ClipboardCapabilities clipboardCaps,
DomainPolicyClone domainPolicy);

View File

@ -9,5 +9,6 @@ toolkit.jar:
content/global/BrowserElementChildPreload.js (../browser-element/BrowserElementChildPreload.js)
content/global/BrowserElementPanning.js (../browser-element/BrowserElementPanning.js)
* content/global/BrowserElementPanningAPZDisabled.js (../browser-element/BrowserElementPanningAPZDisabled.js)
content/global/PushServiceChildPreload.js (../push/PushServiceChildPreload.js)
content/global/preload.js (preload.js)
content/global/post-fork-preload.js (post-fork-preload.js)

View File

@ -164,7 +164,6 @@ struct AudioChunk {
#endif
};
/**
* A list of audio samples consisting of a sequence of slices of SharedBuffers.
* The audio rate is determined by the track, not stored in this class.
@ -207,17 +206,18 @@ public:
"Dropping samples");
uint32_t outSize = (c.mDuration * aOutRate + aInRate - 1) / aInRate;
for (uint32_t i = 0; i < channels; i++) {
const T* in = static_cast<const T*>(c.mChannelData[i]);
T* out = output[i].AppendElements(outSize);
uint32_t outFrames = outSize;
#if !defined(MOZILLA_XPCOMRT_API)
// FIXME Bug 1126414 - XPCOMRT does not support dom::WebAudioUtils::SpeexResamplerProcess
const T* in = static_cast<const T*>(c.mChannelData[i]);
dom::WebAudioUtils::SpeexResamplerProcess(aResampler, i,
in, &inFrames,
out, &outFrames);
MOZ_ASSERT(inFrames == c.mDuration);
#endif // !defined(MOZILLA_XPCOMRT_API)
bufferPtrs[i] = out;
output[i].SetLength(outFrames);
}

View File

@ -157,7 +157,6 @@ MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder)
, mDemuxerInitialized(false)
, mFoundSPSForTelemetry(false)
, mIsEncrypted(false)
, mAreDecodersSetup(false)
, mIndexReady(false)
, mLastSeenEnd(-1)
, mDemuxerMonitor("MP4 Demuxer")
@ -294,12 +293,6 @@ private:
};
#endif // MOZ_EME
void MP4Reader::RequestCodecResource() {
if (mVideo.mDecoder) {
mVideo.mDecoder->AllocateMediaResources();
}
}
bool MP4Reader::IsWaitingMediaResources() {
return mVideo.mDecoder && mVideo.mDecoder->IsWaitingMediaResources();
}
@ -357,14 +350,6 @@ MP4Reader::IsSupportedVideoMimeType(const nsACString& aMimeType)
mPlatform->SupportsMimeType(aMimeType);
}
void
MP4Reader::PreReadMetadata()
{
if (mPlatform) {
RequestCodecResource();
}
}
bool
MP4Reader::InitDemuxer()
{
@ -408,7 +393,6 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
} else if (mPlatform && !IsWaitingMediaResources()) {
*aInfo = mInfo;
*aTags = nullptr;
return NS_OK;
}
if (HasAudio()) {
@ -461,7 +445,7 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
*aInfo = mInfo;
*aTags = nullptr;
if (!IsWaitingMediaResources() && !IsWaitingOnCDMResource()) {
if (!IsWaitingOnCDMResource()) {
NS_ENSURE_TRUE(EnsureDecodersSetup(), NS_ERROR_FAILURE);
}
@ -471,11 +455,28 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
return NS_OK;
}
bool MP4Reader::CheckIfDecoderSetup()
{
if (!mDemuxerInitialized) {
return false;
}
if (HasAudio() && !mAudio.mDecoder) {
return false;
}
if (HasVideo() && !mVideo.mDecoder) {
return false;
}
return true;
}
bool
MP4Reader::EnsureDecodersSetup()
{
if (mAreDecodersSetup) {
return !!mPlatform;
if (CheckIfDecoderSetup()) {
return true;
}
if (mIsEncrypted) {
@ -507,8 +508,11 @@ MP4Reader::EnsureDecodersSetup()
return false;
#endif
} else {
mPlatform = PlatformDecoderModule::Create();
NS_ENSURE_TRUE(mPlatform, false);
// mPlatform doesn't need to be recreated when resuming from dormant.
if (!mPlatform) {
mPlatform = PlatformDecoderModule::Create();
NS_ENSURE_TRUE(mPlatform, false);
}
}
if (HasAudio()) {
@ -549,7 +553,6 @@ MP4Reader::EnsureDecodersSetup()
NS_ENSURE_SUCCESS(rv, false);
}
mAreDecodersSetup = true;
return true;
}
@ -1125,13 +1128,8 @@ MP4Reader::GetBuffered(dom::TimeRanges* aBuffered)
bool MP4Reader::IsDormantNeeded()
{
#if defined(MP4_READER_DORMANT)
return
#if defined(MP4_READER_DORMANT_HEURISTIC)
mDormantEnabled &&
#endif
mVideo.mDecoder &&
mVideo.mDecoder->IsDormantNeeded();
return mDormantEnabled;
#else
return false;
#endif
@ -1146,7 +1144,8 @@ void MP4Reader::ReleaseMediaResources()
container->ClearCurrentFrame();
}
if (mVideo.mDecoder) {
mVideo.mDecoder->ReleaseMediaResources();
mVideo.mDecoder->Shutdown();
mVideo.mDecoder = nullptr;
}
}

View File

@ -28,12 +28,6 @@ typedef std::deque<nsRefPtr<MediaRawData>> MediaSampleQueue;
class MP4Stream;
#if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN) || defined(MOZ_APPLEMEDIA) || defined(MOZ_FFMPEG)
#define MP4_READER_DORMANT
#else
#undef MP4_READER_DORMANT
#endif
#if defined(XP_WIN) || defined(MOZ_APPLEMEDIA) || defined(MOZ_FFMPEG)
#define MP4_READER_DORMANT_HEURISTIC
#else
#undef MP4_READER_DORMANT_HEURISTIC
@ -61,11 +55,6 @@ public:
virtual bool HasAudio() override;
virtual bool HasVideo() override;
// PreReadMetadata() is called by MediaDecoderStateMachine::DecodeMetadata()
// before checking hardware resource. In Gonk, it requests hardware codec so
// MediaDecoderStateMachine could go to DORMANT state if the hardware codec is
// not available.
virtual void PreReadMetadata() override;
virtual nsresult ReadMetadata(MediaInfo* aInfo,
MetadataTags** aTags) override;
@ -106,6 +95,8 @@ private:
bool EnsureDecodersSetup();
bool CheckIfDecoderSetup();
// Sends input to decoder for aTrack, and output to the state machine,
// if necessary.
void Update(TrackType aTrack);
@ -137,7 +128,6 @@ private:
bool IsSupportedAudioMimeType(const nsACString& aMimeType);
bool IsSupportedVideoMimeType(const nsACString& aMimeType);
void NotifyResourcesStatusChanged();
void RequestCodecResource();
virtual bool IsWaitingOnCDMResource() override;
Microseconds GetNextKeyframeTime();
@ -289,8 +279,6 @@ private:
// Synchronized by decoder monitor.
bool mIsEncrypted;
bool mAreDecodersSetup;
bool mIndexReady;
int64_t mLastSeenEnd;
Monitor mDemuxerMonitor;

View File

@ -256,11 +256,6 @@ public:
virtual bool IsWaitingMediaResources() {
return false;
};
virtual bool IsDormantNeeded() {
return false;
};
virtual void AllocateMediaResources() {}
virtual void ReleaseMediaResources() {}
virtual bool IsHardwareAccelerated() const { return false; }
// ConfigurationChanged will be called to inform the video or audio decoder

View File

@ -142,11 +142,6 @@ SharedDecoderManager::Select(SharedDecoderProxy* aProxy)
mActiveProxy = aProxy;
mActiveCallback = aProxy->mCallback;
if (mDecoderReleasedResources) {
mDecoder->AllocateMediaResources();
mDecoderReleasedResources = false;
}
}
void
@ -176,14 +171,6 @@ SharedDecoderManager::DrainComplete()
}
}
void
SharedDecoderManager::ReleaseMediaResources()
{
mDecoderReleasedResources = true;
mDecoder->ReleaseMediaResources();
mActiveProxy = nullptr;
}
void
SharedDecoderManager::Shutdown()
{
@ -262,20 +249,6 @@ SharedDecoderProxy::IsWaitingMediaResources()
return mManager->mActiveProxy != nullptr;
}
bool
SharedDecoderProxy::IsDormantNeeded()
{
return mManager->mDecoder->IsDormantNeeded();
}
void
SharedDecoderProxy::ReleaseMediaResources()
{
if (mManager->mActiveProxy == this) {
mManager->ReleaseMediaResources();
}
}
bool
SharedDecoderProxy::IsHardwareAccelerated() const
{

View File

@ -74,8 +74,6 @@ public:
virtual nsresult Drain() override;
virtual nsresult Shutdown() override;
virtual bool IsWaitingMediaResources() override;
virtual bool IsDormantNeeded() override;
virtual void ReleaseMediaResources() override;
virtual bool IsHardwareAccelerated() const override;
friend class SharedDecoderManager;

View File

@ -27,9 +27,6 @@ PRLogModuleInfo* GetAppleMediaLog() {
namespace mozilla {
// This defines the resolution height over which VDA will be prefered.
#define VDA_RESOLUTION_THRESHOLD 720
bool AppleDecoderModule::sInitialized = false;
bool AppleDecoderModule::sIsVTAvailable = false;
bool AppleDecoderModule::sIsVTHWAvailable = false;
@ -160,9 +157,7 @@ AppleDecoderModule::CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aC
{
nsRefPtr<MediaDataDecoder> decoder;
if (sIsVDAAvailable &&
(!sIsVTHWAvailable || sForceVDA ||
aConfig.image_height >= VDA_RESOLUTION_THRESHOLD)) {
if (sIsVDAAvailable && (!sIsVTHWAvailable || sForceVDA)) {
decoder =
AppleVDADecoder::CreateVDADecoder(aConfig,
aVideoTaskQueue,

View File

@ -73,10 +73,15 @@ GonkAudioDecoderManager::Init(MediaDataDecoderCallback* aCallback)
mLooper->setName("GonkAudioDecoderManager");
mLooper->start();
mDecoder = MediaCodecProxy::CreateByType(mLooper, "audio/mp4a-latm", false, false, nullptr);
mDecoder = MediaCodecProxy::CreateByType(mLooper, "audio/mp4a-latm", false, nullptr);
if (!mDecoder.get()) {
return nullptr;
}
if (!mDecoder->AskMediaCodecAndWait())
{
mDecoder = nullptr;
return nullptr;
}
sp<AMessage> format = new AMessage;
// Fixed values
GADM_LOG("Init Audio channel no:%d, sample-rate:%d", mAudioChannels, mAudioRate);

View File

@ -137,15 +137,23 @@ GonkMediaDataDecoder::~GonkMediaDataDecoder()
nsresult
GonkMediaDataDecoder::Init()
{
mDecoder = mManager->Init(mCallback);
sp<MediaCodecProxy> decoder;
decoder = mManager->Init(mCallback);
mDecoder = decoder;
mDrainComplete = false;
return mDecoder.get() ? NS_OK : NS_ERROR_UNEXPECTED;
return NS_OK;
}
nsresult
GonkMediaDataDecoder::Shutdown()
{
if (!mDecoder.get()) {
return NS_OK;
}
mDecoder->stop();
mDecoder->ReleaseMediaResources();
mDecoder = nullptr;
return NS_OK;
}
@ -256,19 +264,10 @@ GonkMediaDataDecoder::Drain()
bool
GonkMediaDataDecoder::IsWaitingMediaResources() {
return mDecoder->IsWaitingResources();
}
void
GonkMediaDataDecoder::AllocateMediaResources()
{
mManager->AllocateMediaResources();
}
void
GonkMediaDataDecoder::ReleaseMediaResources()
{
mManager->ReleaseMediaResources();
if (!mDecoder.get()) {
return true;
}
return false;
}
} // namespace mozilla

View File

@ -44,10 +44,6 @@ public:
// in the overrided function.
virtual nsresult Flush();
virtual void AllocateMediaResources() {}
virtual void ReleaseMediaResources() {}
// It should be called in MediaTash thread.
bool HasQueuedSample() {
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
@ -100,12 +96,6 @@ public:
virtual bool IsWaitingMediaResources() override;
virtual bool IsDormantNeeded() { return true;}
virtual void AllocateMediaResources() override;
virtual void ReleaseMediaResources() override;
private:
// Called on the task queue. Inserts the sample into the decoder, and

View File

@ -43,10 +43,6 @@ using namespace android;
typedef android::MediaCodecProxy MediaCodecProxy;
namespace mozilla {
enum {
kNotifyCodecReserved = 'core',
kNotifyCodecCanceled = 'coca',
};
GonkVideoDecoderManager::GonkVideoDecoderManager(
MediaTaskQueue* aTaskQueue,
@ -112,13 +108,17 @@ GonkVideoDecoderManager::Init(MediaDataDecoderCallback* aCallback)
if (mLooper->start() != OK || mManagerLooper->start() != OK ) {
return nullptr;
}
mDecoder = MediaCodecProxy::CreateByType(mLooper, "video/avc", false, true, mVideoListener);
mDecoder = MediaCodecProxy::CreateByType(mLooper, "video/avc", false, mVideoListener);
mDecoder->AskMediaCodecAndWait();
uint32_t capability = MediaCodecProxy::kEmptyCapability;
if (mDecoder->getCapability(&capability) == OK && (capability &
MediaCodecProxy::kCanExposeGraphicBuffer)) {
mNativeWindow = new GonkNativeWindow();
}
mReaderCallback->NotifyResourcesStatusChanged();
return mDecoder;
}
@ -488,15 +488,10 @@ GonkVideoDecoderManager::Flush()
return NS_OK;
}
void
GonkVideoDecoderManager::AllocateMediaResources()
{
mDecoder->RequestMediaResources();
}
void
GonkVideoDecoderManager::codecReserved()
{
GVDM_LOG("codecReserved");
sp<AMessage> format = new AMessage;
sp<Surface> surface;
@ -509,24 +504,12 @@ GonkVideoDecoderManager::codecReserved()
}
mDecoder->configure(format, surface, nullptr, 0);
mDecoder->Prepare();
if (mHandler != nullptr) {
// post kNotifyCodecReserved to Looper thread.
sp<AMessage> notify = new AMessage(kNotifyCodecReserved, mHandler->id());
notify->post();
}
}
void
GonkVideoDecoderManager::codecCanceled()
{
mDecoder = nullptr;
if (mHandler != nullptr) {
// post kNotifyCodecCanceled to Looper thread.
sp<AMessage> notify = new AMessage(kNotifyCodecCanceled, mHandler->id());
notify->post();
}
}
// Called on GonkVideoDecoderManager::mManagerLooper thread.
@ -534,21 +517,6 @@ void
GonkVideoDecoderManager::onMessageReceived(const sp<AMessage> &aMessage)
{
switch (aMessage->what()) {
case kNotifyCodecReserved:
{
// Our decode may have acquired the hardware resource that it needs
// to start. Notify the state machine to resume loading metadata.
GVDM_LOG("CodecReserved!");
mReaderCallback->NotifyResourcesStatusChanged();
break;
}
case kNotifyCodecCanceled:
{
mReaderCallback->ReleaseMediaResources();
break;
}
case kNotifyPostReleaseBuffer:
{
ReleaseAllPendingVideoBuffers();

View File

@ -51,8 +51,6 @@ public:
virtual nsresult Flush() override;
virtual void AllocateMediaResources();
virtual void ReleaseMediaResources();
static void RecycleCallback(TextureClient* aClient, void* aClosure);
@ -146,7 +144,6 @@ private:
android::sp<MediaCodecProxy> mDecoder;
nsRefPtr<layers::ImageContainer> mImageContainer;
MediaDataDecoderCallback* mCallback;
android::MediaBuffer* mVideoBuffer;
@ -179,7 +176,6 @@ private:
Vector<android::MediaBuffer*> mPendingVideoBuffers;
// The lock protects mPendingVideoBuffers.
Mutex mPendingVideoBuffersLock;
};
} // namespace mozilla

View File

@ -66,13 +66,6 @@ WMFMediaDataDecoder::ProcessShutdown()
mDecoder = nullptr;
}
void
WMFMediaDataDecoder::ProcessReleaseDecoder()
{
mMFTManager->Shutdown();
mDecoder = nullptr;
}
// Inserts data into the decoder's pipeline.
nsresult
WMFMediaDataDecoder::Input(MediaRawData* aSample)
@ -157,24 +150,6 @@ WMFMediaDataDecoder::Drain()
return NS_OK;
}
void
WMFMediaDataDecoder::AllocateMediaResources()
{
mDecoder = mMFTManager->Init();
}
void
WMFMediaDataDecoder::ReleaseMediaResources()
{
DebugOnly<nsresult> rv = mTaskQueue->FlushAndDispatch(
NS_NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessReleaseDecoder));
#ifdef DEBUG
if (NS_FAILED(rv)) {
NS_WARNING("WMFMediaDataDecoder::ReleaseMediaResources() dispatch of task failed!");
}
#endif
}
bool
WMFMediaDataDecoder::IsHardwareAccelerated() const {
return mMFTManager && mMFTManager->IsHardwareAccelerated();

View File

@ -70,9 +70,6 @@ public:
virtual nsresult Shutdown() override;
virtual bool IsWaitingMediaResources() { return false; };
virtual bool IsDormantNeeded() { return true; };
virtual void AllocateMediaResources() override;
virtual void ReleaseMediaResources() override;
virtual bool IsHardwareAccelerated() const override;
private:
@ -90,7 +87,6 @@ private:
void ProcessDrain();
void ProcessShutdown();
void ProcessReleaseDecoder();
RefPtr<FlushableMediaTaskQueue> mTaskQueue;
MediaDataDecoderCallback* mCallback;

View File

@ -122,40 +122,6 @@ H264Converter::IsWaitingMediaResources()
return MediaDataDecoder::IsWaitingMediaResources();
}
bool
H264Converter::IsDormantNeeded()
{
if (mNeedAVCC) {
return true;
}
return mDecoder ?
mDecoder->IsDormantNeeded() : MediaDataDecoder::IsDormantNeeded();
}
void
H264Converter::AllocateMediaResources()
{
if (mNeedAVCC) {
// Nothing to do, decoder will be allocated on the fly when required.
return;
}
if (mDecoder) {
mDecoder->AllocateMediaResources();
}
}
void
H264Converter::ReleaseMediaResources()
{
if (mNeedAVCC) {
Shutdown();
return;
}
if (mDecoder) {
mDecoder->ReleaseMediaResources();
}
}
bool
H264Converter::IsHardwareAccelerated() const
{
@ -219,7 +185,7 @@ H264Converter::CheckForSPSChange(MediaRawData* aSample)
// The SPS has changed, signal to flush the current decoder and create a
// new one.
mDecoder->Flush();
ReleaseMediaResources();
Shutdown();
return CreateDecoderAndInit(aSample);
}

View File

@ -35,9 +35,6 @@ public:
virtual nsresult Drain() override;
virtual nsresult Shutdown() override;
virtual bool IsWaitingMediaResources() override;
virtual bool IsDormantNeeded() override;
virtual void AllocateMediaResources() override;
virtual void ReleaseMediaResources() override;
virtual bool IsHardwareAccelerated() const override;
// Return true if mimetype is H.264.

View File

@ -78,42 +78,38 @@ sp<MediaCodecProxy>
MediaCodecProxy::CreateByType(sp<ALooper> aLooper,
const char *aMime,
bool aEncoder,
bool aAsync,
wp<CodecResourceListener> aListener)
{
sp<MediaCodecProxy> codec = new MediaCodecProxy(aLooper, aMime, aEncoder, aAsync, aListener);
if ((!aAsync && codec->allocated()) || codec->requestResource()) {
return codec;
}
return nullptr;
sp<MediaCodecProxy> codec = new MediaCodecProxy(aLooper,
aMime,
aEncoder,
aListener);
return codec;
}
MediaCodecProxy::MediaCodecProxy(sp<ALooper> aLooper,
const char *aMime,
bool aEncoder,
bool aAsync,
wp<CodecResourceListener> aListener)
: mCodecLooper(aLooper)
, mCodecMime(aMime)
, mCodecEncoder(aEncoder)
, mListener(aListener)
, mMediaCodecLock("MediaCodecProxy::mMediaCodecLock")
, mPendingRequestMediaResource(false)
{
MOZ_ASSERT(mCodecLooper != nullptr, "ALooper should not be nullptr.");
if (aAsync) {
mResourceHandler = new MediaResourceHandler(this);
} else {
allocateCodec();
}
mResourceHandler = new MediaResourceHandler(this);
}
MediaCodecProxy::~MediaCodecProxy()
{
releaseCodec();
cancelResource();
SetMediaCodecFree();
}
bool
MediaCodecProxy::requestResource()
MediaCodecProxy::AskMediaCodecAndWait()
{
if (mResourceHandler == nullptr) {
return false;
@ -124,30 +120,39 @@ MediaCodecProxy::requestResource()
? IMediaResourceManagerService::HW_VIDEO_ENCODER
: IMediaResourceManagerService::HW_VIDEO_DECODER);
} else if (strncasecmp(mCodecMime.get(), "audio/", 6) == 0) {
mResourceHandler->requestResource(mCodecEncoder
? IMediaResourceManagerService::HW_AUDIO_ENCODER
: IMediaResourceManagerService::HW_AUDIO_DECODER);
if (allocateCodec()) {
return true;
}
} else {
return false;
}
mozilla::MonitorAutoLock mon(mMediaCodecLock);
mPendingRequestMediaResource = true;
while (mPendingRequestMediaResource) {
mMediaCodecLock.Wait();
}
MCP_LOG("AskMediaCodecAndWait complete");
return true;
}
void
MediaCodecProxy::RequestMediaResources()
{
requestResource();
}
void
MediaCodecProxy::cancelResource()
MediaCodecProxy::SetMediaCodecFree()
{
if (mResourceHandler == nullptr) {
return;
}
mozilla::MonitorAutoLock mon(mMediaCodecLock);
if (mPendingRequestMediaResource) {
mPendingRequestMediaResource = false;
mon.NotifyAll();
}
mResourceHandler->cancelResource();
mResourceHandler = nullptr;
}
bool
@ -462,13 +467,19 @@ MediaCodecProxy::getCapability(uint32_t *aCapability)
void
MediaCodecProxy::resourceReserved()
{
MCP_LOG("resourceReserved");
// Create MediaCodec
releaseCodec();
if (!allocateCodec()) {
cancelResource();
SetMediaCodecFree();
return;
}
// Notify initialization waiting.
mozilla::MonitorAutoLock mon(mMediaCodecLock);
mPendingRequestMediaResource = false;
mon.NotifyAll();
// Notification
sp<CodecResourceListener> listener = mListener.promote();
if (listener != nullptr) {
@ -476,20 +487,6 @@ MediaCodecProxy::resourceReserved()
}
}
// Called on a Binder thread
void
MediaCodecProxy::resourceCanceled()
{
// Release MediaCodec
releaseCodec();
// Notification
sp<CodecResourceListener> listener = mListener.promote();
if (listener != nullptr) {
listener->codecCanceled();
}
}
bool MediaCodecProxy::Prepare()
{
@ -611,23 +608,10 @@ status_t MediaCodecProxy::Output(MediaBuffer** aBuffer, int64_t aTimeoutUs)
return err;
}
bool MediaCodecProxy::IsWaitingResources()
{
if (mResourceHandler.get()) {
return mResourceHandler->IsWaitingResource();
}
return false;
}
bool MediaCodecProxy::IsDormantNeeded()
{
return mCodecLooper.get() ? true : false;
}
void MediaCodecProxy::ReleaseMediaResources()
{
releaseCodec();
cancelResource();
SetMediaCodecFree();
}
void MediaCodecProxy::ReleaseMediaBuffer(MediaBuffer* aBuffer) {

View File

@ -12,6 +12,7 @@
#include <stagefright/MediaBuffer.h>
#include <utils/threads.h>
#include "MediaResourceHandler.h"
#include "mozilla/Monitor.h"
namespace android {
// This class is intended to be a proxy for MediaCodec with codec resource
@ -55,7 +56,6 @@ public:
static sp<MediaCodecProxy> CreateByType(sp<ALooper> aLooper,
const char *aMime,
bool aEncoder,
bool aAsync=false,
wp<CodecResourceListener> aListener=nullptr);
// MediaCodec methods
@ -129,22 +129,26 @@ public:
int64_t aTimestampUsecs, uint64_t flags);
status_t Output(MediaBuffer** aBuffer, int64_t aTimeoutUs);
bool Prepare();
bool IsWaitingResources();
bool IsDormantNeeded();
void RequestMediaResources();
void ReleaseMediaResources();
// This updates mOutputBuffer when receiving INFO_OUTPUT_BUFFERS_CHANGED event.
bool UpdateOutputBuffers();
void ReleaseMediaBuffer(MediaBuffer* abuffer);
// It asks for the OMX codec and blocked until the resource is grant to be
// allocated.
bool AskMediaCodecAndWait();
// Free the OMX codec so others can allocate it.
void SetMediaCodecFree();
protected:
virtual ~MediaCodecProxy();
// MediaResourceHandler::EventListener::resourceReserved()
virtual void resourceReserved();
// MediaResourceHandler::EventListener::resourceCanceled()
virtual void resourceCanceled();
virtual void resourceCanceled() {}
private:
// Forbidden
@ -156,14 +160,8 @@ private:
MediaCodecProxy(sp<ALooper> aLooper,
const char *aMime,
bool aEncoder,
bool aAsync,
wp<CodecResourceListener> aListener);
// Request Resource
bool requestResource();
// Cancel Resource
void cancelResource();
// Allocate Codec Resource
bool allocateCodec();
// Release Codec Resource
@ -188,6 +186,8 @@ private:
Vector<sp<ABuffer> > mInputBuffers;
Vector<sp<ABuffer> > mOutputBuffers;
mozilla::Monitor mMediaCodecLock;
bool mPendingRequestMediaResource;
};
} // namespace android

View File

@ -1322,7 +1322,7 @@ MediaCodecReader::CreateMediaCodec(sp<ALooper>& aLooper,
const char* mime;
if (sourceFormat->findCString(kKeyMIMEType, &mime)) {
aTrack.mCodec = MediaCodecProxy::CreateByType(aLooper, mime, false, aAsync, aListener);
aTrack.mCodec = MediaCodecProxy::CreateByType(aLooper, mime, false, aListener);
}
if (aTrack.mCodec == nullptr) {

View File

@ -221,8 +221,11 @@ MediaEngineGonkVideoSource::Start(SourceMediaStream* aStream, TrackID aID)
ReentrantMonitorAutoEnter sync(mCallbackMonitor);
MOZ_ASSERT(mCameraControl, "mCameraControl is nullptr");
if (mState == kStarted) {
return NS_OK;
} else if (!mCameraControl) {
return NS_ERROR_FAILURE;
}
mTrackID = aID;
mImageContainer = layers::LayerManager::CreateImageContainer();

View File

@ -77,7 +77,6 @@ DIRS += [
'notification',
'offline',
'power',
'push',
'quota',
'security',
'settings',
@ -137,6 +136,11 @@ if CONFIG['MOZ_GAMEPAD']:
if CONFIG['MOZ_NFC']:
DIRS += ['nfc']
if CONFIG['MOZ_SIMPLEPUSH']:
DIRS += ['simplepush']
else:
DIRS += ['push']
if CONFIG['MOZ_SECUREELEMENT']:
DIRS += ['secureelement']

View File

@ -4,8 +4,8 @@
"use strict";
// Don't modify this, instead set services.push.debug.
let gDebuggingEnabled = false;
// Don't modify this, instead set dom.push.debug.
let gDebuggingEnabled = true;
function debug(s) {
if (gDebuggingEnabled)
@ -21,6 +21,94 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
Cu.import("resource://gre/modules/AppsUtils.jsm");
const PUSH_SUBSCRIPTION_CID = Components.ID("{CA86B665-BEDA-4212-8D0F-5C9F65270B58}");
function PushSubscription(pushEndpoint, scope, pageURL) {
debug("PushSubscription Constructor");
this._pushEndpoint = pushEndpoint;
this._scope = scope;
this._pageURL = pageURL;
}
PushSubscription.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
contractID: "@mozilla.org/push/PushSubscription;1",
classID : PUSH_SUBSCRIPTION_CID,
QueryInterface : XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
Ci.nsISupportsWeakReference,
Ci.nsIObserver]),
init: function(aWindow) {
debug("PushSubscription init()");
this.initDOMRequestHelper(aWindow, [
"PushService:Unregister:OK",
"PushService:Unregister:KO",
]);
this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
.getService(Ci.nsISyncMessageSender);
},
__init: function(endpoint, scope, pageURL) {
this._pushEndpoint = endpoint;
this._scope = scope;
this._pageURL = pageURL;
},
get endpoint() {
return this._pushEndpoint;
},
get subscriptionId() {
// TODO bug 1149271. Not sure what this is about.
return "The twins of Mammon quarrelled.";
},
unsubscribe: function() {
debug("unsubscribe! ")
let promiseInit = function(resolve, reject) {
let resolverId = this.getPromiseResolverId({resolve: resolve,
reject: reject });
this._cpmm.sendAsyncMessage("Push:Unregister", {
pageURL: this._pageURL,
scope: this._scope,
pushEndpoint: this._pushEndpoint,
requestID: resolverId
});
}.bind(this);
return this.createPromise(promiseInit);
},
receiveMessage: function(aMessage) {
debug("push subscription receiveMessage(): " + JSON.stringify(aMessage))
let json = aMessage.data;
let resolver = this.takePromiseResolver(json.requestID);
if (resolver == null) {
return;
}
switch (aMessage.name) {
case "PushService:Unregister:OK":
resolver.resolve(false);
break;
case "PushService:Unregister:KO":
resolver.reject(true);
break;
default:
debug("NOT IMPLEMENTED! receiveMessage for " + aMessage.name);
}
},
};
const PUSH_CID = Components.ID("{cde1d019-fad8-4044-b141-65fb4fb7a245}");
/**
@ -47,101 +135,186 @@ Push.prototype = {
// Set debug first so that all debugging actually works.
// NOTE: We don't add an observer here like in PushService. Flipping the
// pref will require a reload of the app/page, which seems acceptable.
gDebuggingEnabled = Services.prefs.getBoolPref("services.push.debug");
gDebuggingEnabled = Services.prefs.getBoolPref("dom.push.debug");
debug("init()");
let principal = aWindow.document.nodePrincipal;
let appsService = Cc["@mozilla.org/AppsService;1"]
.getService(Ci.nsIAppsService);
this._manifestURL = appsService.getManifestURLByLocalId(principal.appId);
this._pageURL = principal.URI;
this._pageURL = aWindow.document.nodePrincipal.URI;
this._window = aWindow;
this.initDOMRequestHelper(aWindow, [
"PushService:Register:OK",
"PushService:Register:KO",
"PushService:Unregister:OK",
"PushService:Unregister:KO",
"PushService:Registrations:OK",
"PushService:Registrations:KO"
"PushService:Registration:OK",
"PushService:Registration:KO"
]);
this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
.getService(Ci.nsISyncMessageSender);
},
setScope: function(scope){
debug('setScope ' + scope);
this._scope = scope;
},
askPermission: function (aAllowCallback, aCancelCallback) {
debug("askPermission");
let principal = this._window.document.nodePrincipal;
let type = "push";
let permValue =
Services.perms.testExactPermissionFromPrincipal(principal, type);
debug("Existing permission " + permValue);
if (permValue == Ci.nsIPermissionManager.ALLOW_ACTION) {
aAllowCallback();
return;
}
if (permValue == Ci.nsIPermissionManager.DENY_ACTION) {
aCancelCallback();
return;
}
// Create an array with a single nsIContentPermissionType element.
type = {
type: "push",
access: null,
options: [],
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionType])
};
let typeArray = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
typeArray.appendElement(type, false);
// create a nsIContentPermissionRequest
let request = {
types: typeArray,
principal: principal,
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionRequest]),
allow: function() {
aAllowCallback();
},
cancel: function() {
aCancelCallback();
},
window: this._window
};
debug("asking the window utils about permission...")
// Using askPermission from nsIDOMWindowUtils that takes care of the
// remoting if needed.
let windowUtils = this._window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
windowUtils.askPermission(request);
},
receiveMessage: function(aMessage) {
debug("receiveMessage()");
let request = this.getRequest(aMessage.data.requestID);
debug("push receiveMessage(): " + JSON.stringify(aMessage))
let json = aMessage.data;
if (!request) {
debug("No request " + json.requestID);
let resolver = this.takePromiseResolver(json.requestID);
if (!resolver) {
return;
}
switch (aMessage.name) {
case "PushService:Register:OK":
Services.DOMRequest.fireSuccess(request, json.pushEndpoint);
{
let subscription = new this._window.PushSubscription(json.pushEndpoint,
this._scope,
this._pageURL.spec);
resolver.resolve(subscription);
break;
}
case "PushService:Register:KO":
Services.DOMRequest.fireError(request, json.error);
resolver.reject(null);
break;
case "PushService:Unregister:OK":
Services.DOMRequest.fireSuccess(request, json.pushEndpoint);
case "PushService:Registration:OK":
{
let subscription = null;
try {
subscription = new this._window.PushSubscription(json.registration.pushEndpoint,
this._scope, this._pageURL.spec);
} catch(error) {
}
resolver.resolve(subscription);
break;
case "PushService:Unregister:KO":
Services.DOMRequest.fireError(request, json.error);
break;
case "PushService:Registrations:OK":
Services.DOMRequest.fireSuccess(request, json.registrations);
break;
case "PushService:Registrations:KO":
Services.DOMRequest.fireError(request, json.error);
}
case "PushService:Registration:KO":
resolver.reject(null);
break;
default:
debug("NOT IMPLEMENTED! receiveMessage for " + aMessage.name);
}
},
register: function() {
debug("register()");
let req = this.createRequest();
if (!Services.prefs.getBoolPref("services.push.connection.enabled")) {
// If push socket is disabled by the user, immediately error rather than
// timing out.
Services.DOMRequest.fireErrorAsync(req, "NetworkError");
return req;
}
subscribe: function() {
debug("subscribe()");
let p = this.createPromise(function(resolve, reject) {
let resolverId = this.getPromiseResolverId({ resolve: resolve, reject: reject });
this._cpmm.sendAsyncMessage("Push:Register", {
pageURL: this._pageURL.spec,
manifestURL: this._manifestURL,
requestID: this.getRequestId(req)
});
return req;
this.askPermission(
function() {
this._cpmm.sendAsyncMessage("Push:Register", {
pageURL: this._pageURL.spec,
scope: this._scope,
requestID: resolverId
});
}.bind(this),
function() {
reject("denied");
}
);
}.bind(this));
return p;
},
unregister: function(aPushEndpoint) {
debug("unregister(" + aPushEndpoint + ")");
let req = this.createRequest();
this._cpmm.sendAsyncMessage("Push:Unregister", {
pageURL: this._pageURL.spec,
manifestURL: this._manifestURL,
requestID: this.getRequestId(req),
pushEndpoint: aPushEndpoint
});
return req;
getSubscription: function() {
debug("getSubscription()" + this._scope);
let p = this.createPromise(function(resolve, reject) {
let resolverId = this.getPromiseResolverId({ resolve: resolve, reject: reject });
this.askPermission(
function() {
this._cpmm.sendAsyncMessage("Push:Registration", {
pageURL: this._pageURL.spec,
scope: this._scope,
requestID: resolverId
});
}.bind(this),
function() {
reject("denied");
}
);
}.bind(this));
return p;
},
registrations: function() {
debug("registrations()");
let req = this.createRequest();
this._cpmm.sendAsyncMessage("Push:Registrations", {
manifestURL: this._manifestURL,
requestID: this.getRequestId(req)
});
return req;
}
hasPermission: function() {
debug("getSubscription()" + this._scope);
let p = this.createPromise(function(resolve, reject) {
let permissionManager = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);
let permission = permissionManager.testExactPermission(this._pageURL, "push");
let pushPermissionStatus = "default";
if (permission == Ci.nsIPermissionManager.ALLOW_ACTION) {
pushPermissionStatus = "granted";
} else if (permission == Ci.nsIPermissionManager.DENY_ACTION) {
pushPermissionStatus = "denied";
}
resolve(pushPermissionStatus);
}.bind(this));
return p;
},
}
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Push]);
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Push, PushSubscription]);

View File

@ -2,6 +2,9 @@
component {cde1d019-fad8-4044-b141-65fb4fb7a245} Push.js
contract @mozilla.org/push/PushManager;1 {cde1d019-fad8-4044-b141-65fb4fb7a245}
component {CA86B665-BEDA-4212-8D0F-5C9F65270B58} Push.js
contract @mozilla.org/push/PushSubscription;1 {CA86B665-BEDA-4212-8D0F-5C9F65270B58}
# Component to initialize PushService on startup.
component {4b8caa3b-3c58-4f3c-a7f5-7bd9cb24c11d} PushServiceLauncher.js
contract @mozilla.org/push/ServiceLauncher;1 {4b8caa3b-3c58-4f3c-a7f5-7bd9cb24c11d}

View File

@ -5,8 +5,8 @@
"use strict";
// Don't modify this, instead set services.push.debug.
let gDebuggingEnabled = false;
// Don't modify this, instead set dom.push.debug.
let gDebuggingEnabled = true;
function debug(s) {
if (gDebuggingEnabled)
@ -41,7 +41,7 @@ var threadManager = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadM
this.EXPORTED_SYMBOLS = ["PushService"];
const prefs = new Preferences("services.push.");
const prefs = new Preferences("dom.push.");
// Set debug first so that all debugging actually works.
gDebuggingEnabled = prefs.get("debug");
@ -54,7 +54,7 @@ const kUDP_WAKEUP_WS_STATUS_CODE = 4774; // WebSocket Close status code sent
// wake client up using UDP.
const kCHILD_PROCESS_MESSAGES = ["Push:Register", "Push:Unregister",
"Push:Registrations"];
"Push:Registration"];
const kWS_MAX_WENTDOWN = 2;
@ -79,10 +79,9 @@ this.PushDB.prototype = {
// index to fetch records based on endpoints. used by unregister
objectStore.createIndex("pushEndpoint", "pushEndpoint", { unique: true });
// index to fetch records per manifest, so we can identify endpoints
// associated with an app. Since an app can have multiple endpoints
// uniqueness cannot be enforced
objectStore.createIndex("manifestURL", "manifestURL", { unique: false });
// index to fetch records per scope, so we can identify endpoints
// associated with an app.
objectStore.createIndex("scope", "scope", { unique: true });
},
/*
@ -94,7 +93,7 @@ this.PushDB.prototype = {
* Callback function to invoke when there was an error.
*/
put: function(aChannelRecord, aSuccessCb, aErrorCb) {
debug("put()");
debug("put()" + JSON.stringify(aChannelRecord));
this.newTxn(
"readwrite",
@ -173,30 +172,20 @@ this.PushDB.prototype = {
);
},
getAllByManifestURL: function(aManifestURL, aSuccessCb, aErrorCb) {
debug("getAllByManifestURL()");
if (!aManifestURL) {
if (typeof aErrorCb == "function") {
aErrorCb("PushDB.getAllByManifestURL: Got undefined aManifestURL");
}
return;
}
let self = this;
getByScope: function(aScope, aSuccessCb, aErrorCb) {
debug("getByScope() " + aScope);
this.newTxn(
"readonly",
kPUSHDB_STORE_NAME,
function txnCb(aTxn, aStore) {
let index = aStore.index("manifestURL");
let range = IDBKeyRange.only(aManifestURL);
aTxn.result = [];
index.openCursor(range).onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
debug(cursor.value.manifestURL + " " + cursor.value.channelID);
aTxn.result.push(cursor.value);
cursor.continue();
}
aTxn.result = undefined;
let index = aStore.index("scope");
index.get(aScope).onsuccess = function setTxnResult(aEvent) {
aTxn.result = aEvent.target.result;
debug("Fetch successful " + aEvent.target.result);
}
},
aSuccessCb,
@ -325,17 +314,17 @@ this.PushService = {
}
break;
case "nsPref:changed":
if (aData == "services.push.serverURL") {
debug("services.push.serverURL changed! websocket. new value " +
if (aData == "dom.push.serverURL") {
debug("dom.push.serverURL changed! websocket. new value " +
prefs.get("serverURL"));
this._shutdownWS();
} else if (aData == "services.push.connection.enabled") {
} else if (aData == "dom.push.connection.enabled") {
if (prefs.get("connection.enabled")) {
this._startListeningIfChannelsPresent();
} else {
this._shutdownWS();
}
} else if (aData == "services.push.debug") {
} else if (aData == "dom.push.debug") {
gDebuggingEnabled = prefs.get("debug");
}
break;
@ -382,35 +371,30 @@ this.PushService = {
return;
}
// Only remove push registrations for apps.
if (data.browserOnly) {
return;
}
// TODO 1149274. We should support site permissions as well as a way to go from manifest
// url to 'all scopes registered for push in this app'
let appsService = Cc["@mozilla.org/AppsService;1"]
.getService(Ci.nsIAppsService);
let manifestURL = appsService.getManifestURLByLocalId(data.appId);
if (!manifestURL) {
debug("webapps-clear-data: No manifest URL found for " + data.appId);
let scope = appsService.getScopeByLocalId(data.appId);
if (!scope) {
debug("webapps-clear-data: No scope found for " + data.appId);
return;
}
this._db.getAllByManifestURL(manifestURL, function(records) {
debug("Got " + records.length);
for (let i = 0; i < records.length; i++) {
this._db.delete(records[i].channelID, null, function() {
debug("webapps-clear-data: " + manifestURL +
" Could not delete entry " + records[i].channelID);
});
this._db.getByScope(scope, function(record) {
this._db.delete(records.channelID, null, function() {
debug("webapps-clear-data: " + scope +
" Could not delete entry " + records.channelID);
// courtesy, but don't establish a connection
// just for it
if (this._ws) {
debug("Had a connection, so telling the server");
this._send("unregister", {channelID: records[i].channelID});
this._send("unregister", {channelID: records.channelID});
}
}
}.bind(this), function() {
debug("webapps-clear-data: Error in getAllByManifestURL(" + manifestURL + ")");
}.bind(this), function() {
debug("webapps-clear-data: Error in getByScope(" + scope + ")");
});
});
break;
@ -465,7 +449,7 @@ this.PushService = {
* 1) the gap between the maximum working ping and the first ping that
* gives an error (timeout) OR
* 2) we have reached the pref of the maximum value we allow for a ping
* (services.push.adaptive.upperLimit)
* (dom.push.adaptive.upperLimit)
*/
_recalculatePing: true,
@ -512,6 +496,11 @@ this.PushService = {
if (!prefs.get("enabled"))
return null;
var globalMM = Cc["@mozilla.org/globalmessagemanager;1"]
.getService(Ci.nsIFrameScriptLoader);
globalMM.loadFrameScript("chrome://global/content/PushServiceChildPreload.js", true);
this._db = new PushDB();
let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
@ -672,7 +661,7 @@ this.PushService = {
* This algorithm tries to search the best value between a disconnection and a
* valid ping, to ensure better battery life and network resources usage.
*
* The value is saved in services.push.pingInterval
* The value is saved in dom.push.pingInterval
* @param wsWentDown [Boolean] if the WebSocket was closed or it is still alive
*
*/
@ -842,7 +831,7 @@ this.PushService = {
let serverURL = prefs.get("serverURL");
if (!serverURL) {
debug("No services.push.serverURL found!");
debug("No dom.push.serverURL found!");
return;
}
@ -850,7 +839,7 @@ this.PushService = {
try {
uri = Services.io.newURI(serverURL, null, null);
} catch(e) {
debug("Error creating valid URI from services.push.serverURL (" +
debug("Error creating valid URI from dom.push.serverURL (" +
serverURL + ")");
return;
}
@ -1090,7 +1079,7 @@ this.PushService = {
debug("got new UAID: all re-register");
this._notifyAllAppsRegister()
.then(this._dropRegistrations.bind(this))
.then(this._dropRegistration.bind(this))
.then(finishHandshake.bind(this));
return;
@ -1279,35 +1268,32 @@ this.PushService = {
},
// Fires a push-register system message to all applications that have
// registrations.
// registration.
_notifyAllAppsRegister: function() {
debug("notifyAllAppsRegister()");
let deferred = Promise.defer();
// records are objects describing the registrations as stored in IndexedDB.
// records are objects describing the registration as stored in IndexedDB.
function wakeupRegisteredApps(records) {
// Pages to be notified.
// wakeupTable[manifestURL] -> [ pageURL ]
// wakeupTable[scope] -> [ pageURL ]
let wakeupTable = {};
for (let i = 0; i < records.length; i++) {
let record = records[i];
if (!(record.manifestURL in wakeupTable))
wakeupTable[record.manifestURL] = [];
if (!(record.scope in wakeupTable))
wakeupTable[record.scope] = [];
wakeupTable[record.manifestURL].push(record.pageURL);
wakeupTable[record.scope].push(record.pageURL);
}
let messenger = Cc["@mozilla.org/system-message-internal;1"]
.getService(Ci.nsISystemMessagesInternal);
// TODO -- test needed. E10s support needed.
for (let manifestURL in wakeupTable) {
wakeupTable[manifestURL].forEach(function(pageURL) {
messenger.sendMessage('push-register', {},
Services.io.newURI(pageURL, null, null),
Services.io.newURI(manifestURL, null, null));
let globalMM = Cc['@mozilla.org/globalmessagemanager;1'].getService(Ci.nsIMessageListenerManager);
for (let scope in wakeupTable) {
wakeupTable[scope].forEach(function(pageURL) {
globalMM.broadcastAsyncMessage('pushsubscriptionchanged', aPushRecord.scope);
});
}
deferred.resolve();
}
@ -1317,22 +1303,36 @@ this.PushService = {
},
_notifyApp: function(aPushRecord) {
if (!aPushRecord || !aPushRecord.pageURL || !aPushRecord.manifestURL) {
debug("notifyApp() something is undefined. Dropping notification");
if (!aPushRecord || !aPushRecord.pageURL || !aPushRecord.scope) {
debug("notifyApp() something is undefined. Dropping notification: "
+ JSON.stringify(aPushRecord) );
return;
}
debug("notifyApp() " + aPushRecord.pageURL +
" " + aPushRecord.manifestURL);
" " + aPushRecord.scope);
let pageURI = Services.io.newURI(aPushRecord.pageURL, null, null);
let manifestURI = Services.io.newURI(aPushRecord.manifestURL, null, null);
let scopeURI = Services.io.newURI(aPushRecord.scope, null, null);
let message = {
pushEndpoint: aPushRecord.pushEndpoint,
version: aPushRecord.version
};
let messenger = Cc["@mozilla.org/system-message-internal;1"]
.getService(Ci.nsISystemMessagesInternal);
messenger.sendMessage('push', message, pageURI, manifestURI);
// If permission has been revoked, trash the message.
if(Services.perms.testExactPermission(scopeURI, "push") != Ci.nsIPermissionManager.ALLOW_ACTION) {
debug("Does not have permission for push.")
return;
}
// TODO data.
let data = {
payload: "Short as life is, we make it still shorter by the careless waste of time.",
scope: aPushRecord.scope
};
let globalMM = Cc['@mozilla.org/globalmessagemanager;1']
.getService(Ci.nsIMessageListenerManager);
globalMM.broadcastAsyncMessage('push', data);
},
_updatePushRecord: function(aPushRecord) {
@ -1342,7 +1342,7 @@ this.PushService = {
return deferred.promise;
},
_dropRegistrations: function() {
_dropRegistration: function() {
let deferred = Promise.defer();
this._db.drop(deferred.resolve, deferred.reject);
return deferred.promise;
@ -1365,9 +1365,8 @@ this.PushService = {
* Called on message from the child process. aPageRecord is an object sent by
* navigator.push, identifying the sending page and other fields.
*/
register: function(aPageRecord, aMessageManager) {
debug("register()");
_registerWithServer: function(aPageRecord, aMessageManager) {
let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
.getService(Ci.nsIUUIDGenerator);
// generateUUID() gives a UUID surrounded by {...}, slice them off.
@ -1384,7 +1383,26 @@ this.PushService = {
},
function(message) {
aMessageManager.sendAsyncMessage("PushService:Register:KO", message);
});
}
);
},
register: function(aPageRecord, aMessageManager) {
debug("register(): " + JSON.stringify(aPageRecord));
this._db.getByScope(aPageRecord.scope,
function(aPageRecord, aMessageManager, pushRecord) {
if (pushRecord == null) {
this._registerWithServer(aPageRecord, aMessageManager);
}
else {
this._onRegistrationSuccess(aPageRecord, aMessageManager, pushRecord);
}
}.bind(this, aPageRecord, aMessageManager),
function () {
debug("getByScope failed");
}
);
},
/**
@ -1421,10 +1439,12 @@ this.PushService = {
channelID: data.channelID,
pushEndpoint: data.pushEndpoint,
pageURL: aPageRecord.pageURL,
manifestURL: aPageRecord.manifestURL,
scope: aPageRecord.scope,
version: null
};
debug("scope in _onRegisterSuccess: " + aPageRecord.scope)
this._updatePushRecord(record)
.then(
function() {
@ -1436,7 +1456,7 @@ this.PushService = {
this._send("unregister", {channelID: record.channelID});
message["error"] = error;
deferred.reject(message);
}
}.bind(this)
);
return deferred.promise;
@ -1479,7 +1499,7 @@ this.PushService = {
* data is cheap, reliable notification is not.
*/
unregister: function(aPageRecord, aMessageManager) {
debug("unregister()");
debug("unregister() " + JSON.stringify(aPageRecord));
let fail = function(error) {
debug("unregister() fail() error " + error);
@ -1495,7 +1515,7 @@ this.PushService = {
}
// Non-owner tried to unregister, say success, but don't do anything.
if (record.manifestURL !== aPageRecord.manifestURL) {
if (record.scope !== aPageRecord.scope) {
aMessageManager.sendAsyncMessage("PushService:Unregister:OK", {
requestID: aPageRecord.requestID,
pushEndpoint: aPageRecord.pushEndpoint
@ -1518,38 +1538,35 @@ this.PushService = {
/**
* Called on message from the child process
*/
registrations: function(aPageRecord, aMessageManager) {
debug("registrations()");
if (aPageRecord.manifestURL) {
this._db.getAllByManifestURL(aPageRecord.manifestURL,
this._onRegistrationsSuccess.bind(this, aPageRecord, aMessageManager),
this._onRegistrationsError.bind(this, aPageRecord, aMessageManager));
}
else {
this._onRegistrationsError(aPageRecord, aMessageManager);
}
registration: function(aPageRecord, aMessageManager) {
debug("registration()");
this._db.getByScope(aPageRecord.scope,
this._onRegistrationSuccess.bind(this, aPageRecord, aMessageManager),
this._onRegistrationError.bind(this, aPageRecord, aMessageManager));
},
_onRegistrationsSuccess: function(aPageRecord,
aMessageManager,
pushRecords) {
let registrations = [];
pushRecords.forEach(function(pushRecord) {
registrations.push({
__exposedProps__: { pushEndpoint: 'r', version: 'r' },
pushEndpoint: pushRecord.pushEndpoint,
version: pushRecord.version
});
});
aMessageManager.sendAsyncMessage("PushService:Registrations:OK", {
_onRegistrationSuccess: function(aPageRecord,
aMessageManager,
pushRecord) {
let registration = null;
if (pushRecord) {
registration = {
pushEndpoint: pushRecord.pushEndpoint,
version: pushRecord.version
};
}
aMessageManager.sendAsyncMessage("PushService:Registration:OK", {
requestID: aPageRecord.requestID,
registrations: registrations
registration: registration
});
},
_onRegistrationsError: function(aPageRecord, aMessageManager) {
aMessageManager.sendAsyncMessage("PushService:Registrations:KO", {
_onRegistrationError: function(aPageRecord, aMessageManager) {
aMessageManager.sendAsyncMessage("PushService:Registration:KO", {
requestID: aPageRecord.requestID,
error: "Database error"
});
@ -1733,7 +1750,7 @@ this.PushService = {
this._udpServer = Cc["@mozilla.org/network/udp-socket;1"]
.createInstance(Ci.nsIUDPSocket);
this._udpServer.init(-1, false, Services.scriptSecurityManager.getSystemPrincipal());
this._udpServer.init(-1, false);
this._udpServer.asyncListen(this);
debug("listenForUDPWakeup listening on " + this._udpServer.port);

View File

@ -0,0 +1,18 @@
/* 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/. */
"use strict";
XPCOMUtils.defineLazyServiceGetter(this,
"swm",
"@mozilla.org/serviceworkers/manager;1",
"nsIServiceWorkerManager");
addMessageListener("push", function (aMessage) {
swm.sendPushEvent(aMessage.data.scope, aMessage.data.payload);
});
addMessageListener("pushsubscriptionchanged", function (aMessage) {
swm.sendPushSubscriptionChangedEvent(aMessage.data);
});

View File

@ -30,11 +30,18 @@ PushServiceLauncher.prototype = {
break;
case "final-ui-startup":
Services.obs.removeObserver(this, "final-ui-startup");
if (!Services.prefs.getBoolPref("services.push.enabled")) {
if (!Services.prefs.getBoolPref("dom.push.enabled")) {
return;
}
Cu.import("resource://gre/modules/PushService.jsm");
PushService.init();
let isParent = Cc["@mozilla.org/xre/runtime;1"]
.getService(Ci.nsIXULRuntime)
.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
if (isParent) {
Cu.import("resource://gre/modules/PushService.jsm");
PushService.init();
}
break;
}
}

View File

@ -12,3 +12,7 @@ EXTRA_COMPONENTS += [
EXTRA_JS_MODULES += [
'PushService.jsm',
]
MOCHITEST_MANIFESTS += [
'test/mochitest.ini',
]

27
dom/push/test/frame.html Normal file
View File

@ -0,0 +1,27 @@
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<script>
function waitOnPushMessage(pushSubscription)
{
var p = new Promise(function(res, rej) {
navigator.serviceWorker.onmessage = function(e) {
if (e.data.type == "finished") {
parent.ok(e.data.okay == "yes", "Got a push message.");
res(pushSubscription);
}
};
});
return p;
}
</script>
</head>
<body>
</body>
</html>

View File

@ -0,0 +1,15 @@
[DEFAULT]
subsuite = push
support-files =
worker.js
push-server.sjs
frame.html
[test_has_permissions.html]
skip-if = os == "android" || toolkit == "gonk"
[test_permissions.html]
skip-if = os == "android" || toolkit == "gonk"
[test_register.html]
skip-if = os == "android" || toolkit == "gonk"
[test_multiple_register.html]
skip-if = os == "android" || toolkit == "gonk"

View File

@ -0,0 +1,26 @@
function debug(str) {
// dump("@@@ push-server " + str + "\n");
}
function handleRequest(request, response)
{
debug("handling request!");
const Cc = Components.classes;
const Ci = Components.interfaces;
let params = request.getHeader("X-Push-Server");
debug("params = " + params);
let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
xhr.open("PUT", params);
xhr.send();
xhr.onload = function(e) {
debug("xhr : " + this.status);
}
xhr.onerror = function(e) {
debug("xhr error: " + e);
}
response.setStatusLine(request.httpVersion, "200", "OK");
}

View File

@ -0,0 +1,76 @@
<!DOCTYPE HTML>
<html>
<!--
Bug 1038811: Push tests.
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
-->
<head>
<title>Test for Bug 1038811</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
</head>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1038811">Mozilla Bug 1038811</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
<script class="testbody" type="text/javascript">
function debug(str) {
// console.log(str + "\n");
}
function start() {
return navigator.serviceWorker.register("worker.js" + "?" + (Math.random()), {scope: "."})
.then((swr) => registration = swr);
}
function unregister() {
return registration.unregister().then(function(result) {
ok(result, "Unregister should return true.");
});
}
function hasPermission(swr) {
var p = new Promise(function(res, rej) {
swr.pushManager.hasPermission().then(
function(status) {
debug("status: " + status);
ok(true, "hasPermission() returned a status");
res(swr);
}, function(error) {
ok(false, "hasPermission failed.");
res(swr);
}
);
});
return p;
}
function runTest() {
start()
.then(hasPermission)
.then(unregister)
.catch(function(e) {
ok(false, "Some test failed with error " + e);
}).then(SimpleTest.finish);
}
SpecialPowers.addPermission('push', false, document);
SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true]
]}, runTest);
SimpleTest.waitForExplicitFinish();
</script>
</body>
</html>

View File

@ -0,0 +1,128 @@
<!DOCTYPE HTML>
<html>
<!--
Bug 1038811: Push tests.
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
-->
<head>
<title>Test for Bug 1038811</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
</head>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1038811">Mozilla Bug 1038811</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
<script class="testbody" type="text/javascript">
function debug(str) {
// console.log(str + "\n");
}
function start() {
return navigator.serviceWorker.register("worker.js" + "?" + (Math.random()), {scope: "."})
.then((swr) => registration = swr);
}
function unregister() {
return registration.unregister().then(function(result) {
ok(result, "Unregister should return true.");
});
}
function setupPushNotification(swr) {
var p = new Promise(function(res, rej) {
swr.pushManager.subscribe().then(
function(pushSubscription) {
ok(true, "successful registered for push notification");
res({swr: swr, pushSubscription: pushSubscription});
}, function(error) {
ok(false, "could not register for push notification");
res(null);
}
);
});
return p;
}
function setupSecondEndpoint(result) {
var p = new Promise(function(res, rej) {
result.swr.pushManager.subscribe().then(
function(pushSubscription) {
ok(result.pushSubscription.endpoint == pushSubscription.endpoint, "setupSecondEndpoint - Got the same endpoint back.");
res(result);
}, function(error) {
ok(false, "could not register for push notification");
res(null);
}
);
});
return p;
}
function getEndpointExpectNull(swr) {
var p = new Promise(function(res, rej) {
swr.pushManager.getSubscription().then(
function(pushSubscription) {
ok(pushSubscription == null, "getEndpoint should return null when app not subscribed.");
res(swr);
}, function(error) {
ok(false, "could not register for push notification");
res(null);
}
);
});
return p;
}
function getEndpoint(result) {
var p = new Promise(function(res, rej) {
result.swr.pushManager.getSubscription().then(
function(pushSubscription) {
ok(result.pushSubscription.endpoint == pushSubscription.endpoint, "getEndpoint - Got the same endpoint back.");
res(pushSubscription);
}, function(error) {
ok(false, "could not register for push notification");
res(null);
}
);
});
return p;
}
function unregisterPushNotification(pushSubscription) {
return pushSubscription.unsubscribe();
}
function runTest() {
start()
.then(getEndpointExpectNull)
.then(setupPushNotification)
.then(setupSecondEndpoint)
.then(getEndpoint)
.then(unregisterPushNotification)
.then(unregister)
.catch(function(e) {
ok(false, "Some test failed with error " + e);
}).then(SimpleTest.finish);
}
SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true]
]}, runTest);
SpecialPowers.addPermission('push', true, document);
SimpleTest.waitForExplicitFinish();
</script>
</body>
</html>

View File

@ -0,0 +1,91 @@
<!DOCTYPE HTML>
<html>
<!--
Bug 1038811: Push tests.
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
-->
<head>
<title>Test for Bug 1038811</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
</head>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1038811">Mozilla Bug 1038811</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
<script class="testbody" type="text/javascript">
function debug(str) {
// console.log(str + "\n");
}
function start() {
return navigator.serviceWorker.register("worker.js" + "?" + (Math.random()), {scope: "."})
.then((swr) => registration = swr);
}
function unregister() {
return registration.unregister().then(function(result) {
ok(result, "Unregister should return true.");
});
}
function setupPushNotification(swr) {
var p = new Promise(function(res, rej) {
swr.pushManager.subscribe().then(
function(pushSubscription) {
ok(false, "subscribe() should fail because no permission for push");
res(swr);
}, function(error) {
ok(true, "subscribe() could not register for push notification");
res(swr);
}
);
});
return p;
}
function getEndpoint(swr) {
var p = new Promise(function(res, rej) {
swr.pushManager.getSubscription().then(
function(pushSubscription) {
ok(false, "getSubscription() should fail because no permission for push");
res(swr);
}, function(error) {
ok(true, "getSubscription() could not register for push notification");
res(swr);
}
);
});
return p;
}
function runTest() {
start()
.then(setupPushNotification)
.then(getEndpoint)
.then(unregister)
.catch(function(e) {
ok(false, "Some test failed with error " + e);
}).then(SimpleTest.finish);
}
SpecialPowers.addPermission('push', false, document);
SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true]
]}, runTest);
SimpleTest.waitForExplicitFinish();
</script>
</body>
</html>

View File

@ -0,0 +1,123 @@
<!DOCTYPE HTML>
<html>
<!--
Bug 1038811: Push tests.
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
-->
<head>
<title>Test for Bug 1038811</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
</head>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1038811">Mozilla Bug 1038811</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
<script class="testbody" type="text/javascript">
function debug(str) {
// console.log(str + "\n");
}
var controlledFrame;
function createControlledIFrame(swr) {
var p = new Promise(function(res, rej) {
var iframe = document.createElement('iframe');
iframe.id = "controlledFrame";
iframe.src = "http://mochi.test:8888/tests/dom/push/test/frame.html";
iframe.onload = function() {
res(swr)
}
controlledFrame = iframe;
document.body.appendChild(iframe);
});
return p;
}
function sendPushToPushServer(pushEndpoint) {
// Work around CORS for now.
var xhr = new XMLHttpRequest();
xhr.open('GET', "http://mochi.test:8888/tests/dom/push/test/push-server.sjs", true);
xhr.setRequestHeader("X-Push-Server", pushEndpoint);
xhr.onload = function(e) {
debug("xhr : " + this.status);
}
xhr.onerror = function(e) {
debug("xhr error: " + e);
}
xhr.send("version=24601");
}
var registration;
function start() {
return navigator.serviceWorker.register("worker.js" + "?" + (Math.random()), {scope: "."})
.then((swr) => registration = swr);
}
function unregister() {
return registration.unregister().then(function(result) {
ok(result, "Unregister should return true.");
});
}
function setupPushNotification(swr) {
var p = new Promise(function(res, rej) {
swr.pushManager.subscribe().then(
function(pushSubscription) {
ok(true, "successful registered for push notification");
res(pushSubscription);
}, function(error) {
ok(false, "could not register for push notification");
res(null);
}
);
});
return p;
}
function unregisterPushNotification(pushSubscription) {
controlledFrame.parentNode.removeChild(controlledFrame);
controlledFrame = null;
return pushSubscription.unsubscribe();
}
function waitForPushNotification(pushSubscription) {
var p = controlledFrame.contentWindow.waitOnPushMessage();
sendPushToPushServer(pushSubscription.endpoint);
return p.then(function() {
return pushSubscription;
});
}
function runTest() {
start()
.then(createControlledIFrame)
.then(setupPushNotification)
.then(waitForPushNotification)
.then(unregisterPushNotification)
.then(unregister)
.catch(function(e) {
ok(false, "Some test failed with error " + e);
}).then(SimpleTest.finish);
}
SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true]
]}, runTest);
SpecialPowers.addPermission('push', true, document);
SimpleTest.waitForExplicitFinish();
</script>
</body>
</html>

16
dom/push/test/worker.js Normal file
View File

@ -0,0 +1,16 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
addEventListener("push", function(event) {
self.clients.matchAll().then(function(result) {
if (event instanceof PushEvent &&
event.data instanceof PushMessageData &&
event.data.text().length > 0) {
result[0].postMessage({type: "finished", okay: "yes"});
return;
}
result[0].postMessage({type: "finished", okay: "no"});
});
});

147
dom/simplepush/Push.js Normal file
View File

@ -0,0 +1,147 @@
/* 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/. */
"use strict";
// Don't modify this, instead set services.push.debug.
let gDebuggingEnabled = false;
function debug(s) {
if (gDebuggingEnabled)
dump("-*- Push.js: " + s + "\n");
}
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
Cu.import("resource://gre/modules/AppsUtils.jsm");
const PUSH_CID = Components.ID("{cde1d019-fad8-4044-b141-65fb4fb7a245}");
/**
* The Push component runs in the child process and exposes the SimplePush API
* to the web application. The PushService running in the parent process is the
* one actually performing all operations.
*/
function Push() {
debug("Push Constructor");
}
Push.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
contractID: "@mozilla.org/push/PushManager;1",
classID : PUSH_CID,
QueryInterface : XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
Ci.nsISupportsWeakReference,
Ci.nsIObserver]),
init: function(aWindow) {
// Set debug first so that all debugging actually works.
// NOTE: We don't add an observer here like in PushService. Flipping the
// pref will require a reload of the app/page, which seems acceptable.
gDebuggingEnabled = Services.prefs.getBoolPref("services.push.debug");
debug("init()");
let principal = aWindow.document.nodePrincipal;
let appsService = Cc["@mozilla.org/AppsService;1"]
.getService(Ci.nsIAppsService);
this._manifestURL = appsService.getManifestURLByLocalId(principal.appId);
this._pageURL = principal.URI;
this.initDOMRequestHelper(aWindow, [
"PushService:Register:OK",
"PushService:Register:KO",
"PushService:Unregister:OK",
"PushService:Unregister:KO",
"PushService:Registrations:OK",
"PushService:Registrations:KO"
]);
this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
.getService(Ci.nsISyncMessageSender);
},
receiveMessage: function(aMessage) {
debug("receiveMessage()");
let request = this.getRequest(aMessage.data.requestID);
let json = aMessage.data;
if (!request) {
debug("No request " + json.requestID);
return;
}
switch (aMessage.name) {
case "PushService:Register:OK":
Services.DOMRequest.fireSuccess(request, json.pushEndpoint);
break;
case "PushService:Register:KO":
Services.DOMRequest.fireError(request, json.error);
break;
case "PushService:Unregister:OK":
Services.DOMRequest.fireSuccess(request, json.pushEndpoint);
break;
case "PushService:Unregister:KO":
Services.DOMRequest.fireError(request, json.error);
break;
case "PushService:Registrations:OK":
Services.DOMRequest.fireSuccess(request, json.registrations);
break;
case "PushService:Registrations:KO":
Services.DOMRequest.fireError(request, json.error);
break;
default:
debug("NOT IMPLEMENTED! receiveMessage for " + aMessage.name);
}
},
register: function() {
debug("register()");
let req = this.createRequest();
if (!Services.prefs.getBoolPref("services.push.connection.enabled")) {
// If push socket is disabled by the user, immediately error rather than
// timing out.
Services.DOMRequest.fireErrorAsync(req, "NetworkError");
return req;
}
this._cpmm.sendAsyncMessage("Push:Register", {
pageURL: this._pageURL.spec,
manifestURL: this._manifestURL,
requestID: this.getRequestId(req)
});
return req;
},
unregister: function(aPushEndpoint) {
debug("unregister(" + aPushEndpoint + ")");
let req = this.createRequest();
this._cpmm.sendAsyncMessage("Push:Unregister", {
pageURL: this._pageURL.spec,
manifestURL: this._manifestURL,
requestID: this.getRequestId(req),
pushEndpoint: aPushEndpoint
});
return req;
},
registrations: function() {
debug("registrations()");
let req = this.createRequest();
this._cpmm.sendAsyncMessage("Push:Registrations", {
manifestURL: this._manifestURL,
requestID: this.getRequestId(req)
});
return req;
}
}
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Push]);

View File

@ -0,0 +1,8 @@
# DOM API
component {cde1d019-fad8-4044-b141-65fb4fb7a245} Push.js
contract @mozilla.org/push/PushManager;1 {cde1d019-fad8-4044-b141-65fb4fb7a245}
# Component to initialize PushService on startup.
component {4b8caa3b-3c58-4f3c-a7f5-7bd9cb24c11d} PushServiceLauncher.js
contract @mozilla.org/push/ServiceLauncher;1 {4b8caa3b-3c58-4f3c-a7f5-7bd9cb24c11d}
category app-startup PushServiceLauncher @mozilla.org/push/ServiceLauncher;1

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,43 @@
/* 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/. */
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
function PushServiceLauncher() {
};
PushServiceLauncher.prototype = {
classID: Components.ID("{4b8caa3b-3c58-4f3c-a7f5-7bd9cb24c11d}"),
contractID: "@mozilla.org/push/ServiceLauncher;1",
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsISupportsWeakReference]),
observe: function observe(subject, topic, data) {
switch (topic) {
case "app-startup":
Services.obs.addObserver(this, "final-ui-startup", true);
break;
case "final-ui-startup":
Services.obs.removeObserver(this, "final-ui-startup");
if (!Services.prefs.getBoolPref("services.push.enabled")) {
return;
}
Cu.import("resource://gre/modules/PushService.jsm");
PushService.init();
break;
}
}
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PushServiceLauncher]);

14
dom/simplepush/moz.build Normal file
View File

@ -0,0 +1,14 @@
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXTRA_COMPONENTS += [
'Push.js',
'Push.manifest',
'PushServiceLauncher.js',
]
EXTRA_JS_MODULES += [
'PushService.jsm',
]

View File

@ -874,6 +874,8 @@ var interfaceNamesInGlobalScope =
"Promise",
// IMPORTANT: Do not change this list without review from a DOM peer!
"PropertyNodeList",
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "PushManager", pref: "dom.push.enabled"},
// IMPORTANT: Do not change this list without review from a DOM peer!
"RadioNodeList",
// IMPORTANT: Do not change this list without review from a DOM peer!
@ -910,6 +912,8 @@ var interfaceNamesInGlobalScope =
{name: "ServiceWorker", pref: "dom.serviceWorkers.enabled"},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "ServiceWorkerContainer", pref: "dom.serviceWorkers.enabled"},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "ServiceWorkerRegistration", pref: "dom.serviceWorkers.enabled"},
// IMPORTANT: Do not change this list without review from a DOM peer!
"SettingsLock",
// IMPORTANT: Do not change this list without review from a DOM peer!

View File

@ -65,7 +65,7 @@ function tests(aEnabled) {
expectSuccess([1000, 1000.1]);
// The following loop shouldn't cause us to crash. See bug 701716.
for (var i = 0; i < 10000; i++) {
for (var i = 0; i < 1000; i++) {
navigator.vibrate([100, 100]);
}
ok(true, "Didn't crash after issuing a lot of vibrate() calls.");

View File

@ -51,9 +51,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=633602
var firstCall = !unLockedCoords;
if (!firstCall) {
todo(false, "mousemove is fired twice.");
} else {
isUnlocked = !document.mozPointerLockElement;
}
isUnlocked = !document.mozPointerLockElement;
unLockedCoords = {
screenX: e.screenX,
screenY: e.screenY,

View File

@ -0,0 +1,19 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* https://w3c.github.io/push-api/
*/
[Constructor(DOMString type, optional PushEventInit eventInitDict), Exposed=ServiceWorker]
interface PushEvent : ExtendableEvent {
readonly attribute PushMessageData data;
};
typedef USVString PushMessageDataInit;
dictionary PushEventInit : ExtendableEventInit {
PushMessageDataInit data;
};

View File

@ -2,15 +2,27 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* https://w3c.github.io/push-api/
*/
[NoInterfaceObject,
NavigatorProperty="push",
JSImplementation="@mozilla.org/push/PushManager;1",
CheckPermissions="push",
Pref="services.push.enabled"]
[JSImplementation="@mozilla.org/push/PushManager;1",
Pref="dom.push.enabled"]
interface PushManager {
DOMRequest register();
DOMRequest unregister(DOMString pushEndpoint);
DOMRequest registrations();
Promise<PushSubscription> subscribe();
Promise<PushSubscription?> getSubscription();
Promise<PushPermissionStatus> hasPermission();
// We need a setter in the bindings so that the C++ can use it,
// but we don't want it exposed to client JS. WebPushMethodHider
// always returns false.
[Func="ServiceWorkerRegistration::WebPushMethodHider"] void setScope(DOMString scope);
};
enum PushPermissionStatus
{
"granted",
"denied",
"default"
};

View File

@ -0,0 +1,17 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* https://w3c.github.io/push-api/
*/
[Exposed=ServiceWorker]
interface PushMessageData
{
ArrayBuffer arrayBuffer();
Blob blob();
object json();
USVString text();
};

View File

@ -0,0 +1,17 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* https://w3c.github.io/push-api/
*/
[JSImplementation="@mozilla.org/push/PushSubscription;1",
Constructor(DOMString pushEndpoint, DOMString scope, DOMString pageURL), ChromeOnly]
interface PushSubscription
{
readonly attribute USVString endpoint;
readonly attribute DOMString subscriptionId;
Promise<boolean> unsubscribe();
};

View File

@ -27,7 +27,7 @@ interface ServiceWorkerContainer : EventTarget {
Promise<ServiceWorkerRegistration> getRegistration(optional USVString documentURL = "");
[Throws]
Promise<sequence<ServiceWorkerRegistration>> getRegistrations();
Promise<sequence<ServiceWorkerRegistration>> getRegistrations();
attribute EventHandler oncontrollerchange;
attribute EventHandler onreloadpage;

View File

@ -23,3 +23,10 @@ interface ServiceWorkerRegistration : EventTarget {
// event
attribute EventHandler onupdatefound;
};
partial interface ServiceWorkerRegistration {
#ifndef MOZ_SIMPLEPUSH
[Throws, Pref="dom.push.enabled"]
readonly attribute PushManager pushManager;
#endif
};

View File

@ -0,0 +1,15 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
[NavigatorProperty="push",
JSImplementation="@mozilla.org/push/PushManager;1",
CheckPermissions="push",
Pref="services.push.enabled"]
interface SimplePushManager {
DOMRequest register();
DOMRequest unregister(DOMString pushEndpoint);
DOMRequest registrations();
};

View File

@ -11,6 +11,7 @@ GENERATED_WEBIDL_FILES = [
PREPROCESSED_WEBIDL_FILES = [
'HTMLMediaElement.webidl',
'Navigator.webidl',
'ServiceWorkerRegistration.webidl',
'Window.webidl',
]
@ -353,7 +354,6 @@ WEBIDL_FILES = [
'ProfileTimelineMarker.webidl',
'Promise.webidl',
'PromiseDebugging.webidl',
'PushManager.webidl',
'RadioNodeList.webidl',
'Range.webidl',
'Rect.webidl',
@ -382,7 +382,6 @@ WEBIDL_FILES = [
'ServiceWorker.webidl',
'ServiceWorkerContainer.webidl',
'ServiceWorkerGlobalScope.webidl',
'ServiceWorkerRegistration.webidl',
'SettingChangeNotification.webidl',
'SettingsManager.webidl',
'ShadowRoot.webidl',
@ -661,6 +660,19 @@ if CONFIG['MOZ_B2G_BT']:
'BluetoothManager.webidl',
]
if CONFIG['MOZ_SIMPLEPUSH']:
WEBIDL_FILES += [
'SimplePushManager.webidl'
]
else:
WEBIDL_FILES += [
'PushEvent.webidl',
'PushManager.webidl',
'PushManager.webidl',
'PushMessageData.webidl',
'PushSubscription.webidl',
]
if CONFIG['MOZ_NFC']:
WEBIDL_FILES += [
'MozIsoDepTech.webidl',

View File

@ -200,6 +200,6 @@ ServiceWorkerClients::Claim()
return nullptr;
}
promise->MaybeReject(NS_ERROR_NOT_AVAILABLE);
promise->MaybeResolve(JS::UndefinedHandleValue);
return promise.forget();
}

View File

@ -370,4 +370,59 @@ NS_INTERFACE_MAP_END_INHERITING(ExtendableEvent)
NS_IMPL_CYCLE_COLLECTION_INHERITED(InstallEvent, ExtendableEvent, mActiveWorker)
#ifndef MOZ_SIMPLEPUSH
PushMessageData::PushMessageData(const nsAString& aData)
: mData(aData)
{
}
PushMessageData::~PushMessageData()
{
}
NS_IMPL_ISUPPORTS0(PushMessageData);
void
PushMessageData::Json(JSContext* cx, JS::MutableHandle<JSObject*> aRetval)
{
//todo bug 1149195. Don't be lazy.
NS_ABORT();
}
void
PushMessageData::Text(nsAString& aData)
{
aData = mData;
}
void
PushMessageData::ArrayBuffer(JSContext* cx, JS::MutableHandle<JSObject*> aRetval)
{
//todo bug 1149195. Don't be lazy.
NS_ABORT();
}
mozilla::dom::File*
PushMessageData::Blob()
{
//todo bug 1149195. Don't be lazy.
NS_ABORT();
return nullptr;
}
PushEvent::PushEvent(EventTarget* aOwner)
: ExtendableEvent(aOwner)
{
}
NS_INTERFACE_MAP_BEGIN(PushEvent)
NS_INTERFACE_MAP_END_INHERITING(ExtendableEvent)
NS_IMPL_ADDREF_INHERITED(PushEvent, ExtendableEvent)
NS_IMPL_RELEASE_INHERITED(PushEvent, ExtendableEvent)
#endif /* ! MOZ_SIMPLEPUSH */
END_WORKERS_NAMESPACE

View File

@ -12,6 +12,12 @@
#include "mozilla/dom/InstallEventBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/Response.h"
#ifndef MOZ_SIMPLEPUSH
#include "mozilla/dom/PushEventBinding.h"
#include "mozilla/dom/PushMessageDataBinding.h"
#endif
#include "nsProxyRelease.h"
class nsIInterceptedChannel;
@ -216,5 +222,91 @@ public:
}
};
#ifndef MOZ_SIMPLEPUSH
class PushMessageData final : public nsISupports,
public nsWrapperCache
{
nsString mData;
public:
NS_DECL_ISUPPORTS
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
{
return mozilla::dom::PushMessageDataBinding_workers::Wrap(aCx, this, aGivenProto);
}
nsISupports* GetParentObject() const {
return nullptr;
}
void Json(JSContext* cx, JS::MutableHandle<JSObject*> aRetval);
void Text(nsAString& aData);
void ArrayBuffer(JSContext* cx, JS::MutableHandle<JSObject*> aRetval);
mozilla::dom::File* Blob();
explicit PushMessageData(const nsAString& aData);
private:
~PushMessageData();
};
class PushEvent final : public ExtendableEvent
{
nsString mData;
nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
protected:
explicit PushEvent(mozilla::dom::EventTarget* aOwner);
~PushEvent() {}
public:
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_TO_EVENT
virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
{
return mozilla::dom::PushEventBinding_workers::Wrap(aCx, this, aGivenProto);
}
static already_AddRefed<PushEvent>
Constructor(mozilla::dom::EventTarget* aOwner,
const nsAString& aType,
const PushEventInit& aOptions)
{
nsRefPtr<PushEvent> e = new PushEvent(aOwner);
bool trusted = e->Init(aOwner);
e->InitEvent(aType, aOptions.mBubbles, aOptions.mCancelable);
e->SetTrusted(trusted);
if(aOptions.mData.WasPassed()){
e->mData = aOptions.mData.Value();
}
return e.forget();
}
static already_AddRefed<PushEvent>
Constructor(const GlobalObject& aGlobal,
const nsAString& aType,
const PushEventInit& aOptions,
ErrorResult& aRv)
{
nsCOMPtr<EventTarget> owner = do_QueryInterface(aGlobal.GetAsSupports());
return Constructor(owner, aType, aOptions);
}
void PostInit(nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker)
{
mServiceWorker = aServiceWorker;
}
already_AddRefed<PushMessageData> Data()
{
nsRefPtr<PushMessageData> data = new PushMessageData(mData);
return data.forget();
}
};
#endif /* ! MOZ_SIMPLEPUSH */
END_WORKERS_NAMESPACE
#endif /* mozilla_dom_workers_serviceworkerevents_h__ */

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