Merge mozilla-central and inbound

This commit is contained in:
Ed Morley 2013-09-17 15:30:21 +01:00
commit cdd4002812
318 changed files with 5809 additions and 1298 deletions

View File

@ -400,6 +400,8 @@ pref("dom.mozAlarms.enabled", true);
// SimplePush
pref("services.push.enabled", true);
// Debugging enabled.
pref("services.push.debug", false);
// Is the network connection allowed to be up?
// This preference should be used in UX to enable/disable push.
pref("services.push.connection.enabled", true);

View File

@ -8,6 +8,9 @@
const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
function test() {
// Linux debug test slaves are a bit slow at this test sometimes.
requestLongerTimeout(2);
let gTab, gDebuggee, gPanel, gDebugger;
let gEditor, gSources, gBreakpoints, gBreakpointsAdded, gBreakpointsRemoving;

View File

@ -8,7 +8,7 @@
const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gFrames;
let gFrames, gFramesScrollingInterval;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
@ -40,18 +40,21 @@ function performTest() {
"Should have reached the recurse limit.");
gDebugger.gThreadClient.resume(() => {
window.clearInterval(scrollingIntervalId);
window.clearInterval(gFramesScrollingInterval);
closeDebuggerAndFinish(gPanel);
});
});
});
let scrollingIntervalId = window.setInterval(() => {
gFramesScrollingInterval = window.setInterval(() => {
gFrames.widget._list.scrollByIndex(-1);
}, 100);
}
registerCleanupFunction(function() {
window.clearInterval(gFramesScrollingInterval);
gFramesScrollingInterval = null;
gTab = null;
gDebuggee = null;
gPanel = null;

View File

@ -652,3 +652,10 @@ pref("full-screen-api.content-only", true);
// the window, the window size doesn't change. This pref has no effect when
// running in actual Metro mode, as the widget will already be fullscreen then.
pref("full-screen-api.ignore-widgets", true);
// image visibility prefs.
// image visibility tries to only keep images near the viewport decoded instead
// of keeping all images decoded.
pref("layout.imagevisibility.enabled", true);
pref("layout.imagevisibility.numscrollportwidths", 1);
pref("layout.imagevisibility.numscrollportheights", 1);

View File

@ -9337,6 +9337,7 @@ export STLPORT_CPPFLAGS
export STLPORT_LDFLAGS
export STLPORT_LIBS
export JS_STANDALONE=no
export MOZ_LINKER
if ! test -e js; then
mkdir js

View File

@ -1687,8 +1687,7 @@ public:
*/
#define EVENT(name_, id_, type_, struct_) \
mozilla::dom::EventHandlerNonNull* GetOn##name_(); \
void SetOn##name_(mozilla::dom::EventHandlerNonNull* listener, \
mozilla::ErrorResult& error); \
void SetOn##name_(mozilla::dom::EventHandlerNonNull* listener); \
NS_IMETHOD GetOn##name_(JSContext *cx, JS::Value *vp); \
NS_IMETHOD SetOn##name_(JSContext *cx, const JS::Value &v);
#define TOUCH_EVENT EVENT

View File

@ -1852,6 +1852,7 @@ GK_ATOM(svgImageFrame, "SVGImageFrame")
GK_ATOM(svgInnerSVGFrame, "SVGInnerSVGFrame")
GK_ATOM(svgLinearGradientFrame, "SVGLinearGradientFrame")
GK_ATOM(svgMarkerFrame, "SVGMarkerFrame")
GK_ATOM(svgMarkerAnonChildFrame, "SVGMarkerAnonChildFrame")
GK_ATOM(svgMaskFrame, "SVGMaskFrame")
GK_ATOM(svgOuterSVGFrame, "SVGOuterSVGFrame")
GK_ATOM(svgOuterSVGAnonChildFrame, "SVGOuterSVGAnonChildFrame")

View File

@ -2188,14 +2188,11 @@ nsINode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
return elm ? elm->GetEventHandler(nsGkAtoms::on##name_, EmptyString()) \
: nullptr; \
} \
void nsINode::SetOn##name_(EventHandlerNonNull* handler, \
ErrorResult& error) { \
void nsINode::SetOn##name_(EventHandlerNonNull* handler) \
{ \
nsEventListenerManager *elm = GetListenerManager(true); \
if (elm) { \
error = elm->SetEventHandler(nsGkAtoms::on##name_, \
EmptyString(), handler); \
} else { \
error.Throw(NS_ERROR_OUT_OF_MEMORY); \
elm->SetEventHandler(nsGkAtoms::on##name_, EmptyString(), handler); \
} \
} \
NS_IMETHODIMP nsINode::GetOn##name_(JSContext *cx, JS::Value *vp) { \
@ -2210,9 +2207,8 @@ nsINode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
JS_ObjectIsCallable(cx, callable = &v.toObject())) { \
handler = new EventHandlerNonNull(callable); \
} \
ErrorResult rv; \
SetOn##name_(handler, rv); \
return rv.ErrorCode(); \
SetOn##name_(handler); \
return NS_OK; \
}
#define TOUCH_EVENT EVENT
#define DOCUMENT_ONLY_EVENT EVENT

View File

@ -70,6 +70,7 @@ public:
: mElement(aElement),
mLoading(true),
mIsInline(true),
mHasSourceMapURL(false),
mJSVersion(aVersion),
mLineNo(1),
mCORSMode(aCORSMode)
@ -93,9 +94,11 @@ public:
}
nsCOMPtr<nsIScriptElement> mElement;
bool mLoading; // Are we still waiting for a load to complete?
bool mIsInline; // Is the script inline or loaded?
nsString mScriptText; // Holds script for loaded scripts
bool mLoading; // Are we still waiting for a load to complete?
bool mIsInline; // Is the script inline or loaded?
bool mHasSourceMapURL; // Does the HTTP header have a source map url?
nsString mSourceMapURL; // Holds source map url for loaded scripts
nsString mScriptText; // Holds script for text loaded scripts
uint32_t mJSVersion;
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIPrincipal> mOriginPrincipal;
@ -944,6 +947,9 @@ nsScriptLoader::FillCompileOptionsForRequest(nsScriptLoadRequest *aRequest,
aOptions->setFileAndLine(aRequest->mURL.get(), aRequest->mLineNo);
aOptions->setVersion(JSVersion(aRequest->mJSVersion));
aOptions->setCompileAndGo(JS_IsGlobalObject(scopeChain));
if (aRequest->mHasSourceMapURL) {
aOptions->setSourceMapURL(aRequest->mSourceMapURL.get());
}
if (aRequest->mOriginPrincipal) {
aOptions->setOriginPrincipals(nsJSPrincipals::get(aRequest->mOriginPrincipal));
}
@ -1298,6 +1304,11 @@ nsScriptLoader::PrepareLoadedRequest(nsScriptLoadRequest* aRequest,
if (NS_SUCCEEDED(rv) && !requestSucceeded) {
return NS_ERROR_NOT_AVAILABLE;
}
nsAutoCString sourceMapURL;
httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("X-SourceMap"), sourceMapURL);
aRequest->mHasSourceMapURL = true;
aRequest->mSourceMapURL = NS_ConvertUTF8toUTF16(sourceMapURL);
}
nsCOMPtr<nsIChannel> channel = do_QueryInterface(req);

View File

@ -4,6 +4,9 @@
MOCHITEST_FILES = \
bug421622-referer.sjs \
nochrome_bug765993.html \
nochrome_bug765993.js \
nochrome_bug765993.js^headers^ \
$(NULL)
MOCHITEST_CHROME_FILES = \
@ -52,6 +55,7 @@ MOCHITEST_CHROME_FILES = \
test_document_register.xul \
frame_bug814638.xul \
test_bug914381.html \
test_bug765993.html \
$(NULL)
ifneq ($(MOZ_WIDGET_TOOLKIT),cocoa)

View File

@ -0,0 +1,3 @@
<!DOCTYPE HTML>
<html>
</html>

View File

@ -0,0 +1,4 @@
//@ sourceMappingURL=bar.js.map
// Define a single function to prevent script source from being gc'd
function foo() {}

View File

@ -0,0 +1 @@
X-SourceMap: foo.js.map

View File

@ -0,0 +1,62 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=765993
-->
<head>
<title>Test for Bug 765993</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=765993">Mozilla Bug 765993</a>
<style type="text/css">
#link1 a { -moz-user-select:none; }
</style>
<div id="link1"><a href="http://www.mozilla.org/">link1</a></div>
<div id="link2"><a href="http://www.mozilla.org/">link2</a></div>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 765993 **/
Components.utils.import("resource://gre/modules/jsdebugger.jsm");
addDebuggerToGlobal(this);
window.onload = function () {
SimpleTest.waitForExplicitFinish();
var iframe = document.createElement("iframe");
iframe.src = "http://mochi.test:8888/tests/content/base/test/chrome/nochrome_bug765993.html";
iframe.onload = function () {
var script = iframe.contentWindow.document.createElement("script");
script.src = "http://mochi.test:8888/tests/content/base/test/chrome/nochrome_bug765993.js";
script.onload = function () {
var dbg = new Debugger(iframe.contentWindow);
ok(dbg, "Should be able to create debugger");
var scripts = dbg.findScripts({
url: "http://mochi.test:8888/tests/content/base/test/chrome/nochrome_bug765993.js"
});
ok(scripts.length > 0, "Should be able to find script");
is(scripts[0].sourceMapURL, "foo.js.map");
SimpleTest.finish();
}
iframe.contentWindow.document.body.appendChild(script);
};
document.body.appendChild(iframe);
};
</script>
</pre>
</body>
</html>

View File

@ -74,7 +74,7 @@ protected:
EventHandlerNonNull* GetEventHandler(nsIAtom* aType,
const nsAString& aTypeString);
void SetEventHandler(nsIAtom* aType, const nsAString& aTypeString,
EventHandlerNonNull* aHandler, ErrorResult& rv);
EventHandlerNonNull* aHandler);
};
NS_DEFINE_STATIC_IID_ACCESSOR(EventTarget, NS_EVENTTARGET_IID)

View File

@ -32,25 +32,27 @@ EventTarget::GetEventHandler(nsIAtom* aType, const nsAString& aTypeString)
void
EventTarget::SetEventHandler(const nsAString& aType,
EventHandlerNonNull* aHandler,
ErrorResult& rv)
ErrorResult& aRv)
{
if (!StringBeginsWith(aType, NS_LITERAL_STRING("on"))) {
aRv.Throw(NS_ERROR_INVALID_ARG);
return;
}
if (NS_IsMainThread()) {
nsCOMPtr<nsIAtom> type = do_GetAtom(aType);
return SetEventHandler(type, EmptyString(), aHandler, rv);
SetEventHandler(type, EmptyString(), aHandler);
return;
}
return SetEventHandler(nullptr,
Substring(aType, 2), // Remove "on"
aHandler, rv);
SetEventHandler(nullptr,
Substring(aType, 2), // Remove "on"
aHandler);
}
void
EventTarget::SetEventHandler(nsIAtom* aType, const nsAString& aTypeString,
EventHandlerNonNull* aHandler,
ErrorResult& rv)
EventHandlerNonNull* aHandler)
{
rv = GetListenerManager(true)->SetEventHandler(aType,
aTypeString,
aHandler);
GetListenerManager(true)->SetEventHandler(aType, aTypeString, aHandler);
}
} // namespace dom

View File

@ -276,9 +276,8 @@ nsDOMEventTargetHelper::SetEventHandler(nsIAtom* aType,
JS_ObjectIsCallable(aCx, callable = &aValue.toObject())) {
handler = new EventHandlerNonNull(callable);
}
ErrorResult rv;
SetEventHandler(aType, EmptyString(), handler, rv);
return rv.ErrorCode();
SetEventHandler(aType, EmptyString(), handler);
return NS_OK;
}
void

View File

