mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge inbound to m-c. a=merge
This commit is contained in:
commit
720cc70372
@ -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);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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]
|
||||
|
114
accessible/tests/mochitest/treeupdate/test_bug1100602.html
Normal file
114
accessible/tests/mochitest/treeupdate/test_bug1100602.html
Normal 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>
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
|
||||
window.mozRequestAnimationFrame(null);
|
||||
window.requestAnimationFrame(null);
|
||||
|
||||
</script>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
mozCancelRequestAnimationFrame(mozRequestAnimationFrame(function() {}));
|
||||
mozRequestAnimationFrame(function() {});
|
||||
cancelRequestAnimationFrame(requestAnimationFrame(function() {}));
|
||||
requestAnimationFrame(function() {});
|
||||
</script>
|
||||
|
@ -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,
|
||||
|
@ -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, ...);
|
||||
|
||||
/**
|
||||
|
@ -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.
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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',
|
||||
},
|
||||
|
@ -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.")
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
@ -62,7 +62,7 @@ function initGL(canvas) {
|
||||
}
|
||||
|
||||
function rAF(func) {
|
||||
var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame;
|
||||
var raf = window.requestAnimationFrame;
|
||||
raf(func);
|
||||
}
|
||||
|
||||
|
@ -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.");
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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
@ -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;
|
||||
|
26
dom/notification/NotificationEvent.cpp
Normal file
26
dom/notification/NotificationEvent.cpp
Normal 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
|
74
dom/notification/NotificationEvent.h
Normal file
74
dom/notification/NotificationEvent.h
Normal 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__ */
|
||||
|
@ -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,9 +231,13 @@ 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,
|
||||
Services.tm.currentThread.dispatch(
|
||||
callback.handle.bind(callback,
|
||||
notification.id,
|
||||
notification.title,
|
||||
notification.dir,
|
||||
notification.lang,
|
||||
@ -221,13 +245,16 @@ NotificationStorage.prototype = {
|
||||
notification.tag,
|
||||
notification.icon,
|
||||
notification.data,
|
||||
notification.mozbehavior);
|
||||
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); }
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
};
|
||||
|
26
dom/webidl/NotificationEvent.webidl
Normal file
26
dom/webidl/NotificationEvent.webidl
Normal 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;
|
||||
};
|
@ -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;
|
||||
|
@ -335,6 +335,7 @@ WEBIDL_FILES = [
|
||||
'NodeIterator.webidl',
|
||||
'NodeList.webidl',
|
||||
'Notification.webidl',
|
||||
'NotificationEvent.webidl',
|
||||
'NotifyPaintEvent.webidl',
|
||||
'OfflineAudioCompletionEvent.webidl',
|
||||
'OfflineAudioContext.webidl',
|
||||
|
@ -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);
|
||||
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
Binary file not shown.
@ -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>
|
||||
|
@ -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]
|
||||
|
27
dom/workers/test/serviceworkers/notification/listener.html
Normal file
27
dom/workers/test/serviceworkers/notification/listener.html
Normal 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>
|
11
dom/workers/test/serviceworkers/notification/register.html
Normal file
11
dom/workers/test/serviceworkers/notification/register.html
Normal 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>
|
@ -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>
|
@ -0,0 +1 @@
|
||||
new Notification("Hi there");
|
49
dom/workers/test/serviceworkers/notification_get_sw.js
Normal file
49
dom/workers/test/serviceworkers/notification_get_sw.js
Normal 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();
|
||||
});
|
||||
});
|
||||
}
|
27
dom/workers/test/serviceworkers/notificationclick.html
Normal file
27
dom/workers/test/serviceworkers/notificationclick.html
Normal 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>
|
15
dom/workers/test/serviceworkers/notificationclick.js
Normal file
15
dom/workers/test/serviceworkers/notificationclick.js
Normal 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");
|
||||
});
|
||||
});
|
||||
}
|
@ -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>
|
||||
|
164
dom/workers/test/serviceworkers/test_notification_get.html
Normal file
164
dom/workers/test/serviceworkers/test_notification_get.html
Normal 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>
|
56
dom/workers/test/serviceworkers/test_notificationclick.html
Normal file
56
dom/workers/test/serviceworkers/test_notificationclick.html
Normal 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>
|
@ -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!
|
||||
|
@ -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();
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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.
|
||||
|
@ -11,7 +11,7 @@
|
||||
if (report) {
|
||||
opener.postMessage("callbackHappened", "*");
|
||||
}
|
||||
window.mozRequestAnimationFrame(g);
|
||||
window.requestAnimationFrame(g);
|
||||
}
|
||||
g();
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -1082,7 +1082,7 @@
|
||||
<p>Euro sign: €</p>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
window.mozRequestAnimationFrame(function() {
|
||||
window.requestAnimationFrame(function() {
|
||||
parent.document.documentElement.removeAttribute("class");
|
||||
});
|
||||
}
|
||||
|
@ -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])
|
||||
|
||||
|
@ -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"""
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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");
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user