Merge inbound to m-c. a=merge

This commit is contained in:
Ryan VanderMeulen 2015-07-14 23:36:32 -04:00
commit 720cc70372
99 changed files with 2481 additions and 528 deletions

View File

@ -102,19 +102,28 @@ HTMLLIAccessible::UpdateBullet(bool aHasBullet)
return;
}
nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(this);
AutoTreeMutation mut(this);
DocAccessible* document = Document();
if (aHasBullet) {
mBullet = new HTMLListBulletAccessible(mContent, mDoc);
document->BindToDocument(mBullet, nullptr);
InsertChildAt(0, mBullet);
nsRefPtr<AccShowEvent> event = new AccShowEvent(mBullet, mBullet->GetContent());
mDoc->FireDelayedEvent(event);
reorderEvent->AddSubMutationEvent(event);
} else {
nsRefPtr<AccHideEvent> event = new AccHideEvent(mBullet, mBullet->GetContent());
mDoc->FireDelayedEvent(event);
reorderEvent->AddSubMutationEvent(event);
RemoveChild(mBullet);
document->UnbindFromDocument(mBullet);
mBullet = nullptr;
}
// XXXtodo: fire show/hide and reorder events. That's hard to make it
// right now because coalescence happens by DOM node.
mDoc->FireDelayedEvent(reorderEvent);
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -6,6 +6,7 @@
[test_bug884251.xhtml]
[test_bug895082.html]
[test_bug1040735.html]
[test_bug1100602.html]
[test_canvas.html]
[test_colorpicker.xul]
[test_contextmenu.xul]

View File

@ -0,0 +1,114 @@
<html>
<head>
<title>Test hide/show events for HTMLListBulletAccessibles on list restyle</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../name.js"></script>
<script type="application/javascript"
src="../events.js"></script>
<script type="application/javascript">
/**
* Change list style type to none.
*/
function hideBullet()
{
this.eventSeq = [];
this.liAcc = getAccessible("list_element");
this.bullet = this.liAcc.firstChild;
this.eventSeq.push(new invokerChecker(EVENT_HIDE, this.bullet));
this.eventSeq.push(new invokerChecker(EVENT_REORDER, this.liAcc));
this.invoke = function hideBullet_invoke()
{
getNode("list").setAttribute("style", "list-style-type: none;");
}
this.finalCheck = function hideBullet_finalCheck()
{
is(this.liAcc.name, "list element",
"Check that first child of LI is not a bullet.");
}
this.getID = function hideBullet_getID()
{
return "Hide bullet by setting style to none";
}
}
/**
* Change list style type to circles.
*/
function showBullet()
{
this.eventSeq = [];
this.liAcc = getAccessible("list_element");
this.eventSeq.push(new invokerChecker(EVENT_SHOW,
function(aNode) { return aNode.firstChild; },
this.liAcc));
this.eventSeq.push(new invokerChecker(EVENT_REORDER, this.liAcc));
this.invoke = function showBullet_invoke()
{
getNode("list").setAttribute("style", "list-style-type: circle;");
}
this.finalCheck = function showBullet_finalCheck()
{
is(this.liAcc.name, "◦ list element",
"Check that first child of LI is a circle bullet.");
}
this.getID = function showBullet_getID()
{
return "Show bullet by setting style to circle";
}
}
var gQueue = null;
function doTest()
{
var list = getNode("list");
list.setAttribute("style", "list-style-type: circle;");
gQueue = new eventQueue();
gQueue.push(new hideBullet());
gQueue.push(new showBullet());
gQueue.invoke(); // SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1100602"
title="[e10s] crash in mozilla::a11y::ProxyAccessible::Shutdown()">
Mozilla Bug 1100602
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<ol id="list">
<li id="list_element">list element</li>
</ol>
</body>
</html>

View File

@ -5198,6 +5198,17 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
// Broken Content Detected. e.g. Content-MD5 check failure.
error.AssignLiteral("corruptedContentError");
break;
case NS_ERROR_INTERCEPTION_FAILED:
case NS_ERROR_OPAQUE_INTERCEPTION_DISABLED:
case NS_ERROR_BAD_OPAQUE_INTERCEPTION_REQUEST_MODE:
case NS_ERROR_INTERCEPTED_ERROR_RESPONSE:
case NS_ERROR_INTERCEPTED_USED_RESPONSE:
case NS_ERROR_CLIENT_REQUEST_OPAQUE_INTERCEPTION:
// ServiceWorker intercepted request, but something went wrong.
nsContentUtils::MaybeReportInterceptionErrorToConsole(GetDocument(),
aError);
error.AssignLiteral("corruptedContentError");
break;
default:
break;
}
@ -7825,6 +7836,12 @@ nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
aStatus == NS_ERROR_UNSAFE_CONTENT_TYPE ||
aStatus == NS_ERROR_REMOTE_XUL ||
aStatus == NS_ERROR_OFFLINE ||
aStatus == NS_ERROR_INTERCEPTION_FAILED ||
aStatus == NS_ERROR_OPAQUE_INTERCEPTION_DISABLED ||
aStatus == NS_ERROR_BAD_OPAQUE_INTERCEPTION_REQUEST_MODE ||
aStatus == NS_ERROR_INTERCEPTED_ERROR_RESPONSE ||
aStatus == NS_ERROR_INTERCEPTED_USED_RESPONSE ||
aStatus == NS_ERROR_CLIENT_REQUEST_OPAQUE_INTERCEPTION ||
NS_ERROR_GET_MODULE(aStatus) == NS_ERROR_MODULE_SECURITY) {
// Errors to be shown for any frame
DisplayLoadError(aStatus, url, nullptr, aChannel);
@ -14091,7 +14108,7 @@ nsDocShell::ChannelIntercepted(nsIInterceptedChannel* aChannel)
{
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (!swm) {
aChannel->Cancel();
aChannel->Cancel(NS_ERROR_INTERCEPTION_FAILED);
return NS_OK;
}

View File

@ -23,22 +23,13 @@
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_CLASS(URL)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(URL)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSearchParams)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(URL)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSearchParams)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(URL, mParent, mSearchParams)
NS_IMPL_CYCLE_COLLECTING_ADDREF(URL)
NS_IMPL_CYCLE_COLLECTING_RELEASE(URL)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(URL)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END

View File

@ -39,7 +39,7 @@ class URL final : public URLSearchParamsObserver
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(URL)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(URL)
URL(nsISupports* aParent, already_AddRefed<nsIURI> aURI);

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<script>
window.mozRequestAnimationFrame(null);
window.requestAnimationFrame(null);
</script>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
<script>
mozCancelRequestAnimationFrame(mozRequestAnimationFrame(function() {}));
mozRequestAnimationFrame(function() {});
cancelRequestAnimationFrame(requestAnimationFrame(function() {}));
requestAnimationFrame(function() {});
</script>

View File

@ -3417,6 +3417,36 @@ nsContentUtils::ReportToConsole(uint32_t aErrorFlags,
aLineNumber, aColumnNumber);
}
/* static */ nsresult
nsContentUtils::MaybeReportInterceptionErrorToConsole(nsIDocument* aDocument,
nsresult aError)
{
const char* messageName = nullptr;
if (aError == NS_ERROR_INTERCEPTION_FAILED) {
messageName = "InterceptionFailed";
} else if (aError == NS_ERROR_OPAQUE_INTERCEPTION_DISABLED) {
messageName = "OpaqueInterceptionDisabled";
} else if (aError == NS_ERROR_BAD_OPAQUE_INTERCEPTION_REQUEST_MODE) {
messageName = "BadOpaqueInterceptionRequestMode";
} else if (aError == NS_ERROR_INTERCEPTED_ERROR_RESPONSE) {
messageName = "InterceptedErrorResponse";
} else if (aError == NS_ERROR_INTERCEPTED_USED_RESPONSE) {
messageName = "InterceptedUsedResponse";
} else if (aError == NS_ERROR_CLIENT_REQUEST_OPAQUE_INTERCEPTION) {
messageName = "ClientRequestOpaqueInterception";
}
if (messageName) {
return ReportToConsole(nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("Service Worker Interception"),
aDocument,
nsContentUtils::eDOM_PROPERTIES,
messageName);
}
return NS_OK;
}
/* static */ nsresult
nsContentUtils::ReportToConsoleNonLocalized(const nsAString& aErrorText,

View File

@ -842,6 +842,9 @@ public:
uint32_t aLineNumber = 0,
uint32_t aColumnNumber = 0);
static nsresult
MaybeReportInterceptionErrorToConsole(nsIDocument* aDocument, nsresult aError);
static void LogMessageToConsole(const char* aMsg, ...);
/**

View File

@ -1761,10 +1761,10 @@ private:
void EnableStyleSheetsForSetInternal(const nsAString& aSheetSet,
bool aUpdateCSSLoader);
// Revoke any pending notifications due to mozRequestAnimationFrame calls
// Revoke any pending notifications due to requestAnimationFrame calls
void RevokeAnimationFrameNotifications();
// Reschedule any notifications we need to handle
// mozRequestAnimationFrame, if it's OK to do so.
// requestAnimationFrame, if it's OK to do so.
void MaybeRescheduleAnimationFrameNotifications();
// These are not implemented and not supported.

View File

@ -823,6 +823,7 @@ GK_ATOM(onMozScrolledAreaChanged, "onMozScrolledAreaChanged")
GK_ATOM(onmoznetworkupload, "onmoznetworkupload")
GK_ATOM(onmoznetworkdownload, "onmoznetworkdownload")
GK_ATOM(onnewrdsgroup, "onnewrdsgroup")
GK_ATOM(onnotificationclick, "onnotificationclick")
GK_ATOM(onnoupdate, "onnoupdate")
GK_ATOM(onobsolete, "onobsolete")
GK_ATOM(ononline, "ononline")

View File

@ -2709,11 +2709,9 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
// We wait to fire the debugger hook until the window is all set up and hooked
// up with the outer. See bug 969156.
if (createdInnerWindow) {
// AutoEntryScript required to invoke debugger hook, which is a
// Gecko-specific concept at present.
AutoEntryScript aes(newInnerWindow, "nsGlobalWindow report new global");
JS::Rooted<JSObject*> global(aes.cx(), newInnerWindow->GetWrapper());
JS_FireOnNewGlobalObject(aes.cx(), global);
nsContentUtils::AddScriptRunner(
NS_NewRunnableMethod(newInnerWindow,
&nsGlobalWindow::FireOnNewGlobalObject));
}
if (newInnerWindow && !newInnerWindow->mHasNotifiedGlobalCreated && mDoc) {
@ -14167,6 +14165,18 @@ nsGlobalWindow::SetReplaceableWindowCoord(JSContext* aCx,
(this->*aSetter)(value, aError);
}
void
nsGlobalWindow::FireOnNewGlobalObject()
{
MOZ_ASSERT(IsInnerWindow());
// AutoEntryScript required to invoke debugger hook, which is a
// Gecko-specific concept at present.
AutoEntryScript aes(this, "nsGlobalWindow report new global");
JS::Rooted<JSObject*> global(aes.cx(), GetWrapper());
JS_FireOnNewGlobalObject(aes.cx(), global);
}
#ifdef _WINDOWS_
#error "Never include windows.h in this file!"
#endif

View File

@ -1538,6 +1538,11 @@ protected:
// show, in that case we show a separate dialog to ask this question.
bool ConfirmDialogIfNeeded();
private:
// Fire the JS engine's onNewGlobalObject hook. Only used on inner windows.
void FireOnNewGlobalObject();
protected:
// When adding new member variables, be careful not to create cycles
// through JavaScript. If there is any chance that a member variable
// could own objects that are implemented in JavaScript, then those

View File

@ -22,7 +22,7 @@ SimpleTest.waitForExplicitFinish();
var counter = 3;
var called = false;
var handle1 = window.mozRequestAnimationFrame(function() {
var handle1 = window.requestAnimationFrame(function() {
called = true;
});
ok(handle1 > 0, "Should get back a nonzero handle");
@ -33,11 +33,11 @@ function checker() {
is(called, false, "Canceled callback should not have been called");
SimpleTest.finish();
} else {
window.mozRequestAnimationFrame(checker);
window.requestAnimationFrame(checker);
}
}
window.mozRequestAnimationFrame(checker);
window.mozCancelAnimationFrame(handle1);
window.requestAnimationFrame(checker);
window.cancelAnimationFrame(handle1);
</script>
</pre>

View File

@ -27,7 +27,7 @@ function f() {
}
}
window.mozRequestAnimationFrame(f);
window.requestAnimationFrame(f);
var xhr = new XMLHttpRequest();
xhr.open("GET", "file_bug675121.sjs", false);
xhrInProgress = true;

View File

@ -12,34 +12,34 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=
/** Test for Bug **/
SimpleTest.waitForExplicitFinish();
var unprefixedRan = false;
var prefixedRan = false;
function unprefixed(time) {
is(prefixedRan, true, "We were called second");
unprefixedRan = true;
var firstRan = false;
var secondRan = false;
function second(time) {
is(firstRan, true, "We were called second");
secondRan = true;
ok(Math.abs(time - performance.now()) < 3600000,
"An hour really shouldn't have passed here");
ok(Math.abs(time - Date.now()) > 3600000,
"More than an hour should have passed since 1970");
}
function prefixed(time) {
is(unprefixedRan, false, "Prefixed was called first");
prefixedRan = true;
ok(Math.abs(time - Date.now()) < 3600000,
"Our time should be comparable to Date.now()");
ok(Math.abs(time - performance.now()) > 3600000,
"Our time should not be comparable to performance.now()");
function first(time) {
is(secondRan, false, "second() was called first");
firstRan = true;
ok(Math.abs(time - performance.now()) < 3600000,
"An hour really shouldn't have passed here either");
ok(Math.abs(time - Date.now()) > 3600000,
"More than an hour should have passed since 1970 here either");
}
function prefixed2() {
ok(prefixedRan, "We should be after the other prefixed call");
ok(unprefixedRan, "We should be after the unprefixed call");
function third() {
ok(firstRan, "We should be after the first call");
ok(secondRan, "We should be after the second call");
SimpleTest.finish();
}
window.onload = function() {
window.mozRequestAnimationFrame(prefixed);
window.requestAnimationFrame(unprefixed);
window.mozRequestAnimationFrame(prefixed2);
window.requestAnimationFrame(first);
window.requestAnimationFrame(second);
window.requestAnimationFrame(third);
}
</script>

View File

@ -869,6 +869,14 @@ DOMInterfaces = {
'nativeType': 'nsINodeList',
},
'NotificationEvent': {
'headerFile': 'mozilla/dom/NotificationEvent.h',
'nativeType': 'mozilla::dom::workers::NotificationEvent',
'binaryNames': {
'notification': 'notification_'
}
},
'OfflineAudioContext': {
'nativeType': 'mozilla::dom::AudioContext',
},

View File

@ -73,3 +73,6 @@ MSG_DEF(MSG_INVALID_URL_SCHEME, 2, JSEXN_TYPEERR, "{0} URL {1} must be either ht
MSG_DEF(MSG_RESPONSE_URL_IS_NULL, 0, JSEXN_TYPEERR, "Cannot set Response.finalURL when Response.url is null.")
MSG_DEF(MSG_RESPONSE_HAS_VARY_STAR, 0, JSEXN_TYPEERR, "Invalid Response object with a 'Vary: *' header.")
MSG_DEF(MSG_BAD_FORMDATA, 0, JSEXN_TYPEERR, "Could not parse content as FormData.")
MSG_DEF(MSG_NO_ACTIVE_WORKER, 1, JSEXN_TYPEERR, "No active worker for scope {0}.")
MSG_DEF(MSG_NOTIFICATION_PERMISSION_DENIED, 0, JSEXN_TYPEERR, "Permission to show Notification denied.")
MSG_DEF(MSG_NOTIFICATION_NO_CONSTRUCTOR_IN_SERVICEWORKER, 0, JSEXN_TYPEERR, "Notification constructor cannot be used in ServiceWorkerGlobalScope. Use registration.showNotification() instead.")

View File

@ -622,7 +622,7 @@ const KineticPanning = {
v.y * Math.exp(-t / c) * -c + a.y * t * t + v.y * c);
}
let startTime = content.mozAnimationStartTime;
let startTime = content.performance.now();
let elapsedTime = 0, targetedTime = 0, averageTime = 0;
let velocity = this._velocity;
@ -667,9 +667,9 @@ const KineticPanning = {
return;
}
content.mozRequestAnimationFrame(callback);
content.requestAnimationFrame(callback);
}).bind(this);
content.mozRequestAnimationFrame(callback);
content.requestAnimationFrame(callback);
}
};