@ -174,15 +174,12 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsDOMEventTargetHelper,
} \
return GetEventHandler(nullptr, NS_LITERAL_STRING(#_event)); \
} \
inline void SetOn##_event(mozilla::dom::EventHandlerNonNull* aCallback, \
mozilla::ErrorResult& aRv) \
inline void SetOn##_event(mozilla::dom::EventHandlerNonNull* aCallback) \
{ \
if (NS_IsMainThread()) { \
SetEventHandler(nsGkAtoms::on##_event, EmptyString(), \
aCallback, aRv); \
SetEventHandler(nsGkAtoms::on##_event, EmptyString(), aCallback); \
} else { \
SetEventHandler(nullptr, NS_LITERAL_STRING(#_event), \
aCallback, aRv); \
SetEventHandler(nullptr, NS_LITERAL_STRING(#_event), aCallback); \
} \
}

View File

@ -573,19 +573,18 @@ nsEventListenerManager::FindEventHandler(uint32_t aEventType,
return nullptr;
}
nsresult
nsListenerStruct*
nsEventListenerManager::SetEventHandlerInternal(nsIScriptContext *aContext,
JS::Handle<JSObject*> aScopeObject,
nsIAtom* aName,
const nsAString& aTypeString,
const nsEventHandler& aHandler,
bool aPermitUntrustedEvents,
nsListenerStruct **aListenerStruct)
bool aPermitUntrustedEvents)
{
NS_ASSERTION((aContext && aScopeObject) || aHandler.HasEventHandler(),
"Must have one or the other!");
MOZ_ASSERT((aContext && aScopeObject) || aHandler.HasEventHandler(),
"Must have one or the other!");
MOZ_ASSERT(aName || !aTypeString.IsEmpty());
nsresult rv = NS_OK;
uint32_t eventType = nsContentUtils::GetEventId(aName);
nsListenerStruct* ls = FindEventHandler(eventType, aName, aTypeString);
@ -596,16 +595,14 @@ nsEventListenerManager::SetEventHandlerInternal(nsIScriptContext *aContext,
flags.mListenerIsJSListener = true;
nsCOMPtr<nsIJSEventListener> scriptListener;
rv = NS_NewJSEventListener(aContext, aScopeObject, mTarget, aName,
aHandler, getter_AddRefs(scriptListener));
NS_NewJSEventListener(aContext, aScopeObject, mTarget, aName,
aHandler, getter_AddRefs(scriptListener));
if (NS_SUCCEEDED(rv)) {
EventListenerHolder holder(scriptListener);
AddEventListenerInternal(holder, eventType, aName, aTypeString, flags,
true);
EventListenerHolder holder(scriptListener);
AddEventListenerInternal(holder, eventType, aName, aTypeString, flags,
true);
ls = FindEventHandler(eventType, aName, aTypeString);
}
ls = FindEventHandler(eventType, aName, aTypeString);
} else {
nsIJSEventListener* scriptListener = ls->GetJSListener();
MOZ_ASSERT(scriptListener,
@ -620,19 +617,13 @@ nsEventListenerManager::SetEventHandlerInternal(nsIScriptContext *aContext,
}
}
if (NS_SUCCEEDED(rv) && ls) {
// Set flag to indicate possible need for compilation later
ls->mHandlerIsString = !aHandler.HasEventHandler();
if (aPermitUntrustedEvents) {
ls->mFlags.mAllowUntrustedEvents = true;
}
*aListenerStruct = ls;
} else {
*aListenerStruct = nullptr;
// Set flag to indicate possible need for compilation later
ls->mHandlerIsString = !aHandler.HasEventHandler();
if (aPermitUntrustedEvents) {
ls->mFlags.mAllowUntrustedEvents = true;
}
return rv;
return ls;
}
nsresult
@ -758,10 +749,10 @@ nsEventListenerManager::SetEventHandler(nsIAtom *aName,
JS::Rooted<JSObject*> scope(context->GetNativeContext(),
global->GetGlobalJSObject());
nsListenerStruct *ls;
rv = SetEventHandlerInternal(context, scope, aName, EmptyString(),
nsEventHandler(), aPermitUntrustedEvents, &ls);
NS_ENSURE_SUCCESS(rv, rv);
nsListenerStruct* ls = SetEventHandlerInternal(context, scope, aName,
EmptyString(),
nsEventHandler(),
aPermitUntrustedEvents);
if (!aDeferCompilation) {
return CompileEventHandlerInternal(ls, true, &aBody);
@ -1229,60 +1220,54 @@ nsEventListenerManager::HasUnloadListeners()
return false;
}
nsresult
void
nsEventListenerManager::SetEventHandler(nsIAtom* aEventName,
const nsAString& aTypeString,
EventHandlerNonNull* aHandler)
{
if (!aHandler) {
RemoveEventHandler(aEventName, aTypeString);
return NS_OK;
return;
}
// Untrusted events are always permitted for non-chrome script
// handlers.
nsListenerStruct *ignored;
return SetEventHandlerInternal(nullptr, JS::NullPtr(), aEventName,
aTypeString, nsEventHandler(aHandler),
!mIsMainThreadELM ||
!nsContentUtils::IsCallerChrome(),
&ignored);
SetEventHandlerInternal(nullptr, JS::NullPtr(), aEventName,
aTypeString, nsEventHandler(aHandler),
!mIsMainThreadELM ||
!nsContentUtils::IsCallerChrome());
}
nsresult
void
nsEventListenerManager::SetEventHandler(OnErrorEventHandlerNonNull* aHandler)
{
if (!aHandler) {
RemoveEventHandler(nsGkAtoms::onerror, EmptyString());
return NS_OK;
return;
}
// Untrusted events are always permitted for non-chrome script
// handlers.
nsListenerStruct *ignored;
return SetEventHandlerInternal(nullptr, JS::NullPtr(), nsGkAtoms::onerror,
EmptyString(), nsEventHandler(aHandler),
!mIsMainThreadELM ||
!nsContentUtils::IsCallerChrome(),
&ignored);
SetEventHandlerInternal(nullptr, JS::NullPtr(), nsGkAtoms::onerror,
EmptyString(), nsEventHandler(aHandler),
!mIsMainThreadELM ||
!nsContentUtils::IsCallerChrome());
}
nsresult
void
nsEventListenerManager::SetEventHandler(BeforeUnloadEventHandlerNonNull* aHandler)
{
if (!aHandler) {
RemoveEventHandler(nsGkAtoms::onbeforeunload, EmptyString());
return NS_OK;
return;
}
// Untrusted events are always permitted for non-chrome script
// handlers.
nsListenerStruct *ignored;
return SetEventHandlerInternal(nullptr, JS::NullPtr(), nsGkAtoms::onbeforeunload,
EmptyString(), nsEventHandler(aHandler),
!mIsMainThreadELM ||
!nsContentUtils::IsCallerChrome(),
&ignored);
SetEventHandlerInternal(nullptr, JS::NullPtr(), nsGkAtoms::onbeforeunload,
EmptyString(), nsEventHandler(aHandler),
!mIsMainThreadELM ||
!nsContentUtils::IsCallerChrome());
}
const nsEventHandler*

View File

@ -440,13 +440,12 @@ protected:
* allowed to be null. The nsListenerStruct that results, if any, is returned
* in aListenerStruct.
*/
nsresult SetEventHandlerInternal(nsIScriptContext *aContext,
JS::Handle<JSObject*> aScopeGlobal,
nsIAtom* aName,
const nsAString& aTypeString,
const nsEventHandler& aHandler,
bool aPermitUntrustedEvents,
nsListenerStruct **aListenerStruct);
nsListenerStruct* SetEventHandlerInternal(nsIScriptContext *aContext,
JS::Handle<JSObject*> aScopeGlobal,
nsIAtom* aName,
const nsAString& aTypeString,
const nsEventHandler& aHandler,
bool aPermitUntrustedEvents);
bool IsDeviceType(uint32_t aType);
void EnableDevice(uint32_t aType);
@ -457,11 +456,11 @@ public:
* Set the "inline" event listener for aEventName to aHandler. If
* aHandler is null, this will actually remove the event listener
*/
nsresult SetEventHandler(nsIAtom* aEventName,
const nsAString& aTypeString,
mozilla::dom::EventHandlerNonNull* aHandler);
nsresult SetEventHandler(mozilla::dom::OnErrorEventHandlerNonNull* aHandler);
nsresult SetEventHandler(mozilla::dom::BeforeUnloadEventHandlerNonNull* aHandler);
void SetEventHandler(nsIAtom* aEventName,
const nsAString& aTypeString,
mozilla::dom::EventHandlerNonNull* aHandler);
void SetEventHandler(mozilla::dom::OnErrorEventHandlerNonNull* aHandler);
void SetEventHandler(mozilla::dom::BeforeUnloadEventHandlerNonNull* aHandler);
/**
* Get the value of the "inline" event listener for aEventName.

View File

@ -502,9 +502,8 @@ HTMLBodyElement::IsEventAttributeName(nsIAtom *aName)
JS_ObjectIsCallable(cx, callable = &v.toObject())) { \
handler = new type_(callable); \
} \
ErrorResult rv; \
forwardto_::SetOn##name_(handler, rv); \
return rv.ErrorCode(); \
forwardto_::SetOn##name_(handler); \
return NS_OK; \
}
#define FORWARDED_EVENT(name_, id_, type_, struct_) \
FORWARDED_EVENT_HELPER(name_, nsGenericHTMLElement, EventHandlerNonNull, \
@ -525,7 +524,7 @@ HTMLBodyElement::IsEventAttributeName(nsIAtom *aName)
return nullptr; \
} \
void \
HTMLBodyElement::SetOn##name_(type_* handler, ErrorResult& error) \
HTMLBodyElement::SetOn##name_(type_* handler) \
{ \
nsPIDOMWindow* win = OwnerDoc()->GetInnerWindow(); \
if (!win) { \
@ -534,7 +533,7 @@ HTMLBodyElement::IsEventAttributeName(nsIAtom *aName)
\
nsCOMPtr<nsISupports> supports = do_QueryInterface(win); \
nsGlobalWindow* globalWin = nsGlobalWindow::FromSupports(supports); \
return globalWin->SetOn##name_(handler, error); \
return globalWin->SetOn##name_(handler); \
} \
FORWARDED_EVENT_HELPER(name_, HTMLBodyElement, type_, type_*)
#define WINDOW_EVENT(name_, id_, type_, struct_) \

View File

@ -60,7 +60,7 @@ public:
NS_IMETHOD SetOn##name_(JSContext *cx, const JS::Value &v);
#define WINDOW_EVENT_HELPER(name_, type_) \
type_* GetOn##name_(); \
void SetOn##name_(type_* handler, ErrorResult& error);
void SetOn##name_(type_* handler);
#define WINDOW_EVENT(name_, id_, type_, struct_) \
WINDOW_EVENT_HELPER(name_, EventHandlerNonNull)
#define BEFOREUNLOAD_EVENT(name_, id_, type_, struct_) \

View File

@ -361,9 +361,8 @@ HTMLFrameSetElement::IsEventAttributeName(nsIAtom *aName)
JS_ObjectIsCallable(cx, callable = &v.toObject())) { \
handler = new type_(callable); \
} \
ErrorResult rv; \
forwardto_::SetOn##name_(handler, rv); \
return rv.ErrorCode(); \
forwardto_::SetOn##name_(handler); \
return NS_OK; \
}
#define FORWARDED_EVENT(name_, id_, type_, struct_) \
FORWARDED_EVENT_HELPER(name_, nsGenericHTMLElement, EventHandlerNonNull, \
@ -384,7 +383,7 @@ HTMLFrameSetElement::IsEventAttributeName(nsIAtom *aName)
return nullptr; \
} \
void \
HTMLFrameSetElement::SetOn##name_(type_* handler, ErrorResult& error) \
HTMLFrameSetElement::SetOn##name_(type_* handler) \
{ \
nsPIDOMWindow* win = OwnerDoc()->GetInnerWindow(); \
if (!win) { \
@ -393,7 +392,7 @@ HTMLFrameSetElement::IsEventAttributeName(nsIAtom *aName)
\
nsCOMPtr<nsISupports> supports = do_QueryInterface(win); \
nsGlobalWindow* globalWin = nsGlobalWindow::FromSupports(supports); \
return globalWin->SetOn##name_(handler, error); \
return globalWin->SetOn##name_(handler); \
} \
FORWARDED_EVENT_HELPER(name_, HTMLFrameSetElement, type_, type_*)
#define WINDOW_EVENT(name_, id_, type_, struct_) \

View File

@ -90,7 +90,7 @@ public:
NS_IMETHOD SetOn##name_(JSContext *cx, const JS::Value &v);
#define WINDOW_EVENT_HELPER(name_, type_) \
type_* GetOn##name_(); \
void SetOn##name_(type_* handler, ErrorResult& error);
void SetOn##name_(type_* handler);
#define WINDOW_EVENT(name_, id_, type_, struct_) \
WINDOW_EVENT_HELPER(name_, EventHandlerNonNull)
#define BEFOREUNLOAD_EVENT(name_, id_, type_, struct_) \

View File

@ -6096,7 +6096,7 @@ HTMLInputElement::IsValidEmailAddressList(const nsAString& aValue)
}
}
return !tokenizer.lastTokenEndedWithSeparator();
return !tokenizer.separatorAfterCurrentToken();
}
//static

View File

@ -868,8 +868,7 @@ nsGenericHTMLElement::GetOn##name_() \
return nsINode::GetOn##name_(); \
} \
void \
nsGenericHTMLElement::SetOn##name_(EventHandlerNonNull* handler, \
ErrorResult& error) \
nsGenericHTMLElement::SetOn##name_(EventHandlerNonNull* handler) \
{ \
if (Tag() == nsGkAtoms::body || Tag() == nsGkAtoms::frameset) { \
nsPIDOMWindow* win = OwnerDoc()->GetInnerWindow(); \
@ -879,10 +878,10 @@ nsGenericHTMLElement::SetOn##name_(EventHandlerNonNull* handler, \
\
nsCOMPtr<nsISupports> supports = do_QueryInterface(win); \
nsGlobalWindow* globalWin = nsGlobalWindow::FromSupports(supports); \
return globalWin->SetOn##name_(handler, error); \
return globalWin->SetOn##name_(handler); \
} \
\
return nsINode::SetOn##name_(handler, error); \
return nsINode::SetOn##name_(handler); \
}
#define ERROR_EVENT(name_, id_, type_, struct_) \
already_AddRefed<EventHandlerNonNull> \
@ -908,8 +907,7 @@ nsGenericHTMLElement::GetOn##name_() \
return handler.forget(); \
} \
void \
nsGenericHTMLElement::SetOn##name_(EventHandlerNonNull* handler, \
ErrorResult& error) \
nsGenericHTMLElement::SetOn##name_(EventHandlerNonNull* handler) \
{ \
if (Tag() == nsGkAtoms::body || Tag() == nsGkAtoms::frameset) { \
nsPIDOMWindow* win = OwnerDoc()->GetInnerWindow(); \
@ -923,10 +921,10 @@ nsGenericHTMLElement::SetOn##name_(EventHandlerNonNull* handler, \
if (handler) { \
errorHandler = new OnErrorEventHandlerNonNull(handler); \
} \
return globalWin->SetOn##name_(errorHandler, error); \
return globalWin->SetOn##name_(errorHandler); \
} \
\
return nsINode::SetOn##name_(handler, error); \
return nsINode::SetOn##name_(handler); \
}
#include "nsEventNameList.h" // IWYU pragma: keep
#undef ERROR_EVENT

View File

@ -239,14 +239,12 @@ public:
using nsINode::GetOn##name_; \
using nsINode::SetOn##name_; \
mozilla::dom::EventHandlerNonNull* GetOn##name_(); \
void SetOn##name_(mozilla::dom::EventHandlerNonNull* handler, \
mozilla::ErrorResult& error);
void SetOn##name_(mozilla::dom::EventHandlerNonNull* handler);
#define ERROR_EVENT(name_, id_, type_, struct_) \
using nsINode::GetOn##name_; \
using nsINode::SetOn##name_; \
already_AddRefed<mozilla::dom::EventHandlerNonNull> GetOn##name_(); \
void SetOn##name_(mozilla::dom::EventHandlerNonNull* handler, \
mozilla::ErrorResult& error);
void SetOn##name_(mozilla::dom::EventHandlerNonNull* handler);
#include "nsEventNameList.h" // IWYU pragma: keep
#undef ERROR_EVENT
#undef FORWARDED_EVENT

View File

@ -15,6 +15,7 @@ namespace mozilla {
namespace dom {
struct ThreeDPoint;
class AudioParamTimeline;
class DelayNodeEngine;
}
class AudioNodeStream;
@ -201,6 +202,8 @@ public:
MOZ_COUNT_DTOR(AudioNodeEngine);
}
virtual dom::DelayNodeEngine* AsDelayNodeEngine() { return nullptr; }
virtual void SetStreamTimeParameter(uint32_t aIndex, TrackTicks aParam)
{
NS_ERROR("Invalid SetStreamTimeParameter index");

View File

@ -286,6 +286,20 @@ AudioNodeStream::ObtainInputBlock(AudioChunk& aTmpChunk, uint32_t aPortIndex)
a->IsAudioParamStream()) {
continue;
}
// It is possible for mLastChunks to be empty here, because `a` might be a
// AudioNodeStream that has not been scheduled yet, because it is further
// down the graph _but_ as a connection to this node. Because we enforce the
// presence of at least one DelayNode, with at least one block of delay, and
// because the output of a DelayNode when it has been fed less that
// `delayTime` amount of audio is silence, we can simply continue here,
// because this input would not influence the output of this node. Next
// iteration, a->mLastChunks.IsEmpty() will be false, and everthing will
// work as usual.
if (a->mLastChunks.IsEmpty()) {
continue;
}
AudioChunk* chunk = &a->mLastChunks[mInputs[i]->OutputNumber()];
MOZ_ASSERT(chunk);
if (chunk->IsNull() || chunk->mChannelData.IsEmpty()) {
@ -412,8 +426,7 @@ AudioNodeStream::ProduceOutput(GraphTime aFrom, GraphTime aTo)
uint16_t outputCount = std::max(uint16_t(1), mEngine->OutputCount());
mLastChunks.SetLength(outputCount);
if (mInCycle) {
// XXX DelayNode not supported yet so just produce silence
if (mMuted) {
for (uint16_t i = 0; i < outputCount; ++i) {
mLastChunks[i].SetNull(WEBAUDIO_BLOCK_SIZE);
}

View File

@ -21,6 +21,7 @@ namespace mozilla {
namespace dom {
struct ThreeDPoint;
class AudioParamTimeline;
class DelayNodeEngine;
}
class ThreadSharedFloatArrayBufferList;
@ -54,7 +55,8 @@ public:
mKind(aKind),
mNumberOfInputChannels(2),
mMarkAsFinishedAfterThisBlock(false),
mAudioParamStream(false)
mAudioParamStream(false),
mMuted(false)
{
MOZ_ASSERT(NS_IsMainThread());
mChannelCountMode = dom::ChannelCountMode::Max;
@ -103,6 +105,14 @@ public:
{
return mAudioParamStream;
}
void Mute() {
mMuted = true;
}
void Unmute() {
mMuted = false;
}
const OutputChunks& LastChunks() const
{
return mLastChunks;
@ -153,6 +163,8 @@ protected:
bool mMarkAsFinishedAfterThisBlock;
// Whether the stream is an AudioParamHelper stream.
bool mAudioParamStream;
// Whether the stream is muted. Access only on the MediaStreamGraph thread.
bool mMuted;
};
}

View File

@ -7,6 +7,7 @@
#include "AudioStream.h"
#include "AudioChannelFormat.h"
#include "Latency.h"
namespace mozilla {
@ -137,7 +138,7 @@ DownmixAndInterleave(const nsTArray<const void*>& aChannelData,
}
void
AudioSegment::WriteTo(AudioStream* aOutput)
AudioSegment::WriteTo(uint64_t aID, AudioStream* aOutput)
{
uint32_t outputChannels = aOutput->GetChannels();
nsAutoTArray<AudioDataValue,AUDIO_PROCESSING_FRAMES*GUESS_AUDIO_CHANNELS> buf;
@ -183,6 +184,9 @@ AudioSegment::WriteTo(AudioStream* aOutput)
memset(buf.Elements(), 0, buf.Length()*sizeof(AudioDataValue));
}
aOutput->Write(buf.Elements(), int32_t(duration));
if(!c.mTimeStamp.IsNull())
LogLatency(AsyncLatencyLogger::AudioMediaStreamTrack, aID,
(mozilla::TimeStamp::Now() - c.mTimeStamp).ToMilliseconds());
offset += duration;
}
}

View File

@ -9,6 +9,9 @@
#include "MediaSegment.h"
#include "AudioSampleFormat.h"
#include "SharedBuffer.h"
#ifdef MOZILLA_INTERNAL_API
#include "mozilla/TimeStamp.h"
#endif
namespace mozilla {
@ -102,6 +105,9 @@ struct AudioChunk {
nsTArray<const void*> mChannelData; // one pointer per channel; empty if and only if mBuffer is null
float mVolume; // volume multiplier to apply (1.0f if mBuffer is nonnull)
SampleFormat mBufferFormat; // format of frames in mBuffer (only meaningful if mBuffer is nonnull)
#ifdef MOZILLA_INTERNAL_API
mozilla::TimeStamp mTimeStamp; // time at which this has been fetched from the MediaEngine
#endif
};
/**
@ -125,6 +131,9 @@ public:
}
chunk->mVolume = 1.0f;
chunk->mBufferFormat = AUDIO_FORMAT_FLOAT32;
#ifdef MOZILLA_INTERNAL_API
chunk->mTimeStamp = TimeStamp::Now();
#endif
}
void AppendFrames(already_AddRefed<ThreadSharedObject> aBuffer,
const nsTArray<const int16_t*>& aChannelData,
@ -137,6 +146,9 @@ public:
}
chunk->mVolume = 1.0f;
chunk->mBufferFormat = AUDIO_FORMAT_S16;
#ifdef MOZILLA_INTERNAL_API
chunk->mTimeStamp = TimeStamp::Now();
#endif
}
// Consumes aChunk, and returns a pointer to the persistent copy of aChunk
// in the segment.
@ -147,10 +159,13 @@ public:
chunk->mChannelData.SwapElements(aChunk->mChannelData);
chunk->mVolume = aChunk->mVolume;
chunk->mBufferFormat = aChunk->mBufferFormat;
#ifdef MOZILLA_INTERNAL_API
chunk->mTimeStamp = TimeStamp::Now();
#endif
return chunk;
}
void ApplyVolume(float aVolume);
void WriteTo(AudioStream* aOutput);
void WriteTo(uint64_t aID, AudioStream* aOutput);
static Type StaticType() { return AUDIO; }
};

View File

@ -14,6 +14,7 @@
#include <algorithm>
#include "mozilla/Preferences.h"
#include "soundtouch/SoundTouch.h"
#include "Latency.h"
#if defined(MOZ_CUBEB)
#include "nsAutoRef.h"
@ -322,6 +323,7 @@ class BufferedAudioStream : public AudioStream
int64_t GetPosition();
int64_t GetPositionInFrames();
int64_t GetPositionInFramesInternal();
int64_t GetLatencyInFrames();
bool IsPaused();
// This method acquires the monitor and forward the call to the base
// class, to prevent a race on |mTimeStretcher|, in
@ -503,6 +505,7 @@ BufferedAudioStream::BufferedAudioStream()
: mMonitor("BufferedAudioStream"), mLostFrames(0), mDumpFile(nullptr),
mVolume(1.0), mBytesPerFrame(0), mState(INITIALIZED)
{
AsyncLatencyLogger::Get(true)->AddRef();
}
BufferedAudioStream::~BufferedAudioStream()
@ -511,6 +514,7 @@ BufferedAudioStream::~BufferedAudioStream()
if (mDumpFile) {
fclose(mDumpFile);
}
AsyncLatencyLogger::Get()->Release();
}
nsresult
@ -627,7 +631,6 @@ BufferedAudioStream::Write(const AudioDataValue* aBuf, uint32_t aFrames)
}
mWritten += aFrames;
return NS_OK;
}
@ -775,6 +778,17 @@ BufferedAudioStream::GetPositionInFramesUnlocked()
return std::min<uint64_t>(adjustedPosition, INT64_MAX);
}
int64_t
BufferedAudioStream::GetLatencyInFrames()
{
uint32_t latency;
if(cubeb_stream_get_latency(mCubebStream, &latency)) {
NS_WARNING("Could not get cubeb latency.");
return 0;
}
return static_cast<int64_t>(latency);
}
bool
BufferedAudioStream::IsPaused()
{
@ -886,6 +900,14 @@ BufferedAudioStream::DataCallback(void* aBuffer, long aFrames)
}
WriteDumpFile(mDumpFile, this, aFrames, aBuffer);
if (PR_LOG_TEST(GetLatencyLog(), PR_LOG_DEBUG)) {
uint32_t latency = UINT32_MAX;
if (cubeb_stream_get_latency(mCubebStream, &latency)) {
NS_WARNING("Could not get latency from cubeb.");
}
LogLatency(AsyncLatencyLogger::AudioStream, 0, (mBuffer.Length() * 1000) / mOutRate);
LogLatency(AsyncLatencyLogger::Cubeb, 0, (latency * 1000) / mOutRate);
}
mAudioClock.UpdateWritePosition(servicedFrames);
return servicedFrames;
@ -962,7 +984,7 @@ uint64_t AudioClock::GetPosition()
(static_cast<float>(USECS_PER_S * diffOffset) / mOutRate));
return position;
}
return -1;
return UINT64_MAX;
}
uint64_t AudioClock::GetPositionInFrames()

View File

@ -432,7 +432,7 @@ DecoderTraits::CanHandleMediaType(const char* aMIMEType,
// Totally unsupported codec
return CANPLAY_NO;
}
expectMoreTokens = tokenizer.lastTokenEndedWithSeparator();
expectMoreTokens = tokenizer.separatorAfterCurrentToken();
}
if (expectMoreTokens) {
// Last codec name was empty

135
content/media/Latency.cpp Normal file
View File

@ -0,0 +1,135 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
// We want this available in opt builds
#define FORCE_PR_LOG
#include "Latency.h"
#include "nsThreadUtils.h"
#include <prlog.h>
#include <cmath>
#include <algorithm>
using namespace mozilla;
const char* LatencyLogIndex2Strings[] = {
"Audio MediaStreamTrack",
"Video MediaStreamTrack",
"Cubeb",
"AudioStream",
"NetStat"
};
static nsRefPtr<AsyncLatencyLogger> gAsyncLogger;
PRLogModuleInfo*
GetLatencyLog()
{
static PRLogModuleInfo* sLog;
if (!sLog) {
sLog = PR_NewLogModule("MediaLatency");
}
return sLog;
}
class LogEvent : public nsRunnable
{
public:
LogEvent(AsyncLatencyLogger::LatencyLogIndex aIndex, uint64_t aID, int64_t aValue) :
mIndex(aIndex),
mID(aID),
mValue(aValue)
{}
~LogEvent() {}
NS_IMETHOD Run() {
AsyncLatencyLogger::Get(true)->WriteLog(mIndex, mID, mValue);
return NS_OK;
}
protected:
AsyncLatencyLogger::LatencyLogIndex mIndex;
uint64_t mID;
int64_t mValue;
};
// This is the only function that clients should use.
void LogLatency(AsyncLatencyLogger::LatencyLogIndex aIndex, uint64_t aID, int64_t aValue)
{
AsyncLatencyLogger::Get()->Log(aIndex, aID, aValue);
}
void AsyncLatencyLogger::InitializeStatics()
{
NS_ASSERTION(NS_IsMainThread(), "Main thread only");
GetLatencyLog();
gAsyncLogger = new AsyncLatencyLogger();
}
void AsyncLatencyLogger::Shutdown()
{
gAsyncLogger = nullptr;
}
/* static */
AsyncLatencyLogger* AsyncLatencyLogger::Get(bool aStartTimer)
{
if (aStartTimer) {
gAsyncLogger->Init();
}
return gAsyncLogger;
}
AsyncLatencyLogger::AsyncLatencyLogger()
: mThread(nullptr),
mMutex("AsyncLatencyLogger")
{ }
AsyncLatencyLogger::~AsyncLatencyLogger()
{
MutexAutoLock lock(mMutex);
if (mThread) {
mThread->Shutdown();
}
mStart = TimeStamp();
}
void AsyncLatencyLogger::Init()
{
MutexAutoLock lock(mMutex);
if (mStart.IsNull()) {
mStart = TimeStamp::Now();
nsresult rv = NS_NewNamedThread("Latency Logger", getter_AddRefs(mThread));
NS_ENSURE_SUCCESS_VOID(rv);
}
}
// aID is a sub-identifier (in particular a specific MediaStramTrack)
void AsyncLatencyLogger::WriteLog(LatencyLogIndex aIndex, uint64_t aID, int64_t aValue)
{
PR_LOG(GetLatencyLog(), PR_LOG_DEBUG,
("%s,%llu,%lld.,%lld.",
LatencyLogIndex2Strings[aIndex], aID, GetTimeStamp(), aValue));
}
int64_t AsyncLatencyLogger::GetTimeStamp()
{
TimeDuration t = TimeStamp::Now() - mStart;
return t.ToMilliseconds();
}
void AsyncLatencyLogger::Log(LatencyLogIndex aIndex, uint64_t aID, int64_t aValue)
{
if (PR_LOG_TEST(GetLatencyLog(), PR_LOG_DEBUG)) {
nsCOMPtr<nsIRunnable> event = new LogEvent(aIndex, aID, aValue);
if (mThread) {
mThread->Dispatch(event, NS_DISPATCH_NORMAL);
}
}
}

60
content/media/Latency.h Normal file
View File

@ -0,0 +1,60 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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_LATENCY_H
#define MOZILLA_LATENCY_H
#include "mozilla/TimeStamp.h"
#include "prlog.h"
#include "nsCOMPtr.h"
#include "nsIThread.h"
#include "mozilla/Monitor.h"
#include "nsISupportsImpl.h"
class AsyncLatencyLogger;
class LogEvent;
PRLogModuleInfo* GetLatencyLog();
// This class is a singleton. It is refcounted.
class AsyncLatencyLogger
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncLatencyLogger);
public:
enum LatencyLogIndex {
AudioMediaStreamTrack,
VideoMediaStreamTrack,
Cubeb,
AudioStream,
NetEQ,
_MAX_INDEX
};
void Log(LatencyLogIndex index, uint64_t aID, int64_t value);
void WriteLog(LatencyLogIndex index, uint64_t aID, int64_t value);
static AsyncLatencyLogger* Get(bool aStartTimer = false);
static void InitializeStatics();
static void Shutdown();
private:
AsyncLatencyLogger();
~AsyncLatencyLogger();
int64_t GetTimeStamp();
void Init();
// The thread on which the IO happens
nsCOMPtr<nsIThread> mThread;
// This can be initialized on multiple threads, but is protected by a
// monitor. After the initialization phase, it is accessed on the log
// thread only.
mozilla::TimeStamp mStart;
// This monitor protects mStart and mMediaLatencyLog for the
// initialization sequence. It is initialized at layout startup, and
// destroyed at layout shutdown.
mozilla::Mutex mMutex;
};
void LogLatency(AsyncLatencyLogger::LatencyLogIndex index, uint64_t aID, int64_t value);
#endif

View File

@ -21,5 +21,6 @@ endif
CFLAGS += $(GSTREAMER_CFLAGS)
CXXFLAGS += $(GSTREAMER_CFLAGS)
DEFINES += -DMOZILLA_INTERNAL_API
AudioNodeEngineNEON.$(OBJ_SUFFIX): CXXFLAGS += -mfpu=neon

View File

@ -7,7 +7,11 @@
#define MOZILLA_MEDIASEGMENT_H_
#include "nsTArray.h"
#ifdef MOZILLA_INTERNAL_API
#include "mozilla/TimeStamp.h"
#endif
#include <algorithm>
#include "Latency.h"
namespace mozilla {
@ -180,6 +184,9 @@ public:
} else {
mChunks.InsertElementAt(0)->SetNull(aDuration);
}
#ifdef MOZILLA_INTERNAL_API
mChunks[0].mTimeStamp = mozilla::TimeStamp::Now();
#endif
mDuration += aDuration;
}
virtual void AppendNullData(TrackTicks aDuration)
@ -322,6 +329,9 @@ protected:
}
nsTArray<Chunk> mChunks;
#ifdef MOZILLA_INTERNAL_API
mozilla::TimeStamp mTimeStamp;
#endif
};
}

