Merge m-c and fx-team

This commit is contained in:
Phil Ringnalda 2013-04-21 19:38:48 -07:00
commit ec5e0c7d31
240 changed files with 3784 additions and 1806 deletions

View File

@ -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());

View File

@ -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}">

View File

@ -3649,10 +3649,6 @@ var XULBrowserWindow = {
// unsupported
},
setJSDefaultStatus: function () {
// unsupported
},
setDefaultStatus: function (status) {
this.defaultStatus = status;
this.updateStatusField();

View File

@ -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;

View File

@ -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):

View File

@ -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

View File

@ -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

View File

@ -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)

View 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>

View File

@ -133,3 +133,4 @@ load 841205.html
load 844404.html
load 847127.html
load 849601.html
load 863950.html

View File

@ -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; }

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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();
}

View File

@ -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")

View File

@ -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;
}

View File

@ -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');
}

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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();

View File

@ -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]);
}

View File

@ -132,7 +132,7 @@ public:
return y;
}
uint32_t Which()
virtual uint32_t Which()
{
uint32_t w;
GetWhich(&w);

View 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>

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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;
};
}

View File

@ -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) {

View File

@ -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;
};
}

View File

@ -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);

View File

@ -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

View File

@ -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) {

View File

@ -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();
}

View File

@ -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)

View File

@ -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();

View File

@ -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);
}

View File

@ -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()
{

View File

@ -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();

View File

@ -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);
}

View File

@ -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;
}
}
}

View File

@ -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 */ }

View 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);
}
}
}

View 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

View File

@ -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()));
}

View File

@ -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());

View File

@ -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()));
}

View File

@ -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()));
}

View File

@ -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)

View File

@ -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);

View 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);
}
}
}

View 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

View File

@ -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,

View File

@ -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);
};
}

View File

@ -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',
]

View File

@ -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 \

View 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>

View 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>

View File

@ -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);
}

View File

@ -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];

View File

@ -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;

View File

@ -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);

View File

@ -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:

View File

@ -82,7 +82,7 @@ SVGViewElement::PreserveAspectRatio()
//----------------------------------------------------------------------
already_AddRefed<nsIDOMSVGStringList>
already_AddRefed<DOMSVGStringList>
SVGViewElement::ViewTarget()
{
return DOMSVGStringList::GetDOMWrapper(

View File

@ -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:

View File

@ -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:

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -515,6 +515,6 @@ AudioChannelService::GetInternalType(AudioChannelType aType,
break;
}
MOZ_NOT_REACHED();
MOZ_NOT_REACHED("unexpected audio channel type");
return AUDIO_CHANNEL_INT_LAST;
}

View File

@ -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 \

View File

@ -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 \

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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___ */

View File

@ -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)

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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;

View File

@ -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 = \

View 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>

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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.");

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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