merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2014-10-30 14:45:37 +01:00
commit a758e037c4
347 changed files with 4509 additions and 4266 deletions

View File

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

View File

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

View File

@ -63,6 +63,7 @@ LOCAL_INCLUDES += [
'/accessible/ipc',
'/accessible/xpcom',
'/accessible/xul',
'/dom/base',
'/dom/xbl',
'/ipc/chromium/src',
'/layout/generic',

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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:]))))

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -641,8 +641,6 @@ endif
endif # NO_PROFILE_GUIDED_OPTIMIZE
MOZ_PROGRAM_LDFLAGS += $(MOZ_GLUE_PROGRAM_LDFLAGS)
##############################################
checkout:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -80,7 +80,7 @@ private:
class TestAsyncShutdown : public GMPAsyncShutdown {
public:
TestAsyncShutdown(GMPAsyncShutdownHost* aHost)
explicit TestAsyncShutdown(GMPAsyncShutdownHost* aHost)
: mHost(aHost)
{
}

View File

@ -361,7 +361,7 @@ GMPParent::Shutdown()
class NotifyGMPShutdownTask : public nsRunnable {
public:
NotifyGMPShutdownTask(const nsAString& aNodeId)
explicit NotifyGMPShutdownTask(const nsAString& aNodeId)
: mNodeId(aNodeId)
{
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

@ -32,7 +32,7 @@ public:
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)
Connection(nsPIDOMWindow *aWindow);
explicit Connection(nsPIDOMWindow *aWindow);
void Shutdown();

View File

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

View File

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

View File

@ -31,6 +31,8 @@ public:
virtual bool RecvClose() MOZ_OVERRIDE;
virtual bool RecvRequestDelete() MOZ_OVERRIDE;
uint32_t GetAppId();
void AddIPDLReference();
void ReleaseIPDLReference();

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View 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