View File

@ -24,6 +24,7 @@
#include <algorithm>
#include "DOMMediaStream.h"
#include "GeckoProfiler.h"
#include "nsIScriptError.h"
using namespace mozilla::layers;
using namespace mozilla::dom;
@ -464,6 +465,41 @@ MediaStreamGraphImpl::MarkConsumed(MediaStream* aStream)
}
}
class MediaStreamGraphWarnCycleRunnable : public nsRunnable {
public:
explicit MediaStreamGraphWarnCycleRunnable(MediaStream* aStream)
: mStream(aStream)
{
}
NS_IMETHOD Run()
{
AudioNodeEngine* engine = mStream->AsAudioNodeStream()->Engine();
MutexAutoLock mon(engine->NodeMutex());
AudioNode* node = engine->Node();
nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(node->Context()->GetParentObject());
nsIDocument* doc = nullptr;
if (pWindow) {
doc = pWindow->GetExtantDoc();
}
nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
NS_LITERAL_CSTRING("Media"),
doc,
nsContentUtils::eDOM_PROPERTIES,
"AudioNodeCycleWithoutDelay");
return NS_OK;
}
private:
MediaStream* mStream;
};
static void
WarnIllegalCycle(MediaStream* aStream)
{
nsCOMPtr<nsIRunnable> event = new MediaStreamGraphWarnCycleRunnable(aStream);
NS_DispatchToMainThread(event);
}
void
MediaStreamGraphImpl::UpdateStreamOrderForStream(mozilla::LinkedList<MediaStream>* aStack,
already_AddRefed<MediaStream> aStream)
@ -472,12 +508,46 @@ MediaStreamGraphImpl::UpdateStreamOrderForStream(mozilla::LinkedList<MediaStream
NS_ASSERTION(!stream->mHasBeenOrdered, "stream should not have already been ordered");
if (stream->mIsOnOrderingStack) {
MediaStream* iter = aStack->getLast();
AudioNodeStream* ns = stream->AsAudioNodeStream();
bool delayNodePresent = ns ? ns->Engine()->AsDelayNodeEngine() != nullptr : false;
bool cycleFound = false;
if (iter) {
do {
cycleFound = true;
iter->AsProcessedStream()->mInCycle = true;
AudioNodeStream* ns = iter->AsAudioNodeStream();
if (ns && ns->Engine()->AsDelayNodeEngine()) {
delayNodePresent = true;
}
iter = iter->getPrevious();
} while (iter && iter != stream);
}
if (cycleFound && !delayNodePresent) {
// If we have detected a cycle, the previous loop should exit with stream
// == iter, or the node is connected to itself. Go back in the cycle and
// mute all nodes we find, or just mute the node itself.
if (!iter) {
// The node is connected to itself.
iter = aStack->getLast();
iter->AsAudioNodeStream()->Mute();
} else {
MOZ_ASSERT(iter);
do {
// There can't be non-AudioNodeStream here, MediaStreamAudio{Source,
// Destination}Node are connected to regular MediaStreams, but they can't be
// in a cycle (there is no content API to do so).
MOZ_ASSERT(iter->AsAudioNodeStream());
iter->AsAudioNodeStream()->Mute();
} while((iter = iter->getNext()));
}
// Warn the user that some of the nodes in the graph are muted, but only
// once. This flag is reset when the graph changes.
if (!mUserWarnedAboutCycles) {
WarnIllegalCycle(aStack->getLast());
mUserWarnedAboutCycles = true;
}
}
return;
}
ProcessedMediaStream* ps = stream->AsProcessedStream();
@ -513,6 +583,10 @@ MediaStreamGraphImpl::UpdateStreamOrder()
ProcessedMediaStream* ps = stream->AsProcessedStream();
if (ps) {
ps->mInCycle = false;
AudioNodeStream* ns = ps->AsAudioNodeStream();
if (ns) {
ns->Unmute();
}
}
}
@ -814,7 +888,8 @@ MediaStreamGraphImpl::PlayAudio(MediaStream* aStream,
aStream, MediaTimeToSeconds(t), MediaTimeToSeconds(end),
startTicks, endTicks));
}
output.WriteTo(audioOutput.mStream);
// XXX need unique id for stream & track
output.WriteTo((((uint64_t)i) << 32) | track->GetID(), audioOutput.mStream);
t = end;
}
}
@ -2292,6 +2367,8 @@ MediaStreamGraphImpl::MediaStreamGraphImpl(bool aRealtime)
, mPostedRunInStableState(false)
, mRealtime(aRealtime)
, mNonRealtimeProcessing(false)
, mStreamOrderDirty(false)
, mUserWarnedAboutCycles(false)
{
#ifdef PR_LOGGING
if (!gMediaStreamGraphLog) {
@ -2445,4 +2522,11 @@ MediaStreamGraph::StartNonRealtimeProcessing(uint32_t aTicksToProcess)
graph->EnsureRunInStableState();
}
void
ProcessedMediaStream::AddInput(MediaInputPort* aPort)
{
mInputs.AppendElement(aPort);
GraphImpl()->SetStreamOrderDirty();
}
}

View File

@ -917,10 +917,7 @@ public:
friend class MediaStreamGraphImpl;
// Do not call these from outside MediaStreamGraph.cpp!
virtual void AddInput(MediaInputPort* aPort)
{
mInputs.AppendElement(aPort);
}
virtual void AddInput(MediaInputPort* aPort);
virtual void RemoveInput(MediaInputPort* aPort)
{
mInputs.RemoveElement(aPort);
@ -946,6 +943,9 @@ public:
*/
virtual void ForwardTrackEnabled(TrackID aOutputID, bool aEnabled) {};
bool InCycle() const { return mInCycle; }
protected:
// This state is all accessed only on the media graph thread.

View File

@ -365,6 +365,14 @@ public:
* Remove aPort from the graph and release it.
*/
void DestroyPort(MediaInputPort* aPort);
/**
* Mark the media stream order as dirty.
*/
void SetStreamOrderDirty()
{
mStreamOrderDirty = true;
mUserWarnedAboutCycles = false;
}
// Data members
@ -554,6 +562,16 @@ public:
* value is only accessed on the main thread.
*/
bool mNonRealtimeProcessing;
/**
* True when a change has happened which requires us to recompute the stream
* blocking order.
*/
bool mStreamOrderDirty;
/**
* True when the user has already been warned that this graph contains a
* cycle. Reset each time mStreamOrderDirty becomes true.
*/
bool mUserWarnedAboutCycles;
};
}

View File