View File

@ -62,7 +62,7 @@ function initGL(canvas) {
}
function rAF(func) {
var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame;
var raf = window.requestAnimationFrame;
raf(func);
}

View File

@ -55,10 +55,10 @@ function runTest() {
scrollDown15PxWithPixelScrolling(scrollbox);
// wait for the next refresh driver run
win.mozRequestAnimationFrame(function() {
win.requestAnimationFrame(function() {
// actually, wait for the next one before checking results, since
// scrolling might not be flushed until after this code has run
win.mozRequestAnimationFrame(function() {
win.requestAnimationFrame(function() {
is(scrollbox.scrollTop, scrollTopBefore + 15,
"Pixel scrolling should have finished after one refresh driver iteration. " +
"We shouldn't be scrolling smoothly, even though the pref is set.");

View File

@ -195,5 +195,44 @@ InternalRequest::MapContentPolicyTypeToRequestContext(nsContentPolicyType aConte
return context;
}
bool
InternalRequest::IsNavigationRequest() const
{
// https://fetch.spec.whatwg.org/#navigation-request-context
//
// A navigation request context is one of "form", "frame", "hyperlink",
// "iframe", "internal" (as long as context frame type is not "none"),
// "location", "metarefresh", and "prerender".
//
// TODO: include equivalent check for "form" context
// TODO: include equivalent check for "prerender" context
return mContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
mContentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT ||
mContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_FRAME ||
mContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_IFRAME ||
mContentPolicyType == nsIContentPolicy::TYPE_REFRESH;
}
bool
InternalRequest::IsWorkerRequest() const
{
// https://fetch.spec.whatwg.org/#worker-request-context
//
// A worker request context is one of "serviceworker", "sharedworker", and
// "worker".
//
// Note, service workers are not included here because currently there is
// no way to generate a Request with a "serviceworker" RequestContext.
// ServiceWorker scripts cannot be intercepted.
return mContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_WORKER ||
mContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER;
}
bool
InternalRequest::IsClientRequest() const
{
return IsNavigationRequest() || IsWorkerRequest();
}
} // namespace dom
} // namespace mozilla

View File

@ -356,6 +356,16 @@ public:
mCreatedByFetchEvent = false;
}
bool
IsNavigationRequest() const;
bool
IsWorkerRequest() const;
bool
IsClientRequest() const;
private:
// Does not copy mBodyStream. Use fallible Clone() for complete copy.
explicit InternalRequest(const InternalRequest& aOther);

View File

@ -33,7 +33,7 @@ interface nsIServiceWorkerInfo : nsISupports
readonly attribute DOMString waitingCacheName;
};
[scriptable, builtinclass, uuid(e9abb123-0099-4d9e-85db-c8cd0aff19e6)]
[scriptable, builtinclass, uuid(ed1cbbf2-0400-4caa-8eb2-b09d21a94e20)]
interface nsIServiceWorkerManager : nsISupports
{
/**
@ -126,6 +126,17 @@ interface nsIServiceWorkerManager : nsISupports
in nsIServiceWorkerUnregisterCallback aCallback,
in DOMString aScope);
void sendNotificationClickEvent(in ACString aOriginSuffix,
in ACString scope,
in AString aID,
in AString aTitle,
in AString aDir,
in AString aLang,
in AString aBody,
in AString aTag,
in AString aIcon,
in AString aData,
in AString aBehavior);
void sendPushEvent(in ACString aOriginAttributes,
in ACString aScope,
in DOMString aData);

View File

@ -4,7 +4,7 @@
#include "domstubs.idl"
[scriptable, uuid(9f1c43b9-f01b-4c87-ad3d-1a86520c2159)]
[scriptable, uuid(c1622232-259c-43b0-b52e-89c39dcd9796)]
interface nsINotificationStorageCallback : nsISupports
{
/**
@ -28,7 +28,8 @@ interface nsINotificationStorageCallback : nsISupports
in DOMString tag,
in DOMString icon,
in DOMString data,
in DOMString behavior);
in DOMString behavior,
in DOMString serviceWorkerRegistrationID);
/**
* Callback function used to notify C++ the we have returned
@ -41,7 +42,7 @@ interface nsINotificationStorageCallback : nsISupports
/**
* Interface for notification persistence layer.
*/
[scriptable, uuid(cac01fb0-c2eb-4252-b2f4-5b1fac933bd4)]
[scriptable, uuid(17f85e52-fe57-440e-9ba1-5c312ca02b95)]
interface nsINotificationStorage : nsISupports
{
@ -61,6 +62,10 @@ interface nsINotificationStorage : nsISupports
* Stored in the database to avoid re-computing
* it. Built from origin and tag or id depending
* whether there is a tag defined.
* @param registrationID: Opaque string that identifies the service worker
* registration this Notification is associated with.
* May be empty. Only set for Notifications created by
* showNotification().
*/
void put(in DOMString origin,
in DOMString id,
@ -72,7 +77,8 @@ interface nsINotificationStorage : nsISupports
in DOMString icon,
in DOMString alertName,
in DOMString data,
in DOMString behavior);
in DOMString behavior,
in DOMString serviceWorkerRegistrationID);
/**
* Retrieve a list of notifications.
@ -86,6 +92,20 @@ interface nsINotificationStorage : nsISupports
in DOMString tag,
in nsINotificationStorageCallback aCallback);
/**
* Retrieve a notification by ID.
*
* @param origin: the origin/app for which to fetch notifications.
* @param id: the id of the notification.
* @param callback: nsINotificationStorageCallback whose Handle method will
* be called *at most once* if the notification with that ID is found. Not
* called if that ID is not found. Done() will be called right after
* Handle().
*/
void getByID(in DOMString origin,
in DOMString id,
in nsINotificationStorageCallback aCallback);
/**
* Remove a notification from storage.
*

View File

@ -166,3 +166,15 @@ HittingMaxWorkersPerDomain=A ServiceWorker could not be started immediately beca
PannerNodeDopplerWarning=Use of setVelocity on the PannerNode and AudioListener, and speedOfSound and dopplerFactor on the AudioListener are deprecated and those members will be removed. For more help https://developer.mozilla.org/en-US/docs/Web/API/AudioListener#Deprecated_features
# LOCALIZATION NOTE: Do not translate "Worker".
EmptyWorkerSourceWarning=Attempting to create a Worker from an empty source. This is probably unintentional.
# LOCALIZATION NOTE: Do not translate "ServiceWorker".
InterceptionFailed=ServiceWorker network interception failed due to an unexpected error.
# LOCALIZATION NOTE: Do not translate "ServiceWorker", "FetchEvent.respondWith()", "opaque", or "Response".
OpaqueInterceptionDisabled=A ServiceWorker passed an opaque Response to FetchEvent.respondWith() while opaque interception is disabled.
# LOCALIZATION NOTE: Do not translate "ServiceWorker", "FetchEvent.respondWith()", "FetchEvent.request.type", "same-origin", "cors", "no-cors", "opaque", "Response", or "RequestMode".
BadOpaqueInterceptionRequestMode=A ServiceWorker passed an opaque Response to FetchEvent.respondWith() while the FetchEvent.request.type was either "same-origin" or "cors". Opaque Response objects are only valid when the RequestMode is "no-cors".
# LOCALIZATION NOTE: Do not translate "ServiceWorker", "Error", "Response", "FetchEvent.respondWith()", or "fetch()".
InterceptedErrorResponse=A ServiceWorker passed an Error Response to FetchEvent.respondWith(). This typically means the ServiceWorker performed an invalid fetch() call.
# LOCALIZATION NOTE: Do not translate "ServiceWorker", "Response", "FetchEvent.respondWith()", or "Response.clone()".
InterceptedUsedResponse=A ServiceWorker passed a used Response to FetchEvent.respondWith(). The body of a Response may only be read once. Use Response.clone() to access the body multiple times.
# LOCALIZATION NOTE: Do not translate "ServiceWorker", "Response", "FetchEvent.respondWith()", "FetchEvent.request", or "Worker".
ClientRequestOpaqueInterception=A ServiceWorker passed an opaque Response to FetchEvent.respondWith() while FetchEvent.request was a client request. A client request is generally a browser navigation or top-level Worker script.

File diff suppressed because it is too large Load Diff

View File

@ -115,6 +115,8 @@ class Notification : public DOMEventTargetHelper
friend class NotificationPermissionRequest;
friend class NotificationObserver;
friend class NotificationStorageCallback;
friend class ServiceWorkerNotificationObserver;
friend class WorkerGetRunnable;
friend class WorkerNotificationObserver;
public:
@ -134,6 +136,31 @@ public:
const nsAString& aTitle,
const NotificationOptions& aOption,
ErrorResult& aRv);
/**
* Used when dispatching the ServiceWorkerEvent.
*
* Does not initialize the Notification's behavior.
* This is because:
* 1) The Notification is not shown to the user and so the behavior
* parameters don't matter.
* 2) The default binding requires main thread for parsing the JSON from the
* string behavior.
*/
static already_AddRefed<Notification>
ConstructFromFields(
nsIGlobalObject* aGlobal,
const nsAString& aID,
const nsAString& aTitle,
const nsAString& aDir,
const nsAString& aLang,
const nsAString& aBody,
const nsAString& aTag,
const nsAString& aIcon,
const nsAString& aData,
const nsAString& aServiceWorkerRegistrationID,
ErrorResult& aRv);
void GetID(nsAString& aRetval) {
aRetval = mID;
}
@ -189,10 +216,30 @@ public:
static NotificationPermission GetPermission(const GlobalObject& aGlobal,
ErrorResult& aRv);
static already_AddRefed<Promise>
Get(nsPIDOMWindow* aWindow,
const GetNotificationOptions& aFilter,
const nsAString& aScope,
ErrorResult& aRv);
static already_AddRefed<Promise> Get(const GlobalObject& aGlobal,
const GetNotificationOptions& aFilter,
ErrorResult& aRv);
static already_AddRefed<Promise> WorkerGet(workers::WorkerPrivate* aWorkerPrivate,
const GetNotificationOptions& aFilter,
const nsAString& aScope,
ErrorResult& aRv);
// Notification implementation of
// ServiceWorkerRegistration.showNotification.
static already_AddRefed<Promise>
ShowPersistentNotification(nsIGlobalObject* aGlobal,
const nsAString& aScope,
const nsAString& aTitle,
const NotificationOptions& aOptions,
ErrorResult& aRv);
void Close();
nsPIDOMWindow* GetParentObject()
@ -233,15 +280,20 @@ public:
bool AddRefObject();
void ReleaseObject();
static NotificationPermission GetPermission(nsIGlobalObject* aGlobal,
ErrorResult& aRv);
static NotificationPermission GetPermissionInternal(nsIPrincipal* aPrincipal,
ErrorResult& rv);
bool DispatchClickEvent();
bool DispatchNotificationClickEvent();
protected:
Notification(const nsAString& aID, const nsAString& aTitle, const nsAString& aBody,
Notification(nsIGlobalObject* aGlobal, const nsAString& aID,
const nsAString& aTitle, const nsAString& aBody,
NotificationDirection aDir, const nsAString& aLang,
const nsAString& aTag, const nsAString& aIconUrl,
const NotificationBehavior& aBehavior, nsIGlobalObject* aGlobal);
const NotificationBehavior& aBehavior);
static already_AddRefed<Notification> CreateInternal(nsIGlobalObject* aGlobal,
const nsAString& aID,
@ -277,14 +329,29 @@ protected:
return NotificationDirection::Auto;
}
static nsresult GetOrigin(nsPIDOMWindow* aWindow, nsString& aOrigin);
nsresult GetOriginWorker(nsString& aOrigin);
static nsresult GetOrigin(nsIPrincipal* aPrincipal, nsString& aOrigin);
void GetAlertName(nsAString& aRetval)
{
workers::AssertIsOnMainThread();
if (mAlertName.IsEmpty()) {
SetAlertName();
}
aRetval = mAlertName;
}
void GetScope(nsAString& aScope)
{
aScope = mScope;
}
void
SetScope(const nsAString& aScope)
{
MOZ_ASSERT(mScope.IsEmpty());
mScope = aScope;
}
const nsString mID;
const nsString mTitle;
const nsString mBody;
@ -299,6 +366,7 @@ protected:
nsCOMPtr<nsIVariant> mData;
nsString mAlertName;
nsString mScope;
// Main thread only.
bool mIsClosed;
@ -314,11 +382,25 @@ protected:
private:
virtual ~Notification();
// Creates a Notification and shows it. Returns a reference to the
// Notification if result is NS_OK. The lifetime of this Notification is tied
// to an underlying NotificationRef. Do not hold a non-stack raw pointer to
// it. Be careful about thread safety if acquiring a strong reference.
static already_AddRefed<Notification>
CreateAndShow(nsIGlobalObject* aGlobal,
const nsAString& aTitle,
const NotificationOptions& aOptions,
const nsAString& aScope,
ErrorResult& aRv);
nsIPrincipal* GetPrincipal();
nsresult PersistNotification();
void UnpersistNotification();
void
SetAlertName();
bool IsTargetThread() const
{
return NS_IsMainThread() == !mWorkerPrivate;

View File

@ -0,0 +1,26 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "NotificationEvent.h"
using namespace mozilla::dom;
BEGIN_WORKERS_NAMESPACE
NotificationEvent::NotificationEvent(EventTarget* aOwner)
: ExtendableEvent(aOwner)
{
}
NS_IMPL_ADDREF_INHERITED(NotificationEvent, ExtendableEvent)
NS_IMPL_RELEASE_INHERITED(NotificationEvent, ExtendableEvent)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(NotificationEvent)
NS_INTERFACE_MAP_END_INHERITING(ExtendableEvent)
NS_IMPL_CYCLE_COLLECTION_INHERITED(NotificationEvent, ExtendableEvent, mNotification)
END_WORKERS_NAMESPACE

View File

@ -0,0 +1,74 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_workers_notificationevent_h__
#define mozilla_dom_workers_notificationevent_h__
#include "mozilla/dom/Event.h"
#include "mozilla/dom/NotificationEventBinding.h"
#include "mozilla/dom/ServiceWorkerEvents.h"
#include "mozilla/dom/workers/Workers.h"
BEGIN_WORKERS_NAMESPACE
class ServiceWorker;
class ServiceWorkerClient;
class NotificationEvent final : public ExtendableEvent
{
protected:
explicit NotificationEvent(EventTarget* aOwner);
~NotificationEvent()
{}
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(NotificationEvent, ExtendableEvent)
NS_FORWARD_TO_EVENT
virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
{
return NotificationEventBinding::Wrap(aCx, this, aGivenProto);
}
static already_AddRefed<NotificationEvent>
Constructor(mozilla::dom::EventTarget* aOwner,
const nsAString& aType,
const NotificationEventInit& aOptions,
ErrorResult& aRv)
{
nsRefPtr<NotificationEvent> e = new NotificationEvent(aOwner);
bool trusted = e->Init(aOwner);
e->InitEvent(aType, aOptions.mBubbles, aOptions.mCancelable);
e->SetTrusted(trusted);
e->mNotification = aOptions.mNotification;
e->SetWantsPopupControlCheck(e->IsTrusted());
return e.forget();
}
static already_AddRefed<NotificationEvent>
Constructor(const GlobalObject& aGlobal,
const nsAString& aType,
const NotificationEventInit& aOptions,
ErrorResult& aRv)
{
nsCOMPtr<EventTarget> owner = do_QueryInterface(aGlobal.GetAsSupports());
return Constructor(owner, aType, aOptions, aRv);
}
already_AddRefed<Notification>
Notification_()
{
nsRefPtr<Notification> n = mNotification;
return n.forget();
}
private:
nsRefPtr<Notification> mNotification;
};
END_WORKERS_NAMESPACE
#endif /* mozilla_dom_workers_notificationevent_h__ */

View File

@ -4,7 +4,7 @@
"use strict";
const DEBUG = false;
const DEBUG = true;
function debug(s) { dump("-*- NotificationStorage.js: " + s + "\n"); }
const Cc = Components.classes;
@ -84,8 +84,8 @@ NotificationStorage.prototype = {
},
put: function(origin, id, title, dir, lang, body, tag, icon, alertName,
data, behavior) {
if (DEBUG) { debug("PUT: " + id + ": " + title); }
data, behavior, serviceWorkerRegistrationID) {
if (DEBUG) { debug("PUT: " + origin + " " + id + ": " + title); }
var notification = {
id: id,
title: title,
@ -98,7 +98,8 @@ NotificationStorage.prototype = {
timestamp: new Date().getTime(),
origin: origin,
data: data,
mozbehavior: behavior
mozbehavior: behavior,
serviceWorkerRegistrationID: serviceWorkerRegistrationID,
};
this._notifications[id] = notification;
@ -134,6 +135,25 @@ NotificationStorage.prototype = {
}
},
getByID: function(origin, id, callback) {
if (DEBUG) { debug("GETBYID: " + origin + " " + id); }
var GetByIDProxyCallback = function(id, originalCallback) {
this.searchID = id;
this.originalCallback = originalCallback;
var self = this;
this.handle = function(id, title, dir, lang, body, tag, icon, data, behavior, serviceWorkerRegistrationID) {
if (id == this.searchID) {
self.originalCallback.handle(id, title, dir, lang, body, tag, icon, data, behavior, serviceWorkerRegistrationID);
}
};
this.done = function() {
self.originalCallback.done();
};
};
return this.get(origin, "", new GetByIDProxyCallback(id, callback));
},
delete: function(origin, id) {
if (DEBUG) { debug("DELETE: " + id); }
var notification = this._notifications[id];
@ -211,23 +231,30 @@ NotificationStorage.prototype = {
}
// Pass each notification back separately.
// The callback is called asynchronously to match the behaviour when
// fetching from the database.
notifications.forEach(function(notification) {
try {
callback.handle(notification.id,
notification.title,
notification.dir,
notification.lang,
notification.body,
notification.tag,
notification.icon,
notification.data,
notification.mozbehavior);
Services.tm.currentThread.dispatch(
callback.handle.bind(callback,
notification.id,
notification.title,
notification.dir,
notification.lang,
notification.body,
notification.tag,
notification.icon,
notification.data,
notification.mozbehavior,
notification.serviceWorkerRegistrationID),
Ci.nsIThread.DISPATCH_NORMAL);
} catch (e) {
if (DEBUG) { debug("Error calling callback handle: " + e); }
}
});
try {
callback.done();
Services.tm.currentThread.dispatch(callback.done,
Ci.nsIThread.DISPATCH_NORMAL);
} catch (e) {
if (DEBUG) { debug("Error calling callback done: " + e); }
}

View File

@ -18,11 +18,13 @@ EXTRA_JS_MODULES += [
EXPORTS.mozilla.dom += [
'DesktopNotification.h',
'Notification.h',
'NotificationEvent.h',
]
UNIFIED_SOURCES += [
'DesktopNotification.cpp',
'Notification.cpp',
'NotificationEvent.cpp',
]
FAIL_ON_WARNINGS = True

View File

@ -35,7 +35,7 @@ function start() {
canvas = document.getElementById("two");
paintCanvas();
mozRequestAnimationFrame(moveSomething);
requestAnimationFrame(moveSomething);
}
function paintCanvas() {
@ -52,7 +52,7 @@ function moveSomething() {
return finish();
}
mozRequestAnimationFrame(moveSomething);
requestAnimationFrame(moveSomething);
}
function finish() {

View File

@ -1619,9 +1619,9 @@ PromiseWorkerProxy::RunCallback(JSContext* aCx,
{
MOZ_ASSERT(NS_IsMainThread());
MutexAutoLock lock(mCleanUpLock);
MutexAutoLock lock(GetCleanUpLock());
// If the worker thread's been cancelled we don't need to resolve the Promise.
if (mCleanedUp) {
if (IsClean()) {
return;
}

View File

@ -43,9 +43,10 @@ var MockServices = (function () {
setTimeout(function () {
listener.observe(null, "alertshow", cookie);
}, 100);
setTimeout(function () {
listener.observe(null, "alertclickcallback", cookie);
}, 100);
}
// ?? SpecialPowers.wrap(alertListener).observe(null, "alertclickcallback", cookie);
},
showAppNotification: function(aImageUrl, aTitle, aText, aAlertListener, aDetails) {

View File

@ -68,7 +68,7 @@ dictionary NotificationOptions {
};
dictionary GetNotificationOptions {
DOMString tag;
DOMString tag = "";
};
dictionary NotificationBehavior {
@ -93,3 +93,9 @@ enum NotificationDirection {
"rtl"
};
partial interface ServiceWorkerRegistration {
[Throws]
Promise<void> showNotification(DOMString title, optional NotificationOptions options);
[Throws]
Promise<sequence<Notification>> getNotifications(optional GetNotificationOptions filter);
};

View File

@ -0,0 +1,26 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* http://notifications.spec.whatwg.org/
*
* Copyright:
* To the extent possible under law, the editors have waived all copyright and
* related or neighboring rights to this work.
*/
[Constructor(DOMString type, optional NotificationEventInit eventInitDict),
Exposed=ServiceWorker,Func="mozilla::dom::Notification::PrefEnabled"]
interface NotificationEvent : ExtendableEvent {
readonly attribute Notification notification;
};
dictionary NotificationEventInit : ExtendableEventInit {
required Notification notification;
};
partial interface ServiceWorkerGlobalScope {
attribute EventHandler onnotificationclick;
};

View File

@ -12,7 +12,7 @@
// https://github.com/slightlyoff/ServiceWorker/issues/189
[Func="mozilla::dom::workers::ServiceWorkerVisible",
// FIXME(nsm): Bug 1113522. This is exposed to satisfy webidl constraints, but it won't actually work.
Exposed=(Worker,Window)]
Exposed=(Window,Worker)]
interface ServiceWorker : EventTarget {
readonly attribute USVString scriptURL;
readonly attribute ServiceWorkerState state;

View File

@ -335,6 +335,7 @@ WEBIDL_FILES = [
'NodeIterator.webidl',
'NodeList.webidl',
'Notification.webidl',
'NotificationEvent.webidl',
'NotifyPaintEvent.webidl',
'OfflineAudioCompletionEvent.webidl',
'OfflineAudioContext.webidl',

View File

@ -66,7 +66,6 @@ using mozilla::dom::cache::Cache;
using mozilla::dom::cache::CacheStorage;
using mozilla::dom::Promise;
using mozilla::dom::PromiseNativeHandler;
using mozilla::dom::workers::exceptions::ThrowDOMExceptionForNSResult;
using mozilla::ErrorResult;
using mozilla::ipc::PrincipalInfo;
using mozilla::UniquePtr;
@ -151,13 +150,6 @@ ChannelFromScriptURL(nsIPrincipal* principal,
return NS_ERROR_DOM_SECURITY_ERR;
}
} else if (aIsMainScript) {
// If this script loader is being used to make a new worker then we need
// to do a same-origin check. Otherwise we need to clear the load with the
// security manager.
nsCString scheme;
rv = uri->GetScheme(scheme);
NS_ENSURE_SUCCESS(rv, rv);
// We pass true as the 3rd argument to checkMayLoad here.
// This allows workers in sandboxed documents to load data URLs
// (and other URLs that inherit their principal from their
@ -283,6 +275,8 @@ struct ScriptLoadInfo
CacheStatus mCacheStatus;
Maybe<bool> mMutedErrorFlag;
bool Finished() const
{
return mLoadingFinished && !mCachePromise && !mChannel;
@ -955,12 +949,33 @@ private:
NS_ASSERTION(aString, "This should never be null!");
// Make sure we're not seeing the result of a 404 or something by checking
// the 'requestSucceeded' attribute on the http channel.
nsCOMPtr<nsIRequest> request;
nsresult rv = aLoader->GetRequest(getter_AddRefs(request));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
MOZ_ASSERT(channel);
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
NS_ASSERTION(ssm, "Should never be null!");
nsCOMPtr<nsIPrincipal> channelPrincipal;
rv = ssm->GetChannelResultPrincipal(channel, getter_AddRefs(channelPrincipal));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsIPrincipal* principal = mWorkerPrivate->GetPrincipal();
if (!principal) {
WorkerPrivate* parentWorker = mWorkerPrivate->GetParent();
MOZ_ASSERT(parentWorker, "Must have a parent!");
principal = parentWorker->GetPrincipal();
}
aLoadInfo.mMutedErrorFlag.emplace(principal->Subsumes(channelPrincipal));
// Make sure we're not seeing the result of a 404 or something by checking
// the 'requestSucceeded' attribute on the http channel.
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(request);
if (httpChannel) {
bool requestSucceeded;
@ -996,9 +1011,6 @@ private:
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
NS_ASSERTION(channel, "This should never fail!");
// Figure out what we actually loaded.
nsCOMPtr<nsIURI> finalURI;
rv = NS_GetFinalChannelURI(channel, getter_AddRefs(finalURI));
@ -1104,6 +1116,18 @@ private:
ScriptLoadInfo& loadInfo = mLoadInfos[aIndex];
MOZ_ASSERT(loadInfo.mCacheStatus == ScriptLoadInfo::Cached);
nsCOMPtr<nsIPrincipal> responsePrincipal =
PrincipalInfoToPrincipal(*aPrincipalInfo);
nsIPrincipal* principal = mWorkerPrivate->GetPrincipal();
if (!principal) {
WorkerPrivate* parentWorker = mWorkerPrivate->GetParent();
MOZ_ASSERT(parentWorker, "Must have a parent!");
principal = parentWorker->GetPrincipal();
}
loadInfo.mMutedErrorFlag.emplace(principal->Subsumes(responsePrincipal));
// May be null.
nsIDocument* parentDoc = mWorkerPrivate->GetDocument();
@ -1126,8 +1150,6 @@ private:
nsILoadGroup* loadGroup = mWorkerPrivate->GetLoadGroup();
MOZ_ASSERT(loadGroup);
nsCOMPtr<nsIPrincipal> responsePrincipal =
PrincipalInfoToPrincipal(*aPrincipalInfo);
mozilla::DebugOnly<bool> equal = false;
MOZ_ASSERT(responsePrincipal && NS_SUCCEEDED(responsePrincipal->Equals(principal, &equal)));
MOZ_ASSERT(equal);
@ -1567,7 +1589,7 @@ CacheScriptLoader::OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aCont
return NS_OK;
}
class ChannelGetterRunnable final : public nsRunnable
class ChannelGetterRunnable final : public nsRunnable
{
WorkerPrivate* mParentWorker;
nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
@ -1720,6 +1742,9 @@ ScriptExecutorRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
options.setVersion(JSVERSION_LATEST);
}
MOZ_ASSERT(loadInfo.mMutedErrorFlag.isSome());
options.setMutedErrors(loadInfo.mMutedErrorFlag.valueOr(true));
JS::SourceBufferHolder srcBuf(loadInfo.mScriptTextBuf,
loadInfo.mScriptTextLength,
JS::SourceBufferHolder::GiveOwnership);

View File

@ -79,16 +79,19 @@ namespace {
class CancelChannelRunnable final : public nsRunnable
{
nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
const nsresult mStatus;
public:
explicit CancelChannelRunnable(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel)
CancelChannelRunnable(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
nsresult aStatus)
: mChannel(aChannel)
, mStatus(aStatus)
{
}
NS_IMETHOD Run()
{
MOZ_ASSERT(NS_IsMainThread());
nsresult rv = mChannel->Cancel();
nsresult rv = mChannel->Cancel(mStatus);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
@ -146,15 +149,17 @@ class RespondWithHandler final : public PromiseNativeHandler
nsMainThreadPtrHandle<nsIInterceptedChannel> mInterceptedChannel;
nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
RequestMode mRequestMode;
bool mIsClientRequest;
public:
NS_DECL_ISUPPORTS
RespondWithHandler(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker,
RequestMode aRequestMode)
RequestMode aRequestMode, bool aIsClientRequest)
: mInterceptedChannel(aChannel)
, mServiceWorker(aServiceWorker)
, mRequestMode(aRequestMode)
, mIsClientRequest(aIsClientRequest)
{
}
@ -162,7 +167,7 @@ public:
void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
void CancelRequest();
void CancelRequest(nsresult aStatus);
private:
~RespondWithHandler() {}
};
@ -192,7 +197,8 @@ void RespondWithCopyComplete(void* aClosure, nsresult aStatus)
data->mInternalResponse,
data->mWorkerChannelInfo);
} else {
event = new CancelChannelRunnable(data->mInterceptedChannel);
event = new CancelChannelRunnable(data->mInterceptedChannel,
NS_ERROR_INTERCEPTION_FAILED);
}
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(event)));
}
@ -200,20 +206,28 @@ void RespondWithCopyComplete(void* aClosure, nsresult aStatus)
class MOZ_STACK_CLASS AutoCancel
{
nsRefPtr<RespondWithHandler> mOwner;
nsresult mStatus;
public:
explicit AutoCancel(RespondWithHandler* aOwner)
: mOwner(aOwner)
, mStatus(NS_ERROR_INTERCEPTION_FAILED)
{
}
~AutoCancel()
{
if (mOwner) {
mOwner->CancelRequest();
mOwner->CancelRequest(mStatus);
}
}
void SetCancelStatus(nsresult aStatus)
{
MOZ_ASSERT(NS_FAILED(aStatus));
mStatus = aStatus;
}
void Reset()
{
mOwner = nullptr;
@ -246,17 +260,35 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValu
// security implications are not a complete disaster.
if (response->Type() == ResponseType::Opaque &&
!worker->OpaqueInterceptionEnabled()) {
autoCancel.SetCancelStatus(NS_ERROR_OPAQUE_INTERCEPTION_DISABLED);
return;
}
// Section 4.2, step 2.2 "If either response's type is "opaque" and request's
// mode is not "no-cors" or response's type is error, return a network error."
if (((response->Type() == ResponseType::Opaque) && (mRequestMode != RequestMode::No_cors)) ||
response->Type() == ResponseType::Error) {
// Section 4.2, step 2.2:
// If one of the following conditions is true, return a network error:
// * response's type is "error".
// * request's mode is not "no-cors" and response's type is "opaque".
// * request is a client request and response's type is neither "basic"
// nor "default".
if (response->Type() == ResponseType::Error) {
autoCancel.SetCancelStatus(NS_ERROR_INTERCEPTED_ERROR_RESPONSE);
return;
}
if (response->Type() == ResponseType::Opaque && mRequestMode != RequestMode::No_cors) {
autoCancel.SetCancelStatus(NS_ERROR_BAD_OPAQUE_INTERCEPTION_REQUEST_MODE);
return;
}
if (mIsClientRequest && response->Type() != ResponseType::Basic &&
response->Type() != ResponseType::Default) {
autoCancel.SetCancelStatus(NS_ERROR_CLIENT_REQUEST_OPAQUE_INTERCEPTION);
return;
}
if (NS_WARN_IF(response->BodyUsed())) {
autoCancel.SetCancelStatus(NS_ERROR_INTERCEPTED_USED_RESPONSE);
return;
}
@ -302,13 +334,14 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValu
void
RespondWithHandler::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
{
CancelRequest();
CancelRequest(NS_ERROR_INTERCEPTION_FAILED);
}
void
RespondWithHandler::CancelRequest()
RespondWithHandler::CancelRequest(nsresult aStatus)
{
nsCOMPtr<nsIRunnable> runnable = new CancelChannelRunnable(mInterceptedChannel);
nsCOMPtr<nsIRunnable> runnable =
new CancelChannelRunnable(mInterceptedChannel, aStatus);
NS_DispatchToMainThread(runnable);
}
@ -337,9 +370,11 @@ FetchEvent::RespondWith(const ResponseOrPromise& aArg, ErrorResult& aRv)
} else if (aArg.IsPromise()) {
promise = &aArg.GetAsPromise();
}
nsRefPtr<InternalRequest> ir = mRequest->GetInternalRequest();
mWaitToRespond = true;
nsRefPtr<RespondWithHandler> handler =
new RespondWithHandler(mChannel, mServiceWorker, mRequest->Mode());
new RespondWithHandler(mChannel, mServiceWorker, mRequest->Mode(),
ir->IsClientRequest());
promise->AppendNativeHandler(handler);
}

View File

@ -39,6 +39,7 @@
#include "mozilla/dom/indexedDB/IDBFactory.h"
#include "mozilla/dom/InternalHeaders.h"
#include "mozilla/dom/Navigator.h"
#include "mozilla/dom/NotificationEvent.h"
#include "mozilla/dom/PromiseNativeHandler.h"
#include "mozilla/dom/Request.h"
#include "mozilla/dom/RootedDictionary.h"
@ -2282,6 +2283,133 @@ ServiceWorkerManager::SendPushSubscriptionChangeEvent(const nsACString& aOriginA
#endif
}
class SendNotificationClickEventRunnable final : public WorkerRunnable
{
nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
const nsString mID;
const nsString mTitle;
const nsString mDir;
const nsString mLang;
const nsString mBody;
const nsString mTag;
const nsString mIcon;
const nsString mData;
const nsString mBehavior;
const nsString mScope;
public:
SendNotificationClickEventRunnable(
WorkerPrivate* aWorkerPrivate,
nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker,
const nsAString& aID,
const nsAString& aTitle,
const nsAString& aDir,
const nsAString& aLang,
const nsAString& aBody,
const nsAString& aTag,
const nsAString& aIcon,
const nsAString& aData,
const nsAString& aBehavior,
const nsAString& aScope)
: WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
, mServiceWorker(aServiceWorker)
, mID(aID)
, mTitle(aTitle)
, mDir(aDir)
, mLang(aLang)
, mBody(aBody)
, mTag(aTag)
, mIcon(aIcon)
, mData(aData)
, mBehavior(aBehavior)
, mScope(aScope)
{
AssertIsOnMainThread();
MOZ_ASSERT(aWorkerPrivate);
MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
}
bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
{
MOZ_ASSERT(aWorkerPrivate);
nsRefPtr<EventTarget> target = do_QueryObject(aWorkerPrivate->GlobalScope());
ErrorResult result;
nsRefPtr<Notification> notification =
Notification::ConstructFromFields(aWorkerPrivate->GlobalScope(), mID,
mTitle, mDir, mLang, mBody, mTag, mIcon,
mData, mScope, result);
if (NS_WARN_IF(result.Failed())) {
return false;
}
NotificationEventInit nei;
nei.mNotification = notification;
nei.mBubbles = false;
nei.mCancelable = true;
nsRefPtr<NotificationEvent> event =
NotificationEvent::Constructor(target, NS_LITERAL_STRING("notificationclick"), nei, result);
if (NS_WARN_IF(result.Failed())) {
return false;
}
event->SetTrusted(true);
nsRefPtr<Promise> waitUntilPromise =
DispatchExtendableEventOnWorkerScope(aCx, aWorkerPrivate->GlobalScope(), event);
if (waitUntilPromise) {
nsRefPtr<KeepAliveHandler> handler = new KeepAliveHandler(mServiceWorker);
waitUntilPromise->AppendNativeHandler(handler);
}
return true;
}
};
NS_IMETHODIMP
ServiceWorkerManager::SendNotificationClickEvent(const nsACString& aOriginSuffix,
const nsACString& aScope,
const nsAString& aID,
const nsAString& aTitle,
const nsAString& aDir,
const nsAString& aLang,
const nsAString& aBody,
const nsAString& aTag,
const nsAString& aIcon,
const nsAString& aData,
const nsAString& aBehavior)
{
OriginAttributes attrs;
if (!attrs.PopulateFromSuffix(aOriginSuffix)) {
return NS_ERROR_INVALID_ARG;
}
nsRefPtr<ServiceWorker> serviceWorker = CreateServiceWorkerForScope(attrs, aScope);
if (!serviceWorker) {
return NS_ERROR_FAILURE;
}
nsMainThreadPtrHandle<ServiceWorker> serviceWorkerHandle(
new nsMainThreadPtrHolder<ServiceWorker>(serviceWorker));
nsRefPtr<SendNotificationClickEventRunnable> r =
new SendNotificationClickEventRunnable(serviceWorker->GetWorkerPrivate(),
serviceWorkerHandle, aID, aTitle,
aDir, aLang, aBody, aTag, aIcon,
aData, aBehavior,
NS_ConvertUTF8toUTF16(aScope));
AutoJSAPI jsapi;
jsapi.Init();
if (NS_WARN_IF(!r->Dispatch(jsapi.cx()))) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
NS_IMETHODIMP
ServiceWorkerManager::GetReadyPromise(nsIDOMWindow* aWindow,
nsISupports** aPromise)

View File

@ -6,6 +6,7 @@
#include "ServiceWorkerRegistration.h"
#include "mozilla/dom/Notification.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseWorkerProxy.h"
#include "mozilla/dom/ServiceWorkerRegistrationBinding.h"
@ -595,6 +596,52 @@ ServiceWorkerRegistrationMainThread::Unregister(ErrorResult& aRv)
return promise.forget();
}
// Notification API extension.
already_AddRefed<Promise>
ServiceWorkerRegistrationMainThread::ShowNotification(JSContext* aCx,
const nsAString& aTitle,
const NotificationOptions& aOptions,
ErrorResult& aRv)
{
AssertIsOnMainThread();
MOZ_ASSERT(GetOwner());
nsCOMPtr<nsPIDOMWindow> window = GetOwner();
if (NS_WARN_IF(!window)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
if (NS_WARN_IF(!doc)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsRefPtr<workers::ServiceWorker> worker = GetActive();
if (!worker) {
aRv.ThrowTypeError(MSG_NO_ACTIVE_WORKER);
return nullptr;
}
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(window);
nsRefPtr<Promise> p =
Notification::ShowPersistentNotification(global,
mScope, aTitle, aOptions, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return p.forget();
}
already_AddRefed<Promise>
ServiceWorkerRegistrationMainThread::GetNotifications(const GetNotificationOptions& aOptions, ErrorResult& aRv)
{
AssertIsOnMainThread();
nsCOMPtr<nsPIDOMWindow> window = GetOwner();
return Notification::Get(window, aOptions, mScope, aRv);
}
already_AddRefed<PushManager>
ServiceWorkerRegistrationMainThread::GetPushManager(ErrorResult& aRv)
{
@ -1001,5 +1048,32 @@ WorkerListener::UpdateFound()
}
}
} // namespace dom
} // namespace mozilla
// Notification API extension.
already_AddRefed<Promise>
ServiceWorkerRegistrationWorkerThread::ShowNotification(JSContext* aCx,
const nsAString& aTitle,
const NotificationOptions& aOptions,
ErrorResult& aRv)
{
// Until Bug 1131324 exposes ServiceWorkerContainer on workers,
// ShowPersistentNotification() checks for valid active worker while it is
// also verifying scope so that we block the worker on the main thread only
// once.
nsRefPtr<Promise> p =
Notification::ShowPersistentNotification(mWorkerPrivate->GlobalScope(),
mScope, aTitle, aOptions, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return p.forget();
}
already_AddRefed<Promise>
ServiceWorkerRegistrationWorkerThread::GetNotifications(const GetNotificationOptions& aOptions, ErrorResult& aRv)
{
return Notification::WorkerGet(mWorkerPrivate, aOptions, mScope, aRv);
}
} // dom namespace
} // mozilla namespace

View File

@ -12,6 +12,9 @@
#include "mozilla/dom/ServiceWorkerCommon.h"
#include "mozilla/dom/workers/bindings/WorkerFeature.h"
// Support for Notification API extension.
#include "mozilla/dom/NotificationBinding.h"
class nsPIDOMWindow;
namespace mozilla {
@ -111,6 +114,16 @@ public:
JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
// Partial interface from Notification API.
already_AddRefed<Promise>
ShowNotification(JSContext* aCx,
const nsAString& aTitle,
const NotificationOptions& aOptions,
ErrorResult& aRv);
already_AddRefed<Promise>
GetNotifications(const GetNotificationOptions& aOptions, ErrorResult& aRv);
already_AddRefed<workers::ServiceWorker>
GetInstalling() override;
@ -190,6 +203,16 @@ public:
JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
// Partial interface from Notification API.
already_AddRefed<Promise>
ShowNotification(JSContext* aCx,
const nsAString& aTitle,
const NotificationOptions& aOptions,
ErrorResult& aRv);
already_AddRefed<Promise>
GetNotifications(const GetNotificationOptions& aOptions, ErrorResult& aRv);
already_AddRefed<workers::ServiceWorker>
GetInstalling() override;

View File

@ -208,6 +208,7 @@ public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServiceWorkerGlobalScope,
WorkerGlobalScope)
IMPL_EVENT_HANDLER(notificationclick)
ServiceWorkerGlobalScope(WorkerPrivate* aWorkerPrivate, const nsACString& aScope);

View File

@ -21,10 +21,12 @@ function runTests() {
return testFetchAppResource('test_custom_content_type',
'customContentType', 'text/html');
})
.then(testRedirectedResponse)
.then(testRedirectedHttpsResponse)
.then(testCachedRedirectedResponse)
.then(testCachedRedirectedHttpsResponse)
// XXX: Cross-origin interceptions without CORS result in opaque responses
// which are illegal for navigations like iframes. (bug 1183313)
//.then(testRedirectedResponse)
//.then(testRedirectedHttpsResponse)
//.then(testCachedRedirectedResponse)
//.then(testCachedRedirectedHttpsResponse)
.then(done);
}
</script>

View File

@ -93,6 +93,8 @@ support-files =
client_focus_worker.js
bug1151916_worker.js
bug1151916_driver.html
notificationclick.html
notificationclick.js
worker_updatefoundevent.js
worker_updatefoundevent2.js
updatefoundevent.html
@ -103,6 +105,11 @@ support-files =
periodic/register.html
periodic/wait_for_update.html
periodic/unregister.html
notification_constructor_error.js
notification_get_sw.js
notification/register.html
notification/listener.html
notification_alt/register.html
sanitize/frame.html
sanitize/register.html
sanitize/example_check_and_unregister.html
@ -217,6 +224,9 @@ skip-if = !debug
[test_request_context_xslt.html]
[test_scopes.html]
[test_sandbox_intercept.html]
[test_notificationclick.html]
[test_notification_constructor_error.html]
[test_notification_get.html]
[test_sanitize.html]
[test_sanitize_domain.html]
[test_service_worker_allowed.html]

View File

@ -0,0 +1,27 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1114554 - proxy to forward messages from SW to test</title>
<script class="testbody" type="text/javascript">
var testWindow = parent;
if (opener) {
testWindow = opener;
}
navigator.serviceWorker.onmessage = function(msg) {
// worker message;
testWindow.postMessage(msg.data, "*");
if (msg.data.type == 'finish') {
window.close();
}
};
</script>
</head>
<body>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<script>
function done() {
parent.callback();
}
navigator.serviceWorker.ready.then(done);
navigator.serviceWorker.register("../notification_get_sw.js", {scope: "."}).catch(function(e) {
dump("Registration failure " + e.message + "\n");
});
</script>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<script>
function done() {
parent.callback();
}
navigator.serviceWorker.ready.then(done);
navigator.serviceWorker.register("../notification_get_sw.js", {scope: "."}).catch(function(e) {
dump("Registration failure " + e.message + "\n");
});
</script>

View File

@ -0,0 +1 @@
new Notification("Hi there");

View File

@ -0,0 +1,49 @@
function postAll(data) {
self.clients.matchAll().then(function(clients) {
if (clients.length == 0) {
dump("***************** NO CLIENTS FOUND! Test messages are being lost *******************\n");
}
clients.forEach(function(client) {
client.postMessage(data);
});
});
}
function ok(a, msg) {
postAll({type: 'status', status: !!a, msg: a + ": " + msg });
}
function is(a, b, msg) {
postAll({type: 'status', status: a === b, msg: a + " === " + b + ": " + msg });
}
function done() {
postAll({type: 'finish'});
}
onmessage = function(e) {
dump("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% MESSAGE " + e.data + "\n");
var start;
if (e.data == 'create') {
start = registration.showNotification("This is a title");
} else {
start = Promise.resolve();
}
start.then(function() {
dump("CALLING getNotification\n");
registration.getNotifications().then(function(notifications) {
dump("RECD getNotification\n");
is(notifications.length, 1, "There should be one stored notification");
var notification = notifications[0];
if (!notification) {
done();
return;
}
ok(notification instanceof Notification, "Should be a Notification");
is(notification.title, "This is a title", "Title should match");
notification.close();
done();
});
});
}

View File

@ -0,0 +1,27 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1114554 - controlled page</title>
<script class="testbody" type="text/javascript">
var testWindow = parent;
if (opener) {
testWindow = opener;
}
navigator.serviceWorker.ready.then(function(swr) {
swr.showNotification("Hi there. The ServiceWorker should receive a click event for this.");
});
navigator.serviceWorker.onmessage = function(msg) {
testWindow.callback();
};
</script>
</head>
<body>
</body>
</html>

View File

@ -0,0 +1,15 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/publicdomain/zero/1.0/
//
onnotificationclick = function(e) {
self.clients.matchAll().then(function(clients) {
if (clients.length === 0) {
dump("********************* CLIENTS LIST EMPTY! Test will timeout! ***********************\n");
return;
}
clients.forEach(function(client) {
client.postMessage("done");
});
});
}

View File

@ -0,0 +1,52 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Bug XXXXXXX - Check that Notification constructor throws in ServiceWorkerGlobalScope</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/dom/tests/mochitest/notification/MockServices.js"></script>
<script type="text/javascript" src="/tests/dom/tests/mochitest/notification/NotificationTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script class="testbody" type="text/javascript">
function simpleRegister() {
return navigator.serviceWorker.register("notification_constructor_error.js", { scope: "notification_constructor_error/" }).then(function(swr) {
ok(false, "Registration should fail.");
}, function(e) {
ok(e.message.indexOf("Notification") != -1, "Registration should fail.");
});
}
function runTest() {
MockServices.register();
simpleRegister()
.then(function() {
MockServices.unregister();
SimpleTest.finish();
}).catch(function(e) {
ok(false, "Some test failed with error " + e);
MockServices.unregister();
SimpleTest.finish();
});
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true],
["notification.prompt.testing", true],
]}, runTest);
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,164 @@
<!DOCTYPE HTML>
<html>
<head>
<title>ServiceWorkerRegistration.getNotifications() on main thread and worker thread.</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/dom/tests/mochitest/notification/MockServices.js"></script>
<script type="text/javascript" src="/tests/dom/tests/mochitest/notification/NotificationTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script type="text/javascript">
SimpleTest.requestFlakyTimeout("untriaged");
function testFrame(src) {
return new Promise(function(resolve, reject) {
var iframe = document.createElement("iframe");
iframe.src = src;
window.callback = function(result) {
iframe.src = "about:blank";
document.body.removeChild(iframe);
iframe = null;
SpecialPowers.exactGC(window, function() {
resolve(result);
});
};
document.body.appendChild(iframe);
});
}
function registerSW() {
return testFrame('notification/register.html').then(function() {
ok(true, "Registered service worker.");
});
}
// To check that the scope is respected when retrieving notifications.
function registerAlternateSWAndAddNotification() {
return testFrame('notification_alt/register.html').then(function() {
ok(true, "Registered alternate service worker.");
return navigator.serviceWorker.getRegistration("./notification_alt/").then(function(reg) {
return reg.showNotification("This is a notification_alt");
});
});
}
function testGet() {
// Non persistent notifications will not show up in getNotification().
var n = new Notification("Scope does not match");
var options = NotificationTest.payload;
return navigator.serviceWorker.getRegistration("./notification/")
.then(function(reg) {
return reg.showNotification("This is a title", options)
.then(function() {
return reg;
});
}).then(function(reg) {
return registerAlternateSWAndAddNotification().then(function() {
return reg;
});
}).then(function(reg) {
return reg.getNotifications();
}).then(function(notifications) {
is(notifications.length, 1, "There should be one stored notification");
var notification = notifications[0];
ok(notification instanceof Notification, "Should be a Notification");
is(notification.title, "This is a title", "Title should match");
for (var key in options) {
if (key === "data") {
ok(NotificationTest.customDataMatches(notification.data),
"data property should match");
continue;
}
is(notification[key], options[key], key + " property should match");
}
notification.close();
}).then(function() {
return navigator.serviceWorker.getRegistration("./notification/").then(function(reg) {
return reg.getNotifications();
});
}).then(function(notifications) {
// Make sure closed notifications are no longer retrieved.
is(notifications.length, 0, "There should be no more stored notifications");
}).catch(function(e) {
ok(false, "Something went wrong " + e.message);
});
}
function testGetWorker() {
todo(false, "navigator.serviceWorker is not available on workers yet");
return Promise.resolve();
}
function waitForSWTests(reg, msg) {
return new Promise(function(resolve, reject) {
var content = document.getElementById("content");
iframe = document.createElement("iframe");
content.appendChild(iframe);
iframe.setAttribute('src', "notification/listener.html");
window.onmessage = function(e) {
if (e.data.type == 'status') {
ok(e.data.status, "Service worker test: " + e.data.msg);
} else if (e.data.type == 'finish') {
content.removeChild(iframe);
resolve();
}
}
iframe.onload = function(e) {
iframe.onload = null;
reg.active.postMessage(msg);
}
});
}
function testGetServiceWorker() {
return navigator.serviceWorker.getRegistration("./notification/")
.then(function(reg) {
return waitForSWTests(reg, 'create');
});
}
// Create a Notification here, make sure ServiceWorker sees it.
function testAcrossThreads() {
return navigator.serviceWorker.getRegistration("./notification/")
.then(function(reg) {
return reg.showNotification("This is a title")
.then(function() {
return reg;
});
}).then(function(reg) {
return waitForSWTests(reg, 'do-not-create');
});
}
SimpleTest.waitForExplicitFinish();
MockServices.register();
SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true],
["dom.webnotifications.workers.enabled", true],
["notification.prompt.testing", true],
]}, function() {
registerSW()
.then(testGet)
.then(testGetWorker)
.then(testGetServiceWorker)
.then(testAcrossThreads)
.then(function() {
MockServices.unregister();
SimpleTest.finish();
});
});
</script>
</body>
</html>

View File

@ -0,0 +1,56 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=916893
-->
<head>
<title>Bug 1114554 - Test ServiceWorkerGlobalScope.notificationclick event.</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/dom/tests/mochitest/notification/MockServices.js"></script>
<script type="text/javascript" src="/tests/dom/tests/mochitest/notification/NotificationTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1114554">Bug 1114554</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
<script type="text/javascript">
SimpleTest.requestFlakyTimeout("Mock alert service dispatches show and click events.");
function testFrame(src) {
var iframe = document.createElement("iframe");
iframe.src = src;
window.callback = function() {
window.callback = null;
document.body.removeChild(iframe);
iframe = null;
ok(true, "Got notificationclick event.");
MockServices.unregister();
SimpleTest.finish();
};
document.body.appendChild(iframe);
}
function runTest() {
MockServices.register();
testFrame('notificationclick.html');
navigator.serviceWorker.register("notificationclick.js", { scope: "notificationclick.html" }).then(function(reg) {
}, function(e) {
ok(false, "registration should have passed!");
});
};
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true],
["dom.webnotifications.workers.enabled", true],
["notification.prompt.testing", true],
]}, runTest);
</script>
</body>
</html>

View File

@ -158,6 +158,8 @@ var interfaceNamesInGlobalScope =
"MessagePort",
// IMPORTANT: Do not change this list without review from a DOM peer!
"Notification",
// IMPORTANT: Do not change this list without review from a DOM peer!
"NotificationEvent",
// IMPORTANT: Do not change this list without review from a DOM peer!
"Performance",
// IMPORTANT: Do not change this list without review from a DOM peer!

View File

@ -18,7 +18,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=916893
<pre id="test">
</pre>
<script type="text/javascript">
SimpleTest.requestFlakyTimeout("Mock alert service dispatches show event.");
SimpleTest.requestFlakyTimeout("Mock alert service dispatches show and click events.");
function runTest() {
MockServices.register();

View File

@ -944,8 +944,6 @@ XULDocument::AttributeChanged(nsIDocument* aDocument,
AddElementToRefMap(aElement);
}
nsresult rv;
// Synchronize broadcast listeners
if (mBroadcasterMap &&
CanBroadcast(aNameSpaceID, aAttribute)) {
@ -1012,8 +1010,10 @@ XULDocument::AttributeChanged(nsIDocument* aDocument,
if (!persist.IsEmpty()) {
// XXXldb This should check that it's a token, not just a substring.
if (persist.Find(nsDependentAtomString(aAttribute)) >= 0) {
rv = Persist(aElement, kNameSpaceID_None, aAttribute);
if (NS_FAILED(rv)) return;
nsContentUtils::AddScriptRunner(NS_NewRunnableMethodWithArgs
<nsIContent*, int32_t, nsIAtom*>
(this, &XULDocument::DoPersist, aElement, kNameSpaceID_None,
aAttribute));
}
}
}

View File

@ -298,6 +298,12 @@ protected:
nsresult
Persist(nsIContent* aElement, int32_t aNameSpaceID, nsIAtom* aAttribute);
// Just like Persist but ignores the return value so we can use it
// as a runnable method.
void DoPersist(nsIContent* aElement, int32_t aNameSpaceID, nsIAtom* aAttribute)
{
Persist(aElement, aNameSpaceID, aAttribute);
}
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;

View File

@ -1883,6 +1883,11 @@ gfxWindowsPlatform::InitD3D11Devices()
}
bool useWARP = false;
bool allowWARP = false;
if (IsWin8OrLater()) {
allowWARP = true;
}
nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
if (gfxInfo) {
@ -1906,7 +1911,7 @@ gfxWindowsPlatform::InitD3D11Devices()
}
}
useWARP = true;
useWARP = allowWARP;
}
}
}
@ -1942,7 +1947,7 @@ gfxWindowsPlatform::InitD3D11Devices()
if (!gfxPrefs::LayersD3D11DisableWARP()) {
return;
}
useWARP = true;
useWARP = allowWARP;
}
}
@ -1964,7 +1969,7 @@ gfxWindowsPlatform::InitD3D11Devices()
return;
}
useWARP = true;
useWARP = allowWARP;
adapter = nullptr;
}
@ -1974,7 +1979,7 @@ gfxWindowsPlatform::InitD3D11Devices()
return;
}
useWARP = true;
useWARP = allowWARP;
adapter = nullptr;
}

