mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge mozilla-central and inbound
This commit is contained in:
commit
c39b834022
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
3
content/base/test/chrome/nochrome_bug765993.html
Normal file
3
content/base/test/chrome/nochrome_bug765993.html
Normal file
@ -0,0 +1,3 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
</html>
|
4
content/base/test/chrome/nochrome_bug765993.js
Normal file
4
content/base/test/chrome/nochrome_bug765993.js
Normal file
@ -0,0 +1,4 @@
|
||||
//@ sourceMappingURL=bar.js.map
|
||||
|
||||
// Define a single function to prevent script source from being gc'd
|
||||
function foo() {}
|
1
content/base/test/chrome/nochrome_bug765993.js^headers^
Normal file
1
content/base/test/chrome/nochrome_bug765993.js^headers^
Normal file
@ -0,0 +1 @@
|
||||
X-SourceMap: foo.js.map
|
62
content/base/test/chrome/test_bug765993.html
Normal file
62
content/base/test/chrome/test_bug765993.html
Normal 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>
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
@ -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*
|
||||
|
@ -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.
|
||||
|
@ -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_) \
|
||||
|
@ -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_) \
|
||||
|
@ -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_) \
|
||||
|
@ -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_) \
|
||||
|
@ -6096,7 +6096,7 @@ HTMLInputElement::IsValidEmailAddressList(const nsAString& aValue)
|
||||
}
|
||||
}
|
||||
|
||||
return !tokenizer.lastTokenEndedWithSeparator();
|
||||
return !tokenizer.separatorAfterCurrentToken();
|
||||
}
|
||||
|
||||
//static
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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; }
|
||||
};
|
||||
|
@ -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()
|
||||
|
@ -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
135
content/media/Latency.cpp
Normal 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
60
content/media/Latency.h
Normal 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
|
@ -21,5 +21,6 @@ endif
|
||||
|
||||
CFLAGS += $(GSTREAMER_CFLAGS)
|
||||
CXXFLAGS += $(GSTREAMER_CFLAGS)
|
||||
DEFINES += -DMOZILLA_INTERNAL_API
|
||||
|
||||
AudioNodeEngineNEON.$(OBJ_SUFFIX): CXXFLAGS += -mfpu=neon
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -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',
|
||||
|
104
content/media/test/graph_latency.py
Normal file
104
content/media/test/graph_latency.py
Normal 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)
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -495,7 +495,10 @@ AudioContext::Graph() const
|
||||
MediaStream*
|
||||
AudioContext::DestinationStream() const
|
||||
{
|
||||
return Destination()->Stream();
|
||||
if (Destination()) {
|
||||
return Destination()->Stream();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
double
|
||||
|
@ -130,6 +130,10 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual const DelayNode* AsDelayNode() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AudioContext* GetParentObject() const
|
||||
{
|
||||
return mContext;
|
||||
|
@ -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);
|
||||
|
@ -32,6 +32,11 @@ public:
|
||||
return mDelay;
|
||||
}
|
||||
|
||||
virtual const DelayNode* AsDelayNode() const MOZ_OVERRIDE
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
virtual void NotifyInputConnected() MOZ_OVERRIDE
|
||||
{
|
||||
mMediaStreamGraphUpdateIndexAtLastInputConnection =
|
||||
|
@ -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)
|
||||
|
@ -98,6 +98,7 @@ public:
|
||||
: mOutputQueue("SharedBuffers::outputQueue")
|
||||
, mDelaySoFar(TRACK_TICKS_MAX)
|
||||
, mSampleRate(aSampleRate)
|
||||
, mLatency(0.0)
|
||||
, mDroppingBuffers(false)
|
||||
{
|
||||
}
|
||||
|
@ -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 \
|
||||
|
@ -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);
|
||||
|
170
content/media/webaudio/test/test_delayNodeCycles.html
Normal file
170
content/media/webaudio/test/test_delayNodeCycles.html
Normal 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>
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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())) {
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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") === "",
|
||||
|
@ -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.
|
||||
|
@ -52,7 +52,7 @@ public:
|
||||
GetOnmessage();
|
||||
|
||||
void
|
||||
SetOnmessage(EventHandlerNonNull* aCallback, ErrorResult& aRv);
|
||||
SetOnmessage(EventHandlerNonNull* aCallback);
|
||||
|
||||
// Non WebIDL methods
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -104,6 +104,10 @@ DOMInterfaces = {
|
||||
'resultNotAddRefed': [ 'destination', 'listener' ],
|
||||
},
|
||||
|
||||
'AudioBuffer': {
|
||||
'implicitJSContext': [ 'copyToChannel' ],
|
||||
},
|
||||
|
||||
'AudioBufferSourceNode': {
|
||||
'implicitJSContext': [ 'buffer' ],
|
||||
'resultNotAddRefed': [ 'playbackRate' ],
|
||||
|
@ -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 \
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -27,7 +27,6 @@ interface AudioBufferSourceNode : AudioNode {
|
||||
[Throws]
|
||||
void stop(optional double when = 0);
|
||||
|
||||
[SetterThrows]
|
||||
attribute EventHandler onended;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -14,8 +14,6 @@ interface DOMRequest : EventTarget {
|
||||
readonly attribute any result;
|
||||
readonly attribute nsISupports? error;
|
||||
|
||||
[SetterThrows]
|
||||
attribute EventHandler onsuccess;
|
||||
[SetterThrows]
|
||||
attribute EventHandler onerror;
|
||||
};
|
||||
|
@ -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]
|
||||
|
@ -20,9 +20,7 @@ interface DesktopNotification : EventTarget
|
||||
[Throws]
|
||||
void show();
|
||||
|
||||
[SetterThrows]
|
||||
attribute EventHandler onclick;
|
||||
|
||||
[SetterThrows]
|
||||
attribute EventHandler onclose;
|
||||
};
|
||||
|
@ -8,7 +8,6 @@ dictionary DeviceStorageEnumerationParameters {
|
||||
};
|
||||
|
||||
interface DeviceStorage : EventTarget {
|
||||
[SetterThrows]
|
||||
attribute EventHandler onchange;
|
||||
|
||||
[Throws]
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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();
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
|
@ -15,8 +15,6 @@ interface FileHandle : EventTarget {
|
||||
[Throws]
|
||||
DOMRequest getFile();
|
||||
|
||||
[SetterThrows]
|
||||
attribute EventHandler onabort;
|
||||
[SetterThrows]
|
||||
attribute EventHandler onerror;
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -9,6 +9,5 @@ interface LockedFile;
|
||||
interface FileRequest : DOMRequest {
|
||||
readonly attribute LockedFile? lockedFile;
|
||||
|
||||
[SetterThrows]
|
||||
attribute EventHandler onprogress;
|
||||
};
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user