@ -72,11 +72,13 @@ struct VideoChunk {
{
mDuration = aDuration;
mFrame.SetNull();
mTimeStamp = TimeStamp();
}
void SetForceBlack(bool aForceBlack) { mFrame.SetForceBlack(aForceBlack); }
TrackTicks mDuration;
VideoFrame mFrame;
mozilla::TimeStamp mTimeStamp;
};
class VideoSegment : public MediaSegmentBase<VideoSegment, VideoChunk> {

View File

@ -69,6 +69,7 @@ EXPORTS += [
'DecoderTraits.h',
'EncodedBufferCache.h',
'FileBlockCache.h',
'Latency.h',
'MP3FrameParser.h',
'MediaCache.h',
'MediaDecoder.h',
@ -117,6 +118,7 @@ CPP_SOURCES += [
'DecoderTraits.cpp',
'EncodedBufferCache.cpp',
'FileBlockCache.cpp',
'Latency.cpp',
'MP3FrameParser.cpp',
'MediaCache.cpp',
'MediaDecoder.cpp',

View File

@ -0,0 +1,104 @@
#!/usr/bin/env python
# graph_latency.py - graph media latency
#
# 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/.
# needs matplotlib (sudo aptitude install python-matplotlib)
import matplotlib.pyplot as plt
from matplotlib import rc
import sys
from pprint import pprint
import re
# FIX! needs to be sum of a single mediastreamtrack and any output overhead for it
# So there is one sum per MST
def compute_sum(data):
'Compute the sum for each timestamp. This expects the output of parse_data.'
last_values = {}
out = ([],[])
for i in data:
if i[0] not in last_values.keys():
last_values[i[0]] = 0
last_values[i[0]] = float(i[3])
print last_values
out[0].append(i[2])
out[1].append(sum(last_values.values()))
return out
def clean_data(raw_data):
'''
Remove the PR_LOG cruft at the beginning of each line and returns a list of
tuple.
'''
out = []
for line in raw_data:
match = re.match(r'(.*)#(.*)', line)
if match:
continue
else:
out.append(line.split(": ")[1])
return out
# returns a list of tuples
def parse_data(raw_lines):
'''
Split each line by , and put every bit in a tuple.
'''
out = []
for line in raw_lines:
out.append(line.split(','))
return out
if len(sys.argv) == 3:
name = sys.argv[1]
channels = int(sys.argv[2])
else:
print sys.argv[0] + "latency_log"
try:
f = open(sys.argv[1])
except:
print "cannot open " + name
raw_lines = f.readlines()
lines = clean_data(raw_lines)
data = parse_data(lines)
final_data = {}
for tupl in data:
name = tupl[0]
if tupl[1] != 0:
name = name+tupl[1]
if name not in final_data.keys():
final_data[name] = ([], [])
# sanity-check values
if float(tupl[3]) < 10*1000:
final_data[name][0].append(float(tupl[2]))
final_data[name][1].append(float(tupl[3]))
#overall = compute_sum(data)
#final_data["overall"] = overall
pprint(final_data)
fig = plt.figure()
for i in final_data.keys():
plt.plot(final_data[i][0], final_data[i][1], label=i)
plt.legend()
plt.suptitle("Latency in ms (y-axis) against time in ms (x-axis).")
size = fig.get_size_inches()
# make it gigantic so we can see things. sometimes, if the graph is too big,
# this errors. reduce the factor so it stays under 2**15.
fig.set_size_inches((size[0]*10, size[1]*2))
name = sys.argv[1][:-4] + ".pdf"
fig.savefig(name)

View File

@ -108,6 +108,56 @@ AudioBuffer::RestoreJSChannelData(JSContext* aJSContext)
return true;
}
void
AudioBuffer::CopyFromChannel(const Float32Array& aDestination, uint32_t aChannelNumber,
uint32_t aStartInChannel, ErrorResult& aRv)
{
uint32_t length = aDestination.Length();
if (aChannelNumber >= NumberOfChannels() ||
aStartInChannel + length >= mLength) {
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return;
}
if (!mSharedChannels && JS_GetTypedArrayLength(mJSChannels[aChannelNumber]) != mLength) {
// The array was probably neutered
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return;
}
const float* sourceData = mSharedChannels ?
mSharedChannels->GetData(aChannelNumber) :
JS_GetFloat32ArrayData(mJSChannels[aChannelNumber]);
PodCopy(aDestination.Data(), sourceData + aStartInChannel, length);
}
void
AudioBuffer::CopyToChannel(JSContext* aJSContext, const Float32Array& aSource,
uint32_t aChannelNumber, uint32_t aStartInChannel,
ErrorResult& aRv)
{
uint32_t length = aSource.Length();
if (aChannelNumber >= NumberOfChannels() ||
aStartInChannel + length >= mLength) {
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return;
}
if (!mSharedChannels && JS_GetTypedArrayLength(mJSChannels[aChannelNumber]) != mLength) {
// The array was probably neutered
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return;
}
if (!RestoreJSChannelData(aJSContext)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
PodCopy(JS_GetFloat32ArrayData(mJSChannels[aChannelNumber]) + aStartInChannel,
aSource.Data(), length);
}
void
AudioBuffer::SetRawChannelContents(JSContext* aJSContext, uint32_t aChannel,
float* aContents)

View File

@ -81,6 +81,12 @@ public:
JSObject* GetChannelData(JSContext* aJSContext, uint32_t aChannel,
ErrorResult& aRv);
void CopyFromChannel(const Float32Array& aDestination, uint32_t aChannelNumber,
uint32_t aStartInChannel, ErrorResult& aRv);
void CopyToChannel(JSContext* aJSContext, const Float32Array& aSource,
uint32_t aChannelNumber, uint32_t aStartInChannel,
ErrorResult& aRv);
/**
* Returns a ThreadSharedFloatArrayBufferList containing the sample data.
* Can return null if there is no data.

View File

@ -495,7 +495,10 @@ AudioContext::Graph() const
MediaStream*
AudioContext::DestinationStream() const
{
return Destination()->Stream();
if (Destination()) {
return Destination()->Stream();
}
return nullptr;
}
double

View File

@ -130,6 +130,10 @@ public:
return nullptr;
}
virtual const DelayNode* AsDelayNode() const {
return nullptr;
}
AudioContext* GetParentObject() const
{
return mContext;

View File

@ -44,6 +44,11 @@ public:
{
}
virtual DelayNodeEngine* AsDelayNodeEngine()
{
return this;
}
void SetSourceStream(AudioNodeStream* aSource)
{
mSource = aSource;
@ -123,18 +128,28 @@ public:
float* const* outputChannels = reinterpret_cast<float* const*>
(const_cast<void* const*>(aOutput->mChannelData.Elements()));
bool inCycle = aStream->AsProcessedStream()->InCycle();
double sampleRate = aStream->SampleRate();
if (mDelay.HasSimpleValue()) {
double delayFrames = mDelay.GetValue() * sampleRate;
mProcessor.Process(delayFrames, inputChannels, outputChannels,
// If this DelayNode is in a cycle, make sure the delay value is at least
// one block.
float delayFrames = mDelay.GetValue() * sampleRate;
float delayFramesClamped = inCycle ? std::max(static_cast<float>(WEBAUDIO_BLOCK_SIZE), delayFrames) :
delayFrames;
mProcessor.Process(delayFramesClamped, inputChannels, outputChannels,
numChannels, WEBAUDIO_BLOCK_SIZE);
} else {
// Compute the delay values for the duration of the input AudioChunk
// If this DelayNode is in a cycle, make sure the delay value is at least
// one block.
double computedDelay[WEBAUDIO_BLOCK_SIZE];
TrackTicks tick = aStream->GetCurrentPosition();
for (size_t counter = 0; counter < WEBAUDIO_BLOCK_SIZE; ++counter) {
computedDelay[counter] =
mDelay.GetValueAtTime(tick, counter) * sampleRate;
float delayAtTick = mDelay.GetValueAtTime(tick, counter) * sampleRate;
float delayAtTickClamped = inCycle ? std::max(static_cast<float>(WEBAUDIO_BLOCK_SIZE), delayAtTick) :
delayAtTick;
computedDelay[counter] = delayAtTickClamped;
}
mProcessor.Process(computedDelay, inputChannels, outputChannels,
numChannels, WEBAUDIO_BLOCK_SIZE);

View File

@ -32,6 +32,11 @@ public:
return mDelay;
}
virtual const DelayNode* AsDelayNode() const MOZ_OVERRIDE
{
return this;
}
virtual void NotifyInputConnected() MOZ_OVERRIDE
{
mMediaStreamGraphUpdateIndexAtLastInputConnection =

View File

@ -36,6 +36,39 @@ NS_INTERFACE_MAP_END_INHERITING(AudioNode)
NS_IMPL_ADDREF_INHERITED(OscillatorNode, AudioNode)
NS_IMPL_RELEASE_INHERITED(OscillatorNode, AudioNode)
static const float sLeak = 0.995;
class DCBlocker
{
public:
// These are sane defauts when the initial mPhase is zero
DCBlocker(float aLastInput = 0.0f,
float aLastOutput = 0.0f,
float aPole = 0.995)
:mLastInput(aLastInput),
mLastOutput(aLastOutput),
mPole(aPole)
{
MOZ_ASSERT(aPole > 0);
}
inline float Process(float aInput)
{
float out;
out = mLastOutput * mPole + aInput - mLastInput;
mLastOutput = out;
mLastInput = aInput;
return out;
}
private:
float mLastInput;
float mLastOutput;
float mPole;
};
class OscillatorNodeEngine : public AudioNodeEngine
{
public:
@ -50,6 +83,16 @@ public:
, mDetune(0.f)
, mType(OscillatorType::Sine)
, mPhase(0.)
, mFinalFrequency(0.0)
, mNumberOfHarmonics(0)
, mSignalPeriod(0.0)
, mAmplitudeAtZero(0.0)
, mPhaseIncrement(0.0)
, mSquare(0.0)
, mTriangle(0.0)
, mSaw(0.0)
, mPhaseWrap(0.0)
, mRecomputeFrequency(true)
{
}
@ -70,6 +113,7 @@ public:
const AudioParamTimeline& aValue,
TrackRate aSampleRate) MOZ_OVERRIDE
{
mRecomputeFrequency = true;
switch (aIndex) {
case FREQUENCY:
MOZ_ASSERT(mSource && mDestination);
@ -85,6 +129,7 @@ public:
NS_ERROR("Bad OscillatorNodeEngine TimelineParameter");
}
}
virtual void SetStreamTimeParameter(uint32_t aIndex, TrackTicks aParam)
{
switch (aIndex) {
@ -94,29 +139,95 @@ public:
NS_ERROR("Bad OscillatorNodeEngine StreamTimeParameter");
}
}
virtual void SetInt32Parameter(uint32_t aIndex, int32_t aParam)
{
switch (aIndex) {
case TYPE: mType = static_cast<OscillatorType>(aParam); break;
default:
NS_ERROR("Bad OscillatorNodeEngine Int32Parameter");
mType = static_cast<OscillatorType>(aParam);
// Set the new type, and update integrators with the new initial conditions.
switch (mType) {
case OscillatorType::Sine:
mPhase = 0.0;
break;
case OscillatorType::Square:
mPhase = 0.0;
// Initial integration condition is -0.5, because our square has 50%
// duty cycle.
mSquare = -0.5;
break;
case OscillatorType::Triangle:
// Initial mPhase and related integration condition so the triangle is
// in the middle of the first upward slope.
// XXX actually do the maths and put the right number here.
mPhase = M_PI / 2;
mSquare = 0.5;
mTriangle = 0.0;
break;
case OscillatorType::Sawtooth:
/* initial mPhase so the oscillator start at the middle
* of the ramp, per spec */
mPhase = M_PI / 2;
/* mSaw = 0 when mPhase = pi/2 */
mSaw = 0.0;
break;
default:
NS_ERROR("Bad OscillatorNodeEngine Int32Parameter.");
};
}
void IncrementPhase()
{
mPhase += mPhaseIncrement;
if (mPhase > mPhaseWrap) {
mPhase -= mPhaseWrap;
}
}
double ComputeFrequency(TrackTicks ticks, size_t count)
// Square and triangle are using a bipolar band-limited impulse train, saw is
// using a normal band-limited impulse train.
bool UsesBipolarBLIT() {
return mType == OscillatorType::Square || mType == OscillatorType::Triangle;
}
void UpdateFrequencyIfNeeded(TrackTicks ticks, size_t count)
{
double frequency, detune;
if (mFrequency.HasSimpleValue()) {
bool simpleFrequency = mFrequency.HasSimpleValue();
bool simpleDetune = mDetune.HasSimpleValue();
// Shortcut if frequency-related AudioParam are not automated, and we
// already have computed the frequency information and related parameters.
if (simpleFrequency && simpleDetune && !mRecomputeFrequency) {
return;
}
if (simpleFrequency) {
frequency = mFrequency.GetValue();
} else {
frequency = mFrequency.GetValueAtTime(ticks, count);
}
if (mDetune.HasSimpleValue()) {
if (simpleDetune) {
detune = mDetune.GetValue();
} else {
detune = mDetune.GetValueAtTime(ticks, count);
}
return frequency * pow(2., detune / 1200.);
mFinalFrequency = frequency * pow(2., detune / 1200.);
mRecomputeFrequency = false;
// When using bipolar BLIT, we divide the signal period by two, because we
// are using two BLIT out of phase.
mSignalPeriod = UsesBipolarBLIT() ? 0.5 * mSource->SampleRate() / mFinalFrequency
: mSource->SampleRate() / mFinalFrequency;
// Wrap the phase accordingly:
mPhaseWrap = UsesBipolarBLIT() || mType == OscillatorType::Sine ? 2 * M_PI
: M_PI;
// Even number of harmonics for bipolar blit, odd otherwise.
mNumberOfHarmonics = UsesBipolarBLIT() ? 2 * floor(0.5 * mSignalPeriod)
: 2 * floor(0.5 * mSignalPeriod) + 1;
mPhaseIncrement = mType == OscillatorType::Sine ? 2 * M_PI / mSignalPeriod
: M_PI / mSignalPeriod;
mAmplitudeAtZero = mNumberOfHarmonics / mSignalPeriod;
}
void FillBounds(float* output, TrackTicks ticks,
@ -141,95 +252,98 @@ public:
}
}
void ComputeSine(AudioChunk *aOutput)
float BipolarBLIT()
{
AllocateAudioBlock(1, aOutput);
float* output = static_cast<float*>(const_cast<void*>(aOutput->mChannelData[0]));
float blit;
float denom = sin(mPhase);
TrackTicks ticks = mSource->GetCurrentPosition();
uint32_t start, end;
FillBounds(output, ticks, start, end);
double rate = 2.*M_PI / mSource->SampleRate();
double phase = mPhase;
for (uint32_t i = start; i < end; ++i) {
phase += ComputeFrequency(ticks, i) * rate;
output[i] = sin(phase);
}
mPhase = phase;
while (mPhase > 2.0*M_PI) {
// Rescale to avoid precision reductions on long runs.
mPhase -= 2.0*M_PI;
}
}
void ComputeSquare(AudioChunk *aOutput)
{
AllocateAudioBlock(1, aOutput);
float* output = static_cast<float*>(const_cast<void*>(aOutput->mChannelData[0]));
TrackTicks ticks = mSource->GetCurrentPosition();
uint32_t start, end;
FillBounds(output, ticks, start, end);
double rate = 1.0 / mSource->SampleRate();
double phase = mPhase;
for (uint32_t i = start; i < end; ++i) {
phase += ComputeFrequency(ticks, i) * rate;
if (phase > 1.0) {
phase -= 1.0;
}
output[i] = phase < 0.5 ? 1.0 : -1.0;
}
mPhase = phase;
}
void ComputeSawtooth(AudioChunk *aOutput)
{
AllocateAudioBlock(1, aOutput);
float* output = static_cast<float*>(const_cast<void*>(aOutput->mChannelData[0]));
TrackTicks ticks = mSource->GetCurrentPosition();
uint32_t start, end;
FillBounds(output, ticks, start, end);
double rate = 1.0 / mSource->SampleRate();
double phase = mPhase;
for (uint32_t i = start; i < end; ++i) {
phase += ComputeFrequency(ticks, i) * rate;
if (phase > 1.0) {
phase -= 1.0;
}
output[i] = phase < 0.5 ? 2.0*phase : 2.0*(phase - 1.0);
}
mPhase = phase;
}
void ComputeTriangle(AudioChunk *aOutput)
{
AllocateAudioBlock(1, aOutput);
float* output = static_cast<float*>(const_cast<void*>(aOutput->mChannelData[0]));
TrackTicks ticks = mSource->GetCurrentPosition();
uint32_t start, end;
FillBounds(output, ticks, start, end);
double rate = 1.0 / mSource->SampleRate();
double phase = mPhase;
for (uint32_t i = start; i < end; ++i) {
phase += ComputeFrequency(ticks, i) * rate;
if (phase > 1.0) {
phase -= 1.0;
}
if (phase < 0.25) {
output[i] = 4.0*phase;
} else if (phase < 0.75) {
output[i] = 1.0 - 4.0*(phase - 0.25);
if (fabs(denom) < std::numeric_limits<float>::epsilon()) {
if (mPhase < 0.1f || mPhase > 2 * M_PI - 0.1f) {
blit = mAmplitudeAtZero;
} else {
output[i] = 4.0*(phase - 0.75) - 1.0;
blit = -mAmplitudeAtZero;
}
} else {
blit = sin(mNumberOfHarmonics * mPhase);
blit /= mSignalPeriod * denom;
}
return blit;
}
float UnipolarBLIT()
{
float blit;
float denom = sin(mPhase);
if (fabs(denom) <= std::numeric_limits<float>::epsilon()) {
blit = mAmplitudeAtZero;
} else {
blit = sin(mNumberOfHarmonics * mPhase);
blit /= mSignalPeriod * denom;
}
return blit;
}
void ComputeSine(float * aOutput, TrackTicks ticks, uint32_t aStart, uint32_t aEnd)
{
for (uint32_t i = aStart; i < aEnd; ++i) {
UpdateFrequencyIfNeeded(ticks, i);
aOutput[i] = sin(mPhase);
IncrementPhase();
}
}
void ComputeSquare(float * aOutput, TrackTicks ticks, uint32_t aStart, uint32_t aEnd)
{
for (uint32_t i = aStart; i < aEnd; ++i) {
UpdateFrequencyIfNeeded(ticks, i);
// Integration to get us a square. It turns out we can have a
// pure integrator here.
mSquare += BipolarBLIT();
aOutput[i] = mSquare;
// maybe we want to apply a gain, the wg has not decided yet
aOutput[i] *= 1.5;
IncrementPhase();
}
}
void ComputeSawtooth(float * aOutput, TrackTicks ticks, uint32_t aStart, uint32_t aEnd)
{
float dcoffset;
for (uint32_t i = aStart; i < aEnd; ++i) {
UpdateFrequencyIfNeeded(ticks, i);
// DC offset so the Saw does not ramp up to infinity when integrating.
dcoffset = mFinalFrequency / mSource->SampleRate();
// Integrate and offset so we get mAmplitudeAtZero sawtooth. We have a
// very low frequency component somewhere here, but I'm not sure where.
mSaw += UnipolarBLIT() - dcoffset;
// reverse the saw so we are spec compliant
aOutput[i] = -mSaw * 1.5;
IncrementPhase();
}
}
void ComputeTriangle(float * aOutput, TrackTicks ticks, uint32_t aStart, uint32_t aEnd)
{
for (uint32_t i = aStart; i < aEnd; ++i) {
UpdateFrequencyIfNeeded(ticks, i);
// Integrate to get a square
mSquare += BipolarBLIT();
// Leaky integrate to get a triangle. We get too much dc offset if we don't
// leaky integrate here.
// C6 = k0 / period
// (period is samplingrate / frequency, k0 = (PI/2)/(2*PI)) = 0.25
float C6 = 0.25 / (mSource->SampleRate() / mFinalFrequency);
mTriangle = mTriangle * sLeak + mSquare + C6;
// DC Block, and scale back to [-1.0; 1.0]
aOutput[i] = mDCBlocker.Process(mTriangle) / (mSignalPeriod/2) * 1.5;
IncrementPhase();
}
mPhase = phase;
}
void ComputeSilence(AudioChunk *aOutput)
@ -261,25 +375,35 @@ public:
*aFinished = true;
return;
}
AllocateAudioBlock(1, aOutput);
float* output = static_cast<float*>(
const_cast<void*>(aOutput->mChannelData[0]));
uint32_t start, end;
FillBounds(output, ticks, start, end);
// Synthesize the correct waveform.
switch (mType) {
switch(mType) {
case OscillatorType::Sine:
ComputeSine(aOutput);
ComputeSine(output, ticks, start, end);
break;
case OscillatorType::Square:
ComputeSquare(aOutput);
break;
case OscillatorType::Sawtooth:
ComputeSawtooth(aOutput);
ComputeSquare(output, ticks, start, end);
break;
case OscillatorType::Triangle:
ComputeTriangle(aOutput);
ComputeTriangle(output, ticks, start, end);
break;
case OscillatorType::Sawtooth:
ComputeSawtooth(output, ticks, start, end);
break;
default:
ComputeSilence(aOutput);
}
};
}
DCBlocker mDCBlocker;
AudioNodeStream* mSource;
AudioNodeStream* mDestination;
TrackTicks mStart;
@ -287,7 +411,17 @@ public:
AudioParamTimeline mFrequency;
AudioParamTimeline mDetune;
OscillatorType mType;
double mPhase;
float mPhase;
float mFinalFrequency;
uint32_t mNumberOfHarmonics;
float mSignalPeriod;
float mAmplitudeAtZero;
float mPhaseIncrement;
float mSquare;
float mTriangle;
float mSaw;
float mPhaseWrap;
bool mRecomputeFrequency;
};
OscillatorNode::OscillatorNode(AudioContext* aContext)

View File

@ -98,6 +98,7 @@ public:
: mOutputQueue("SharedBuffers::outputQueue")
, mDelaySoFar(TRACK_TICKS_MAX)
, mSampleRate(aSampleRate)
, mLatency(0.0)
, mDroppingBuffers(false)
{
}

View File

@ -57,6 +57,7 @@ MOCHITEST_FILES := \
test_delayNodeAtMax.html \
test_delayNodeSmallMaxDelay.html \
test_delayNodeWithGain.html \
test_delayNodeCycles.html \
test_dynamicsCompressorNode.html \
test_gainNode.html \
test_gainNodeInLoop.html \

View File

@ -31,9 +31,54 @@ addLoadEvent(function() {
foundNonZero = true;
break;
}
buf[j] = j;
}
ok(!foundNonZero, "Buffer " + i + " should be initialized to 0");
}
// Now test copying the channel data out of a normal buffer
var copy = new Float32Array(100);
buffer.copyFromChannel(copy, 0, 1024);
for (var i = 0; i < copy.length; ++i) {
is(copy[i], 1024 + i, "Correct sample");
}
// Test copying the channel data out of a playing buffer
var srcNode = context.createBufferSource();
srcNode.buffer = buffer;
srcNode.start(0);
copy = new Float32Array(100);
buffer.copyFromChannel(copy, 0, 1024);
for (var i = 0; i < copy.length; ++i) {
is(copy[i], 1024 + i, "Correct sample");
}
// Test copying to the channel data
var newData = new Float32Array(200);
buffer.copyToChannel(newData, 0, 100);
var changedData = buffer.getChannelData(0);
for (var i = 0; i < changedData.length; ++i) {
if (i < 100 || i >= 300) {
is(changedData[i], i, "Untouched sample");
} else {
is(changedData[i], 0, "Correct sample");
}
}
// Now, neuter the array buffer
var worker = new Worker("audioBufferSourceNodeNeutered_worker.js");
var data = buffer.getChannelData(0).buffer;
worker.postMessage(data, [data]);
SpecialPowers.gc();
expectException(function() {
buffer.copyFromChannel(copy, 0, 1024);
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
buffer.copyToChannel(newData, 0, 100);
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
context.createBuffer(2, 2048, 7999);
}, DOMException.NOT_SUPPORTED_ERR);