View File

@ -8154,7 +8154,7 @@ IonBuilder::getElemTryDense(bool* emitted, MDefinition* obj, MDefinition* index)
// Don't generate a fast path if there have been bounds check failures
// and this access might be on a sparse property.
if (ElementAccessHasExtraIndexedProperty(constraints(), obj) && failedBoundsCheck_) {
if (ElementAccessHasExtraIndexedProperty(this, obj) && failedBoundsCheck_) {
trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
return true;
}
@ -8188,7 +8188,7 @@ IonBuilder::getStaticTypedArrayObject(MDefinition* obj, MDefinition* index)
return nullptr;
}
if (ElementAccessHasExtraIndexedProperty(constraints(), obj)) {
if (ElementAccessHasExtraIndexedProperty(this, obj)) {
trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
return nullptr;
}
@ -8536,7 +8536,7 @@ IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType
// cannot hit another indexed property on the object or its prototypes.
bool readOutOfBounds =
types->hasType(TypeSet::UndefinedType()) &&
!ElementAccessHasExtraIndexedProperty(constraints(), obj);
!ElementAccessHasExtraIndexedProperty(this, obj);
MIRType knownType = MIRType_Value;
if (unboxedType == JSVAL_TYPE_MAGIC && barrier == BarrierKind::NoBarrier)
@ -9097,7 +9097,7 @@ IonBuilder::setElemTryDense(bool* emitted, MDefinition* object,
// Don't generate a fast path if there have been bounds check failures
// and this access might be on a sparse property.
if (ElementAccessHasExtraIndexedProperty(constraints(), object) && failedBoundsCheck_) {
if (ElementAccessHasExtraIndexedProperty(this, object) && failedBoundsCheck_) {
trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
return true;
}
@ -9163,7 +9163,7 @@ IonBuilder::setElemTryCache(bool* emitted, MDefinition* object,
// from them. If TI can guard that there are no indexed properties on the prototype
// chain, we know that we anen't missing any setters by overwriting the hole with
// another value.
bool guardHoles = ElementAccessHasExtraIndexedProperty(constraints(), object);
bool guardHoles = ElementAccessHasExtraIndexedProperty(this, object);
// Make sure the object being written to doesn't have copy on write elements.
const Class* clasp = object->resultTypeSet() ? object->resultTypeSet()->getKnownClass(constraints()) : nullptr;
@ -9199,7 +9199,7 @@ IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion,
// Writes which are on holes in the object do not have to bail out if they
// cannot hit another indexed property on the object or its prototypes.
bool writeOutOfBounds = !ElementAccessHasExtraIndexedProperty(constraints(), obj);
bool writeOutOfBounds = !ElementAccessHasExtraIndexedProperty(this, obj);
if (NeedsPostBarrier(info(), value))
current->add(MPostWriteBarrier::New(alloc(), obj, value));
@ -11068,7 +11068,7 @@ IonBuilder::getPropTryCache(bool* emitted, MDefinition* obj, PropertyName* name,
// reflect such possible values.
if (barrier != BarrierKind::TypeSet) {
BarrierKind protoBarrier =
PropertyReadOnPrototypeNeedsTypeBarrier(this, constraints(), obj, name, types);
PropertyReadOnPrototypeNeedsTypeBarrier(this, obj, name, types);
if (protoBarrier != BarrierKind::NoBarrier) {
MOZ_ASSERT(barrier <= protoBarrier);
barrier = protoBarrier;
@ -12373,7 +12373,7 @@ IonBuilder::jsop_in()
break;
}
if (ElementAccessHasExtraIndexedProperty(constraints(), obj))
if (ElementAccessHasExtraIndexedProperty(this, obj))
break;
return jsop_in_dense(obj, id, unboxedType);

View File

@ -649,7 +649,7 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode)
return InliningStatus_NotInlined;
}
if (ArrayPrototypeHasIndexedProperty(constraints(), script())) {
if (ArrayPrototypeHasIndexedProperty(this, script())) {
trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
return InliningStatus_NotInlined;
}
@ -791,7 +791,7 @@ IonBuilder::inlineArrayPush(CallInfo& callInfo)
return InliningStatus_NotInlined;
}
if (ArrayPrototypeHasIndexedProperty(constraints(), script())) {
if (ArrayPrototypeHasIndexedProperty(this, script())) {
trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
return InliningStatus_NotInlined;
}
@ -890,7 +890,7 @@ IonBuilder::inlineArrayConcat(CallInfo& callInfo)
}
// Watch out for indexed properties on the prototype.
if (ArrayPrototypeHasIndexedProperty(constraints(), script())) {
if (ArrayPrototypeHasIndexedProperty(this, script())) {
trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
return InliningStatus_NotInlined;
}
@ -1006,7 +1006,7 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo)
}
// Watch out for indexed properties on the prototype.
if (ArrayPrototypeHasIndexedProperty(constraints(), script())) {
if (ArrayPrototypeHasIndexedProperty(this, script())) {
trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
return InliningStatus_NotInlined;
}
@ -2127,7 +2127,7 @@ IonBuilder::inlineDefineDataProperty(CallInfo& callInfo)
MDefinition* id = callInfo.getArg(1);
MDefinition* value = callInfo.getArg(2);
if (ElementAccessHasExtraIndexedProperty(constraints(), obj))
if (ElementAccessHasExtraIndexedProperty(this, obj))
return InliningStatus_NotInlined;
// setElemTryDense will push the value as the result of the define instead

View File

@ -4884,15 +4884,14 @@ jit::ElementAccessMightBeCopyOnWrite(CompilerConstraintList* constraints, MDefin
}
bool
jit::ElementAccessHasExtraIndexedProperty(CompilerConstraintList* constraints,
MDefinition* obj)
jit::ElementAccessHasExtraIndexedProperty(IonBuilder* builder, MDefinition* obj)
{
TemporaryTypeSet* types = obj->resultTypeSet();
if (!types || types->hasObjectFlags(constraints, OBJECT_FLAG_LENGTH_OVERFLOW))
if (!types || types->hasObjectFlags(builder->constraints(), OBJECT_FLAG_LENGTH_OVERFLOW))
return true;
return TypeCanHaveExtraIndexedProperties(constraints, types);
return TypeCanHaveExtraIndexedProperties(builder, types);
}
MIRType
@ -5056,7 +5055,6 @@ jit::PropertyReadNeedsTypeBarrier(JSContext* propertycx,
BarrierKind
jit::PropertyReadOnPrototypeNeedsTypeBarrier(IonBuilder* builder,
CompilerConstraintList* constraints,
MDefinition* obj, PropertyName* name,
TemporaryTypeSet* observed)
{
@ -5074,13 +5072,14 @@ jit::PropertyReadOnPrototypeNeedsTypeBarrier(IonBuilder* builder,
if (!key)
continue;
while (true) {
if (!key->hasStableClassAndProto(constraints))
if (!key->hasStableClassAndProto(builder->constraints()))
return BarrierKind::TypeSet;
if (!key->proto().isObject())
break;
JSObject* proto = builder->checkNurseryObject(key->proto().toObject());
key = TypeSet::ObjectKey::get(proto);
BarrierKind kind = PropertyReadNeedsTypeBarrier(constraints, key, name, observed);
BarrierKind kind = PropertyReadNeedsTypeBarrier(builder->constraints(),
key, name, observed);
if (kind == BarrierKind::TypeSet)
return BarrierKind::TypeSet;
@ -5164,6 +5163,58 @@ jit::AddObjectsForPropertyRead(MDefinition* obj, PropertyName* name,
}
}
static bool
PrototypeHasIndexedProperty(IonBuilder* builder, JSObject* obj)
{
do {
TypeSet::ObjectKey* key = TypeSet::ObjectKey::get(builder->checkNurseryObject(obj));
if (ClassCanHaveExtraProperties(key->clasp()))
return true;
if (key->unknownProperties())
return true;
HeapTypeSetKey index = key->property(JSID_VOID);
if (index.nonData(builder->constraints()) || index.isOwnProperty(builder->constraints()))
return true;
obj = obj->getProto();
} while (obj);
return false;
}
// Whether Array.prototype, or an object on its proto chain, has an indexed property.
bool
jit::ArrayPrototypeHasIndexedProperty(IonBuilder* builder, JSScript* script)
{
if (JSObject* proto = script->global().maybeGetArrayPrototype())
return PrototypeHasIndexedProperty(builder, proto);
return true;
}
// Whether obj or any of its prototypes have an indexed property.
bool
jit::TypeCanHaveExtraIndexedProperties(IonBuilder* builder, TemporaryTypeSet* types)
{
const Class* clasp = types->getKnownClass(builder->constraints());
// Note: typed arrays have indexed properties not accounted for by type
// information, though these are all in bounds and will be accounted for
// by JIT paths.
if (!clasp || (ClassCanHaveExtraProperties(clasp) && !IsAnyTypedArrayClass(clasp)))
return true;
if (types->hasObjectFlags(builder->constraints(), OBJECT_FLAG_SPARSE_INDEXES))
return true;
JSObject* proto;
if (!types->getCommonPrototype(builder->constraints(), &proto))
return true;
if (!proto)
return false;
return PrototypeHasIndexedProperty(builder, proto);
}
static bool
PropertyTypeIncludes(TempAllocator& alloc, HeapTypeSetKey property,
MDefinition* value, MIRType implicitType)

View File

@ -13719,8 +13719,7 @@ bool ElementAccessIsAnyTypedArray(CompilerConstraintList* constraints,
Scalar::Type* arrayType);
bool ElementAccessIsPacked(CompilerConstraintList* constraints, MDefinition* obj);
bool ElementAccessMightBeCopyOnWrite(CompilerConstraintList* constraints, MDefinition* obj);
bool ElementAccessHasExtraIndexedProperty(CompilerConstraintList* constraints,
MDefinition* obj);
bool ElementAccessHasExtraIndexedProperty(IonBuilder* builder, MDefinition* obj);
MIRType DenseNativeElementType(CompilerConstraintList* constraints, MDefinition* obj);
BarrierKind PropertyReadNeedsTypeBarrier(JSContext* propertycx,
CompilerConstraintList* constraints,
@ -13731,7 +13730,6 @@ BarrierKind PropertyReadNeedsTypeBarrier(JSContext* propertycx,
MDefinition* obj, PropertyName* name,
TemporaryTypeSet* observed);
BarrierKind PropertyReadOnPrototypeNeedsTypeBarrier(IonBuilder* builder,
CompilerConstraintList* constraints,
MDefinition* obj, PropertyName* name,
TemporaryTypeSet* observed);
bool PropertyReadIsIdempotent(CompilerConstraintList* constraints,
@ -13745,6 +13743,8 @@ bool PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, CompilerConstraintList*
MBasicBlock* current, MDefinition** pobj,
PropertyName* name, MDefinition** pvalue,
bool canModify, MIRType implicitType = MIRType_None);
bool ArrayPrototypeHasIndexedProperty(IonBuilder* builder, JSScript* script);
bool TypeCanHaveExtraIndexedProperties(IonBuilder* builder, TemporaryTypeSet* types);
} // namespace jit
} // namespace js

View File

@ -2829,6 +2829,19 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
void compareExchange32(const T& mem, Register oldval, Register newval, Register output) {
compareExchange(4, false, mem, oldval, newval, output);
}
template <typename T>
void atomicExchange32(const T& mem, Register value, Register output) {
MOZ_CRASH("atomicExchang32");
}
template <typename T>
void atomicExchange8ZeroExtend(const T& mem, Register value, Register output) {
MOZ_CRASH("atomicExchange8ZeroExtend");
}
template <typename T>
void atomicExchange8SignExtend(const T& mem, Register value, Register output) {
MOZ_CRASH("atomicExchange8SignExtend");
}
template <typename T, typename S>
void atomicFetchAdd8SignExtend(const S& value, const T& mem, Register temp, Register output) {
@ -2864,6 +2877,15 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
atomicEffectOp(4, AtomicFetchAddOp, value, mem);
}
template <typename T>
void atomicExchange16ZeroExtend(const T& mem, Register value, Register output) {
MOZ_CRASH("atomicExchange16ZeroExtend");
}
template <typename T>
void atomicExchange16SignExtend(const T& mem, Register value, Register output) {
MOZ_CRASH("atomicExchange16SignExtend");
}
template <typename T, typename S>
void atomicFetchSub8SignExtend(const S& value, const T& mem, Register temp, Register output) {
atomicFetchOp(1, true, AtomicFetchSubOp, value, mem, temp, output);
@ -3003,6 +3025,10 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
// Emit a BLR or NOP instruction. ToggleCall can be used to patch
// this instruction.
CodeOffsetLabel toggledCall(JitCode* target, bool enabled) {
// The returned offset must be to the first instruction generated,
// for the debugger to match offset with Baseline's pcMappingEntries_.
BufferOffset offset = nextOffset();
// TODO: Random pool insertion between instructions below is terrible.
// Unfortunately, we can't forbid pool prevention, because we're trying
// to add an entry to a pool. So as a temporary fix, just flush the pool
@ -3012,7 +3038,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
syncStackPtr();
BufferOffset offset = nextOffset();
BufferOffset loadOffset;
{
vixl::UseScratchRegisterScope temps(this);

View File

@ -2449,57 +2449,6 @@ js::ClassCanHaveExtraProperties(const Class* clasp)
|| IsAnyTypedArrayClass(clasp);
}
static bool
PrototypeHasIndexedProperty(CompilerConstraintList* constraints, JSObject* obj)
{
do {
TypeSet::ObjectKey* key = TypeSet::ObjectKey::get(obj);
if (ClassCanHaveExtraProperties(key->clasp()))
return true;
if (key->unknownProperties())
return true;
HeapTypeSetKey index = key->property(JSID_VOID);
if (index.nonData(constraints) || index.isOwnProperty(constraints))
return true;
obj = obj->getProto();
} while (obj);
return false;
}
bool
js::ArrayPrototypeHasIndexedProperty(CompilerConstraintList* constraints, JSScript* script)
{
if (JSObject* proto = script->global().maybeGetArrayPrototype())
return PrototypeHasIndexedProperty(constraints, proto);
return true;
}
bool
js::TypeCanHaveExtraIndexedProperties(CompilerConstraintList* constraints,
TemporaryTypeSet* types)
{
const Class* clasp = types->getKnownClass(constraints);
// Note: typed arrays have indexed properties not accounted for by type
// information, though these are all in bounds and will be accounted for
// by JIT paths.
if (!clasp || (ClassCanHaveExtraProperties(clasp) && !IsAnyTypedArrayClass(clasp)))
return true;
if (types->hasObjectFlags(constraints, OBJECT_FLAG_SPARSE_INDEXES))
return true;
JSObject* proto;
if (!types->getCommonPrototype(constraints, &proto))
return true;
if (!proto)
return false;
return PrototypeHasIndexedProperty(constraints, proto);
}
void
TypeZone::processPendingRecompiles(FreeOp* fop, RecompileInfoVector& recompiles)
{

View File

@ -974,17 +974,6 @@ inline bool isInlinableCall(jsbytecode* pc);
bool
ClassCanHaveExtraProperties(const Class* clasp);
/*
* Whether Array.prototype, or an object on its proto chain, has an
* indexed property.
*/
bool
ArrayPrototypeHasIndexedProperty(CompilerConstraintList* constraints, JSScript* script);
/* Whether obj or any of its prototypes have an indexed property. */
bool
TypeCanHaveExtraIndexedProperties(CompilerConstraintList* constraints, TemporaryTypeSet* types);
/* Persistent type information for a script, retained across GCs. */
class TypeScript
{

View File

@ -1939,6 +1939,15 @@ js::TryConvertToUnboxedLayout(ExclusiveContext* cx, Shape* templateShape,
return true;
}
// Make sure that all properties on the template shape are property
// names, and not indexes.
for (Shape::Range<NoGC> r(templateShape); !r.empty(); r.popFront()) {
jsid id = r.front().propid();
uint32_t dummy;
if (!JSID_IS_ATOM(id) || JSID_TO_ATOM(id)->isIndex(&dummy))
return true;
}
layoutSize = ComputePlainObjectLayout(cx, templateShape, properties);
// The entire object must be allocatable inline.

View File

@ -11,7 +11,7 @@
if (report) {
opener.postMessage("callbackHappened", "*");
}
window.mozRequestAnimationFrame(g);
window.requestAnimationFrame(g);
}
g();

View File

@ -21,24 +21,22 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=569520
SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout("untriaged");
var startNow = Date.now();
var start = window.mozAnimationStartTime;
var start = window.performance.now();
var firstListenerArg;
var secondListenerArg;
var thirdListenerTime;
// callback arg is wallclock from mozRequestAnimationFrame
// callback arg is in the same timeline as performance.now()
function thirdListener(t) {
thirdListenerTime = t;
// They really shouldn't be more than 100ms apart, but we can get weird
// effects on slow machines. 5 minutes is our test timeout, though.
ok(Math.abs(startNow - start) <= 5 * 60 * 1000, "Bogus animation start time");
ok(secondListenerArg >= firstListenerArg, // callback args from consecutive unprefixed requestAnimationFrame
ok(secondListenerArg >= firstListenerArg, // callback args from consecutive requestAnimationFrame
"Second listener should fire after first listener");
ok(thirdListenerTime >= start, "Third listener should fire after start");
ok(thirdListenerTime >= secondListenerArg,
"Third listener should fire after second listener");
ok(firstListenerArg >= start, "First listener should fire after start");
SimpleTest.finish();
}
@ -46,7 +44,7 @@ function thirdListener(t) {
// callback arg is from requestAnimationFrame and comparable to performance.now()
function secondListener(t) {
secondListenerArg = t;
mozRequestAnimationFrame(thirdListener);
requestAnimationFrame(thirdListener);
}
function firstListener(t) {

View File

@ -21,24 +21,22 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=569520
SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout("untriaged");
var startNow = Date.now();
var start = window.mozAnimationStartTime;
var start = window.performance.now();
var firstListenerArg;
var secondListenerArg;
var thirdListenerTime;
// callback arg is wallclock from mozRequestAnimationFrame
// callback arg is in the same timeline as performance.now()
function thirdListener(t) {
thirdListenerTime = t;
// They really shouldn't be more than 100ms apart, but we can get weird
// effects on slow machines. 5 minutes is our test timeout, though.
ok(Math.abs(startNow - start) <= 5 * 60 * 1000, "Bogus animation start time");
ok(secondListenerArg >= firstListenerArg, // callback args from consecutive unprefixed requestAnimationFrame
ok(secondListenerArg >= firstListenerArg, // callback args from consecutive requestAnimationFrame
"Second listener should fire after first listener");
ok(thirdListenerTime >= start, "Third listener should fire after start");
ok(thirdListenerTime >= secondListenerArg,
"Third listener should fire after second listener");
ok(firstListenerArg >= start, "First listener should fire after start");
SimpleTest.finish();
}
@ -46,7 +44,7 @@ function thirdListener(t) {
// callback arg is from requestAnimationFrame and comparable to performance.now()
function secondListener(t) {
secondListenerArg = t;
mozRequestAnimationFrame(thirdListener);
requestAnimationFrame(thirdListener);
}
function firstListener(t) {

View File

@ -19,7 +19,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=607529
SimpleTest.waitForExplicitFinish();
/* General idea: Open a new window (needed because we don't bfcache
subframes) that uses mozRequestAnimationFrame, navigate it, navigate it
subframes) that uses requestAnimationFrame, navigate it, navigate it
back, and verify that the animations are still running. */
var doneOneLoad = false;

View File

@ -42,7 +42,7 @@ function onScroll() {
function doTest() {
window.getSelection().collapse(inner.firstChild, 0);
window.mozRequestAnimationFrame(onFrame);
window.requestAnimationFrame(onFrame);
d.onscroll = onScroll;
sendKey("DOWN");
}
@ -50,7 +50,7 @@ function doTest() {
function prepareTest() {
// Start the test after we've gotten at least one rAF callback, to make sure
// that rAF is no longer throttled. (See bug 1145439.)
window.mozRequestAnimationFrame(function() {
window.requestAnimationFrame(function() {
SpecialPowers.pushPrefEnv({"set":[[smoothScrollPref, false]]}, doTest);
});
}

View File

@ -48,7 +48,7 @@ function runTest() {
// Delay until next repaint in case stuff is asynchronous. Also
// take a trip through the event loop.
setTimeout(function() {
window.mozRequestAnimationFrame(function() {
window.requestAnimationFrame(function() {
is(sel.anchorNode, target.firstChild, "Should have selected 'target' text node");
is(sel.anchorOffset, 1, "Selection should have moved left one character");
// We should not have needed to scroll the caret into view

View File

@ -5,8 +5,6 @@ var property = "left";
var rfa = null;
if (window.requestAnimationFrame) {
rfa = requestAnimationFrame;
} else if (window.mozRequestAnimationFrame) {
rfa = mozRequestAnimationFrame;
} else if (window.webkitRequestAnimationFrame) {
rfa = webkitRequestAnimationFrame;
} else if (window.msRequestAnimationFrame) {

View File

@ -1,8 +1,6 @@
var rfa = null;
if (window.requestAnimationFrame) {
rfa = requestAnimationFrame;
} else if (window.mozRequestAnimationFrame) {
rfa = mozRequestAnimationFrame;
} else if (window.webkitRequestAnimationFrame) {
rfa = webkitRequestAnimationFrame;
} else if (window.msRequestAnimationFrame) {

View File

@ -5,8 +5,6 @@ var property = "top";
var rfa = null;
if (window.requestAnimationFrame) {
rfa = requestAnimationFrame;
} else if (window.mozRequestAnimationFrame) {
rfa = mozRequestAnimationFrame;
} else if (window.webkitRequestAnimationFrame) {
rfa = webkitRequestAnimationFrame;
} else if (window.msRequestAnimationFrame) {

View File

@ -89,13 +89,15 @@ InterceptedJARChannel::FinishSynthesizedResponse()
}
NS_IMETHODIMP
InterceptedJARChannel::Cancel()
InterceptedJARChannel::Cancel(nsresult aStatus)
{
MOZ_ASSERT(NS_FAILED(aStatus));
if (!mChannel) {
return NS_ERROR_FAILURE;
}
nsresult rv = mChannel->Cancel(NS_BINDING_ABORTED);
nsresult rv = mChannel->Cancel(aStatus);
NS_ENSURE_SUCCESS(rv, rv);
mResponseBody = nullptr;
mChannel = nullptr;

View File

@ -1022,7 +1022,7 @@ pref("dom.allow_scripts_to_close_windows", false);
pref("dom.disable_open_during_load", false);
pref("dom.popup_maximum", 20);
pref("dom.popup_allowed_events", "change click dblclick mouseup reset submit touchend");
pref("dom.popup_allowed_events", "change click dblclick mouseup notificationclick reset submit touchend");
pref("dom.disable_open_click_delay", 1000);
pref("dom.storage.enabled", true);

View File

@ -26,7 +26,7 @@ class ChannelInfo;
* which do not implement nsIChannel.
*/
[scriptable, uuid(f2c07a6b-366d-4ef4-85ab-a77f4bcb1646)]
[scriptable, uuid(1062c96a-d73c-4ad5-beb7-6e803e414973)]
interface nsIInterceptedChannel : nsISupports
{
/**
@ -59,7 +59,7 @@ interface nsIInterceptedChannel : nsISupports
* @return NS_ERROR_FAILURE if the response has already been synthesized or
* the original request has been instructed to continue.
*/
void cancel();
void cancel(in nsresult status);
/**
* The synthesized response body to be produced.

View File

@ -98,7 +98,7 @@ HttpChannelParent::ActorDestroy(ActorDestroyReason why)
// If this is an intercepted channel, we need to make sure that any resources are
// cleaned up to avoid leaks.
if (mInterceptedChannel) {
mInterceptedChannel->Cancel();
mInterceptedChannel->Cancel(NS_ERROR_INTERCEPTION_FAILED);
mInterceptedChannel = nullptr;
}
}

View File

@ -230,15 +230,17 @@ InterceptedChannelChrome::FinishSynthesizedResponse()
}
NS_IMETHODIMP
InterceptedChannelChrome::Cancel()
InterceptedChannelChrome::Cancel(nsresult aStatus)
{
MOZ_ASSERT(NS_FAILED(aStatus));
if (!mChannel) {
return NS_ERROR_FAILURE;
}
// we need to use AsyncAbort instead of Cancel since there's no active pump
// to cancel which will provide OnStart/OnStopRequest to the channel.
nsresult rv = mChannel->AsyncAbort(NS_BINDING_ABORTED);
nsresult rv = mChannel->AsyncAbort(aStatus);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
@ -335,15 +337,17 @@ InterceptedChannelContent::FinishSynthesizedResponse()
}
NS_IMETHODIMP
InterceptedChannelContent::Cancel()
InterceptedChannelContent::Cancel(nsresult aStatus)
{
MOZ_ASSERT(NS_FAILED(aStatus));
if (!mChannel) {
return NS_ERROR_FAILURE;
}
// we need to use AsyncAbort instead of Cancel since there's no active pump
// to cancel which will provide OnStart/OnStopRequest to the channel.
nsresult rv = mChannel->AsyncAbort(NS_BINDING_ABORTED);
nsresult rv = mChannel->AsyncAbort(aStatus);
NS_ENSURE_SUCCESS(rv, rv);
mChannel = nullptr;
mStreamListener = nullptr;

View File

@ -81,7 +81,7 @@ public:
NS_IMETHOD GetChannel(nsIChannel** aChannel) override;
NS_IMETHOD SynthesizeStatus(uint16_t aStatus, const nsACString& aReason) override;
NS_IMETHOD SynthesizeHeader(const nsACString& aName, const nsACString& aValue) override;
NS_IMETHOD Cancel() override;
NS_IMETHOD Cancel(nsresult aStatus) override;
NS_IMETHOD SetChannelInfo(mozilla::dom::ChannelInfo* aChannelInfo) override;
virtual void NotifyController() override;
@ -108,7 +108,7 @@ public:
NS_IMETHOD GetChannel(nsIChannel** aChannel) override;
NS_IMETHOD SynthesizeStatus(uint16_t aStatus, const nsACString& aReason) override;
NS_IMETHOD SynthesizeHeader(const nsACString& aName, const nsACString& aValue) override;
NS_IMETHOD Cancel() override;
NS_IMETHOD Cancel(nsresult aStatus) override;
NS_IMETHOD SetChannelInfo(mozilla::dom::ChannelInfo* aChannelInfo) override;
virtual void NotifyController() override;

View File

@ -188,7 +188,7 @@ add_test(function() {
// ensure that the intercepted channel can be cancelled
add_test(function() {
var chan = make_channel(URL + '/body', null, function(intercepted) {
intercepted.cancel();
intercepted.cancel(Cr.NS_BINDING_ABORTED);
});
chan.asyncOpen(new ChannelListener(run_next_test, null,
CL_EXPECT_FAILURE), null);

View File

@ -1082,7 +1082,7 @@
<p>Euro sign: €</p>
<script>
window.onload = function() {
window.mozRequestAnimationFrame(function() {
window.requestAnimationFrame(function() {
parent.document.documentElement.removeAttribute("class");
});
}

View File

@ -183,12 +183,12 @@ class chunk_by_slice(InstanceFilter):
# chunk will contain an equal number of enabled tests.
if self.this_chunk == 1:
start = 0
else:
elif start < len(chunk_tests):
start = tests.index(chunk_tests[start])
if self.this_chunk == self.total_chunks:
end = len(tests)
else:
elif end < len(chunk_tests):
end = tests.index(chunk_tests[end])
return (t for t in tests[start:end])

View File

@ -66,6 +66,15 @@ class ChunkBySlice(TestCase):
disabled = list(i for i in xrange(num_tests) if i % 4 == 0)
self.run_all_combos(num_tests=num_tests, disabled=disabled)
def test_two_times_more_chunks_than_tests(self):
# test case for bug 1182817
tests = self.generate_tests(5)
total_chunks = 10
for i in range(1, total_chunks + 1):
# ensure IndexError is not raised
chunk_by_slice(i, total_chunks)(tests, {})
class ChunkByDir(TestCase):
"""Test chunking related filters"""

View File

@ -7,3 +7,16 @@
[Basic type response could be loaded in the new window.]
expected: TIMEOUT
[CORS type response could not be loaded in the iframe.]
expected: FAIL
[Opaque type response could not be loaded in the iframe.]
expected: FAIL
[CORS type response could not be loaded in the new window.]
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1183162
expected: FAIL
[Opaque type response could not be loaded in the new window.]
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1183162
expected: FAIL

View File

@ -29,6 +29,7 @@ let ClickEventHandler = {
this._screenX = null;
this._screenY = null;
this._lastFrame = null;
this.autoscrollLoop = this.autoscrollLoop.bind(this);
Services.els.addSystemEventListener(global, "mousedown", this, true);
@ -142,9 +143,9 @@ let ClickEventHandler = {
this._screenY = event.screenY;
this._scrollErrorX = 0;
this._scrollErrorY = 0;
this._lastFrame = content.mozAnimationStartTime;
this._lastFrame = content.performance.now();
content.mozRequestAnimationFrame(this);
content.requestAnimationFrame(this.autoscrollLoop);
},
stopScroll: function() {
@ -211,11 +212,7 @@ let ClickEventHandler = {
this._scrollable.scrollLeft += actualScrollX;
this._scrollable.scrollTop += actualScrollY;
}
content.mozRequestAnimationFrame(this);
},
sample: function(timestamp) {
this.autoscrollLoop(timestamp);
content.requestAnimationFrame(this.autoscrollLoop);
},
handleEvent: function(event) {

View File

@ -43,7 +43,7 @@ function test()
var skipFrames = 1;
var checkScroll = function () {
if (skipFrames--) {
window.mozRequestAnimationFrame(checkScroll);
window.requestAnimationFrame(checkScroll);
return;
}
ok(elem.scrollTop == 0, "element should not have scrolled vertically");
@ -70,6 +70,6 @@ function test()
* so request and force redraws to get the chance to check for scrolling at
* all.
*/
window.mozRequestAnimationFrame(checkScroll);
window.requestAnimationFrame(checkScroll);
}
}

View File

@ -117,7 +117,7 @@ function test()
// although it also depends on acceleration, which here in this test
// should be > 1 due to how it synthesizes mouse events below.
if (timeCompensation < 5) {
window.mozRequestAnimationFrame(checkScroll);
window.requestAnimationFrame(checkScroll);
return;
}
@ -174,7 +174,7 @@ function test()
Services.prefs.clearUserPref("middlemouse.paste");
// Start checking for the scroll.
window.mozRequestAnimationFrame(checkScroll);
window.requestAnimationFrame(checkScroll);
}
waitForExplicitFinish();

View File

@ -44,7 +44,6 @@ var iswin = (navigator.platform.indexOf("Win") == 0);
function runTests()
{
var list = $("list");
list.focus();
// on Mac, up and cursor keys open the menu, but on other platforms, the
@ -92,8 +91,6 @@ function pressLetter()
function pressedAgain()
{
var list = $("list");
keyCheck(list, "T", iswin ? "2b" : 3, "letter pressed again");
SpecialPowers.setIntPref("ui.menu.incremental_search.timeout", 0); // prevent to timeout
keyCheck(list, "W", 2, "second letter pressed");
@ -103,8 +100,6 @@ function pressedAgain()
function differentPressed()
{
var list = $("list");
keyCheck(list, "O", 1, "different letter pressed");
if (gOpenPhase) {
@ -117,6 +112,11 @@ function differentPressed()
list.selectedItem = $("i1");
// Hide and show the list to avoid using any existing incremental key state.
list.hidden = true;
list.clientWidth;
list.hidden = false;
gShowPopup = true;
gOpenPhase = true;
@ -131,6 +131,8 @@ function differentPressed()
function tabAndScroll()
{
list = $("list");
if (navigator.platform.indexOf("Mac") == -1) {
$("button1").focus();
synthesizeKeyExpectEvent("VK_TAB", { }, list, "focus", "focus to menulist");
@ -193,7 +195,6 @@ function checkModifiers(event)
function checkEnter()
{
var list = $("list");
list.addEventListener("popuphidden", checkEnterWithModifiers, false);
list.addEventListener("command", checkModifiers, false);
list.open = true;
@ -204,7 +205,6 @@ function checkEnterWithModifiers()
{
is(gModifiers, 1, "modifiers checked when not set");
var list = $("list");
ok(!list.open, "list closed on enter press");
list.removeEventListener("popuphidden", checkEnterWithModifiers, false);
@ -218,7 +218,6 @@ function verifyPopupOnClose()
{
is(gModifiers, 2, "modifiers checked when set");
var list = $("list");
ok(!list.open, "list closed on enter press with modifiers");
list.removeEventListener("popuphidden", done, false);
@ -229,8 +228,6 @@ function verifyPopupOnClose()
function checkCursorNavigation()
{
var list = $("list2");
var commandEventsCount = 0;
list.addEventListener("command", event => {
is(event.target, list.selectedItem, "command event fired on selected item");

View File

@ -74,7 +74,7 @@
document.getAnonymousElementByAttribute(this, "anonid", "spacer");
var isLTR =
document.defaultView.getComputedStyle(this, null).direction == "ltr";
var startTime = window.mozAnimationStartTime;
var startTime = performance.now();
var self = this;
function nextStep(t) {
@ -83,7 +83,7 @@
if (!width) {
// Maybe we've been removed from the document.
if (self._alive)
mozRequestAnimationFrame(nextStep);
requestAnimationFrame(nextStep);
return;
}
@ -101,11 +101,11 @@
spacer.width = width;
spacer.left = width * position;
mozRequestAnimationFrame(nextStep);
requestAnimationFrame(nextStep);
} catch (e) {
}
}
mozRequestAnimationFrame(nextStep);
requestAnimationFrame(nextStep);
]]></body>
</method>

View File

@ -292,13 +292,13 @@
this.distance = distance;
this.startPos = this.scrollbox.scrollPosition;
this.duration = Math.min(1000, Math.round(50 * Math.sqrt(Math.abs(distance))));
this.startTime = window.mozAnimationStartTime;
this.startTime = window.performance.now();
if (!this.requestHandle)
this.requestHandle = window.mozRequestAnimationFrame(this);
this.requestHandle = window.requestAnimationFrame(this.sample.bind(this));
},
stop: function scrollAnim_stop() {
window.mozCancelAnimationFrame(this.requestHandle);
window.cancelAnimationFrame(this.requestHandle);
this.requestHandle = 0;
},
sample: function scrollAnim_handleEvent(timeStamp) {
@ -311,7 +311,7 @@
if (pos == 1)
this.scrollbox._stopSmoothScroll();
else
this.requestHandle = window.mozRequestAnimationFrame(this);
this.requestHandle = window.requestAnimationFrame(this.sample.bind(this));
}
})]]></field>
@ -677,12 +677,12 @@
scrollbox: this,
requestHandle: 0, /* 0 indicates there is no pending request */
start: function arrowSmoothScroll_start() {
this.lastFrameTime = window.mozAnimationStartTime;
this.lastFrameTime = window.performance.now();
if (!this.requestHandle)
this.requestHandle = window.mozRequestAnimationFrame(this);
this.requestHandle = window.requestAnimationFrame(this.sample.bind(this));
},
stop: function arrowSmoothScroll_stop() {
window.mozCancelAnimationFrame(this.requestHandle);
window.cancelAnimationFrame(this.requestHandle);
this.requestHandle = 0;
},
sample: function arrowSmoothScroll_handleEvent(timeStamp) {
@ -693,7 +693,7 @@
const scrollDelta = 0.5 * timePassed * scrollIndex;
this.scrollbox.scrollPosition += scrollDelta;
this.requestHandle = window.mozRequestAnimationFrame(this);
this.requestHandle = window.requestAnimationFrame(this.sample.bind(this));
}
})]]></field>

View File

@ -318,6 +318,21 @@
ERROR(NS_NET_STATUS_SENDING_TO, FAILURE(5)),
ERROR(NS_NET_STATUS_WAITING_FOR, FAILURE(10)),
ERROR(NS_NET_STATUS_RECEIVING_FROM, FAILURE(6)),
/* nsIInterceptedChannel */
/* Generic error for non-specific failures during service worker interception */
ERROR(NS_ERROR_INTERCEPTION_FAILED, FAILURE(100)),
/* Service worker intercepted with an opaque response while
dom.serviceWorkers.interception.opaque.enabled pref was set to false */
ERROR(NS_ERROR_OPAQUE_INTERCEPTION_DISABLED, FAILURE(101)),
/* Attempt to return opaque response for anything but "non-cors" request */
ERROR(NS_ERROR_BAD_OPAQUE_INTERCEPTION_REQUEST_MODE, FAILURE(102)),
/* Service worker intercepted with an error response */
ERROR(NS_ERROR_INTERCEPTED_ERROR_RESPONSE, FAILURE(103)),
/* Service worker intercepted with a response with bodyUsed set to true */
ERROR(NS_ERROR_INTERCEPTED_USED_RESPONSE, FAILURE(104)),
/* Service worker intercepted a client request with an opaque response */
ERROR(NS_ERROR_CLIENT_REQUEST_OPAQUE_INTERCEPTION, FAILURE(105)),
#undef MODULE