mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 06:45:42 +00:00
Merge m-c and fx-team
This commit is contained in:
commit
12a533fa7b
@ -20,11 +20,11 @@
|
||||
|
||||
#include "nsCURILoader.h"
|
||||
#include "nsDocShellLoadTypes.h"
|
||||
#include "nsDOMEvent.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIContentViewer.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsEventListenerManager.h"
|
||||
#include "nsIDOMEventTarget.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
@ -32,6 +32,7 @@
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::a11y;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// DocManager
|
||||
@ -252,10 +253,8 @@ DocManager::HandleEvent(nsIDOMEvent* aEvent)
|
||||
nsAutoString type;
|
||||
aEvent->GetType(type);
|
||||
|
||||
nsCOMPtr<nsIDOMEventTarget> target;
|
||||
aEvent->GetTarget(getter_AddRefs(target));
|
||||
|
||||
nsCOMPtr<nsIDocument> document(do_QueryInterface(target));
|
||||
nsCOMPtr<nsIDocument> document =
|
||||
do_QueryInterface(aEvent->InternalDOMEvent()->GetTarget());
|
||||
NS_ASSERTION(document, "pagehide or DOMContentLoaded for non document!");
|
||||
if (!document)
|
||||
return NS_OK;
|
||||
@ -327,8 +326,8 @@ void
|
||||
DocManager::AddListeners(nsIDocument* aDocument,
|
||||
bool aAddDOMContentLoadedListener)
|
||||
{
|
||||
nsPIDOMWindow *window = aDocument->GetWindow();
|
||||
nsIDOMEventTarget *target = window->GetChromeEventHandler();
|
||||
nsPIDOMWindow* window = aDocument->GetWindow();
|
||||
EventTarget* target = window->GetChromeEventHandler();
|
||||
nsEventListenerManager* elm = target->GetListenerManager(true);
|
||||
elm->AddEventListenerByType(this, NS_LITERAL_STRING("pagehide"),
|
||||
dom::TrustedEventsAtCapture());
|
||||
@ -355,7 +354,7 @@ DocManager::RemoveListeners(nsIDocument* aDocument)
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
nsIDOMEventTarget* target = window->GetChromeEventHandler();
|
||||
EventTarget* target = window->GetChromeEventHandler();
|
||||
nsEventListenerManager* elm = target->GetListenerManager(true);
|
||||
elm->RemoveEventListenerByType(this, NS_LITERAL_STRING("pagehide"),
|
||||
dom::TrustedEventsAtCapture());
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0"?>
|
||||
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1364316540000">
|
||||
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1366143901000">
|
||||
<emItems>
|
||||
<emItem blockID="i58" id="webmaster@buzzzzvideos.info">
|
||||
<versionRange minVersion="0" maxVersion="*">
|
||||
@ -83,7 +83,7 @@
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3">
|
||||
</versionRange>
|
||||
</emItem>
|
||||
<emItem blockID="i101" id="{3a12052a-66ef-49db-8c39-e5b0bd5c83fa}">
|
||||
<emItem blockID="i84" id="pink@rosaplugin.info">
|
||||
<versionRange minVersion="0" maxVersion="*">
|
||||
</versionRange>
|
||||
</emItem>
|
||||
@ -358,6 +358,10 @@
|
||||
<versionRange minVersion="0.1" maxVersion="5.2.0.7164" severity="1">
|
||||
</versionRange>
|
||||
</emItem>
|
||||
<emItem blockID="i334" id="{0F827075-B026-42F3-885D-98981EE7B1AE}">
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3">
|
||||
</versionRange>
|
||||
</emItem>
|
||||
<emItem blockID="i47" id="youtube@youtube2.com">
|
||||
</emItem>
|
||||
<emItem blockID="i103" id="kdrgun@gmail.com">
|
||||
@ -429,7 +433,7 @@
|
||||
<versionRange minVersion="0" maxVersion="*" severity="1">
|
||||
</versionRange>
|
||||
</emItem>
|
||||
<emItem blockID="i84" id="pink@rosaplugin.info">
|
||||
<emItem blockID="i101" id="{3a12052a-66ef-49db-8c39-e5b0bd5c83fa}">
|
||||
<versionRange minVersion="0" maxVersion="*">
|
||||
</versionRange>
|
||||
</emItem>
|
||||
@ -567,7 +571,7 @@
|
||||
<pluginItem blockID="p94">
|
||||
<match name="filename" exp="Flash\ Player\.plugin" /> <versionRange minVersion="0" maxVersion="10.2.159.1" severity="0">
|
||||
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
|
||||
<versionRange minVersion="0" maxVersion="17.*" />
|
||||
<versionRange minVersion="0.1" maxVersion="17.0.1" />
|
||||
</targetApplication>
|
||||
</versionRange>
|
||||
</pluginItem>
|
||||
@ -656,14 +660,14 @@
|
||||
</versionRange>
|
||||
</pluginItem>
|
||||
<pluginItem blockID="p178">
|
||||
<match name="filename" exp="(NPSWF[0-9_]*\.dll)|(Flash\ Player\.plugin)" /> <versionRange minVersion="11.0" maxVersion="11.2.202.274.9999" severity="0" vulnerabilitystatus="1">
|
||||
<match name="filename" exp="(NPSWF[0-9_]*\.dll)|(Flash\ Player\.plugin)" /> <versionRange minVersion="11.0" maxVersion="11.4.*" severity="0" vulnerabilitystatus="1">
|
||||
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
|
||||
<versionRange minVersion="19.0a1" maxVersion="*" />
|
||||
</targetApplication>
|
||||
</versionRange>
|
||||
</pluginItem>
|
||||
<pluginItem blockID="p178">
|
||||
<match name="filename" exp="(NPSWF[0-9_]*\.dll)|(Flash\ Player\.plugin)" /> <versionRange minVersion="11.0" maxVersion="11.2.202.274.9999" severity="0" vulnerabilitystatus="1">
|
||||
<match name="filename" exp="(NPSWF[0-9_]*\.dll)|(Flash\ Player\.plugin)" /> <versionRange minVersion="11.0" maxVersion="11.4.*" severity="0" vulnerabilitystatus="1">
|
||||
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
|
||||
<versionRange minVersion="17.0.4" maxVersion="17.0.*" />
|
||||
</targetApplication>
|
||||
@ -828,13 +832,6 @@
|
||||
</targetApplication>
|
||||
</versionRange>
|
||||
</pluginItem>
|
||||
<pluginItem blockID="p316">
|
||||
<match name="filename" exp="(NPSWF[0-9_]*\.dll)|(Flash\ Player\.plugin)" /> <versionRange minVersion="11.2.202.275" maxVersion="11.4.402.286.9999" severity="0" vulnerabilitystatus="1">
|
||||
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
|
||||
<versionRange minVersion="21.0a1" maxVersion="*" />
|
||||
</targetApplication>
|
||||
</versionRange>
|
||||
</pluginItem>
|
||||
<pluginItem blockID="p328">
|
||||
<match name="filename" exp="Silverlight\.plugin" /> <versionRange minVersion="5.1" maxVersion="5.1.20124.9999" severity="0" vulnerabilitystatus="1">
|
||||
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
|
||||
|
@ -3649,10 +3649,6 @@ var XULBrowserWindow = {
|
||||
// unsupported
|
||||
},
|
||||
|
||||
setJSDefaultStatus: function () {
|
||||
// unsupported
|
||||
},
|
||||
|
||||
setDefaultStatus: function (status) {
|
||||
this.defaultStatus = status;
|
||||
this.updateStatusField();
|
||||
|
@ -457,6 +457,7 @@ toolbar:not([mode="icons"]) #restore-button {
|
||||
}
|
||||
|
||||
.toolbarbutton-1[disabled="true"] > .toolbarbutton-icon,
|
||||
.toolbarbutton-1[disabled="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
.toolbarbutton-1[type="menu-button"] > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon,
|
||||
#restore-button[disabled="true"] > .toolbarbutton-icon {
|
||||
opacity: .4;
|
||||
@ -464,12 +465,13 @@ toolbar:not([mode="icons"]) #restore-button {
|
||||
|
||||
@media (-moz-mac-lion-theme) {
|
||||
.toolbarbutton-1[disabled="true"] > .toolbarbutton-icon,
|
||||
.toolbarbutton-1[disabled="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
.toolbarbutton-1[type="menu-button"] > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon,
|
||||
#restore-button[disabled="true"] > .toolbarbutton-icon,
|
||||
.toolbarbutton-1[disabled="true"] > .toolbarbutton-menu-dropmarker,
|
||||
.toolbarbutton-1[disabled="true"] > .toolbarbutton-menubutton-dropmarker,
|
||||
.toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-icon,
|
||||
.toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-icon,
|
||||
.toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
#restore-button:not(:hover):-moz-window-inactive > .toolbarbutton-icon,
|
||||
.toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-menu-dropmarker,
|
||||
.toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-menubutton-dropmarker {
|
||||
@ -477,6 +479,7 @@ toolbar:not([mode="icons"]) #restore-button {
|
||||
}
|
||||
|
||||
.toolbarbutton-1:-moz-window-inactive[disabled="true"] > .toolbarbutton-icon,
|
||||
.toolbarbutton-1:-moz-window-inactive[disabled="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
.toolbarbutton-1:-moz-window-inactive[type="menu-button"] > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon,
|
||||
#restore-button:-moz-window-inactive[disabled="true"] > .toolbarbutton-icon {
|
||||
opacity: .25;
|
||||
|
@ -968,6 +968,10 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
|
||||
os.kill(pid, signal.SIGKILL)
|
||||
|
||||
def dumpScreen(self, utilityPath):
|
||||
if self.haveDumpedScreen:
|
||||
self.log.info("Not taking screenshot here: see the one that was previously logged")
|
||||
return
|
||||
|
||||
self.haveDumpedScreen = True;
|
||||
|
||||
# Need to figure out what tool and whether it write to a file or stdout
|
||||
@ -1017,10 +1021,7 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
|
||||
def killAndGetStack(self, processPID, utilityPath, debuggerInfo):
|
||||
"""Kill the process, preferrably in a way that gets us a stack trace."""
|
||||
if not debuggerInfo:
|
||||
if self.haveDumpedScreen:
|
||||
self.log.info("Not taking screenshot here: see the one that was previously logged")
|
||||
else:
|
||||
self.dumpScreen(utilityPath)
|
||||
self.dumpScreen(utilityPath)
|
||||
|
||||
if self.CRASHREPORTER and not debuggerInfo:
|
||||
if self.UNIXISH:
|
||||
@ -1076,10 +1077,7 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
|
||||
if "TEST-START" in line and "|" in line:
|
||||
self.lastTestSeen = line.split("|")[1].strip()
|
||||
if not debuggerInfo and "TEST-UNEXPECTED-FAIL" in line and "Test timed out" in line:
|
||||
if self.haveDumpedScreen:
|
||||
self.log.info("Not taking screenshot here: see the one that was previously logged")
|
||||
else:
|
||||
self.dumpScreen(utilityPath)
|
||||
self.dumpScreen(utilityPath)
|
||||
|
||||
(line, didTimeout) = self.readWithTimeout(logsource, timeout)
|
||||
if not hitMaxTime and maxTime and datetime.now() - startTime > timedelta(seconds = maxTime):
|
||||
|
@ -121,13 +121,20 @@ class RemoteAutomation(Automation):
|
||||
javaException = self.checkForJavaException(logcat)
|
||||
if javaException:
|
||||
return True
|
||||
|
||||
# If crash reporting is disabled (MOZ_CRASHREPORTER!=1), we can't say
|
||||
# anything.
|
||||
if not self.CRASHREPORTER:
|
||||
return False
|
||||
|
||||
try:
|
||||
dumpDir = tempfile.mkdtemp()
|
||||
remoteCrashDir = self._remoteProfile + '/minidumps/'
|
||||
if not self._devicemanager.dirExists(remoteCrashDir):
|
||||
# As of this writing, the minidumps directory is automatically
|
||||
# created when fennec (first) starts, so its lack of presence
|
||||
# is a hint that something went wrong.
|
||||
# If crash reporting is enabled (MOZ_CRASHREPORTER=1), the
|
||||
# minidumps directory is automatically created when Fennec
|
||||
# (first) starts, so its lack of presence is a hint that
|
||||
# something went wrong.
|
||||
print "Automation Error: No crash directory (%s) found on remote device" % remoteCrashDir
|
||||
# Whilst no crash was found, the run should still display as a failure
|
||||
return True
|
||||
|
@ -944,6 +944,7 @@ endif
|
||||
# so no need to conditionalize on OS version or debugging format.
|
||||
|
||||
$(SHARED_LIBRARY): $(OBJS) $(LOBJS) $(DEF_FILE) $(RESFILE) $(LIBRARY) $(EXTRA_DEPS) $(GLOBAL_DEPS)
|
||||
$(info $(notdir $@))
|
||||
ifndef INCREMENTAL_LINKER
|
||||
$(RM) $@
|
||||
endif
|
||||
|
@ -223,6 +223,7 @@ if test -n "$gonkdir" ; then
|
||||
AC_DEFINE(HAVE_PTHREADS)
|
||||
CROSS_COMPILE=1
|
||||
MOZ_CHROME_FILE_FORMAT=omni
|
||||
NSS_NO_LIBPKIX=1
|
||||
direct_nspr_config=1
|
||||
else
|
||||
MOZ_ANDROID_NDK
|
||||
@ -8541,6 +8542,8 @@ AC_SUBST(MOZ_PERMISSIONS)
|
||||
AC_SUBST(MOZ_PREF_EXTENSIONS)
|
||||
AC_SUBST(MOZ_JS_LIBS)
|
||||
AC_SUBST(MOZ_PSM)
|
||||
AC_DEFINE(NSS_NO_LIBPKIX)
|
||||
AC_SUBST(NSS_NO_LIBPKIX)
|
||||
AC_SUBST(MOZ_DEBUG)
|
||||
AC_SUBST(MOZ_DEBUG_SYMBOLS)
|
||||
AC_SUBST(MOZ_DEBUG_ENABLE_DEFS)
|
||||
|
18
content/base/crashtests/863950.html
Normal file
18
content/base/crashtests/863950.html
Normal file
@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html style="position: fixed;">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<script>
|
||||
|
||||
function boom()
|
||||
{
|
||||
var cp = document.caretPositionFromPoint(0, 1);
|
||||
document.documentElement.removeChild(document.body);
|
||||
cp.getClientRect();
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body style="margin: 0;" onload="boom();"></body>
|
||||
</html>
|
@ -133,3 +133,4 @@ load 841205.html
|
||||
load 844404.html
|
||||
load 847127.html
|
||||
load 849601.html
|
||||
load 863950.html
|
||||
|
@ -49,7 +49,6 @@ class nsIDOMDocumentFragment;
|
||||
class nsIDOMDocumentType;
|
||||
class nsIDOMElement;
|
||||
class nsIDOMNodeList;
|
||||
class nsIDOMTouch;
|
||||
class nsIDOMTouchList;
|
||||
class nsIDOMXPathExpression;
|
||||
class nsIDOMXPathNSResolver;
|
||||
@ -102,8 +101,10 @@ class Link;
|
||||
class NodeFilter;
|
||||
class NodeIterator;
|
||||
class ProcessingInstruction;
|
||||
class Touch;
|
||||
class TreeWalker;
|
||||
class UndoManager;
|
||||
template<typename> class OwningNonNull;
|
||||
template<typename> class Sequence;
|
||||
|
||||
template<typename, typename> class CallbackObjectHolder;
|
||||
@ -2090,7 +2091,7 @@ public:
|
||||
nsIDOMXPathNSResolver* aResolver, uint16_t aType,
|
||||
nsISupports* aResult, mozilla::ErrorResult& rv);
|
||||
// Touch event handlers already on nsINode
|
||||
already_AddRefed<nsIDOMTouch>
|
||||
already_AddRefed<mozilla::dom::Touch>
|
||||
CreateTouch(nsIDOMWindow* aView, mozilla::dom::EventTarget* aTarget,
|
||||
int32_t aIdentifier, int32_t aPageX, int32_t aPageY,
|
||||
int32_t aScreenX, int32_t aScreenY, int32_t aClientX,
|
||||
@ -2098,10 +2099,10 @@ public:
|
||||
float aRotationAngle, float aForce);
|
||||
already_AddRefed<nsIDOMTouchList> CreateTouchList();
|
||||
already_AddRefed<nsIDOMTouchList>
|
||||
CreateTouchList(nsIDOMTouch* aTouch,
|
||||
const mozilla::dom::Sequence<nsRefPtr<nsIDOMTouch> >& aTouches);
|
||||
CreateTouchList(mozilla::dom::Touch& aTouch,
|
||||
const mozilla::dom::Sequence<mozilla::dom::OwningNonNull<mozilla::dom::Touch> >& aTouches);
|
||||
already_AddRefed<nsIDOMTouchList>
|
||||
CreateTouchList(const mozilla::dom::Sequence<nsRefPtr<nsIDOMTouch> >& aTouches);
|
||||
CreateTouchList(const mozilla::dom::Sequence<mozilla::dom::OwningNonNull<mozilla::dom::Touch> >& aTouches);
|
||||
|
||||
virtual nsHTMLDocument* AsHTMLDocument() { return nullptr; }
|
||||
|
||||
|
@ -1099,10 +1099,10 @@ WebSocket::UpdateMustKeepAlive()
|
||||
|
||||
if (mKeepingAlive && !shouldKeepAlive) {
|
||||
mKeepingAlive = false;
|
||||
static_cast<nsIDOMEventTarget*>(this)->Release();
|
||||
static_cast<EventTarget*>(this)->Release();
|
||||
} else if (!mKeepingAlive && shouldKeepAlive) {
|
||||
mKeepingAlive = true;
|
||||
static_cast<nsIDOMEventTarget*>(this)->AddRef();
|
||||
static_cast<EventTarget*>(this)->AddRef();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1112,7 +1112,7 @@ WebSocket::DontKeepAliveAnyMore()
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
||||
if (mKeepingAlive) {
|
||||
mKeepingAlive = false;
|
||||
static_cast<nsIDOMEventTarget*>(this)->Release();
|
||||
static_cast<EventTarget*>(this)->Release();
|
||||
}
|
||||
mCheckMustKeepAlive = false;
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ MarkMessageManagers()
|
||||
static_cast<nsFrameMessageManager*>(tabMM)->GetCallback();
|
||||
if (cb) {
|
||||
nsFrameLoader* fl = static_cast<nsFrameLoader*>(cb);
|
||||
nsIDOMEventTarget* et = fl->GetTabChildGlobalAsEventTarget();
|
||||
EventTarget* et = fl->GetTabChildGlobalAsEventTarget();
|
||||
if (!et) {
|
||||
continue;
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ void
|
||||
nsDOMFileReader::RootResultArrayBuffer()
|
||||
{
|
||||
nsContentUtils::PreserveWrapper(
|
||||
static_cast<nsIDOMEventTarget*>(
|
||||
static_cast<EventTarget*>(
|
||||
static_cast<nsDOMEventTargetHelper*>(this)), this);
|
||||
}
|
||||
|
||||
@ -104,7 +104,7 @@ nsDOMFileReader::RootResultArrayBuffer()
|
||||
nsDOMFileReader::nsDOMFileReader()
|
||||
: mFileData(nullptr),
|
||||
mDataLen(0), mDataFormat(FILE_AS_BINARY),
|
||||
mResultArrayBuffer(nullptr)
|
||||
mResultArrayBuffer(nullptr)
|
||||
{
|
||||
nsLayoutStatics::AddRef();
|
||||
SetDOMStringToNull(mResult);
|
||||
|
@ -9171,7 +9171,7 @@ nsDocument::CreateTouch(nsIDOMWindow* aView,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMTouch>
|
||||
already_AddRefed<Touch>
|
||||
nsIDocument::CreateTouch(nsIDOMWindow* aView,
|
||||
EventTarget* aTarget,
|
||||
int32_t aIdentifier,
|
||||
@ -9182,14 +9182,14 @@ nsIDocument::CreateTouch(nsIDOMWindow* aView,
|
||||
float aRotationAngle,
|
||||
float aForce)
|
||||
{
|
||||
nsCOMPtr<nsIDOMTouch> touch = new Touch(aTarget,
|
||||
aIdentifier,
|
||||
aPageX, aPageY,
|
||||
aScreenX, aScreenY,
|
||||
aClientX, aClientY,
|
||||
aRadiusX, aRadiusY,
|
||||
aRotationAngle,
|
||||
aForce);
|
||||
nsRefPtr<Touch> touch = new Touch(aTarget,
|
||||
aIdentifier,
|
||||
aPageX, aPageY,
|
||||
aScreenX, aScreenY,
|
||||
aClientX, aClientY,
|
||||
aRadiusX, aRadiusY,
|
||||
aRotationAngle,
|
||||
aForce);
|
||||
return touch.forget();
|
||||
}
|
||||
|
||||
@ -9242,23 +9242,23 @@ nsIDocument::CreateTouchList()
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMTouchList>
|
||||
nsIDocument::CreateTouchList(nsIDOMTouch* aTouch,
|
||||
const Sequence<nsRefPtr<nsIDOMTouch> >& aTouches)
|
||||
nsIDocument::CreateTouchList(Touch& aTouch,
|
||||
const Sequence<OwningNonNull<Touch> >& aTouches)
|
||||
{
|
||||
nsRefPtr<nsDOMTouchList> retval = new nsDOMTouchList();
|
||||
retval->Append(aTouch);
|
||||
retval->Append(&aTouch);
|
||||
for (uint32_t i = 0; i < aTouches.Length(); ++i) {
|
||||
retval->Append(aTouches[i]);
|
||||
retval->Append(aTouches[i].get());
|
||||
}
|
||||
return retval.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMTouchList>
|
||||
nsIDocument::CreateTouchList(const Sequence<nsRefPtr<nsIDOMTouch> >& aTouches)
|
||||
nsIDocument::CreateTouchList(const Sequence<OwningNonNull<Touch> >& aTouches)
|
||||
{
|
||||
nsRefPtr<nsDOMTouchList> retval = new nsDOMTouchList();
|
||||
for (uint32_t i = 0; i < aTouches.Length(); ++i) {
|
||||
retval->Append(aTouches[i]);
|
||||
retval->Append(aTouches[i].get());
|
||||
}
|
||||
return retval.forget();
|
||||
}
|
||||
|
@ -639,6 +639,7 @@ GK_ATOM(onanimationend, "onanimationend")
|
||||
GK_ATOM(onanimationiteration, "onanimationiteration")
|
||||
GK_ATOM(onanimationstart, "onanimationstart")
|
||||
GK_ATOM(onAppCommand, "onAppCommand")
|
||||
GK_ATOM(onaudioprocess, "onaudioprocess")
|
||||
GK_ATOM(onbeforecopy, "onbeforecopy")
|
||||
GK_ATOM(onbeforecut, "onbeforecut")
|
||||
GK_ATOM(onbeforepaste, "onbeforepaste")
|
||||
|
@ -246,10 +246,9 @@ nsInProcessTabChildGlobal::DelayedDisconnect()
|
||||
if (mListenerManager) {
|
||||
mListenerManager->Disconnect();
|
||||
}
|
||||
|
||||
|
||||
if (!mLoadingScript) {
|
||||
nsContentUtils::ReleaseWrapper(static_cast<nsIDOMEventTarget*>(this),
|
||||
this);
|
||||
nsContentUtils::ReleaseWrapper(static_cast<EventTarget*>(this), this);
|
||||
if (mCx) {
|
||||
DestroyCx();
|
||||
}
|
||||
@ -309,8 +308,7 @@ nsInProcessTabChildGlobal::InitTabChildGlobal()
|
||||
id.AppendLiteral("?ownedBy=");
|
||||
id.Append(u);
|
||||
}
|
||||
nsISupports* scopeSupports =
|
||||
NS_ISUPPORTS_CAST(nsIDOMEventTarget*, this);
|
||||
nsISupports* scopeSupports = NS_ISUPPORTS_CAST(EventTarget*, this);
|
||||
NS_ENSURE_STATE(InitTabChildGlobalInternal(scopeSupports, id));
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -488,19 +488,19 @@ function start() {
|
||||
var testsToSkip = [];
|
||||
|
||||
if (kIsAndroid) {
|
||||
var testsToSkip = loadTextFileSynchronous('skipped_tests_android.txt')
|
||||
testsToSkip = loadTextFileSynchronous('skipped_tests_android.txt')
|
||||
.replace(/\r/g, '') // convert to unix line breaks
|
||||
.split('\n');
|
||||
}
|
||||
|
||||
if (kIsLinuxMesa) {
|
||||
var testsToSkip = loadTextFileSynchronous('skipped_tests_linux_mesa.txt')
|
||||
testsToSkip = loadTextFileSynchronous('skipped_tests_linux_mesa.txt')
|
||||
.replace(/\r/g, '') // convert to unix line breaks
|
||||
.split('\n');
|
||||
}
|
||||
|
||||
if (kIsWindows && !kIsWindowsVistaOrHigher) {
|
||||
var testsToSkip = loadTextFileSynchronous('skipped_tests_winxp.txt')
|
||||
testsToSkip = loadTextFileSynchronous('skipped_tests_winxp.txt')
|
||||
.replace(/\r/g, '') // convert to unix line breaks
|
||||
.split('\n');
|
||||
}
|
||||
|
@ -848,6 +848,11 @@ NON_IDL_EVENT(animationiteration,
|
||||
EventNameType_None,
|
||||
NS_ANIMATION_EVENT)
|
||||
|
||||
NON_IDL_EVENT(audioprocess,
|
||||
NS_AUDIO_PROCESS,
|
||||
EventNameType_None,
|
||||
NS_EVENT)
|
||||
|
||||
#ifdef DEFINED_FORWARDED_EVENT
|
||||
#undef DEFINED_FORWARDED_EVENT
|
||||
#undef FORWARDED_EVENT
|
||||
|
@ -4,25 +4,29 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/Touch.h"
|
||||
#include "nsGUIEvent.h"
|
||||
#include "nsDOMClassInfoID.h"
|
||||
#include "nsIClassInfo.h"
|
||||
#include "nsIXPCScriptable.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsPresContext.h"
|
||||
|
||||
DOMCI_DATA(Touch, mozilla::dom::Touch)
|
||||
#include "mozilla/dom/TouchBinding.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDOMTouchEvent.h"
|
||||
#include "nsGUIEvent.h"
|
||||
#include "nsPresContext.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_1(Touch, mTarget)
|
||||
/* static */ bool
|
||||
Touch::PrefEnabled()
|
||||
{
|
||||
return nsDOMTouchEvent::PrefEnabled();
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(Touch, mTarget)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Touch)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMTouch)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMTouch)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Touch)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(Touch)
|
||||
@ -31,91 +35,96 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(Touch)
|
||||
NS_IMETHODIMP
|
||||
Touch::GetIdentifier(int32_t* aIdentifier)
|
||||
{
|
||||
*aIdentifier = mIdentifier;
|
||||
*aIdentifier = Identifier();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Touch::GetTarget(nsIDOMEventTarget** aTarget)
|
||||
{
|
||||
NS_ADDREF(*aTarget = Target());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
EventTarget*
|
||||
Touch::Target() const
|
||||
{
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(mTarget);
|
||||
if (content && content->ChromeOnlyAccess() &&
|
||||
!nsContentUtils::CanAccessNativeAnon()) {
|
||||
content = content->FindFirstNonChromeOnlyAccessContent();
|
||||
*aTarget = content.forget().get();
|
||||
return NS_OK;
|
||||
return content->FindFirstNonChromeOnlyAccessContent();
|
||||
}
|
||||
NS_IF_ADDREF(*aTarget = mTarget);
|
||||
return NS_OK;
|
||||
|
||||
return mTarget;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Touch::GetScreenX(int32_t* aScreenX)
|
||||
{
|
||||
*aScreenX = mScreenPoint.x;
|
||||
*aScreenX = ScreenX();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Touch::GetScreenY(int32_t* aScreenY)
|
||||
{
|
||||
*aScreenY = mScreenPoint.y;
|
||||
*aScreenY = ScreenY();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Touch::GetClientX(int32_t* aClientX)
|
||||
{
|
||||
*aClientX = mClientPoint.x;
|
||||
*aClientX = ClientX();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Touch::GetClientY(int32_t* aClientY)
|
||||
{
|
||||
*aClientY = mClientPoint.y;
|
||||
*aClientY = ClientY();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Touch::GetPageX(int32_t* aPageX)
|
||||
{
|
||||
*aPageX = mPagePoint.x;
|
||||
*aPageX = PageX();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Touch::GetPageY(int32_t* aPageY)
|
||||
{
|
||||
*aPageY = mPagePoint.y;
|
||||
*aPageY = PageY();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Touch::GetRadiusX(int32_t* aRadiusX)
|
||||
{
|
||||
*aRadiusX = mRadius.x;
|
||||
*aRadiusX = RadiusX();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Touch::GetRadiusY(int32_t* aRadiusY)
|
||||
{
|
||||
*aRadiusY = mRadius.y;
|
||||
*aRadiusY = RadiusY();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Touch::GetRotationAngle(float* aRotationAngle)
|
||||
{
|
||||
*aRotationAngle = mRotationAngle;
|
||||
*aRotationAngle = RotationAngle();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Touch::GetForce(float* aForce)
|
||||
{
|
||||
*aForce = mForce;
|
||||
*aForce = Force();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -135,5 +144,11 @@ Touch::Equals(nsIDOMTouch* aTouch)
|
||||
(mRadius.x != radiusX) || (mRadius.y != radiusY);
|
||||
}
|
||||
|
||||
/* virtual */ JSObject*
|
||||
Touch::WrapObject(JSContext* aCx, JSObject* aScope)
|
||||
{
|
||||
return TouchBinding::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -17,8 +17,11 @@ namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class Touch MOZ_FINAL : public nsIDOMTouch
|
||||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
static bool PrefEnabled();
|
||||
|
||||
Touch(mozilla::dom::EventTarget* aTarget,
|
||||
int32_t aIdentifier,
|
||||
int32_t aPageX,
|
||||
@ -32,6 +35,7 @@ public:
|
||||
float aRotationAngle,
|
||||
float aForce)
|
||||
{
|
||||
SetIsDOMBinding();
|
||||
mTarget = aTarget;
|
||||
mIdentifier = aIdentifier;
|
||||
mPagePoint = nsIntPoint(aPageX, aPageY);
|
||||
@ -54,6 +58,7 @@ public:
|
||||
float aRotationAngle,
|
||||
float aForce)
|
||||
{
|
||||
SetIsDOMBinding();
|
||||
mIdentifier = aIdentifier;
|
||||
mPagePoint = nsIntPoint(0, 0);
|
||||
mScreenPoint = nsIntPoint(0, 0);
|
||||
@ -69,7 +74,7 @@ public:
|
||||
nsJSContext::LikelyShortLivingObjectCreated();
|
||||
}
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(Touch)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Touch)
|
||||
NS_DECL_NSIDOMTOUCH
|
||||
void InitializePoints(nsPresContext* aPresContext, nsEvent* aEvent)
|
||||
{
|
||||
@ -93,6 +98,23 @@ public:
|
||||
}
|
||||
bool Equals(nsIDOMTouch* aTouch);
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx, JSObject* aScope) MOZ_OVERRIDE;
|
||||
EventTarget* GetParentObject() { return mTarget; }
|
||||
|
||||
// WebIDL
|
||||
int32_t Identifier() const { return mIdentifier; }
|
||||
EventTarget* Target() const;
|
||||
int32_t ScreenX() const { return mScreenPoint.x; }
|
||||
int32_t ScreenY() const { return mScreenPoint.y; }
|
||||
int32_t ClientX() const { return mClientPoint.x; }
|
||||
int32_t ClientY() const { return mClientPoint.y; }
|
||||
int32_t PageX() const { return mPagePoint.x; }
|
||||
int32_t PageY() const { return mPagePoint.y; }
|
||||
int32_t RadiusX() const { return mRadius.x; }
|
||||
int32_t RadiusY() const { return mRadius.y; }
|
||||
float RotationAngle() const { return mRotationAngle; }
|
||||
float Force() const { return mForce; }
|
||||
|
||||
int32_t mIdentifier;
|
||||
nsIntPoint mPagePoint;
|
||||
nsIntPoint mClientPoint;
|
||||
|
@ -460,7 +460,7 @@ nsDOMEvent::StopImmediatePropagation()
|
||||
|
||||
static nsIDocument* GetDocumentForReport(nsEvent* aEvent)
|
||||
{
|
||||
nsIDOMEventTarget* target = aEvent->currentTarget;
|
||||
EventTarget* target = aEvent->currentTarget;
|
||||
if (nsCOMPtr<nsINode> node = do_QueryInterface(target)) {
|
||||
return node->OwnerDoc();
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ nsDOMKeyboardEvent::nsDOMKeyboardEvent(mozilla::dom::EventTarget* aOwner,
|
||||
mEventIsInternal = true;
|
||||
mEvent->time = PR_Now();
|
||||
}
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
nsDOMKeyboardEvent::~nsDOMKeyboardEvent()
|
||||
@ -45,7 +46,7 @@ NS_IMETHODIMP
|
||||
nsDOMKeyboardEvent::GetAltKey(bool* aIsDown)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aIsDown);
|
||||
*aIsDown = static_cast<nsInputEvent*>(mEvent)->IsAlt();
|
||||
*aIsDown = AltKey();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -53,7 +54,7 @@ NS_IMETHODIMP
|
||||
nsDOMKeyboardEvent::GetCtrlKey(bool* aIsDown)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aIsDown);
|
||||
*aIsDown = static_cast<nsInputEvent*>(mEvent)->IsControl();
|
||||
*aIsDown = CtrlKey();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -61,7 +62,7 @@ NS_IMETHODIMP
|
||||
nsDOMKeyboardEvent::GetShiftKey(bool* aIsDown)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aIsDown);
|
||||
*aIsDown = static_cast<nsInputEvent*>(mEvent)->IsShift();
|
||||
*aIsDown = ShiftKey();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -69,7 +70,7 @@ NS_IMETHODIMP
|
||||
nsDOMKeyboardEvent::GetMetaKey(bool* aIsDown)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aIsDown);
|
||||
*aIsDown = static_cast<nsInputEvent*>(mEvent)->IsMeta();
|
||||
*aIsDown = MetaKey();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -79,7 +80,7 @@ nsDOMKeyboardEvent::GetModifierState(const nsAString& aKey,
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aState);
|
||||
|
||||
*aState = GetModifierStateInternal(aKey);
|
||||
*aState = GetModifierState(aKey);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -87,39 +88,41 @@ NS_IMETHODIMP
|
||||
nsDOMKeyboardEvent::GetCharCode(uint32_t* aCharCode)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aCharCode);
|
||||
*aCharCode = CharCode();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
nsDOMKeyboardEvent::CharCode()
|
||||
{
|
||||
switch (mEvent->message) {
|
||||
case NS_KEY_UP:
|
||||
case NS_KEY_DOWN:
|
||||
*aCharCode = 0;
|
||||
break;
|
||||
return 0;
|
||||
case NS_KEY_PRESS:
|
||||
*aCharCode = ((nsKeyEvent*)mEvent)->charCode;
|
||||
break;
|
||||
default:
|
||||
*aCharCode = 0;
|
||||
break;
|
||||
return static_cast<nsKeyEvent*>(mEvent)->charCode;
|
||||
}
|
||||
return NS_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMKeyboardEvent::GetKeyCode(uint32_t* aKeyCode)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aKeyCode);
|
||||
*aKeyCode = KeyCode();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
nsDOMKeyboardEvent::KeyCode()
|
||||
{
|
||||
switch (mEvent->message) {
|
||||
case NS_KEY_UP:
|
||||
case NS_KEY_PRESS:
|
||||
case NS_KEY_DOWN:
|
||||
*aKeyCode = ((nsKeyEvent*)mEvent)->keyCode;
|
||||
break;
|
||||
default:
|
||||
*aKeyCode = 0;
|
||||
break;
|
||||
return static_cast<nsKeyEvent*>(mEvent)->keyCode;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* virtual */
|
||||
@ -127,29 +130,30 @@ nsresult
|
||||
nsDOMKeyboardEvent::Which(uint32_t* aWhich)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aWhich);
|
||||
*aWhich = Which();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
nsDOMKeyboardEvent::Which()
|
||||
{
|
||||
switch (mEvent->message) {
|
||||
case NS_KEY_UP:
|
||||
case NS_KEY_DOWN:
|
||||
return GetKeyCode(aWhich);
|
||||
return KeyCode();
|
||||
case NS_KEY_PRESS:
|
||||
//Special case for 4xp bug 62878. Try to make value of which
|
||||
//more closely mirror the values that 4.x gave for RETURN and BACKSPACE
|
||||
{
|
||||
uint32_t keyCode = ((nsKeyEvent*)mEvent)->keyCode;
|
||||
if (keyCode == NS_VK_RETURN || keyCode == NS_VK_BACK) {
|
||||
*aWhich = keyCode;
|
||||
return NS_OK;
|
||||
return keyCode;
|
||||
}
|
||||
return GetCharCode(aWhich);
|
||||
return CharCode();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*aWhich = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -157,7 +161,7 @@ nsDOMKeyboardEvent::GetLocation(uint32_t* aLocation)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aLocation);
|
||||
|
||||
*aLocation = static_cast<nsKeyEvent*>(mEvent)->location;
|
||||
*aLocation = Location();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "nsIDOMKeyEvent.h"
|
||||
#include "nsDOMUIEvent.h"
|
||||
#include "mozilla/dom/KeyEventBinding.h"
|
||||
|
||||
class nsDOMKeyboardEvent : public nsDOMUIEvent,
|
||||
public nsIDOMKeyEvent
|
||||
@ -25,6 +26,56 @@ public:
|
||||
// Forward to base class
|
||||
NS_FORWARD_TO_NSDOMUIEVENT
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope)
|
||||
{
|
||||
return mozilla::dom::KeyEventBinding::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
bool AltKey()
|
||||
{
|
||||
return static_cast<nsInputEvent*>(mEvent)->IsAlt();
|
||||
}
|
||||
|
||||
bool CtrlKey()
|
||||
{
|
||||
return static_cast<nsInputEvent*>(mEvent)->IsControl();
|
||||
}
|
||||
|
||||
bool ShiftKey()
|
||||
{
|
||||
return static_cast<nsInputEvent*>(mEvent)->IsShift();
|
||||
}
|
||||
|
||||
bool MetaKey()
|
||||
{
|
||||
return static_cast<nsInputEvent*>(mEvent)->IsMeta();
|
||||
}
|
||||
|
||||
bool GetModifierState(const nsAString& aKey)
|
||||
{
|
||||
return GetModifierStateInternal(aKey);
|
||||
}
|
||||
|
||||
uint32_t CharCode();
|
||||
uint32_t KeyCode();
|
||||
virtual uint32_t Which() MOZ_OVERRIDE;
|
||||
|
||||
uint32_t Location()
|
||||
{
|
||||
return static_cast<nsKeyEvent*>(mEvent)->location;
|
||||
}
|
||||
|
||||
void InitKeyEvent(const nsAString& aType, bool aCanBubble, bool aCancelable,
|
||||
nsIDOMWindow* aView, bool aCtrlKey, bool aAltKey,
|
||||
bool aShiftKey, bool aMetaKey,
|
||||
uint32_t aKeyCode, uint32_t aCharCode,
|
||||
mozilla::ErrorResult& aRv)
|
||||
{
|
||||
aRv = InitKeyEvent(aType, aCanBubble, aCancelable, aView,
|
||||
aCtrlKey, aAltKey, aShiftKey,aMetaKey,
|
||||
aKeyCode, aCharCode);
|
||||
}
|
||||
|
||||
protected:
|
||||
// Specific implementation for a keyboard event.
|
||||
virtual nsresult Which(uint32_t* aWhich);
|
||||
|
@ -37,6 +37,13 @@ public:
|
||||
JSContext* aCx, JS::Value* aVal);
|
||||
|
||||
// Web IDL binding methods
|
||||
virtual uint32_t Which() MOZ_OVERRIDE
|
||||
{
|
||||
uint32_t w = 0;
|
||||
Which(&w);
|
||||
return w;
|
||||
}
|
||||
|
||||
int32_t ScreenX();
|
||||
int32_t ScreenY();
|
||||
int32_t ClientX();
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "mozilla/dom/Touch.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
// TouchList
|
||||
nsDOMTouchList::nsDOMTouchList(nsTArray<nsCOMPtr<nsIDOMTouch> > &aTouches)
|
||||
@ -195,7 +196,7 @@ nsDOMTouchEvent::GetTargetTouches(nsIDOMTouchList** aTargetTouches)
|
||||
// touch that is ending
|
||||
if ((mEvent->message != NS_TOUCH_END &&
|
||||
mEvent->message != NS_TOUCH_CANCEL) || !touches[i]->mChanged) {
|
||||
nsIDOMEventTarget* targetPtr = touches[i]->GetTarget();
|
||||
EventTarget* targetPtr = touches[i]->GetTarget();
|
||||
if (targetPtr == mEvent->originalTarget) {
|
||||
targetTouches.AppendElement(touches[i]);
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ public:
|
||||
return y;
|
||||
}
|
||||
|
||||
uint32_t Which()
|
||||
virtual uint32_t Which()
|
||||
{
|
||||
uint32_t w;
|
||||
GetWhich(&w);
|
||||
|
9
content/html/content/crashtests/862084.html
Normal file
9
content/html/content/crashtests/862084.html
Normal file
@ -0,0 +1,9 @@
|
||||
<!doctype html>
|
||||
<select></select>
|
||||
<script>
|
||||
var select = document.getElementsByTagName("select");
|
||||
select.item(0);
|
||||
select[0];
|
||||
select.namedItem("x")
|
||||
select["x"]
|
||||
</script>
|
@ -50,4 +50,4 @@ load 828180.html
|
||||
load 832011.html
|
||||
load 837033.html
|
||||
pref(dom.experimental_forms_range,true) load 838256-1.html
|
||||
|
||||
load 862084.html
|
||||
|
@ -2785,7 +2785,7 @@ IsLTR(Element* aElement)
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLInputElement::ShouldPreventDOMActivateDispatch(nsIDOMEventTarget* aOriginalTarget)
|
||||
HTMLInputElement::ShouldPreventDOMActivateDispatch(EventTarget* aOriginalTarget)
|
||||
{
|
||||
/*
|
||||
* For the moment, there is only one situation where we actually want to
|
||||
|
@ -1070,7 +1070,7 @@ protected:
|
||||
* This is used in situations where the anonymous subtree should already have
|
||||
* sent a DOMActivate and prevents firing more than once.
|
||||
*/
|
||||
bool ShouldPreventDOMActivateDispatch(nsIDOMEventTarget* aOriginalTarget);
|
||||
bool ShouldPreventDOMActivateDispatch(EventTarget* aOriginalTarget);
|
||||
|
||||
nsCOMPtr<nsIControllers> mControllers;
|
||||
|
||||
|
@ -12,9 +12,7 @@ include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
LIBRARY_NAME = gkcontentmathml_s
|
||||
LIBXUL_LIBRARY = 1
|
||||
ifndef _MSC_VER
|
||||
FAIL_ON_WARNINGS = 1
|
||||
endif # !_MSC_VER
|
||||
|
||||
CPPSRCS = \
|
||||
nsMathMLElement.cpp \
|
||||
@ -22,19 +20,16 @@ CPPSRCS = \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
include $(topsrcdir)/ipc/chromium/chromium-config.mk
|
||||
|
||||
# we don't want the shared lib, but we want to force the creation of a static
|
||||
# lib.
|
||||
FORCE_STATIC_LIB = 1
|
||||
|
||||
EXPORTS = \
|
||||
$(NULL)
|
||||
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
INCLUDES += \
|
||||
-I$(srcdir)/../../../base/src \
|
||||
$(NULL)
|
||||
INCLUDES += \
|
||||
-I$(srcdir)/../../../base/src \
|
||||
$(NULL)
|
||||
|
||||
DEFINES += -D_IMPL_NS_LAYOUT
|
||||
|
@ -3,9 +3,10 @@
|
||||
* 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 "mozilla/Util.h"
|
||||
|
||||
#include "nsMathMLElement.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "mozilla/Util.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsRuleData.h"
|
||||
@ -76,6 +77,14 @@ ReportParseErrorNoTag(const nsString& aValue,
|
||||
"AttributeParsingErrorNoTag", argv, 2);
|
||||
}
|
||||
|
||||
nsMathMLElement::nsMathMLElement(already_AddRefed<nsINodeInfo> aNodeInfo)
|
||||
: nsMathMLElementBase(aNodeInfo),
|
||||
ALLOW_THIS_IN_INITIALIZER_LIST(Link(this)),
|
||||
mIncrementScriptLevel(false)
|
||||
{
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMathMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
|
@ -24,12 +24,7 @@ class nsMathMLElement : public nsMathMLElementBase,
|
||||
public mozilla::dom::Link
|
||||
{
|
||||
public:
|
||||
nsMathMLElement(already_AddRefed<nsINodeInfo> aNodeInfo)
|
||||
: nsMathMLElementBase(aNodeInfo), Link(this),
|
||||
mIncrementScriptLevel(false)
|
||||
{
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
nsMathMLElement(already_AddRefed<nsINodeInfo> aNodeInfo);
|
||||
|
||||
// Implementation of nsISupports is inherited from nsMathMLElementBase
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class AudioNode;
|
||||
struct ThreeDPoint;
|
||||
}
|
||||
|
||||
@ -146,12 +147,15 @@ AudioBlockPanStereoToStereo(const float aInputL[WEBAUDIO_BLOCK_SIZE],
|
||||
*/
|
||||
class AudioNodeEngine {
|
||||
public:
|
||||
AudioNodeEngine()
|
||||
explicit AudioNodeEngine(dom::AudioNode* aNode)
|
||||
: mNode(aNode)
|
||||
{
|
||||
MOZ_ASSERT(mNode, "The engine is constructed with a null node");
|
||||
MOZ_COUNT_CTOR(AudioNodeEngine);
|
||||
}
|
||||
virtual ~AudioNodeEngine()
|
||||
{
|
||||
MOZ_ASSERT(!mNode, "The node reference must be already cleared");
|
||||
MOZ_COUNT_DTOR(AudioNodeEngine);
|
||||
}
|
||||
|
||||
@ -199,6 +203,16 @@ public:
|
||||
{
|
||||
*aOutput = aInput;
|
||||
}
|
||||
|
||||
dom::AudioNode* Node() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return mNode;
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class dom::AudioNode;
|
||||
dom::AudioNode* mNode;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -193,7 +193,7 @@ AudioChunk*
|
||||
AudioNodeStream::ObtainInputBlock(AudioChunk* aTmpChunk)
|
||||
{
|
||||
uint32_t inputCount = mInputs.Length();
|
||||
uint32_t outputChannelCount = 0;
|
||||
uint32_t outputChannelCount = mNumberOfInputChannels;
|
||||
nsAutoTArray<AudioChunk*,250> inputChunks;
|
||||
for (uint32_t i = 0; i < inputCount; ++i) {
|
||||
MediaStream* s = mInputs[i]->GetSource();
|
||||
@ -209,8 +209,10 @@ AudioNodeStream::ObtainInputBlock(AudioChunk* aTmpChunk)
|
||||
}
|
||||
|
||||
inputChunks.AppendElement(chunk);
|
||||
outputChannelCount =
|
||||
GetAudioChannelsSuperset(outputChannelCount, chunk->mChannelData.Length());
|
||||
if (!mNumberOfInputChannels) {
|
||||
outputChannelCount =
|
||||
GetAudioChannelsSuperset(outputChannelCount, chunk->mChannelData.Length());
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t inputChunkCount = inputChunks.Length();
|
||||
@ -219,7 +221,8 @@ AudioNodeStream::ObtainInputBlock(AudioChunk* aTmpChunk)
|
||||
return aTmpChunk;
|
||||
}
|
||||
|
||||
if (inputChunkCount == 1) {
|
||||
if (inputChunkCount == 1 &&
|
||||
inputChunks[0]->mChannelData.Length() == outputChannelCount) {
|
||||
return inputChunks[0];
|
||||
}
|
||||
|
||||
@ -233,6 +236,21 @@ AudioNodeStream::ObtainInputBlock(AudioChunk* aTmpChunk)
|
||||
AudioChannelsUpMix(&channels, outputChannelCount, nullptr);
|
||||
NS_ASSERTION(outputChannelCount == channels.Length(),
|
||||
"We called GetAudioChannelsSuperset to avoid this");
|
||||
} else if (channels.Length() > outputChannelCount) {
|
||||
nsAutoTArray<float*,GUESS_AUDIO_CHANNELS> outputChannels;
|
||||
outputChannels.SetLength(outputChannelCount);
|
||||
for (uint32_t i = 0; i < outputChannelCount; ++i) {
|
||||
outputChannels[i] =
|
||||
const_cast<float*>(static_cast<const float*>(aTmpChunk->mChannelData[i]));
|
||||
}
|
||||
|
||||
AudioChannelsDownMix(channels, outputChannels.Elements(),
|
||||
outputChannelCount, WEBAUDIO_BLOCK_SIZE);
|
||||
|
||||
channels.SetLength(outputChannelCount);
|
||||
for (uint32_t i = 0; i < channels.Length(); ++i) {
|
||||
channels[i] = outputChannels[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t c = 0; c < channels.Length(); ++c) {
|
||||
|
@ -43,10 +43,12 @@ public:
|
||||
* Transfers ownership of aEngine to the new AudioNodeStream.
|
||||
*/
|
||||
AudioNodeStream(AudioNodeEngine* aEngine,
|
||||
MediaStreamGraph::AudioNodeStreamKind aKind)
|
||||
MediaStreamGraph::AudioNodeStreamKind aKind,
|
||||
uint32_t aNumberOfInputChannels = 0)
|
||||
: ProcessedMediaStream(nullptr),
|
||||
mEngine(aEngine),
|
||||
mKind(aKind)
|
||||
mKind(aKind),
|
||||
mNumberOfInputChannels(aNumberOfInputChannels)
|
||||
{
|
||||
// AudioNodes are always producing data
|
||||
mHasCurrentData = true;
|
||||
@ -91,6 +93,8 @@ protected:
|
||||
AudioChunk mLastChunk;
|
||||
// Whether this is an internal or external stream
|
||||
MediaStreamGraph::AudioNodeStreamKind mKind;
|
||||
// The number of input channels that this stream requires. 0 means don't care.
|
||||
uint32_t mNumberOfInputChannels;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -2010,9 +2010,10 @@ MediaStreamGraph::CreateTrackUnionStream(DOMMediaStream* aWrapper)
|
||||
|
||||
AudioNodeStream*
|
||||
MediaStreamGraph::CreateAudioNodeStream(AudioNodeEngine* aEngine,
|
||||
AudioNodeStreamKind aKind)
|
||||
AudioNodeStreamKind aKind,
|
||||
uint32_t aNumberOfInputChannels)
|
||||
{
|
||||
AudioNodeStream* stream = new AudioNodeStream(aEngine, aKind);
|
||||
AudioNodeStream* stream = new AudioNodeStream(aEngine, aKind, aNumberOfInputChannels);
|
||||
NS_ADDREF(stream);
|
||||
MediaStreamGraphImpl* graph = static_cast<MediaStreamGraphImpl*>(this);
|
||||
stream->SetGraphImpl(graph);
|
||||
|
@ -909,7 +909,8 @@ public:
|
||||
* Takes ownership of aEngine.
|
||||
*/
|
||||
AudioNodeStream* CreateAudioNodeStream(AudioNodeEngine* aEngine,
|
||||
AudioNodeStreamKind aKind);
|
||||
AudioNodeStreamKind aKind,
|
||||
uint32_t aNumberOfInputChannels = 0);
|
||||
/**
|
||||
* Returns the number of graph updates sent. This can be used to track
|
||||
* whether a given update has been processed by the graph thread and reflected
|
||||
|
@ -20,6 +20,11 @@ var rate = 44100;
|
||||
|
||||
function runTests() {
|
||||
var a1 = new Audio();
|
||||
|
||||
ok("mozSetup" in a1, "mozSetup should be supported");
|
||||
ok("mozWriteAudio" in a1, "mozWriteAudio should be supported");
|
||||
ok("mozCurrentSampleOffset" in a1, "mozCurrentSampleOffset should be supported");
|
||||
|
||||
try {
|
||||
a1.mozSetup(channels, rate);
|
||||
} catch (ex) {
|
||||
|
@ -21,38 +21,34 @@ class AnalyserNodeEngine : public AudioNodeEngine
|
||||
class TransferBuffer : public nsRunnable
|
||||
{
|
||||
public:
|
||||
TransferBuffer(AnalyserNode* aNode,
|
||||
TransferBuffer(AudioNodeStream* aStream,
|
||||
const AudioChunk& aChunk)
|
||||
: mNode(aNode)
|
||||
: mStream(aStream)
|
||||
, mChunk(aChunk)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
mNode->AppendChunk(mChunk);
|
||||
nsRefPtr<AnalyserNode> node = static_cast<AnalyserNode*>(mStream->Engine()->Node());
|
||||
if (node) {
|
||||
node->AppendChunk(mChunk);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
AnalyserNode* mNode;
|
||||
nsRefPtr<AudioNodeStream> mStream;
|
||||
AudioChunk mChunk;
|
||||
};
|
||||
|
||||
public:
|
||||
explicit AnalyserNodeEngine(AnalyserNode& aNode)
|
||||
: mMutex("AnalyserNodeEngine")
|
||||
, mNode(&aNode)
|
||||
explicit AnalyserNodeEngine(AnalyserNode* aNode)
|
||||
: AudioNodeEngine(aNode)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
void DisconnectFromNode()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
mNode = nullptr;
|
||||
}
|
||||
|
||||
virtual void ProduceAudioBlock(AudioNodeStream* aStream,
|
||||
const AudioChunk& aInput,
|
||||
AudioChunk* aOutput,
|
||||
@ -60,17 +56,12 @@ public:
|
||||
{
|
||||
*aOutput = aInput;
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (mNode &&
|
||||
aInput.mChannelData.Length() > 0) {
|
||||
nsRefPtr<TransferBuffer> transfer = new TransferBuffer(mNode, aInput);
|
||||
nsRefPtr<TransferBuffer> transfer = new TransferBuffer(aStream, aInput);
|
||||
NS_DispatchToMainThread(transfer);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Mutex mMutex;
|
||||
AnalyserNode* mNode; // weak pointer, cleared by AnalyserNode::DestroyMediaStream
|
||||
};
|
||||
|
||||
AnalyserNode::AnalyserNode(AudioContext* aContext)
|
||||
@ -81,7 +72,7 @@ AnalyserNode::AnalyserNode(AudioContext* aContext)
|
||||
, mSmoothingTimeConstant(.8)
|
||||
, mWriteIndex(0)
|
||||
{
|
||||
mStream = aContext->Graph()->CreateAudioNodeStream(new AnalyserNodeEngine(*this),
|
||||
mStream = aContext->Graph()->CreateAudioNodeStream(new AnalyserNodeEngine(this),
|
||||
MediaStreamGraph::INTERNAL_STREAM);
|
||||
AllocateBuffer();
|
||||
}
|
||||
@ -255,11 +246,6 @@ AnalyserNode::ApplyBlackmanWindow(float* aBuffer, uint32_t aSize)
|
||||
void
|
||||
AnalyserNode::DestroyMediaStream()
|
||||
{
|
||||
if (mStream) {
|
||||
AudioNodeStream* ns = static_cast<AudioNodeStream*>(mStream.get());
|
||||
AnalyserNodeEngine* engine = static_cast<AnalyserNodeEngine*>(ns->Engine());
|
||||
engine->DisconnectFromNode();
|
||||
}
|
||||
AudioNode::DestroyMediaStream();
|
||||
}
|
||||
|
||||
|
@ -107,6 +107,13 @@ AudioBuffer::RestoreJSChannelData(JSContext* aJSContext)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioBuffer::SetRawChannelContents(JSContext* aJSContext, uint32_t aChannel,
|
||||
float* aContents)
|
||||
{
|
||||
memcpy(JS_GetFloat32ArrayData(mJSChannels[aChannel]), aContents, sizeof(float)*mLength);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
AudioBuffer::GetChannelData(JSContext* aJSContext, uint32_t aChannel,
|
||||
ErrorResult& aRv)
|
||||
|
@ -102,6 +102,14 @@ public:
|
||||
uint32_t aChannel,
|
||||
void* aContents);
|
||||
|
||||
// This replaces the contents of the JS array for the given channel.
|
||||
// This function needs to be called on an AudioBuffer which has not been
|
||||
// handed off to the content yet, and right after the object has been
|
||||
// initialized.
|
||||
void SetRawChannelContents(JSContext* aJSContext,
|
||||
uint32_t aChannel,
|
||||
float* aContents);
|
||||
|
||||
protected:
|
||||
void RestoreJSChannelData(JSContext* aJSContext);
|
||||
void ClearJSChannels();
|
||||
|
@ -38,7 +38,9 @@ NS_IMPL_RELEASE_INHERITED(AudioBufferSourceNode, AudioNode)
|
||||
class AudioBufferSourceNodeEngine : public AudioNodeEngine
|
||||
{
|
||||
public:
|
||||
explicit AudioBufferSourceNodeEngine(AudioDestinationNode* aDestination) :
|
||||
explicit AudioBufferSourceNodeEngine(AudioNode* aNode,
|
||||
AudioDestinationNode* aDestination) :
|
||||
AudioNodeEngine(aNode),
|
||||
mStart(0), mStop(TRACK_TICKS_MAX),
|
||||
mResampler(nullptr),
|
||||
mOffset(0), mDuration(0),
|
||||
@ -419,7 +421,7 @@ AudioBufferSourceNode::AudioBufferSourceNode(AudioContext* aContext)
|
||||
, mStartCalled(false)
|
||||
{
|
||||
mStream = aContext->Graph()->CreateAudioNodeStream(
|
||||
new AudioBufferSourceNodeEngine(aContext->Destination()),
|
||||
new AudioBufferSourceNodeEngine(this, aContext->Destination()),
|
||||
MediaStreamGraph::INTERNAL_STREAM);
|
||||
mStream->AddMainThreadListener(this);
|
||||
}
|
||||
|
@ -19,8 +19,13 @@
|
||||
#include "AudioListener.h"
|
||||
#include "DynamicsCompressorNode.h"
|
||||
#include "BiquadFilterNode.h"
|
||||
#include "ScriptProcessorNode.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
// Note that this number is an arbitrary large value to protect against OOM
|
||||
// attacks.
|
||||
const unsigned MAX_SCRIPT_PROCESSOR_CHANNELS = 10000;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
@ -99,6 +104,46 @@ AudioContext::CreateBuffer(JSContext* aJSContext, uint32_t aNumberOfChannels,
|
||||
return buffer.forget();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool IsValidBufferSize(uint32_t aBufferSize) {
|
||||
switch (aBufferSize) {
|
||||
case 0: // let the implementation choose the buffer size
|
||||
case 256:
|
||||
case 512:
|
||||
case 1024:
|
||||
case 2048:
|
||||
case 4096:
|
||||
case 8192:
|
||||
case 16384:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
already_AddRefed<ScriptProcessorNode>
|
||||
AudioContext::CreateScriptProcessor(uint32_t aBufferSize,
|
||||
uint32_t aNumberOfInputChannels,
|
||||
uint32_t aNumberOfOutputChannels,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (aNumberOfInputChannels == 0 || aNumberOfOutputChannels == 0 ||
|
||||
aNumberOfInputChannels > MAX_SCRIPT_PROCESSOR_CHANNELS ||
|
||||
aNumberOfOutputChannels > MAX_SCRIPT_PROCESSOR_CHANNELS ||
|
||||
!IsValidBufferSize(aBufferSize)) {
|
||||
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<ScriptProcessorNode> scriptProcessor =
|
||||
new ScriptProcessorNode(this, aBufferSize, aNumberOfInputChannels,
|
||||
aNumberOfOutputChannels);
|
||||
return scriptProcessor.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<AnalyserNode>
|
||||
AudioContext::CreateAnalyser()
|
||||
{
|
||||
|
@ -48,6 +48,7 @@ class DynamicsCompressorNode;
|
||||
class GainNode;
|
||||
class GlobalObject;
|
||||
class PannerNode;
|
||||
class ScriptProcessorNode;
|
||||
|
||||
class AudioContext MOZ_FINAL : public nsWrapperCache,
|
||||
public EnableWebAudioCheck
|
||||
@ -99,6 +100,22 @@ public:
|
||||
uint32_t aLength, float aSampleRate,
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<ScriptProcessorNode>
|
||||
CreateScriptProcessor(uint32_t aBufferSize,
|
||||
uint32_t aNumberOfInputChannels,
|
||||
uint32_t aNumberOfOutputChannels,
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<ScriptProcessorNode>
|
||||
CreateJavaScriptNode(uint32_t aBufferSize,
|
||||
uint32_t aNumberOfInputChannels,
|
||||
uint32_t aNumberOfOutputChannels,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
return CreateScriptProcessor(aBufferSize, aNumberOfInputChannels,
|
||||
aNumberOfOutputChannels, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<AnalyserNode>
|
||||
CreateAnalyser();
|
||||
|
||||
|
@ -18,7 +18,7 @@ NS_IMPL_ISUPPORTS_INHERITED0(AudioDestinationNode, AudioNode)
|
||||
AudioDestinationNode::AudioDestinationNode(AudioContext* aContext, MediaStreamGraph* aGraph)
|
||||
: AudioNode(aContext)
|
||||
{
|
||||
mStream = aGraph->CreateAudioNodeStream(new AudioNodeEngine(),
|
||||
mStream = aGraph->CreateAudioNodeStream(new AudioNodeEngine(this),
|
||||
MediaStreamGraph::EXTERNAL_STREAM);
|
||||
}
|
||||
|
||||
|
@ -201,5 +201,14 @@ AudioNode::Disconnect(uint32_t aOutput, ErrorResult& aRv)
|
||||
Context()->UpdatePannerSource();
|
||||
}
|
||||
|
||||
void
|
||||
AudioNode::UnbindFromEngine()
|
||||
{
|
||||
AudioNodeStream* ns = static_cast<AudioNodeStream*>(mStream.get());
|
||||
MOZ_ASSERT(ns, "How come we don't have a stream here?");
|
||||
MOZ_ASSERT(ns->Engine()->mNode == this, "Invalid node reference");
|
||||
ns->Engine()->mNode = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -83,6 +83,7 @@ public:
|
||||
virtual void DestroyMediaStream()
|
||||
{
|
||||
if (mStream) {
|
||||
UnbindFromEngine();
|
||||
mStream->Destroy();
|
||||
mStream = nullptr;
|
||||
}
|
||||
@ -152,6 +153,8 @@ private:
|
||||
// This could possibly delete 'this'.
|
||||
void DisconnectFromGraph();
|
||||
|
||||
void UnbindFromEngine();
|
||||
|
||||
protected:
|
||||
static void Callback(AudioNode* aNode) { /* not implemented */ }
|
||||
|
||||
|
52
content/media/webaudio/AudioProcessingEvent.cpp
Normal file
52
content/media/webaudio/AudioProcessingEvent.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#include "AudioProcessingEvent.h"
|
||||
#include "mozilla/dom/AudioProcessingEventBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED_3(AudioProcessingEvent, nsDOMEvent,
|
||||
mInputBuffer, mOutputBuffer, mNode)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(AudioProcessingEvent)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(AudioProcessingEvent, nsDOMEvent)
|
||||
NS_IMPL_RELEASE_INHERITED(AudioProcessingEvent, nsDOMEvent)
|
||||
|
||||
AudioProcessingEvent::AudioProcessingEvent(ScriptProcessorNode* aOwner,
|
||||
nsPresContext* aPresContext,
|
||||
nsEvent* aEvent)
|
||||
: nsDOMEvent(aOwner, aPresContext, aEvent)
|
||||
, mPlaybackTime(0.0)
|
||||
, mNode(aOwner)
|
||||
{
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
AudioProcessingEvent::WrapObject(JSContext* aCx, JSObject* aScope)
|
||||
{
|
||||
return AudioProcessingEventBinding::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
void
|
||||
AudioProcessingEvent::LazilyCreateBuffer(nsRefPtr<AudioBuffer>& aBuffer,
|
||||
uint32_t aNumberOfChannels)
|
||||
{
|
||||
AutoPushJSContext cx(mNode->Context()->GetJSContext());
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
aBuffer = new AudioBuffer(mNode->Context(), mNode->BufferSize(),
|
||||
mNode->Context()->SampleRate());
|
||||
aBuffer->InitializeBuffers(aNumberOfChannels, cx);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
83
content/media/webaudio/AudioProcessingEvent.h
Normal file
83
content/media/webaudio/AudioProcessingEvent.h
Normal file
@ -0,0 +1,83 @@
|
||||
/* -*- 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 AudioProcessingEvent_h_
|
||||
#define AudioProcessingEvent_h_
|
||||
|
||||
#include "nsDOMEvent.h"
|
||||
#include "AudioBuffer.h"
|
||||
#include "ScriptProcessorNode.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class AudioProcessingEvent : public nsDOMEvent,
|
||||
public EnableWebAudioCheck
|
||||
{
|
||||
public:
|
||||
AudioProcessingEvent(ScriptProcessorNode* aOwner,
|
||||
nsPresContext *aPresContext,
|
||||
nsEvent *aEvent);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_FORWARD_TO_NSDOMEVENT
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AudioProcessingEvent, nsDOMEvent)
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope);
|
||||
|
||||
void InitEvent(AudioBuffer* aInputBuffer,
|
||||
uint32_t aNumberOfInputChannels,
|
||||
double aPlaybackTime)
|
||||
{
|
||||
InitEvent(NS_LITERAL_STRING("audioprocess"), false, false);
|
||||
mInputBuffer = aInputBuffer;
|
||||
mNumberOfInputChannels = aNumberOfInputChannels;
|
||||
mPlaybackTime = aPlaybackTime;
|
||||
}
|
||||
|
||||
double PlaybackTime() const
|
||||
{
|
||||
return mPlaybackTime;
|
||||
}
|
||||
|
||||
AudioBuffer* InputBuffer()
|
||||
{
|
||||
if (!mInputBuffer) {
|
||||
LazilyCreateBuffer(mInputBuffer, mNumberOfInputChannels);
|
||||
}
|
||||
return mInputBuffer;
|
||||
}
|
||||
|
||||
AudioBuffer* OutputBuffer()
|
||||
{
|
||||
if (!mOutputBuffer) {
|
||||
LazilyCreateBuffer(mOutputBuffer, mNode->NumberOfOutputChannels());
|
||||
}
|
||||
return mOutputBuffer;
|
||||
}
|
||||
|
||||
bool HasOutputBuffer() const
|
||||
{
|
||||
return !!mOutputBuffer;
|
||||
}
|
||||
|
||||
private:
|
||||
void LazilyCreateBuffer(nsRefPtr<AudioBuffer>& aBuffer,
|
||||
uint32_t aNumberOfChannels);
|
||||
|
||||
private:
|
||||
double mPlaybackTime;
|
||||
nsRefPtr<AudioBuffer> mInputBuffer;
|
||||
nsRefPtr<AudioBuffer> mOutputBuffer;
|
||||
nsRefPtr<ScriptProcessorNode> mNode;
|
||||
uint32_t mNumberOfInputChannels;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -26,8 +26,9 @@ NS_IMPL_RELEASE_INHERITED(BiquadFilterNode, AudioNode)
|
||||
class BiquadFilterNodeEngine : public AudioNodeEngine
|
||||
{
|
||||
public:
|
||||
explicit BiquadFilterNodeEngine(AudioDestinationNode* aDestination)
|
||||
: mSource(nullptr)
|
||||
BiquadFilterNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination)
|
||||
: AudioNodeEngine(aNode)
|
||||
, mSource(nullptr)
|
||||
, mDestination(static_cast<AudioNodeStream*> (aDestination->Stream()))
|
||||
// Keep the default values in sync with the default values in
|
||||
// BiquadFilterNode::BiquadFilterNode
|
||||
@ -103,7 +104,7 @@ BiquadFilterNode::BiquadFilterNode(AudioContext* aContext)
|
||||
, mQ(new AudioParam(this, SendQToStream, 1.f))
|
||||
, mGain(new AudioParam(this, SendGainToStream, 0.f))
|
||||
{
|
||||
BiquadFilterNodeEngine* engine = new BiquadFilterNodeEngine(aContext->Destination());
|
||||
BiquadFilterNodeEngine* engine = new BiquadFilterNodeEngine(this, aContext->Destination());
|
||||
mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM);
|
||||
engine->SetSourceStream(static_cast<AudioNodeStream*> (mStream.get()));
|
||||
}
|
||||
|
@ -29,32 +29,35 @@ class DelayNodeEngine : public AudioNodeEngine
|
||||
{
|
||||
public:
|
||||
enum ChangeType { ADDREF, RELEASE };
|
||||
PlayingRefChanged(DelayNode& aNode, ChangeType aChange)
|
||||
: mNode(aNode)
|
||||
PlayingRefChanged(AudioNodeStream* aStream, ChangeType aChange)
|
||||
: mStream(aStream)
|
||||
, mChange(aChange)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
if (mChange == ADDREF) {
|
||||
mNode.mPlayingRef.Take(&mNode);
|
||||
} else if (mChange == RELEASE) {
|
||||
mNode.mPlayingRef.Drop(&mNode);
|
||||
nsRefPtr<DelayNode> node = static_cast<DelayNode*>(mStream->Engine()->Node());
|
||||
if (node) {
|
||||
if (mChange == ADDREF) {
|
||||
node->mPlayingRef.Take(node);
|
||||
} else if (mChange == RELEASE) {
|
||||
node->mPlayingRef.Drop(node);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
DelayNode& mNode;
|
||||
nsRefPtr<AudioNodeStream> mStream;
|
||||
ChangeType mChange;
|
||||
};
|
||||
|
||||
public:
|
||||
DelayNodeEngine(AudioDestinationNode* aDestination, DelayNode& aDelay)
|
||||
: mSource(nullptr)
|
||||
DelayNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination)
|
||||
: AudioNodeEngine(aNode)
|
||||
, mSource(nullptr)
|
||||
, mDestination(static_cast<AudioNodeStream*> (aDestination->Stream()))
|
||||
, mDelayNode(aDelay)
|
||||
// Keep the default value in sync with the default value in DelayNode::DelayNode.
|
||||
, mDelay(0.f)
|
||||
, mMaxDelay(0.)
|
||||
@ -136,7 +139,7 @@ public:
|
||||
mLeftOverData = static_cast<int32_t>(mCurrentDelayTime * IdealAudioRate());
|
||||
|
||||
nsRefPtr<PlayingRefChanged> refchanged =
|
||||
new PlayingRefChanged(mDelayNode, PlayingRefChanged::ADDREF);
|
||||
new PlayingRefChanged(aStream, PlayingRefChanged::ADDREF);
|
||||
NS_DispatchToMainThread(refchanged);
|
||||
} else if (mLeftOverData != INT32_MIN) {
|
||||
mLeftOverData -= WEBAUDIO_BLOCK_SIZE;
|
||||
@ -145,7 +148,7 @@ public:
|
||||
playedBackAllLeftOvers = true;
|
||||
|
||||
nsRefPtr<PlayingRefChanged> refchanged =
|
||||
new PlayingRefChanged(mDelayNode, PlayingRefChanged::RELEASE);
|
||||
new PlayingRefChanged(aStream, PlayingRefChanged::RELEASE);
|
||||
NS_DispatchToMainThread(refchanged);
|
||||
}
|
||||
}
|
||||
@ -244,7 +247,6 @@ public:
|
||||
|
||||
AudioNodeStream* mSource;
|
||||
AudioNodeStream* mDestination;
|
||||
DelayNode& mDelayNode;
|
||||
AudioParamTimeline mDelay;
|
||||
// Maximum delay time in seconds
|
||||
double mMaxDelay;
|
||||
@ -264,7 +266,7 @@ DelayNode::DelayNode(AudioContext* aContext, double aMaxDelay)
|
||||
: AudioNode(aContext)
|
||||
, mDelay(new AudioParam(this, SendDelayToStream, 0.0f))
|
||||
{
|
||||
DelayNodeEngine* engine = new DelayNodeEngine(aContext->Destination(), *this);
|
||||
DelayNodeEngine* engine = new DelayNodeEngine(this, aContext->Destination());
|
||||
mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM);
|
||||
engine->SetSourceStream(static_cast<AudioNodeStream*> (mStream.get()));
|
||||
AudioNodeStream* ns = static_cast<AudioNodeStream*>(mStream.get());
|
||||
|
@ -31,8 +31,10 @@ NS_IMPL_RELEASE_INHERITED(DynamicsCompressorNode, AudioNode)
|
||||
class DynamicsCompressorNodeEngine : public AudioNodeEngine
|
||||
{
|
||||
public:
|
||||
explicit DynamicsCompressorNodeEngine(AudioDestinationNode* aDestination)
|
||||
: mSource(nullptr)
|
||||
explicit DynamicsCompressorNodeEngine(AudioNode* aNode,
|
||||
AudioDestinationNode* aDestination)
|
||||
: AudioNodeEngine(aNode)
|
||||
, mSource(nullptr)
|
||||
, mDestination(static_cast<AudioNodeStream*> (aDestination->Stream()))
|
||||
// Keep the default value in sync with the default value in
|
||||
// DynamicsCompressorNode::DynamicsCompressorNode.
|
||||
@ -120,7 +122,7 @@ DynamicsCompressorNode::DynamicsCompressorNode(AudioContext* aContext)
|
||||
, mAttack(new AudioParam(this, SendAttackToStream, 0.003f))
|
||||
, mRelease(new AudioParam(this, SendReleaseToStream, 0.25f))
|
||||
{
|
||||
DynamicsCompressorNodeEngine* engine = new DynamicsCompressorNodeEngine(aContext->Destination());
|
||||
DynamicsCompressorNodeEngine* engine = new DynamicsCompressorNodeEngine(this, aContext->Destination());
|
||||
mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM);
|
||||
engine->SetSourceStream(static_cast<AudioNodeStream*> (mStream.get()));
|
||||
}
|
||||
|
@ -26,8 +26,9 @@ NS_IMPL_RELEASE_INHERITED(GainNode, AudioNode)
|
||||
class GainNodeEngine : public AudioNodeEngine
|
||||
{
|
||||
public:
|
||||
explicit GainNodeEngine(AudioDestinationNode* aDestination)
|
||||
: mSource(nullptr)
|
||||
GainNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination)
|
||||
: AudioNodeEngine(aNode)
|
||||
, mSource(nullptr)
|
||||
, mDestination(static_cast<AudioNodeStream*> (aDestination->Stream()))
|
||||
// Keep the default value in sync with the default value in GainNode::GainNode.
|
||||
, mGain(1.f)
|
||||
@ -97,7 +98,7 @@ GainNode::GainNode(AudioContext* aContext)
|
||||
: AudioNode(aContext)
|
||||
, mGain(new AudioParam(this, SendGainToStream, 1.0f))
|
||||
{
|
||||
GainNodeEngine* engine = new GainNodeEngine(aContext->Destination());
|
||||
GainNodeEngine* engine = new GainNodeEngine(this, aContext->Destination());
|
||||
mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM);
|
||||
engine->SetSourceStream(static_cast<AudioNodeStream*> (mStream.get()));
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ CPPSRCS := \
|
||||
AudioListener.cpp \
|
||||
AudioNode.cpp \
|
||||
AudioParam.cpp \
|
||||
AudioProcessingEvent.cpp \
|
||||
BiquadFilterNode.cpp \
|
||||
DelayNode.cpp \
|
||||
DynamicsCompressorNode.cpp \
|
||||
@ -31,6 +32,7 @@ CPPSRCS := \
|
||||
GainNode.cpp \
|
||||
MediaBufferDecoder.cpp \
|
||||
PannerNode.cpp \
|
||||
ScriptProcessorNode.cpp \
|
||||
ThreeDPoint.cpp \
|
||||
WebAudioUtils.cpp \
|
||||
$(NULL)
|
||||
|
@ -18,9 +18,10 @@ using namespace std;
|
||||
class PannerNodeEngine : public AudioNodeEngine
|
||||
{
|
||||
public:
|
||||
PannerNodeEngine()
|
||||
explicit PannerNodeEngine(AudioNode* aNode)
|
||||
: AudioNodeEngine(aNode)
|
||||
// Please keep these default values consistent with PannerNode::PannerNode below.
|
||||
: mPanningModel(PanningModelTypeValues::HRTF)
|
||||
, mPanningModel(PanningModelTypeValues::HRTF)
|
||||
, mPanningModelFunction(&PannerNodeEngine::HRTFPanningFunction)
|
||||
, mDistanceModel(DistanceModelTypeValues::Inverse)
|
||||
, mDistanceModelFunction(&PannerNodeEngine::InverseGainFunction)
|
||||
@ -172,7 +173,7 @@ PannerNode::PannerNode(AudioContext* aContext)
|
||||
, mConeOuterAngle(360.)
|
||||
, mConeOuterGain(0.)
|
||||
{
|
||||
mStream = aContext->Graph()->CreateAudioNodeStream(new PannerNodeEngine(),
|
||||
mStream = aContext->Graph()->CreateAudioNodeStream(new PannerNodeEngine(this),
|
||||
MediaStreamGraph::INTERNAL_STREAM);
|
||||
// We should register once we have set up our stream and engine.
|
||||
Context()->Listener()->RegisterPannerNode(this);
|
||||
|
377
content/media/webaudio/ScriptProcessorNode.cpp
Normal file
377
content/media/webaudio/ScriptProcessorNode.cpp
Normal file
@ -0,0 +1,377 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#include "ScriptProcessorNode.h"
|
||||
#include "mozilla/dom/ScriptProcessorNodeBinding.h"
|
||||
#include "AudioBuffer.h"
|
||||
#include "AudioDestinationNode.h"
|
||||
#include "AudioNodeEngine.h"
|
||||
#include "AudioNodeStream.h"
|
||||
#include "AudioProcessingEvent.h"
|
||||
#include "WebAudioUtils.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include <deque>
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ScriptProcessorNode)
|
||||
NS_INTERFACE_MAP_END_INHERITING(AudioNode)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(ScriptProcessorNode, AudioNode)
|
||||
NS_IMPL_RELEASE_INHERITED(ScriptProcessorNode, AudioNode)
|
||||
|
||||
// This class manages a queue of output buffers shared between
|
||||
// the main thread and the Media Stream Graph thread.
|
||||
class SharedBuffers
|
||||
{
|
||||
private:
|
||||
class OutputQueue
|
||||
{
|
||||
public:
|
||||
explicit OutputQueue(const char* aName)
|
||||
: mMutex(aName)
|
||||
{}
|
||||
|
||||
Mutex& Lock() { return mMutex; }
|
||||
|
||||
size_t ReadyToConsume() const
|
||||
{
|
||||
mMutex.AssertCurrentThreadOwns();
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
return mBufferList.size();
|
||||
}
|
||||
|
||||
// Produce one buffer
|
||||
AudioChunk& Produce()
|
||||
{
|
||||
mMutex.AssertCurrentThreadOwns();
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mBufferList.push_back(AudioChunk());
|
||||
return mBufferList.back();
|
||||
}
|
||||
|
||||
// Consumes one buffer.
|
||||
AudioChunk Consume()
|
||||
{
|
||||
mMutex.AssertCurrentThreadOwns();
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(ReadyToConsume() > 0);
|
||||
AudioChunk front = mBufferList.front();
|
||||
mBufferList.pop_front();
|
||||
return front;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::deque<AudioChunk> BufferList;
|
||||
|
||||
// Synchronizes access to mBufferList. Note that it's the responsibility
|
||||
// of the callers to perform the required locking, and we assert that every
|
||||
// time we access mBufferList.
|
||||
Mutex mMutex;
|
||||
// The list representing the queue.
|
||||
BufferList mBufferList;
|
||||
};
|
||||
|
||||
public:
|
||||
SharedBuffers()
|
||||
: mOutputQueue("SharedBuffers::outputQueue")
|
||||
, mDelaySoFar(TRACK_TICKS_MAX)
|
||||
{
|
||||
}
|
||||
|
||||
// main thread
|
||||
void FinishProducingOutputBuffer(ThreadSharedFloatArrayBufferList* aBuffer,
|
||||
uint32_t aBufferSize)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
MutexAutoLock lock(mOutputQueue.Lock());
|
||||
for (uint32_t offset = 0; offset < aBufferSize; offset += WEBAUDIO_BLOCK_SIZE) {
|
||||
AudioChunk& chunk = mOutputQueue.Produce();
|
||||
if (aBuffer) {
|
||||
chunk.mDuration = WEBAUDIO_BLOCK_SIZE;
|
||||
chunk.mBuffer = aBuffer;
|
||||
chunk.mChannelData.SetLength(aBuffer->GetChannels());
|
||||
for (uint32_t i = 0; i < aBuffer->GetChannels(); ++i) {
|
||||
chunk.mChannelData[i] = aBuffer->GetData(i) + offset;
|
||||
}
|
||||
chunk.mVolume = 1.0f;
|
||||
chunk.mBufferFormat = AUDIO_FORMAT_FLOAT32;
|
||||
} else {
|
||||
chunk.SetNull(WEBAUDIO_BLOCK_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// graph thread
|
||||
AudioChunk GetOutputBuffer()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
AudioChunk buffer;
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mOutputQueue.Lock());
|
||||
if (mOutputQueue.ReadyToConsume() > 0) {
|
||||
if (mDelaySoFar == TRACK_TICKS_MAX) {
|
||||
mDelaySoFar = 0;
|
||||
}
|
||||
buffer = mOutputQueue.Consume();
|
||||
} else {
|
||||
// If we're out of buffers to consume, just output silence
|
||||
buffer.SetNull(WEBAUDIO_BLOCK_SIZE);
|
||||
if (mDelaySoFar != TRACK_TICKS_MAX) {
|
||||
// Remember the delay that we just hit
|
||||
mDelaySoFar += WEBAUDIO_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
TrackTicks DelaySoFar() const
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
return mDelaySoFar == TRACK_TICKS_MAX ? 0 : mDelaySoFar;
|
||||
}
|
||||
|
||||
private:
|
||||
OutputQueue mOutputQueue;
|
||||
// How much delay we've seen so far. This measures the amount of delay
|
||||
// caused by the main thread lagging behind in producing output buffers.
|
||||
// TRACK_TICKS_MAX means that we have not received our first buffer yet.
|
||||
TrackTicks mDelaySoFar;
|
||||
};
|
||||
|
||||
class ScriptProcessorNodeEngine : public AudioNodeEngine
|
||||
{
|
||||
public:
|
||||
typedef nsAutoTArray<nsAutoArrayPtr<float>, 2> InputChannels;
|
||||
|
||||
ScriptProcessorNodeEngine(ScriptProcessorNode* aNode,
|
||||
AudioDestinationNode* aDestination,
|
||||
uint32_t aBufferSize,
|
||||
uint32_t aNumberOfInputChannels)
|
||||
: AudioNodeEngine(aNode)
|
||||
, mSharedBuffers(aNode->GetSharedBuffers())
|
||||
, mSource(nullptr)
|
||||
, mDestination(static_cast<AudioNodeStream*> (aDestination->Stream()))
|
||||
, mBufferSize(aBufferSize)
|
||||
, mInputWriteIndex(0)
|
||||
, mSeenNonSilenceInput(false)
|
||||
{
|
||||
mInputChannels.SetLength(aNumberOfInputChannels);
|
||||
AllocateInputBlock();
|
||||
}
|
||||
|
||||
void SetSourceStream(AudioNodeStream* aSource)
|
||||
{
|
||||
mSource = aSource;
|
||||
}
|
||||
|
||||
virtual void ProduceAudioBlock(AudioNodeStream* aStream,
|
||||
const AudioChunk& aInput,
|
||||
AudioChunk* aOutput,
|
||||
bool* aFinished) MOZ_OVERRIDE
|
||||
{
|
||||
// If our node is dead, just output silence
|
||||
if (!mNode) {
|
||||
aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
// First, record our input buffer
|
||||
for (uint32_t i = 0; i < mInputChannels.Length(); ++i) {
|
||||
if (aInput.IsNull()) {
|
||||
PodZero(mInputChannels[i] + mInputWriteIndex,
|
||||
aInput.GetDuration());
|
||||
} else {
|
||||
mSeenNonSilenceInput = true;
|
||||
PodCopy(mInputChannels[i] + mInputWriteIndex,
|
||||
static_cast<const float*>(aInput.mChannelData[i]),
|
||||
aInput.GetDuration());
|
||||
}
|
||||
}
|
||||
mInputWriteIndex += aInput.GetDuration();
|
||||
|
||||
// Now, see if we have data to output
|
||||
// Note that we need to do this before sending the buffer to the main
|
||||
// thread so that our delay time is updated.
|
||||
*aOutput = mSharedBuffers->GetOutputBuffer();
|
||||
|
||||
if (mInputWriteIndex >= mBufferSize) {
|
||||
SendBuffersToMainThread(aStream);
|
||||
mInputWriteIndex -= mBufferSize;
|
||||
mSeenNonSilenceInput = false;
|
||||
AllocateInputBlock();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void AllocateInputBlock()
|
||||
{
|
||||
for (unsigned i = 0; i < mInputChannels.Length(); ++i) {
|
||||
if (!mInputChannels[i]) {
|
||||
mInputChannels[i] = new float[mBufferSize];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SendBuffersToMainThread(AudioNodeStream* aStream)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
// we now have a full input buffer ready to be sent to the main thread.
|
||||
TrackTicks playbackTick = mSource->GetCurrentPosition();
|
||||
// Add the duration of the current sample
|
||||
playbackTick += WEBAUDIO_BLOCK_SIZE;
|
||||
// Add the delay caused by the main thread
|
||||
playbackTick += mSharedBuffers->DelaySoFar();
|
||||
// Compute the playback time in the coordinate system of the destination
|
||||
double playbackTime =
|
||||
WebAudioUtils::StreamPositionToDestinationTime(playbackTick,
|
||||
mSource,
|
||||
mDestination);
|
||||
|
||||
class Command : public nsRunnable
|
||||
{
|
||||
public:
|
||||
Command(AudioNodeStream* aStream,
|
||||
InputChannels& aInputChannels,
|
||||
double aPlaybackTime,
|
||||
bool aNullInput)
|
||||
: mStream(aStream)
|
||||
, mPlaybackTime(aPlaybackTime)
|
||||
, mNullInput(aNullInput)
|
||||
{
|
||||
mInputChannels.SetLength(aInputChannels.Length());
|
||||
if (!aNullInput) {
|
||||
for (uint32_t i = 0; i < mInputChannels.Length(); ++i) {
|
||||
mInputChannels[i] = aInputChannels[i].forget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP Run()
|
||||
{
|
||||
// If it's not safe to run scripts right now, schedule this to run later
|
||||
if (!nsContentUtils::IsSafeToRunScript()) {
|
||||
nsContentUtils::AddScriptRunner(this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<ScriptProcessorNode> node = static_cast<ScriptProcessorNode*>(mStream->Engine()->Node());
|
||||
if (!node) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AutoPushJSContext cx(node->Context()->GetJSContext());
|
||||
if (cx) {
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
// Create the input buffer
|
||||
nsRefPtr<AudioBuffer> inputBuffer;
|
||||
if (!mNullInput) {
|
||||
inputBuffer = new AudioBuffer(node->Context(),
|
||||
node->BufferSize(),
|
||||
node->Context()->SampleRate());
|
||||
if (!inputBuffer->InitializeBuffers(mInputChannels.Length(), cx)) {
|
||||
return NS_OK;
|
||||
}
|
||||
// Put the channel data inside it
|
||||
for (uint32_t i = 0; i < mInputChannels.Length(); ++i) {
|
||||
inputBuffer->SetRawChannelContents(cx, i, mInputChannels[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Ask content to produce data in the output buffer
|
||||
// Note that we always avoid creating the output buffer here, and we try to
|
||||
// avoid creating the input buffer as well. The AudioProcessingEvent class
|
||||
// knows how to lazily create them if needed once the script tries to access
|
||||
// them. Otherwise, we may be able to get away without creating them!
|
||||
nsRefPtr<AudioProcessingEvent> event = new AudioProcessingEvent(node, nullptr, nullptr);
|
||||
event->InitEvent(inputBuffer,
|
||||
mInputChannels.Length(),
|
||||
mPlaybackTime);
|
||||
node->DispatchTrustedEvent(event);
|
||||
|
||||
// Steal the output buffers
|
||||
nsRefPtr<ThreadSharedFloatArrayBufferList> output;
|
||||
if (event->HasOutputBuffer()) {
|
||||
uint32_t rate, length;
|
||||
output = event->OutputBuffer()->GetThreadSharedChannelsForRate(cx, &rate, &length);
|
||||
unused << rate;
|
||||
unused << length;
|
||||
}
|
||||
|
||||
// Append it to our output buffer queue
|
||||
node->GetSharedBuffers()->FinishProducingOutputBuffer(output, node->BufferSize());
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
nsRefPtr<AudioNodeStream> mStream;
|
||||
InputChannels mInputChannels;
|
||||
double mPlaybackTime;
|
||||
bool mNullInput;
|
||||
};
|
||||
|
||||
NS_DispatchToMainThread(new Command(aStream, mInputChannels,
|
||||
playbackTime,
|
||||
!mSeenNonSilenceInput));
|
||||
}
|
||||
|
||||
friend class ScriptProcessorNode;
|
||||
|
||||
SharedBuffers* mSharedBuffers;
|
||||
AudioNodeStream* mSource;
|
||||
AudioNodeStream* mDestination;
|
||||
InputChannels mInputChannels;
|
||||
const uint32_t mBufferSize;
|
||||
// The write index into the current input buffer
|
||||
uint32_t mInputWriteIndex;
|
||||
bool mSeenNonSilenceInput;
|
||||
};
|
||||
|
||||
ScriptProcessorNode::ScriptProcessorNode(AudioContext* aContext,
|
||||
uint32_t aBufferSize,
|
||||
uint32_t aNumberOfInputChannels,
|
||||
uint32_t aNumberOfOutputChannels)
|
||||
: AudioNode(aContext)
|
||||
, mSharedBuffers(new SharedBuffers())
|
||||
, mBufferSize(aBufferSize ?
|
||||
aBufferSize : // respect what the web developer requested
|
||||
4096) // choose our own buffer size -- 4KB for now
|
||||
, mNumberOfOutputChannels(aNumberOfOutputChannels)
|
||||
{
|
||||
MOZ_ASSERT(BufferSize() % WEBAUDIO_BLOCK_SIZE == 0, "Invalid buffer size");
|
||||
ScriptProcessorNodeEngine* engine =
|
||||
new ScriptProcessorNodeEngine(this,
|
||||
aContext->Destination(),
|
||||
BufferSize(),
|
||||
aNumberOfInputChannels);
|
||||
mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM,
|
||||
aNumberOfInputChannels);
|
||||
engine->SetSourceStream(static_cast<AudioNodeStream*> (mStream.get()));
|
||||
}
|
||||
|
||||
ScriptProcessorNode::~ScriptProcessorNode()
|
||||
{
|
||||
DestroyMediaStream();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
ScriptProcessorNode::WrapObject(JSContext* aCx, JSObject* aScope)
|
||||
{
|
||||
return ScriptProcessorNodeBinding::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
70
content/media/webaudio/ScriptProcessorNode.h
Normal file
70
content/media/webaudio/ScriptProcessorNode.h
Normal file
@ -0,0 +1,70 @@
|
||||
/* -*- 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 ScriptProcessorNode_h_
|
||||
#define ScriptProcessorNode_h_
|
||||
|
||||
#include "AudioNode.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class AudioNodeStream;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class AudioContext;
|
||||
class ScriptProcessorNodeEngine;
|
||||
class SharedBuffers;
|
||||
|
||||
class ScriptProcessorNode : public AudioNode
|
||||
{
|
||||
public:
|
||||
ScriptProcessorNode(AudioContext* aContext,
|
||||
uint32_t aBufferSize,
|
||||
uint32_t aNumberOfInputChannels,
|
||||
uint32_t aNumberOfOutputChannels);
|
||||
virtual ~ScriptProcessorNode();
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
IMPL_EVENT_HANDLER(audioprocess)
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope);
|
||||
|
||||
virtual bool SupportsMediaStreams() const MOZ_OVERRIDE
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t BufferSize() const
|
||||
{
|
||||
return mBufferSize;
|
||||
}
|
||||
|
||||
SharedBuffers* GetSharedBuffers() const
|
||||
{
|
||||
return mSharedBuffers;
|
||||
}
|
||||
|
||||
uint32_t NumberOfOutputChannels() const
|
||||
{
|
||||
return mNumberOfOutputChannels;
|
||||
}
|
||||
|
||||
using nsDOMEventTargetHelper::DispatchTrustedEvent;
|
||||
|
||||
private:
|
||||
nsAutoPtr<SharedBuffers> mSharedBuffers;
|
||||
const uint32_t mBufferSize;
|
||||
const uint32_t mNumberOfOutputChannels;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -34,6 +34,17 @@ struct ConvertTimeToTickHelper
|
||||
}
|
||||
};
|
||||
|
||||
double
|
||||
WebAudioUtils::StreamPositionToDestinationTime(TrackTicks aSourcePosition,
|
||||
AudioNodeStream* aSource,
|
||||
AudioNodeStream* aDestination)
|
||||
{
|
||||
StreamTime sourceTime = TicksToTimeRoundDown(IdealAudioRate(), aSourcePosition);
|
||||
GraphTime graphTime = aSource->StreamTimeToGraphTime(sourceTime);
|
||||
StreamTime destinationTime = aDestination->GraphTimeToStreamTimeOptimistic(graphTime);
|
||||
return MediaTimeToSeconds(destinationTime);
|
||||
}
|
||||
|
||||
void
|
||||
WebAudioUtils::ConvertAudioParamToTicks(AudioParamTimeline& aParam,
|
||||
AudioNodeStream* aSource,
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include <cmath>
|
||||
#include "AudioParamTimeline.h"
|
||||
#include "MediaSegment.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -73,6 +74,14 @@ struct WebAudioUtils {
|
||||
aDouble = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a stream position into the time coordinate of the destination
|
||||
* stream.
|
||||
*/
|
||||
static double StreamPositionToDestinationTime(TrackTicks aSourcePosition,
|
||||
AudioNodeStream* aSource,
|
||||
AudioNodeStream* aDestination);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -26,11 +26,13 @@ EXPORTS.mozilla.dom += [
|
||||
'AudioListener.h',
|
||||
'AudioNode.h',
|
||||
'AudioParam.h',
|
||||
'AudioProcessingEvent.h',
|
||||
'BiquadFilterNode.h',
|
||||
'DelayNode.h',
|
||||
'DynamicsCompressorNode.h',
|
||||
'EnableWebAudioCheck.h',
|
||||
'GainNode.h',
|
||||
'PannerNode.h',
|
||||
'ScriptProcessorNode.h',
|
||||
]
|
||||
|
||||
|
@ -22,6 +22,7 @@ MOCHITEST_FILES := \
|
||||
test_AudioContext.html \
|
||||
test_AudioListener.html \
|
||||
test_AudioParam.html \
|
||||
test_audioBufferSourceNode.html \
|
||||
test_badConnect.html \
|
||||
test_biquadFilterNode.html \
|
||||
test_currentTime.html \
|
||||
@ -30,6 +31,7 @@ MOCHITEST_FILES := \
|
||||
test_dynamicsCompressorNode.html \
|
||||
test_gainNode.html \
|
||||
test_pannerNode.html \
|
||||
test_scriptProcessorNode.html \
|
||||
test_singleSourceDest.html \
|
||||
ting.ogg \
|
||||
ting-expected.wav \
|
||||
|
52
content/media/webaudio/test/test_audioBufferSourceNode.html
Normal file
52
content/media/webaudio/test/test_audioBufferSourceNode.html
Normal file
@ -0,0 +1,52 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test AudioBufferSourceNode</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="webaudio.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(function() {
|
||||
SpecialPowers.setBoolPref("media.webaudio.enabled", true);
|
||||
|
||||
var context = new AudioContext();
|
||||
var buffer = context.createBuffer(1, 2048, context.sampleRate);
|
||||
for (var i = 0; i < 2048; ++i) {
|
||||
buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
|
||||
}
|
||||
|
||||
var source = context.createBufferSource();
|
||||
source.buffer = buffer;
|
||||
|
||||
var sp = context.createScriptProcessor(2048);
|
||||
source.start(0);
|
||||
source.connect(sp);
|
||||
sp.connect(context.destination);
|
||||
sp.onaudioprocess = function(e) {
|
||||
compareBuffers(e.inputBuffer.getChannelData(0), buffer.getChannelData(0));
|
||||
compareBuffers(e.inputBuffer.getChannelData(1), buffer.getChannelData(0));
|
||||
|
||||
// On the next iteration, we'll get a silence buffer
|
||||
sp.onaudioprocess = function(e) {
|
||||
var emptyBuffer = context.createBuffer(1, 2048, context.sampleRate);
|
||||
compareBuffers(e.inputBuffer.getChannelData(0), emptyBuffer.getChannelData(0));
|
||||
compareBuffers(e.inputBuffer.getChannelData(1), emptyBuffer.getChannelData(0));
|
||||
|
||||
sp.onaudioprocess = null;
|
||||
sp.disconnect(context.destination);
|
||||
|
||||
SpecialPowers.clearUserPref("media.webaudio.enabled");
|
||||
SimpleTest.finish();
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
139
content/media/webaudio/test/test_scriptProcessorNode.html
Normal file
139
content/media/webaudio/test/test_scriptProcessorNode.html
Normal file
@ -0,0 +1,139 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test ScriptProcessorNode</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="webaudio.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(function() {
|
||||
SpecialPowers.setBoolPref("media.webaudio.enabled", true);
|
||||
|
||||
var context = new AudioContext();
|
||||
var buffer = null;
|
||||
|
||||
var sourceSP = context.createJavaScriptNode(2048);
|
||||
sourceSP.addEventListener("audioprocess", function(e) {
|
||||
// generate the audio
|
||||
for (var i = 0; i < 2048; ++i) {
|
||||
// Make sure our first sample won't be zero
|
||||
e.outputBuffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * (i + 1) / context.sampleRate);
|
||||
e.outputBuffer.getChannelData(0)[i] = Math.sin(880 * 2 * Math.PI * (i + 1) / context.sampleRate);
|
||||
}
|
||||
// Remember our generated audio
|
||||
buffer = e.outputBuffer;
|
||||
|
||||
sourceSP.removeEventListener("audioprocess", arguments.callee);
|
||||
}, false);
|
||||
|
||||
expectException(function() {
|
||||
context.createScriptProcessor(1);
|
||||
}, DOMException.INDEX_SIZE_ERR);
|
||||
expectException(function() {
|
||||
context.createScriptProcessor(2);
|
||||
}, DOMException.INDEX_SIZE_ERR);
|
||||
expectException(function() {
|
||||
context.createScriptProcessor(128);
|
||||
}, DOMException.INDEX_SIZE_ERR);
|
||||
expectException(function() {
|
||||
context.createScriptProcessor(255);
|
||||
}, DOMException.INDEX_SIZE_ERR);
|
||||
|
||||
function findFirstNonZeroSample(buffer) {
|
||||
for (var i = 0; i < buffer.length; ++i) {
|
||||
if (buffer.getChannelData(0)[i] != 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return buffer.length;
|
||||
}
|
||||
|
||||
var sp = context.createScriptProcessor(2048);
|
||||
sourceSP.connect(sp);
|
||||
sp.connect(context.destination);
|
||||
var lastPlaybackTime = 0;
|
||||
sp.onaudioprocess = function(e) {
|
||||
isnot(buffer, null, "The audioprocess handler for sourceSP must be run at this point");
|
||||
is(e.target, sp, "Correct event target");
|
||||
ok(e.playbackTime > lastPlaybackTime, "playbackTime correctly set");
|
||||
lastPlaybackTime = e.playbackTime;
|
||||
is(e.inputBuffer.numberOfChannels, 2, "Correct number of channels for the input buffer");
|
||||
is(e.inputBuffer.length, 2048, "Correct length for the input buffer");
|
||||
is(e.inputBuffer.sampleRate, context.sampleRate, "Correct sample rate for the input buffer");
|
||||
is(e.outputBuffer.numberOfChannels, 2, "Correct number of channels for the output buffer");
|
||||
is(e.outputBuffer.length, 2048, "Correct length for the output buffer");
|
||||
is(e.outputBuffer.sampleRate, context.sampleRate, "Correct sample rate for the output buffer");
|
||||
|
||||
// Because of the initial latency added by the second script processor node,
|
||||
// we will never see any generated audio frames in the first callback.
|
||||
var emptyBuffer = context.createBuffer(1, 2048, context.sampleRate);
|
||||
compareBuffers(e.inputBuffer.getChannelData(0), emptyBuffer.getChannelData(0));
|
||||
compareBuffers(e.inputBuffer.getChannelData(1), emptyBuffer.getChannelData(0));
|
||||
compareBuffers(e.outputBuffer.getChannelData(0), emptyBuffer.getChannelData(0));
|
||||
compareBuffers(e.outputBuffer.getChannelData(1), emptyBuffer.getChannelData(0));
|
||||
|
||||
sp.onaudioprocess = function(e) {
|
||||
is(e.target, sp, "Correct event target");
|
||||
ok(e.playbackTime > lastPlaybackTime, "playbackTime correctly set");
|
||||
lastPlaybackTime = e.playbackTime;
|
||||
is(e.inputBuffer.numberOfChannels, 2, "Correct number of channels for the input buffer");
|
||||
is(e.inputBuffer.length, 2048, "Correct length for the input buffer");
|
||||
is(e.inputBuffer.sampleRate, context.sampleRate, "Correct sample rate for the input buffer");
|
||||
is(e.outputBuffer.numberOfChannels, 2, "Correct number of channels for the output buffer");
|
||||
is(e.outputBuffer.length, 2048, "Correct length for the output buffer");
|
||||
is(e.outputBuffer.sampleRate, context.sampleRate, "Correct sample rate for the output buffer");
|
||||
|
||||
var firstNonZero = findFirstNonZeroSample(e.inputBuffer);
|
||||
|
||||
compareBuffers(e.inputBuffer.getChannelData(0), emptyBuffer.getChannelData(0), 0, Math.min(firstNonZero, 2048));
|
||||
compareBuffers(e.inputBuffer.getChannelData(1), emptyBuffer.getChannelData(0), 0, Math.min(firstNonZero, 2048));
|
||||
compareBuffers(e.inputBuffer.getChannelData(0), buffer.getChannelData(0), Math.min(firstNonZero, 2048), 2048 - firstNonZero, 0, -firstNonZero);
|
||||
compareBuffers(e.inputBuffer.getChannelData(1), buffer.getChannelData(1), Math.min(firstNonZero, 2048), 2048 - firstNonZero, 0, -firstNonZero);
|
||||
compareBuffers(e.outputBuffer.getChannelData(0), emptyBuffer.getChannelData(0));
|
||||
compareBuffers(e.outputBuffer.getChannelData(1), emptyBuffer.getChannelData(0));
|
||||
|
||||
if (firstNonZero == 0) {
|
||||
// If we did not experience any delays, the test is done!
|
||||
sp.onaudioprocess = null;
|
||||
|
||||
SpecialPowers.clearUserPref("media.webaudio.enabled");
|
||||
SimpleTest.finish();
|
||||
} else if (firstNonZero != 2048) {
|
||||
// In case we just saw a zero buffer this time, wait one more round
|
||||
sp.onaudioprocess = function(e) {
|
||||
is(e.target, sp, "Correct event target");
|
||||
ok(e.playbackTime > lastPlaybackTime, "playbackTime correctly set");
|
||||
lastPlaybackTime = e.playbackTime;
|
||||
is(e.inputBuffer.numberOfChannels, 2, "Correct number of channels for the input buffer");
|
||||
is(e.inputBuffer.length, 2048, "Correct length for the input buffer");
|
||||
is(e.inputBuffer.sampleRate, context.sampleRate, "Correct sample rate for the input buffer");
|
||||
is(e.outputBuffer.numberOfChannels, 2, "Correct number of channels for the output buffer");
|
||||
is(e.outputBuffer.length, 2048, "Correct length for the output buffer");
|
||||
is(e.outputBuffer.sampleRate, context.sampleRate, "Correct sample rate for the output buffer");
|
||||
|
||||
compareBuffers(e.inputBuffer.getChannelData(0), buffer.getChannelData(0), 0, firstNonZero, 0, 2048 - firstNonZero);
|
||||
compareBuffers(e.inputBuffer.getChannelData(1), buffer.getChannelData(1), 0, firstNonZero, 0, 2048 - firstNonZero);
|
||||
compareBuffers(e.inputBuffer.getChannelData(0), emptyBuffer.getChannelData(0), firstNonZero);
|
||||
compareBuffers(e.inputBuffer.getChannelData(1), emptyBuffer.getChannelData(0), firstNonZero);
|
||||
compareBuffers(e.outputBuffer.getChannelData(0), emptyBuffer.getChannelData(0));
|
||||
compareBuffers(e.outputBuffer.getChannelData(1), emptyBuffer.getChannelData(0));
|
||||
|
||||
sp.onaudioprocess = null;
|
||||
|
||||
SpecialPowers.clearUserPref("media.webaudio.enabled");
|
||||
SimpleTest.finish();
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -22,3 +22,38 @@ function expectTypeError(func) {
|
||||
}
|
||||
ok(threw, "The exception was thrown");
|
||||
}
|
||||
|
||||
function fuzzyCompare(a, b) {
|
||||
return Math.abs(a - b) < 1e-5;
|
||||
}
|
||||
|
||||
function compareBuffers(buf1, buf2,
|
||||
/*optional*/ offset,
|
||||
/*optional*/ length,
|
||||
/*optional*/ sourceOffset,
|
||||
/*optional*/ destOffset) {
|
||||
is(buf1.length, buf2.length, "Buffers must have the same length");
|
||||
if (length == undefined) {
|
||||
length = buf1.length - (offset || 0);
|
||||
}
|
||||
sourceOffset = sourceOffset || 0;
|
||||
destOffset = destOffset || 0;
|
||||
var difference = 0;
|
||||
var maxDifference = 0;
|
||||
var firstBadIndex = -1;
|
||||
for (var i = offset || 0; i < Math.min(buf1.length, (offset || 0) + length); ++i) {
|
||||
if (!fuzzyCompare(buf1[i + sourceOffset], buf2[i + destOffset])) {
|
||||
console.log(buf1[i+sourceOffset] + " " + buf2[i+destOffset]);
|
||||
difference++;
|
||||
maxDifference = Math.max(maxDifference, Math.abs(buf1[i + sourceOffset] - buf2[i + destOffset]));
|
||||
if (firstBadIndex == -1) {
|
||||
firstBadIndex = i;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
is(difference, 0, "Found " + difference + " different samples, maxDifference: " +
|
||||
maxDifference + ", first bad index: " + firstBadIndex +
|
||||
" with source offset " + sourceOffset + " and desitnation offset " +
|
||||
destOffset);
|
||||
}
|
||||
|
@ -4,6 +4,8 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "DOMSVGStringList.h"
|
||||
|
||||
#include "mozilla/dom/SVGStringListBinding.h"
|
||||
#include "mozilla/dom/SVGTests.h"
|
||||
#include "nsError.h"
|
||||
#include "nsCOMPtr.h"
|
||||
@ -14,24 +16,15 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace dom;
|
||||
|
||||
static nsSVGAttrTearoffTable<SVGStringList, DOMSVGStringList>
|
||||
sSVGStringListTearoffTable;
|
||||
|
||||
NS_SVG_VAL_IMPL_CYCLE_COLLECTION(DOMSVGStringList, mElement)
|
||||
NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(DOMSVGStringList, mElement)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGStringList)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGStringList)
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
DOMCI_DATA(SVGStringList, mozilla::DOMSVGStringList)
|
||||
namespace mozilla {
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGStringList)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMSVGStringList)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGStringList)
|
||||
NS_INTERFACE_MAP_END
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMSVGStringList, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMSVGStringList, Release)
|
||||
|
||||
|
||||
/* static */ already_AddRefed<DOMSVGStringList>
|
||||
@ -57,23 +50,28 @@ DOMSVGStringList::~DOMSVGStringList()
|
||||
sSVGStringListTearoffTable.RemoveTearoff(&InternalList());
|
||||
}
|
||||
|
||||
/* virtual */ JSObject*
|
||||
DOMSVGStringList::WrapObject(JSContext* aCx, JSObject* aScope)
|
||||
{
|
||||
return SVGStringListBinding::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// nsIDOMSVGStringList implementation:
|
||||
// SVGStringList implementation:
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGStringList::GetNumberOfItems(uint32_t *aNumberOfItems)
|
||||
uint32_t
|
||||
DOMSVGStringList::NumberOfItems() const
|
||||
{
|
||||
*aNumberOfItems = InternalList().Length();
|
||||
return NS_OK;
|
||||
return InternalList().Length();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGStringList::GetLength(uint32_t *aLength)
|
||||
uint32_t
|
||||
DOMSVGStringList::Length() const
|
||||
{
|
||||
return GetNumberOfItems(aLength);
|
||||
return NumberOfItems();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
void
|
||||
DOMSVGStringList::Clear()
|
||||
{
|
||||
if (InternalList().IsExplicitlySet()) {
|
||||
@ -84,108 +82,117 @@ DOMSVGStringList::Clear()
|
||||
mElement->DidChangeStringList(mIsConditionalProcessingAttribute,
|
||||
mAttrEnum, emptyOrOldValue);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGStringList::Initialize(const nsAString & newItem, nsAString & _retval)
|
||||
void
|
||||
DOMSVGStringList::Initialize(const nsAString& aNewItem, nsAString& aRetval,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (InternalList().IsExplicitlySet()) {
|
||||
InternalList().Clear();
|
||||
}
|
||||
return InsertItemBefore(newItem, 0, _retval);
|
||||
InsertItemBefore(aNewItem, 0, aRetval, aRv);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGStringList::GetItem(uint32_t index,
|
||||
nsAString & _retval)
|
||||
void
|
||||
DOMSVGStringList::GetItem(uint32_t aIndex, nsAString& aRetval, ErrorResult& aRv)
|
||||
{
|
||||
if (index >= InternalList().Length()) {
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
bool found;
|
||||
IndexedGetter(aIndex, found, aRetval);
|
||||
if (!found) {
|
||||
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
|
||||
}
|
||||
_retval = InternalList()[index];
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGStringList::InsertItemBefore(const nsAString & newItem,
|
||||
uint32_t index,
|
||||
nsAString & _retval)
|
||||
void
|
||||
DOMSVGStringList::IndexedGetter(uint32_t aIndex, bool& aFound,
|
||||
nsAString& aRetval)
|
||||
{
|
||||
if (newItem.IsEmpty()) { // takes care of DOMStringIsNull too
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
aFound = aIndex < InternalList().Length();
|
||||
if (aFound) {
|
||||
aRetval = InternalList()[aIndex];
|
||||
}
|
||||
index = std::min(index, InternalList().Length());
|
||||
}
|
||||
|
||||
void
|
||||
DOMSVGStringList::InsertItemBefore(const nsAString& aNewItem, uint32_t aIndex,
|
||||
nsAString& aRetval, ErrorResult& aRv)
|
||||
{
|
||||
if (aNewItem.IsEmpty()) {
|
||||
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
||||
return;
|
||||
}
|
||||
aIndex = std::min(aIndex, InternalList().Length());
|
||||
|
||||
// Ensure we have enough memory so we can avoid complex error handling below:
|
||||
if (!InternalList().SetCapacity(InternalList().Length() + 1)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue =
|
||||
mElement->WillChangeStringList(mIsConditionalProcessingAttribute,
|
||||
mAttrEnum);
|
||||
InternalList().InsertItem(index, newItem);
|
||||
InternalList().InsertItem(aIndex, aNewItem);
|
||||
|
||||
mElement->DidChangeStringList(mIsConditionalProcessingAttribute, mAttrEnum,
|
||||
emptyOrOldValue);
|
||||
_retval = newItem;
|
||||
return NS_OK;
|
||||
aRetval = aNewItem;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGStringList::ReplaceItem(const nsAString & newItem,
|
||||
uint32_t index,
|
||||
nsAString & _retval)
|
||||
void
|
||||
DOMSVGStringList::ReplaceItem(const nsAString& aNewItem, uint32_t aIndex,
|
||||
nsAString& aRetval, ErrorResult& aRv)
|
||||
{
|
||||
if (newItem.IsEmpty()) { // takes care of DOMStringIsNull too
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
if (aNewItem.IsEmpty()) {
|
||||
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
||||
return;
|
||||
}
|
||||
if (index >= InternalList().Length()) {
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
if (aIndex >= InternalList().Length()) {
|
||||
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
_retval = InternalList()[index];
|
||||
aRetval = InternalList()[aIndex];
|
||||
nsAttrValue emptyOrOldValue =
|
||||
mElement->WillChangeStringList(mIsConditionalProcessingAttribute,
|
||||
mAttrEnum);
|
||||
InternalList().ReplaceItem(index, newItem);
|
||||
InternalList().ReplaceItem(aIndex, aNewItem);
|
||||
|
||||
mElement->DidChangeStringList(mIsConditionalProcessingAttribute, mAttrEnum,
|
||||
emptyOrOldValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGStringList::RemoveItem(uint32_t index,
|
||||
nsAString & _retval)
|
||||
void
|
||||
DOMSVGStringList::RemoveItem(uint32_t aIndex, nsAString& aRetval,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (index >= InternalList().Length()) {
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
if (aIndex >= InternalList().Length()) {
|
||||
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue =
|
||||
mElement->WillChangeStringList(mIsConditionalProcessingAttribute,
|
||||
mAttrEnum);
|
||||
InternalList().RemoveItem(index);
|
||||
InternalList().RemoveItem(aIndex);
|
||||
|
||||
mElement->DidChangeStringList(mIsConditionalProcessingAttribute, mAttrEnum,
|
||||
emptyOrOldValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGStringList::AppendItem(const nsAString & newItem,
|
||||
nsAString & _retval)
|
||||
void
|
||||
DOMSVGStringList::AppendItem(const nsAString& aNewItem, nsAString& aRetval,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
return InsertItemBefore(newItem, InternalList().Length(), _retval);
|
||||
InsertItemBefore(aNewItem, InternalList().Length(), aRetval, aRv);
|
||||
}
|
||||
|
||||
SVGStringList &
|
||||
DOMSVGStringList::InternalList()
|
||||
DOMSVGStringList::InternalList() const
|
||||
{
|
||||
if (mIsConditionalProcessingAttribute) {
|
||||
nsCOMPtr<dom::SVGTests> tests = do_QueryObject(mElement);
|
||||
nsCOMPtr<dom::SVGTests> tests = do_QueryObject(mElement.get());
|
||||
return tests->mStringListAttributes[mAttrEnum];
|
||||
}
|
||||
return mElement->GetStringListInfo().mStringLists[mAttrEnum];
|
||||
|
@ -9,12 +9,12 @@
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsIDOMSVGStringList.h"
|
||||
#include "nsSVGElement.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
class SVGStringList;
|
||||
|
||||
/**
|
||||
@ -43,12 +43,32 @@ class SVGStringList;
|
||||
* them so it can return the same objects each time. It simply returns a new
|
||||
* string each time any given item is requested.
|
||||
*/
|
||||
class DOMSVGStringList MOZ_FINAL : public nsIDOMSVGStringList
|
||||
class DOMSVGStringList MOZ_FINAL : public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(DOMSVGStringList)
|
||||
NS_DECL_NSIDOMSVGSTRINGLIST
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMSVGStringList)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DOMSVGStringList)
|
||||
|
||||
nsSVGElement* GetParentObject() const
|
||||
{
|
||||
return mElement;
|
||||
}
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope) MOZ_OVERRIDE;
|
||||
|
||||
uint32_t NumberOfItems() const;
|
||||
uint32_t Length() const;
|
||||
void Clear();
|
||||
void Initialize(const nsAString& aNewItem, nsAString& aRetval,
|
||||
ErrorResult& aRv);
|
||||
void GetItem(uint32_t aIndex, nsAString& aRetval, ErrorResult& aRv);
|
||||
void IndexedGetter(uint32_t aIndex, bool& aFound, nsAString& aRetval);
|
||||
void InsertItemBefore(const nsAString& aNewItem, uint32_t aIndex,
|
||||
nsAString& aRetval, ErrorResult& aRv);
|
||||
void ReplaceItem(const nsAString& aNewItem, uint32_t aIndex,
|
||||
nsAString& aRetval, ErrorResult& aRv);
|
||||
void RemoveItem(uint32_t aIndex, nsAString& aRetval, ErrorResult& aRv);
|
||||
void AppendItem(const nsAString& aNewItem, nsAString& aRetval,
|
||||
ErrorResult& aRv);
|
||||
|
||||
/**
|
||||
* Factory method to create and return a DOMSVGStringList wrapper
|
||||
@ -76,11 +96,13 @@ private:
|
||||
: mElement(aElement)
|
||||
, mAttrEnum(aAttrEnum)
|
||||
, mIsConditionalProcessingAttribute(aIsConditionalProcessingAttribute)
|
||||
{}
|
||||
{
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
~DOMSVGStringList();
|
||||
|
||||
SVGStringList &InternalList();
|
||||
SVGStringList &InternalList() const;
|
||||
|
||||
// Strong ref to our element to keep it alive.
|
||||
nsRefPtr<nsSVGElement> mElement;
|
||||
|
@ -28,7 +28,7 @@ SVGTests::SVGTests()
|
||||
mStringListAttributes[LANGUAGE].SetIsCommaSeparated(true);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMSVGStringList>
|
||||
already_AddRefed<DOMSVGStringList>
|
||||
SVGTests::RequiredFeatures()
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGElement> elem = do_QueryInterface(this);
|
||||
@ -37,7 +37,7 @@ SVGTests::RequiredFeatures()
|
||||
&mStringListAttributes[FEATURES], element, true, FEATURES).get();
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMSVGStringList>
|
||||
already_AddRefed<DOMSVGStringList>
|
||||
SVGTests::RequiredExtensions()
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGElement> elem = do_QueryInterface(this);
|
||||
@ -46,7 +46,7 @@ SVGTests::RequiredExtensions()
|
||||
&mStringListAttributes[EXTENSIONS], element, true, EXTENSIONS).get();
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMSVGStringList>
|
||||
already_AddRefed<DOMSVGStringList>
|
||||
SVGTests::SystemLanguage()
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGElement> elem = do_QueryInterface(this);
|
||||
|
@ -12,7 +12,6 @@
|
||||
|
||||
class nsAttrValue;
|
||||
class nsIAtom;
|
||||
class nsIDOMSVGStringList;
|
||||
class nsString;
|
||||
|
||||
namespace mozilla {
|
||||
@ -91,9 +90,9 @@ public:
|
||||
void MaybeInvalidate();
|
||||
|
||||
// WebIDL
|
||||
already_AddRefed<nsIDOMSVGStringList> RequiredFeatures();
|
||||
already_AddRefed<nsIDOMSVGStringList> RequiredExtensions();
|
||||
already_AddRefed<nsIDOMSVGStringList> SystemLanguage();
|
||||
already_AddRefed<DOMSVGStringList> RequiredFeatures();
|
||||
already_AddRefed<DOMSVGStringList> RequiredExtensions();
|
||||
already_AddRefed<DOMSVGStringList> SystemLanguage();
|
||||
bool HasExtension(const nsAString& aExtension);
|
||||
|
||||
private:
|
||||
|
@ -82,7 +82,7 @@ SVGViewElement::PreserveAspectRatio()
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
already_AddRefed<nsIDOMSVGStringList>
|
||||
already_AddRefed<DOMSVGStringList>
|
||||
SVGViewElement::ViewTarget()
|
||||
{
|
||||
return DOMSVGStringList::GetDOMWrapper(
|
||||
|
@ -19,7 +19,6 @@ static const unsigned short SVG_ZOOMANDPAN_MAGNIFY = 2;
|
||||
typedef nsSVGElement SVGViewElementBase;
|
||||
|
||||
class nsSVGOuterSVGFrame;
|
||||
class nsIDOMSVGStringList;
|
||||
|
||||
nsresult NS_NewSVGViewElement(nsIContent **aResult,
|
||||
already_AddRefed<nsINodeInfo> aNodeInfo);
|
||||
@ -49,7 +48,7 @@ public:
|
||||
void SetZoomAndPan(uint16_t aZoomAndPan, ErrorResult& rv);
|
||||
already_AddRefed<nsIDOMSVGAnimatedRect> ViewBox();
|
||||
already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> PreserveAspectRatio();
|
||||
already_AddRefed<nsIDOMSVGStringList> ViewTarget();
|
||||
already_AddRefed<DOMSVGStringList> ViewTarget();
|
||||
|
||||
private:
|
||||
|
||||
|
@ -75,25 +75,29 @@ function run_tests()
|
||||
is(strings.numberOfItems, 3, 'numberOfItems should be 3');
|
||||
|
||||
|
||||
ok(initializeThrowsFor(strings, null),
|
||||
"SVGStringList.initialize() should throw when passed null");
|
||||
ok(!initializeThrowsFor(strings, null),
|
||||
"SVGStringList.initialize() should not throw when passed null");
|
||||
ok(initializeThrowsFor(strings, ""),
|
||||
"SVGStringList.initialize() should throw when passed the empty string");
|
||||
is(strings.length, 0, 'length should be 0');
|
||||
|
||||
ok(insertItemBeforeThrowsFor(strings, null),
|
||||
"SVGStringList.insertItemBefore() should throw when passed null");
|
||||
ok(!insertItemBeforeThrowsFor(strings, null),
|
||||
"SVGStringList.insertItemBefore() should not throw when passed null");
|
||||
ok(insertItemBeforeThrowsFor(strings, ""),
|
||||
"SVGStringList.insertItemBefore() should throw when passed the empty string");
|
||||
is(strings.length, 1, 'length should be 1');
|
||||
|
||||
ok(replaceItemThrowsFor(strings, null),
|
||||
"SVGStringList.replaceItem() should throw when passed null");
|
||||
ok(!replaceItemThrowsFor(strings, null),
|
||||
"SVGStringList.replaceItem() should not throw when passed null");
|
||||
ok(replaceItemThrowsFor(strings, ""),
|
||||
"SVGStringList.replaceItem() should throw when passed the empty string");
|
||||
is(strings.length, 1, 'length should be 1');
|
||||
|
||||
ok(appendItemThrowsFor(strings, null),
|
||||
"SVGStringList.appendItem() should throw when passed null");
|
||||
ok(!appendItemThrowsFor(strings, null),
|
||||
"SVGStringList.appendItem() should not throw when passed null");
|
||||
ok(appendItemThrowsFor(strings, ""),
|
||||
"SVGStringList.appendItem() should throw when passed the empty string");
|
||||
is(strings.length, 2, 'length should be 2');
|
||||
|
||||
|
||||
// more sanity checks:
|
||||
|
@ -27,6 +27,8 @@
|
||||
#include "nsXULTemplateResultXML.h"
|
||||
#include "nsXULSortService.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsXMLQuery, nsXMLQuery)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@ -175,7 +177,7 @@ nsXULTemplateQueryProcessorXML::GetDatasource(nsIArray* aDataSources,
|
||||
do_CreateInstance(NS_XMLHTTPREQUEST_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = req->Init(docPrincipal, context,
|
||||
rv = req->Init(docPrincipal, context,
|
||||
scriptObject ? scriptObject : doc->GetScopeObject(),
|
||||
nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -184,7 +186,7 @@ nsXULTemplateQueryProcessorXML::GetDatasource(nsIArray* aDataSources,
|
||||
EmptyString(), EmptyString());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(req));
|
||||
nsCOMPtr<EventTarget> target(do_QueryInterface(req));
|
||||
rv = target->AddEventListener(NS_LITERAL_STRING("load"), this, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -1787,11 +1787,11 @@ NS_IMETHODIMP
|
||||
nsDocShell::SetChromeEventHandler(nsIDOMEventTarget* aChromeEventHandler)
|
||||
{
|
||||
// Weak reference. Don't addref.
|
||||
mChromeEventHandler = aChromeEventHandler;
|
||||
nsCOMPtr<EventTarget> handler = do_QueryInterface(aChromeEventHandler);
|
||||
mChromeEventHandler = handler.get();
|
||||
|
||||
if (mScriptGlobal) {
|
||||
mScriptGlobal->SetChromeEventHandler(handler);
|
||||
mScriptGlobal->SetChromeEventHandler(mChromeEventHandler);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -1801,8 +1801,8 @@ NS_IMETHODIMP
|
||||
nsDocShell::GetChromeEventHandler(nsIDOMEventTarget** aChromeEventHandler)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aChromeEventHandler);
|
||||
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mChromeEventHandler);
|
||||
target.swap(*aChromeEventHandler);
|
||||
nsCOMPtr<EventTarget> handler = mChromeEventHandler;
|
||||
handler.forget(aChromeEventHandler);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -9718,6 +9718,11 @@ nsDocShell::ScrollToAnchor(nsACString & aCurHash, nsACString & aNewHash,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIScrollableFrame* rootScroll = shell->GetRootScrollFrameAsScrollable();
|
||||
if (rootScroll) {
|
||||
rootScroll->ClearDidHistoryRestore();
|
||||
}
|
||||
|
||||
// If we have no new anchor, we do not want to scroll, unless there is a
|
||||
// current anchor and we are doing a history load. So return if we have no
|
||||
// new anchor, and there is no current anchor or the load is not a history
|
||||
|
@ -751,7 +751,7 @@ protected:
|
||||
// For that reasons don't use nsCOMPtr.
|
||||
|
||||
nsIDocShellTreeOwner * mTreeOwner; // Weak Reference
|
||||
nsIDOMEventTarget * mChromeEventHandler; //Weak Reference
|
||||
mozilla::dom::EventTarget* mChromeEventHandler; //Weak Reference
|
||||
|
||||
eCharsetReloadState mCharsetReloadState;
|
||||
|
||||
|
@ -515,6 +515,6 @@ AudioChannelService::GetInternalType(AudioChannelType aType,
|
||||
break;
|
||||
}
|
||||
|
||||
MOZ_NOT_REACHED();
|
||||
MOZ_NOT_REACHED("unexpected audio channel type");
|
||||
return AUDIO_CHANNEL_INT_LAST;
|
||||
}
|
||||
|
@ -23,9 +23,7 @@ LIBRARY_NAME = domaudiochannel_s
|
||||
LIBXUL_LIBRARY = 1
|
||||
FORCE_STATIC_LIB = 1
|
||||
EXPORT_LIBRARY = 1
|
||||
ifndef _MSC_VER
|
||||
FAIL_ON_WARNINGS := 1
|
||||
endif # !_MSC_VER
|
||||
|
||||
CPPSRCS += \
|
||||
AudioChannelService.cpp \
|
||||
|
@ -12,9 +12,7 @@ include $(DEPTH)/config/autoconf.mk
|
||||
LIBRARY_NAME = jsdombase_s
|
||||
LIBXUL_LIBRARY = 1
|
||||
FORCE_STATIC_LIB = 1
|
||||
ifndef _MSC_VER
|
||||
FAIL_ON_WARNINGS := 1
|
||||
endif # !_MSC_VER
|
||||
|
||||
EXTRA_COMPONENTS = \
|
||||
SiteSpecificUserAgent.js \
|
||||
|
@ -660,16 +660,10 @@ StaticRefPtr<VibrateWindowListener> gVibrateWindowListener;
|
||||
NS_IMETHODIMP
|
||||
VibrateWindowListener::HandleEvent(nsIDOMEvent* aEvent)
|
||||
{
|
||||
nsCOMPtr<nsIDOMEventTarget> target;
|
||||
aEvent->GetTarget(getter_AddRefs(target));
|
||||
nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(target);
|
||||
nsCOMPtr<nsIDocument> doc =
|
||||
do_QueryInterface(aEvent->InternalDOMEvent()->GetTarget());
|
||||
|
||||
bool hidden = true;
|
||||
if (doc) {
|
||||
doc->GetHidden(&hidden);
|
||||
}
|
||||
|
||||
if (hidden) {
|
||||
if (!doc || doc->Hidden()) {
|
||||
// It's important that we call CancelVibrate(), not Vibrate() with an
|
||||
// empty list, because Vibrate() will fail if we're no longer focused, but
|
||||
// CancelVibrate() will succeed, so long as nobody else has started a new
|
||||
@ -687,7 +681,7 @@ VibrateWindowListener::HandleEvent(nsIDOMEvent* aEvent)
|
||||
void
|
||||
VibrateWindowListener::RemoveListener()
|
||||
{
|
||||
nsCOMPtr<nsIDOMEventTarget> target = do_QueryReferent(mDocument);
|
||||
nsCOMPtr<EventTarget> target = do_QueryReferent(mDocument);
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
@ -268,8 +268,6 @@
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "HTMLLegendElement.h"
|
||||
|
||||
#include "DOMSVGStringList.h"
|
||||
|
||||
#include "mozilla/dom/indexedDB/IDBWrapperCache.h"
|
||||
#include "mozilla/dom/indexedDB/IDBFileHandle.h"
|
||||
#include "mozilla/dom/indexedDB/IDBRequest.h"
|
||||
@ -690,9 +688,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
||||
#ifdef MOZ_XUL
|
||||
NS_DEFINE_CLASSINFO_DATA(TreeColumn, nsDOMGenericSH,
|
||||
DEFAULT_SCRIPTABLE_FLAGS)
|
||||
|
||||
NS_DEFINE_CLASSINFO_DATA(TreeColumns, nsTreeColumnsSH,
|
||||
ARRAY_SCRIPTABLE_FLAGS)
|
||||
#endif
|
||||
|
||||
NS_DEFINE_CLASSINFO_DATA(CSSMozDocumentRule, nsDOMGenericSH,
|
||||
@ -724,8 +719,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(SVGRect, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(SVGStringList, nsSVGStringListSH,
|
||||
ARRAY_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(SVGZoomEvent, nsEventSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
|
||||
@ -893,8 +886,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
||||
NS_DEFINE_CLASSINFO_DATA(IDBOpenDBRequest, IDBEventTargetSH,
|
||||
IDBEVENTTARGET_SCRIPTABLE_FLAGS)
|
||||
|
||||
NS_DEFINE_CLASSINFO_DATA(Touch, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(TouchList, nsDOMTouchListSH,
|
||||
ARRAY_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(TouchEvent, nsEventSH,
|
||||
@ -1952,10 +1943,6 @@ nsDOMClassInfo::Init()
|
||||
DOM_CLASSINFO_MAP_BEGIN(TreeColumn, nsITreeColumn)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsITreeColumn)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(TreeColumns, nsITreeColumns)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsITreeColumns)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
#endif
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(CSSMozDocumentRule, nsIDOMCSSMozDocumentRule)
|
||||
@ -2011,10 +1998,6 @@ nsDOMClassInfo::Init()
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGRect)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(SVGStringList, nsIDOMSVGStringList)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGStringList)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(SVGZoomEvent, nsIDOMSVGZoomEvent)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGZoomEvent)
|
||||
DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES
|
||||
@ -2287,11 +2270,6 @@ nsDOMClassInfo::Init()
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN_MAYBE_DISABLE(Touch, nsIDOMTouch,
|
||||
!nsDOMTouchEvent::PrefEnabled())
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMTouch)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN_MAYBE_DISABLE(TouchList, nsIDOMTouchList,
|
||||
!nsDOMTouchEvent::PrefEnabled())
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMTouchList)
|
||||
@ -7224,30 +7202,6 @@ nsCSSRuleListSH::GetItemAt(nsISupports *aNative, uint32_t aIndex,
|
||||
return list->GetItemAt(aIndex, aResult);
|
||||
}
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
// TreeColumns helper
|
||||
|
||||
nsISupports*
|
||||
nsTreeColumnsSH::GetItemAt(nsISupports *aNative, uint32_t aIndex,
|
||||
nsWrapperCache **aCache, nsresult *aResult)
|
||||
{
|
||||
nsTreeColumns* columns = nsTreeColumns::FromSupports(aNative);
|
||||
|
||||
return columns->GetColumnAt(aIndex);
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
nsTreeColumnsSH::GetNamedItem(nsISupports *aNative,
|
||||
const nsAString& aName,
|
||||
nsWrapperCache **aCache,
|
||||
nsresult *aResult)
|
||||
{
|
||||
nsTreeColumns* columns = nsTreeColumns::FromSupports(aNative);
|
||||
|
||||
return columns->GetNamedColumn(aName);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Storage2SH
|
||||
|
||||
@ -7478,9 +7432,8 @@ nsEventListenerThisTranslator::TranslateThis(nsISupports *aInitialThis,
|
||||
nsCOMPtr<nsIDOMEvent> event(do_QueryInterface(aInitialThis));
|
||||
NS_ENSURE_TRUE(event, NS_ERROR_UNEXPECTED);
|
||||
|
||||
nsCOMPtr<nsIDOMEventTarget> target;
|
||||
event->GetCurrentTarget(getter_AddRefs(target));
|
||||
target.forget(_retval);
|
||||
nsCOMPtr<EventTarget> target = event->InternalDOMEvent()->GetCurrentTarget();
|
||||
*_retval = target.forget().get();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -7630,42 +7583,3 @@ nsOfflineResourceListSH::GetStringAt(nsISupports *aNative, int32_t aIndex,
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
||||
// SVGStringList helper
|
||||
|
||||
nsresult
|
||||
nsSVGStringListSH::GetStringAt(nsISupports *aNative, int32_t aIndex,
|
||||
nsAString& aResult)
|
||||
{
|
||||
if (aIndex < 0) {
|
||||
SetDOMStringToNull(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
DOMSVGStringList* list = static_cast<DOMSVGStringList*>(
|
||||
static_cast<nsIDOMSVGStringList*>(aNative));
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGStringList> list_qi = do_QueryInterface(aNative);
|
||||
|
||||
// If this assertion fires the QI implementation for the object in
|
||||
// question doesn't use the nsIDOMDOMSVGStringList pointer as the
|
||||
// nsISupports pointer. That must be fixed, or we'll crash...
|
||||
NS_ABORT_IF_FALSE(list_qi == list, "Uh, fix QI!");
|
||||
}
|
||||
#endif
|
||||
|
||||
nsresult rv = list->GetItem(aIndex, aResult);
|
||||
#ifdef DEBUG
|
||||
if (DOMStringIsNull(aResult)) {
|
||||
uint32_t length = 0;
|
||||
list->GetLength(&length);
|
||||
NS_ASSERTION(uint32_t(aIndex) >= length, "Item should only return null for out-of-bounds access");
|
||||
}
|
||||
#endif
|
||||
if (rv == NS_ERROR_DOM_INDEX_SIZE_ERR) {
|
||||
SetDOMStringToNull(aResult);
|
||||
rv = NS_OK;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
@ -989,37 +989,6 @@ class nsDOMTouchListSH : public nsArraySH
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
// TreeColumns helper
|
||||
|
||||
class nsTreeColumnsSH : public nsNamedArraySH
|
||||
{
|
||||
protected:
|
||||
nsTreeColumnsSH(nsDOMClassInfoData* aData) : nsNamedArraySH(aData)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~nsTreeColumnsSH()
|
||||
{
|
||||
}
|
||||
|
||||
virtual nsISupports* GetItemAt(nsISupports *aNative, uint32_t aIndex,
|
||||
nsWrapperCache **aCache, nsresult *aResult);
|
||||
|
||||
// Override nsNamedArraySH::GetNamedItem()
|
||||
virtual nsISupports* GetNamedItem(nsISupports *aNative,
|
||||
const nsAString& aName,
|
||||
nsWrapperCache **cache,
|
||||
nsresult *aResult);
|
||||
|
||||
public:
|
||||
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
|
||||
{
|
||||
return new nsTreeColumnsSH(aData);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
// WebApps Storage helpers
|
||||
|
||||
class nsStorage2SH : public nsDOMGenericSH
|
||||
@ -1175,27 +1144,4 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// SVGStringList helper
|
||||
|
||||
class nsSVGStringListSH : public nsStringArraySH
|
||||
{
|
||||
protected:
|
||||
nsSVGStringListSH(nsDOMClassInfoData* aData) : nsStringArraySH(aData)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~nsSVGStringListSH()
|
||||
{
|
||||
}
|
||||
|
||||
virtual nsresult GetStringAt(nsISupports *aNative, int32_t aIndex,
|
||||
nsAString& aResult);
|
||||
|
||||
public:
|
||||
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
|
||||
{
|
||||
return new nsSVGStringListSH(aData);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* nsDOMClassInfo_h___ */
|
||||
|
@ -96,7 +96,6 @@ DOMCI_CLASS(DOMStringList)
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
DOMCI_CLASS(TreeColumn)
|
||||
DOMCI_CLASS(TreeColumns)
|
||||
#endif
|
||||
|
||||
DOMCI_CLASS(CSSMozDocumentRule)
|
||||
@ -115,7 +114,6 @@ DOMCI_CLASS(SVGAnimatedString)
|
||||
DOMCI_CLASS(SVGLength)
|
||||
DOMCI_CLASS(SVGNumber)
|
||||
DOMCI_CLASS(SVGRect)
|
||||
DOMCI_CLASS(SVGStringList)
|
||||
DOMCI_CLASS(SVGZoomEvent)
|
||||
|
||||
// Canvas
|
||||
@ -212,7 +210,6 @@ DOMCI_CLASS(IDBIndex)
|
||||
DOMCI_CLASS(IDBVersionChangeEvent)
|
||||
DOMCI_CLASS(IDBOpenDBRequest)
|
||||
|
||||
DOMCI_CLASS(Touch)
|
||||
DOMCI_CLASS(TouchList)
|
||||
DOMCI_CLASS(TouchEvent)
|
||||
|
||||
|
@ -104,7 +104,7 @@ struct nsDelayedBlurOrFocusEvent
|
||||
nsDelayedBlurOrFocusEvent(uint32_t aType,
|
||||
nsIPresShell* aPresShell,
|
||||
nsIDocument* aDocument,
|
||||
nsIDOMEventTarget* aTarget)
|
||||
EventTarget* aTarget)
|
||||
: mType(aType),
|
||||
mPresShell(aPresShell),
|
||||
mDocument(aDocument),
|
||||
@ -119,7 +119,7 @@ struct nsDelayedBlurOrFocusEvent
|
||||
uint32_t mType;
|
||||
nsCOMPtr<nsIPresShell> mPresShell;
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
nsCOMPtr<nsIDOMEventTarget> mTarget;
|
||||
nsCOMPtr<EventTarget> mTarget;
|
||||
};
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFocusManager)
|
||||
@ -999,7 +999,7 @@ nsFocusManager::FireDelayedEvents(nsIDocument* aDocument)
|
||||
if (mDelayedBlurFocusEvents[i].mDocument == aDocument &&
|
||||
!aDocument->EventHandlingSuppressed()) {
|
||||
uint32_t type = mDelayedBlurFocusEvents[i].mType;
|
||||
nsCOMPtr<nsIDOMEventTarget> target = mDelayedBlurFocusEvents[i].mTarget;
|
||||
nsCOMPtr<EventTarget> target = mDelayedBlurFocusEvents[i].mTarget;
|
||||
nsCOMPtr<nsIPresShell> presShell = mDelayedBlurFocusEvents[i].mPresShell;
|
||||
mDelayedBlurFocusEvents.RemoveElementAt(i);
|
||||
SendFocusOrBlurEvent(type, presShell, aDocument, target, 0, false);
|
||||
@ -1900,7 +1900,7 @@ nsFocusManager::SendFocusOrBlurEvent(uint32_t aType,
|
||||
NS_ASSERTION(aType == NS_FOCUS_CONTENT || aType == NS_BLUR_CONTENT,
|
||||
"Wrong event type for SendFocusOrBlurEvent");
|
||||
|
||||
nsCOMPtr<nsIDOMEventTarget> eventTarget = do_QueryInterface(aTarget);
|
||||
nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aTarget);
|
||||
|
||||
// for focus events, if this event was from a mouse or key and event
|
||||
// handling on the document is suppressed, queue the event and fire it
|
||||
|
@ -2587,7 +2587,6 @@ void
|
||||
nsGlobalWindow::ClearStatus()
|
||||
{
|
||||
SetStatus(EmptyString());
|
||||
SetDefaultStatus(EmptyString());
|
||||
}
|
||||
|
||||
void
|
||||
@ -3893,17 +3892,17 @@ nsGlobalWindow::SetStatus(const nsAString& aStatus)
|
||||
{
|
||||
FORWARD_TO_OUTER(SetStatus, (aStatus), NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
mStatus = aStatus;
|
||||
|
||||
/*
|
||||
* If caller is not chrome and dom.disable_window_status_change is true,
|
||||
* prevent setting window.status by exiting early
|
||||
* prevent propagating window.status to the UI by exiting early
|
||||
*/
|
||||
|
||||
if (!CanSetProperty("dom.disable_window_status_change")) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mStatus = aStatus;
|
||||
|
||||
nsCOMPtr<nsIWebBrowserChrome> browserChrome;
|
||||
GetWebBrowserChrome(getter_AddRefs(browserChrome));
|
||||
if(browserChrome) {
|
||||
@ -3914,43 +3913,6 @@ nsGlobalWindow::SetStatus(const nsAString& aStatus)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGlobalWindow::GetDefaultStatus(nsAString& aDefaultStatus)
|
||||
{
|
||||
FORWARD_TO_OUTER(GetDefaultStatus, (aDefaultStatus),
|
||||
NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
aDefaultStatus = mDefaultStatus;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGlobalWindow::SetDefaultStatus(const nsAString& aDefaultStatus)
|
||||
{
|
||||
FORWARD_TO_OUTER(SetDefaultStatus, (aDefaultStatus),
|
||||
NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
/*
|
||||
* If caller is not chrome and dom.disable_window_status_change is true,
|
||||
* prevent setting window.defaultStatus by exiting early
|
||||
*/
|
||||
|
||||
if (!CanSetProperty("dom.disable_window_status_change")) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mDefaultStatus = aDefaultStatus;
|
||||
|
||||
nsCOMPtr<nsIWebBrowserChrome> browserChrome;
|
||||
GetWebBrowserChrome(getter_AddRefs(browserChrome));
|
||||
if (browserChrome) {
|
||||
browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT_DEFAULT,
|
||||
PromiseFlatString(aDefaultStatus).get());
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGlobalWindow::GetName(nsAString& aName)
|
||||
{
|
||||
@ -8071,7 +8033,7 @@ nsGlobalWindow::GetListenerManager(bool aCreateIfNotFound)
|
||||
|
||||
if (!mListenerManager && aCreateIfNotFound) {
|
||||
mListenerManager =
|
||||
new nsEventListenerManager(static_cast<nsIDOMEventTarget*>(this));
|
||||
new nsEventListenerManager(static_cast<EventTarget*>(this));
|
||||
}
|
||||
|
||||
return mListenerManager;
|
||||
@ -8685,7 +8647,7 @@ nsGlobalWindow::DispatchSyncPopState()
|
||||
|
||||
domEvent->SetTrusted(true);
|
||||
|
||||
nsCOMPtr<nsIDOMEventTarget> outerWindow =
|
||||
nsCOMPtr<EventTarget> outerWindow =
|
||||
do_QueryInterface(GetOuterWindow());
|
||||
NS_ENSURE_TRUE(outerWindow, NS_ERROR_UNEXPECTED);
|
||||
|
||||
@ -8995,18 +8957,36 @@ nsGlobalWindow::GetIndexedDB(nsISupports** _retval)
|
||||
}
|
||||
|
||||
if (!IsChromeWindow()) {
|
||||
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
|
||||
do_GetService(THIRDPARTYUTIL_CONTRACTID);
|
||||
NS_ENSURE_TRUE(thirdPartyUtil, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
// Whitelist about:home, since it doesn't have a base domain it would not
|
||||
// pass the thirdPartyUtil check, though it should be able to use
|
||||
// indexedDB.
|
||||
bool skipThirdPartyCheck = false;
|
||||
nsIPrincipal *principal = GetPrincipal();
|
||||
if (principal) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
principal->GetURI(getter_AddRefs(uri));
|
||||
bool isAbout = false;
|
||||
if (uri && NS_SUCCEEDED(uri->SchemeIs("about", &isAbout)) && isAbout) {
|
||||
nsAutoCString path;
|
||||
skipThirdPartyCheck = NS_SUCCEEDED(uri->GetPath(path)) &&
|
||||
path.EqualsLiteral("home");
|
||||
}
|
||||
}
|
||||
|
||||
bool isThirdParty;
|
||||
rv = thirdPartyUtil->IsThirdPartyWindow(this, nullptr, &isThirdParty);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
if (!skipThirdPartyCheck) {
|
||||
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
|
||||
do_GetService(THIRDPARTYUTIL_CONTRACTID);
|
||||
NS_ENSURE_TRUE(thirdPartyUtil, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
if (isThirdParty) {
|
||||
NS_WARNING("IndexedDB is not permitted in a third-party window.");
|
||||
*_retval = nullptr;
|
||||
return NS_OK;
|
||||
bool isThirdParty;
|
||||
rv = thirdPartyUtil->IsThirdPartyWindow(this, nullptr, &isThirdParty);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
if (isThirdParty) {
|
||||
NS_WARNING("IndexedDB is not permitted in a third-party window.");
|
||||
*_retval = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ nsScreen::Reset()
|
||||
hal::UnlockScreenOrientation();
|
||||
|
||||
if (mEventListener) {
|
||||
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetOwner());
|
||||
nsCOMPtr<EventTarget> target = do_QueryInterface(GetOwner());
|
||||
if (target) {
|
||||
target->RemoveSystemEventListener(NS_LITERAL_STRING("mozfullscreenchange"),
|
||||
mEventListener, /* usecapture */ true);
|
||||
@ -368,7 +368,7 @@ nsScreen::MozLockOrientation(const Sequence<nsString>& aOrientations,
|
||||
// and when we will have to unlock the screen.
|
||||
// This needs to be done before LockScreenOrientation call to make sure
|
||||
// the locking can be unlocked.
|
||||
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetOwner());
|
||||
nsCOMPtr<EventTarget> target = do_QueryInterface(GetOwner());
|
||||
if (!target) {
|
||||
return false;
|
||||
}
|
||||
@ -390,7 +390,7 @@ nsScreen::MozLockOrientation(const Sequence<nsString>& aOrientations,
|
||||
|
||||
// This is only for compilers that don't understand that the previous switch
|
||||
// will always return.
|
||||
MOZ_NOT_REACHED();
|
||||
MOZ_NOT_REACHED("unexpected lock orientation permission value");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -426,8 +426,7 @@ nsScreen::FullScreenEventListener::HandleEvent(nsIDOMEvent* aEvent)
|
||||
MOZ_ASSERT(eventType.EqualsLiteral("mozfullscreenchange"));
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIDOMEventTarget> target;
|
||||
aEvent->GetCurrentTarget(getter_AddRefs(target));
|
||||
nsCOMPtr<EventTarget> target = aEvent->InternalDOMEvent()->GetCurrentTarget();
|
||||
|
||||
// We have to make sure that the event we got is the event sent when
|
||||
// fullscreen is disabled because we could get one when fullscreen
|
||||
|
@ -78,7 +78,7 @@ nsWindowRoot::DispatchEvent(nsIDOMEvent* aEvt, bool *aRetVal)
|
||||
{
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
nsresult rv = nsEventDispatcher::DispatchDOMEvent(
|
||||
static_cast<nsIDOMEventTarget*>(this), nullptr, aEvt, nullptr, &status);
|
||||
static_cast<EventTarget*>(this), nullptr, aEvt, nullptr, &status);
|
||||
*aRetVal = (status != nsEventStatus_eConsumeNoDefault);
|
||||
return rv;
|
||||
}
|
||||
@ -89,7 +89,7 @@ nsWindowRoot::DispatchDOMEvent(nsEvent* aEvent,
|
||||
nsPresContext* aPresContext,
|
||||
nsEventStatus* aEventStatus)
|
||||
{
|
||||
return nsEventDispatcher::DispatchDOMEvent(static_cast<nsIDOMEventTarget*>(this),
|
||||
return nsEventDispatcher::DispatchDOMEvent(static_cast<EventTarget*>(this),
|
||||
aEvent, aDOMEvent,
|
||||
aPresContext, aEventStatus);
|
||||
}
|
||||
@ -149,7 +149,7 @@ nsWindowRoot::GetListenerManager(bool aCreateIfNotFound)
|
||||
{
|
||||
if (!mListenerManager && aCreateIfNotFound) {
|
||||
mListenerManager =
|
||||
new nsEventListenerManager(static_cast<nsIDOMEventTarget*>(this));
|
||||
new nsEventListenerManager(static_cast<EventTarget*>(this));
|
||||
}
|
||||
|
||||
return mListenerManager;
|
||||
|
@ -28,6 +28,7 @@ MOCHITEST_FILES = \
|
||||
test_writable-replaceable.html \
|
||||
test_domcursor.html \
|
||||
test_named_frames.html \
|
||||
test_Image_constructor.html \
|
||||
$(NULL)
|
||||
|
||||
MOCHITEST_CHROME_FILES = \
|
||||
|
32
dom/base/test/test_Image_constructor.html
Normal file
32
dom/base/test/test_Image_constructor.html
Normal file
@ -0,0 +1,32 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=862702
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- Make sure our script runs before anything else -->
|
||||
<script>
|
||||
var img = new Image;
|
||||
</script>
|
||||
<title>Test for Bug 862702</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 862702 **/
|
||||
is(Object.getPrototypeOf(img), HTMLImageElement.prototype,
|
||||
"Wrong prototype object");
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=862702">Mozilla Bug 862702</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -630,6 +630,10 @@ WrapNewBindingNonWrapperCachedObject(JSContext* cx, JSObject* scope, T* value,
|
||||
obj = value->WrapObject(cx, scope);
|
||||
}
|
||||
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We can end up here in all sorts of compartments, per above. Make
|
||||
// sure to JS_WrapValue!
|
||||
*vp = JS::ObjectValue(*obj);
|
||||
@ -660,11 +664,18 @@ WrapNewBindingNonWrapperCachedOwnedObject(JSContext* cx, JSObject* scope,
|
||||
|
||||
bool tookOwnership = false;
|
||||
obj = value->WrapObject(cx, scope, &tookOwnership);
|
||||
if (obj) {
|
||||
MOZ_ASSERT(tookOwnership);
|
||||
}
|
||||
if (tookOwnership) {
|
||||
value.forget();
|
||||
}
|
||||
}
|
||||
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We can end up here in all sorts of compartments, per above. Make
|
||||
// sure to JS_WrapValue!
|
||||
*vp = JS::ObjectValue(*obj);
|
||||
@ -1734,6 +1745,15 @@ InterfaceHasInstance(JSContext* cx, JSHandleObject obj, JSMutableHandleValue vp,
|
||||
void
|
||||
ReportLenientThisUnwrappingFailure(JSContext* cx, JS::Handle<JSObject*> obj);
|
||||
|
||||
inline JSObject*
|
||||
GetUnforgeableHolder(JSObject* aGlobal, prototypes::ID aId)
|
||||
{
|
||||
JSObject** protoAndIfaceArray = GetProtoAndIfaceArray(aGlobal);
|
||||
JSObject* interfaceProto = protoAndIfaceArray[aId];
|
||||
return &js::GetReservedSlot(interfaceProto,
|
||||
DOM_INTERFACE_PROTO_SLOTS_BASE).toObject();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -122,6 +122,10 @@ DOMInterfaces = {
|
||||
'nativeOwnership': 'refcounted'
|
||||
},
|
||||
|
||||
'AudioProcessingEvent' : {
|
||||
'resultNotAddRefed': [ 'inputBuffer', 'outputBuffer' ],
|
||||
},
|
||||
|
||||
'BeforeUnloadEvent': {
|
||||
'nativeType': 'nsDOMBeforeUnloadEvent',
|
||||
},
|
||||
@ -557,6 +561,10 @@ DOMInterfaces = {
|
||||
'workers': True,
|
||||
}],
|
||||
|
||||
'KeyEvent': {
|
||||
'nativeType': 'nsDOMKeyboardEvent',
|
||||
},
|
||||
|
||||
'Location': {
|
||||
# NOTE: Before you turn on codegen for Location, make sure all the
|
||||
# Unforgeable stuff is dealt with.
|
||||
@ -960,6 +968,12 @@ DOMInterfaces = {
|
||||
'resultNotAddRefed': [ 'getItem' ]
|
||||
},
|
||||
|
||||
'SVGStringList': {
|
||||
'nativeType': 'mozilla::DOMSVGStringList',
|
||||
'headerFile': 'DOMSVGStringList.h',
|
||||
'nativeOwnership': 'refcounted',
|
||||
},
|
||||
|
||||
'SVGSVGElement': {
|
||||
'resultNotAddRefed': [ 'getElementById' ]
|
||||
},
|
||||
@ -1013,6 +1027,10 @@ DOMInterfaces = {
|
||||
'nativeType': 'nsDOMTransitionEvent',
|
||||
},
|
||||
|
||||
'TreeColumns': {
|
||||
'nativeType': 'nsTreeColumns',
|
||||
},
|
||||
|
||||
'TreeWalker': {
|
||||
'wrapperCache': False,
|
||||
'resultNotAddRefed': [ 'root', 'currentNode' ],
|
||||
@ -1506,6 +1524,10 @@ addExternalIface('MozObserver', nativeType='nsIObserver', notflattened=True)
|
||||
addExternalIface('MozRDFCompositeDataSource', nativeType='nsIRDFCompositeDataSource',
|
||||
notflattened=True)
|
||||
addExternalIface('MozRDFResource', nativeType='nsIRDFResource', notflattened=True)
|
||||
addExternalIface('MozTreeBoxObject', nativeType='nsITreeBoxObject',
|
||||
notflattened=True)
|
||||
addExternalIface('MozTreeColumn', nativeType='nsITreeColumn',
|
||||
headerFile='nsITreeColumns.h')
|
||||
addExternalIface('MozXULTemplateBuilder', nativeType='nsIXULTemplateBuilder')
|
||||
addExternalIface('MozNamedAttrMap')
|
||||
addExternalIface('nsIControllers', nativeType='nsIControllers')
|
||||
@ -1528,7 +1550,6 @@ addExternalIface('SVGAnimatedNumber')
|
||||
addExternalIface('SVGAnimatedString')
|
||||
addExternalIface('SVGLength')
|
||||
addExternalIface('SVGNumber')
|
||||
addExternalIface('Touch', headerFile='nsIDOMTouchEvent.h')
|
||||
addExternalIface('TouchList', headerFile='nsIDOMTouchEvent.h')
|
||||
addExternalIface('URI', nativeType='nsIURI', headerFile='nsIURI.h',
|
||||
notflattened=True)
|
||||
|
@ -209,6 +209,45 @@ def PrototypeIDAndDepth(descriptor):
|
||||
depth = "0"
|
||||
return (prototypeID, depth)
|
||||
|
||||
def UseHolderForUnforgeable(descriptor):
|
||||
return (descriptor.concrete and
|
||||
descriptor.proxy and
|
||||
any(m for m in descriptor.interface.members if m.isAttr() and m.isUnforgeable()))
|
||||
|
||||
def CallOnUnforgeableHolder(descriptor, code, isXrayCheck=None):
|
||||
"""
|
||||
Generate the code to execute the code in "code" on an unforgeable holder if
|
||||
needed. code should be a string containing the code to execute. If it
|
||||
contains a ${holder} string parameter it will be replaced with the
|
||||
unforgeable holder object.
|
||||
|
||||
If isXrayCheck is not None it should be a string that contains a statement
|
||||
returning whether proxy is an Xray. If isXrayCheck is None the generated
|
||||
code won't try to unwrap Xrays.
|
||||
"""
|
||||
code = string.Template(code).substitute({ "holder": "unforgeableHolder" })
|
||||
if not isXrayCheck is None:
|
||||
pre = """// Scope for 'global', 'ac' and 'unforgeableHolder'
|
||||
{
|
||||
JSObject* global;
|
||||
Maybe<JSAutoCompartment> ac;
|
||||
if (""" + isXrayCheck + """) {
|
||||
global = js::GetGlobalForObjectCrossCompartment(js::UncheckedUnwrap(proxy));
|
||||
ac.construct(cx, global);
|
||||
} else {
|
||||
global = js::GetGlobalForObjectCrossCompartment(proxy);
|
||||
}"""
|
||||
else:
|
||||
pre = """// Scope for 'global' and 'unforgeableHolder'
|
||||
{
|
||||
JSObject* global = js::GetGlobalForObjectCrossCompartment(proxy);"""
|
||||
|
||||
return (pre + """
|
||||
JSObject* unforgeableHolder = GetUnforgeableHolder(global, prototypes::id::%s);
|
||||
""" + CGIndenter(CGGeneric(code)).define() + """
|
||||
}
|
||||
""") % descriptor.name
|
||||
|
||||
class CGPrototypeJSClass(CGThing):
|
||||
def __init__(self, descriptor, properties):
|
||||
CGThing.__init__(self)
|
||||
@ -219,10 +258,13 @@ class CGPrototypeJSClass(CGThing):
|
||||
return ""
|
||||
def define(self):
|
||||
(prototypeID, depth) = PrototypeIDAndDepth(self.descriptor)
|
||||
slotCount = "DOM_INTERFACE_PROTO_SLOTS_BASE"
|
||||
if UseHolderForUnforgeable(self.descriptor):
|
||||
slotCount += " + 1 /* slot for the JSObject holding the unforgeable properties */"
|
||||
return """static DOMIfaceAndProtoJSClass PrototypeClass = {
|
||||
{
|
||||
"%sPrototype",
|
||||
JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(2),
|
||||
JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(%s),
|
||||
JS_PropertyStub, /* addProperty */
|
||||
JS_DeletePropertyStub, /* delProperty */
|
||||
JS_PropertyStub, /* getProperty */
|
||||
@ -244,7 +286,7 @@ class CGPrototypeJSClass(CGThing):
|
||||
%s,
|
||||
%s
|
||||
};
|
||||
""" % (self.descriptor.interface.identifier.name,
|
||||
""" % (self.descriptor.interface.identifier.name, slotCount,
|
||||
NativePropertyHooks(self.descriptor),
|
||||
self.descriptor.interface.identifier.name,
|
||||
prototypeID, depth)
|
||||
@ -272,11 +314,15 @@ class CGInterfaceObjectJSClass(CGThing):
|
||||
else:
|
||||
hasinstance = "nullptr"
|
||||
(prototypeID, depth) = PrototypeIDAndDepth(self.descriptor)
|
||||
slotCount = "DOM_INTERFACE_SLOTS_BASE"
|
||||
if len(self.descriptor.interface.namedConstructors) > 0:
|
||||
slotCount += (" + %i /* slots for the named constructors */" %
|
||||
len(self.descriptor.interface.namedConstructors))
|
||||
return """
|
||||
static DOMIfaceAndProtoJSClass InterfaceObjectClass = {
|
||||
{
|
||||
"Function",
|
||||
JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_SLOTS_BASE + %i),
|
||||
JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(%s),
|
||||
JS_PropertyStub, /* addProperty */
|
||||
JS_DeletePropertyStub, /* delProperty */
|
||||
JS_PropertyStub, /* getProperty */
|
||||
@ -298,7 +344,7 @@ static DOMIfaceAndProtoJSClass InterfaceObjectClass = {
|
||||
%s,
|
||||
%s
|
||||
};
|
||||
""" % (len(self.descriptor.interface.namedConstructors), ctorname,
|
||||
""" % (slotCount, ctorname,
|
||||
hasinstance, ctorname, NativePropertyHooks(self.descriptor),
|
||||
self.descriptor.interface.identifier.name,
|
||||
prototypeID, depth)
|
||||
@ -419,6 +465,12 @@ class CGIfWrapper(CGWrapper):
|
||||
CGWrapper.__init__(self, CGIndenter(child), pre=pre.define(),
|
||||
post="\n}")
|
||||
|
||||
class CGIfElseWrapper(CGList):
|
||||
def __init__(self, condition, ifTrue, ifFalse):
|
||||
kids = [ CGIfWrapper(ifTrue, condition),
|
||||
CGWrapper(CGIndenter(ifFalse), pre=" else {\n", post="\n}") ]
|
||||
CGList.__init__(self, kids)
|
||||
|
||||
class CGTemplatedType(CGWrapper):
|
||||
def __init__(self, templateName, child, isConst=False, isReference=False):
|
||||
const = "const " if isConst else ""
|
||||
@ -1430,13 +1482,6 @@ class AttrDefiner(PropertyDefiner):
|
||||
# non-static attributes go on the interface prototype object
|
||||
assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
|
||||
|
||||
if unforgeable and len(attributes) != 0 and descriptor.proxy:
|
||||
raise TypeError("Unforgeable properties are not supported on "
|
||||
"proxy bindings without [NamedPropertiesObject]. "
|
||||
"And not even supported on the ones with "
|
||||
"[NamedPropertiesObject] yet, but we should fix "
|
||||
"that, since they're safe there.")
|
||||
|
||||
def generateArray(self, array, name, doIdArrays):
|
||||
if len(array) == 0:
|
||||
return ""
|
||||
@ -1640,6 +1685,20 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
||||
else:
|
||||
prefCache = None
|
||||
|
||||
if UseHolderForUnforgeable(self.descriptor):
|
||||
createUnforgeableHolder = CGGeneric("""JSObject* unforgeableHolder = JS_NewObjectWithGivenProto(aCx, nullptr, nullptr, nullptr);
|
||||
if (!unforgeableHolder) {
|
||||
return;
|
||||
}""")
|
||||
defineUnforgeables = InitUnforgeablePropertiesOnObject(self.descriptor,
|
||||
"unforgeableHolder",
|
||||
self.properties)
|
||||
createUnforgeableHolder = CGList([createUnforgeableHolder,
|
||||
defineUnforgeables],
|
||||
"\n")
|
||||
else:
|
||||
createUnforgeableHolder = None
|
||||
|
||||
getParentProto = ("JSObject* parentProto = %s;\n" +
|
||||
"if (!parentProto) {\n" +
|
||||
" return;\n" +
|
||||
@ -1707,8 +1766,19 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
||||
properties,
|
||||
chromeProperties,
|
||||
'"' + self.descriptor.interface.identifier.name + '"' if needInterfaceObject else "NULL"))
|
||||
if UseHolderForUnforgeable(self.descriptor):
|
||||
assert needInterfacePrototypeObject
|
||||
setUnforgeableHolder = CGGeneric(
|
||||
"JSObject* proto = protoAndIfaceArray[prototypes::id::%s];\n"
|
||||
"if (proto) {\n"
|
||||
" js::SetReservedSlot(proto, DOM_INTERFACE_PROTO_SLOTS_BASE,\n"
|
||||
" JS::ObjectValue(*unforgeableHolder));\n"
|
||||
"}" % self.descriptor.name)
|
||||
else:
|
||||
setUnforgeableHolder = None
|
||||
functionBody = CGList(
|
||||
[CGGeneric(getParentProto), initIds, prefCache, CGGeneric(call)],
|
||||
[CGGeneric(getParentProto), initIds, prefCache,
|
||||
createUnforgeableHolder, CGGeneric(call), setUnforgeableHolder],
|
||||
"\n\n")
|
||||
return CGIndenter(functionBody).define()
|
||||
|
||||
@ -1870,25 +1940,31 @@ def CreateBindingJSObject(descriptor, parent):
|
||||
"""
|
||||
return create % parent
|
||||
|
||||
def GetAccessCheck(descriptor, globalName):
|
||||
def GetAccessCheck(descriptor, object):
|
||||
"""
|
||||
globalName is the name of the global JSObject*
|
||||
object is the name of a JSObject*
|
||||
|
||||
returns a string
|
||||
"""
|
||||
if descriptor.workers:
|
||||
accessCheck = "mozilla::dom::workers::GetWorkerPrivateFromContext(aCx)->IsChromeWorker()"
|
||||
else:
|
||||
accessCheck = "xpc::AccessCheck::isChrome(%s)" % globalName
|
||||
accessCheck = "xpc::AccessCheck::isChrome(%s)" % object
|
||||
return accessCheck
|
||||
|
||||
def InitUnforgeableProperties(descriptor, properties):
|
||||
def InitUnforgeablePropertiesOnObject(descriptor, obj, properties, failureReturnValue=""):
|
||||
"""
|
||||
properties is a PropertyArrays instance
|
||||
"""
|
||||
defineUnforgeables = ("if (!DefineUnforgeableAttributes(aCx, obj, %s)) {\n"
|
||||
" return nullptr;\n"
|
||||
failureReturn = "return"
|
||||
if len(failureReturnValue) > 0:
|
||||
failureReturn += " " + failureReturnValue
|
||||
failureReturn += ";"
|
||||
|
||||
defineUnforgeables = ("if (!DefineUnforgeableAttributes(aCx, " + obj + ", %s)) {\n"
|
||||
" " + failureReturn + "\n"
|
||||
"}")
|
||||
|
||||
unforgeableAttrs = properties.unforgeableAttrs
|
||||
unforgeables = []
|
||||
if unforgeableAttrs.hasNonChromeOnly():
|
||||
@ -1898,16 +1974,30 @@ def InitUnforgeableProperties(descriptor, properties):
|
||||
unforgeables.append(
|
||||
CGIfWrapper(CGGeneric(defineUnforgeables %
|
||||
unforgeableAttrs.variableName(True)),
|
||||
GetAccessCheck(descriptor, "global")))
|
||||
GetAccessCheck(descriptor, obj)))
|
||||
return CGList(unforgeables, "\n")
|
||||
|
||||
return CGIndenter(CGWrapper(
|
||||
CGList(unforgeables, "\n"),
|
||||
pre=("\n"
|
||||
def InitUnforgeableProperties(descriptor, properties):
|
||||
"""
|
||||
properties is a PropertyArrays instance
|
||||
"""
|
||||
unforgeableAttrs = properties.unforgeableAttrs
|
||||
if not unforgeableAttrs.hasNonChromeOnly() and not unforgeableAttrs.hasChromeOnly():
|
||||
return ""
|
||||
|
||||
if descriptor.proxy:
|
||||
unforgeableProperties = CGGeneric(
|
||||
"// Unforgeable properties on proxy-based bindings are stored in an object held\n"
|
||||
"// by the interface prototype object.\n")
|
||||
else:
|
||||
unforgeableProperties = CGWrapper(
|
||||
InitUnforgeablePropertiesOnObject(descriptor, "obj", properties, "nullptr"),
|
||||
pre=(
|
||||
"// Important: do unforgeable property setup after we have handed\n"
|
||||
"// over ownership of the C++ object to obj as needed, so that if\n"
|
||||
"// we fail and it ends up GCed it won't have problems in the\n"
|
||||
"// finalizer trying to drop its ownership of the C++ object.\n"),
|
||||
post="\n")).define() if len(unforgeables) > 0 else ""
|
||||
"// finalizer trying to drop its ownership of the C++ object.\n"))
|
||||
return CGIndenter(CGWrapper(unforgeableProperties, pre="\n", post="\n")).define()
|
||||
|
||||
def AssertInheritanceChain(descriptor):
|
||||
asserts = ""
|
||||
@ -2929,10 +3019,16 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||
if type.isEnum():
|
||||
assert not isEnforceRange and not isClamp
|
||||
|
||||
enumName = type.unroll().inner.identifier.name
|
||||
declType = CGGeneric(enumName)
|
||||
if type.nullable():
|
||||
raise TypeError("We don't support nullable enumerated arguments "
|
||||
"yet")
|
||||
enum = type.inner.identifier.name
|
||||
declType = CGTemplatedType("Nullable", declType)
|
||||
declType = declType.define()
|
||||
enumLoc = "const_cast<%s&>(${declName}).SetValue()" % declType
|
||||
else:
|
||||
enumLoc = "${declName}"
|
||||
declType = declType.define()
|
||||
|
||||
if invalidEnumValueFatal:
|
||||
handleInvalidEnumValueCode = " MOZ_ASSERT(index >= 0);\n"
|
||||
else:
|
||||
@ -2954,20 +3050,36 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||
"%(exceptionCode)s\n"
|
||||
" }\n"
|
||||
"%(handleInvalidEnumValueCode)s"
|
||||
" ${declName} = static_cast<%(enumtype)s>(index);\n"
|
||||
"}" % { "enumtype" : enum,
|
||||
"values" : enum + "Values::strings",
|
||||
" %(enumLoc)s = static_cast<%(enumtype)s>(index);\n"
|
||||
"}" % { "enumtype" : enumName,
|
||||
"values" : enumName + "Values::strings",
|
||||
"invalidEnumValueFatal" : toStringBool(invalidEnumValueFatal),
|
||||
"handleInvalidEnumValueCode" : handleInvalidEnumValueCode,
|
||||
"exceptionCode" : CGIndenter(exceptionCodeIndented).define() })
|
||||
"exceptionCode" : CGIndenter(exceptionCodeIndented).define(),
|
||||
"enumLoc" : enumLoc,
|
||||
})
|
||||
|
||||
setNull = "const_cast<%s&>(${declName}).SetNull();" % declType
|
||||
|
||||
if type.nullable():
|
||||
template = CGIfElseWrapper("${val}.isNullOrUndefined()",
|
||||
CGGeneric(setNull),
|
||||
CGGeneric(template)).define()
|
||||
|
||||
if defaultValue is not None:
|
||||
assert(defaultValue.type.tag() == IDLType.Tags.domstring)
|
||||
template = handleDefault(template,
|
||||
("${declName} = %sValues::%s" %
|
||||
(enum,
|
||||
getEnumValueName(defaultValue.value))))
|
||||
return (template, CGGeneric(enum), None, isOptional)
|
||||
if isinstance(defaultValue, IDLNullValue):
|
||||
assert type.nullable()
|
||||
template = handleDefault(template, setNull)
|
||||
else:
|
||||
assert(defaultValue.type.tag() == IDLType.Tags.domstring)
|
||||
template = handleDefault(template,
|
||||
("%s = %sValues::%s" %
|
||||
(enumLoc, enumName,
|
||||
getEnumValueName(defaultValue.value))))
|
||||
if type.nullable() and not isOptional:
|
||||
# isOptional will handle the const bits itself
|
||||
declType = "const " + declType
|
||||
return (template, CGGeneric(declType), None, isOptional)
|
||||
|
||||
if type.isCallback():
|
||||
assert not isEnforceRange and not isClamp
|
||||
@ -3586,18 +3698,28 @@ if (!returnArray) {
|
||||
|
||||
if type.isEnum():
|
||||
if type.nullable():
|
||||
raise TypeError("We don't support nullable enumerated return types "
|
||||
"yet")
|
||||
return ("""MOZ_ASSERT(uint32_t(%(result)s) < ArrayLength(%(strings)s));
|
||||
JSString* %(resultStr)s = JS_NewStringCopyN(cx, %(strings)s[uint32_t(%(result)s)].value, %(strings)s[uint32_t(%(result)s)].length);
|
||||
if (!%(resultStr)s) {
|
||||
resultLoc = "%s.Value()" % result
|
||||
else:
|
||||
resultLoc = result
|
||||
conversion = ("""{
|
||||
// Scope for resultStr
|
||||
MOZ_ASSERT(uint32_t(%(result)s) < ArrayLength(%(strings)s));
|
||||
JSString* resultStr = JS_NewStringCopyN(cx, %(strings)s[uint32_t(%(result)s)].value, %(strings)s[uint32_t(%(result)s)].length);
|
||||
if (!resultStr) {
|
||||
%(exceptionCode)s
|
||||
}
|
||||
""" % { "result" : result,
|
||||
"resultStr" : result + "_str",
|
||||
"strings" : type.inner.identifier.name + "Values::strings",
|
||||
"exceptionCode" : exceptionCodeIndented.define() } +
|
||||
setValue("JS::StringValue(%s_str)" % result), False)
|
||||
}
|
||||
""" % { "result" : resultLoc,
|
||||
"strings" : type.unroll().inner.identifier.name + "Values::strings",
|
||||
"exceptionCode" : CGIndenter(exceptionCodeIndented).define() } +
|
||||
CGIndenter(CGGeneric(setValue("JS::StringValue(resultStr)"))).define() +
|
||||
"\n}")
|
||||
|
||||
if type.nullable():
|
||||
conversion = CGIfElseWrapper(
|
||||
"%s.IsNull()" % result,
|
||||
CGGeneric(setValue("JS::NullValue()", False)),
|
||||
CGGeneric(conversion)).define()
|
||||
return conversion, False
|
||||
|
||||
if type.isCallback() or type.isCallbackInterface():
|
||||
# See comments in WrapNewBindingObject explaining why we need
|
||||
@ -3778,9 +3900,10 @@ def getRetvalDeclarationForType(returnType, descriptorProvider,
|
||||
return CGGeneric("nsString"), True
|
||||
return CGGeneric("DOMString"), True
|
||||
if returnType.isEnum():
|
||||
result = CGGeneric(returnType.unroll().inner.identifier.name)
|
||||
if returnType.nullable():
|
||||
raise TypeError("We don't support nullable enum return values")
|
||||
return CGGeneric(returnType.inner.identifier.name), False
|
||||
result = CGTemplatedType("Nullable", result)
|
||||
return result, False
|
||||
if returnType.isGeckoInterface():
|
||||
result = CGGeneric(descriptorProvider.getDescriptor(
|
||||
returnType.unroll().inner.identifier.name).nativeType)
|
||||
@ -6159,7 +6282,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(ClassMethod):
|
||||
indexedGetter = self.descriptor.operations['IndexedGetter']
|
||||
indexedSetter = self.descriptor.operations['IndexedSetter']
|
||||
|
||||
setOrIndexedGet = ""
|
||||
setOrIndexedGet = "bool isXray = xpc::WrapperFactory::IsXrayWrapper(proxy);\n"
|
||||
if self.descriptor.supportsIndexedProperties():
|
||||
setOrIndexedGet += "int32_t index = GetArrayIndexFromId(cx, id);\n"
|
||||
readonly = toStringBool(indexedSetter is None)
|
||||
@ -6170,6 +6293,22 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(ClassMethod):
|
||||
CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define() + "\n" +
|
||||
"}\n") % (self.descriptor.nativeType)
|
||||
|
||||
if UseHolderForUnforgeable(self.descriptor):
|
||||
getUnforgeable = """if (!JS_GetPropertyDescriptorById(cx, ${holder}, id, flags, desc)) {
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT_IF(desc->obj, desc->obj == ${holder});"""
|
||||
getUnforgeable = CallOnUnforgeableHolder(self.descriptor,
|
||||
getUnforgeable, "isXray")
|
||||
getUnforgeable += """if (desc->obj) {
|
||||
desc->obj = proxy;
|
||||
return !isXray || JS_WrapPropertyDescriptor(cx, desc);
|
||||
}
|
||||
|
||||
"""
|
||||
else:
|
||||
getUnforgeable = ""
|
||||
|
||||
if indexedSetter or self.descriptor.operations['NamedSetter']:
|
||||
setOrIndexedGet += "if (flags & JSRESOLVE_ASSIGNING) {\n"
|
||||
if indexedSetter:
|
||||
@ -6183,6 +6322,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(ClassMethod):
|
||||
setOrIndexedGet += (" FillPropertyDescriptor(desc, proxy, JSVAL_VOID, false);\n" +
|
||||
" return true;\n" +
|
||||
" }\n")
|
||||
setOrIndexedGet += CGIndenter(CGGeneric(getUnforgeable)).define()
|
||||
if self.descriptor.operations['NamedSetter']:
|
||||
if not 'NamedCreator' in self.descriptor.operations:
|
||||
# FIXME need to check that this is a 'supported property name'
|
||||
@ -6197,13 +6337,19 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(ClassMethod):
|
||||
setOrIndexedGet += "}"
|
||||
if indexedGetter:
|
||||
setOrIndexedGet += (" else {\n" +
|
||||
CGIndenter(CGGeneric(get)).define() +
|
||||
CGIndenter(CGGeneric(get + "\n" + getUnforgeable)).define() +
|
||||
"}")
|
||||
else:
|
||||
setOrIndexedGet += (" else {\n" +
|
||||
CGIndenter(CGGeneric(getUnforgeable)).define() +
|
||||
"}")
|
||||
setOrIndexedGet += "\n\n"
|
||||
elif indexedGetter:
|
||||
setOrIndexedGet += ("if (!(flags & JSRESOLVE_ASSIGNING)) {\n" +
|
||||
CGIndenter(CGGeneric(get)).define() +
|
||||
"}\n\n")
|
||||
else:
|
||||
if indexedGetter:
|
||||
setOrIndexedGet += ("if (!(flags & JSRESOLVE_ASSIGNING)) {\n" +
|
||||
CGIndenter(CGGeneric(get)).define() +
|
||||
"}\n\n")
|
||||
setOrIndexedGet += getUnforgeable
|
||||
|
||||
if self.descriptor.supportsNamedProperties():
|
||||
readonly = toStringBool(self.descriptor.operations['NamedSetter'] is None)
|
||||
@ -6224,7 +6370,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(ClassMethod):
|
||||
namedGet = ""
|
||||
|
||||
return setOrIndexedGet + """JSObject* expando;
|
||||
if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) {
|
||||
if (!isXray && (expando = GetExpandoObject(proxy))) {
|
||||
if (!JS_GetPropertyDescriptorById(cx, expando, id, flags, desc)) {
|
||||
return false;
|
||||
}
|
||||
@ -6265,6 +6411,19 @@ class CGDOMJSProxyHandler_defineProperty(ClassMethod):
|
||||
" return ThrowErrorMessage(cx, MSG_NO_PROPERTY_SETTER, \"%s\");\n" +
|
||||
"}\n") % self.descriptor.name
|
||||
|
||||
if UseHolderForUnforgeable(self.descriptor):
|
||||
defineOnUnforgeable = ("JSBool hasUnforgeable;\n"
|
||||
"if (!JS_HasPropertyById(cx, ${holder}, id, &hasUnforgeable)) {\n"
|
||||
" return false;\n"
|
||||
"}\n"
|
||||
"if (hasUnforgeable) {\n"
|
||||
" JSBool defined;\n"
|
||||
" return js_DefineOwnProperty(cx, ${holder}, id, *desc, &defined);\n"
|
||||
"}\n")
|
||||
set += CallOnUnforgeableHolder(self.descriptor,
|
||||
defineOnUnforgeable,
|
||||
"xpc::WrapperFactory::IsXrayWrapper(proxy)")
|
||||
|
||||
namedSetter = self.descriptor.operations['NamedSetter']
|
||||
if namedSetter:
|
||||
if not self.descriptor.operations['NamedCreator'] is namedSetter:
|
||||
@ -6329,7 +6488,10 @@ class CGDOMJSProxyHandler_delete(ClassMethod):
|
||||
body = None
|
||||
return body
|
||||
|
||||
delete = ""
|
||||
delete = """MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
|
||||
"Should not have a XrayWrapper here");
|
||||
|
||||
"""
|
||||
|
||||
indexedBody = getDeleterBody("Indexed")
|
||||
if indexedBody is not None:
|
||||
@ -6340,6 +6502,19 @@ class CGDOMJSProxyHandler_delete(ClassMethod):
|
||||
" return true;\n" +
|
||||
"}\n") % self.descriptor.nativeType
|
||||
|
||||
if UseHolderForUnforgeable(self.descriptor):
|
||||
unforgeable = ("JSBool hasUnforgeable;\n"
|
||||
"if (!JS_HasPropertyById(cx, ${holder}, id, &hasUnforgeable)) {\n"
|
||||
" return false;\n"
|
||||
"}\n"
|
||||
"if (hasUnforgeable) {\n"
|
||||
" // We should throw if Throw is true!\n"
|
||||
" *bp = false;\n"
|
||||
" return true;\n"
|
||||
"}")
|
||||
delete += CallOnUnforgeableHolder(self.descriptor, unforgeable)
|
||||
delete += "\n"
|
||||
|
||||
namedBody = getDeleterBody("Named")
|
||||
if namedBody is not None:
|
||||
# We always return above for an index id in the case when we support
|
||||
@ -6366,31 +6541,43 @@ class CGDOMJSProxyHandler_getOwnPropertyNames(ClassMethod):
|
||||
def getBody(self):
|
||||
# Per spec, we do indices, then named props, then everything else
|
||||
if self.descriptor.supportsIndexedProperties():
|
||||
addIndices = """uint32_t length = UnwrapProxy(proxy)->Length();
|
||||
addIndices = """
|
||||
uint32_t length = UnwrapProxy(proxy)->Length();
|
||||
MOZ_ASSERT(int32_t(length) >= 0);
|
||||
for (int32_t i = 0; i < int32_t(length); ++i) {
|
||||
if (!props.append(INT_TO_JSID(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
"""
|
||||
else:
|
||||
addIndices = ""
|
||||
|
||||
if self.descriptor.supportsNamedProperties():
|
||||
addNames = """nsTArray<nsString> names;
|
||||
addNames = """
|
||||
nsTArray<nsString> names;
|
||||
UnwrapProxy(proxy)->GetSupportedNames(names);
|
||||
if (!AppendNamedPropertyIds(cx, proxy, names, props)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
"""
|
||||
else:
|
||||
addNames = ""
|
||||
|
||||
return addIndices + addNames + """JSObject* expando;
|
||||
if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = DOMProxyHandler::GetExpandoObject(proxy)) &&
|
||||
if UseHolderForUnforgeable(self.descriptor):
|
||||
addUnforgeable = (
|
||||
"if (!js::GetPropertyNames(cx, ${holder}, JSITER_OWNONLY | JSITER_HIDDEN, &props)) {\n"
|
||||
" return false;\n"
|
||||
"}")
|
||||
addUnforgeable = CallOnUnforgeableHolder(self.descriptor,
|
||||
addUnforgeable,
|
||||
"isXray")
|
||||
else:
|
||||
addUnforgeable = ""
|
||||
return """bool isXray = xpc::WrapperFactory::IsXrayWrapper(proxy);
|
||||
""" + addIndices + addUnforgeable + addNames + """
|
||||
JSObject* expando;
|
||||
if (!isXray && (expando = DOMProxyHandler::GetExpandoObject(proxy)) &&
|
||||
!js::GetPropertyNames(cx, expando, JSITER_OWNONLY | JSITER_HIDDEN, &props)) {
|
||||
return false;
|
||||
}
|
||||
@ -6416,6 +6603,17 @@ class CGDOMJSProxyHandler_hasOwn(ClassMethod):
|
||||
else:
|
||||
indexed = ""
|
||||
|
||||
if UseHolderForUnforgeable(self.descriptor):
|
||||
unforgeable = ("JSBool b = true;\n"
|
||||
"JSBool ok = JS_AlreadyHasOwnPropertyById(cx, ${holder}, id, &b);\n"
|
||||
"*bp = !!b;\n"
|
||||
"if (!ok || *bp) {\n"
|
||||
" return ok;\n"
|
||||
"}")
|
||||
unforgeable = CallOnUnforgeableHolder(self.descriptor, unforgeable)
|
||||
else:
|
||||
unforgeable = ""
|
||||
|
||||
if self.descriptor.supportsNamedProperties():
|
||||
# If we support indexed properties we always return above for index
|
||||
# property names, so no need to check for those here.
|
||||
@ -6428,7 +6626,11 @@ class CGDOMJSProxyHandler_hasOwn(ClassMethod):
|
||||
else:
|
||||
named = ""
|
||||
|
||||
return indexed + """JSObject* expando = GetExpandoObject(proxy);
|
||||
return """MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
|
||||
"Should not have a XrayWrapper here");
|
||||
|
||||
""" + indexed + unforgeable + """
|
||||
JSObject* expando = GetExpandoObject(proxy);
|
||||
if (expando) {
|
||||
JSBool b = true;
|
||||
JSBool ok = JS_HasPropertyById(cx, expando, id, &b);
|
||||
@ -6451,7 +6653,20 @@ class CGDOMJSProxyHandler_get(ClassMethod):
|
||||
ClassMethod.__init__(self, "get", "bool", args)
|
||||
self.descriptor = descriptor
|
||||
def getBody(self):
|
||||
getFromExpando = """JSObject* expando = DOMProxyHandler::GetExpandoObject(proxy);
|
||||
if UseHolderForUnforgeable(self.descriptor):
|
||||
hasUnforgeable = (
|
||||
"JSBool hasUnforgeable;\n"
|
||||
"if (!JS_AlreadyHasOwnPropertyById(cx, ${holder}, id, &hasUnforgeable)) {\n"
|
||||
" return false;\n"
|
||||
"}\n"
|
||||
"if (hasUnforgeable) {\n"
|
||||
" return JS_ForwardGetPropertyTo(cx, ${holder}, id, proxy, vp.address());\n"
|
||||
"}")
|
||||
getUnforgeableOrExpando = CallOnUnforgeableHolder(self.descriptor,
|
||||
hasUnforgeable)
|
||||
else:
|
||||
getUnforgeableOrExpando = ""
|
||||
getUnforgeableOrExpando += """JSObject* expando = DOMProxyHandler::GetExpandoObject(proxy);
|
||||
if (expando) {
|
||||
JSBool hasProp;
|
||||
if (!JS_HasPropertyById(cx, expando, id, &hasProp)) {
|
||||
@ -6475,9 +6690,9 @@ if (expando) {
|
||||
} else {
|
||||
%s
|
||||
}
|
||||
""" % (stripTrailingWhitespace(getFromExpando.replace('\n', '\n ')))
|
||||
""" % (stripTrailingWhitespace(getUnforgeableOrExpando.replace('\n', '\n ')))
|
||||
else:
|
||||
getIndexedOrExpando = getFromExpando + "\n"
|
||||
getIndexedOrExpando = getUnforgeableOrExpando + "\n"
|
||||
|
||||
if self.descriptor.supportsNamedProperties():
|
||||
getNamed = CGProxyNamedGetter(self.descriptor, templateValues)
|
||||
@ -6604,7 +6819,9 @@ class CGDOMJSProxyHandler(CGClass):
|
||||
# XXXbz This should really just test supportsIndexedProperties() and
|
||||
# supportsNamedProperties(), but that would make us throw in all cases
|
||||
# because we don't know whether we're in strict mode.
|
||||
if descriptor.operations['IndexedSetter'] or descriptor.operations['NamedSetter']:
|
||||
if (descriptor.operations['IndexedSetter'] or
|
||||
descriptor.operations['NamedSetter'] or
|
||||
UseHolderForUnforgeable(descriptor)):
|
||||
methods.append(CGDOMJSProxyHandler_defineProperty(descriptor))
|
||||
methods.extend([CGDOMJSProxyHandler_getOwnPropertyNames(descriptor),
|
||||
CGDOMJSProxyHandler_hasOwn(descriptor),
|
||||
@ -7516,10 +7733,14 @@ class CGNativeMember(ClassMethod):
|
||||
# Outparam
|
||||
return "void", "", "retval = ${declName};"
|
||||
if type.isEnum():
|
||||
enumName = type.unroll().inner.identifier.name
|
||||
if type.nullable():
|
||||
raise TypeError("We don't support nullable enum return values")
|
||||
typeName = type.inner.identifier.name
|
||||
return typeName, "%s(0)" % typeName, "return ${declName};"
|
||||
enumName = CGTemplatedType("Nullable",
|
||||
CGGeneric(enumName)).define()
|
||||
defaultValue = "%s()" % enumName
|
||||
else:
|
||||
defaultValue = "%s(0)" % enumName
|
||||
return enumName, defaultValue, "return ${declName};"
|
||||
if type.isGeckoInterface():
|
||||
iface = type.unroll().inner;
|
||||
nativeType = self.descriptor.getDescriptor(
|
||||
@ -7709,7 +7930,7 @@ class CGNativeMember(ClassMethod):
|
||||
return declType, True, False
|
||||
|
||||
if type.isEnum():
|
||||
return type.inner.identifier.name, False, True
|
||||
return type.unroll().inner.identifier.name, False, True
|
||||
|
||||
if type.isCallback() or type.isCallbackInterface():
|
||||
forceOwningType = optional or isMember
|
||||
|
@ -42,9 +42,14 @@ class nsCycleCollectionParticipant;
|
||||
#define DOM_PROTO_INSTANCE_CLASS_SLOT 0
|
||||
|
||||
// Interface objects store a number of reserved slots equal to
|
||||
// DOM_INTERFACE_BASE_SLOTS + number of named constructors.
|
||||
// DOM_INTERFACE_SLOTS_BASE + number of named constructors.
|
||||
#define DOM_INTERFACE_SLOTS_BASE (DOM_XRAY_EXPANDO_SLOT + 1)
|
||||
|
||||
// Interface prototype objects store a number of reserved slots equal to
|
||||
// DOM_INTERFACE_PROTO_SLOTS_BASE or DOM_INTERFACE_PROTO_SLOTS_BASE + 1 if a
|
||||
// slot for the unforgeable holder is needed.
|
||||
#define DOM_INTERFACE_PROTO_SLOTS_BASE (DOM_XRAY_EXPANDO_SLOT + 1)
|
||||
|
||||
MOZ_STATIC_ASSERT(DOM_PROTO_INSTANCE_CLASS_SLOT != DOM_XRAY_EXPANDO_SLOT,
|
||||
"Interface prototype object use both of these, so they must "
|
||||
"not be the same slot.");
|
||||
|
@ -143,8 +143,8 @@ DOMProxyHandler::defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::
|
||||
return false;
|
||||
}
|
||||
|
||||
return JS_DefinePropertyById(cx, expando, id, desc->value, desc->getter, desc->setter,
|
||||
desc->attrs);
|
||||
JSBool dummy;
|
||||
return js_DefineOwnProperty(cx, expando, id, *desc, &dummy);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -2227,8 +2227,11 @@ class IDLValue(IDLObject):
|
||||
if type == self.type:
|
||||
return self # Nothing to do
|
||||
|
||||
# If the type allows null, rerun this matching on the inner type
|
||||
if type.nullable():
|
||||
# If the type allows null, rerun this matching on the inner type, except
|
||||
# nullable enums. We handle those specially, because we want our
|
||||
# default string values to stay strings even when assigned to a nullable
|
||||
# enum.
|
||||
if type.nullable() and not type.isEnum():
|
||||
innerValue = self.coerceToType(type.inner, location)
|
||||
return IDLValue(self.location, type, innerValue.value)
|
||||
|
||||
@ -2253,10 +2256,11 @@ class IDLValue(IDLObject):
|
||||
(self.value, type), [location])
|
||||
elif self.type.isString() and type.isEnum():
|
||||
# Just keep our string, but make sure it's a valid value for this enum
|
||||
if self.value not in type.inner.values():
|
||||
enum = type.unroll().inner
|
||||
if self.value not in enum.values():
|
||||
raise WebIDLError("'%s' is not a valid default value for enum %s"
|
||||
% (self.value, type.inner.identifier.name),
|
||||
[location, type.inner.location])
|
||||
% (self.value, enum.identifier.name),
|
||||
[location, enum.location])
|
||||
return self
|
||||
elif self.type.isFloat() and type.isFloat():
|
||||
if (not type.isUnrestricted() and
|
||||
|
@ -378,9 +378,14 @@ public:
|
||||
|
||||
// Enumerated types
|
||||
void PassEnum(TestEnum);
|
||||
void PassNullableEnum(const Nullable<TestEnum>&);
|
||||
void PassOptionalEnum(const Optional<TestEnum>&);
|
||||
void PassEnumWithDefault(TestEnum);
|
||||
void PassOptionalNullableEnum(const Optional<Nullable<TestEnum> >&);
|
||||
void PassOptionalNullableEnumWithDefaultValue(const Nullable<TestEnum>&);
|
||||
void PassOptionalNullableEnumWithDefaultValue2(const Nullable<TestEnum>&);
|
||||
TestEnum ReceiveEnum();
|
||||
Nullable<TestEnum> ReceiveNullableEnum();
|
||||
TestEnum EnumAttribute();
|
||||
TestEnum ReadonlyEnumAttribute();
|
||||
void SetEnumAttribute(TestEnum);
|
||||
|
@ -357,13 +357,14 @@ interface TestInterface {
|
||||
|
||||
// Enumerated types
|
||||
void passEnum(TestEnum arg);
|
||||
// No support for nullable enums yet
|
||||
// void passNullableEnum(TestEnum? arg);
|
||||
void passNullableEnum(TestEnum? arg);
|
||||
void passOptionalEnum(optional TestEnum arg);
|
||||
void passEnumWithDefault(optional TestEnum arg = "a");
|
||||
// void passOptionalNullableEnum(optional TestEnum? arg);
|
||||
// void passOptionalNullableEnumWithDefaultValue(optional TestEnum? arg = null);
|
||||
void passOptionalNullableEnum(optional TestEnum? arg);
|
||||
void passOptionalNullableEnumWithDefaultValue(optional TestEnum? arg = null);
|
||||
void passOptionalNullableEnumWithDefaultValue2(optional TestEnum? arg = "a");
|
||||
TestEnum receiveEnum();
|
||||
TestEnum? receiveNullableEnum();
|
||||
attribute TestEnum enumAttribute;
|
||||
readonly attribute TestEnum readonlyEnumAttribute;
|
||||
|
||||
|
@ -265,13 +265,14 @@ interface TestExampleInterface {
|
||||
|
||||
// Enumerated types
|
||||
void passEnum(TestEnum arg);
|
||||
// No support for nullable enums yet
|
||||
// void passNullableEnum(TestEnum? arg);
|
||||
void passNullableEnum(TestEnum? arg);
|
||||
void passOptionalEnum(optional TestEnum arg);
|
||||
void passEnumWithDefault(optional TestEnum arg = "a");
|
||||
// void passOptionalNullableEnum(optional TestEnum? arg);
|
||||
// void passOptionalNullableEnumWithDefaultValue(optional TestEnum? arg = null);
|
||||
void passOptionalNullableEnum(optional TestEnum? arg);
|
||||
void passOptionalNullableEnumWithDefaultValue(optional TestEnum? arg = null);
|
||||
void passOptionalNullableEnumWithDefaultValue2(optional TestEnum? arg = "a");
|
||||
TestEnum receiveEnum();
|
||||
TestEnum? receiveNullableEnum();
|
||||
attribute TestEnum enumAttribute;
|
||||
readonly attribute TestEnum readonlyEnumAttribute;
|
||||
|
||||
|
@ -287,14 +287,14 @@ interface TestJSImplInterface {
|
||||
|
||||
// Enumerated types
|
||||
void passEnum(MyTestEnum arg);
|
||||
// No support for nullable enums yet
|
||||
// void passNullableEnum(MyTestEnum? arg);
|
||||
// Optional enum arg doesn't work with callback interfaces. See bug 843355.
|
||||
//void passOptionalEnum(optional MyTestEnum arg);
|
||||
void passNullableEnum(MyTestEnum? arg);
|
||||
void passOptionalEnum(optional MyTestEnum arg);
|
||||
void passEnumWithDefault(optional MyTestEnum arg = "a");
|
||||
// void passOptionalNullableEnum(optional MyTestEnum? arg);
|
||||
// void passOptionalNullableEnumWithDefaultValue(optional MyTestEnum? arg = null);
|
||||
void passOptionalNullableEnum(optional MyTestEnum? arg);
|
||||
void passOptionalNullableEnumWithDefaultValue(optional MyTestEnum? arg = null);
|
||||
void passOptionalNullableEnumWithDefaultValue2(optional MyTestEnum? arg = "a");
|
||||
MyTestEnum receiveEnum();
|
||||
MyTestEnum? receiveNullableEnum();
|
||||
attribute MyTestEnum enumAttribute;
|
||||
readonly attribute MyTestEnum readonlyEnumAttribute;
|
||||
|
||||
|
@ -41,23 +41,16 @@ public:
|
||||
|
||||
void Notify(const BluetoothSignal& aParam);
|
||||
|
||||
nsIDOMEventTarget*
|
||||
ToIDOMEventTarget() const
|
||||
{
|
||||
return static_cast<nsDOMEventTargetHelper*>(
|
||||
const_cast<BluetoothAdapter*>(this));
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
ToISupports() const
|
||||
ToISupports()
|
||||
{
|
||||
return ToIDOMEventTarget();
|
||||
return static_cast<EventTarget*>(this);
|
||||
}
|
||||
|
||||
void Unroot();
|
||||
virtual void SetPropertyByValue(const BluetoothNamedValue& aValue);
|
||||
private:
|
||||
|
||||
|
||||
BluetoothAdapter(nsPIDOMWindow* aOwner, const BluetoothValue& aValue);
|
||||
~BluetoothAdapter();
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user