View File

@ -0,0 +1,170 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test the support of cycles.</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script src="webaudio.js" type="text/javascript"></script>
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
function getSineBuffer(ctx) {
var buffer = ctx.createBuffer(1, 2048, ctx.sampleRate);
var b = buffer.getChannelData(0);
for (var i = 0; i < 2048; i++) {
b[i] = Math.sin(440 * 2 * Math.PI * i / ctx.sampleRate);
}
return buffer;
}
function createAndPlayWithCycleAndDelayNode(ctx) {
var source = ctx.createBufferSource();
source.loop = true;
source.buffer = getSineBuffer(ctx);
var gain = ctx.createGain();
var delay = ctx.createDelay();
delay.delayTime = 0.5;
source.connect(gain);
gain.connect(delay);
delay.connect(ctx.destination);
// cycle
delay.connect(gain);
source.start(0);
}
function createAndPlayWithCycleAndDelayNodeButNullDelayTime(ctx) {
var source = ctx.createBufferSource();
source.loop = true;
source.buffer = getSineBuffer(ctx);
var gain = ctx.createGain();
var delay = ctx.createDelay();
delay.delayTime = 0.0;
source.connect(gain);
gain.connect(delay);
delay.connect(ctx.destination);
// cycle
delay.connect(gain);
source.start(0);
}
function createAndPlayWithCycleAndNoDelayNode(ctx) {
var source = ctx.createBufferSource();
source.loop = true;
source.buffer = getSineBuffer(ctx);
var gain = ctx.createGain();
var gain2 = ctx.createGain();
source.connect(gain);
gain.connect(gain2);
// cycle
gain2.connect(gain);
gain2.connect(ctx.destination);
source.start(0);
}
function createAndPlayWithCycleAndNoDelayNodeInCycle(ctx) {
var source = ctx.createBufferSource();
source.loop = true;
source.buffer = getSineBuffer(ctx);
var delay = ctx.createDelay();
var gain = ctx.createGain();
var gain2 = ctx.createGain();
// Their is a cycle, a delay, but the delay is not in the cycle.
source.connect(delay);
delay.connect(gain);
gain.connect(gain2);
// cycle
gain2.connect(gain);
gain2.connect(ctx.destination);
source.start(0);
}
var remainingTests = 0;
function finish() {
if (--remainingTests == 0) {
SimpleTest.finish();
}
}
function getOfflineContext(oncomplete) {
var ctx = new OfflineAudioContext(1, 48000, 48000);
ctx.oncomplete = oncomplete;
return ctx;
}
function checkSilentBuffer(e) {
var buffer = e.renderedBuffer.getChannelData(0);
for (var i = 0; i < buffer.length; i++) {
if (buffer[i] != 0.0) {
ok(false, "buffer should be silent.");
finish();
return;
}
}
ok(true, "buffer should be silent.");
finish();
}
function checkNoisyBuffer(e) {
var buffer = e.renderedBuffer.getChannelData(0);
for (var i = 0; i < buffer.length; i++) {
if (buffer[i] != 0.0) {
ok(true, "buffer should be noisy.");
finish();
return true;
}
}
ok(false, "buffer should be noisy.");
finish();
return false;
}
function expectSilentOutput(f) {
remainingTests++;
var ctx = getOfflineContext(checkSilentBuffer);
f(ctx);
ctx.startRendering();
}
function expectNoisyOutput(f) {
remainingTests++;
var ctx = getOfflineContext(checkNoisyBuffer);
f(ctx);
ctx.startRendering();
}
// This is trying to make a graph with a cycle and no DelayNode in the graph.
// The cycle subgraph should be muted, in this graph the output should be silent.
expectSilentOutput(createAndPlayWithCycleAndNoDelayNode);
// This is trying to make a graph with a cycle and a DelayNode in the graph, but
// not part of the cycle.
// The cycle subgraph should be muted, in this graph the output should be silent.
expectSilentOutput(createAndPlayWithCycleAndNoDelayNodeInCycle);
// Those are making legal graphs, with at least one DelayNode in the cycle.
// There should be some non-silent output.
expectNoisyOutput(createAndPlayWithCycleAndDelayNode);
// DelayNode.delayTime will be clamped to 128/ctx.sampleRate.
// There should be some non-silent output.
expectNoisyOutput(createAndPlayWithCycleAndDelayNodeButNullDelayTime);
});
</script>
</pre>
</body>
</html>

View File

@ -354,6 +354,7 @@ public:
, mCameraManager(aCameraManager)
, mWindowId(aWindowId)
{
AsyncLatencyLogger::Get(true)->AddRef();
}
#else
MediaEngineWebRTC()
@ -365,7 +366,12 @@ public:
{
}
#endif
~MediaEngineWebRTC() { Shutdown(); }
~MediaEngineWebRTC() {
Shutdown();
#ifdef MOZ_B2G_CAMERA
AsyncLatencyLogger::Get()->Release();
#endif
}
// Clients should ensure to clean-up sources video/audio sources
// before invoking Shutdown on this class.

View File

