mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 06:43:32 +00:00
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
commit
a758e037c4
2
CLOBBER
2
CLOBBER
@ -22,4 +22,4 @@
|
||||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Backing out bug 1087560 needs a CLOBBER
|
||||
For some reason, Clobber had problems applying the changes for Android in Bug 1091118
|
||||
|
@ -220,15 +220,6 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime)
|
||||
Accessible* outerDocAcc = mDocument->GetAccessible(ownerContent);
|
||||
if (outerDocAcc && outerDocAcc->AppendChild(childDoc)) {
|
||||
if (mDocument->AppendChildDocument(childDoc)) {
|
||||
if (IPCAccessibilityActive()) {
|
||||
DocAccessibleChild* ipcDoc = new DocAccessibleChild(childDoc);
|
||||
childDoc->SetIPCDoc(ipcDoc);
|
||||
auto contentChild = dom::ContentChild::GetSingleton();
|
||||
DocAccessibleChild* parentIPCDoc = mDocument->IPCDoc();
|
||||
uint64_t id = reinterpret_cast<uintptr_t>(outerDocAcc->UniqueID());
|
||||
contentChild->SendPDocAccessibleConstructor(ipcDoc, parentIPCDoc,
|
||||
id);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
@ -240,7 +231,8 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime)
|
||||
childDoc->Shutdown();
|
||||
}
|
||||
}
|
||||
mHangingChildDocuments.Clear();
|
||||
|
||||
nsTArray<nsRefPtr<DocAccessible>> newChildDocs = Move(mHangingChildDocuments);
|
||||
|
||||
// If the document is ready and all its subdocuments are completely loaded
|
||||
// then process the document load.
|
||||
@ -282,6 +274,20 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime)
|
||||
mObservingState = eRefreshProcessing;
|
||||
|
||||
ProcessEventQueue();
|
||||
|
||||
if (IPCAccessibilityActive()) {
|
||||
size_t newDocCount = newChildDocs.Length();
|
||||
for (size_t i = 0; i < newDocCount; i++) {
|
||||
DocAccessible* childDoc = newChildDocs[i];
|
||||
DocAccessibleChild* ipcDoc = new DocAccessibleChild(childDoc);
|
||||
childDoc->SetIPCDoc(ipcDoc);
|
||||
auto contentChild = dom::ContentChild::GetSingleton();
|
||||
DocAccessibleChild* parentIPCDoc = mDocument->IPCDoc();
|
||||
uint64_t id = reinterpret_cast<uintptr_t>(childDoc->Parent()->UniqueID());
|
||||
contentChild->SendPDocAccessibleConstructor(ipcDoc, parentIPCDoc, id);
|
||||
}
|
||||
}
|
||||
|
||||
mObservingState = eRefreshObserving;
|
||||
if (!mDocument)
|
||||
return;
|
||||
|
@ -63,6 +63,7 @@ LOCAL_INCLUDES += [
|
||||
'/accessible/ipc',
|
||||
'/accessible/xpcom',
|
||||
'/accessible/xul',
|
||||
'/dom/base',
|
||||
'/dom/xbl',
|
||||
'/ipc/chromium/src',
|
||||
'/layout/generic',
|
||||
|
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
SharedLibrary('IA2Marshal')
|
||||
GeckoSharedLibrary('IA2Marshal', linkage=None)
|
||||
|
||||
DEFINES['REGISTER_PROXY_DLL'] = True
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
SharedLibrary('AccessibleMarshal')
|
||||
GeckoSharedLibrary('AccessibleMarshal', linkage=None)
|
||||
|
||||
GENERATED_SOURCES += [
|
||||
'dlldata.c',
|
||||
|
@ -18,6 +18,12 @@ SerializeTree(Accessible* aRoot, nsTArray<AccessibleData>& aTree)
|
||||
uint32_t role = aRoot->Role();
|
||||
uint32_t childCount = aRoot->ChildCount();
|
||||
|
||||
// OuterDocAccessibles are special because we don't want to serialize the
|
||||
// child doc here, we'll call PDocAccessibleConstructor in
|
||||
// NotificationController.
|
||||
if (childCount == 1 && aRoot->GetChildAt(0)->IsDoc())
|
||||
childCount = 0;
|
||||
|
||||
aTree.AppendElement(AccessibleData(id, role, childCount));
|
||||
for (uint32_t i = 0; i < childCount; i++)
|
||||
SerializeTree(aRoot->GetChildAt(i), aTree);
|
||||
|
@ -6,9 +6,9 @@
|
||||
|
||||
if not CONFIG['LIBXUL_SDK']:
|
||||
if CONFIG['GAIADIR']:
|
||||
Program(CONFIG['MOZ_APP_NAME'] + "-bin")
|
||||
GeckoProgram(CONFIG['MOZ_APP_NAME'] + "-bin")
|
||||
else:
|
||||
Program(CONFIG['MOZ_APP_NAME'])
|
||||
GeckoProgram(CONFIG['MOZ_APP_NAME'])
|
||||
if CONFIG['MOZ_B2G_LOADER']:
|
||||
SOURCES += [
|
||||
'B2GLoader.cpp',
|
||||
@ -26,8 +26,6 @@ if not CONFIG['LIBXUL_SDK']:
|
||||
'zlib',
|
||||
]
|
||||
|
||||
DEFINES['XPCOM_GLUE'] = True
|
||||
|
||||
for var in ('MOZ_APP_NAME', 'MOZ_APP_VERSION', 'MOZ_UPDATER'):
|
||||
DEFINES[var] = CONFIG[var]
|
||||
|
||||
@ -70,10 +68,6 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
'utils',
|
||||
]
|
||||
|
||||
USE_LIBS += [
|
||||
'xpcomglue',
|
||||
]
|
||||
|
||||
DISABLE_STL_WRAPPING = True
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
|
@ -4,9 +4,6 @@
|
||||
|
||||
GAIA_PATH := gaia/profile
|
||||
|
||||
# This is needed to avoid making run-b2g depend on mozglue
|
||||
WRAP_LDFLAGS :=
|
||||
|
||||
GENERATED_DIRS += $(DIST)/bin/$(GAIA_PATH)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -6,7 +6,10 @@
|
||||
|
||||
DIRS += ['profile/extensions']
|
||||
|
||||
Program(CONFIG['MOZ_APP_NAME'])
|
||||
if CONFIG['OS_ARCH'] == 'WINNT' and CONFIG['MOZ_METRO']:
|
||||
GeckoProgram(CONFIG['MOZ_APP_NAME'])
|
||||
else:
|
||||
GeckoProgram(CONFIG['MOZ_APP_NAME'], msvcrt='static')
|
||||
|
||||
SOURCES += [
|
||||
'nsBrowserApp.cpp',
|
||||
@ -18,8 +21,6 @@ for var in ('MOZILLA_OFFICIAL', 'LIBXUL_SDK'):
|
||||
if CONFIG[var]:
|
||||
DEFINES[var] = True
|
||||
|
||||
DEFINES['XPCOM_GLUE'] = True
|
||||
|
||||
GENERATED_INCLUDES += [
|
||||
'/build',
|
||||
]
|
||||
@ -34,7 +35,10 @@ if not CONFIG['MOZ_METRO']:
|
||||
DELAYLOAD_DLLS += [
|
||||
'mozglue.dll',
|
||||
]
|
||||
USE_STATIC_LIBS = True
|
||||
|
||||
USE_LIBS += [
|
||||
'mozglue',
|
||||
]
|
||||
|
||||
if CONFIG['_MSC_VER']:
|
||||
# Always enter a Windows program through wmain, whether or not we're
|
||||
@ -56,16 +60,6 @@ if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
if CONFIG['OS_ARCH'] == 'WINNT' and not CONFIG['GNU_CC']:
|
||||
LDFLAGS += ['/HEAP:0x40000']
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT' and not CONFIG['MOZ_METRO']:
|
||||
USE_LIBS += [
|
||||
'mozglue',
|
||||
'xpcomglue_staticruntime',
|
||||
]
|
||||
else:
|
||||
USE_LIBS += [
|
||||
'xpcomglue',
|
||||
]
|
||||
|
||||
DISABLE_STL_WRAPPING = True
|
||||
|
||||
if CONFIG['MOZ_LINKER']:
|
||||
|
@ -2344,7 +2344,12 @@ let E10SUINotification = {
|
||||
checkStatus: function() {
|
||||
let skipE10sChecks = false;
|
||||
try {
|
||||
// This order matters, because
|
||||
// browser.tabs.remote.autostart.disabled-because-using-a11y is not
|
||||
// always defined and will throw when not present.
|
||||
// privacy.trackingprotection.enabled is always defined.
|
||||
skipE10sChecks = (UpdateChannel.get() != "nightly") ||
|
||||
Services.prefs.getBoolPref("privacy.trackingprotection.enabled") ||
|
||||
Services.prefs.getBoolPref("browser.tabs.remote.autostart.disabled-because-using-a11y");
|
||||
} catch(e) {}
|
||||
|
||||
|
@ -6,11 +6,6 @@ ifndef MOZ_WINCONSOLE
|
||||
MOZ_WINCONSOLE = 0
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
DIST_PROGRAM = CommandExecuteHandler$(BIN_SUFFIX)
|
||||
|
||||
# Don't link against mozglue.dll
|
||||
MOZ_GLUE_LDFLAGS =
|
||||
MOZ_GLUE_PROGRAM_LDFLAGS =
|
||||
|
@ -1,7 +0,0 @@
|
||||
# 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/.
|
||||
|
||||
# don't use moz glue libs
|
||||
MOZ_GLUE_LDFLAGS =
|
||||
MOZ_GLUE_PROGRAM_LDFLAGS =
|
@ -73,6 +73,14 @@ if test "$compiler" = "clang"; then
|
||||
fi
|
||||
if test "$compiler" = "clang-cl"; then
|
||||
CLANG_CL=1
|
||||
# We force clang-cl to emulate Visual C++ 2013 in configure.in, but that
|
||||
# is based on the CLANG_CL variable defined here, so make sure that we're
|
||||
# getting the right version here manually.
|
||||
CC_VERSION=1800
|
||||
CXX_VERSION=1800
|
||||
# Build on clang-cl with MSVC 2013 with fallback emulation.
|
||||
CFLAGS="$CFLAGS -fmsc-version=1800 -fallback"
|
||||
CXXFLAGS="$CXXFLAGS -fmsc-version=1800 -fallback"
|
||||
fi
|
||||
|
||||
if test "$GNU_CC"; then
|
||||
|
@ -5,8 +5,6 @@
|
||||
# LLVM_CXXFLAGS comes with its own optimization flags.
|
||||
MOZ_OPTIMIZE =
|
||||
|
||||
MOZ_GLUE_LDFLAGS =
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
|
||||
# In the current moz.build world, we need to override essentially every
|
||||
|
@ -119,11 +119,6 @@ With a ``Framework`` name of ``foo``, the framework file name will be ``foo``.
|
||||
This template however affects the behavior on all platforms, so it needs to
|
||||
be set only on OSX.
|
||||
|
||||
Another special kind of library, XPCOM-specific, are XPCOM components. One can
|
||||
build such a component with the ``XPCOMBinaryComponent`` template.
|
||||
|
||||
XPCOMBinaryComponent('foo')
|
||||
|
||||
|
||||
Executables
|
||||
===========
|
||||
@ -293,3 +288,28 @@ On e.g. Linux, the above ``myprog`` will have DT_NEEDED markers for
|
||||
``libmylib.so`` and ``libfoo.so`` instead of ``libmylib.so`` and
|
||||
``libotherlib.so`` if there weren't a ``SONAME``. This means the runtime
|
||||
requirement for ``myprog`` is ``libfoo.so`` instead of ``libotherlib.so``.
|
||||
|
||||
|
||||
Gecko-related binaries
|
||||
======================
|
||||
|
||||
Some programs or libraries are totally independent of Gecko, and can use the
|
||||
above mentioned templates. Others are Gecko-related in some way, and may
|
||||
need XPCOM linkage, mozglue. These things are tedious. A set of additional
|
||||
templates exists to ease defining such programs and libraries. They are
|
||||
essentially the same as the above mentioned templates, prefixed with "Gecko":
|
||||
|
||||
- ``GeckoProgram``
|
||||
- ``GeckoSimplePrograms``
|
||||
- ``GeckoCppUnitTests``
|
||||
- ``GeckoSharedLibrary``
|
||||
- ``GeckoFramework``
|
||||
|
||||
There is also ``XPCOMBinaryComponent`` for XPCOM components, which is a
|
||||
special kind of library.
|
||||
|
||||
All the Gecko-prefixed templates take the same arguments as their
|
||||
non-Gecko-prefixed counterparts, and can take a few more arguments
|
||||
for non-standard cases. See the definition of ``GeckoBinary`` in
|
||||
build/gecko_templates.mozbuild for more details, but most usecases
|
||||
should not require these additional arguments.
|
||||
|
155
build/gecko_templates.mozbuild
Normal file
155
build/gecko_templates.mozbuild
Normal file
@ -0,0 +1,155 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
@template
|
||||
def GeckoBinary(linkage='dependent', msvcrt='dynamic', mozglue=None):
|
||||
'''Template for Gecko-related binaries.
|
||||
|
||||
This template is meant to be used in other templates.
|
||||
|
||||
`linkage` indicates the wanted xpcom linkage type. Valid values are
|
||||
'dependent', 'standalone' or None. 'dependent' is the default. It is
|
||||
used for e.g. XPCOM components and executables with direct dependencies
|
||||
on libxul. Most executables should use the 'standalone' linkage, which
|
||||
uses the standalone XPCOM glue to load libxul. None means no XPCOM glue
|
||||
or libxul linkage at all.
|
||||
|
||||
`msvcrt` indicates which Microsoft Visual Studio CRT, for Windows build,
|
||||
ought to be linked: 'static' or 'dynamic'.
|
||||
|
||||
`mozglue` indicates whether to link against the mozglue library, and if
|
||||
so, what linkage to apply. Valid values are None (mozglue not linked),
|
||||
'program' (mozglue linked to an executable program), or 'library' (mozglue
|
||||
linked to a shared library).
|
||||
'''
|
||||
if msvcrt == 'dynamic' or CONFIG['OS_ARCH'] != 'WINNT':
|
||||
xpcomglue = 'xpcomglue'
|
||||
elif msvcrt == 'static':
|
||||
USE_STATIC_LIBS = True
|
||||
xpcomglue = 'xpcomglue_staticruntime'
|
||||
if not CONFIG['GNU_CC']:
|
||||
mozglue = None
|
||||
else:
|
||||
error('msvcrt must be "dynamic" or "static"')
|
||||
|
||||
if linkage == 'dependent':
|
||||
USE_LIBS += [
|
||||
'mozalloc',
|
||||
'nspr',
|
||||
'%s_s' % xpcomglue,
|
||||
'xul',
|
||||
]
|
||||
elif linkage == 'standalone':
|
||||
DEFINES['XPCOM_GLUE'] = True
|
||||
|
||||
USE_LIBS += [
|
||||
xpcomglue,
|
||||
]
|
||||
elif linkage != None:
|
||||
error('`linkage` must be "dependent", "standalone" or None')
|
||||
|
||||
if mozglue:
|
||||
if CONFIG['JS_STANDALONE']:
|
||||
pass
|
||||
elif CONFIG['MOZ_CRT']:
|
||||
if msvcrt == 'dynamic':
|
||||
USE_LIBS += ['mozcrt']
|
||||
elif msvcrt == 'static':
|
||||
USE_LIBS += ['mozglue']
|
||||
else:
|
||||
error('`msvcrt` must be "dynamic" or "static"')
|
||||
else:
|
||||
LDFLAGS += CONFIG['MOZ_GLUE_WRAP_LDFLAGS']
|
||||
if mozglue == 'program':
|
||||
USE_LIBS += ['mozglue']
|
||||
if CONFIG['MOZ_GLUE_IN_PROGRAM']:
|
||||
if CONFIG['GNU_CC']:
|
||||
LDFLAGS += ['-rdynamic']
|
||||
if CONFIG['MOZ_MEMORY']:
|
||||
USE_LIBS += ['memory']
|
||||
if CONFIG['MOZ_LINKER']:
|
||||
OS_LIBS += CONFIG['MOZ_ZLIB_LIBS']
|
||||
elif mozglue == 'library':
|
||||
if not CONFIG['MOZ_GLUE_IN_PROGRAM']:
|
||||
USE_LIBS += ['mozglue']
|
||||
else:
|
||||
error('`mozglue` must be "program" or "library"')
|
||||
|
||||
|
||||
@template
|
||||
def GeckoProgram(name, linkage='standalone', **kwargs):
|
||||
'''Template for program executables related to Gecko.
|
||||
|
||||
`name` identifies the executable base name.
|
||||
|
||||
See the documentation for `GeckoBinary` for other possible arguments,
|
||||
with the notable difference that the default for `linkage` is 'standalone'.
|
||||
'''
|
||||
Program(name)
|
||||
|
||||
GeckoBinary(linkage=linkage, mozglue='program', **kwargs)
|
||||
|
||||
|
||||
@template
|
||||
def GeckoSimplePrograms(names, **kwargs):
|
||||
'''Template for simple program executables related to Gecko.
|
||||
|
||||
`names` identifies the executable base names for each executable.
|
||||
|
||||
See the documentation for `GeckoBinary` for other possible arguments.
|
||||
'''
|
||||
SimplePrograms(names)
|
||||
|
||||
GeckoBinary(mozglue='program', **kwargs)
|
||||
|
||||
|
||||
@template
|
||||
def GeckoCppUnitTests(names, **kwargs):
|
||||
'''Template for C++ unit tests related to Gecko.
|
||||
|
||||
`names` identifies the executable base names for each executable.
|
||||
|
||||
See the documentation for `GeckoBinary` for other possible arguments.
|
||||
'''
|
||||
CppUnitTests(names)
|
||||
|
||||
GeckoBinary(mozglue='program', **kwargs)
|
||||
|
||||
|
||||
@template
|
||||
def GeckoSharedLibrary(name, **kwargs):
|
||||
'''Template for shared libraries related to Gecko.
|
||||
|
||||
`name` identifies the library base name.
|
||||
See the documentation for `GeckoBinary` for other possible arguments.
|
||||
'''
|
||||
SharedLibrary(name)
|
||||
|
||||
GeckoBinary(mozglue='library', **kwargs)
|
||||
|
||||
|
||||
@template
|
||||
def GeckoFramework(name, **kwargs):
|
||||
'''Template for OSX frameworks related to Gecko.
|
||||
|
||||
`name` identifies the library base name.
|
||||
See the documentation for `GeckoBinary` for other possible arguments.
|
||||
'''
|
||||
Framework(name)
|
||||
|
||||
GeckoBinary(mozglue='library', **kwargs)
|
||||
|
||||
|
||||
@template
|
||||
def XPCOMBinaryComponent(name):
|
||||
'''Template defining an XPCOM binary component for Gecko.
|
||||
|
||||
`name` is the name of the component.
|
||||
'''
|
||||
GeckoSharedLibrary(name)
|
||||
|
||||
IS_COMPONENT = True
|
||||
|
@ -115,28 +115,4 @@ def HostLibrary(name):
|
||||
HOST_LIBRARY_NAME = name
|
||||
|
||||
|
||||
@template
|
||||
def GeckoBinary():
|
||||
'''Template for binaries using Gecko.
|
||||
|
||||
This template is meant to be used in other templates.
|
||||
'''
|
||||
USE_LIBS += [
|
||||
'mozalloc',
|
||||
'nspr',
|
||||
'xpcomglue_s',
|
||||
'xul',
|
||||
]
|
||||
|
||||
|
||||
@template
|
||||
def XPCOMBinaryComponent(name):
|
||||
'''Template defining an XPCOM binary component for Gecko.
|
||||
|
||||
name is the name of the component.
|
||||
'''
|
||||
SharedLibrary(name)
|
||||
|
||||
GeckoBinary()
|
||||
|
||||
IS_COMPONENT = True
|
||||
include('gecko_templates.mozbuild')
|
||||
|
@ -7,8 +7,6 @@ INTERNAL_TOOLS = 1
|
||||
|
||||
OS_CXXFLAGS := $(filter-out -fno-exceptions,$(OS_CXXFLAGS)) -fexceptions
|
||||
|
||||
WRAP_LDFLAGS=
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
test-array$(DLL_SUFFIX) test-ctors$(DLL_SUFFIX): %$(DLL_SUFFIX): %.$(OBJ_SUFFIX) elfhack
|
||||
|
@ -10,5 +10,3 @@ if CONFIG['MOZ_LIBSTDCXX_TARGET_VERSION'] or CONFIG['MOZ_LIBSTDCXX_HOST_VERSION'
|
||||
if CONFIG['USE_ELF_HACK']:
|
||||
DIRS += ['elfhack']
|
||||
|
||||
TEST_DIRS += ['test']
|
||||
|
||||
|
@ -1,38 +0,0 @@
|
||||
# -*- makefile -*-
|
||||
#
|
||||
# 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 $(topsrcdir)/config/rules.mk
|
||||
|
||||
##################################################
|
||||
## Gather a list of tests, generate timestamp deps
|
||||
##################################################
|
||||
TS=.ts
|
||||
ifneq (,$(findstring check,$(MAKECMDGOALS)))
|
||||
allsrc = $(wildcard $(srcdir)/*)
|
||||
tests2run = $(notdir $(filter %.tpl,$(allsrc)))
|
||||
check_targets += $(addprefix $(TS)/,$(tests2run))
|
||||
endif
|
||||
|
||||
check:: $(TS) $(check_targets)
|
||||
|
||||
#############################################
|
||||
# Only invoke tests when sources have changed
|
||||
#############################################
|
||||
$(TS)/%: $(srcdir)/%
|
||||
$(PERL) $(srcdir)/runtest $<
|
||||
@touch $@
|
||||
|
||||
#####################################################
|
||||
## Extra dep needed to synchronize parallel execution
|
||||
#####################################################
|
||||
$(TS): $(TS)/.done
|
||||
$(TS)/.done:
|
||||
$(MKDIR) -p $(dir $@)
|
||||
touch $@
|
||||
|
||||
GARBAGE_DIRS += $(TS)
|
||||
|
||||
# EOF
|
@ -1,95 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
###########################################################################
|
||||
## Intent:
|
||||
## Test::Harness is a testing wrapper that will process output
|
||||
## from Test.pm module tests. Sumarize results, report stats
|
||||
## and exit with overall status for the testing suites.
|
||||
##
|
||||
## Run testing suite:
|
||||
## % make clean test
|
||||
## % perl runtest
|
||||
##
|
||||
## Run Individual tests
|
||||
## % perl tUtils0
|
||||
###########################################################################
|
||||
|
||||
##----------------------------##
|
||||
##---] CORE/CPAN INCLUDES [---##
|
||||
##----------------------------##
|
||||
use strict;
|
||||
use warnings;
|
||||
use Getopt::Long;
|
||||
|
||||
use Test::Harness;
|
||||
|
||||
##-------------------##
|
||||
##---] EXPORTS [---##
|
||||
##-------------------##
|
||||
our $VERSION = qw(1.0);
|
||||
use FindBin;
|
||||
|
||||
##-------------------##
|
||||
##---] GLOBALS [---##
|
||||
##-------------------##
|
||||
my %argv;
|
||||
|
||||
##----------------##
|
||||
##---] MAIN [---##
|
||||
##----------------##
|
||||
unless(GetOptions(\%argv,
|
||||
qw(debug|d)
|
||||
))
|
||||
{
|
||||
print "Usage: $0\n";
|
||||
print " --debug Enable debug mode\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
if (2 > $Test::Harness::VERSION)
|
||||
{
|
||||
print "Unit tests will not be run, Test::Harness is too old\n"
|
||||
if ($argv{debug});
|
||||
exit 0;
|
||||
}
|
||||
|
||||
|
||||
my @tests;
|
||||
|
||||
########################################
|
||||
## Gather a list of tests if none passed
|
||||
########################################
|
||||
unless (@tests = @ARGV)
|
||||
{
|
||||
local *D;
|
||||
opendir(D, '.');
|
||||
while($_ = readdir(D)) {
|
||||
next unless /.t\S+$/;
|
||||
next if (/\.ts$/);
|
||||
push(@tests, $_);
|
||||
}
|
||||
closedir(D);
|
||||
}
|
||||
|
||||
###############################################
|
||||
## Glob a list of tests when directories passed
|
||||
###############################################
|
||||
my @tmp;
|
||||
foreach (@tests)
|
||||
{
|
||||
local *D;
|
||||
if (-d $_ && (my $dir = $_))
|
||||
{
|
||||
opendir(D, $_) || die "opendir(D) failed: $!";
|
||||
my @tests = grep(/\.t[^\.\s]+/o, readdir(D));
|
||||
closedir(D);
|
||||
push(@tmp, map{ join('/', $dir, $_); } @tests);
|
||||
} else {
|
||||
push(@tmp, $_);
|
||||
}
|
||||
}
|
||||
@tests = @tmp;
|
||||
|
||||
print "$0: @ARGV\n" if ($argv{debug});
|
||||
runtests(@tests);
|
||||
|
||||
# EOF
|
@ -1,151 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
###########################################################################
|
||||
## Intent: Unit test to verify uniq.pl
|
||||
###########################################################################
|
||||
|
||||
##----------------------------##
|
||||
##---] CORE/CPAN INCLUDES [---##
|
||||
##----------------------------##
|
||||
use strict;
|
||||
use warnings;
|
||||
use Cwd;
|
||||
use Getopt::Long; # GetOptions
|
||||
|
||||
use Test;
|
||||
sub BEGIN { plan tests => 12 }
|
||||
|
||||
##-------------------##
|
||||
##---] EXPORTS [---##
|
||||
##-------------------##
|
||||
our $VERSION = qw(1.0);
|
||||
|
||||
##------------------##
|
||||
##---] INCLUDES [---##
|
||||
##------------------##
|
||||
use FindBin;
|
||||
|
||||
##-------------------##
|
||||
##---] GLOBALS [---##
|
||||
##-------------------##
|
||||
my %argv;
|
||||
|
||||
|
||||
###########################################################################
|
||||
## Intent: Run the arch command for output
|
||||
##
|
||||
## Returns:
|
||||
## 0 on success
|
||||
## $? command shell exit status
|
||||
###########################################################################
|
||||
sub uniq_pl
|
||||
{
|
||||
my $cmd = "perl $FindBin::RealBin/../uniq.pl @_";
|
||||
print "Running: $cmd\n" if ($argv{debug});
|
||||
my @tmp = `$cmd 2>&1`;
|
||||
my @output = map{ split(/\s+/o); } @tmp;
|
||||
wantarray ? @output : "@output";
|
||||
} # uniq_pl
|
||||
|
||||
###########################################################################
|
||||
## Intent:
|
||||
##
|
||||
## Returns:
|
||||
## 0 on success
|
||||
###########################################################################
|
||||
sub check_uniq
|
||||
{
|
||||
print STDERR "Running test: check_uniq\n" if ($argv{debug});
|
||||
|
||||
# TODO: improve test, uniq.pl regexpr handling not quite right
|
||||
|
||||
my @todo =
|
||||
(
|
||||
[ '', qw(a a/b a/b/c) ] => [ qw(a a/b a/b/c) ],
|
||||
[ '', qw(a/b a a/b/c) ] => [ qw(a/b a a/b/c) ],
|
||||
[ '', qw(a/b/c a/b a) ] => [ qw(a/b/c a/b a) ],
|
||||
|
||||
[ '', qw(a a/b a/b/c a/b a) ] => [ qw(a a/b a/b/c) ], # dup removal
|
||||
|
||||
[ '-s', qw(a a/b a/b/c) ] => [ qw(a a/b a/b/c) ],
|
||||
[ '-s', qw(a/b a a/b/c) ] => [ qw(a a/b a/b/c) ],
|
||||
[ '-s', qw(a/b/c a/b a) ] => [ qw(a a/b a/b/c) ],
|
||||
|
||||
[ '-r', qw(a a/b a/b/c) ] => [ qw(a) ],
|
||||
[ '-r', qw(a/b a a/b/c) ] => [ qw(a/b a) ],
|
||||
[ '-r', qw(a/b/c a/b a) ] => [ qw(a/b/c a/b a) ],
|
||||
|
||||
[ '-r', qw(. .. a/b ../a aa/bb) ] => [ qw(. .. a/b aa/bb) ],
|
||||
[ '-r', qw(.. a/b ../a . aa/bb) ] => [ qw(.. a/b . aa/bb) ],
|
||||
);
|
||||
|
||||
my $ct=1;
|
||||
while (@todo)
|
||||
{
|
||||
my ($a, $b) = splice(@todo, 0, 2);
|
||||
my @args = @{ $a };
|
||||
my @exp = @{ $b };
|
||||
|
||||
my @out = uniq_pl(@args);
|
||||
# compareExp(\@out, \@exp, 'Failed on line ' . __LINE__ . ", dataset $ct");
|
||||
if (0 && 7 == $ct)
|
||||
{
|
||||
print STDERR "\n";
|
||||
print STDERR map{ "args> $_\n" }@args;
|
||||
print STDERR "\n";
|
||||
print STDERR map{ "exp> $_\n" }@exp;
|
||||
print STDERR "\n";
|
||||
print STDERR map{ "out> $_\n" }@out;
|
||||
}
|
||||
|
||||
ok("@out", "@exp", 'Failed on line ' . __LINE__ . ", dataset $ct");
|
||||
$ct++;
|
||||
}
|
||||
|
||||
} # check_uniq
|
||||
|
||||
###########################################################################
|
||||
## Intent: Smoke tests for the unittests module
|
||||
###########################################################################
|
||||
sub smoke
|
||||
{
|
||||
print STDERR "Running test: smoke()\n" if ($argv{debug});
|
||||
} # smoke()
|
||||
|
||||
###########################################################################
|
||||
## Intent: Intitialize global test objects and consts
|
||||
###########################################################################
|
||||
sub init
|
||||
{
|
||||
print "Running: init()\n" if ($argv{debug});
|
||||
# testplan(24, 0);
|
||||
} # init()
|
||||
|
||||
##----------------##
|
||||
##---] MAIN [---##
|
||||
##----------------##
|
||||
unless(GetOptions(\%argv,
|
||||
qw(
|
||||
debug|d
|
||||
manual
|
||||
test=s@
|
||||
verbose
|
||||
)))
|
||||
{
|
||||
print "USAGE: $0\n";
|
||||
print " --debug Enable script debug mode\n";
|
||||
print " --fail Force a testing failure condition\n";
|
||||
print " --manual Also run disabled tests\n";
|
||||
print " --smoke Run smoke tests then exit\n";
|
||||
print " --test Run a list of tests by function name\n";
|
||||
print " --verbose Enable script verbose mode\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
init();
|
||||
testbyname(@{ $argv{test} }) if ($argv{test});
|
||||
smoke();
|
||||
|
||||
check_uniq();
|
||||
ok(1, 0, 'Forced failure by command line arg --fail') if ($argv{fail});
|
||||
|
||||
# EOF
|
@ -1,91 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
# 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/.
|
||||
|
||||
##----------------------------##
|
||||
##---] CORE/CPAN INCLUDES [---##
|
||||
##----------------------------##
|
||||
use strict;
|
||||
use warnings;
|
||||
use Getopt::Long;
|
||||
|
||||
##-------------------##
|
||||
##---] EXPORTS [---##
|
||||
##-------------------##
|
||||
our $VERSION = qw(1.1);
|
||||
|
||||
##-------------------##
|
||||
##---] GLOBALS [---##
|
||||
##-------------------##
|
||||
my %argv;
|
||||
my $modver = $Getopt::Long::VERSION || 0;
|
||||
my $isOldGetopt = ($modver eq '2.25') ? 1 : 0;
|
||||
|
||||
###########################################################################
|
||||
## Intent: Script init function
|
||||
###########################################################################
|
||||
sub init
|
||||
{
|
||||
if ($isOldGetopt)
|
||||
{
|
||||
# mozilla.build/mingw perl in need of an upgrade
|
||||
# emulate Getopt::Long switch|short:init
|
||||
foreach (qw(debug regex sort))
|
||||
{
|
||||
if (defined($argv{$_}))
|
||||
{
|
||||
$argv{$_} ||= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} # init
|
||||
|
||||
##----------------##
|
||||
##---] MAIN [---##
|
||||
##----------------##
|
||||
my @args = ($isOldGetopt)
|
||||
? qw(debug|d regex|r sort|s)
|
||||
: qw(debug|d:1 regex|r:1 sort|s:1)
|
||||
;
|
||||
|
||||
unless(GetOptions(\%argv, @args))
|
||||
{
|
||||
print "Usage: $0\n";
|
||||
print " --sort Sort list elements early\n";
|
||||
print " --regex Exclude subdirs by pattern\n";
|
||||
}
|
||||
|
||||
init();
|
||||
my $debug = $argv{debug} || 0;
|
||||
|
||||
my %seen;
|
||||
my @out;
|
||||
my @in = ($argv{sort}) ? sort @ARGV : @ARGV;
|
||||
|
||||
foreach my $d (@in)
|
||||
{
|
||||
next if ($seen{$d}++);
|
||||
|
||||
print " arg is $d\n" if ($debug);
|
||||
|
||||
if ($argv{regex})
|
||||
{
|
||||
my $found = 0;
|
||||
foreach my $dir (@out)
|
||||
{
|
||||
my $dirM = quotemeta($dir);
|
||||
$found++, last if ($d eq $dir || $d =~ m!^${dirM}\/!);
|
||||
}
|
||||
print "Adding $d\n" if ($debug && !$found);
|
||||
push @out, $d if (!$found);
|
||||
} else {
|
||||
print "Adding: $d\n" if ($debug);
|
||||
push(@out, $d);
|
||||
}
|
||||
}
|
||||
|
||||
print "@out\n"
|
||||
|
||||
# EOF
|
7
testing/tools/screenshot/Makefile.in → build/unix/uniq.py
Normal file → Executable file
7
testing/tools/screenshot/Makefile.in → build/unix/uniq.py
Normal file → Executable file
@ -1,9 +1,10 @@
|
||||
#! /usr/bin/env python
|
||||
# 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/.
|
||||
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
|
||||
'''Prints the given arguments in sorted order with duplicates removed.'''
|
||||
|
||||
MOZ_GLUE_PROGRAM_LDFLAGS =
|
||||
import sys
|
||||
|
||||
endif # windows
|
||||
print(' '.join(sorted(set(sys.argv[1:]))))
|
@ -2,8 +2,6 @@
|
||||
# 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/.
|
||||
|
||||
MOZ_GLUE_LDFLAGS =
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
ifdef WIN32_REDIST_DIR
|
||||
|
@ -1,5 +0,0 @@
|
||||
# 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/.
|
||||
|
||||
MOZ_GLUE_LDFLAGS =
|
@ -1,5 +0,0 @@
|
||||
# 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/.
|
||||
|
||||
MOZ_GLUE_LDFLAGS =
|
@ -234,20 +234,10 @@ endif # NS_TRACE_MALLOC || MOZ_DMD
|
||||
|
||||
endif # MOZ_DEBUG
|
||||
|
||||
# We don't build a static CRT when building a custom CRT,
|
||||
# it appears to be broken. So don't link to jemalloc if
|
||||
# the Makefile wants static CRT linking.
|
||||
ifeq ($(MOZ_MEMORY)_$(USE_STATIC_LIBS),1_1)
|
||||
# Disable default CRT libs and add the right lib path for the linker
|
||||
MOZ_GLUE_LDFLAGS=
|
||||
endif
|
||||
|
||||
endif # WINNT && !GNU_CC
|
||||
|
||||
ifdef MOZ_GLUE_PROGRAM_LDFLAGS
|
||||
ifdef MOZ_GLUE_IN_PROGRAM
|
||||
DEFINES += -DMOZ_GLUE_IN_PROGRAM
|
||||
else
|
||||
MOZ_GLUE_PROGRAM_LDFLAGS=$(MOZ_GLUE_LDFLAGS)
|
||||
endif
|
||||
|
||||
#
|
||||
|
29
config/external/nss/Makefile.in
vendored
29
config/external/nss/Makefile.in
vendored
@ -108,11 +108,6 @@ NSPR_LIB_DIR := $(subst -L,,$(subst -L$(DIST),-L$(ABS_DIST),$(NSPR_LIB_DIR)))
|
||||
else
|
||||
NSPR_LIB_DIR = $(ABS_DIST)/lib
|
||||
endif
|
||||
# Can't pass this in DEFAULT_GMAKE_FLAGS because that overrides
|
||||
# definitions in NSS, so just export it into the sub-make's environment.
|
||||
ifeq (WINNT_1,$(OS_TARGET)_$(MOZ_MEMORY))
|
||||
export DLLFLAGS
|
||||
endif
|
||||
|
||||
# To get debug symbols from NSS
|
||||
export MOZ_DEBUG_SYMBOLS
|
||||
@ -222,9 +217,17 @@ endif
|
||||
endif
|
||||
|
||||
ifdef WRAP_LDFLAGS
|
||||
NSS_EXTRA_LDFLAGS += $(WRAP_LDFLAGS)
|
||||
endif
|
||||
|
||||
ifdef MOZ_GLUE_WRAP_LDFLAGS
|
||||
NSS_EXTRA_LDFLAGS += $(SHARED_LIBS:$(DEPTH)%=$(MOZ_BUILD_ROOT)%) $(MOZ_GLUE_WRAP_LDFLAGS)
|
||||
endif
|
||||
|
||||
ifneq (,$(WRAP_LDFLAGS)$(MOZ_GLUE_WRAP_LDFLAGS))
|
||||
DEFAULT_GMAKE_FLAGS += \
|
||||
LDFLAGS='$(LDFLAGS) $(WRAP_LDFLAGS)' \
|
||||
DSO_LDOPTS='$(DSO_LDOPTS) $(LDFLAGS) $(WRAP_LDFLAGS)' \
|
||||
LDFLAGS='$(LDFLAGS) $(NSS_EXTRA_LDFLAGS)' \
|
||||
DSO_LDOPTS='$(DSO_LDOPTS) $(LDFLAGS) $(NSS_EXTRA_LDFLAGS)' \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
@ -357,6 +360,18 @@ endif # MOZ_FOLD_LIBS
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
# Can't pass this in DEFAULT_GMAKE_FLAGS because that overrides
|
||||
# definitions in NSS, so just export it into the sub-make's environment.
|
||||
ifeq (WINNT_1,$(OS_TARGET)_$(MOZ_MEMORY))
|
||||
ifdef MOZ_CRT
|
||||
# OS_LIBS comes from having mozcrt as a dependency in moz.build.
|
||||
DLLFLAGS := $(OS_LIBS)
|
||||
else
|
||||
DLLFLAGS := -LIBPATH:$(ABS_DIST)/lib -DEFAULTLIB:mozglue
|
||||
endif
|
||||
export DLLFLAGS
|
||||
endif
|
||||
|
||||
ifdef MOZ_FOLD_LIBS
|
||||
# Force the linker to include everything from the static libraries.
|
||||
EXPAND_LIBS_EXEC += --extract
|
||||
|
2
config/external/nss/moz.build
vendored
2
config/external/nss/moz.build
vendored
@ -10,7 +10,7 @@ if CONFIG['MOZ_NATIVE_NSS']:
|
||||
Library('nss')
|
||||
OS_LIBS += CONFIG['NSS_LIBS']
|
||||
elif CONFIG['MOZ_FOLD_LIBS']:
|
||||
SharedLibrary('nss')
|
||||
GeckoSharedLibrary('nss', linkage=None)
|
||||
# TODO: The library name can be changed when bug 845217 is fixed.
|
||||
SHARED_LIBRARY_NAME = 'nss3'
|
||||
|
||||
|
7
config/external/sqlite/Makefile.in
vendored
7
config/external/sqlite/Makefile.in
vendored
@ -26,10 +26,3 @@ $(LD_VERSION_SCRIPT): $(topsrcdir)/db/sqlite3/src/sqlite.def
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
ifeq (Darwin,$(OS_TARGET))
|
||||
# On OSX, with jemalloc enabled, having sqlite linked against mozglue
|
||||
# causes crashes in NSS standalone tools.
|
||||
MOZ_GLUE_LDFLAGS =
|
||||
endif
|
||||
|
@ -1,57 +0,0 @@
|
||||
#! perl
|
||||
# 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/.
|
||||
|
||||
|
||||
# Converts a list of atoms in the form:
|
||||
# // OUTPUT_CLASS=<classname>
|
||||
# // MACRO_NAME=<macro>
|
||||
# <macroname>(atomName, "String")
|
||||
# <macroname>(atomName2, "String2")
|
||||
#
|
||||
# into a file suitable for gperf using static atoms
|
||||
#
|
||||
# usage:
|
||||
# make-atom-strings < file.h > file.gperf
|
||||
#
|
||||
# the lines in the C++ comments define two variables:
|
||||
# OUTPUT_CLASS is the class who has all the atoms as members
|
||||
# MACRO_NAME is the macro to look for in the rest of the file
|
||||
#
|
||||
# for example
|
||||
# // OUTPUT_CLASS=nsHTMLAtoms
|
||||
# // MACRO_NAME=HTML_ATOM
|
||||
# HTML_ATOM(a, "a")
|
||||
# HTML_ATOM(body, "body")
|
||||
#
|
||||
# etc...
|
||||
#
|
||||
# this will generate a file that looks like:
|
||||
# struct nsStaticAtom ( const char* mValue; nsIAtom** aAtom; }
|
||||
# %%
|
||||
# "a", &nsHTMLAtoms::a
|
||||
# "body", &nsHTMLAtoms::body
|
||||
#
|
||||
# etc...
|
||||
#
|
||||
# the output can be plugged into gperf to generate a perfect hash
|
||||
|
||||
print "struct nsStaticAtom {const char* mValue; nsIAtom** aAtom; };\n";
|
||||
print "%%\n";
|
||||
|
||||
my $classname, $macroname;
|
||||
|
||||
while (<>) {
|
||||
chop;
|
||||
if (/OUTPUT_CLASS=(\S+)/) {
|
||||
$classname=$1;
|
||||
} elsif (/MACRO_NAME=(\S+)/) {
|
||||
$macroname=$1;
|
||||
}
|
||||
elsif ($classname && $macroname &&
|
||||
/$macroname\((\S+),\s*\"(.*?)\"\s*\)/) {
|
||||
my ($str, $atom) = ($2, $1);
|
||||
print "\"$str\", (nsIAtom**)&${classname}::$atom\n";
|
||||
}
|
||||
}
|
@ -158,5 +158,8 @@ endif
|
||||
ifeq ($(MOZ_REPLACE_MALLOC_LINKAGE),dummy library)
|
||||
mozglue/build/target memory/replace/logalloc/replay/target: memory/replace/dummy/target
|
||||
endif
|
||||
ifdef MOZ_CRT
|
||||
mozglue/crt/target: mozglue/build/target
|
||||
endif
|
||||
|
||||
endif
|
||||
|
@ -641,8 +641,6 @@ endif
|
||||
|
||||
endif # NO_PROFILE_GUIDED_OPTIMIZE
|
||||
|
||||
MOZ_PROGRAM_LDFLAGS += $(MOZ_GLUE_PROGRAM_LDFLAGS)
|
||||
|
||||
##############################################
|
||||
|
||||
checkout:
|
||||
|
76
configure.in
76
configure.in
@ -514,10 +514,7 @@ case "$target" in
|
||||
if test -z "$CLANG_CL"; then
|
||||
AC_DEFINE(HAVE_SEH_EXCEPTIONS)
|
||||
else
|
||||
# Build on clang-cl with MSVC 2013 with fallback emulation.
|
||||
CFLAGS="$CFLAGS -fmsc-version=1800 -fallback"
|
||||
CXXFLAGS="$CXXFLAGS -fmsc-version=1800 -fallback"
|
||||
# Send our CFLAGS to NSS too
|
||||
# Send our CFLAGS to NSS
|
||||
MOZ_CFLAGS_NSS=1
|
||||
AC_DEFINE_UNQUOTED(GTEST_HAS_SEH, 0)
|
||||
fi
|
||||
@ -6273,7 +6270,7 @@ fi
|
||||
AC_SUBST(MOZ_GIO_COMPONENT)
|
||||
|
||||
dnl Remove dupes
|
||||
MOZ_EXTENSIONS=`${PERL} ${srcdir}/build/unix/uniq.pl ${MOZ_EXTENSIONS}`
|
||||
MOZ_EXTENSIONS=`$PYTHON ${srcdir}/build/unix/uniq.py ${MOZ_EXTENSIONS}`
|
||||
|
||||
dnl Ensure every extension exists, to avoid mostly-inscrutable error messages
|
||||
dnl when trying to build a nonexistent extension.
|
||||
@ -7075,28 +7072,15 @@ if test "$NS_TRACE_MALLOC"; then
|
||||
MOZ_MEMORY=
|
||||
fi
|
||||
|
||||
if test "${OS_TARGET}" = "Android"; then
|
||||
dnl On Android, we use WRAP_LDFLAGS to link everything to mozglue
|
||||
:
|
||||
elif test "${OS_TARGET}" = "WINNT" -o "${OS_TARGET}" = "Darwin"; then
|
||||
dnl On Windows and OSX, we want to link all our binaries against mozglue
|
||||
MOZ_GLUE_LDFLAGS='$(call EXPAND_LIBNAME_PATH,mozglue,$(LIBXUL_DIST)/lib)'
|
||||
else
|
||||
dnl On other Unix systems, we only want to link executables against mozglue
|
||||
MOZ_GLUE_PROGRAM_LDFLAGS='$(call EXPAND_LIBNAME_PATH,mozglue,$(LIBXUL_DIST)/lib)'
|
||||
dnl On other Unix systems, where mozglue is a static library, jemalloc is
|
||||
dnl separated for the SDK, so we need to add it here.
|
||||
if test "$MOZ_MEMORY" = 1 -o \( "$LIBXUL_SDK" -a -f "$LIBXUL_SDK/lib/${LIB_PREFIX}memory.${LIB_SUFFIX}" \); then
|
||||
MOZ_GLUE_PROGRAM_LDFLAGS="$MOZ_GLUE_PROGRAM_LDFLAGS "'$(call EXPAND_LIBNAME_PATH,memory,$(LIBXUL_DIST)/lib)'
|
||||
fi
|
||||
if test -n "$GNU_CC"; then
|
||||
dnl And we need mozglue symbols to be exported.
|
||||
MOZ_GLUE_PROGRAM_LDFLAGS="$MOZ_GLUE_PROGRAM_LDFLAGS -rdynamic"
|
||||
fi
|
||||
if test "$MOZ_LINKER" = 1; then
|
||||
MOZ_GLUE_PROGRAM_LDFLAGS="$MOZ_GLUE_PROGRAM_LDFLAGS $MOZ_ZLIB_LIBS"
|
||||
fi
|
||||
fi
|
||||
case "${OS_TARGET}" in
|
||||
Android|WINNT|Darwin)
|
||||
MOZ_GLUE_IN_PROGRAM=
|
||||
;;
|
||||
*)
|
||||
dnl On !Android !Windows !OSX, we only want to link executables against mozglue
|
||||
MOZ_GLUE_IN_PROGRAM=1
|
||||
;;
|
||||
esac
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable dynamic replacement of malloc implementation
|
||||
@ -7224,7 +7208,6 @@ else
|
||||
if test -n "$gonkdir"; then
|
||||
AC_DEFINE(MOZ_MEMORY_GONK)
|
||||
fi
|
||||
MOZ_GLUE_LDFLAGS=
|
||||
;;
|
||||
*-*linux*)
|
||||
AC_DEFINE(MOZ_MEMORY_LINUX)
|
||||
@ -7243,11 +7226,7 @@ else
|
||||
WIN32_CRTDLL_FULLPATH=`lib -nologo -list $WIN32_CRT_LIBS | grep crtdll\\.obj`
|
||||
lib -NOLOGO -OUT:crtdll.obj $WIN32_CRT_LIBS -EXTRACT:$WIN32_CRTDLL_FULLPATH
|
||||
if grep -q '__imp__\{0,1\}free' crtdll.obj; then
|
||||
MOZ_GLUE_LDFLAGS='-LIBPATH:$(DIST)/lib -NODEFAULTLIB:msvcrt -NODEFAULTLIB:msvcprt -DEFAULTLIB:mozcrt'
|
||||
dnl Also pass this to NSPR/NSS
|
||||
DLLFLAGS="$DLLFLAGS $MOZ_GLUE_LDFLAGS"
|
||||
else
|
||||
DLLFLAGS="$DLLFLAGS -LIBPATH:\$(DIST)/lib -DEFAULTLIB:mozglue"
|
||||
MOZ_CRT=1
|
||||
fi
|
||||
rm crtdll.obj
|
||||
;;
|
||||
@ -7259,22 +7238,23 @@ fi # MOZ_MEMORY
|
||||
AC_SUBST(MOZ_MEMORY)
|
||||
AC_SUBST(MOZ_JEMALLOC3)
|
||||
AC_SUBST(MOZ_NATIVE_JEMALLOC)
|
||||
AC_SUBST(MOZ_GLUE_LDFLAGS)
|
||||
AC_SUBST(MOZ_GLUE_PROGRAM_LDFLAGS)
|
||||
AC_SUBST(MOZ_CRT)
|
||||
export MOZ_CRT
|
||||
AC_SUBST(MOZ_GLUE_IN_PROGRAM)
|
||||
AC_SUBST_LIST(WIN32_CRT_LIBS)
|
||||
dnl Need to set this for make because NSS doesn't have configure
|
||||
AC_SUBST(DLLFLAGS)
|
||||
|
||||
dnl We need to wrap dlopen and related functions on Android because we use
|
||||
dnl our own linker.
|
||||
if test "$OS_TARGET" = Android; then
|
||||
WRAP_LDFLAGS="${WRAP_LDFLAGS} -L$_objdir/dist/lib -lmozglue"
|
||||
WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=PR_GetEnv,--wrap=PR_SetEnv"
|
||||
MOZ_GLUE_WRAP_LDFLAGS="${MOZ_GLUE_WRAP_LDFLAGS} -Wl,--wrap=PR_GetEnv,--wrap=PR_SetEnv"
|
||||
if test "$MOZ_WIDGET_TOOLKIT" = gonk -a -n "$MOZ_NUWA_PROCESS"; then
|
||||
WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=pthread_create,--wrap=epoll_wait,--wrap=poll,--wrap=pthread_cond_timedwait,--wrap=__pthread_cond_timedwait,--wrap=pthread_cond_wait,--wrap=epoll_create,--wrap=epoll_ctl,--wrap=close,--wrap=pthread_key_create,--wrap=pthread_key_delete,--wrap=socketpair,--wrap=pthread_self,--wrap=pthread_mutex_lock,--wrap=pthread_join,--wrap=pipe,--wrap=pipe2,--wrap=tgkill"
|
||||
MOZ_GLUE_WRAP_LDFLAGS="${MOZ_GLUE_WRAP_LDFLAGS} -Wl,--wrap=pthread_create,--wrap=epoll_wait,--wrap=poll,--wrap=pthread_cond_timedwait,--wrap=__pthread_cond_timedwait,--wrap=pthread_cond_wait,--wrap=epoll_create,--wrap=epoll_ctl,--wrap=close,--wrap=pthread_key_create,--wrap=pthread_key_delete,--wrap=socketpair,--wrap=pthread_self,--wrap=pthread_mutex_lock,--wrap=pthread_join,--wrap=pipe,--wrap=pipe2,--wrap=tgkill"
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_SUBST_LIST(MOZ_GLUE_WRAP_LDFLAGS)
|
||||
export MOZ_GLUE_WRAP_LDFLAGS
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Use JS Call tracing
|
||||
dnl ========================================================
|
||||
@ -8355,7 +8335,7 @@ MOZ_ARG_ENABLE_STRING(necko-protocols,
|
||||
done],
|
||||
NECKO_PROTOCOLS="$NECKO_PROTOCOLS_DEFAULT")
|
||||
dnl Remove dupes
|
||||
NECKO_PROTOCOLS=`${PERL} ${srcdir}/build/unix/uniq.pl ${NECKO_PROTOCOLS}`
|
||||
NECKO_PROTOCOLS=`$PYTHON ${srcdir}/build/unix/uniq.py ${NECKO_PROTOCOLS}`
|
||||
AC_SUBST_SET(NECKO_PROTOCOLS)
|
||||
for p in $NECKO_PROTOCOLS; do
|
||||
AC_DEFINE_UNQUOTED(NECKO_PROTOCOL_$p)
|
||||
@ -9203,8 +9183,11 @@ if test "$MOZ_TREE_FREETYPE"; then
|
||||
if ! test -e modules; then
|
||||
mkdir modules
|
||||
fi
|
||||
|
||||
AC_OUTPUT_SUBDIRS(modules/freetype2,$cache_file)
|
||||
# Only export CC and CXX for the subconfigure, and avoid spilling that
|
||||
# further down the road.
|
||||
(export CC CXX;
|
||||
AC_OUTPUT_SUBDIRS(modules/freetype2)
|
||||
) || exit 1
|
||||
fi
|
||||
|
||||
if test -z "$direct_nspr_config"; then
|
||||
@ -9303,11 +9286,8 @@ ac_configure_args="$ac_configure_args --prefix=$dist"
|
||||
if test "$MOZ_MEMORY"; then
|
||||
ac_configure_args="$ac_configure_args --enable-jemalloc"
|
||||
fi
|
||||
if test -n "$MOZ_GLUE_LDFLAGS"; then
|
||||
export MOZ_GLUE_LDFLAGS
|
||||
fi
|
||||
if test -n "$MOZ_GLUE_PROGRAM_LDFLAGS"; then
|
||||
export MOZ_GLUE_PROGRAM_LDFLAGS
|
||||
if test -n "$MOZ_GLUE_IN_PROGRAM"; then
|
||||
export MOZ_GLUE_IN_PROGRAM
|
||||
fi
|
||||
if test -n "$ZLIB_IN_MOZGLUE"; then
|
||||
MOZ_ZLIB_LIBS=
|
||||
|
@ -1,14 +1,16 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
# This script makes docshell test case templates. It takes one argument:
|
||||
#
|
||||
# gen_template.pl
|
||||
# Makes docshell test case templates.
|
||||
# Takes one argument:
|
||||
# -b: a bugnumber
|
||||
#
|
||||
# -b : a bugnumber
|
||||
# For example, this command:
|
||||
#
|
||||
# e.g.: perl gen_template.pl -b 303267
|
||||
# perl gen_template.pl -b 303267
|
||||
#
|
||||
# Writes test case template files for bug 303267 to the current directory.
|
||||
# Writes test case template files test_bug303267.xul and bug303267_window.xul
|
||||
# to the current directory.
|
||||
|
||||
use FindBin;
|
||||
use Getopt::Long;
|
||||
GetOptions("b=i"=> \$bug_number);
|
||||
|
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
CppUnitTests([
|
||||
GeckoCppUnitTests([
|
||||
'TestAudioChannelService',
|
||||
])
|
||||
|
||||
@ -14,10 +14,3 @@ if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
MOCHITEST_MANIFESTS += ['mochitest.ini']
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
USE_LIBS += [
|
||||
'mozalloc',
|
||||
'nspr',
|
||||
'xpcomglue_s',
|
||||
'xul',
|
||||
]
|
||||
|
@ -1195,7 +1195,7 @@ Console::ProcessCallData(ConsoleCallData* aData)
|
||||
JS::UndefinedHandleValue,
|
||||
JSPROP_ENUMERATE | JSPROP_SHARED | JSPROP_GETTER |
|
||||
JSPROP_SETTER,
|
||||
JS_DATA_TO_FUNC_PTR(JSPropertyOp, funObj.get()),
|
||||
JS_DATA_TO_FUNC_PTR(JSNative, funObj.get()),
|
||||
nullptr)) {
|
||||
return;
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIEVENTTARGET
|
||||
|
||||
WebSocketImpl(WebSocket* aWebSocket)
|
||||
explicit WebSocketImpl(WebSocket* aWebSocket)
|
||||
: mWebSocket(aWebSocket)
|
||||
, mOnCloseScheduled(false)
|
||||
, mFailed(false)
|
||||
@ -325,11 +325,19 @@ WebSocketImpl::PrintErrorOnConsole(const char *aBundleURI,
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = errorObject->InitWithWindowID(message,
|
||||
NS_ConvertUTF8toUTF16(mScriptFile),
|
||||
EmptyString(), mScriptLine, 0,
|
||||
nsIScriptError::errorFlag, "Web Socket",
|
||||
mInnerWindowID);
|
||||
if (mInnerWindowID) {
|
||||
rv = errorObject->InitWithWindowID(message,
|
||||
NS_ConvertUTF8toUTF16(mScriptFile),
|
||||
EmptyString(), mScriptLine, 0,
|
||||
nsIScriptError::errorFlag, "Web Socket",
|
||||
mInnerWindowID);
|
||||
} else {
|
||||
rv = errorObject->Init(message,
|
||||
NS_ConvertUTF8toUTF16(mScriptFile),
|
||||
EmptyString(), mScriptLine, 0,
|
||||
nsIScriptError::errorFlag, "Web Socket");
|
||||
}
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// print the error message directly to the JS console
|
||||
@ -463,7 +471,7 @@ namespace {
|
||||
class DisconnectInternalRunnable MOZ_FINAL : public WorkerMainThreadRunnable
|
||||
{
|
||||
public:
|
||||
DisconnectInternalRunnable(WebSocketImpl* aImpl)
|
||||
explicit DisconnectInternalRunnable(WebSocketImpl* aImpl)
|
||||
: WorkerMainThreadRunnable(aImpl->mWorkerPrivate)
|
||||
, mImpl(aImpl)
|
||||
{ }
|
||||
@ -866,20 +874,25 @@ public:
|
||||
}
|
||||
|
||||
nsPIDOMWindow* window = wp->GetWindow();
|
||||
if (!window) {
|
||||
mRv.Throw(NS_ERROR_FAILURE);
|
||||
return true;
|
||||
if (window) {
|
||||
return InitWithWindow(window);
|
||||
}
|
||||
|
||||
return InitWindowless();
|
||||
}
|
||||
|
||||
private:
|
||||
bool InitWithWindow(nsPIDOMWindow* aWindow)
|
||||
{
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(window))) {
|
||||
if (NS_WARN_IF(!jsapi.Init(aWindow))) {
|
||||
mRv.Throw(NS_ERROR_FAILURE);
|
||||
return true;
|
||||
}
|
||||
|
||||
ClearException ce(jsapi.cx());
|
||||
|
||||
nsIDocument* doc = window->GetExtantDoc();
|
||||
nsIDocument* doc = aWindow->GetExtantDoc();
|
||||
if (!doc) {
|
||||
mRv.Throw(NS_ERROR_FAILURE);
|
||||
return true;
|
||||
@ -896,7 +909,22 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool InitWindowless()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
WorkerPrivate* wp = mWorkerPrivate;
|
||||
while (wp->GetParent()) {
|
||||
wp = wp->GetParent();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!wp->GetWindow());
|
||||
|
||||
mImpl->Init(nullptr, wp->GetPrincipal(), mURL, mProtocolArray, mScriptFile,
|
||||
mScriptLine, mRv, mConnectionFailed);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Raw pointer. This worker runs synchronously.
|
||||
WebSocketImpl* mImpl;
|
||||
|
||||
@ -1036,7 +1064,7 @@ WebSocket::Constructor(const GlobalObject& aGlobal,
|
||||
class MOZ_STACK_CLASS ClearWebSocket
|
||||
{
|
||||
public:
|
||||
ClearWebSocket(WebSocketImpl* aWebSocketImpl)
|
||||
explicit ClearWebSocket(WebSocketImpl* aWebSocketImpl)
|
||||
: mWebSocketImpl(aWebSocketImpl)
|
||||
, mDone(false)
|
||||
{
|
||||
@ -1202,6 +1230,8 @@ WebSocketImpl::Init(JSContext* aCx,
|
||||
mScriptFile = aScriptFile;
|
||||
mScriptLine = aScriptLine;
|
||||
} else {
|
||||
MOZ_ASSERT(aCx);
|
||||
|
||||
unsigned lineno;
|
||||
JS::AutoFilename file;
|
||||
if (JS::DescribeScriptedCaller(aCx, &file, &lineno)) {
|
||||
@ -1210,8 +1240,12 @@ WebSocketImpl::Init(JSContext* aCx,
|
||||
}
|
||||
}
|
||||
|
||||
// Get WindowID
|
||||
mInnerWindowID = nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(aCx);
|
||||
// If we don't have aCx, we are window-less, so we don't have a
|
||||
// inner-windowID. This can happen in sharedWorkers and ServiceWorkers or in
|
||||
// DedicateWorkers created by JSM.
|
||||
if (aCx) {
|
||||
mInnerWindowID = nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(aCx);
|
||||
}
|
||||
|
||||
// parses the url
|
||||
aRv = ParseURL(PromiseFlatString(aURL));
|
||||
@ -1587,7 +1621,7 @@ namespace {
|
||||
class PrefEnabledRunnable MOZ_FINAL : public WorkerMainThreadRunnable
|
||||
{
|
||||
public:
|
||||
PrefEnabledRunnable(WorkerPrivate* aWorkerPrivate)
|
||||
explicit PrefEnabledRunnable(WorkerPrivate* aWorkerPrivate)
|
||||
: WorkerMainThreadRunnable(aWorkerPrivate)
|
||||
, mEnabled(false)
|
||||
{ }
|
||||
|
@ -1034,8 +1034,9 @@ nsDOMClassInfo::ResolveConstructor(JSContext *cx, JSObject *aObj,
|
||||
// return the Object constructor.
|
||||
|
||||
JS::Rooted<jsid> id(cx, sConstructor_id);
|
||||
if (!::JS_DefinePropertyById(cx, obj, id, val, JSPROP_ENUMERATE,
|
||||
JS_PropertyStub, JS_StrictPropertyStub)) {
|
||||
if (!::JS_DefinePropertyById(cx, obj, id, val,
|
||||
JSPROP_ENUMERATE,
|
||||
JS_STUBGETTER, JS_STUBSETTER)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
@ -1249,8 +1250,12 @@ nsDOMClassInfo::PostCreatePrototype(JSContext * cx, JSObject * aProto)
|
||||
if (!contentDefinedProperty && desc.object() && !desc.value().isUndefined() &&
|
||||
!JS_DefineUCProperty(cx, global, mData->mNameUTF16,
|
||||
NS_strlen(mData->mNameUTF16),
|
||||
desc.value(), desc.attributes(),
|
||||
desc.getter(), desc.setter())) {
|
||||
desc.value(),
|
||||
// Descriptors never store JSNatives for accessors:
|
||||
// they have either JSFunctions or JSPropertyOps.
|
||||
desc.attributes() | JSPROP_PROPOP_ACCESSORS,
|
||||
JS_PROPERTYOP_GETTER(desc.getter()),
|
||||
JS_PROPERTYOP_SETTER(desc.setter()))) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
@ -1451,9 +1456,8 @@ DefineInterfaceConstants(JSContext *cx, JS::Handle<JSObject*> obj, const nsIID *
|
||||
NS_ENSURE_TRUE(NS_SUCCEEDED(rv), rv);
|
||||
|
||||
if (!::JS_DefineProperty(cx, obj, name, v,
|
||||
JSPROP_ENUMERATE | JSPROP_READONLY |
|
||||
JSPROP_PERMANENT,
|
||||
JS_PropertyStub, JS_StrictPropertyStub)) {
|
||||
JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT,
|
||||
JS_STUBGETTER, JS_STUBSETTER)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
@ -2051,7 +2055,7 @@ ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
|
||||
if (!JS_WrapValue(cx, &v) ||
|
||||
!JS_DefineProperty(cx, class_obj, "prototype", v,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY,
|
||||
JS_PropertyStub, JS_StrictPropertyStub)) {
|
||||
JS_STUBGETTER, JS_STUBSETTER)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
@ -2510,7 +2514,7 @@ LookupComponentsShim(JSContext *cx, JS::Handle<JSObject*> global,
|
||||
bool ok =
|
||||
JS_DefineProperty(cx, components, "interfaces", interfaces,
|
||||
JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY,
|
||||
JS_PropertyStub, JS_StrictPropertyStub);
|
||||
JS_STUBGETTER, JS_STUBSETTER);
|
||||
NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
// Define a bunch of shims from the Ci.nsIDOMFoo to window.Foo for DOM
|
||||
@ -2533,7 +2537,7 @@ LookupComponentsShim(JSContext *cx, JS::Handle<JSObject*> global,
|
||||
// Define the shim on the interfaces object.
|
||||
ok = JS_DefineProperty(cx, interfaces, geckoName, v,
|
||||
JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY,
|
||||
JS_PropertyStub, JS_StrictPropertyStub);
|
||||
JS_STUBGETTER, JS_STUBSETTER);
|
||||
NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
|
@ -2591,8 +2591,9 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
||||
if (!aState) {
|
||||
JS::Rooted<JSObject*> rootedWrapper(cx, GetWrapperPreserveColor());
|
||||
if (!JS_DefineProperty(cx, newInnerGlobal, "window", rootedWrapper,
|
||||
JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT,
|
||||
JS_PropertyStub, JS_StrictPropertyStub)) {
|
||||
JSPROP_ENUMERATE | JSPROP_READONLY |
|
||||
JSPROP_PERMANENT,
|
||||
JS_STUBGETTER, JS_STUBSETTER)) {
|
||||
NS_ERROR("can't create the 'window' property");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -4528,7 +4529,7 @@ nsGlobalWindow::SetOpener(JSContext* aCx, JS::Handle<JS::Value> aOpener,
|
||||
|
||||
if (!JS_WrapObject(aCx, &thisObj) ||
|
||||
!JS_DefineProperty(aCx, thisObj, "opener", aOpener, JSPROP_ENUMERATE,
|
||||
JS_PropertyStub, JS_StrictPropertyStub)) {
|
||||
JS_STUBGETTER, JS_STUBSETTER)) {
|
||||
aError.Throw(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
@ -14022,9 +14023,8 @@ nsGlobalWindow::SetConsole(JSContext* aCx, JS::Handle<JS::Value> aValue)
|
||||
}
|
||||
|
||||
if (!JS_WrapObject(aCx, &thisObj) ||
|
||||
!JS_DefineProperty(aCx, thisObj, "console", aValue,
|
||||
JSPROP_ENUMERATE, JS_PropertyStub,
|
||||
JS_StrictPropertyStub)) {
|
||||
!JS_DefineProperty(aCx, thisObj, "console", aValue, JSPROP_ENUMERATE,
|
||||
JS_STUBGETTER, JS_STUBSETTER)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
|
||||
if CONFIG['OS_ARCH'] != 'Darwin':
|
||||
XPCSHELL_TESTS_MANIFESTS += ['unit_ipc/xpcshell.ini']
|
||||
|
||||
CppUnitTests([
|
||||
GeckoCppUnitTests([
|
||||
'TestCSPParser',
|
||||
'TestGetURL',
|
||||
'TestNativeXMLHttpRequest',
|
||||
@ -38,10 +38,3 @@ MOCHITEST_CHROME_MANIFESTS += [
|
||||
]
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
||||
|
||||
USE_LIBS += [
|
||||
'mozalloc',
|
||||
'nspr',
|
||||
'xpcomglue_s',
|
||||
'xul',
|
||||
]
|
||||
|
@ -528,8 +528,9 @@ CreateInterfaceObject(JSContext* cx, JS::Handle<JSObject*> global,
|
||||
namedConstructors->mNargs));
|
||||
if (!namedConstructor ||
|
||||
!JS_DefineProperty(cx, namedConstructor, "prototype",
|
||||
proto, JSPROP_PERMANENT | JSPROP_READONLY,
|
||||
JS_PropertyStub, JS_StrictPropertyStub) ||
|
||||
proto,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY,
|
||||
JS_STUBGETTER, JS_STUBSETTER) ||
|
||||
(defineOnGlobal &&
|
||||
!DefineConstructor(cx, global, namedConstructors->mName,
|
||||
namedConstructor))) {
|
||||
@ -968,24 +969,24 @@ XrayResolveAttribute(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
||||
// Because of centralization, we need to make sure we fault in the
|
||||
// JitInfos as well. At present, until the JSAPI changes, the easiest
|
||||
// way to do this is wrap them up as functions ourselves.
|
||||
desc.setAttributes(attrSpec.flags & ~JSPROP_NATIVE_ACCESSORS);
|
||||
desc.setAttributes(attrSpec.flags);
|
||||
// They all have getters, so we can just make it.
|
||||
JS::Rooted<JSFunction*> fun(cx,
|
||||
JS_NewFunctionById(cx, (JSNative)attrSpec.getter.propertyOp.op,
|
||||
JS_NewFunctionById(cx, attrSpec.getter.native.op,
|
||||
0, 0, wrapper, id));
|
||||
if (!fun)
|
||||
return false;
|
||||
SET_JITINFO(fun, attrSpec.getter.propertyOp.info);
|
||||
SET_JITINFO(fun, attrSpec.getter.native.info);
|
||||
JSObject *funobj = JS_GetFunctionObject(fun);
|
||||
desc.setGetterObject(funobj);
|
||||
desc.attributesRef() |= JSPROP_GETTER;
|
||||
if (attrSpec.setter.propertyOp.op) {
|
||||
if (attrSpec.setter.native.op) {
|
||||
// We have a setter! Make it.
|
||||
fun = JS_NewFunctionById(cx, (JSNative)attrSpec.setter.propertyOp.op, 1, 0,
|
||||
fun = JS_NewFunctionById(cx, attrSpec.setter.native.op, 1, 0,
|
||||
wrapper, id);
|
||||
if (!fun)
|
||||
return false;
|
||||
SET_JITINFO(fun, attrSpec.setter.propertyOp.info);
|
||||
SET_JITINFO(fun, attrSpec.setter.native.info);
|
||||
funobj = JS_GetFunctionObject(fun);
|
||||
desc.setSetterObject(funobj);
|
||||
desc.attributesRef() |= JSPROP_SETTER;
|
||||
|
@ -2412,7 +2412,7 @@ class AttrDefiner(PropertyDefiner):
|
||||
|
||||
def flags(attr):
|
||||
unforgeable = " | JSPROP_PERMANENT" if self.unforgeable else ""
|
||||
return ("JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_NATIVE_ACCESSORS" +
|
||||
return ("JSPROP_SHARED | JSPROP_ENUMERATE" +
|
||||
unforgeable)
|
||||
|
||||
def getter(attr):
|
||||
@ -2430,14 +2430,14 @@ class AttrDefiner(PropertyDefiner):
|
||||
accessor = "GenericBindingGetter"
|
||||
jitinfo = ("&%s_getterinfo" %
|
||||
IDLToCIdentifier(attr.identifier.name))
|
||||
return "{ { JS_CAST_NATIVE_TO(%s, JSPropertyOp), %s } }" % \
|
||||
return "{ { %s, %s } }" % \
|
||||
(accessor, jitinfo)
|
||||
|
||||
def setter(attr):
|
||||
if (attr.readonly and
|
||||
attr.getExtendedAttribute("PutForwards") is None and
|
||||
attr.getExtendedAttribute("Replaceable") is None):
|
||||
return "JSOP_NULLWRAPPER"
|
||||
return "JSNATIVE_WRAPPER(nullptr)"
|
||||
if self.static:
|
||||
accessor = 'set_' + IDLToCIdentifier(attr.identifier.name)
|
||||
jitinfo = "nullptr"
|
||||
@ -2451,7 +2451,7 @@ class AttrDefiner(PropertyDefiner):
|
||||
else:
|
||||
accessor = "GenericBindingSetter"
|
||||
jitinfo = "&%s_setterinfo" % IDLToCIdentifier(attr.identifier.name)
|
||||
return "{ { JS_CAST_NATIVE_TO(%s, JSStrictPropertyOp), %s } }" % \
|
||||
return "{ { %s, %s } }" % \
|
||||
(accessor, jitinfo)
|
||||
|
||||
def specData(attr):
|
||||
@ -7631,8 +7631,9 @@ class CGNewResolveHook(CGAbstractBindingMethod):
|
||||
// define it.
|
||||
if (!desc.value().isUndefined() &&
|
||||
!JS_DefinePropertyById(cx, obj, id, desc.value(),
|
||||
desc.attributes(),
|
||||
desc.getter(), desc.setter())) {
|
||||
desc.attributes() | JSPROP_PROPOP_ACCESSORS,
|
||||
JS_PROPERTYOP_GETTER(desc.getter()),
|
||||
JS_PROPERTYOP_SETTER(desc.setter()))) {
|
||||
return false;
|
||||
}
|
||||
objp.set(obj);
|
||||
@ -9603,8 +9604,9 @@ class CGResolveOwnPropertyViaNewresolve(CGAbstractBindingMethod):
|
||||
if (objDesc.object() &&
|
||||
!objDesc.value().isUndefined() &&
|
||||
!JS_DefinePropertyById(cx, obj, id, objDesc.value(),
|
||||
objDesc.attributes(),
|
||||
objDesc.getter(), objDesc.setter())) {
|
||||
objDesc.attributes() | JSPROP_PROPOP_ACCESSORS,
|
||||
JS_PROPERTYOP_GETTER(objDesc.getter()),
|
||||
JS_PROPERTYOP_SETTER(objDesc.setter()))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -610,172 +610,180 @@ public:
|
||||
|
||||
}
|
||||
|
||||
void Uniform1i(WebGLUniformLocation* location, GLint x);
|
||||
void Uniform2i(WebGLUniformLocation* location, GLint x, GLint y);
|
||||
void Uniform3i(WebGLUniformLocation* location, GLint x, GLint y,
|
||||
GLint z);
|
||||
void Uniform4i(WebGLUniformLocation* location, GLint x, GLint y,
|
||||
GLint z, GLint w);
|
||||
void Uniform1i(WebGLUniformLocation* loc, GLint x);
|
||||
void Uniform2i(WebGLUniformLocation* loc, GLint x, GLint y);
|
||||
void Uniform3i(WebGLUniformLocation* loc, GLint x, GLint y, GLint z);
|
||||
void Uniform4i(WebGLUniformLocation* loc, GLint x, GLint y, GLint z,
|
||||
GLint w);
|
||||
|
||||
void Uniform1f(WebGLUniformLocation* location, GLfloat x);
|
||||
void Uniform2f(WebGLUniformLocation* location, GLfloat x, GLfloat y);
|
||||
void Uniform3f(WebGLUniformLocation* location, GLfloat x, GLfloat y,
|
||||
GLfloat z);
|
||||
void Uniform4f(WebGLUniformLocation* location, GLfloat x, GLfloat y,
|
||||
GLfloat z, GLfloat w);
|
||||
void Uniform1f(WebGLUniformLocation* loc, GLfloat x);
|
||||
void Uniform2f(WebGLUniformLocation* loc, GLfloat x, GLfloat y);
|
||||
void Uniform3f(WebGLUniformLocation* loc, GLfloat x, GLfloat y, GLfloat z);
|
||||
void Uniform4f(WebGLUniformLocation* loc, GLfloat x, GLfloat y, GLfloat z,
|
||||
GLfloat w);
|
||||
|
||||
void Uniform1iv(WebGLUniformLocation* location,
|
||||
const dom::Int32Array& arr) {
|
||||
// Int array
|
||||
void Uniform1iv(WebGLUniformLocation* loc, const dom::Int32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform1iv_base(location, arr.Length(), arr.Data());
|
||||
Uniform1iv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform1iv(WebGLUniformLocation* location,
|
||||
const dom::Sequence<GLint>& arr) {
|
||||
Uniform1iv_base(location, arr.Length(), arr.Elements());
|
||||
void Uniform1iv(WebGLUniformLocation* loc,
|
||||
const dom::Sequence<GLint>& arr)
|
||||
{
|
||||
Uniform1iv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform1iv_base(WebGLUniformLocation* location, uint32_t arrayLength,
|
||||
void Uniform1iv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLint* data);
|
||||
|
||||
void Uniform2iv(WebGLUniformLocation* location,
|
||||
const dom::Int32Array& arr) {
|
||||
void Uniform2iv(WebGLUniformLocation* loc, const dom::Int32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform2iv_base(location, arr.Length(), arr.Data());
|
||||
Uniform2iv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform2iv(WebGLUniformLocation* location,
|
||||
const dom::Sequence<GLint>& arr) {
|
||||
Uniform2iv_base(location, arr.Length(), arr.Elements());
|
||||
void Uniform2iv(WebGLUniformLocation* loc,
|
||||
const dom::Sequence<GLint>& arr)
|
||||
{
|
||||
Uniform2iv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform2iv_base(WebGLUniformLocation* location, uint32_t arrayLength,
|
||||
void Uniform2iv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLint* data);
|
||||
|
||||
void Uniform3iv(WebGLUniformLocation* location,
|
||||
const dom::Int32Array& arr) {
|
||||
void Uniform3iv(WebGLUniformLocation* loc, const dom::Int32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform3iv_base(location, arr.Length(), arr.Data());
|
||||
Uniform3iv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform3iv(WebGLUniformLocation* location,
|
||||
const dom::Sequence<GLint>& arr) {
|
||||
Uniform3iv_base(location, arr.Length(), arr.Elements());
|
||||
void Uniform3iv(WebGLUniformLocation* loc,
|
||||
const dom::Sequence<GLint>& arr)
|
||||
{
|
||||
Uniform3iv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform3iv_base(WebGLUniformLocation* location, uint32_t arrayLength,
|
||||
void Uniform3iv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLint* data);
|
||||
|
||||
void Uniform4iv(WebGLUniformLocation* location,
|
||||
const dom::Int32Array& arr) {
|
||||
void Uniform4iv(WebGLUniformLocation* loc, const dom::Int32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform4iv_base(location, arr.Length(), arr.Data());
|
||||
Uniform4iv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform4iv(WebGLUniformLocation* location,
|
||||
const dom::Sequence<GLint>& arr) {
|
||||
Uniform4iv_base(location, arr.Length(), arr.Elements());
|
||||
void Uniform4iv(WebGLUniformLocation* loc,
|
||||
const dom::Sequence<GLint>& arr)
|
||||
{
|
||||
Uniform4iv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform4iv_base(WebGLUniformLocation* location, uint32_t arrayLength,
|
||||
void Uniform4iv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLint* data);
|
||||
|
||||
void Uniform1fv(WebGLUniformLocation* location,
|
||||
const dom::Float32Array& arr) {
|
||||
// Float array
|
||||
void Uniform1fv(WebGLUniformLocation* loc, const dom::Float32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform1fv_base(location, arr.Length(), arr.Data());
|
||||
Uniform1fv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform1fv(WebGLUniformLocation* location,
|
||||
const dom::Sequence<GLfloat>& arr) {
|
||||
Uniform1fv_base(location, arr.Length(), arr.Elements());
|
||||
void Uniform1fv(WebGLUniformLocation* loc,
|
||||
const dom::Sequence<GLfloat>& arr)
|
||||
{
|
||||
Uniform1fv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform1fv_base(WebGLUniformLocation* location, uint32_t arrayLength,
|
||||
void Uniform1fv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLfloat* data);
|
||||
|
||||
void Uniform2fv(WebGLUniformLocation* location,
|
||||
const dom::Float32Array& arr) {
|
||||
void Uniform2fv(WebGLUniformLocation* loc, const dom::Float32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform2fv_base(location, arr.Length(), arr.Data());
|
||||
Uniform2fv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform2fv(WebGLUniformLocation* location,
|
||||
const dom::Sequence<GLfloat>& arr) {
|
||||
Uniform2fv_base(location, arr.Length(), arr.Elements());
|
||||
void Uniform2fv(WebGLUniformLocation* loc,
|
||||
const dom::Sequence<GLfloat>& arr)
|
||||
{
|
||||
Uniform2fv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform2fv_base(WebGLUniformLocation* location, uint32_t arrayLength,
|
||||
void Uniform2fv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLfloat* data);
|
||||
|
||||
void Uniform3fv(WebGLUniformLocation* location,
|
||||
const dom::Float32Array& arr) {
|
||||
void Uniform3fv(WebGLUniformLocation* loc, const dom::Float32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform3fv_base(location, arr.Length(), arr.Data());
|
||||
Uniform3fv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform3fv(WebGLUniformLocation* location,
|
||||
const dom::Sequence<GLfloat>& arr) {
|
||||
Uniform3fv_base(location, arr.Length(), arr.Elements());
|
||||
void Uniform3fv(WebGLUniformLocation* loc,
|
||||
const dom::Sequence<GLfloat>& arr)
|
||||
{
|
||||
Uniform3fv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform3fv_base(WebGLUniformLocation* location, uint32_t arrayLength,
|
||||
void Uniform3fv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLfloat* data);
|
||||
|
||||
void Uniform4fv(WebGLUniformLocation* location,
|
||||
const dom::Float32Array& arr) {
|
||||
void Uniform4fv(WebGLUniformLocation* loc, const dom::Float32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform4fv_base(location, arr.Length(), arr.Data());
|
||||
Uniform4fv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform4fv(WebGLUniformLocation* location,
|
||||
const dom::Sequence<GLfloat>& arr) {
|
||||
Uniform4fv_base(location, arr.Length(), arr.Elements());
|
||||
void Uniform4fv(WebGLUniformLocation* loc,
|
||||
const dom::Sequence<GLfloat>& arr)
|
||||
{
|
||||
Uniform4fv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform4fv_base(WebGLUniformLocation* location, uint32_t arrayLength,
|
||||
void Uniform4fv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLfloat* data);
|
||||
|
||||
void UniformMatrix2fv(WebGLUniformLocation* location,
|
||||
WebGLboolean transpose,
|
||||
const dom::Float32Array &value) {
|
||||
// Matrix
|
||||
void UniformMatrix2fv(WebGLUniformLocation* loc, WebGLboolean transpose,
|
||||
const dom::Float32Array& value)
|
||||
{
|
||||
value.ComputeLengthAndData();
|
||||
UniformMatrix2fv_base(location, transpose, value.Length(), value.Data());
|
||||
UniformMatrix2fv_base(loc, transpose, value.Length(), value.Data());
|
||||
}
|
||||
void UniformMatrix2fv(WebGLUniformLocation* location,
|
||||
WebGLboolean transpose,
|
||||
const dom::Sequence<float> &value) {
|
||||
UniformMatrix2fv_base(location, transpose, value.Length(),
|
||||
void UniformMatrix2fv(WebGLUniformLocation* loc, WebGLboolean transpose,
|
||||
const dom::Sequence<float>& value)
|
||||
{
|
||||
UniformMatrix2fv_base(loc, transpose, value.Length(),
|
||||
value.Elements());
|
||||
}
|
||||
void UniformMatrix2fv_base(WebGLUniformLocation* location,
|
||||
WebGLboolean transpose, uint32_t arrayLength,
|
||||
void UniformMatrix2fv_base(WebGLUniformLocation* loc,
|
||||
WebGLboolean transpose, size_t arrayLength,
|
||||
const float* data);
|
||||
|
||||
void UniformMatrix3fv(WebGLUniformLocation* location,
|
||||
WebGLboolean transpose,
|
||||
const dom::Float32Array &value) {
|
||||
void UniformMatrix3fv(WebGLUniformLocation* loc, WebGLboolean transpose,
|
||||
const dom::Float32Array& value)
|
||||
{
|
||||
value.ComputeLengthAndData();
|
||||
UniformMatrix3fv_base(location, transpose, value.Length(), value.Data());
|
||||
UniformMatrix3fv_base(loc, transpose, value.Length(), value.Data());
|
||||
}
|
||||
void UniformMatrix3fv(WebGLUniformLocation* location,
|
||||
WebGLboolean transpose,
|
||||
const dom::Sequence<float> &value) {
|
||||
UniformMatrix3fv_base(location, transpose, value.Length(),
|
||||
value.Elements());
|
||||
void UniformMatrix3fv(WebGLUniformLocation* loc, WebGLboolean transpose,
|
||||
const dom::Sequence<float>& value)
|
||||
{
|
||||
UniformMatrix3fv_base(loc, transpose, value.Length(), value.Elements());
|
||||
}
|
||||
void UniformMatrix3fv_base(WebGLUniformLocation* location,
|
||||
WebGLboolean transpose, uint32_t arrayLength,
|
||||
void UniformMatrix3fv_base(WebGLUniformLocation* loc,
|
||||
WebGLboolean transpose, size_t arrayLength,
|
||||
const float* data);
|
||||
|
||||
void UniformMatrix4fv(WebGLUniformLocation* location,
|
||||
WebGLboolean transpose,
|
||||
const dom::Float32Array &value) {
|
||||
void UniformMatrix4fv(WebGLUniformLocation* loc, WebGLboolean transpose,
|
||||
const dom::Float32Array& value)
|
||||
{
|
||||
value.ComputeLengthAndData();
|
||||
UniformMatrix4fv_base(location, transpose, value.Length(), value.Data());
|
||||
UniformMatrix4fv_base(loc, transpose, value.Length(), value.Data());
|
||||
}
|
||||
void UniformMatrix4fv(WebGLUniformLocation* location,
|
||||
WebGLboolean transpose,
|
||||
const dom::Sequence<float> &value) {
|
||||
UniformMatrix4fv_base(location, transpose, value.Length(),
|
||||
void UniformMatrix4fv(WebGLUniformLocation* loc, WebGLboolean transpose,
|
||||
const dom::Sequence<float>& value)
|
||||
{
|
||||
UniformMatrix4fv_base(loc, transpose, value.Length(),
|
||||
value.Elements());
|
||||
}
|
||||
void UniformMatrix4fv_base(WebGLUniformLocation* location,
|
||||
WebGLboolean transpose, uint32_t arrayLength,
|
||||
void UniformMatrix4fv_base(WebGLUniformLocation* loc,
|
||||
WebGLboolean transpose, size_t arrayLength,
|
||||
const float* data);
|
||||
|
||||
void UseProgram(WebGLProgram *prog);
|
||||
bool ValidateAttribArraySetter(const char* name, uint32_t cnt, uint32_t arrayLength);
|
||||
bool ValidateUniformArraySetter(const char* name, uint32_t expectedElemSize, WebGLUniformLocation *location_object,
|
||||
GLint& location, uint32_t& numElementsToUpload, uint32_t arrayLength);
|
||||
bool ValidateUniformMatrixArraySetter(const char* name, int dim, WebGLUniformLocation *location_object,
|
||||
GLint& location, uint32_t& numElementsToUpload, uint32_t arrayLength,
|
||||
WebGLboolean aTranspose);
|
||||
bool ValidateUniformSetter(const char* name, WebGLUniformLocation *location_object, GLint& location);
|
||||
bool ValidateUniformSetter(WebGLUniformLocation* loc, uint8_t setterSize,
|
||||
GLenum setterType, const char* info,
|
||||
GLuint* out_rawLoc);
|
||||
bool ValidateUniformArraySetter(WebGLUniformLocation* loc,
|
||||
uint8_t setterElemSize, GLenum setterType,
|
||||
size_t setterArraySize, const char* info,
|
||||
GLuint* out_rawLoc,
|
||||
GLsizei* out_numElementsToUpload);
|
||||
bool ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
|
||||
uint8_t setterDims, GLenum setterType,
|
||||
size_t setterArraySize,
|
||||
bool setterTranspose,
|
||||
const char* info, GLuint* out_rawLoc,
|
||||
GLsizei* out_numElementsToUpload);
|
||||
void ValidateProgram(WebGLProgram *prog);
|
||||
bool ValidateUniformLocation(const char* info, WebGLUniformLocation *location_object);
|
||||
bool ValidateSamplerUniformSetter(const char* info,
|
||||
@ -1047,6 +1055,12 @@ protected:
|
||||
int32_t mGLMaxDrawBuffers;
|
||||
uint32_t mGLMaxTransformFeedbackSeparateAttribs;
|
||||
|
||||
public:
|
||||
GLuint MaxVertexAttribs() const {
|
||||
return mGLMaxVertexAttribs;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Represents current status of the context with respect to context loss.
|
||||
// That is, whether the context is lost, and what part of the context loss
|
||||
// process we currently are at.
|
||||
@ -1115,7 +1129,6 @@ protected:
|
||||
WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims);
|
||||
bool ValidateDrawModeEnum(GLenum mode, const char *info);
|
||||
bool ValidateAttribIndex(GLuint index, const char *info);
|
||||
bool ValidateStencilParamsForDrawCall();
|
||||
|
||||
bool ValidateGLSLVariableName(const nsAString& name, const char *info);
|
||||
|
@ -120,9 +120,8 @@ WebGLContext::AttachShader(WebGLProgram *program, WebGLShader *shader)
|
||||
return ErrorInvalidOperation("attachShader: shader is already attached");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WebGLContext::BindAttribLocation(WebGLProgram *prog, GLuint location,
|
||||
WebGLContext::BindAttribLocation(WebGLProgram* prog, GLuint location,
|
||||
const nsAString& name)
|
||||
{
|
||||
if (IsContextLost())
|
||||
@ -136,11 +135,15 @@ WebGLContext::BindAttribLocation(WebGLProgram *prog, GLuint location,
|
||||
if (!ValidateGLSLVariableName(name, "bindAttribLocation"))
|
||||
return;
|
||||
|
||||
if (!ValidateAttribIndex(location, "bindAttribLocation"))
|
||||
return;
|
||||
if (location >= MaxVertexAttribs()) {
|
||||
return ErrorInvalidValue("bindAttribLocation: `location` must be less"
|
||||
" than MAX_VERTEX_ATTRIBS.");
|
||||
}
|
||||
|
||||
if (StringBeginsWith(name, NS_LITERAL_STRING("gl_")))
|
||||
return ErrorInvalidOperation("bindAttribLocation: can't set the location of a name that starts with 'gl_'");
|
||||
return ErrorInvalidOperation("bindAttribLocation: can't set the"
|
||||
" location of a name that starts with"
|
||||
" 'gl_'.");
|
||||
|
||||
NS_LossyConvertUTF16toASCII cname(name);
|
||||
nsCString mappedName;
|
||||
@ -427,6 +430,17 @@ WebGLContext::CopyTexSubImage2D_base(TexImageTarget texImageTarget,
|
||||
// this should never fail, validation happened earlier.
|
||||
MOZ_ASSERT(effectiveInternalFormat != LOCAL_GL_NONE);
|
||||
|
||||
const bool widthOrHeightIsZero = (width == 0 || height == 0);
|
||||
if (gl->WorkAroundDriverBugs() &&
|
||||
sub && widthOrHeightIsZero)
|
||||
{
|
||||
// NV driver on Linux complains that CopyTexSubImage2D(level=0,
|
||||
// xoffset=0, yoffset=2, x=0, y=0, width=0, height=0) from a 300x150 FB
|
||||
// to a 0x2 texture. This a useless thing to do, but technically legal.
|
||||
// NV331.38 generates INVALID_VALUE.
|
||||
return DummyFramebufferOperation(info);
|
||||
}
|
||||
|
||||
// check if the memory size of this texture may change with this call
|
||||
bool sizeMayChange = !sub;
|
||||
if (!sub && tex->HasImageInfoAt(texImageTarget, level)) {
|
||||
@ -879,9 +893,19 @@ WebGLContext::GetActiveAttrib(WebGLProgram *prog, uint32_t index)
|
||||
return nullptr;
|
||||
|
||||
MakeContextCurrent();
|
||||
GLuint progname = prog->GLName();
|
||||
|
||||
GLuint activeAttribs = 0;
|
||||
gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_ATTRIBUTES,
|
||||
(GLint*)&activeAttribs);
|
||||
if (index >= activeAttribs) {
|
||||
ErrorInvalidValue("`index` (%i) must be less than ACTIVE_ATTRIBUTES"
|
||||
" (%i).",
|
||||
index, activeAttribs);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GLint len = 0;
|
||||
GLuint progname = prog->GLName();;
|
||||
gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &len);
|
||||
if (len == 0)
|
||||
return nullptr;
|
||||
@ -977,9 +1001,19 @@ WebGLContext::GetActiveUniform(WebGLProgram *prog, uint32_t index)
|
||||
return nullptr;
|
||||
|
||||
MakeContextCurrent();
|
||||
GLuint progname = prog->GLName();
|
||||
|
||||
GLuint activeUniforms = 0;
|
||||
gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_UNIFORMS,
|
||||
(GLint*)&activeUniforms);
|
||||
if (index >= activeUniforms) {
|
||||
ErrorInvalidValue("`index` (%i) must be less than ACTIVE_UNIFORMS"
|
||||
" (%i).",
|
||||
index, activeUniforms);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GLint len = 0;
|
||||
GLuint progname = prog->GLName();
|
||||
gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH, &len);
|
||||
if (len == 0)
|
||||
return nullptr;
|
||||
@ -1069,8 +1103,14 @@ WebGLContext::GetBufferParameter(GLenum target, GLenum pname)
|
||||
if (IsContextLost())
|
||||
return JS::NullValue();
|
||||
|
||||
if (target != LOCAL_GL_ARRAY_BUFFER && target != LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
|
||||
ErrorInvalidEnumInfo("getBufferParameter: target", target);
|
||||
|
||||
WebGLRefPtr<WebGLBuffer>* slot = GetBufferSlotByTarget(target,
|
||||
"getBufferParameter");
|
||||
if (!slot)
|
||||
return JS::NullValue();
|
||||
|
||||
if (!*slot) {
|
||||
ErrorInvalidOperation("No buffer bound to `target` (0x%4x).", target);
|
||||
return JS::NullValue();
|
||||
}
|
||||
|
||||
@ -2690,286 +2730,322 @@ WebGLContext::SurfaceFromElementResultToImageSurface(nsLayoutUtils::SurfaceFromE
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Uniform setters.
|
||||
|
||||
void
|
||||
WebGLContext::Uniform1i(WebGLUniformLocation *location_object, GLint a1)
|
||||
WebGLContext::Uniform1i(WebGLUniformLocation* loc, GLint a1)
|
||||
{
|
||||
GLint location;
|
||||
if (!ValidateUniformSetter("Uniform1i", location_object, location))
|
||||
GLuint rawLoc;
|
||||
if (!ValidateUniformSetter(loc, 1, LOCAL_GL_INT, "uniform1i", &rawLoc))
|
||||
return;
|
||||
|
||||
// Only uniform1i can take sampler settings.
|
||||
if (!ValidateSamplerUniformSetter("Uniform1i", location_object, a1))
|
||||
if (!ValidateSamplerUniformSetter("Uniform1i", loc, a1))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform1i(location, a1);
|
||||
gl->fUniform1i(rawLoc, a1);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::Uniform2i(WebGLUniformLocation *location_object, GLint a1,
|
||||
GLint a2)
|
||||
WebGLContext::Uniform2i(WebGLUniformLocation* loc, GLint a1, GLint a2)
|
||||
{
|
||||
GLint location;
|
||||
if (!ValidateUniformSetter("Uniform2i", location_object, location))
|
||||
GLuint rawLoc;
|
||||
if (!ValidateUniformSetter(loc, 2, LOCAL_GL_INT, "uniform2i", &rawLoc))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform2i(location, a1, a2);
|
||||
gl->fUniform2i(rawLoc, a1, a2);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::Uniform3i(WebGLUniformLocation *location_object, GLint a1,
|
||||
GLint a2, GLint a3)
|
||||
WebGLContext::Uniform3i(WebGLUniformLocation* loc, GLint a1, GLint a2, GLint a3)
|
||||
{
|
||||
GLint location;
|
||||
if (!ValidateUniformSetter("Uniform3i", location_object, location))
|
||||
GLuint rawLoc;
|
||||
if (!ValidateUniformSetter(loc, 3, LOCAL_GL_INT, "uniform3i", &rawLoc))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform3i(location, a1, a2, a3);
|
||||
gl->fUniform3i(rawLoc, a1, a2, a3);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::Uniform4i(WebGLUniformLocation *location_object, GLint a1,
|
||||
GLint a2, GLint a3, GLint a4)
|
||||
WebGLContext::Uniform4i(WebGLUniformLocation* loc, GLint a1, GLint a2, GLint a3,
|
||||
GLint a4)
|
||||
{
|
||||
GLint location;
|
||||
if (!ValidateUniformSetter("Uniform4i", location_object, location))
|
||||
GLuint rawLoc;
|
||||
if (!ValidateUniformSetter(loc, 4, LOCAL_GL_INT, "uniform4i", &rawLoc))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform4i(location, a1, a2, a3, a4);
|
||||
gl->fUniform4i(rawLoc, a1, a2, a3, a4);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::Uniform1f(WebGLUniformLocation *location_object, GLfloat a1)
|
||||
WebGLContext::Uniform1f(WebGLUniformLocation* loc, GLfloat a1)
|
||||
{
|
||||
GLint location;
|
||||
if (!ValidateUniformSetter("Uniform1f", location_object, location))
|
||||
GLuint rawLoc;
|
||||
if (!ValidateUniformSetter(loc, 1, LOCAL_GL_FLOAT, "uniform1f", &rawLoc))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform1f(location, a1);
|
||||
gl->fUniform1f(rawLoc, a1);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::Uniform2f(WebGLUniformLocation *location_object, GLfloat a1,
|
||||
GLfloat a2)
|
||||
WebGLContext::Uniform2f(WebGLUniformLocation* loc, GLfloat a1, GLfloat a2)
|
||||
{
|
||||
GLint location;
|
||||
if (!ValidateUniformSetter("Uniform2f", location_object, location))
|
||||
GLuint rawLoc;
|
||||
if (!ValidateUniformSetter(loc, 2, LOCAL_GL_FLOAT, "uniform2f", &rawLoc))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform2f(location, a1, a2);
|
||||
gl->fUniform2f(rawLoc, a1, a2);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::Uniform3f(WebGLUniformLocation *location_object, GLfloat a1,
|
||||
GLfloat a2, GLfloat a3)
|
||||
WebGLContext::Uniform3f(WebGLUniformLocation* loc, GLfloat a1, GLfloat a2,
|
||||
GLfloat a3)
|
||||
{
|
||||
GLint location;
|
||||
if (!ValidateUniformSetter("Uniform3f", location_object, location))
|
||||
GLuint rawLoc;
|
||||
if (!ValidateUniformSetter(loc, 3, LOCAL_GL_FLOAT, "uniform3f", &rawLoc))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform3f(location, a1, a2, a3);
|
||||
gl->fUniform3f(rawLoc, a1, a2, a3);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::Uniform4f(WebGLUniformLocation *location_object, GLfloat a1,
|
||||
GLfloat a2, GLfloat a3, GLfloat a4)
|
||||
WebGLContext::Uniform4f(WebGLUniformLocation* loc, GLfloat a1, GLfloat a2,
|
||||
GLfloat a3, GLfloat a4)
|
||||
{
|
||||
GLint location;
|
||||
if (!ValidateUniformSetter("Uniform4f", location_object, location))
|
||||
GLuint rawLoc;
|
||||
if (!ValidateUniformSetter(loc, 4, LOCAL_GL_FLOAT, "uniform4f", &rawLoc))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform4f(location, a1, a2, a3, a4);
|
||||
gl->fUniform4f(rawLoc, a1, a2, a3, a4);
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
// Array
|
||||
|
||||
void
|
||||
WebGLContext::Uniform1iv_base(WebGLUniformLocation *location_object,
|
||||
uint32_t arrayLength, const GLint* data)
|
||||
WebGLContext::Uniform1iv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLint* data)
|
||||
{
|
||||
uint32_t numElementsToUpload;
|
||||
GLint location;
|
||||
if (!ValidateUniformArraySetter("Uniform1iv", 1, location_object, location,
|
||||
numElementsToUpload, arrayLength)) {
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
if (!ValidateUniformArraySetter(loc, 1, LOCAL_GL_INT, arrayLength,
|
||||
"uniform1iv", &rawLoc,
|
||||
&numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateSamplerUniformSetter("Uniform1iv", location_object, data[0]))
|
||||
if (!ValidateSamplerUniformSetter("uniform1iv", loc, data[0]))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform1iv(location, numElementsToUpload, data);
|
||||
gl->fUniform1iv(rawLoc, numElementsToUpload, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::Uniform2iv_base(WebGLUniformLocation *location_object,
|
||||
uint32_t arrayLength, const GLint* data)
|
||||
WebGLContext::Uniform2iv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLint* data)
|
||||
{
|
||||
uint32_t numElementsToUpload;
|
||||
GLint location;
|
||||
if (!ValidateUniformArraySetter("Uniform2iv", 2, location_object, location,
|
||||
numElementsToUpload, arrayLength)) {
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
if (!ValidateUniformArraySetter(loc, 2, LOCAL_GL_INT, arrayLength,
|
||||
"uniform2iv", &rawLoc,
|
||||
&numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateSamplerUniformSetter("Uniform2iv", location_object, data[0]) ||
|
||||
!ValidateSamplerUniformSetter("Uniform2iv", location_object, data[1]))
|
||||
if (!ValidateSamplerUniformSetter("uniform2iv", loc, data[0]) ||
|
||||
!ValidateSamplerUniformSetter("uniform2iv", loc, data[1]))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform2iv(location, numElementsToUpload, data);
|
||||
gl->fUniform2iv(rawLoc, numElementsToUpload, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::Uniform3iv_base(WebGLUniformLocation *location_object,
|
||||
uint32_t arrayLength, const GLint* data)
|
||||
WebGLContext::Uniform3iv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLint* data)
|
||||
{
|
||||
uint32_t numElementsToUpload;
|
||||
GLint location;
|
||||
if (!ValidateUniformArraySetter("Uniform3iv", 3, location_object, location,
|
||||
numElementsToUpload, arrayLength)) {
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
if (!ValidateUniformArraySetter(loc, 3, LOCAL_GL_INT, arrayLength,
|
||||
"uniform3iv", &rawLoc,
|
||||
&numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateSamplerUniformSetter("Uniform3iv", location_object, data[0]) ||
|
||||
!ValidateSamplerUniformSetter("Uniform3iv", location_object, data[1]) ||
|
||||
!ValidateSamplerUniformSetter("Uniform3iv", location_object, data[2]))
|
||||
if (!ValidateSamplerUniformSetter("uniform3iv", loc, data[0]) ||
|
||||
!ValidateSamplerUniformSetter("uniform3iv", loc, data[1]) ||
|
||||
!ValidateSamplerUniformSetter("uniform3iv", loc, data[2]))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform3iv(location, numElementsToUpload, data);
|
||||
gl->fUniform3iv(rawLoc, numElementsToUpload, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::Uniform4iv_base(WebGLUniformLocation *location_object,
|
||||
uint32_t arrayLength, const GLint* data)
|
||||
WebGLContext::Uniform4iv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLint* data)
|
||||
{
|
||||
uint32_t numElementsToUpload;
|
||||
GLint location;
|
||||
if (!ValidateUniformArraySetter("Uniform4iv", 4, location_object, location,
|
||||
numElementsToUpload, arrayLength)) {
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
if (!ValidateUniformArraySetter(loc, 4, LOCAL_GL_INT, arrayLength,
|
||||
"uniform4iv", &rawLoc,
|
||||
&numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateSamplerUniformSetter("Uniform4iv", location_object, data[0]) ||
|
||||
!ValidateSamplerUniformSetter("Uniform4iv", location_object, data[1]) ||
|
||||
!ValidateSamplerUniformSetter("Uniform4iv", location_object, data[2]) ||
|
||||
!ValidateSamplerUniformSetter("Uniform4iv", location_object, data[3]))
|
||||
if (!ValidateSamplerUniformSetter("uniform4iv", loc, data[0]) ||
|
||||
!ValidateSamplerUniformSetter("uniform4iv", loc, data[1]) ||
|
||||
!ValidateSamplerUniformSetter("uniform4iv", loc, data[2]) ||
|
||||
!ValidateSamplerUniformSetter("uniform4iv", loc, data[3]))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform4iv(location, numElementsToUpload, data);
|
||||
gl->fUniform4iv(rawLoc, numElementsToUpload, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::Uniform1fv_base(WebGLUniformLocation *location_object,
|
||||
uint32_t arrayLength, const GLfloat* data)
|
||||
WebGLContext::Uniform1fv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLfloat* data)
|
||||
{
|
||||
uint32_t numElementsToUpload;
|
||||
GLint location;
|
||||
if (!ValidateUniformArraySetter("Uniform1fv", 1, location_object, location,
|
||||
numElementsToUpload, arrayLength)) {
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
if (!ValidateUniformArraySetter(loc, 1, LOCAL_GL_FLOAT, arrayLength,
|
||||
"uniform1fv", &rawLoc,
|
||||
&numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform1fv(location, numElementsToUpload, data);
|
||||
gl->fUniform1fv(rawLoc, numElementsToUpload, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::Uniform2fv_base(WebGLUniformLocation *location_object,
|
||||
uint32_t arrayLength, const GLfloat* data)
|
||||
WebGLContext::Uniform2fv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLfloat* data)
|
||||
{
|
||||
uint32_t numElementsToUpload;
|
||||
GLint location;
|
||||
if (!ValidateUniformArraySetter("Uniform2fv", 2, location_object, location,
|
||||
numElementsToUpload, arrayLength)) {
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
if (!ValidateUniformArraySetter(loc, 2, LOCAL_GL_FLOAT, arrayLength,
|
||||
"uniform2fv", &rawLoc,
|
||||
&numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform2fv(location, numElementsToUpload, data);
|
||||
gl->fUniform2fv(rawLoc, numElementsToUpload, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::Uniform3fv_base(WebGLUniformLocation *location_object,
|
||||
uint32_t arrayLength, const GLfloat* data)
|
||||
WebGLContext::Uniform3fv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLfloat* data)
|
||||
{
|
||||
uint32_t numElementsToUpload;
|
||||
GLint location;
|
||||
if (!ValidateUniformArraySetter("Uniform3fv", 3, location_object, location,
|
||||
numElementsToUpload, arrayLength)) {
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
if (!ValidateUniformArraySetter(loc, 3, LOCAL_GL_FLOAT, arrayLength,
|
||||
"uniform3fv", &rawLoc,
|
||||
&numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform3fv(location, numElementsToUpload, data);
|
||||
gl->fUniform3fv(rawLoc, numElementsToUpload, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::Uniform4fv_base(WebGLUniformLocation *location_object,
|
||||
uint32_t arrayLength, const GLfloat* data)
|
||||
WebGLContext::Uniform4fv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLfloat* data)
|
||||
{
|
||||
uint32_t numElementsToUpload;
|
||||
GLint location;
|
||||
if (!ValidateUniformArraySetter("Uniform4fv", 4, location_object, location,
|
||||
numElementsToUpload, arrayLength)) {
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
if (!ValidateUniformArraySetter(loc, 4, LOCAL_GL_FLOAT, arrayLength,
|
||||
"uniform4fv", &rawLoc,
|
||||
&numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform4fv(location, numElementsToUpload, data);
|
||||
gl->fUniform4fv(rawLoc, numElementsToUpload, data);
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
// Matrix
|
||||
|
||||
void
|
||||
WebGLContext::UniformMatrix2fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const float* data)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
if (!ValidateUniformMatrixArraySetter(loc, 2, LOCAL_GL_FLOAT, arrayLength,
|
||||
transpose, "uniformMatrix2fv",
|
||||
&rawLoc, &numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniformMatrix2fv(rawLoc, numElementsToUpload, false, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::UniformMatrix2fv_base(WebGLUniformLocation* location_object,
|
||||
WebGLboolean aTranspose, uint32_t arrayLength,
|
||||
const float* data)
|
||||
WebGLContext::UniformMatrix3fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const float* data)
|
||||
{
|
||||
uint32_t numElementsToUpload;
|
||||
GLint location;
|
||||
if (!ValidateUniformMatrixArraySetter("UniformMatrix2fv", 2, location_object, location,
|
||||
numElementsToUpload, arrayLength, aTranspose)) {
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
if (!ValidateUniformMatrixArraySetter(loc, 3, LOCAL_GL_FLOAT, arrayLength,
|
||||
transpose, "uniformMatrix3fv",
|
||||
&rawLoc, &numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniformMatrix2fv(location, numElementsToUpload, false, data);
|
||||
gl->fUniformMatrix3fv(rawLoc, numElementsToUpload, false, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::UniformMatrix3fv_base(WebGLUniformLocation* location_object,
|
||||
WebGLboolean aTranspose, uint32_t arrayLength,
|
||||
const float* data)
|
||||
WebGLContext::UniformMatrix4fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const float* data)
|
||||
{
|
||||
uint32_t numElementsToUpload;
|
||||
GLint location;
|
||||
if (!ValidateUniformMatrixArraySetter("UniformMatrix3fv", 3, location_object, location,
|
||||
numElementsToUpload, arrayLength, aTranspose)) {
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
if (!ValidateUniformMatrixArraySetter(loc, 4, LOCAL_GL_FLOAT, arrayLength,
|
||||
transpose, "uniformMatrix4fv",
|
||||
&rawLoc, &numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniformMatrix3fv(location, numElementsToUpload, false, data);
|
||||
gl->fUniformMatrix4fv(rawLoc, numElementsToUpload, false, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::UniformMatrix4fv_base(WebGLUniformLocation* location_object,
|
||||
WebGLboolean aTranspose, uint32_t arrayLength,
|
||||
const float* data)
|
||||
{
|
||||
uint32_t numElementsToUpload;
|
||||
GLint location;
|
||||
if (!ValidateUniformMatrixArraySetter("UniformMatrix4fv", 4, location_object, location,
|
||||
numElementsToUpload, arrayLength, aTranspose)) {
|
||||
return;
|
||||
}
|
||||
MakeContextCurrent();
|
||||
gl->fUniformMatrix4fv(location, numElementsToUpload, false, data);
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
WebGLContext::UseProgram(WebGLProgram *prog)
|
||||
@ -4267,9 +4343,18 @@ WebGLContext::Finish() {
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::LineWidth(GLfloat width) {
|
||||
WebGLContext::LineWidth(GLfloat width)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
// Doing it this way instead of `if (width <= 0.0)` handles NaNs.
|
||||
const bool isValid = width > 0.0;
|
||||
if (!isValid) {
|
||||
ErrorInvalidValue("lineWidth: `width` must be positive and non-zero.");
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fLineWidth(width);
|
||||
}
|
||||
|
@ -674,7 +674,7 @@ GLenum
|
||||
WebGLContext::GetAndFlushUnderlyingGLErrors()
|
||||
{
|
||||
// Get and clear GL error in ALL cases.
|
||||
GLenum error = gl->GetAndClearError();
|
||||
GLenum error = gl->fGetError();
|
||||
|
||||
// Only store in mUnderlyingGLError if is hasn't already recorded an
|
||||
// error.
|
||||
|
@ -1322,109 +1322,168 @@ WebGLContext::ValidateAttribArraySetter(const char* name, uint32_t cnt, uint32_t
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::ValidateUniformArraySetter(const char* name, uint32_t expectedElemSize, WebGLUniformLocation *location_object,
|
||||
GLint& location, uint32_t& numElementsToUpload, uint32_t arrayLength)
|
||||
static bool
|
||||
IsUniformSetterTypeValid(GLenum setterType, GLenum uniformType)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return false;
|
||||
if (!ValidateUniformLocation(name, location_object))
|
||||
return false;
|
||||
location = location_object->Location();
|
||||
uint32_t uniformElemSize = location_object->ElementSize();
|
||||
if (expectedElemSize != uniformElemSize) {
|
||||
ErrorInvalidOperation("%s: this function expected a uniform of element size %d,"
|
||||
" got a uniform of element size %d", name,
|
||||
expectedElemSize,
|
||||
uniformElemSize);
|
||||
switch (uniformType) {
|
||||
case LOCAL_GL_BOOL:
|
||||
case LOCAL_GL_BOOL_VEC2:
|
||||
case LOCAL_GL_BOOL_VEC3:
|
||||
case LOCAL_GL_BOOL_VEC4:
|
||||
return true; // GLfloat(0.0) sets a bool to false.
|
||||
|
||||
case LOCAL_GL_INT:
|
||||
case LOCAL_GL_SAMPLER_2D:
|
||||
case LOCAL_GL_SAMPLER_CUBE:
|
||||
case LOCAL_GL_INT_VEC2:
|
||||
case LOCAL_GL_INT_VEC3:
|
||||
case LOCAL_GL_INT_VEC4:
|
||||
return setterType == LOCAL_GL_INT;
|
||||
|
||||
case LOCAL_GL_FLOAT:
|
||||
case LOCAL_GL_FLOAT_VEC2:
|
||||
case LOCAL_GL_FLOAT_VEC3:
|
||||
case LOCAL_GL_FLOAT_VEC4:
|
||||
case LOCAL_GL_FLOAT_MAT2:
|
||||
case LOCAL_GL_FLOAT_MAT3:
|
||||
case LOCAL_GL_FLOAT_MAT4:
|
||||
return setterType == LOCAL_GL_FLOAT;
|
||||
|
||||
default:
|
||||
MOZ_ASSERT(false); // should never get here
|
||||
return false;
|
||||
}
|
||||
if (arrayLength == 0 ||
|
||||
arrayLength % expectedElemSize)
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckUniformSizeAndType(WebGLContext& webgl, WebGLUniformLocation* loc,
|
||||
uint8_t setterElemSize, GLenum setterType,
|
||||
const char* info)
|
||||
{
|
||||
if (setterElemSize != loc->ElementSize()) {
|
||||
webgl.ErrorInvalidOperation("%s: Bad uniform size: %i", info,
|
||||
loc->ElementSize());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsUniformSetterTypeValid(setterType, loc->Info().type)) {
|
||||
webgl.ErrorInvalidOperation("%s: Bad uniform type: %i", info,
|
||||
loc->Info().type);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckUniformArrayLength(WebGLContext& webgl, WebGLUniformLocation* loc,
|
||||
uint8_t setterElemSize, size_t setterArraySize,
|
||||
const char* info)
|
||||
{
|
||||
if (setterArraySize == 0 ||
|
||||
setterArraySize % setterElemSize)
|
||||
{
|
||||
ErrorInvalidValue("%s: expected an array of length a multiple"
|
||||
" of %d, got an array of length %d", name,
|
||||
expectedElemSize,
|
||||
arrayLength);
|
||||
webgl.ErrorInvalidValue("%s: expected an array of length a multiple of"
|
||||
" %d, got an array of length %d.", info,
|
||||
setterElemSize, setterArraySize);
|
||||
return false;
|
||||
}
|
||||
const WebGLUniformInfo& info = location_object->Info();
|
||||
if (!info.isArray &&
|
||||
arrayLength != expectedElemSize) {
|
||||
ErrorInvalidOperation("%s: expected an array of length exactly"
|
||||
" %d (since this uniform is not an array"
|
||||
" uniform), got an array of length %d", name,
|
||||
expectedElemSize,
|
||||
arrayLength);
|
||||
return false;
|
||||
}
|
||||
numElementsToUpload =
|
||||
std::min(info.arraySize, arrayLength / expectedElemSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::ValidateUniformMatrixArraySetter(const char* name, int dim, WebGLUniformLocation *location_object,
|
||||
GLint& location, uint32_t& numElementsToUpload, uint32_t arrayLength,
|
||||
WebGLboolean aTranspose)
|
||||
{
|
||||
uint32_t expectedElemSize = (dim)*(dim);
|
||||
if (IsContextLost())
|
||||
return false;
|
||||
if (!ValidateUniformLocation(name, location_object))
|
||||
return false;
|
||||
location = location_object->Location();
|
||||
uint32_t uniformElemSize = location_object->ElementSize();
|
||||
if (expectedElemSize != uniformElemSize) {
|
||||
ErrorInvalidOperation("%s: this function expected a uniform of element size %d,"
|
||||
" got a uniform of element size %d", name,
|
||||
expectedElemSize,
|
||||
uniformElemSize);
|
||||
return false;
|
||||
}
|
||||
if (arrayLength == 0 ||
|
||||
arrayLength % expectedElemSize)
|
||||
if (!loc->Info().isArray &&
|
||||
setterArraySize != setterElemSize)
|
||||
{
|
||||
ErrorInvalidValue("%s: expected an array of length a multiple"
|
||||
" of %d, got an array of length %d", name,
|
||||
expectedElemSize,
|
||||
arrayLength);
|
||||
webgl.ErrorInvalidOperation("%s: expected an array of length exactly %d"
|
||||
" (since this uniform is not an array"
|
||||
" uniform), got an array of length %d.",
|
||||
info, setterElemSize, setterArraySize);
|
||||
return false;
|
||||
}
|
||||
const WebGLUniformInfo& info = location_object->Info();
|
||||
if (!info.isArray &&
|
||||
arrayLength != expectedElemSize) {
|
||||
ErrorInvalidOperation("%s: expected an array of length exactly"
|
||||
" %d (since this uniform is not an array"
|
||||
" uniform), got an array of length %d", name,
|
||||
expectedElemSize,
|
||||
arrayLength);
|
||||
return false;
|
||||
}
|
||||
if (aTranspose) {
|
||||
ErrorInvalidValue("%s: transpose must be FALSE as per the "
|
||||
"OpenGL ES 2.0 spec", name);
|
||||
return false;
|
||||
}
|
||||
numElementsToUpload =
|
||||
std::min(info.arraySize, arrayLength / (expectedElemSize));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::ValidateUniformSetter(const char* name, WebGLUniformLocation *location_object, GLint& location)
|
||||
WebGLContext::ValidateUniformSetter(WebGLUniformLocation* loc,
|
||||
uint8_t setterElemSize, GLenum setterType,
|
||||
const char* info, GLuint* out_rawLoc)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return false;
|
||||
if (!ValidateUniformLocation(name, location_object))
|
||||
|
||||
if (!ValidateUniformLocation(info, loc))
|
||||
return false;
|
||||
location = location_object->Location();
|
||||
|
||||
if (!CheckUniformSizeAndType(*this, loc, setterElemSize, setterType, info))
|
||||
return false;
|
||||
|
||||
*out_rawLoc = loc->Location();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebGLContext::ValidateAttribIndex(GLuint index, const char *info)
|
||||
bool
|
||||
WebGLContext::ValidateUniformArraySetter(WebGLUniformLocation* loc,
|
||||
uint8_t setterElemSize, GLenum setterType,
|
||||
size_t setterArraySize,
|
||||
const char* info, GLuint* out_rawLoc,
|
||||
GLsizei* out_numElementsToUpload)
|
||||
{
|
||||
return mBoundVertexArray->EnsureAttrib(index, info);
|
||||
if (IsContextLost())
|
||||
return false;
|
||||
|
||||
if (!ValidateUniformLocation(info, loc))
|
||||
return false;
|
||||
|
||||
if (!CheckUniformSizeAndType(*this, loc, setterElemSize, setterType, info))
|
||||
return false;
|
||||
|
||||
if (!CheckUniformArrayLength(*this, loc, setterElemSize, setterArraySize,
|
||||
info))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_rawLoc = loc->Location();
|
||||
*out_numElementsToUpload = std::min((size_t)loc->Info().arraySize,
|
||||
setterArraySize / setterElemSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
|
||||
uint8_t setterDims,
|
||||
GLenum setterType,
|
||||
size_t setterArraySize,
|
||||
bool setterTranspose,
|
||||
const char* info,
|
||||
GLuint* out_rawLoc,
|
||||
GLsizei* out_numElementsToUpload)
|
||||
{
|
||||
uint8_t setterElemSize = setterDims * setterDims;
|
||||
|
||||
if (IsContextLost())
|
||||
return false;
|
||||
|
||||
if (!ValidateUniformLocation(info, loc))
|
||||
return false;
|
||||
|
||||
if (!CheckUniformSizeAndType(*this, loc, setterElemSize, setterType, info))
|
||||
return false;
|
||||
|
||||
if (!CheckUniformArrayLength(*this, loc, setterElemSize, setterArraySize,
|
||||
info))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (setterTranspose) {
|
||||
ErrorInvalidValue("%s: `transpose` must be false.", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_rawLoc = loc->Location();
|
||||
*out_numElementsToUpload = std::min((size_t)loc->Info().arraySize,
|
||||
setterArraySize / setterElemSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebGLContext::ValidateStencilParamsForDrawCall()
|
||||
@ -1620,31 +1679,22 @@ WebGLContext::InitAndValidateGL()
|
||||
// however these constants only entered the OpenGL standard at OpenGL 3.2. So we will try reading,
|
||||
// and check OpenGL error for INVALID_ENUM.
|
||||
|
||||
// before we start, we check that no error already occurred, to prevent hiding it in our subsequent error handling
|
||||
error = gl->GetAndClearError();
|
||||
if (error != LOCAL_GL_NO_ERROR) {
|
||||
GenerateWarning("GL error 0x%x occurred during WebGL context initialization!", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
// On the public_webgl list, "problematic GetParameter pnames" thread, the following formula was given:
|
||||
// mGLMaxVaryingVectors = min (GL_MAX_VERTEX_OUTPUT_COMPONENTS, GL_MAX_FRAGMENT_INPUT_COMPONENTS) / 4
|
||||
GLint maxVertexOutputComponents,
|
||||
minFragmentInputComponents;
|
||||
gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS, &maxVertexOutputComponents);
|
||||
gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS, &minFragmentInputComponents);
|
||||
GLint maxVertexOutputComponents = 0;
|
||||
GLint maxFragmentInputComponents = 0;
|
||||
|
||||
error = gl->GetAndClearError();
|
||||
switch (error) {
|
||||
case LOCAL_GL_NO_ERROR:
|
||||
mGLMaxVaryingVectors = std::min(maxVertexOutputComponents, minFragmentInputComponents) / 4;
|
||||
break;
|
||||
case LOCAL_GL_INVALID_ENUM:
|
||||
mGLMaxVaryingVectors = 16; // = 64/4, 64 is the min value for maxVertexOutputComponents in OpenGL 3.2 spec
|
||||
break;
|
||||
default:
|
||||
GenerateWarning("GL error 0x%x occurred during WebGL context initialization!", error);
|
||||
return false;
|
||||
const bool ok = (gl->GetPotentialInteger(LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS,
|
||||
&maxVertexOutputComponents) &&
|
||||
gl->GetPotentialInteger(LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS,
|
||||
&maxFragmentInputComponents));
|
||||
|
||||
if (ok) {
|
||||
mGLMaxVaryingVectors = std::min(maxVertexOutputComponents,
|
||||
maxFragmentInputComponents) / 4;
|
||||
} else {
|
||||
mGLMaxVaryingVectors = 16;
|
||||
// = 64/4, 64 is the min value for maxVertexOutputComponents in OpenGL 3.2 spec
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1694,9 +1744,10 @@ WebGLContext::InitAndValidateGL()
|
||||
// Mesa can only be detected with the GL_VERSION string, of the form "2.1 Mesa 7.11.0"
|
||||
mIsMesa = strstr((const char *)(gl->fGetString(LOCAL_GL_VERSION)), "Mesa");
|
||||
|
||||
// notice that the point of calling GetAndClearError here is not only to check for error,
|
||||
// it is also to reset the error flags so that a subsequent WebGL getError call will give the correct result.
|
||||
error = gl->GetAndClearError();
|
||||
// Notice that the point of calling fGetError here is not only to check for
|
||||
// errors, but also to reset the error flags so that a subsequent WebGL
|
||||
// getError call will give the correct result.
|
||||
error = gl->fGetError();
|
||||
if (error != LOCAL_GL_NO_ERROR) {
|
||||
GenerateWarning("GL error 0x%x occurred during WebGL context initialization!", error);
|
||||
return false;
|
||||
|
@ -20,12 +20,36 @@
|
||||
using namespace mozilla;
|
||||
using namespace dom;
|
||||
|
||||
static bool
|
||||
CheckAttribIndex(WebGLContext& webgl, GLuint index, const char* info)
|
||||
{
|
||||
if (index >= webgl.MaxVertexAttribs()) {
|
||||
if (index == GLuint(-1)) {
|
||||
webgl.ErrorInvalidValue("%s: -1 is not a valid `index`. This value"
|
||||
" probably comes from a getAttribLocation()"
|
||||
" call, where this return value -1 means"
|
||||
" that the passed name didn't correspond to"
|
||||
" an active attribute in the specified"
|
||||
" program.", info);
|
||||
} else {
|
||||
webgl.ErrorInvalidValue("%s: `index` must be less than"
|
||||
" MAX_VERTEX_ATTRIBS.", info);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::VertexAttrib1f(GLuint index, GLfloat x0)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!CheckAttribIndex(*this, index, "vertexAttrib1f"))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
if (index) {
|
||||
@ -46,6 +70,9 @@ WebGLContext::VertexAttrib2f(GLuint index, GLfloat x0, GLfloat x1)
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!CheckAttribIndex(*this, index, "vertexAttrib2f"))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
if (index) {
|
||||
@ -66,6 +93,9 @@ WebGLContext::VertexAttrib3f(GLuint index, GLfloat x0, GLfloat x1, GLfloat x2)
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!CheckAttribIndex(*this, index, "vertexAttrib3f"))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
if (index) {
|
||||
@ -87,6 +117,9 @@ WebGLContext::VertexAttrib4f(GLuint index, GLfloat x0, GLfloat x1,
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!CheckAttribIndex(*this, index, "vertexAttrib4f"))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
if (index) {
|
||||
@ -103,82 +136,94 @@ WebGLContext::VertexAttrib4f(GLuint index, GLfloat x0, GLfloat x1,
|
||||
|
||||
|
||||
void
|
||||
WebGLContext::VertexAttrib1fv_base(GLuint idx, uint32_t arrayLength,
|
||||
WebGLContext::VertexAttrib1fv_base(GLuint index, uint32_t arrayLength,
|
||||
const GLfloat* ptr)
|
||||
{
|
||||
if (!ValidateAttribArraySetter("VertexAttrib1fv", 1, arrayLength))
|
||||
return;
|
||||
|
||||
if (!CheckAttribIndex(*this, index, "vertexAttrib1fv"))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
if (idx) {
|
||||
gl->fVertexAttrib1fv(idx, ptr);
|
||||
if (index) {
|
||||
gl->fVertexAttrib1fv(index, ptr);
|
||||
} else {
|
||||
mVertexAttrib0Vector[0] = ptr[0];
|
||||
mVertexAttrib0Vector[1] = GLfloat(0);
|
||||
mVertexAttrib0Vector[2] = GLfloat(0);
|
||||
mVertexAttrib0Vector[3] = GLfloat(1);
|
||||
if (gl->IsGLES())
|
||||
gl->fVertexAttrib1fv(idx, ptr);
|
||||
gl->fVertexAttrib1fv(index, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::VertexAttrib2fv_base(GLuint idx, uint32_t arrayLength,
|
||||
WebGLContext::VertexAttrib2fv_base(GLuint index, uint32_t arrayLength,
|
||||
const GLfloat* ptr)
|
||||
{
|
||||
if (!ValidateAttribArraySetter("VertexAttrib2fv", 2, arrayLength))
|
||||
return;
|
||||
|
||||
if (!CheckAttribIndex(*this, index, "vertexAttrib2fv"))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
if (idx) {
|
||||
gl->fVertexAttrib2fv(idx, ptr);
|
||||
if (index) {
|
||||
gl->fVertexAttrib2fv(index, ptr);
|
||||
} else {
|
||||
mVertexAttrib0Vector[0] = ptr[0];
|
||||
mVertexAttrib0Vector[1] = ptr[1];
|
||||
mVertexAttrib0Vector[2] = GLfloat(0);
|
||||
mVertexAttrib0Vector[3] = GLfloat(1);
|
||||
if (gl->IsGLES())
|
||||
gl->fVertexAttrib2fv(idx, ptr);
|
||||
gl->fVertexAttrib2fv(index, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::VertexAttrib3fv_base(GLuint idx, uint32_t arrayLength,
|
||||
WebGLContext::VertexAttrib3fv_base(GLuint index, uint32_t arrayLength,
|
||||
const GLfloat* ptr)
|
||||
{
|
||||
if (!ValidateAttribArraySetter("VertexAttrib3fv", 3, arrayLength))
|
||||
return;
|
||||
|
||||
if (!CheckAttribIndex(*this, index, "vertexAttrib3fv"))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
if (idx) {
|
||||
gl->fVertexAttrib3fv(idx, ptr);
|
||||
if (index) {
|
||||
gl->fVertexAttrib3fv(index, ptr);
|
||||
} else {
|
||||
mVertexAttrib0Vector[0] = ptr[0];
|
||||
mVertexAttrib0Vector[1] = ptr[1];
|
||||
mVertexAttrib0Vector[2] = ptr[2];
|
||||
mVertexAttrib0Vector[3] = GLfloat(1);
|
||||
if (gl->IsGLES())
|
||||
gl->fVertexAttrib3fv(idx, ptr);
|
||||
gl->fVertexAttrib3fv(index, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::VertexAttrib4fv_base(GLuint idx, uint32_t arrayLength,
|
||||
WebGLContext::VertexAttrib4fv_base(GLuint index, uint32_t arrayLength,
|
||||
const GLfloat* ptr)
|
||||
{
|
||||
if (!ValidateAttribArraySetter("VertexAttrib4fv", 4, arrayLength))
|
||||
return;
|
||||
|
||||
if (!CheckAttribIndex(*this, index, "vertexAttrib4fv"))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
if (idx) {
|
||||
gl->fVertexAttrib4fv(idx, ptr);
|
||||
if (index) {
|
||||
gl->fVertexAttrib4fv(index, ptr);
|
||||
} else {
|
||||
mVertexAttrib0Vector[0] = ptr[0];
|
||||
mVertexAttrib0Vector[1] = ptr[1];
|
||||
mVertexAttrib0Vector[2] = ptr[2];
|
||||
mVertexAttrib0Vector[3] = ptr[3];
|
||||
if (gl->IsGLES())
|
||||
gl->fVertexAttrib4fv(idx, ptr);
|
||||
gl->fVertexAttrib4fv(index, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -188,14 +233,16 @@ WebGLContext::EnableVertexAttribArray(GLuint index)
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateAttribIndex(index, "enableVertexAttribArray"))
|
||||
if (!CheckAttribIndex(*this, index, "enableVertexAttribArray"))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
InvalidateBufferFetching();
|
||||
|
||||
gl->fEnableVertexAttribArray(index);
|
||||
MOZ_ASSERT(mBoundVertexArray->HasAttrib(index)); // should have been validated earlier
|
||||
|
||||
MOZ_ASSERT(mBoundVertexArray);
|
||||
mBoundVertexArray->EnsureAttrib(index);
|
||||
mBoundVertexArray->mAttribs[index].enabled = true;
|
||||
}
|
||||
|
||||
@ -205,7 +252,7 @@ WebGLContext::DisableVertexAttribArray(GLuint index)
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateAttribIndex(index, "disableVertexAttribArray"))
|
||||
if (!CheckAttribIndex(*this, index, "disableVertexAttribArray"))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
@ -214,11 +261,11 @@ WebGLContext::DisableVertexAttribArray(GLuint index)
|
||||
if (index || gl->IsGLES())
|
||||
gl->fDisableVertexAttribArray(index);
|
||||
|
||||
MOZ_ASSERT(mBoundVertexArray->HasAttrib(index)); // should have been validated earlier
|
||||
MOZ_ASSERT(mBoundVertexArray);
|
||||
mBoundVertexArray->EnsureAttrib(index);
|
||||
mBoundVertexArray->mAttribs[index].enabled = false;
|
||||
}
|
||||
|
||||
|
||||
JS::Value
|
||||
WebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname,
|
||||
ErrorResult& rv)
|
||||
@ -226,9 +273,12 @@ WebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname,
|
||||
if (IsContextLost())
|
||||
return JS::NullValue();
|
||||
|
||||
if (!ValidateAttribIndex(index, "getVertexAttrib"))
|
||||
if (!CheckAttribIndex(*this, index, "getVertexAttrib"))
|
||||
return JS::NullValue();
|
||||
|
||||
MOZ_ASSERT(mBoundVertexArray);
|
||||
mBoundVertexArray->EnsureAttrib(index);
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
switch (pname) {
|
||||
@ -300,7 +350,6 @@ WebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname,
|
||||
}
|
||||
|
||||
ErrorInvalidEnumInfo("getVertexAttrib: parameter", pname);
|
||||
|
||||
return JS::NullValue();
|
||||
}
|
||||
|
||||
@ -310,7 +359,7 @@ WebGLContext::GetVertexAttribOffset(GLuint index, GLenum pname)
|
||||
if (IsContextLost())
|
||||
return 0;
|
||||
|
||||
if (!ValidateAttribIndex(index, "getVertexAttribOffset"))
|
||||
if (!CheckAttribIndex(*this, index, "getVertexAttribOffset"))
|
||||
return 0;
|
||||
|
||||
if (pname != LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER) {
|
||||
@ -318,6 +367,8 @@ WebGLContext::GetVertexAttribOffset(GLuint index, GLenum pname)
|
||||
return 0;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mBoundVertexArray);
|
||||
mBoundVertexArray->EnsureAttrib(index);
|
||||
return mBoundVertexArray->mAttribs[index].byteOffset;
|
||||
}
|
||||
|
||||
@ -329,6 +380,9 @@ WebGLContext::VertexAttribPointer(GLuint index, GLint size, GLenum type,
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!CheckAttribIndex(*this, index, "vertexAttribPointer"))
|
||||
return;
|
||||
|
||||
if (mBoundArrayBuffer == nullptr)
|
||||
return ErrorInvalidOperation("vertexAttribPointer: must have valid GL_ARRAY_BUFFER binding");
|
||||
|
||||
@ -353,9 +407,8 @@ WebGLContext::VertexAttribPointer(GLuint index, GLint size, GLenum type,
|
||||
// requiredAlignment should always be a power of two.
|
||||
GLsizei requiredAlignmentMask = requiredAlignment - 1;
|
||||
|
||||
if (!ValidateAttribIndex(index, "vertexAttribPointer")) {
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(mBoundVertexArray);
|
||||
mBoundVertexArray->EnsureAttrib(index);
|
||||
|
||||
if (size < 1 || size > 4)
|
||||
return ErrorInvalidValue("vertexAttribPointer: invalid element size");
|
||||
@ -406,9 +459,11 @@ WebGLContext::VertexAttribDivisor(GLuint index, GLuint divisor)
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateAttribIndex(index, "vertexAttribDivisor")) {
|
||||
if (!CheckAttribIndex(*this, index, "vertexAttribDivisor"))
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mBoundVertexArray);
|
||||
mBoundVertexArray->EnsureAttrib(index);
|
||||
|
||||
WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[index];
|
||||
vd.divisor = divisor;
|
||||
|
@ -49,24 +49,14 @@ WebGLVertexArray::Delete()
|
||||
mAttribs.Clear();
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLVertexArray::EnsureAttrib(GLuint index, const char *info)
|
||||
void
|
||||
WebGLVertexArray::EnsureAttrib(GLuint index)
|
||||
{
|
||||
if (index >= GLuint(mContext->mGLMaxVertexAttribs)) {
|
||||
if (index == GLuint(-1)) {
|
||||
mContext->ErrorInvalidValue("%s: index -1 is invalid. That probably comes from a getAttribLocation() call, "
|
||||
"where this return value -1 means that the passed name didn't correspond to an active attribute in "
|
||||
"the specified program.", info);
|
||||
} else {
|
||||
mContext->ErrorInvalidValue("%s: index %d is out of range", info, index);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (index >= mAttribs.Length()) {
|
||||
MOZ_ASSERT(index < GLuint(mContext->mGLMaxVertexAttribs));
|
||||
|
||||
if (index >= mAttribs.Length()) {
|
||||
mAttribs.SetLength(index + 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLVertexArray,
|
||||
|
@ -61,7 +61,7 @@ public:
|
||||
// -------------------------------------------------------------------------
|
||||
// MEMBER FUNCTIONS
|
||||
|
||||
bool EnsureAttrib(GLuint index, const char *info);
|
||||
void EnsureAttrib(GLuint index);
|
||||
bool HasAttrib(GLuint index) {
|
||||
return index < mAttribs.Length();
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
CppUnitTests([
|
||||
GeckoCppUnitTests([
|
||||
'TestWebGLElementArrayCache',
|
||||
])
|
||||
|
||||
@ -13,10 +13,3 @@ FAIL_ON_WARNINGS = True
|
||||
LOCAL_INCLUDES += [
|
||||
'../',
|
||||
]
|
||||
|
||||
USE_LIBS += [
|
||||
'mozalloc',
|
||||
'nspr',
|
||||
'xpcomglue_s',
|
||||
'xul',
|
||||
]
|
||||
|
@ -130,9 +130,7 @@ function GetExpectedTestFailSet() {
|
||||
} else {
|
||||
// Android 2.3 slaves.
|
||||
failSet['conformance/glsl/functions/glsl-function-sin.html'] = true;
|
||||
failSet['conformance/misc/error-reporting.html'] = true;
|
||||
failSet['conformance/misc/object-deletion-behaviour.html'] = true;
|
||||
failSet['conformance/programs/get-active-test.html'] = true;
|
||||
failSet['conformance/textures/tex-image-and-sub-image-2d-with-video.html'] = true;
|
||||
failSet['conformance/textures/texture-mips.html'] = true;
|
||||
failSet['conformance/textures/texture-npot.html'] = true;
|
||||
|
@ -268,7 +268,8 @@ protected:
|
||||
class MOZ_STACK_CLASS WantsPopupControlCheck
|
||||
{
|
||||
public:
|
||||
WantsPopupControlCheck(nsIDOMEvent* aEvent) : mEvent(aEvent->InternalDOMEvent())
|
||||
explicit WantsPopupControlCheck(nsIDOMEvent* aEvent) :
|
||||
mEvent(aEvent->InternalDOMEvent())
|
||||
{
|
||||
mOriginalWantsPopupControlCheck = mEvent->GetWantsPopupControlCheck();
|
||||
mEvent->SetWantsPopupControlCheck(mEvent->IsTrusted());
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include "mozilla/HoldDropJSObjects.h"
|
||||
#include "jsapi.h"
|
||||
#include "nsGlobalWindow.h" // So we can assign an nsGlobalWindow* to mWindowSource
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -141,8 +142,8 @@ MessageEvent::Constructor(const GlobalObject& aGlobal,
|
||||
}
|
||||
|
||||
if (!aParam.mSource.IsNull()) {
|
||||
if (aParam.mSource.Value().IsWindowProxy()) {
|
||||
event->mWindowSource = aParam.mSource.Value().GetAsWindowProxy();
|
||||
if (aParam.mSource.Value().IsWindow()) {
|
||||
event->mWindowSource = aParam.mSource.Value().GetAsWindow();
|
||||
} else {
|
||||
event->mPortSource = aParam.mSource.Value().GetAsMessagePort();
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ class MainThreadFetchResolver MOZ_FINAL : public FetchDriverObserver
|
||||
|
||||
NS_DECL_OWNINGTHREAD
|
||||
public:
|
||||
MainThreadFetchResolver(Promise* aPromise);
|
||||
explicit MainThreadFetchResolver(Promise* aPromise);
|
||||
|
||||
void
|
||||
OnResponseAvailable(InternalResponse* aResponse) MOZ_OVERRIDE;
|
||||
@ -188,7 +188,7 @@ class WorkerFetchResponseRunnable : public WorkerRunnable
|
||||
{
|
||||
nsRefPtr<WorkerFetchResolver> mResolver;
|
||||
public:
|
||||
WorkerFetchResponseRunnable(WorkerFetchResolver* aResolver)
|
||||
explicit WorkerFetchResponseRunnable(WorkerFetchResolver* aResolver)
|
||||
: WorkerRunnable(aResolver->GetWorkerPrivate(), WorkerThreadModifyBusyCount)
|
||||
, mResolver(aResolver)
|
||||
{
|
||||
|
@ -1787,7 +1787,11 @@ HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded)
|
||||
if (!window) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
if (ContainsRestrictedContent()) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
OutputMediaStream* out = mOutputStreams.AppendElement();
|
||||
#ifdef DEBUG
|
||||
// Estimate hints based on the type of the media element
|
||||
@ -3992,10 +3996,21 @@ HTMLMediaElement::GetMediaKeys() const
|
||||
return mMediaKeys;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLMediaElement::ContainsRestrictedContent()
|
||||
{
|
||||
return GetMediaKeys() != nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
HTMLMediaElement::SetMediaKeys(mozilla::dom::MediaKeys* aMediaKeys,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (MozAudioCaptured()) {
|
||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global =
|
||||
do_QueryInterface(OwnerDoc()->GetInnerWindow());
|
||||
if (!global) {
|
||||
@ -4030,6 +4045,8 @@ HTMLMediaElement::SetMediaKeys(mozilla::dom::MediaKeys* aMediaKeys,
|
||||
if (mDecoder) {
|
||||
mDecoder->SetCDMProxy(mMediaKeys->GetCDMProxy());
|
||||
}
|
||||
// Update the same-origin status.
|
||||
NotifyDecoderPrincipalChanged();
|
||||
}
|
||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
return promise.forget();
|
||||
|
@ -550,6 +550,7 @@ public:
|
||||
// in the URL bar of the browser window.
|
||||
already_AddRefed<nsIPrincipal> GetTopLevelPrincipal();
|
||||
|
||||
bool ContainsRestrictedContent();
|
||||
#endif // MOZ_EME
|
||||
|
||||
bool MozAutoplayEnabled() const
|
||||
|
@ -729,7 +729,7 @@ class EmptyBlobImpl MOZ_FINAL
|
||||
: public FileImplBase
|
||||
{
|
||||
public:
|
||||
EmptyBlobImpl(const nsAString& aContentType)
|
||||
explicit EmptyBlobImpl(const nsAString& aContentType)
|
||||
: FileImplBase(aContentType, 0)
|
||||
{
|
||||
mImmutable = true;
|
||||
@ -840,7 +840,7 @@ struct MOZ_STACK_CLASS CreateBlobImplMetadata MOZ_FINAL
|
||||
bool mHasRecursed;
|
||||
const bool mIsSameProcessActor;
|
||||
|
||||
CreateBlobImplMetadata(bool aIsSameProcessActor)
|
||||
explicit CreateBlobImplMetadata(bool aIsSameProcessActor)
|
||||
: mLength(0)
|
||||
, mLastModifiedDate(0)
|
||||
, mHasRecursed(false)
|
||||
@ -1678,7 +1678,7 @@ class BlobChild::RemoteBlobImpl::CreateStreamHelper MOZ_FINAL
|
||||
bool mDone;
|
||||
|
||||
public:
|
||||
CreateStreamHelper(RemoteBlobImpl* aRemoteBlobImpl);
|
||||
explicit CreateStreamHelper(RemoteBlobImpl* aRemoteBlobImpl);
|
||||
|
||||
nsresult
|
||||
GetStream(nsIInputStream** aInputStream);
|
||||
|
@ -299,6 +299,8 @@ ThreadedDriver::RunThread()
|
||||
(long)mIterationStart, (long)mIterationEnd,
|
||||
(long)mStateComputedTime, (long)mNextStateComputedTime));
|
||||
|
||||
mGraphImpl->mFlushSourcesNow = mGraphImpl->mFlushSourcesOnNextIteration;
|
||||
mGraphImpl->mFlushSourcesOnNextIteration = false;
|
||||
stillProcessing = mGraphImpl->OneIteration(prevCurrentTime,
|
||||
nextCurrentTime,
|
||||
StateComputedTime(),
|
||||
@ -796,7 +798,9 @@ AudioCallbackDriver::OSXDeviceSwitchingWorkaround()
|
||||
// callback is called "some" number of times, and then stops being called,
|
||||
// and then gets called again. 10 is to be safe, it's a low-enough number
|
||||
// of milliseconds anyways (< 100ms)
|
||||
//STREAM_LOG(PR_LOG_DEBUG, ("Callbacks during switch: %d", mCallbackReceivedWhileSwitching+1));
|
||||
if (mCallbackReceivedWhileSwitching++ >= 10) {
|
||||
STREAM_LOG(PR_LOG_DEBUG, ("Got %d callbacks, switching back to CallbackDriver", mCallbackReceivedWhileSwitching));
|
||||
// If we have a self reference, we have fallen back temporarily on a
|
||||
// system clock driver, but we just got called back, that means the osx
|
||||
// audio backend has switched to the new device.
|
||||
@ -1032,8 +1036,10 @@ AudioCallbackDriver::DeviceChangedCallback() {
|
||||
if (mSelfReference) {
|
||||
return;
|
||||
}
|
||||
STREAM_LOG(PR_LOG_ERROR, ("Switching to SystemClockDriver during output switch"));
|
||||
mSelfReference.Take(this);
|
||||
mCallbackReceivedWhileSwitching = 0;
|
||||
mGraphImpl->mFlushSourcesOnNextIteration = true;
|
||||
mNextDriver = new SystemClockDriver(GraphImpl());
|
||||
mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd,
|
||||
mStateComputedTime, mNextStateComputedTime);
|
||||
|
@ -2975,8 +2975,8 @@ void MediaDecoderStateMachine::StartBuffering()
|
||||
// we just trigger UpdateReadyStateForData; when it runs, it
|
||||
// will check the current state and decide whether to tell
|
||||
// the element we're buffering or not.
|
||||
UpdateReadyState();
|
||||
SetState(DECODER_STATE_BUFFERING);
|
||||
UpdateReadyState();
|
||||
DECODER_LOG("Changed state from DECODING to BUFFERING, decoded for %.3lfs",
|
||||
decodeDuration.ToSeconds());
|
||||
#ifdef PR_LOGGING
|
||||
|
@ -88,6 +88,10 @@ public:
|
||||
* Replace all contents up to aDuration with null data.
|
||||
*/
|
||||
virtual void ForgetUpTo(TrackTicks aDuration) = 0;
|
||||
/**
|
||||
* Forget all data buffered after a given point
|
||||
*/
|
||||
virtual void FlushAfter(TrackTicks aNewEnd) = 0;
|
||||
/**
|
||||
* Insert aDuration of null data at the start of the segment.
|
||||
*/
|
||||
@ -176,6 +180,29 @@ public:
|
||||
mChunks.InsertElementAt(0)->SetNull(aDuration);
|
||||
mDuration += aDuration;
|
||||
}
|
||||
virtual void FlushAfter(TrackTicks aNewEnd)
|
||||
{
|
||||
if (mChunks.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mChunks[0].IsNull()) {
|
||||
TrackTicks extraToKeep = aNewEnd - mChunks[0].GetDuration();
|
||||
if (extraToKeep < 0) {
|
||||
// reduce the size of the Null, get rid of everthing else
|
||||
mChunks[0].SetNull(aNewEnd);
|
||||
extraToKeep = 0;
|
||||
}
|
||||
RemoveTrailing(extraToKeep, 1);
|
||||
} else {
|
||||
if (aNewEnd > mDuration) {
|
||||
NS_ASSERTION(aNewEnd <= mDuration, "can't add data in FlushAfter");
|
||||
return;
|
||||
}
|
||||
RemoveTrailing(aNewEnd, 0);
|
||||
}
|
||||
mDuration = aNewEnd;
|
||||
}
|
||||
virtual void InsertNullDataAtStart(TrackTicks aDuration)
|
||||
{
|
||||
if (aDuration <= 0) {
|
||||
@ -350,6 +377,28 @@ protected:
|
||||
mDuration -= aDuration - t;
|
||||
}
|
||||
|
||||
void RemoveTrailing(TrackTicks aKeep, uint32_t aStartIndex)
|
||||
{
|
||||
NS_ASSERTION(aKeep >= 0, "Can't keep negative duration");
|
||||
TrackTicks t = aKeep;
|
||||
uint32_t i;
|
||||
for (i = aStartIndex; i < mChunks.Length(); ++i) {
|
||||
Chunk* c = &mChunks[i];
|
||||
if (c->GetDuration() > t) {
|
||||
c->SliceTo(0, t);
|
||||
break;
|
||||
}
|
||||
t -= c->GetDuration();
|
||||
if (t == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i+1 < mChunks.Length()) {
|
||||
mChunks.RemoveElementsAt(i+1, mChunks.Length() - (i+1));
|
||||
}
|
||||
// Caller must adjust mDuration
|
||||
}
|
||||
|
||||
nsTArray<Chunk> mChunks;
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
mozilla::TimeStamp mTimeStamp;
|
||||
|
@ -1439,6 +1439,7 @@ MediaStreamGraphImpl::OneIteration(GraphTime aFrom, GraphTime aTo,
|
||||
|
||||
SwapMessageQueues();
|
||||
}
|
||||
mFlushSourcesNow = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -2722,6 +2723,8 @@ MediaStreamGraphImpl::MediaStreamGraphImpl(bool aRealtime,
|
||||
, mSampleRate(aSampleRate)
|
||||
, mForceShutDown(false)
|
||||
, mPostedRunInStableStateEvent(false)
|
||||
, mFlushSourcesNow(false)
|
||||
, mFlushSourcesOnNextIteration(false)
|
||||
, mDetectedNotRunning(false)
|
||||
, mPostedRunInStableState(false)
|
||||
, mRealtime(aRealtime)
|
||||
|
@ -610,6 +610,13 @@ public:
|
||||
*/
|
||||
bool mPostedRunInStableStateEvent;
|
||||
|
||||
/**
|
||||
* Used to flush any accumulated data when the output streams
|
||||
* may have stalled (on Mac after an output device change)
|
||||
*/
|
||||
bool mFlushSourcesNow;
|
||||
bool mFlushSourcesOnNextIteration;
|
||||
|
||||
// Main thread only
|
||||
|
||||
/**
|
||||
|
@ -154,6 +154,12 @@ public:
|
||||
{
|
||||
mSegment->ForgetUpTo(aTime);
|
||||
}
|
||||
void FlushAfter(TrackTicks aNewEnd)
|
||||
{
|
||||
// Forget everything after a given endpoint
|
||||
// a specified amount
|
||||
mSegment->FlushAfter(aNewEnd);
|
||||
}
|
||||
|
||||
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
|
@ -263,8 +263,9 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) :
|
||||
*aOutputTrackFinished = true;
|
||||
}
|
||||
|
||||
if (interval.mStart >= interval.mEnd)
|
||||
if (interval.mStart >= interval.mEnd) {
|
||||
break;
|
||||
}
|
||||
next = interval.mEnd;
|
||||
|
||||
// Ticks >= startTicks and < endTicks are in the interval
|
||||
@ -305,6 +306,14 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) :
|
||||
map->mEndOfConsumedInputTicks = inputEndTicks;
|
||||
map->mEndOfLastInputIntervalInInputStream = inputEnd;
|
||||
map->mEndOfLastInputIntervalInOutputStream = outputEnd;
|
||||
|
||||
if (GraphImpl()->mFlushSourcesNow) {
|
||||
TrackTicks flushto = inputEndTicks;
|
||||
STREAM_LOG(PR_LOG_DEBUG, ("TrackUnionStream %p flushing after %lld of %lld ticks of input data from track %d for track %d",
|
||||
this, flushto, aInputTrack->GetSegment()->GetDuration(), aInputTrack->GetID(), outputTrack->GetID()));
|
||||
aInputTrack->FlushAfter(flushto);
|
||||
MOZ_ASSERT(inputTrackEndPoint >= aInputTrack->GetEnd());
|
||||
}
|
||||
// Now we prove that the above properties hold:
|
||||
// Property #1: trivial by construction.
|
||||
// Property #3: trivial by construction. Between every two
|
||||
|
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
CppUnitTests([
|
||||
GeckoCppUnitTests([
|
||||
'TestAudioBuffers',
|
||||
'TestAudioMixer'
|
||||
])
|
||||
@ -14,10 +14,3 @@ FAIL_ON_WARNINGS = True
|
||||
LOCAL_INCLUDES += [
|
||||
'..',
|
||||
]
|
||||
|
||||
USE_LIBS += [
|
||||
'mozalloc',
|
||||
'nspr',
|
||||
'xpcomglue_s',
|
||||
'xul',
|
||||
]
|
||||
|
@ -531,6 +531,7 @@ MP4Reader::Decode(TrackType aTrack)
|
||||
nsAutoPtr<MP4Sample> compressed(PopSample(aTrack));
|
||||
if (!compressed) {
|
||||
// EOS, or error. Send the decoder a signal to drain.
|
||||
LOG("MP4Reader: EOS or error - no samples available");
|
||||
LOG("Draining %s", TrackTypeToStr(aTrack));
|
||||
data.mMonitor.Lock();
|
||||
MOZ_ASSERT(!data.mEOS);
|
||||
|
@ -272,7 +272,7 @@ AppleATDecoder::SampleCallback(uint32_t aNumBytes,
|
||||
packets.get());
|
||||
|
||||
if (rv && rv != kNeedMoreData) {
|
||||
LOG("Error decoding audio stream: %#x\n", rv);
|
||||
LOG("Error decoding audio stream: %d\n", rv);
|
||||
mCallback->Error();
|
||||
break;
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ public:
|
||||
|
||||
class VerifyAndFinishContinuation : public ReadContinuation {
|
||||
public:
|
||||
VerifyAndFinishContinuation(string aValue)
|
||||
explicit VerifyAndFinishContinuation(string aValue)
|
||||
: mValue(aValue)
|
||||
{}
|
||||
void ReadComplete(GMPErr aErr, const std::string& aData) MOZ_OVERRIDE {
|
||||
@ -146,7 +146,7 @@ static const string OpenAgainRecordId = "open-again-record-id";
|
||||
|
||||
class OpenedSecondTimeContinuation : public OpenContinuation {
|
||||
public:
|
||||
OpenedSecondTimeContinuation(GMPRecord* aRecord)
|
||||
explicit OpenedSecondTimeContinuation(GMPRecord* aRecord)
|
||||
: mRecord(aRecord)
|
||||
{
|
||||
}
|
||||
@ -248,7 +248,7 @@ public:
|
||||
|
||||
class ReportReadStatusContinuation : public ReadContinuation {
|
||||
public:
|
||||
ReportReadStatusContinuation(const string& aRecordId)
|
||||
explicit ReportReadStatusContinuation(const string& aRecordId)
|
||||
: mRecordId(aRecordId)
|
||||
{}
|
||||
void ReadComplete(GMPErr aErr, const std::string& aData) MOZ_OVERRIDE {
|
||||
@ -269,7 +269,7 @@ public:
|
||||
|
||||
class ReportReadRecordContinuation : public ReadContinuation {
|
||||
public:
|
||||
ReportReadRecordContinuation(const string& aRecordId)
|
||||
explicit ReportReadRecordContinuation(const string& aRecordId)
|
||||
: mRecordId(aRecordId)
|
||||
{}
|
||||
void ReadComplete(GMPErr aErr, const std::string& aData) MOZ_OVERRIDE {
|
||||
@ -330,7 +330,7 @@ FakeDecryptor::UpdateSession(uint32_t aPromiseId,
|
||||
|
||||
class CompleteShutdownTask : public GMPTask {
|
||||
public:
|
||||
CompleteShutdownTask(GMPAsyncShutdownHost* aHost)
|
||||
explicit CompleteShutdownTask(GMPAsyncShutdownHost* aHost)
|
||||
: mHost(aHost)
|
||||
{
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ private:
|
||||
|
||||
class TestAsyncShutdown : public GMPAsyncShutdown {
|
||||
public:
|
||||
TestAsyncShutdown(GMPAsyncShutdownHost* aHost)
|
||||
explicit TestAsyncShutdown(GMPAsyncShutdownHost* aHost)
|
||||
: mHost(aHost)
|
||||
{
|
||||
}
|
||||
|
@ -361,7 +361,7 @@ GMPParent::Shutdown()
|
||||
|
||||
class NotifyGMPShutdownTask : public nsRunnable {
|
||||
public:
|
||||
NotifyGMPShutdownTask(const nsAString& aNodeId)
|
||||
explicit NotifyGMPShutdownTask(const nsAString& aNodeId)
|
||||
: mNodeId(aNodeId)
|
||||
{
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ CloseFile(const nsACString& key, PRFileDesc*& entry, void* cx)
|
||||
|
||||
class GMPDiskStorage : public GMPStorage {
|
||||
public:
|
||||
GMPDiskStorage(const nsCString& aNodeId)
|
||||
explicit GMPDiskStorage(const nsCString& aNodeId)
|
||||
: mNodeId(aNodeId)
|
||||
{
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ namespace mozilla
|
||||
class MockMediaResource : public MediaResource
|
||||
{
|
||||
public:
|
||||
MockMediaResource(const char* aFileName);
|
||||
explicit MockMediaResource(const char* aFileName);
|
||||
virtual nsIURI* URI() const MOZ_OVERRIDE { return nullptr; }
|
||||
virtual nsresult Close() MOZ_OVERRIDE { return NS_OK; }
|
||||
virtual void Suspend(bool aCloseImmediately) MOZ_OVERRIDE {}
|
||||
|
@ -168,7 +168,7 @@ NS_IMPL_ISUPPORTS(GMPShutdownObserver, nsIRunnable, nsIObserver)
|
||||
|
||||
class NotifyObserversTask : public nsRunnable {
|
||||
public:
|
||||
NotifyObserversTask(const char* aTopic)
|
||||
explicit NotifyObserversTask(const char* aTopic)
|
||||
: mTopic(aTopic)
|
||||
{}
|
||||
NS_IMETHOD Run() {
|
||||
|
@ -24,7 +24,7 @@ public:
|
||||
nsRefPtr<MockMediaResource> resource;
|
||||
nsRefPtr<MP4Reader> reader;
|
||||
|
||||
TestBinding(const char* aFileName = "gizmo.mp4")
|
||||
explicit TestBinding(const char* aFileName = "gizmo.mp4")
|
||||
: decoder(new MP4Decoder())
|
||||
, resource(new MockMediaResource(aFileName))
|
||||
, reader(new MP4Reader(decoder))
|
||||
|
@ -26,7 +26,7 @@ namespace mozilla {
|
||||
class MediaSourceResource MOZ_FINAL : public MediaResource
|
||||
{
|
||||
public:
|
||||
MediaSourceResource(nsIPrincipal* aPrincipal = nullptr)
|
||||
explicit MediaSourceResource(nsIPrincipal* aPrincipal = nullptr)
|
||||
: mPrincipal(aPrincipal) {}
|
||||
|
||||
virtual nsresult Close() MOZ_OVERRIDE { return NS_OK; }
|
||||
|
@ -84,6 +84,18 @@ public:
|
||||
mTaskQueue = aTaskQueue;
|
||||
}
|
||||
|
||||
void BreakCycles()
|
||||
{
|
||||
if (mReader) {
|
||||
mReader->BreakCycles();
|
||||
mReader = nullptr;
|
||||
}
|
||||
mTaskQueue = nullptr;
|
||||
#ifdef MOZ_EME
|
||||
mCDMProxy = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
virtual nsresult SetCDMProxy(CDMProxy* aProxy)
|
||||
{
|
||||
|
@ -391,7 +391,7 @@ TrackBuffer::BreakCycles()
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
|
||||
mDecoders[i]->GetReader()->BreakCycles();
|
||||
mDecoders[i]->BreakCycles();
|
||||
}
|
||||
mDecoders.Clear();
|
||||
|
||||
|
190
dom/media/test/eme.js
Normal file
190
dom/media/test/eme.js
Normal file
@ -0,0 +1,190 @@
|
||||
const KEYSYSTEM_TYPE = "org.w3.clearkey";
|
||||
|
||||
function bail(message)
|
||||
{
|
||||
return function(err) {
|
||||
ok(false, message);
|
||||
if (err) {
|
||||
info(err);
|
||||
}
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
function ArrayBufferToString(arr)
|
||||
{
|
||||
var str = '';
|
||||
var view = new Uint8Array(arr);
|
||||
for (var i = 0; i < view.length; i++) {
|
||||
str += String.fromCharCode(view[i]);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
function StringToArrayBuffer(str)
|
||||
{
|
||||
var arr = new ArrayBuffer(str.length);
|
||||
var view = new Uint8Array(arr);
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
view[i] = str.charCodeAt(i);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
function Base64ToHex(str)
|
||||
{
|
||||
var bin = window.atob(str.replace(/-/g, "+").replace(/_/g, "/"));
|
||||
var res = "";
|
||||
for (var i = 0; i < bin.length; i++) {
|
||||
res += ("0" + bin.charCodeAt(i).toString(16)).substr(-2);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function HexToBase64(hex)
|
||||
{
|
||||
var bin = "";
|
||||
for (var i = 0; i < hex.length; i += 2) {
|
||||
bin += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
|
||||
}
|
||||
return window.btoa(bin).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
||||
}
|
||||
|
||||
function UpdateSessionFunc(test, token) {
|
||||
return function(ev) {
|
||||
var msgStr = ArrayBufferToString(ev.message);
|
||||
var msg = JSON.parse(msgStr);
|
||||
|
||||
info(token + " got message from CDM: " + msgStr);
|
||||
is(msg.type, test.sessionType, token + " key session type should match");
|
||||
ok(msg.kids, token + " message event should contain key ID array");
|
||||
|
||||
var outKeys = [];
|
||||
|
||||
for (var i = 0; i < msg.kids.length; i++) {
|
||||
var id64 = msg.kids[i];
|
||||
var idHex = Base64ToHex(msg.kids[i]).toLowerCase();
|
||||
var key = test.keys[idHex];
|
||||
|
||||
if (key) {
|
||||
info(token + " found key " + key + " for key id " + idHex);
|
||||
outKeys.push({
|
||||
"kty":"oct",
|
||||
"alg":"A128KW",
|
||||
"kid":id64,
|
||||
"k":HexToBase64(key)
|
||||
});
|
||||
} else {
|
||||
bail(token + " Couldn't find key for key id " + idHex);
|
||||
}
|
||||
}
|
||||
|
||||
var update = JSON.stringify({
|
||||
"keys" : outKeys,
|
||||
"type" : msg.type
|
||||
});
|
||||
info(token + " sending update message to CDM: " + update);
|
||||
|
||||
ev.target.update(StringToArrayBuffer(update)).then(function() {
|
||||
info(token + " MediaKeySession update ok!");
|
||||
}, bail(token + " MediaKeySession update failed"));
|
||||
}
|
||||
}
|
||||
|
||||
function PlayFragmented(test, elem)
|
||||
{
|
||||
return new Promise(function(resolve, reject) {
|
||||
var ms = new MediaSource();
|
||||
elem.src = URL.createObjectURL(ms);
|
||||
|
||||
var sb;
|
||||
var curFragment = 0;
|
||||
|
||||
function addNextFragment() {
|
||||
if (curFragment >= test.fragments.length) {
|
||||
ms.endOfStream();
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
var fragmentFile = test.fragments[curFragment++];
|
||||
|
||||
var req = new XMLHttpRequest();
|
||||
req.open("GET", fragmentFile);
|
||||
req.responseType = "arraybuffer";
|
||||
|
||||
req.addEventListener("load", function() {
|
||||
info("fetch of " + fragmentFile + " complete");
|
||||
sb.appendBuffer(new Uint8Array(req.response));
|
||||
});
|
||||
|
||||
req.addEventListener("error", bail("Error fetching " + fragmentFile));
|
||||
req.addEventListener("abort", bail("Aborted fetching " + fragmentFile));
|
||||
|
||||
info("fetching resource " + fragmentFile);
|
||||
req.send(null);
|
||||
}
|
||||
|
||||
ms.addEventListener("sourceopen", function () {
|
||||
sb = ms.addSourceBuffer(test.type);
|
||||
sb.addEventListener("updateend", addNextFragment);
|
||||
|
||||
addNextFragment();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// Returns a promise that is resovled when the media element is ready to have
|
||||
// its play() function called; when it's loaded MSE fragments, or once the load
|
||||
// has started for non-MSE video.
|
||||
function LoadTest(test, elem)
|
||||
{
|
||||
if (test.fragments) {
|
||||
return PlayFragmented(test, elem);
|
||||
}
|
||||
|
||||
// This file isn't fragmented; set the media source normally.
|
||||
return new Promise(function(resolve, reject) {
|
||||
elem.src = test.name;
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function SetupEME(test, token, params)
|
||||
{
|
||||
var v = document.createElement("video");
|
||||
|
||||
// Log events dispatched to make debugging easier...
|
||||
["loadstart", "loadedmetadata", "loadeddata", "ended",
|
||||
"play", "canplay", "playing", "canplaythrough"].forEach(function (e) {
|
||||
v.addEventListener(e, function(event) {
|
||||
info(token + " " + e);
|
||||
}, false);
|
||||
});
|
||||
|
||||
var onSetKeysFail = (params && params.onSetKeysFail)
|
||||
? params.onSetKeysFail
|
||||
: bail(token + " Failed to set MediaKeys on <video> element");
|
||||
|
||||
v.addEventListener("encrypted", function(ev) {
|
||||
info(token + " got encrypted event");
|
||||
MediaKeys.create(KEYSYSTEM_TYPE).then(function(mediaKeys) {
|
||||
info(token + " created MediaKeys object ok");
|
||||
mediaKeys.sessions = [];
|
||||
return v.setMediaKeys(mediaKeys);
|
||||
}, bail("failed to create MediaKeys object")).then(function() {
|
||||
info(token + " set MediaKeys on <video> element ok");
|
||||
|
||||
var session = v.mediaKeys.createSession(test.sessionType);
|
||||
if (params && params.onsessioncreated) {
|
||||
params.onsessioncreated(session);
|
||||
}
|
||||
session.addEventListener("message", UpdateSessionFunc(test, token));
|
||||
session.generateRequest(ev.initDataType, ev.initData).then(function() {
|
||||
}, bail(token + " Failed to initialise MediaKeySession"));
|
||||
|
||||
}, onSetKeysFail);
|
||||
});
|
||||
|
||||
return v;
|
||||
}
|
@ -140,6 +140,7 @@ support-files =
|
||||
dirac.ogg^headers^
|
||||
dynamic_redirect.sjs
|
||||
dynamic_resource.sjs
|
||||
eme.js
|
||||
gizmo-frag-cenc1.m4s
|
||||
gizmo-frag-cenc2.m4s
|
||||
gizmo-frag-cencinit.mp4
|
||||
@ -360,7 +361,11 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_defaultMuted.html]
|
||||
[test_delay_load.html]
|
||||
skip-if = buildapp == 'b2g' && toolkit != 'gonk' # bug 1082984
|
||||
[test_encryptedMediaExtensions.html]
|
||||
[test_eme_canvas_blocked.html]
|
||||
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1057908
|
||||
[test_eme_playback.html]
|
||||
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1057908
|
||||
[test_eme_stream_capture_blocked.html]
|
||||
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1057908
|
||||
[test_error_in_video_document.html]
|
||||
skip-if = toolkit == 'android' || (os == 'win' && !debug) || (os == 'mac' && !debug) # bug 608634
|
||||
|
67
dom/media/test/test_eme_canvas_blocked.html
Normal file
67
dom/media/test/test_eme_canvas_blocked.html
Normal file
@ -0,0 +1,67 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test Encrypted Media Extensions</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
<script type="text/javascript" src="eme.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
var manager = new MediaTestManager;
|
||||
|
||||
function startTest(test, token)
|
||||
{
|
||||
manager.started(token);
|
||||
|
||||
var sessions = [];
|
||||
|
||||
var v = SetupEME(test, token);
|
||||
v.preload = "auto"; // Required due to "canplay" not firing for MSE unless we do this.
|
||||
|
||||
v.addEventListener("loadeddata", function(ev) {
|
||||
var video = ev.target;
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.width = video.videoWidth;
|
||||
canvas.height = video.videoHeight;
|
||||
document.body.appendChild(canvas);
|
||||
var ctx = canvas.getContext("2d");
|
||||
var threwError = false;
|
||||
try {
|
||||
ctx.drawImage(video, 0, 0);
|
||||
} catch (ex) {
|
||||
threwError = true;
|
||||
}
|
||||
ok(threwError, token + " - Should throw an error when trying to draw EME video to canvas.");
|
||||
manager.finished(token);
|
||||
});
|
||||
|
||||
v.addEventListener("error", bail(token + " got error event"));
|
||||
|
||||
LoadTest(test, v);
|
||||
}
|
||||
|
||||
function beginTest() {
|
||||
manager.runTests(gEMETests, startTest);
|
||||
}
|
||||
|
||||
var prefs = [
|
||||
[ "media.mediasource.enabled", true ],
|
||||
[ "media.mediasource.ignore_codecs", true ],
|
||||
];
|
||||
|
||||
if (/Linux/.test(navigator.userAgent) ||
|
||||
!document.createElement('video').canPlayType("video/mp4")) {
|
||||
// XXX remove once we have mp4 PlatformDecoderModules on all platforms.
|
||||
prefs.push([ "media.fragmented-mp4.exposed", true ]);
|
||||
prefs.push([ "media.fragmented-mp4.use-blank-decoder", true ]);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({ "set" : prefs }, beginTest);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
128
dom/media/test/test_eme_playback.html
Normal file
128
dom/media/test/test_eme_playback.html
Normal file
@ -0,0 +1,128 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test Encrypted Media Extensions</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
<script type="text/javascript" src="eme.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
var manager = new MediaTestManager;
|
||||
|
||||
|
||||
function KeysChangeFunc(session, keys, token) {
|
||||
session.keyIdsReceived = [];
|
||||
for (var keyid in keys) {
|
||||
info("Set " + keyid + " to false in session.keyIdsReceived");
|
||||
session.keyIdsReceived[keyid] = false;
|
||||
}
|
||||
return function(ev) {
|
||||
var session = ev.target;
|
||||
session.gotKeysChanged = true;
|
||||
session.getUsableKeyIds().then(function(keyIds) {
|
||||
for (var k = 0; k < keyIds.length; k++) {
|
||||
var kid = Base64ToHex(window.btoa(ArrayBufferToString(keyIds[k])));
|
||||
ok(kid in session.keyIdsReceived, token + " session.keyIdsReceived contained " + kid + " as expected.");
|
||||
session.keyIdsReceived[kid] = true;
|
||||
}
|
||||
}, bail("Failed to get keyIds"));
|
||||
}
|
||||
}
|
||||
|
||||
function startTest(test, token)
|
||||
{
|
||||
manager.started(token);
|
||||
|
||||
var sessions = [];
|
||||
|
||||
var v = SetupEME(test, token,
|
||||
{
|
||||
onsessioncreated: function(session) {
|
||||
sessions.push(session);
|
||||
session.addEventListener("keyschange", KeysChangeFunc(session, test.keys, token), false);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
var gotEncrypted = false;
|
||||
var gotPlaying = false;
|
||||
|
||||
v.addEventListener("encrypted", function(ev) {
|
||||
ok(MediaKeys.isTypeSupported(KEYSYSTEM_TYPE, ev.initDataType, test.type),
|
||||
token + " MediaKeys should support this keysystem");
|
||||
gotEncrypted = true;
|
||||
});
|
||||
|
||||
v.addEventListener("playing", function () { gotPlaying = true; });
|
||||
|
||||
v.addEventListener("ended", function(ev) {
|
||||
ok(true, token + " got ended event");
|
||||
|
||||
ok(gotEncrypted, token + " encrypted event should have fired");
|
||||
ok(gotPlaying, token + " playing event should have fired");
|
||||
|
||||
ok(Math.abs(test.duration - v.duration) < 0.1,
|
||||
token + " Duration of video should be corrrect");
|
||||
ok(Math.abs(test.duration - v.currentTime) < 0.1,
|
||||
token + " Current time should be same as duration");
|
||||
|
||||
// Verify all sessions had all keys went sent the to the CDM usable, and thus
|
||||
// that we received keyschange event(s).
|
||||
is(sessions.length, 1, token + " should have 1 session");
|
||||
for (var i = 0; i < sessions.length; i++) {
|
||||
var session = sessions[i];
|
||||
ok(session.gotKeysChanged, token + " should have received at least one keychange event");
|
||||
for (var kid in session.keyIdsReceived) {
|
||||
ok(session.keyIdsReceived[kid], token + " key with id " + kid + " was usable as expected");
|
||||
}
|
||||
}
|
||||
|
||||
manager.finished(token);
|
||||
});
|
||||
|
||||
v.addEventListener("error", bail(token + " got error event"));
|
||||
|
||||
LoadTest(test, v).then(function(){v.play();}, bail(token + " failed to load"));
|
||||
}
|
||||
|
||||
function testIsTypeSupported()
|
||||
{
|
||||
var t = MediaKeys.isTypeSupported;
|
||||
const clearkey = "org.w3.clearkey";
|
||||
ok(!t("bogus", "bogon", "video/bogus"), "Invalid type.");
|
||||
ok(t(clearkey), "ClearKey supported.");
|
||||
ok(!t(clearkey, "bogus"), "ClearKey bogus initDataType not supported.");
|
||||
ok(t(clearkey, "cenc"), "ClearKey/cenc should be supported.");
|
||||
ok(!t(clearkey, "cenc", "bogus"), "ClearKey/cenc bogus content type should be supported.");
|
||||
ok(t(clearkey, "cenc", 'video/mp4'), "ClearKey/cenc video/mp4 supported.");
|
||||
ok(t(clearkey, "cenc", 'video/mp4; codecs="avc1.4d4015,mp4a.40.2"'), "ClearKey/cenc H.264/AAC supported.");
|
||||
ok(t(clearkey, "cenc", 'audio/mp4'), "ClearKey/cenc audio/mp4 supported.");
|
||||
ok(t(clearkey, "cenc", 'audio/mp4; codecs="mp4a.40.2"'), "ClearKey/cenc AAC LC supported.");
|
||||
}
|
||||
|
||||
function beginTest() {
|
||||
testIsTypeSupported();
|
||||
manager.runTests(gEMETests, startTest);
|
||||
}
|
||||
|
||||
var prefs = [
|
||||
[ "media.mediasource.enabled", true ],
|
||||
[ "media.mediasource.ignore_codecs", true ],
|
||||
];
|
||||
|
||||
if (/Linux/.test(navigator.userAgent) ||
|
||||
!document.createElement('video').canPlayType("video/mp4")) {
|
||||
// XXX remove once we have mp4 PlatformDecoderModules on all platforms.
|
||||
prefs.push([ "media.fragmented-mp4.exposed", true ]);
|
||||
prefs.push([ "media.fragmented-mp4.use-blank-decoder", true ]);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({ "set" : prefs }, beginTest);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
102
dom/media/test/test_eme_stream_capture_blocked.html
Normal file
102
dom/media/test/test_eme_stream_capture_blocked.html
Normal file
@ -0,0 +1,102 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test Encrypted Media Extensions</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
<script type="text/javascript" src="eme.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
var manager = new MediaTestManager;
|
||||
|
||||
function startTest(test, token)
|
||||
{
|
||||
// Three cases:
|
||||
// 1. setting MediaKeys on an element captured by MediaElementSource should fail, and
|
||||
// 2. creating a MediaElementSource on a media element with a MediaKeys should fail, and
|
||||
// 3. capturing a media element with mozCaptureStream that has a MediaKeys should fail.
|
||||
|
||||
// Case 1. setting MediaKeys on an element captured by MediaElementSource should fail.
|
||||
var case1token = token + "_case1";
|
||||
var setKeysFailed = function() {
|
||||
ok(true, case1token + " setMediaKeys failed as expected.");
|
||||
manager.finished(case1token);
|
||||
};
|
||||
var v1 = SetupEME(test, case1token, { onSetKeysFail: setKeysFailed });
|
||||
var context = new AudioContext();
|
||||
var node = context.createMediaElementSource(v1);
|
||||
v1.preload = "auto"; // Required due to "canplay" not firing for MSE unless we do this.
|
||||
v1.addEventListener("error", bail(case1token + " got error event"));
|
||||
v1.addEventListener("canplay", function(ev) {
|
||||
ok(false, case1token + " should never reach canplay, as setMediaKeys should fail");
|
||||
});
|
||||
manager.started(case1token);
|
||||
LoadTest(test, v1);
|
||||
|
||||
|
||||
// Case 2. creating a MediaElementSource on a media element with a MediaKeys should fail.
|
||||
var case2token = token + "_case2";
|
||||
var v2 = SetupEME(test, case2token);
|
||||
v2.preload = "auto"; // Required due to "canplay" not firing for MSE unless we do this.
|
||||
v2.addEventListener("error", bail(case2token + " got error event"));
|
||||
v2.addEventListener("canplay", function(ev) {
|
||||
ok(true, case2token + " should reach canplay");
|
||||
var threw = false;
|
||||
try {
|
||||
var context = new AudioContext();
|
||||
var node = context.createMediaElementSource(v2);
|
||||
} catch (e) {
|
||||
threw = true;
|
||||
}
|
||||
ok(threw, "Should throw an error creating a MediaElementSource on an EME video.");
|
||||
manager.finished(case2token);
|
||||
});
|
||||
manager.started(case2token);
|
||||
LoadTest(test, v2);
|
||||
|
||||
|
||||
// Case 3. capturing a media element with mozCaptureStream that has a MediaKeys should fail.
|
||||
var case3token = token + "_case3";
|
||||
var v3 = SetupEME(test, case3token);
|
||||
v3.preload = "auto"; // Required due to "canplay" not firing for MSE unless we do this.
|
||||
v3.addEventListener("error", bail(case3token + " got error event"));
|
||||
v3.addEventListener("canplay", function(ev) {
|
||||
ok(true, case3token + " should reach canplay");
|
||||
var threw = false;
|
||||
try {
|
||||
var stream = v3.mozCaptureStreamUntilEnded();
|
||||
} catch (e) {
|
||||
threw = true;
|
||||
}
|
||||
ok(threw, "Should throw an error calling mozCaptureStreamUntilEnded an EME video.");
|
||||
manager.finished(case3token);
|
||||
});
|
||||
manager.started(case3token);
|
||||
LoadTest(test, v3);
|
||||
}
|
||||
|
||||
function beginTest() {
|
||||
manager.runTests(gEMETests, startTest);
|
||||
}
|
||||
|
||||
var prefs = [
|
||||
[ "media.mediasource.enabled", true ],
|
||||
[ "media.mediasource.ignore_codecs", true ],
|
||||
];
|
||||
|
||||
if (/Linux/.test(navigator.userAgent) ||
|
||||
!document.createElement('video').canPlayType("video/mp4")) {
|
||||
// XXX remove once we have mp4 PlatformDecoderModules on all platforms.
|
||||
prefs.push([ "media.fragmented-mp4.exposed", true ]);
|
||||
prefs.push([ "media.fragmented-mp4.use-blank-decoder", true ]);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({ "set" : prefs }, beginTest);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -1,278 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test Encrypted Media Extensions</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
var manager = new MediaTestManager;
|
||||
|
||||
const KEYSYSTEM_TYPE = "org.w3.clearkey";
|
||||
|
||||
function bail(message)
|
||||
{
|
||||
return function(err) {
|
||||
ok(false, message);
|
||||
if (err) {
|
||||
info(err);
|
||||
}
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
function ArrayBufferToString(arr)
|
||||
{
|
||||
var str = '';
|
||||
var view = new Uint8Array(arr);
|
||||
for (var i = 0; i < view.length; i++) {
|
||||
str += String.fromCharCode(view[i]);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
function StringToArrayBuffer(str)
|
||||
{
|
||||
var arr = new ArrayBuffer(str.length);
|
||||
var view = new Uint8Array(arr);
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
view[i] = str.charCodeAt(i);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
function Base64ToHex(str)
|
||||
{
|
||||
var bin = window.atob(str.replace(/-/g, "+").replace(/_/g, "/"));
|
||||
var res = "";
|
||||
for (var i = 0; i < bin.length; i++) {
|
||||
res += ("0" + bin.charCodeAt(i).toString(16)).substr(-2);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function HexToBase64(hex)
|
||||
{
|
||||
var bin = "";
|
||||
for (var i = 0; i < hex.length; i += 2) {
|
||||
bin += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
|
||||
}
|
||||
return window.btoa(bin).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
||||
}
|
||||
|
||||
function UpdateSessionFunc(test) {
|
||||
return function(ev) {
|
||||
var msgStr = ArrayBufferToString(ev.message);
|
||||
var msg = JSON.parse(msgStr);
|
||||
|
||||
info("got message from CDM: " + msgStr);
|
||||
is(msg.type, test.sessionType, "Key session type should match");
|
||||
ok(msg.kids, "message event should contain key ID array");
|
||||
|
||||
var outKeys = [];
|
||||
|
||||
for (var i = 0; i < msg.kids.length; i++) {
|
||||
var id64 = msg.kids[i];
|
||||
var idHex = Base64ToHex(msg.kids[i]).toLowerCase();
|
||||
var key = test.keys[idHex];
|
||||
|
||||
if (key) {
|
||||
info("found key " + key + " for key id " + idHex);
|
||||
outKeys.push({
|
||||
"kty":"oct",
|
||||
"alg":"A128KW",
|
||||
"kid":id64,
|
||||
"k":HexToBase64(key)
|
||||
});
|
||||
} else {
|
||||
bail("Couldn't find key for key id " + idHex);
|
||||
}
|
||||
}
|
||||
|
||||
var update = JSON.stringify({
|
||||
"keys" : outKeys,
|
||||
"type" : msg.type
|
||||
});
|
||||
info("sending update message to CDM: " + update);
|
||||
|
||||
ev.target.update(StringToArrayBuffer(update)).then(function() {
|
||||
info("MediaKeySession update ok!");
|
||||
}, bail("MediaKeySession update failed"));
|
||||
}
|
||||
}
|
||||
|
||||
function PlayFragmented(test, elem)
|
||||
{
|
||||
var ms = new MediaSource();
|
||||
elem.src = URL.createObjectURL(ms);
|
||||
|
||||
var sb;
|
||||
var curFragment = 0;
|
||||
|
||||
function addNextFragment() {
|
||||
if (curFragment >= test.fragments.length) {
|
||||
ms.endOfStream();
|
||||
elem.play();
|
||||
return;
|
||||
}
|
||||
|
||||
var fragmentFile = test.fragments[curFragment++];
|
||||
|
||||
var req = new XMLHttpRequest();
|
||||
req.open("GET", fragmentFile);
|
||||
req.responseType = "arraybuffer";
|
||||
|
||||
req.addEventListener("load", function() {
|
||||
sb.appendBuffer(new Uint8Array(req.response));
|
||||
});
|
||||
|
||||
info("fetching resource " + fragmentFile);
|
||||
req.send(null);
|
||||
}
|
||||
|
||||
ms.addEventListener("sourceopen", function () {
|
||||
sb = ms.addSourceBuffer(test.type);
|
||||
sb.addEventListener("updateend", addNextFragment);
|
||||
|
||||
addNextFragment();
|
||||
});
|
||||
}
|
||||
|
||||
function PlayTest(test, elem)
|
||||
{
|
||||
if (test.fragments) {
|
||||
PlayFragmented(test, elem);
|
||||
return;
|
||||
}
|
||||
|
||||
// This file isn't fragmented; set the media source normally.
|
||||
elem.src = test.name;
|
||||
elem.play();
|
||||
}
|
||||
|
||||
function KeysChangeFunc(session, keys) {
|
||||
session.keyIdsReceived = [];
|
||||
for (var keyid in keys) {
|
||||
info("Set " + keyid + " to false in session.keyIdsReceived");
|
||||
session.keyIdsReceived[keyid] = false;
|
||||
}
|
||||
return function(ev) {
|
||||
var session = ev.target;
|
||||
session.gotKeysChanged = true;
|
||||
session.getUsableKeyIds().then(function(keyIds) {
|
||||
for (var k = 0; k < keyIds.length; k++) {
|
||||
var kid = Base64ToHex(window.btoa(ArrayBufferToString(keyIds[k])));
|
||||
ok(kid in session.keyIdsReceived, "session.keyIdsReceived contained " + kid + " as expected.");
|
||||
session.keyIdsReceived[kid] = true;
|
||||
}
|
||||
}, bail("Failed to get keyIds"));
|
||||
}
|
||||
}
|
||||
|
||||
function startTest(test, token)
|
||||
{
|
||||
manager.started(test._token);
|
||||
|
||||
var v = document.createElement("video");
|
||||
var gotEncrypted = false;
|
||||
var gotPlaying = false;
|
||||
|
||||
v.addEventListener("encrypted", function(ev) {
|
||||
gotEncrypted = true;
|
||||
|
||||
info(token + " got encrypted event");
|
||||
ok(MediaKeys.isTypeSupported(KEYSYSTEM_TYPE, ev.initDataType, test.type),
|
||||
token + " MediaKeys should support this keysystem");
|
||||
|
||||
MediaKeys.create(KEYSYSTEM_TYPE).then(function(mediaKeys) {
|
||||
info(token + " created MediaKeys object ok");
|
||||
mediaKeys.sessions = [];
|
||||
return v.setMediaKeys(mediaKeys);
|
||||
}, bail("failed to create MediaKeys object")).then(function() {
|
||||
info(token + " set MediaKeys on <video> element ok");
|
||||
|
||||
ok(MediaKeys.isTypeSupported(KEYSYSTEM_TYPE, ev.initDataType, test.type),
|
||||
"MediaKeys should still support keysystem after CDM created...");
|
||||
|
||||
var session = v.mediaKeys.createSession(test.sessionType);
|
||||
v.mediaKeys.sessions.push(session);
|
||||
session.addEventListener("keyschange", KeysChangeFunc(session, test.keys), false);
|
||||
session.addEventListener("message", UpdateSessionFunc(test));
|
||||
session.generateRequest(ev.initDataType, ev.initData).then(function() {
|
||||
}, bail(token + " Failed to initialise MediaKeySession"));
|
||||
|
||||
}, bail(token + " Failed to set MediaKeys on <video> element"));
|
||||
});
|
||||
|
||||
v.addEventListener("playing", function () { gotPlaying = true; });
|
||||
|
||||
v.addEventListener("ended", function(ev) {
|
||||
ok(true, token + " got ended event");
|
||||
manager.finished(test._token);
|
||||
|
||||
ok(gotEncrypted, token + " encrypted event should have fired");
|
||||
ok(gotPlaying, token + " playing event should have fired");
|
||||
|
||||
ok(Math.abs(test.duration - v.duration) < 0.1,
|
||||
token + " Duration of video should be corrrect");
|
||||
ok(Math.abs(test.duration - v.currentTime) < 0.1,
|
||||
token + " Current time should be same as duration");
|
||||
// Verify all sessions had all keys went sent the to the CDM usable, and thus
|
||||
// that we received keyschange event(s).
|
||||
var sessions = v.mediaKeys.sessions;
|
||||
is(sessions.length, 1, "should have 1 session");
|
||||
for (var i = 0; i < sessions.length; i++) {
|
||||
var session = sessions[i];
|
||||
ok(session.gotKeysChanged, "Should have received at least one keychange event");
|
||||
for (var kid in session.keyIdsReceived) {
|
||||
ok(session.keyIdsReceived[kid], "key with id " + kid + " was usable as expected");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
v.addEventListener("error", bail(token + " got error event"));
|
||||
|
||||
PlayTest(test, v);
|
||||
}
|
||||
|
||||
function testIsTypeSupported()
|
||||
{
|
||||
var t = MediaKeys.isTypeSupported;
|
||||
const clearkey = "org.w3.clearkey";
|
||||
ok(!t("bogus", "bogon", "video/bogus"), "Invalid type.");
|
||||
ok(t(clearkey), "ClearKey supported.");
|
||||
ok(!t(clearkey, "bogus"), "ClearKey bogus initDataType not supported.");
|
||||
ok(t(clearkey, "cenc"), "ClearKey/cenc should be supported.");
|
||||
ok(!t(clearkey, "cenc", "bogus"), "ClearKey/cenc bogus content type should be supported.");
|
||||
ok(t(clearkey, "cenc", 'video/mp4'), "ClearKey/cenc video/mp4 supported.");
|
||||
ok(t(clearkey, "cenc", 'video/mp4; codecs="avc1.4d4015,mp4a.40.2"'), "ClearKey/cenc H.264/AAC supported.");
|
||||
ok(t(clearkey, "cenc", 'audio/mp4'), "ClearKey/cenc audio/mp4 supported.");
|
||||
ok(t(clearkey, "cenc", 'audio/mp4; codecs="mp4a.40.2"'), "ClearKey/cenc AAC LC supported.");
|
||||
}
|
||||
|
||||
function beginTest() {
|
||||
testIsTypeSupported();
|
||||
manager.runTests(gEMETests, startTest);
|
||||
}
|
||||
|
||||
var prefs = [
|
||||
[ "media.mediasource.enabled", true ],
|
||||
[ "media.mediasource.ignore_codecs", true ],
|
||||
];
|
||||
|
||||
if (/Linux/.test(navigator.userAgent) ||
|
||||
!document.createElement('video').canPlayType("video/mp4")) {
|
||||
// XXX remove once we have mp4 PlatformDecoderModules on all platforms.
|
||||
prefs.push([ "media.fragmented-mp4.exposed", true ]);
|
||||
prefs.push([ "media.fragmented-mp4.use-blank-decoder", true ]);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({ "set" : prefs }, beginTest);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -285,6 +285,12 @@ AudioContext::CreateMediaElementSource(HTMLMediaElement& aMediaElement,
|
||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
#ifdef MOZ_EME
|
||||
if (aMediaElement.ContainsRestrictedContent()) {
|
||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
nsRefPtr<DOMMediaStream> stream = aMediaElement.MozCaptureStream(aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
|
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
CppUnitTests([
|
||||
GeckoCppUnitTests([
|
||||
'TestAudioEventTimeline',
|
||||
])
|
||||
|
||||
@ -13,10 +13,3 @@ FAIL_ON_WARNINGS = True
|
||||
LOCAL_INCLUDES += [
|
||||
'..',
|
||||
]
|
||||
|
||||
USE_LIBS += [
|
||||
'mozalloc',
|
||||
'nspr',
|
||||
'xpcomglue_s',
|
||||
'xul',
|
||||
]
|
||||
|
@ -19,8 +19,8 @@ namespace mozilla {
|
||||
class MediaEngineCameraVideoSource : public MediaEngineVideoSource
|
||||
{
|
||||
public:
|
||||
MediaEngineCameraVideoSource(int aIndex,
|
||||
const char* aMonitorName = "Camera.Monitor")
|
||||
explicit MediaEngineCameraVideoSource(int aIndex,
|
||||
const char* aMonitorName = "Camera.Monitor")
|
||||
: MediaEngineVideoSource(kReleased)
|
||||
, mMonitor(aMonitorName)
|
||||
, mWidth(0)
|
||||
|
@ -32,7 +32,7 @@ public:
|
||||
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)
|
||||
|
||||
Connection(nsPIDOMWindow *aWindow);
|
||||
explicit Connection(nsPIDOMWindow *aWindow);
|
||||
|
||||
void Shutdown();
|
||||
|
||||
|
@ -51,7 +51,7 @@ Cu.skipCOWCallableChecks();
|
||||
|
||||
TCPServerSocket.prototype = {
|
||||
__exposedProps__: {
|
||||
port: 'r',
|
||||
localPort: 'r',
|
||||
onconnect: 'rw',
|
||||
onerror: 'rw'
|
||||
},
|
||||
@ -77,7 +77,7 @@ TCPServerSocket.prototype = {
|
||||
this["onconnect"].call(null, socket);
|
||||
} catch (e) {
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
socket.close();
|
||||
@ -128,7 +128,7 @@ TCPServerSocket.prototype = {
|
||||
var error = new Error(message, filename, lineNumber, columnNumber);
|
||||
|
||||
this["onerror"].call(null, new TCPSocketEvent(type, this, error));
|
||||
}
|
||||
}
|
||||
},
|
||||
/* end nsITCPServerSocketInternal method */
|
||||
|
||||
@ -148,7 +148,8 @@ TCPServerSocket.prototype = {
|
||||
onSocketAccepted: function tss_onSocketAccepted(server, trans) {
|
||||
// precondition: this._inChild == false
|
||||
try {
|
||||
let that = TCPSocketInternal.createAcceptedParent(trans, this._binaryType);
|
||||
let that = TCPSocketInternal.createAcceptedParent(trans, this._binaryType,
|
||||
this.useWin);
|
||||
this._callListenerAcceptCommon(that);
|
||||
}
|
||||
catch(e) {
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include "TCPSocketParent.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/AppProcessChecker.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -58,7 +60,8 @@ TCPServerSocketParent::Init(PNeckoParent* neckoParent, const uint16_t& aLocalPor
|
||||
return true;
|
||||
}
|
||||
|
||||
rv = mIntermediary->Listen(this, aLocalPort, aBacklog, aBinaryType, getter_AddRefs(mServerSocket));
|
||||
rv = mIntermediary->Listen(this, aLocalPort, aBacklog, aBinaryType, GetAppId(),
|
||||
getter_AddRefs(mServerSocket));
|
||||
if (NS_FAILED(rv) || !mServerSocket) {
|
||||
FireInteralError(this, __LINE__);
|
||||
return true;
|
||||
@ -66,6 +69,19 @@ TCPServerSocketParent::Init(PNeckoParent* neckoParent, const uint16_t& aLocalPor
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TCPServerSocketParent::GetAppId()
|
||||
{
|
||||
uint32_t appId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
|
||||
const PContentParent *content = Manager()->Manager();
|
||||
const InfallibleTArray<PBrowserParent*>& browsers = content->ManagedPBrowserParent();
|
||||
if (browsers.Length() > 0) {
|
||||
TabParent *tab = static_cast<TabParent*>(browsers[0]);
|
||||
appId = tab->OwnAppId();
|
||||
}
|
||||
return appId;
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
TCPServerSocketParent::SendCallbackAccept(nsITCPSocketParent *socket)
|
||||
{
|
||||
|
@ -31,6 +31,8 @@ public:
|
||||
virtual bool RecvClose() MOZ_OVERRIDE;
|
||||
virtual bool RecvRequestDelete() MOZ_OVERRIDE;
|
||||
|
||||
uint32_t GetAppId();
|
||||
|
||||
void AddIPDLReference();
|
||||
void ReleaseIPDLReference();
|
||||
|
||||
|
@ -77,7 +77,13 @@ TCPSocketEvent.prototype = {
|
||||
__exposedProps__: {
|
||||
type: 'r',
|
||||
target: 'r',
|
||||
data: 'r'
|
||||
data: 'r',
|
||||
// Promise::ResolveInternal tries to check if the thing being resolved is
|
||||
// itself a promise through the presence of "then". Accordingly, we list
|
||||
// it as an exposed property, although we return undefined for it.
|
||||
// Bug 882123 covers making TCPSocket be a proper event target with proper
|
||||
// events.
|
||||
then: 'r'
|
||||
},
|
||||
get type() {
|
||||
return this._type;
|
||||
@ -87,6 +93,9 @@ TCPSocketEvent.prototype = {
|
||||
},
|
||||
get data() {
|
||||
return this._data;
|
||||
},
|
||||
get then() {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@ -310,7 +319,7 @@ TCPSocket.prototype = {
|
||||
}
|
||||
}, null);
|
||||
},
|
||||
|
||||
|
||||
_initStream: function ts_initStream(binaryType) {
|
||||
this._binaryType = binaryType;
|
||||
this._socketInputStream = this._transport.openInputStream(0, 0, 0);
|
||||
@ -431,7 +440,7 @@ TCPSocket.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
createAcceptedParent: function ts_createAcceptedParent(transport, binaryType) {
|
||||
createAcceptedParent: function ts_createAcceptedParent(transport, binaryType, windowObject) {
|
||||
let that = new TCPSocket();
|
||||
that._transport = transport;
|
||||
that._initStream(binaryType);
|
||||
@ -444,6 +453,7 @@ TCPSocket.prototype = {
|
||||
// Grab host/port from SocketTransport.
|
||||
that._host = transport.host;
|
||||
that._port = transport.port;
|
||||
that.useWin = windowObject;
|
||||
|
||||
return that;
|
||||
},
|
||||
@ -458,6 +468,7 @@ TCPSocket.prototype = {
|
||||
that._socketBridge = socketChild;
|
||||
that._host = socketChild.host;
|
||||
that._port = socketChild.port;
|
||||
that.useWin = windowObject;
|
||||
|
||||
return that;
|
||||
},
|
||||
@ -637,8 +648,7 @@ TCPSocket.prototype = {
|
||||
if (this._hasPrivileges !== true && this._hasPrivileges !== null) {
|
||||
throw new Error("TCPSocket does not have permission in this context.\n");
|
||||
}
|
||||
|
||||
let that = new TCPServerSocket(this.useWin || this);
|
||||
let that = new TCPServerSocket(this.useWin);
|
||||
|
||||
options = options || { binaryType : this.binaryType };
|
||||
backlog = backlog || -1;
|
||||
|
@ -43,9 +43,7 @@ TCPSocketParentIntermediary.prototype = {
|
||||
return null;
|
||||
|
||||
let socketInternal = socket.QueryInterface(Ci.nsITCPSocketInternal);
|
||||
if (socketInternal) {
|
||||
socketInternal.setAppId(aAppId);
|
||||
}
|
||||
socketInternal.setAppId(aAppId);
|
||||
|
||||
// Handle parent's request to update buffered amount.
|
||||
socketInternal.setOnUpdateBufferedAmountHandler(
|
||||
@ -56,7 +54,7 @@ TCPSocketParentIntermediary.prototype = {
|
||||
return socket;
|
||||
},
|
||||
|
||||
listen: function(aTCPServerSocketParent, aLocalPort, aBacklog, aBinaryType) {
|
||||
listen: function(aTCPServerSocketParent, aLocalPort, aBacklog, aBinaryType, aAppId) {
|
||||
let baseSocket = Cc["@mozilla.org/tcp-socket;1"].createInstance(Ci.nsIDOMTCPSocket);
|
||||
let serverSocket = baseSocket.listen(aLocalPort, { binaryType: aBinaryType }, aBacklog);
|
||||
if (!serverSocket)
|
||||
@ -68,12 +66,18 @@ TCPSocketParentIntermediary.prototype = {
|
||||
var socketParent = Cc["@mozilla.org/tcp-socket-parent;1"]
|
||||
.createInstance(Ci.nsITCPSocketParent);
|
||||
var intermediary = new TCPSocketParentIntermediary();
|
||||
|
||||
let socketInternal = socket.QueryInterface(Ci.nsITCPSocketInternal);
|
||||
socketInternal.setAppId(aAppId);
|
||||
socketInternal.setOnUpdateBufferedAmountHandler(
|
||||
intermediary._onUpdateBufferedAmountHandler.bind(intermediary, socketParent));
|
||||
|
||||
// Handlers are set to the JS-implemented socket object on the parent side,
|
||||
// so that the socket parent object can communicate data
|
||||
// with the corresponding socket child object through IPC.
|
||||
intermediary._setCallbacks(socketParent, socket);
|
||||
// The members in the socket parent object are set with arguments,
|
||||
// so that the socket parent object can communicate data
|
||||
// so that the socket parent object can communicate data
|
||||
// with the JS socket object on the parent side via the intermediary object.
|
||||
socketParent.setSocketAndIntermediary(socket, intermediary);
|
||||
aTCPServerSocketParent.sendCallbackAccept(socketParent);
|
||||
|
@ -216,7 +216,7 @@ interface nsIDOMTCPSocket : nsISupports
|
||||
* Needed to account for multiple possible types that can be provided to
|
||||
* the socket callbacks as arguments.
|
||||
*/
|
||||
[scriptable, uuid(017f130f-2477-4215-8783-57eada957699)]
|
||||
[scriptable, uuid(b1235064-9a08-4714-ad03-1212e4562803)]
|
||||
interface nsITCPSocketInternal : nsISupports {
|
||||
// Trigger the callback for |type| and provide a DOMError() object with the given data
|
||||
void callListenerError(in DOMString type, in DOMString name);
|
||||
@ -253,8 +253,11 @@ interface nsITCPSocketInternal : nsISupports {
|
||||
// @param binaryType
|
||||
// "arraybuffer" to use ArrayBuffer instances
|
||||
// in the ondata callback and as the argument to send.
|
||||
// @param window
|
||||
// An object to create ArrayBuffer for this window. See Bug 831107.
|
||||
nsIDOMTCPSocket createAcceptedParent(in nsISocketTransport transport,
|
||||
in DOMString binaryType);
|
||||
in DOMString binaryType,
|
||||
in nsIDOMWindow window);
|
||||
|
||||
// Create a DOM socket on the child side
|
||||
// This is called when the socket is accepted on the parent side.
|
||||
|
@ -76,7 +76,8 @@ interface nsITCPSocketIntermediary : nsISupports {
|
||||
// Listen on a port
|
||||
nsIDOMTCPServerSocket listen(in nsITCPServerSocketParent parent,
|
||||
in unsigned short port, in unsigned short backlog,
|
||||
in DOMString binaryType);
|
||||
in DOMString binaryType,
|
||||
in unsigned long appId);
|
||||
|
||||
// Called when received a child request to send a string.
|
||||
void onRecvSendString(in DOMString data, in uint32_t trackingNumber);
|
||||
|
83
dom/network/tests/add_task.js
Normal file
83
dom/network/tests/add_task.js
Normal file
@ -0,0 +1,83 @@
|
||||
// Temporary implementation of add_task for mochitest-plain until bug 1078657 is
|
||||
// implemented.
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
(function(scope) {
|
||||
var pendingTasks = [];
|
||||
var pendingPromise = null;
|
||||
|
||||
// Strict spawn function that takes a known generatorFunc and assumes that
|
||||
// every yielded value will be a Promise. If nesting is desired, then yield*
|
||||
// should be used!
|
||||
function spawn(generatorFunc) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
try {
|
||||
var iterator = generatorFunc();
|
||||
}
|
||||
catch (ex) {
|
||||
ok(false, 'Problem invoking generator func: ' + ex + ': ' + ex.stack);
|
||||
return;
|
||||
}
|
||||
var stepResolved = function(result) {
|
||||
try {
|
||||
var iterStep = iterator.next(result);
|
||||
}
|
||||
catch (ex) {
|
||||
ok(false, 'Problem invoking iterator step: ' + ex + ': ' + ex.stack);
|
||||
return;
|
||||
}
|
||||
if (iterStep.done) {
|
||||
resolve(iterStep.value);
|
||||
return;
|
||||
}
|
||||
if (!iterStep.value || !iterStep.value.then) {
|
||||
ok(false, 'Iterator step returned non-Promise: ' + iterStep.value);
|
||||
}
|
||||
iterStep.value.then(stepResolved, generalErrback);
|
||||
};
|
||||
stepResolved();
|
||||
});
|
||||
}
|
||||
|
||||
function maybeSpawn(promiseOrGenerator) {
|
||||
if (promiseOrGenerator.then) {
|
||||
return promiseOrGenerator;
|
||||
}
|
||||
return spawn(promiseOrGenerator);
|
||||
}
|
||||
|
||||
scope.add_task = function(thing) {
|
||||
pendingTasks.push(thing);
|
||||
};
|
||||
|
||||
function generalErrback(ex) {
|
||||
ok(false,
|
||||
'A rejection happened: ' +
|
||||
(ex ? (ex + ': ' + ex.stack) : ''));
|
||||
}
|
||||
|
||||
function runNextTask() {
|
||||
if (pendingTasks.length) {
|
||||
pendingPromise = maybeSpawn(pendingTasks.shift());
|
||||
pendingPromise.then(runNextTask, generalErrback);
|
||||
} else {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger runNextTask after we think all JS files have been loaded.
|
||||
// The primary goal is that we can call SimpleTest.finish() after all test
|
||||
// code has been loaded and run. We gate this based on the document's
|
||||
// readyState.
|
||||
var running = false;
|
||||
function maybeStartRunning() {
|
||||
if (!running && document.readyState === 'complete') {
|
||||
running = true;
|
||||
document.removeEventListener('readystateChange', maybeStartRunning);
|
||||
// Defer to a subsequent turn of the event loop to let micro-tasks and any
|
||||
// other clever setTimeout(0) instances run first.
|
||||
window.setTimeout(runNextTask, 0);
|
||||
}
|
||||
}
|
||||
document.addEventListener('readystatechange', maybeStartRunning);
|
||||
maybeStartRunning();
|
||||
})(this);
|
@ -1,9 +1,12 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
add_task.js
|
||||
file_udpsocket_iframe.html
|
||||
test_tcpsocket_client_and_server_basics.js
|
||||
|
||||
[test_network_basics.html]
|
||||
skip-if = toolkit == "gonk" || toolkit == 'android'
|
||||
[test_tcpsocket_client_and_server_basics.html]
|
||||
[test_tcpsocket_default_permissions.html]
|
||||
skip-if = toolkit == "gonk"
|
||||
[test_tcpsocket_enabled_no_perm.html]
|
||||
|
@ -0,0 +1,27 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Core tests for TCPSocket and TCPServerSocket that replace their previous
|
||||
separate xpcshell incarnations. This migration and cleanup occurred as part
|
||||
of bug 1084245 in order to get coverage of the tests from content.
|
||||
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1084245
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1084245</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" src="add_task.js"></script>
|
||||
<script type="application/javascript;version=1.7" src="test_tcpsocket_client_and_server_basics.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1084245">Mozilla Bug 1084245</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
363
dom/network/tests/test_tcpsocket_client_and_server_basics.js
Normal file
363
dom/network/tests/test_tcpsocket_client_and_server_basics.js
Normal file
@ -0,0 +1,363 @@
|
||||
'use strict';
|
||||
|
||||
const SERVER_BACKLOG = -1;
|
||||
|
||||
const SOCKET_EVENTS = ['open', 'data', 'drain', 'error', 'close'];
|
||||
|
||||
function concatUint8Arrays(a, b) {
|
||||
let newArr = new Uint8Array(a.length + b.length);
|
||||
newArr.set(a, 0);
|
||||
newArr.set(b, a.length);
|
||||
return newArr;
|
||||
}
|
||||
|
||||
function assertUint8ArraysEqual(a, b, comparingWhat) {
|
||||
if (a.length !== b.length) {
|
||||
ok(false, comparingWhat + ' arrays do not have the same length; ' +
|
||||
a.length + ' versus ' + b.length);
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
if (a[i] !== b[i]) {
|
||||
ok(false, comparingWhat + ' arrays differ at index ' + i +
|
||||
a[i] + ' versus ' + b[i]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ok(true, comparingWhat + ' arrays were equivalent.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to add event listeners to a socket and provide two Promise-returning
|
||||
* helpers (see below for docs on them). This *must* be called during the turn of
|
||||
* the event loop where TCPSocket.open is called or the onconnect method is being
|
||||
* invoked.
|
||||
*/
|
||||
function listenForEventsOnSocket(socket, socketType) {
|
||||
let wantDataLength = null;
|
||||
let pendingResolve = null;
|
||||
let receivedEvents = [];
|
||||
let receivedData = null;
|
||||
let handleGenericEvent = function(event) {
|
||||
dump('(' + socketType + ' event: ' + event.type + ')\n');
|
||||
if (pendingResolve && wantDataLength === null) {
|
||||
pendingResolve(event);
|
||||
pendingResolve = null;
|
||||
} else {
|
||||
receivedEvents.push(event);
|
||||
}
|
||||
};
|
||||
|
||||
socket.onopen = handleGenericEvent;
|
||||
socket.ondrain = handleGenericEvent;
|
||||
socket.onerror = handleGenericEvent;
|
||||
socket.onclose = handleGenericEvent;
|
||||
socket.ondata = function(event) {
|
||||
dump('(' + socketType + ' event: ' + event.type + ' length: ' +
|
||||
event.data.byteLength + ')\n');
|
||||
var arr = new Uint8Array(event.data);
|
||||
if (receivedData === null) {
|
||||
receivedData = arr;
|
||||
} else {
|
||||
receivedData = concatUint8Arrays(receivedData, arr);
|
||||
}
|
||||
if (wantDataLength !== null &&
|
||||
receivedData.length >= wantDataLength) {
|
||||
pendingResolve(receivedData);
|
||||
pendingResolve = null;
|
||||
receivedData = null;
|
||||
wantDataLength = null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return {
|
||||
/**
|
||||
* Return a Promise that will be resolved with the next (non-data) event
|
||||
* received by the socket. If there are queued events, the Promise will
|
||||
* be immediately resolved (but you won't see that until a future turn of
|
||||
* the event loop).
|
||||
*/
|
||||
waitForEvent: function() {
|
||||
if (pendingResolve) {
|
||||
throw new Error('only one wait allowed at a time.');
|
||||
}
|
||||
|
||||
if (receivedEvents.length) {
|
||||
return Promise.resolve(receivedEvents.shift());
|
||||
}
|
||||
|
||||
dump('(' + socketType + ' waiting for event)\n');
|
||||
return new Promise(function(resolve, reject) {
|
||||
pendingResolve = resolve;
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Return a Promise that will be resolved with a Uint8Array of at least the
|
||||
* given length. We buffer / accumulate received data until we have enough
|
||||
* data. Data is buffered even before you call this method, so be sure to
|
||||
* explicitly wait for any and all data sent by the other side.
|
||||
*/
|
||||
waitForDataWithAtLeastLength: function(length) {
|
||||
if (pendingResolve) {
|
||||
throw new Error('only one wait allowed at a time.');
|
||||
}
|
||||
if (receivedData && receivedData.length >= length) {
|
||||
let promise = Promise.resolve(receivedData);
|
||||
receivedData = null;
|
||||
return promise;
|
||||
}
|
||||
dump('(' + socketType + ' waiting for ' + length + ' bytes)\n');
|
||||
return new Promise(function(resolve, reject) {
|
||||
pendingResolve = resolve;
|
||||
wantDataLength = length;
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a promise that is resolved when the server receives a connection. The
|
||||
* promise is resolved with { socket, queue } where `queue` is the result of
|
||||
* calling listenForEventsOnSocket(socket). This must be done because we need
|
||||
* to add the event listener during the connection.
|
||||
*/
|
||||
function waitForConnection(listeningServer) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
// Because of the event model of sockets, we can't use the
|
||||
// listenForEventsOnSocket mechanism; we need to hook up listeners during
|
||||
// the connect event.
|
||||
listeningServer.onconnect = function(socket) {
|
||||
// Clobber the listener to get upset if it receives any more connections
|
||||
// after this.
|
||||
listeningServer.onconnect = function() {
|
||||
ok(false, 'Received a connection when not expecting one.');
|
||||
};
|
||||
ok(true, 'Listening server accepted socket');
|
||||
resolve({
|
||||
socket: socket,
|
||||
queue: listenForEventsOnSocket(socket, 'server')
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function defer() {
|
||||
var deferred = {};
|
||||
deferred.promise = new Promise(function(resolve, reject) {
|
||||
deferred.resolve = resolve;
|
||||
deferred.reject = reject;
|
||||
});
|
||||
return deferred;
|
||||
}
|
||||
|
||||
|
||||
function* test_basics() {
|
||||
// Enable our use of TCPSocket
|
||||
let prefDeferred = defer();
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ set: [ ['dom.mozTCPSocket.enabled', true] ] },
|
||||
prefDeferred.resolve);
|
||||
yield prefDeferred.promise;
|
||||
|
||||
let permDeferred = defer();
|
||||
SpecialPowers.pushPermissions(
|
||||
[ { type: 'tcp-socket', allow: true, context: document } ],
|
||||
permDeferred.resolve);
|
||||
yield permDeferred.promise;
|
||||
|
||||
// See bug 903830; in e10s mode we never get to find out the localPort if we
|
||||
// let it pick a free port by choosing 0. This is the same port the xpcshell
|
||||
// test was using.
|
||||
let serverPort = 8085;
|
||||
|
||||
let TCPSocket = navigator.mozTCPSocket;
|
||||
// - Start up a listening socket.
|
||||
let listeningServer = TCPSocket.listen(serverPort,
|
||||
{ binaryType: 'arraybuffer' },
|
||||
SERVER_BACKLOG);
|
||||
|
||||
let connectedPromise = waitForConnection(listeningServer);
|
||||
|
||||
// -- Open a connection to the server
|
||||
let clientSocket = TCPSocket.open('127.0.0.1', serverPort,
|
||||
{ binaryType: 'arraybuffer' });
|
||||
let clientQueue = listenForEventsOnSocket(clientSocket, 'client');
|
||||
|
||||
// (the client connects)
|
||||
is((yield clientQueue.waitForEvent()).type, 'open', 'got open event');
|
||||
is(clientSocket.readyState, 'open', 'client readyState is open');
|
||||
|
||||
// (the server connected)
|
||||
let { socket: serverSocket, queue: serverQueue } = yield connectedPromise;
|
||||
is(serverSocket.readyState, 'open', 'server readyState is open');
|
||||
|
||||
// -- Simple send / receive
|
||||
// - Send data from client to server
|
||||
// (But not so much we cross the drain threshold.)
|
||||
let smallUint8Array = new Uint8Array(256);
|
||||
for (let i = 0; i < smallUint8Array.length; i++) {
|
||||
smallUint8Array[i] = i;
|
||||
}
|
||||
is(clientSocket.send(smallUint8Array.buffer, 0, smallUint8Array.length), true,
|
||||
'Client sending less than 64k, buffer should not be full.');
|
||||
|
||||
let serverReceived = yield serverQueue.waitForDataWithAtLeastLength(256);
|
||||
assertUint8ArraysEqual(serverReceived, smallUint8Array,
|
||||
'Server received/client sent');
|
||||
|
||||
// - Send data from server to client
|
||||
// (But not so much we cross the drain threshold.)
|
||||
is(serverSocket.send(smallUint8Array.buffer, 0, smallUint8Array.length), true,
|
||||
'Server sending less than 64k, buffer should not be full.');
|
||||
|
||||
let clientReceived = yield clientQueue.waitForDataWithAtLeastLength(256);
|
||||
assertUint8ArraysEqual(clientReceived, smallUint8Array,
|
||||
'Client received/server sent');
|
||||
|
||||
// -- Perform sending multiple times with different buffer slices
|
||||
// - Send data from client to server
|
||||
// (But not so much we cross the drain threshold.)
|
||||
is(clientSocket.send(smallUint8Array.buffer, 0, 7),
|
||||
true, 'Client sending less than 64k, buffer should not be full.');
|
||||
is(clientSocket.send(smallUint8Array.buffer, 7, smallUint8Array.length - 7),
|
||||
true, 'Client sending less than 64k, buffer should not be full.');
|
||||
|
||||
serverReceived = yield serverQueue.waitForDataWithAtLeastLength(256);
|
||||
assertUint8ArraysEqual(serverReceived, smallUint8Array,
|
||||
'Server received/client sent');
|
||||
|
||||
// - Send data from server to client
|
||||
// (But not so much we cross the drain threshold.)
|
||||
is(serverSocket.send(smallUint8Array.buffer, 0, 7),
|
||||
true, 'Server sending less than 64k, buffer should not be full.');
|
||||
is(serverSocket.send(smallUint8Array.buffer, 7, smallUint8Array.length - 7),
|
||||
true, 'Server sending less than 64k, buffer should not be full.');
|
||||
|
||||
clientReceived = yield clientQueue.waitForDataWithAtLeastLength(256);
|
||||
assertUint8ArraysEqual(clientReceived, smallUint8Array,
|
||||
'Client received/server sent');
|
||||
|
||||
|
||||
// -- Send "big" data in both directions
|
||||
// (Enough to cross the buffering/drain threshold; 64KiB)
|
||||
let bigUint8Array = new Uint8Array(65536 + 3);
|
||||
for (let i = 0; i < bigUint8Array.length; i++) {
|
||||
bigUint8Array[i] = i % 256;
|
||||
}
|
||||
// Do this twice so we have confidence that the 'drain' event machinery
|
||||
// doesn't break after the first use.
|
||||
for (let iSend = 0; iSend < 2; iSend++) {
|
||||
// - Send "big" data from the client to the server
|
||||
is(clientSocket.send(bigUint8Array.buffer, 0, bigUint8Array.length), false,
|
||||
'Client sending more than 64k should result in the buffer being full.');
|
||||
is((yield clientQueue.waitForEvent()).type, 'drain',
|
||||
'The drain event should fire after a large send that indicated full.');
|
||||
|
||||
serverReceived = yield serverQueue.waitForDataWithAtLeastLength(
|
||||
bigUint8Array.length);
|
||||
assertUint8ArraysEqual(serverReceived, bigUint8Array,
|
||||
'server received/client sent');
|
||||
|
||||
// - Send "big" data from the server to the client
|
||||
is(serverSocket.send(bigUint8Array.buffer, 0, bigUint8Array.length), false,
|
||||
'Server sending more than 64k should result in the buffer being full.');
|
||||
is((yield serverQueue.waitForEvent()).type, 'drain',
|
||||
'The drain event should fire after a large send that indicated full.');
|
||||
|
||||
clientReceived = yield clientQueue.waitForDataWithAtLeastLength(
|
||||
bigUint8Array.length);
|
||||
assertUint8ArraysEqual(clientReceived, bigUint8Array,
|
||||
'client received/server sent');
|
||||
}
|
||||
|
||||
// -- Server closes the connection
|
||||
serverSocket.close();
|
||||
is(serverSocket.readyState, 'closing',
|
||||
'readyState should be closing immediately after calling close');
|
||||
|
||||
is((yield clientQueue.waitForEvent()).type, 'close',
|
||||
'The client should get a close event when the server closes.');
|
||||
is(clientSocket.readyState, 'closed',
|
||||
'client readyState should be closed after close event');
|
||||
is((yield serverQueue.waitForEvent()).type, 'close',
|
||||
'The server should get a close event when it closes itself.');
|
||||
is(serverSocket.readyState, 'closed',
|
||||
'server readyState should be closed after close event');
|
||||
|
||||
// -- Re-establish connection
|
||||
connectedPromise = waitForConnection(listeningServer);
|
||||
clientSocket = TCPSocket.open('127.0.0.1', serverPort,
|
||||
{ binaryType: 'arraybuffer' });
|
||||
clientQueue = listenForEventsOnSocket(clientSocket, 'client');
|
||||
is((yield clientQueue.waitForEvent()).type, 'open', 'got open event');
|
||||
|
||||
let connectedResult = yield connectedPromise;
|
||||
// destructuring assignment is not yet ES6 compliant, must manually unpack
|
||||
serverSocket = connectedResult.socket;
|
||||
serverQueue = connectedResult.queue;
|
||||
|
||||
// -- Client closes the connection
|
||||
clientSocket.close();
|
||||
is(clientSocket.readyState, 'closing',
|
||||
'client readyState should be losing immediately after calling close');
|
||||
|
||||
is((yield clientQueue.waitForEvent()).type, 'close',
|
||||
'The client should get a close event when it closes itself.');
|
||||
is(clientSocket.readyState, 'closed',
|
||||
'client readyState should be closed after the close event is received');
|
||||
is((yield serverQueue.waitForEvent()).type, 'close',
|
||||
'The server should get a close event when the client closes.');
|
||||
is(serverSocket.readyState, 'closed',
|
||||
'server readyState should be closed after the close event is received');
|
||||
|
||||
|
||||
// -- Re-establish connection
|
||||
connectedPromise = waitForConnection(listeningServer);
|
||||
clientSocket = TCPSocket.open('127.0.0.1', serverPort,
|
||||
{ binaryType: 'arraybuffer' });
|
||||
clientQueue = listenForEventsOnSocket(clientSocket, 'client');
|
||||
is((yield clientQueue.waitForEvent()).type, 'open', 'got open event');
|
||||
|
||||
connectedResult = yield connectedPromise;
|
||||
// destructuring assignment is not yet ES6 compliant, must manually unpack
|
||||
serverSocket = connectedResult.socket;
|
||||
serverQueue = connectedResult.queue;
|
||||
|
||||
// -- Call close after enqueueing a lot of data, make sure it goes through.
|
||||
// We'll have the client send and close.
|
||||
is(clientSocket.send(bigUint8Array.buffer, 0, bigUint8Array.length), false,
|
||||
'Client sending more than 64k should result in the buffer being full.');
|
||||
clientSocket.close();
|
||||
// The drain will still fire
|
||||
is((yield clientQueue.waitForEvent()).type, 'drain',
|
||||
'The drain event should fire after a large send that returned true.');
|
||||
// Then we'll get a close
|
||||
is((yield clientQueue.waitForEvent()).type, 'close',
|
||||
'The close event should fire after the drain event.');
|
||||
|
||||
// The server will get its data
|
||||
serverReceived = yield serverQueue.waitForDataWithAtLeastLength(
|
||||
bigUint8Array.length);
|
||||
assertUint8ArraysEqual(serverReceived, bigUint8Array,
|
||||
'server received/client sent');
|
||||
// And a close.
|
||||
is((yield serverQueue.waitForEvent()).type, 'close',
|
||||
'The drain event should fire after a large send that returned true.');
|
||||
|
||||
|
||||
// -- Close the listening server (and try to connect)
|
||||
// We want to verify that the server actually closes / stops listening when
|
||||
// we tell it to.
|
||||
listeningServer.close();
|
||||
|
||||
// - try and connect, get an error
|
||||
clientSocket = TCPSocket.open('127.0.0.1', serverPort,
|
||||
{ binaryType: 'arraybuffer' });
|
||||
clientQueue = listenForEventsOnSocket(clientSocket, 'client');
|
||||
is((yield clientQueue.waitForEvent()).type, 'error', 'fail to connect');
|
||||
is(clientSocket.readyState, 'closed',
|
||||
'client readyState should be closed after the failure to connect');
|
||||
}
|
||||
|
||||
add_task(test_basics);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user