@ -6,12 +6,12 @@
#include "mozilla/Util.h"
#include "SVGAnimatedPreserveAspectRatio.h"
#include "nsWhitespaceTokenizer.h"
#include "mozilla/dom/SVGAnimatedPreserveAspectRatioBinding.h"
#include "nsSMILValue.h"
#include "nsSVGAttrTearoffTable.h"
#include "nsWhitespaceTokenizer.h"
#include "SMILEnumType.h"
#include "nsAttrValueInlines.h"
#include "mozilla/dom/SVGAnimatedPreserveAspectRatioBinding.h"
#include "SVGContentUtils.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -135,12 +135,9 @@ static nsresult
ToPreserveAspectRatio(const nsAString &aString,
SVGPreserveAspectRatio *aValue)
{
if (aString.IsEmpty() || NS_IsAsciiWhitespace(aString[0])) {
return NS_ERROR_DOM_SYNTAX_ERR;
}
nsWhitespaceTokenizer tokenizer(aString);
if (!tokenizer.hasMoreTokens()) {
nsWhitespaceTokenizerTemplate<IsSVGWhitespace> tokenizer(aString);
if (tokenizer.whitespaceBeforeFirstToken() ||
!tokenizer.hasMoreTokens()) {
return NS_ERROR_DOM_SYNTAX_ERR;
}
const nsAString &token = tokenizer.nextToken();
@ -172,7 +169,7 @@ ToPreserveAspectRatio(const nsAString &aString,
val.SetMeetOrSlice(SVG_MEETORSLICE_MEET);
}
if (tokenizer.hasMoreTokens()) {
if (tokenizer.whitespaceAfterCurrentToken()) {
return NS_ERROR_DOM_SYNTAX_ERR;
}

View File

@ -67,7 +67,7 @@ SVGLengthList::SetValueFromString(const nsAString& aValue)
return NS_ERROR_OUT_OF_MEMORY;
}
}
if (tokenizer.lastTokenEndedWithSeparator()) {
if (tokenizer.separatorAfterCurrentToken()) {
return NS_ERROR_DOM_SYNTAX_ERR; // trailing comma
}
return CopyFrom(temp);

View File

@ -4,15 +4,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SVGMotionSMILAnimationFunction.h"
#include "nsSMILParserUtils.h"
#include "nsSVGAngle.h"
#include "SVGMotionSMILType.h"
#include "SVGMotionSMILPathUtils.h"
#include "nsSVGPathDataParser.h"
#include "mozilla/dom/SVGAnimationElement.h"
#include "mozilla/dom/SVGPathElement.h" // for nsSVGPathList
#include "mozilla/dom/SVGMPathElement.h"
#include "nsAttrValue.h"
#include "nsAttrValueInlines.h"
#include "nsSMILParserUtils.h"
#include "nsSVGAngle.h"
#include "nsSVGPathDataParser.h"
#include "SVGMotionSMILType.h"
#include "SVGMotionSMILPathUtils.h"
namespace mozilla {

View File

@ -106,7 +106,7 @@ SVGMotionSMILPathUtils::PathGenerator::
return false;
}
if (tokenizer.lastTokenEndedWithSeparator() || // Trailing comma.
if (tokenizer.separatorAfterCurrentToken() || // Trailing comma.
tokenizer.hasMoreTokens()) { // More text remains
return false;
}

View File

@ -72,7 +72,7 @@ SVGNumberList::SetValueFromString(const nsAString& aValue)
return NS_ERROR_OUT_OF_MEMORY;
}
}
if (tokenizer.lastTokenEndedWithSeparator()) {
if (tokenizer.separatorAfterCurrentToken()) {
return NS_ERROR_DOM_SYNTAX_ERR; // trailing comma
}
return CopyFrom(temp);

View File

@ -110,7 +110,7 @@ SVGPointList::SetValueFromString(const nsAString& aValue)
temp.AppendItem(SVGPoint(x, y));
}
if (tokenizer.lastTokenEndedWithSeparator()) {
if (tokenizer.separatorAfterCurrentToken()) {
rv = NS_ERROR_DOM_SYNTAX_ERR; // trailing comma
}
nsresult rv2 = CopyFrom(temp);

View File

@ -54,11 +54,11 @@ SVGStringList::SetValue(const nsAString& aValue)
return NS_ERROR_OUT_OF_MEMORY;
}
}
if (tokenizer.lastTokenEndedWithSeparator()) {
if (tokenizer.separatorAfterCurrentToken()) {
return NS_ERROR_DOM_SYNTAX_ERR; // trailing comma
}
} else {
nsWhitespaceTokenizer tokenizer(aValue);
nsWhitespaceTokenizerTemplate<IsSVGWhitespace> tokenizer(aValue);
while (tokenizer.hasMoreTokens()) {
if (!temp.AppendItem(tokenizer.nextToken())) {

View File

@ -6,11 +6,10 @@
#include "mozilla/dom/SVGTransform.h"
#include "mozilla/dom/SVGMatrix.h"
#include "mozilla/dom/SVGTransformBinding.h"
#include "nsError.h"
#include "nsAttrValueInlines.h"
#include "nsSVGAnimatedTransformList.h"
#include "nsSVGAttrTearoffTable.h"
#include "mozilla/dom/SVGTransformBinding.h"
namespace mozilla {
namespace dom {

View File

@ -6,17 +6,15 @@
#include "mozilla/Util.h"
#include "nsSVGAngle.h"
#include "prdtoa.h"
#include "nsTextFormatter.h"
#include "nsSVGAttrTearoffTable.h"
#include "mozilla/dom/SVGMarkerElement.h"
#include "nsMathUtils.h"
#include "nsContentUtils.h" // NS_ENSURE_FINITE
#include "nsSMILValue.h"
#include "SVGOrientSMILType.h"
#include "nsAttrValueInlines.h"
#include "nsSVGAttrTearoffTable.h"
#include "nsTextFormatter.h"
#include "prdtoa.h"
#include "SVGAngle.h"
#include "SVGAnimatedAngle.h"
#include "SVGOrientSMILType.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -104,7 +102,7 @@ GetValueFromString(const nsAString &aValueAsString,
NS_ConvertUTF16toUTF8 value(aValueAsString);
const char *str = value.get();
if (NS_IsAsciiWhitespace(*str))
if (IsSVGWhitespace(*str))
return NS_ERROR_DOM_SYNTAX_ERR;
char *rest;

View File

@ -8,6 +8,7 @@
#include "nsSVGInteger.h"
#include "nsSMILValue.h"
#include "SMILIntegerType.h"
#include "SVGContentUtils.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -24,7 +25,7 @@ GetValueFromString(const nsAString &aValueAsString,
NS_ConvertUTF16toUTF8 value(aValueAsString);
const char *str = value.get();
if (NS_IsAsciiWhitespace(*str))
if (IsSVGWhitespace(*str))
return NS_ERROR_DOM_SYNTAX_ERR;
char *rest;

View File

@ -29,7 +29,7 @@ ParseIntegerOptionalInteger(const nsAString& aValue,
nsCharSeparatedTokenizerTemplate<IsSVGWhitespace>
tokenizer(aValue, ',',
nsCharSeparatedTokenizer::SEPARATOR_OPTIONAL);
if (tokenizer.firstTokenBeganWithWhitespace()) {
if (tokenizer.whitespaceBeforeFirstToken()) {
return NS_ERROR_DOM_SYNTAX_ERR;
}
@ -53,8 +53,8 @@ ParseIntegerOptionalInteger(const nsAString& aValue,
if (i == 0 || // Too few values.
tokenizer.hasMoreTokens() || // Too many values.
tokenizer.lastTokenEndedWithWhitespace() || // Trailing whitespace.
tokenizer.lastTokenEndedWithSeparator()) { // Trailing comma.
tokenizer.whitespaceAfterCurrentToken() || // Trailing whitespace.
tokenizer.separatorAfterCurrentToken()) { // Trailing comma.
return NS_ERROR_DOM_SYNTAX_ERR;
}

View File

@ -6,17 +6,16 @@
#include "mozilla/Util.h"
#include "nsSVGLength2.h"
#include "prdtoa.h"
#include "nsTextFormatter.h"
#include "mozilla/dom/SVGSVGElement.h"
#include "nsIFrame.h"
#include "nsSVGIntegrationUtils.h"
#include "nsSVGAttrTearoffTable.h"
#include "nsContentUtils.h" // NS_ENSURE_FINITE
#include "nsSMILValue.h"
#include "nsSMILFloatType.h"
#include "nsAttrValueInlines.h"
#include "mozilla/dom/SVGAnimatedLength.h"
#include "mozilla/dom/SVGSVGElement.h"
#include "nsContentUtils.h" // NS_ENSURE_FINITE
#include "nsIFrame.h"
#include "nsSMILFloatType.h"
#include "nsSMILValue.h"
#include "nsSVGAttrTearoffTable.h"
#include "nsSVGIntegrationUtils.h"
#include "nsTextFormatter.h"
#include "prdtoa.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -131,7 +130,7 @@ GetValueFromString(const nsAString &aValueAsString,
NS_ConvertUTF16toUTF8 value(aValueAsString);
const char *str = value.get();
if (NS_IsAsciiWhitespace(*str))
if (IsSVGWhitespace(*str))
return NS_ERROR_DOM_SYNTAX_ERR;
char *rest;

View File

@ -3,16 +3,16 @@
* 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 "nsError.h"
#include "nsSVGAttrTearoffTable.h"
#include "nsSVGNumber2.h"
#include "prdtoa.h"
#include "nsMathUtils.h"
#include "nsContentUtils.h" // NS_ENSURE_FINITE
#include "nsSMILValue.h"
#include "nsSMILFloatType.h"
#include "nsIDOMSVGNumber.h"
#include "mozilla/Attributes.h"
#include "nsContentUtils.h" // NS_ENSURE_FINITE
#include "nsError.h"
#include "nsIDOMSVGNumber.h"
#include "nsSMILFloatType.h"
#include "nsSMILValue.h"
#include "nsSVGAttrTearoffTable.h"
#include "prdtoa.h"
#include "SVGContentUtils.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -58,7 +58,7 @@ GetValueFromString(const nsAString &aValueAsString,
NS_ConvertUTF16toUTF8 value(aValueAsString);
const char *str = value.get();
if (NS_IsAsciiWhitespace(*str))
if (IsSVGWhitespace(*str))
return NS_ERROR_DOM_SYNTAX_ERR;
char *rest;

View File

@ -28,7 +28,7 @@ ParseNumberOptionalNumber(const nsAString& aValue,
nsCharSeparatedTokenizerTemplate<IsSVGWhitespace>
tokenizer(aValue, ',',
nsCharSeparatedTokenizer::SEPARATOR_OPTIONAL);
if (tokenizer.firstTokenBeganWithWhitespace()) {
if (tokenizer.whitespaceBeforeFirstToken()) {
return NS_ERROR_DOM_SYNTAX_ERR;
}
@ -52,8 +52,8 @@ ParseNumberOptionalNumber(const nsAString& aValue,
if (i == 0 || // Too few values.
tokenizer.hasMoreTokens() || // Too many values.
tokenizer.lastTokenEndedWithWhitespace() || // Trailing whitespace.
tokenizer.lastTokenEndedWithSeparator()) { // Trailing comma.
tokenizer.whitespaceAfterCurrentToken() || // Trailing whitespace.
tokenizer.separatorAfterCurrentToken()) { // Trailing comma.
return NS_ERROR_DOM_SYNTAX_ERR;
}

View File

@ -7,11 +7,9 @@
#include "prdtoa.h"
#include "nsTextFormatter.h"
#include "nsCharSeparatedTokenizer.h"
#include "nsMathUtils.h"
#include "nsSMILValue.h"
#include "SVGContentUtils.h"
#include "SVGViewBoxSMILType.h"
#include "nsAttrValueInlines.h"
#define NUM_VIEWBOX_COMPONENTS 4
using namespace mozilla;
@ -139,7 +137,7 @@ ToSVGViewBoxRect(const nsAString& aStr, nsSVGViewBoxRect *aViewBox)
if (i != NUM_VIEWBOX_COMPONENTS || // Too few values.
tokenizer.hasMoreTokens() || // Too many values.
tokenizer.lastTokenEndedWithSeparator()) { // Trailing comma.
tokenizer.separatorAfterCurrentToken()) { // Trailing comma.
return NS_ERROR_DOM_SYNTAX_ERR;
}

View File

@ -198,11 +198,14 @@ function runTests()
// enum attribute
is(1, SVGFEConvolveMatrixElement.SVG_EDGEMODE_DUPLICATE, "SVG_EDGEMODE_DUPLICATE value");
is(2, SVGFEConvolveMatrixElement.SVG_EDGEMODE_WRAP, "SVG_EDGEMODE_WRAP value");
convolve.setAttribute("edgeMode", "wrap");
is(convolve.edgeMode.baseVal, 2, "enum baseVal");
is(convolve.edgeMode.animVal, 2, "enum animVal");
convolve.edgeMode.baseVal = 1;
is(convolve.edgeMode.animVal, 1, "enum animVal");
is(convolve.edgeMode.baseVal, SVGFEConvolveMatrixElement.SVG_EDGEMODE_WRAP, "enum baseVal");
is(convolve.edgeMode.animVal, SVGFEConvolveMatrixElement.SVG_EDGEMODE_WRAP, "enum animVal");
convolve.edgeMode.baseVal = SVGFEConvolveMatrixElement.SVG_EDGEMODE_DUPLICATE;
is(convolve.edgeMode.animVal, SVGFEConvolveMatrixElement.SVG_EDGEMODE_DUPLICATE, "enum animVal");
is(convolve.getAttribute("edgeMode"), "duplicate", "enum attribute");
convolve.setAttribute("edgeMode", "");
ok(convolve.getAttribute("edgeMode") === "", "empty enum attribute");
@ -224,26 +227,58 @@ function runTests()
// preserveAspectRatio attribute
is(0, SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_UNKNOWN, "SVG_PRESERVEASPECTRATIO_UNKNOWN value");
is(1, SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_NONE, "SVG_PRESERVEASPECTRATIO_NONE value");
is(3, SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN, "SVG_PRESERVEASPECTRATIO_XMIDYMIN value");
is(5, SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMID, "SVG_PRESERVEASPECTRATIO_XMINYMID value");
is(7, SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMID, "SVG_PRESERVEASPECTRATIO_XMAXYMID value");
is(10, SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMAX , "SVG_PRESERVEASPECTRATIO_XMAXYMAX value");
is(0, SVGPreserveAspectRatio.SVG_MEETORSLICE_UNKNOWN, "SVG_MEETORSLICE_UNKNOWN value");
is(1, SVGPreserveAspectRatio.SVG_MEETORSLICE_MEET, "SVG_MEETORSLICE_MEET value");
is(2, SVGPreserveAspectRatio.SVG_MEETORSLICE_SLICE, "SVG_MEETORSLICE_SLICE value");
marker.setAttribute("preserveAspectRatio", "xMinYMid slice");
is(marker.preserveAspectRatio.baseVal.align, 5, "preserveAspectRatio.align baseVal");
is(marker.preserveAspectRatio.animVal.align, 5, "preserveAspectRatio.align animVal");
is(marker.preserveAspectRatio.baseVal.meetOrSlice, 2, "preserveAspectRatio.meetOrSlice baseVal");
is(marker.preserveAspectRatio.animVal.meetOrSlice, 2, "preserveAspectRatio.meetOrSlice animVal");
marker.preserveAspectRatio.baseVal.align = 3;
is(marker.preserveAspectRatio.animVal.align, 3, "preserveAspectRatio animVal");
is(marker.preserveAspectRatio.animVal.meetOrSlice, 2, "preserveAspectRatio.meetOrSlice animVal");
marker.preserveAspectRatio.baseVal.meetOrSlice = 1;
is(marker.preserveAspectRatio.animVal.align, 3, "preserveAspectRatio animVal");
is(marker.preserveAspectRatio.animVal.meetOrSlice, 1, "preserveAspectRatio.meetOrSlice animVal");
is(marker.preserveAspectRatio.baseVal.align,
SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMID, "preserveAspectRatio.align baseVal");
is(marker.preserveAspectRatio.animVal.align,
SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMID, "preserveAspectRatio.align animVal");
is(marker.preserveAspectRatio.baseVal.meetOrSlice,
SVGPreserveAspectRatio.SVG_MEETORSLICE_SLICE, "preserveAspectRatio.meetOrSlice baseVal");
is(marker.preserveAspectRatio.animVal.meetOrSlice,
SVGPreserveAspectRatio.SVG_MEETORSLICE_SLICE, "preserveAspectRatio.meetOrSlice animVal");
marker.preserveAspectRatio.baseVal.align =
SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN;
is(marker.preserveAspectRatio.animVal.align,
SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN, "preserveAspectRatio animVal");
is(marker.preserveAspectRatio.animVal.meetOrSlice,
SVGPreserveAspectRatio.SVG_MEETORSLICE_SLICE, "preserveAspectRatio.meetOrSlice animVal");
marker.preserveAspectRatio.baseVal.meetOrSlice = SVGPreserveAspectRatio.SVG_MEETORSLICE_MEET;
is(marker.preserveAspectRatio.animVal.align,
SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN, "preserveAspectRatio animVal");
is(marker.preserveAspectRatio.animVal.meetOrSlice,
SVGPreserveAspectRatio.SVG_MEETORSLICE_MEET, "preserveAspectRatio.meetOrSlice animVal");
is(marker.getAttribute("preserveAspectRatio"), "xMidYMin meet", "preserveAspectRatio attribute");
var basePreserveAspectRatio = marker.preserveAspectRatio.baseVal;
var animPreserveAspectRatio = marker.preserveAspectRatio.animVal;
marker.setAttribute("preserveAspectRatio", "xMaxYMid slice");
is(basePreserveAspectRatio.align, 7, "preserveAspectRatio.align baseVal");
is(animPreserveAspectRatio.align, 7, "preserveAspectRatio.align animVal");
is(basePreserveAspectRatio.meetOrSlice, 2, "preserveAspectRatio.meetOrSlice baseVal");
is(animPreserveAspectRatio.meetOrSlice, 2, "preserveAspectRatio.meetOrSlice animVal");
is(basePreserveAspectRatio.align,
SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMID, "preserveAspectRatio.align baseVal");
is(animPreserveAspectRatio.align,
SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMID, "preserveAspectRatio.align animVal");
is(basePreserveAspectRatio.meetOrSlice,
SVGPreserveAspectRatio.SVG_MEETORSLICE_SLICE, "preserveAspectRatio.meetOrSlice baseVal");
is(animPreserveAspectRatio.meetOrSlice,
SVGPreserveAspectRatio.SVG_MEETORSLICE_SLICE, "preserveAspectRatio.meetOrSlice animVal");
marker.setAttribute("preserveAspectRatio", " none"); // invalid, space at beginning
is(basePreserveAspectRatio.align, SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID,
"default preserveAspectRatio attribute");
marker.setAttribute("preserveAspectRatio", "none "); // invalid, space at end
is(basePreserveAspectRatio.align, SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID,
"default preserveAspectRatio attribute");
marker.setAttribute("preserveAspectRatio", "");
ok(marker.getAttribute("preserveAspectRatio") === "",

View File

@ -432,12 +432,12 @@ MessagePort::GetOnmessage()
}
void
MessagePort::SetOnmessage(EventHandlerNonNull* aCallback, ErrorResult& aRv)
MessagePort::SetOnmessage(EventHandlerNonNull* aCallback)
{
if (NS_IsMainThread()) {
SetEventHandler(nsGkAtoms::onmessage, EmptyString(), aCallback, aRv);
SetEventHandler(nsGkAtoms::onmessage, EmptyString(), aCallback);
} else {
SetEventHandler(nullptr, NS_LITERAL_STRING("message"), aCallback, aRv);
SetEventHandler(nullptr, NS_LITERAL_STRING("message"), aCallback);
}
// When using onmessage, the call to start() is implied.

View File

@ -52,7 +52,7 @@ public:
GetOnmessage();
void
SetOnmessage(EventHandlerNonNull* aCallback, ErrorResult& aRv);
SetOnmessage(EventHandlerNonNull* aCallback);
// Non WebIDL methods

View File

@ -12056,9 +12056,8 @@ nsGlobalWindow::DisableNetworkEvent(uint32_t aType)
JS_ObjectIsCallable(cx, callable = &v.toObject())) { \
handler = new EventHandlerNonNull(callable); \
} \
ErrorResult rv; \
SetOn##name_(handler, rv); \
return rv.ErrorCode(); \
SetOn##name_(handler); \
return NS_OK; \
}
#define ERROR_EVENT(name_, id_, type_, struct_) \
NS_IMETHODIMP nsGlobalWindow::GetOn##name_(JSContext *cx, \
@ -12087,7 +12086,8 @@ nsGlobalWindow::DisableNetworkEvent(uint32_t aType)
JS_ObjectIsCallable(cx, callable = &v.toObject())) { \
handler = new OnErrorEventHandlerNonNull(callable); \
} \
return elm->SetEventHandler(handler); \
elm->SetEventHandler(handler); \
return NS_OK; \
}
#define BEFOREUNLOAD_EVENT(name_, id_, type_, struct_) \
NS_IMETHODIMP nsGlobalWindow::GetOn##name_(JSContext *cx, \
@ -12117,7 +12117,8 @@ nsGlobalWindow::DisableNetworkEvent(uint32_t aType)
JS_ObjectIsCallable(cx, callable = &v.toObject())) { \
handler = new BeforeUnloadEventHandlerNonNull(callable); \
} \
return elm->SetEventHandler(handler); \
elm->SetEventHandler(handler); \
return NS_OK; \
}
#define WINDOW_ONLY_EVENT EVENT
#define TOUCH_EVENT EVENT

View File

@ -707,15 +707,11 @@ public:
return elm ? elm->GetEventHandler(nsGkAtoms::on##name_, EmptyString()) \
: nullptr; \
} \
void SetOn##name_(mozilla::dom::EventHandlerNonNull* handler, \
mozilla::ErrorResult& error) \
void SetOn##name_(mozilla::dom::EventHandlerNonNull* handler) \
{ \
nsEventListenerManager *elm = GetListenerManager(true); \
if (elm) { \
error = elm->SetEventHandler(nsGkAtoms::on##name_, EmptyString(), \
handler); \
} else { \
error.Throw(NS_ERROR_OUT_OF_MEMORY); \
elm->SetEventHandler(nsGkAtoms::on##name_, EmptyString(), handler); \
} \
}
#define ERROR_EVENT(name_, id_, type_, struct_) \
@ -724,14 +720,11 @@ public:
nsEventListenerManager *elm = GetListenerManager(false); \
return elm ? elm->GetOnErrorEventHandler() : nullptr; \
} \
void SetOn##name_(mozilla::dom::OnErrorEventHandlerNonNull* handler, \
mozilla::ErrorResult& error) \
void SetOn##name_(mozilla::dom::OnErrorEventHandlerNonNull* handler) \
{ \
nsEventListenerManager *elm = GetListenerManager(true); \
if (elm) { \
error = elm->SetEventHandler(handler); \
} else { \
error.Throw(NS_ERROR_OUT_OF_MEMORY); \
elm->SetEventHandler(handler); \
} \
}
#define BEFOREUNLOAD_EVENT(name_, id_, type_, struct_) \
@ -740,14 +733,11 @@ public:
nsEventListenerManager *elm = GetListenerManager(false); \
return elm ? elm->GetOnBeforeUnloadEventHandler() : nullptr; \
} \
void SetOn##name_(mozilla::dom::BeforeUnloadEventHandlerNonNull* handler, \
mozilla::ErrorResult& error) \
void SetOn##name_(mozilla::dom::BeforeUnloadEventHandlerNonNull* handler) \
{ \
nsEventListenerManager *elm = GetListenerManager(true); \
if (elm) { \
error = elm->SetEventHandler(handler); \
} else { \
error.Throw(NS_ERROR_OUT_OF_MEMORY); \
elm->SetEventHandler(handler); \
} \
}
#define WINDOW_ONLY_EVENT EVENT

View File

@ -104,6 +104,10 @@ DOMInterfaces = {
'resultNotAddRefed': [ 'destination', 'listener' ],
},
'AudioBuffer': {
'implicitJSContext': [ 'copyToChannel' ],
},
'AudioBufferSourceNode': {
'implicitJSContext': [ 'buffer' ],
'resultNotAddRefed': [ 'playbackRate' ],

View File

@ -25,8 +25,8 @@ linked_generated_events_cpp_files := $(subst .webidl,.cpp,$(generated_events_web
all_webidl_files += $(test_webidl_files)
binding_header_files := $(subst .webidl,Binding.h,$(all_webidl_files))
binding_cpp_files := $(subst .webidl,Binding.cpp,$(all_webidl_files))
generated_header_files := $(subst .webidl,Binding.h,$(all_webidl_files)) $(exported_generated_events_headers)
generated_cpp_files := $(subst .webidl,Binding.cpp,$(all_webidl_files)) $(linked_generated_events_cpp_files)
# We want to be able to only regenerate the .cpp and .h files that really need
# to change when a .webidl file changes. We do this by making the
@ -174,9 +174,9 @@ $(preprocessed_webidl_files): %: $(webidl_base)/% $(GLOBAL_DEPS)
all_webidl_files_absolute = $(addprefix $(CURDIR)/,$(all_webidl_files))
$(all_webidl_files_absolute): $(CURDIR)/%: %
$(binding_header_files): .BindingGen
$(generated_header_files): .BindingGen
$(binding_cpp_files): .BindingGen
$(generated_cpp_files): .BindingGen
# $(binding_dependency_trackers) pick up additional dependencies via .pp files
# The rule: just brings the tracker up to date, if it's out of date, so that
@ -264,14 +264,14 @@ GARBAGE += \
# headers they depend on. This is really only needed for the test files, since
# the non-test headers are all exported above anyway. Note that this means that
# we do all of our codegen during export.
webidl:: $(binding_header_files)
webidl:: $(generated_header_files)
.PHONY: webidl
distclean::
-$(RM) \
$(binding_header_files) \
$(binding_cpp_files) \
$(generated_header_files) \
$(generated_cpp_files) \
$(all_webidl_files) \
$(globalgen_targets) \
ParserResults.pkl \

View File

@ -83,6 +83,8 @@ ResponseTypeSyncXHRWarning=Use of XMLHttpRequest's responseType attribute is no
WithCredentialsSyncXHRWarning=Use of XMLHttpRequest's withCredentials attribute is no longer supported in the synchronous mode in window context.
TimeoutSyncXHRWarning=Use of XMLHttpRequest's timeout attribute is not supported in the synchronous mode in window context.
JSONCharsetWarning=An attempt was made to declare a non-UTF-8 encoding for JSON retrieved using XMLHttpRequest. Only UTF-8 is supported for decoding JSON.
# LOCALIZATION NOTE: Do not translate DelayNode
AudioNodeCycleWithoutDelay=Cycles in audio graphs are only supported if they contain at least one DelayNode.
# LOCALIZATION NOTE: Do not translate AudioBufferSourceNode
MediaBufferSourceNodeResampleOutOfMemory=Insufficient memory to resample the AudioBufferSourceNode for playback.
# LOCALIZATION NOTE: Do not translate decodeAudioData.

View File

@ -4,8 +4,12 @@
"use strict";
// Don't modify this, instead set services.push.debug.
let gDebuggingEnabled = false;
function debug(s) {
// dump("-*- Push.js: " + s + "\n");
if (gDebuggingEnabled)
dump("-*- Push.js: " + s + "\n");
}
const Cc = Components.classes;
@ -39,6 +43,10 @@ Push.prototype = {
Ci.nsISupportsWeakReference]),
init: function(aWindow) {
// Set debug first so that all debugging actually works.
// NOTE: We don't add an observer here like in PushService. Flipping the
// pref will require a reload of the app/page, which seems acceptable.
gDebuggingEnabled = Services.prefs.getBoolPref("services.push.debug");
debug("init()");
let principal = aWindow.document.nodePrincipal;
@ -96,7 +104,7 @@ Push.prototype = {
register: function() {
debug("register()");
var req = this.createRequest();
let req = this.createRequest();
if (!Services.prefs.getBoolPref("services.push.connection.enabled")) {
// If push socket is disabled by the user, immediately error rather than
// timing out.
@ -114,7 +122,7 @@ Push.prototype = {
unregister: function(aPushEndpoint) {
debug("unregister(" + aPushEndpoint + ")");
var req = this.createRequest();
let req = this.createRequest();
this._cpmm.sendAsyncMessage("Push:Unregister", {
pageURL: this._pageURL.spec,
manifestURL: this._manifestURL,
@ -126,7 +134,7 @@ Push.prototype = {
registrations: function() {
debug("registrations()");
var req = this.createRequest();
let req = this.createRequest();
this._cpmm.sendAsyncMessage("Push:Registrations", {
manifestURL: this._manifestURL,
requestID: this.getRequestId(req)

View File

@ -4,8 +4,12 @@
"use strict";
// Don't modify this, instead set services.push.debug.
let gDebuggingEnabled = false;
function debug(s) {
// dump("-*- PushService.jsm: " + s + "\n");
if (gDebuggingEnabled)
dump("-*- PushService.jsm: " + s + "\n");
}
const Cc = Components.classes;
@ -26,6 +30,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "AlarmService",
this.EXPORTED_SYMBOLS = ["PushService"];
const prefs = new Preferences("services.push.");
// Set debug first so that all debugging actually works.
gDebuggingEnabled = prefs.get("debug");
const kPUSHDB_DB_NAME = "push";
const kPUSHDB_DB_VERSION = 1; // Change this if the IndexedDB format changes
@ -126,7 +132,7 @@ this.PushDB.prototype = {
function txnCb(aTxn, aStore) {
aTxn.result = undefined;
var index = aStore.index("pushEndpoint");
let index = aStore.index("pushEndpoint");
index.get(aPushEndpoint).onsuccess = function setTxnResult(aEvent) {
aTxn.result = aEvent.target.result;
debug("Fetch successful " + aEvent.target.result);
@ -165,16 +171,16 @@ this.PushDB.prototype = {
return;
}
var self = this;
let self = this;
this.newTxn(
"readonly",
kPUSHDB_STORE_NAME,
function txnCb(aTxn, aStore) {
var index = aStore.index("manifestURL");
var range = self.dbGlobal.IDBKeyRange.only(aManifestURL);
let index = aStore.index("manifestURL");
let range = self.dbGlobal.IDBKeyRange.only(aManifestURL);
aTxn.result = [];
index.openCursor(range).onsuccess = function(event) {
var cursor = event.target.result;
let cursor = event.target.result;
if (cursor) {
debug(cursor.value.manifestURL + " " + cursor.value.channelID);
aTxn.result.push(cursor.value);
@ -318,6 +324,8 @@ this.PushService = {
} else {
this._shutdownWS();
}
} else if (aData == "services.push.debug") {
gDebuggingEnabled = prefs.get("debug");
}
break;
case "timer-callback":
@ -325,15 +333,15 @@ this.PushService = {
if (Object.keys(this._pendingRequests).length == 0)
this._requestTimeoutTimer.cancel();
for (var channelID in this._pendingRequests) {
var duration = Date.now() - this._pendingRequests[channelID].ctime;
for (let channelID in this._pendingRequests) {
let duration = Date.now() - this._pendingRequests[channelID].ctime;
if (duration > this._requestTimeout) {
debug("Request timeout: Removing " + channelID);
this._pendingRequests[channelID]
.deferred.reject({status: 0, error: "Timeout"});
delete this._pendingRequests[channelID];
for (var i = this._requestQueue.length - 1; i >= 0; --i)
for (let i = this._requestQueue.length - 1; i >= 0; --i)
if (this._requestQueue[i].channelID == channelID)
this._requestQueue.splice(i, 1);
}
@ -362,7 +370,7 @@ this.PushService = {
this._db.getAllByManifestURL(manifestURL, function(records) {
debug("Got " + records.length);
for (var i = 0; i < records.length; i++) {
for (let i = 0; i < records.length; i++) {
this._db.delete(records[i].channelID, null, function() {
debug("app uninstall: " + manifestURL +
" Could not delete entry " + records[i].channelID);
@ -467,6 +475,8 @@ this.PushService = {
prefs.observe("serverURL", this);
// Used to monitor if the user wishes to disable Push.
prefs.observe("connection.enabled", this);
// Debugging
prefs.observe("debug", this);
this._started = true;
},
@ -493,6 +503,7 @@ this.PushService = {
debug("uninit()");
prefs.ignore("debug", this);
prefs.ignore("connection.enabled", this);
prefs.ignore("serverURL", this);
Services.obs.removeObserver(this, this._getNetworkStateChangeEventName());
@ -547,7 +558,7 @@ this.PushService = {
debug("reconnectAfterBackoff()");
// Calculate new timeout, but cap it to pingInterval.
var retryTimeout = prefs.get("retryBaseInterval") *
let retryTimeout = prefs.get("retryBaseInterval") *
Math.pow(2, this._retryFailCount);
retryTimeout = Math.min(retryTimeout, prefs.get("pingInterval"));
@ -578,13 +589,13 @@ this.PushService = {
return;
}
var serverURL = prefs.get("serverURL");
let serverURL = prefs.get("serverURL");
if (!serverURL) {
debug("No services.push.serverURL found!");
return;
}
var uri;
let uri;
try {
uri = Services.io.newURI(serverURL, null, null);
} catch(e) {
@ -800,29 +811,7 @@ this.PushService = {
typeof this._pendingRequests[reply.channelID] !== "object")
return;
var tmp = this._pendingRequests[reply.channelID];
delete this._pendingRequests[reply.channelID];
if (Object.keys(this._pendingRequests).length == 0 &&
this._requestTimeoutTimer)
this._requestTimeoutTimer.cancel();
if (reply.status == 200) {
tmp.deferred.resolve(reply);
} else {
tmp.deferred.reject(reply);
}
},
/**
* Protocol handler invoked by server message.
*/
_handleUnregisterReply: function(reply) {
debug("handleUnregisterReply()");
if (typeof reply.channelID !== "string" ||
typeof this._pendingRequests[reply.channelID] !== "object")
return;
var tmp = this._pendingRequests[reply.channelID];
let tmp = this._pendingRequests[reply.channelID];
delete this._pendingRequests[reply.channelID];
if (Object.keys(this._pendingRequests).length == 0 &&
this._requestTimeoutTimer)
@ -846,8 +835,8 @@ this.PushService = {
}
debug("Reply updates: " + reply.updates.length);
for (var i = 0; i < reply.updates.length; i++) {
var update = reply.updates[i];
for (let i = 0; i < reply.updates.length; i++) {
let update = reply.updates[i];
debug("Update: " + update.channelID + ": " + update.version);
if (typeof update.channelID !== "string") {
debug("Invalid update literal at index " + i);
@ -859,7 +848,7 @@ this.PushService = {
continue;
}
var version = update.version;
let version = update.version;
if (typeof version === "string") {
version = parseInt(version, 10);
@ -892,7 +881,7 @@ this.PushService = {
return Promise.reject("Received non-string channelID");
}
var deferred = Promise.defer();
let deferred = Promise.defer();
if (Object.keys(this._pendingRequests).length == 0) {
// start the timer since we now have at least one request
@ -957,7 +946,7 @@ this.PushService = {
_receivedUpdate: function(aChannelID, aLatestVersion) {
debug("Updating: " + aChannelID + " -> " + aLatestVersion);
var compareRecordVersionAndNotify = function(aPushRecord) {
let compareRecordVersionAndNotify = function(aPushRecord) {
debug("compareRecordVersionAndNotify()");
if (!aPushRecord) {
debug("No record for channel ID " + aChannelID);
@ -982,7 +971,7 @@ this.PushService = {
}
}
var recoverNoSuchChannelID = function(aChannelIDFromServer) {
let recoverNoSuchChannelID = function(aChannelIDFromServer) {
debug("Could not get channelID " + aChannelIDFromServer + " from DB");
}
@ -995,15 +984,15 @@ this.PushService = {
// registrations.
_notifyAllAppsRegister: function() {
debug("notifyAllAppsRegister()");
var deferred = Promise.defer();
let deferred = Promise.defer();
// records are objects describing the registrations as stored in IndexedDB.
function wakeupRegisteredApps(records) {
// Pages to be notified.
// wakeupTable[manifestURL] -> [ pageURL ]
var wakeupTable = {};
for (var i = 0; i < records.length; i++) {
var record = records[i];
let wakeupTable = {};
for (let i = 0; i < records.length; i++) {
let record = records[i];
if (!(record.manifestURL in wakeupTable))
wakeupTable[record.manifestURL] = [];
@ -1013,7 +1002,7 @@ this.PushService = {
let messenger = Cc["@mozilla.org/system-message-internal;1"]
.getService(Ci.nsISystemMessagesInternal);
for (var manifestURL in wakeupTable) {
for (let manifestURL in wakeupTable) {
wakeupTable[manifestURL].forEach(function(pageURL) {
messenger.sendMessage('push-register', {},
Services.io.newURI(pageURL, null, null),
@ -1037,9 +1026,9 @@ this.PushService = {
debug("notifyApp() " + aPushRecord.pageURL +
" " + aPushRecord.manifestURL);
var pageURI = Services.io.newURI(aPushRecord.pageURL, null, null);
var manifestURI = Services.io.newURI(aPushRecord.manifestURL, null, null);
var message = {
let pageURI = Services.io.newURI(aPushRecord.pageURL, null, null);
let manifestURI = Services.io.newURI(aPushRecord.manifestURL, null, null);
let message = {
pushEndpoint: aPushRecord.pushEndpoint,
version: aPushRecord.version
};
@ -1050,13 +1039,13 @@ this.PushService = {
_updatePushRecord: function(aPushRecord) {
debug("updatePushRecord()");
var deferred = Promise.defer();
let deferred = Promise.defer();
this._db.put(aPushRecord, deferred.resolve, deferred.reject);
return deferred.promise;
},
_dropRegistrations: function() {
var deferred = Promise.defer();
let deferred = Promise.defer();
this._db.drop(deferred.resolve, deferred.reject);
return deferred.promise;
},
@ -1084,7 +1073,7 @@ this.PushService = {
let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
.getService(Ci.nsIUUIDGenerator);
// generateUUID() gives a UUID surrounded by {...}, slice them off.
var channelID = uuidGenerator.generateUUID().toString().slice(1, -1);
let channelID = uuidGenerator.generateUUID().toString().slice(1, -1);
this._sendRequest("register", {channelID: channelID})
.then(
@ -1106,8 +1095,8 @@ this.PushService = {
*/
_onRegisterSuccess: function(aPageRecord, generatedChannelID, data) {
debug("_onRegisterSuccess()");
var deferred = Promise.defer();
var message = { requestID: aPageRecord.requestID };
let deferred = Promise.defer();
let message = { requestID: aPageRecord.requestID };
if (typeof data.channelID !== "string") {
debug("Invalid channelID " + message);
@ -1130,7 +1119,7 @@ this.PushService = {
throw message;
}
var record = {
let record = {
channelID: data.channelID,
pushEndpoint: data.pushEndpoint,
pageURL: aPageRecord.pageURL,
@ -1146,7 +1135,7 @@ this.PushService = {
},
function(error) {
// Unable to save.
this._sendRequest("unregister", {channelID: record.channelID});
this._send("unregister", {channelID: record.channelID});
message["error"] = error;
deferred.reject(message);
}
@ -1195,9 +1184,9 @@ this.PushService = {
unregister: function(aPageRecord, aMessageManager) {
debug("unregister()");
var fail = function(error) {
let fail = function(error) {
debug("unregister() fail() error " + error);
var message = {requestID: aPageRecord.requestID, error: error};
let message = {requestID: aPageRecord.requestID, error: error};
aMessageManager.sendAsyncMessage("PushService:Unregister:KO", message);
}
@ -1248,7 +1237,7 @@ this.PushService = {
_onRegistrationsSuccess: function(aPageRecord,
aMessageManager,
pushRecords) {
var registrations = [];
let registrations = [];
pushRecords.forEach(function(pushRecord) {
registrations.push({
__exposedProps__: { pushEndpoint: 'r', version: 'r' },
@ -1281,14 +1270,14 @@ this.PushService = {
// Since we've had a successful connection reset the retry fail count.
this._retryFailCount = 0;
var data = {
let data = {
messageType: "hello",
}
if (this._UAID)
data["uaid"] = this._UAID;
var networkState = this._getNetworkState();
let networkState = this._getNetworkState();
if (networkState.ip) {
// Hostport is apparently a thing.
data["wakeup_hostport"] = {
@ -1346,7 +1335,7 @@ this.PushService = {
// handshake, so this alarm does not need to be set explicitly at startup.
this._setAlarm(prefs.get("pingInterval"));
var reply = undefined;
let reply = undefined;
try {
reply = JSON.parse(message);
} catch(e) {
@ -1361,11 +1350,11 @@ this.PushService = {
// A whitelist of protocol handlers. Add to these if new messages are added
// in the protocol.
var handlers = ["Hello", "Register", "Unregister", "Notification"];
let handlers = ["Hello", "Register", "Notification"];
// Build up the handler name to call from messageType.
// e.g. messageType == "register" -> _handleRegisterReply.
var handlerName = reply.messageType[0].toUpperCase() +
let handlerName = reply.messageType[0].toUpperCase() +
reply.messageType.slice(1).toLowerCase();
if (handlers.indexOf(handlerName) == -1) {
@ -1374,7 +1363,7 @@ this.PushService = {
return;
}
var handler = "_handle" + handlerName + "Reply";
let handler = "_handle" + handlerName + "Reply";
if (typeof this[handler] !== "function") {
debug("Handler whitelisted but not implemented! " + handler);
@ -1463,9 +1452,9 @@ this.PushService = {
throw "UDP disabled";
}
var nm = Cc["@mozilla.org/network/manager;1"].getService(Ci.nsINetworkManager);
let nm = Cc["@mozilla.org/network/manager;1"].getService(Ci.nsINetworkManager);
if (nm.active && nm.active.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE) {
var mcp = Cc["@mozilla.org/ril/content-helper;1"].getService(Ci.nsIMobileConnectionProvider);
let mcp = Cc["@mozilla.org/ril/content-helper;1"].getService(Ci.nsIMobileConnectionProvider);
if (mcp.iccInfo) {
debug("Running on mobile data");
return {

View File

@ -24,5 +24,9 @@ interface AudioBuffer {
[Throws]
Float32Array getChannelData(unsigned long channel);
[Throws]
void copyFromChannel(Float32Array destination, long channelNumber, optional unsigned long startInChannel = 0);
[Throws]
void copyToChannel(Float32Array source, long channelNumber, optional unsigned long startInChannel = 0);
};

View File

@ -27,7 +27,6 @@ interface AudioBufferSourceNode : AudioNode {
[Throws]
void stop(optional double when = 0);
[SetterThrows]
attribute EventHandler onended;
};

View File

@ -22,7 +22,6 @@ interface AudioChannelManager : EventTarget {
* speakers (or vice versa). This allows you to, for example, pause your
* window's audio when the headphones are unplugged.
*/
[SetterThrows]
attribute EventHandler onheadphoneschange;
/**

View File

@ -16,12 +16,8 @@ interface BatteryManager : EventTarget {
readonly attribute unrestricted double dischargingTime;
readonly attribute double level;
[SetterThrows]
attribute EventHandler onchargingchange;
[SetterThrows]
attribute EventHandler onchargingtimechange;
[SetterThrows]
attribute EventHandler ondischargingtimechange;
[SetterThrows]
attribute EventHandler onlevelchange;
};

View File

@ -48,27 +48,21 @@ interface BluetoothAdapter : EventTarget {
[GetterThrows]
readonly attribute any uuids;
[SetterThrows]
attribute EventHandler ondevicefound;
// Fired when pairing process is completed
[SetterThrows]
attribute EventHandler onpairedstatuschanged;
// Fired when a2dp connection status changed
[SetterThrows]
attribute EventHandler ona2dpstatuschanged;
// Fired when handsfree connection status changed
[SetterThrows]
attribute EventHandler onhfpstatuschanged;
// Fired when sco connection status changed
[SetterThrows]
attribute EventHandler onscostatuschanged;
// Fired when remote devices query current media play status
[SetterThrows]
attribute EventHandler onrequestmediaplaystatus;
[Creator, Throws]

View File

@ -7,11 +7,8 @@ interface BluetoothManager : EventTarget {
[Throws]
readonly attribute boolean enabled;
[SetterThrows]
attribute EventHandler onenabled;
[SetterThrows]
attribute EventHandler ondisabled;
[SetterThrows]
attribute EventHandler onadapteradded;
[Throws]

View File

@ -14,8 +14,6 @@ interface DOMRequest : EventTarget {
readonly attribute any result;
readonly attribute nsISupports? error;
[SetterThrows]
attribute EventHandler onsuccess;
[SetterThrows]
attribute EventHandler onerror;
};

View File

@ -21,14 +21,10 @@ interface DataChannel : EventTarget
readonly attribute boolean reliable;
readonly attribute RTCDataChannelState readyState;
readonly attribute unsigned long bufferedAmount;
[SetterThrows]
attribute EventHandler onopen;
[SetterThrows]
attribute EventHandler onerror;
[SetterThrows]
attribute EventHandler onclose;
void close();
[SetterThrows]
attribute EventHandler onmessage;
attribute RTCDataChannelType binaryType;
[Throws]

View File

@ -20,9 +20,7 @@ interface DesktopNotification : EventTarget
[Throws]
void show();
[SetterThrows]
attribute EventHandler onclick;
[SetterThrows]
attribute EventHandler onclose;
};

View File

@ -8,7 +8,6 @@ dictionary DeviceStorageEnumerationParameters {
};
interface DeviceStorage : EventTarget {
[SetterThrows]
attribute EventHandler onchange;
[Throws]

View File

@ -136,17 +136,17 @@ partial interface Document {
//(Not implemented)readonly attribute HTMLCollection commands;
// special event handler IDL attributes that only apply to Document objects
[LenientThis, SetterThrows] attribute EventHandler onreadystatechange;
[LenientThis] attribute EventHandler onreadystatechange;
// Gecko extensions?
[LenientThis, SetterThrows] attribute EventHandler onmouseenter;
[LenientThis, SetterThrows] attribute EventHandler onmouseleave;
[SetterThrows] attribute EventHandler onwheel;
[SetterThrows] attribute EventHandler oncopy;
[SetterThrows] attribute EventHandler oncut;
[SetterThrows] attribute EventHandler onpaste;
[SetterThrows] attribute EventHandler onbeforescriptexecute;
[SetterThrows] attribute EventHandler onafterscriptexecute;
[LenientThis] attribute EventHandler onmouseenter;
[LenientThis] attribute EventHandler onmouseleave;
attribute EventHandler onwheel;
attribute EventHandler oncopy;
attribute EventHandler oncut;
attribute EventHandler onpaste;
attribute EventHandler onbeforescriptexecute;
attribute EventHandler onafterscriptexecute;
/**
* True if this document is synthetic : stand alone image, video, audio file,
* etc.

View File

@ -71,11 +71,10 @@ interface Element : Node {
// Mozilla specific stuff
[SetterThrows,LenientThis]
[LenientThis]
attribute EventHandler onmouseenter;
[SetterThrows,LenientThis]
[LenientThis]
attribute EventHandler onmouseleave;
[SetterThrows]
attribute EventHandler onwheel;
// Selectors API

View File

@ -24,143 +24,85 @@ typedef OnErrorEventHandlerNonNull? OnErrorEventHandler;
[NoInterfaceObject]
interface GlobalEventHandlers {
[SetterThrows]
attribute EventHandler onabort;
//(Not implemented)[SetterThrows]
//(Not implemented)attribute EventHandler oncancel;
[SetterThrows]
attribute EventHandler oncanplay;
[SetterThrows]
attribute EventHandler oncanplaythrough;
[SetterThrows]
attribute EventHandler onchange;
[SetterThrows]
attribute EventHandler onclick;
//(Not implemented)[SetterThrows]
//(Not implemented)attribute EventHandler onclose;
[SetterThrows]
attribute EventHandler oncontextmenu;
//(Not implemented)[SetterThrows]
//(Not implemented)attribute EventHandler oncuechange;
[SetterThrows]
attribute EventHandler ondblclick;
[SetterThrows]
attribute EventHandler ondrag;
[SetterThrows]
attribute EventHandler ondragend;
[SetterThrows]
attribute EventHandler ondragenter;
[SetterThrows]
attribute EventHandler ondragleave;
[SetterThrows]
attribute EventHandler ondragover;
[SetterThrows]
attribute EventHandler ondragstart;
[SetterThrows]
attribute EventHandler ondrop;
[SetterThrows]
attribute EventHandler ondurationchange;
[SetterThrows]
attribute EventHandler onemptied;
[SetterThrows]
attribute EventHandler onended;
[SetterThrows]
attribute EventHandler oninput;
[SetterThrows]
attribute EventHandler oninvalid;
[SetterThrows]
attribute EventHandler onkeydown;
[SetterThrows]
attribute EventHandler onkeypress;
[SetterThrows]
attribute EventHandler onkeyup;
[SetterThrows]
attribute EventHandler onloadeddata;
[SetterThrows]
attribute EventHandler onloadedmetadata;
[SetterThrows]
attribute EventHandler onloadstart;
[SetterThrows]
attribute EventHandler onmousedown;
[SetterThrows]
attribute EventHandler onmousemove;
[SetterThrows]
attribute EventHandler onmouseout;
[SetterThrows]
attribute EventHandler onmouseover;
[SetterThrows]
attribute EventHandler onmouseup;
//(Not implemented)[SetterThrows]
//(Not implemented)attribute EventHandler onmousewheel;
[SetterThrows]
attribute EventHandler onpause;
[SetterThrows]
attribute EventHandler onplay;
[SetterThrows]
attribute EventHandler onplaying;
[SetterThrows]
attribute EventHandler onprogress;
[SetterThrows]
attribute EventHandler onratechange;
[SetterThrows]
attribute EventHandler onreset;
[SetterThrows]
attribute EventHandler onseeked;
[SetterThrows]
attribute EventHandler onseeking;
[SetterThrows]
attribute EventHandler onselect;
[SetterThrows]
attribute EventHandler onshow;
//(Not implemented)[SetterThrows]
//(Not implemented)attribute EventHandler onsort;
[SetterThrows]
attribute EventHandler onstalled;
[SetterThrows]
attribute EventHandler onsubmit;
[SetterThrows]
attribute EventHandler onsuspend;
[SetterThrows]
attribute EventHandler ontimeupdate;
[SetterThrows]
attribute EventHandler onvolumechange;
[SetterThrows]
attribute EventHandler onwaiting;
// Mozilla-specific handlers
[SetterThrows]
attribute EventHandler onmozfullscreenchange;
[SetterThrows]
attribute EventHandler onmozfullscreenerror;
[SetterThrows]
attribute EventHandler onmozpointerlockchange;
[SetterThrows]
attribute EventHandler onmozpointerlockerror;
};
[NoInterfaceObject]
interface NodeEventHandlers {
[SetterThrows]
attribute EventHandler onblur;
// We think the spec is wrong here.
// attribute OnErrorEventHandler onerror;
[SetterThrows]
attribute EventHandler onerror;
[SetterThrows]
attribute EventHandler onfocus;
[SetterThrows]
attribute EventHandler onload;
[SetterThrows]
attribute EventHandler onscroll;
};
[NoInterfaceObject]
interface WindowEventHandlers {
[SetterThrows]
attribute EventHandler onafterprint;
[SetterThrows]
attribute EventHandler onbeforeprint;
[SetterThrows]
attribute BeforeUnloadEventHandler onbeforeunload;
// For now, onerror comes from NodeEventHandlers
// When we convert Window to WebIDL this may need to change.
@ -170,24 +112,15 @@ interface WindowEventHandlers {
//(Not implemented)attribute EventHandler onfullscreenchange;
//(Not implemented)[SetterThrows]
//(Not implemented)attribute EventHandler onfullscreenerror;
[SetterThrows]
attribute EventHandler onhashchange;
[SetterThrows]
attribute EventHandler onmessage;
[SetterThrows]
attribute EventHandler onoffline;
[SetterThrows]
attribute EventHandler ononline;
[SetterThrows]
attribute EventHandler onpagehide;
[SetterThrows]
attribute EventHandler onpageshow;
[SetterThrows]
attribute EventHandler onpopstate;
[SetterThrows]
attribute EventHandler onresize;
//(Not implemented)[SetterThrows]
//(Not implemented)attribute EventHandler onstorage;
[SetterThrows]
attribute EventHandler onunload;
};

View File

@ -25,12 +25,9 @@ interface EventSource : EventTarget {
readonly attribute unsigned short readyState;
// networking
[SetterThrows]
attribute EventHandler onopen;
[SetterThrows]
attribute EventHandler onmessage;
[SetterThrows]
attribute EventHandler onerror;
attribute EventHandler onopen;
attribute EventHandler onmessage;
attribute EventHandler onerror;
void close();
};

View File

@ -32,22 +32,18 @@ interface FMRadio : EventTarget {
readonly attribute double channelWidth;
/* Fired when the FM radio is enabled. */
[SetterThrows]
attribute EventHandler onenabled;
/* Fired when the FM radio is disabled. */
[SetterThrows]
attribute EventHandler ondisabled;
/**
* Fired when the antenna becomes available or unavailable, i.e., fired when
* the antennaAvailable attribute changes.
*/
[SetterThrows]
attribute EventHandler onantennaavailablechange;
/* Fired when the FM radio's frequency is changed. */
[SetterThrows]
attribute EventHandler onfrequencychange;
/**

View File

@ -15,8 +15,6 @@ interface FileHandle : EventTarget {
[Throws]
DOMRequest getFile();
[SetterThrows]
attribute EventHandler onabort;
[SetterThrows]
attribute EventHandler onerror;
};

View File

@ -39,17 +39,11 @@ interface FileReader : EventTarget {
readonly attribute DOMError? error;
// event handler attributes
[SetterThrows]
attribute EventHandler onloadstart;
[SetterThrows]
attribute EventHandler onprogress;
[SetterThrows]
attribute EventHandler onload;
[SetterThrows]
attribute EventHandler onabort;
[SetterThrows]
attribute EventHandler onerror;
[SetterThrows]
attribute EventHandler onloadend;
};

View File

@ -9,6 +9,5 @@ interface LockedFile;
interface FileRequest : DOMRequest {
readonly attribute LockedFile? lockedFile;
[SetterThrows]
attribute EventHandler onprogress;
};

View File

@ -79,11 +79,8 @@ interface HTMLElement : Element {
// FIXME Bug 810677 Move className from HTMLElement to Element
attribute DOMString className;
[SetterThrows]
attribute EventHandler oncopy;
[SetterThrows]
attribute EventHandler oncut;
[SetterThrows]
attribute EventHandler onpaste;
};
@ -99,17 +96,17 @@ partial interface HTMLElement {
[NoInterfaceObject]
interface TouchEventHandlers {
[SetterThrows,Func="nsGenericHTMLElement::TouchEventsEnabled"]
[Func="nsGenericHTMLElement::TouchEventsEnabled"]
attribute EventHandler ontouchstart;
[SetterThrows,Func="nsGenericHTMLElement::TouchEventsEnabled"]
[Func="nsGenericHTMLElement::TouchEventsEnabled"]
attribute EventHandler ontouchend;
[SetterThrows,Func="nsGenericHTMLElement::TouchEventsEnabled"]
[Func="nsGenericHTMLElement::TouchEventsEnabled"]
attribute EventHandler ontouchmove;
[SetterThrows,Func="nsGenericHTMLElement::TouchEventsEnabled"]
[Func="nsGenericHTMLElement::TouchEventsEnabled"]
attribute EventHandler ontouchenter;
[SetterThrows,Func="nsGenericHTMLElement::TouchEventsEnabled"]
[Func="nsGenericHTMLElement::TouchEventsEnabled"]
attribute EventHandler ontouchleave;
[SetterThrows,Func="nsGenericHTMLElement::TouchEventsEnabled"]
[Func="nsGenericHTMLElement::TouchEventsEnabled"]
attribute EventHandler ontouchcancel;
};

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