зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to b2g-inbound
This commit is contained in:
Коммит
7152bb64a1
2
CLOBBER
2
CLOBBER
|
@ -22,4 +22,4 @@
|
|||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Merge day clobber
|
||||
Bug 1061335 - CLOBBER for Win32 compiler update.
|
||||
|
|
|
@ -15,7 +15,7 @@ export MOZILLA_OFFICIAL=1
|
|||
export MOZ_TELEMETRY_REPORTING=1
|
||||
|
||||
if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
|
||||
. $topsrcdir/build/win32/mozconfig.vs2010-win64
|
||||
. $topsrcdir/build/win32/mozconfig.vs2013-win64
|
||||
else
|
||||
. $topsrcdir/build/win32/mozconfig.vs2010
|
||||
fi
|
||||
|
|
|
@ -14,7 +14,7 @@ export MOZILLA_OFFICIAL=1
|
|||
export MOZ_TELEMETRY_REPORTING=1
|
||||
|
||||
if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
|
||||
. $topsrcdir/build/win32/mozconfig.vs2010-win64
|
||||
. $topsrcdir/build/win32/mozconfig.vs2013-win64
|
||||
else
|
||||
. $topsrcdir/build/win32/mozconfig.vs2010
|
||||
fi
|
||||
|
|
|
@ -115,7 +115,6 @@
|
|||
#ifdef XP_UNIX
|
||||
#ifndef XP_MACOSX
|
||||
@BINPATH@/run-mozilla.sh
|
||||
@BINPATH@/mozilla-xremote-client
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -290,6 +290,11 @@ function openPrefs() {
|
|||
|
||||
function init() {
|
||||
fxAccounts.getSignedInUser().then(user => {
|
||||
// tests in particular might cause the window to start closing before
|
||||
// getSignedInUser has returned.
|
||||
if (window.closed) {
|
||||
return;
|
||||
}
|
||||
// If the url contains an entrypoint query parameter, extract it into a variable
|
||||
// to append it to the accounts URI resource.
|
||||
// Works for the following cases:
|
||||
|
@ -301,11 +306,6 @@ function init() {
|
|||
if (entryPointPos >= 0) {
|
||||
entryPoint = window.location.href.substring(entryPointPos).split("&")[0];
|
||||
}
|
||||
// tests in particular might cause the window to start closing before
|
||||
// getSignedInUser has returned.
|
||||
if (window.closed) {
|
||||
return;
|
||||
}
|
||||
if (window.location.href.contains("action=signin")) {
|
||||
if (user) {
|
||||
// asking to sign-in when already signed in just shows manage.
|
||||
|
|
|
@ -394,17 +394,31 @@ Sanitizer.prototype = {
|
|||
clear: function ()
|
||||
{
|
||||
// Clear site-specific permissions like "Allow this site to open popups"
|
||||
// we ignore the "end" range and hope it is now() - none of the
|
||||
// interfaces used here support a true range anyway.
|
||||
let startDateMS = this.range == null ? null : this.range[0] / 1000;
|
||||
var pm = Components.classes["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Components.interfaces.nsIPermissionManager);
|
||||
pm.removeAll();
|
||||
if (startDateMS == null) {
|
||||
pm.removeAll();
|
||||
} else {
|
||||
pm.removeAllSince(startDateMS);
|
||||
}
|
||||
|
||||
// Clear site-specific settings like page-zoom level
|
||||
var cps = Components.classes["@mozilla.org/content-pref/service;1"]
|
||||
.getService(Components.interfaces.nsIContentPrefService2);
|
||||
cps.removeAllDomains(null);
|
||||
if (startDateMS == null) {
|
||||
cps.removeAllDomains(null);
|
||||
} else {
|
||||
cps.removeAllDomainsSince(startDateMS, null);
|
||||
}
|
||||
|
||||
// Clear "Never remember passwords for this site", which is not handled by
|
||||
// the permission manager
|
||||
// (Note the login manager doesn't support date ranges yet, and bug
|
||||
// 1058438 is calling for loginSaving stuff to end up in the
|
||||
// permission manager)
|
||||
var pwmgr = Components.classes["@mozilla.org/login-manager;1"]
|
||||
.getService(Components.interfaces.nsILoginManager);
|
||||
var hosts = pwmgr.getAllDisabledHosts();
|
||||
|
@ -412,7 +426,8 @@ Sanitizer.prototype = {
|
|||
pwmgr.setLoginSavingEnabled(host, true);
|
||||
}
|
||||
|
||||
// Clear site security settings
|
||||
// Clear site security settings - no support for ranges in this
|
||||
// interface either, so we clearAll().
|
||||
var sss = Cc["@mozilla.org/ssservice;1"]
|
||||
.getService(Ci.nsISiteSecurityService);
|
||||
sss.clearAll();
|
||||
|
|
|
@ -1605,11 +1605,21 @@ this.MozLoopService = {
|
|||
MozLoopServiceInternal.clearError("profile");
|
||||
}),
|
||||
|
||||
openFxASettings: function() {
|
||||
let url = new URL("/settings", gFxAOAuthClient.parameters.content_uri);
|
||||
let win = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
win.switchToTabHavingURI(url.toString(), true);
|
||||
},
|
||||
openFxASettings: Task.async(function() {
|
||||
try {
|
||||
let fxAOAuthClient = yield MozLoopServiceInternal.promiseFxAOAuthClient();
|
||||
if (!fxAOAuthClient) {
|
||||
log.error("Could not get the OAuth client");
|
||||
return;
|
||||
}
|
||||
|
||||
let url = new URL("/settings", fxAOAuthClient.parameters.content_uri);
|
||||
let win = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
win.switchToTabHavingURI(url.toString(), true);
|
||||
} catch (ex) {
|
||||
log.error("Error opening FxA settings", ex);
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Performs a hawk based request to the loop server.
|
||||
|
|
|
@ -391,3 +391,41 @@ add_task(function* loginWithRegistration401() {
|
|||
|
||||
yield checkFxA401();
|
||||
});
|
||||
|
||||
add_task(function* openFxASettings() {
|
||||
yield resetFxA();
|
||||
|
||||
// Since the default b-c window has a blank tab, open a new non-blank tab to
|
||||
// force switchToTabHavingURI to open a new tab instead of reusing the current
|
||||
// blank tab.
|
||||
gBrowser.selectedTab = gBrowser.addTab(BASE_URL);
|
||||
|
||||
let params = {
|
||||
client_id: "client_id",
|
||||
content_uri: BASE_URL + "/content",
|
||||
oauth_uri: BASE_URL + "/oauth",
|
||||
profile_uri: BASE_URL + "/profile",
|
||||
state: "state",
|
||||
test_error: "token_401",
|
||||
};
|
||||
yield promiseOAuthParamsSetup(BASE_URL, params);
|
||||
|
||||
let deferredTab = Promise.defer();
|
||||
let progressListener = {
|
||||
onLocationChange: function onLocationChange(aBrowser) {
|
||||
gBrowser.removeTabsProgressListener(progressListener);
|
||||
let contentURI = Services.io.newURI(params.content_uri, null, null);
|
||||
is(aBrowser.currentURI.spec, Services.io.newURI("/settings", null, contentURI).spec,
|
||||
"Check settings tab URL");
|
||||
deferredTab.resolve();
|
||||
},
|
||||
};
|
||||
gBrowser.addTabsProgressListener(progressListener);
|
||||
|
||||
MozLoopService.openFxASettings();
|
||||
|
||||
yield deferredTab.promise;
|
||||
while (gBrowser.tabs.length > 1) {
|
||||
gBrowser.removeTab(gBrowser.tabs[1]);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -342,86 +342,6 @@ nsBrowserContentHandler.prototype = {
|
|||
cmdLine.preventDefault = true;
|
||||
}
|
||||
|
||||
try {
|
||||
var remoteCommand = cmdLine.handleFlagWithParam("remote", true);
|
||||
}
|
||||
catch (e) {
|
||||
throw NS_ERROR_ABORT;
|
||||
}
|
||||
|
||||
if (remoteCommand != null) {
|
||||
try {
|
||||
var a = /^\s*(\w+)\(([^\)]*)\)\s*$/.exec(remoteCommand);
|
||||
var remoteVerb;
|
||||
if (a) {
|
||||
remoteVerb = a[1].toLowerCase();
|
||||
var remoteParams = [];
|
||||
var sepIndex = a[2].lastIndexOf(",");
|
||||
if (sepIndex == -1)
|
||||
remoteParams[0] = a[2];
|
||||
else {
|
||||
remoteParams[0] = a[2].substring(0, sepIndex);
|
||||
remoteParams[1] = a[2].substring(sepIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
switch (remoteVerb) {
|
||||
case "openurl":
|
||||
case "openfile":
|
||||
// openURL(<url>)
|
||||
// openURL(<url>,new-window)
|
||||
// openURL(<url>,new-tab)
|
||||
|
||||
// First param is the URL, second param (if present) is the "target"
|
||||
// (tab, window)
|
||||
var url = remoteParams[0];
|
||||
var target = nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW;
|
||||
if (remoteParams[1]) {
|
||||
var targetParam = remoteParams[1].toLowerCase()
|
||||
.replace(/^\s*|\s*$/g, "");
|
||||
if (targetParam == "new-tab")
|
||||
target = nsIBrowserDOMWindow.OPEN_NEWTAB;
|
||||
else if (targetParam == "new-window")
|
||||
target = nsIBrowserDOMWindow.OPEN_NEWWINDOW;
|
||||
else {
|
||||
// The "target" param isn't one of our supported values, so
|
||||
// assume it's part of a URL that contains commas.
|
||||
url += "," + remoteParams[1];
|
||||
}
|
||||
}
|
||||
|
||||
var uri = resolveURIInternal(cmdLine, url);
|
||||
handURIToExistingBrowser(uri, target, cmdLine);
|
||||
break;
|
||||
|
||||
case "xfedocommand":
|
||||
// xfeDoCommand(openBrowser)
|
||||
if (remoteParams[0].toLowerCase() != "openbrowser")
|
||||
throw NS_ERROR_ABORT;
|
||||
|
||||
// Passing defaultArgs, so use NO_EXTERNAL_URIS
|
||||
openWindow(null, this.chromeURL, "_blank",
|
||||
"chrome,dialog=no,all" + this.getFeatures(cmdLine),
|
||||
this.defaultArgs, NO_EXTERNAL_URIS);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Somebody sent us a remote command we don't know how to process:
|
||||
// just abort.
|
||||
throw "Unknown remote command.";
|
||||
}
|
||||
|
||||
cmdLine.preventDefault = true;
|
||||
}
|
||||
catch (e) {
|
||||
Components.utils.reportError(e);
|
||||
// If we had a -remote flag but failed to process it, throw
|
||||
// NS_ERROR_ABORT so that the xremote code knows to return a failure
|
||||
// back to the handling code.
|
||||
throw NS_ERROR_ABORT;
|
||||
}
|
||||
}
|
||||
|
||||
var uriparam;
|
||||
try {
|
||||
while ((uriparam = cmdLine.handleFlagWithParam("new-window", false))) {
|
||||
|
|
|
@ -27,7 +27,7 @@ export MOZILLA_OFFICIAL=1
|
|||
export MOZ_TELEMETRY_REPORTING=1
|
||||
|
||||
if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
|
||||
. $topsrcdir/build/win32/mozconfig.vs2010-win64
|
||||
. $topsrcdir/build/win32/mozconfig.vs2013-win64
|
||||
else
|
||||
. $topsrcdir/build/win32/mozconfig.vs2010
|
||||
fi
|
||||
|
|
|
@ -20,7 +20,7 @@ ac_add_options --with-google-oauth-api-keyfile=${_google_oauth_api_keyfile}
|
|||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
|
||||
. $topsrcdir/build/win32/mozconfig.vs2010-win64
|
||||
. $topsrcdir/build/win32/mozconfig.vs2013-win64
|
||||
else
|
||||
. $topsrcdir/build/win32/mozconfig.vs2010
|
||||
fi
|
||||
|
|
|
@ -8,7 +8,7 @@ ac_add_options --with-windows-version=601
|
|||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
|
||||
. $topsrcdir/build/win32/mozconfig.vs2010-win64
|
||||
. $topsrcdir/build/win32/mozconfig.vs2013-win64
|
||||
else
|
||||
. $topsrcdir/build/win32/mozconfig.vs2010
|
||||
fi
|
||||
|
|
|
@ -161,7 +161,6 @@
|
|||
#ifdef XP_UNIX
|
||||
#ifndef XP_MACOSX
|
||||
@BINPATH@/run-mozilla.sh
|
||||
@BINPATH@/mozilla-xremote-client
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -675,10 +675,19 @@ ifeq (,$(filter $(OS_TARGET),WINNT Darwin))
|
|||
CHECK_TEXTREL = @$(TOOLCHAIN_PREFIX)readelf -d $(1) | grep TEXTREL > /dev/null && echo 'TEST-UNEXPECTED-FAIL | check_textrel | We do not want text relocations in libraries and programs' || true
|
||||
endif
|
||||
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT),android)
|
||||
# While this is very unlikely (libc being added by the compiler at the end
|
||||
# of the linker command line), if libmozglue.so ends up after libc.so, all
|
||||
# hell breaks loose, so better safe than sorry, and check it's actually the
|
||||
# case.
|
||||
CHECK_MOZGLUE_ORDER = @$(TOOLCHAIN_PREFIX)readelf -d $(1) | grep NEEDED | awk '{ libs[$$NF] = ++n } END { if (libs["[libmozglue.so]"] && libs["[libc.so]"] < libs["[libmozglue.so]"]) { print "libmozglue.so must be linked before libc.so"; exit 1 } }'
|
||||
endif
|
||||
|
||||
define CHECK_BINARY
|
||||
$(call CHECK_STDCXX,$(1))
|
||||
$(call CHECK_TEXTREL,$(1))
|
||||
$(call LOCAL_CHECKS,$(1))
|
||||
$(call CHECK_MOZGLUE_ORDER,$(1))
|
||||
endef
|
||||
|
||||
# autoconf.mk sets OBJ_SUFFIX to an error to avoid use before including
|
||||
|
|
|
@ -330,7 +330,7 @@ nss_def_file := $(srcdir)/nss.def
|
|||
ifeq (WINNT,$(OS_TARGET))
|
||||
# Create a .def file based on the various .def files for nss, smime, ssl and
|
||||
# nssutil.
|
||||
nss3.def: $(nss_def_file) $(DEPTH)/db/sqlite3/src/sqlite-processed.def
|
||||
nss3.def: $(nss_def_file) $(DEPTH)/db/sqlite3/src/sqlite-processed.def $(NSS_EXTRA_SYMBOLS_FILE)
|
||||
echo LIBRARY nss3$(DLL_SUFFIX) > $@.tmp
|
||||
echo EXPORTS >> $@.tmp
|
||||
grep -v -h -e ^LIBRARY -e ^EXPORTS -e ^\; $^ >> $@.tmp
|
||||
|
@ -340,10 +340,9 @@ ifdef GCC_USE_GNU_LD
|
|||
sqlite_def_file := $(topsrcdir)/db/sqlite3/src/sqlite.def
|
||||
nspr_def_file := $(srcdir)/nspr-dummy.def
|
||||
|
||||
nss3.def: $(nss_def_file) $(sqlite_def_file) $(nspr_def_file)
|
||||
nss3.def: $(nss_def_file) $(sqlite_def_file) $(nspr_def_file) $(NSS_EXTRA_SYMBOLS_FILE)
|
||||
@$(call py_action,convert_def_file, \
|
||||
$(DEFINES) $(ACDEFINES) $(XULPPFLAGS) -o $@ \
|
||||
$(nss_def_file) $(sqlite_def_file) $(nspr_def_file))
|
||||
$(DEFINES) $(ACDEFINES) $(XULPPFLAGS) -o $@ $^)
|
||||
|
||||
GARBAGE += \
|
||||
nss3.def \
|
||||
|
|
51
configure.in
51
configure.in
|
@ -7192,9 +7192,7 @@ else
|
|||
*-android*|*-linuxandroid*)
|
||||
AC_DEFINE(MOZ_MEMORY_LINUX)
|
||||
AC_DEFINE(MOZ_MEMORY_ANDROID)
|
||||
if test -z "$gonkdir"; then
|
||||
_WRAP_MALLOC=1
|
||||
else
|
||||
if test -n "$gonkdir"; then
|
||||
AC_DEFINE(MOZ_MEMORY_GONK)
|
||||
fi
|
||||
MOZ_GLUE_LDFLAGS=
|
||||
|
@ -7243,11 +7241,7 @@ 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"
|
||||
if test "$MOZ_WIDGET_TOOLKIT" = android; then
|
||||
WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=getaddrinfo,--wrap=freeaddrinfo,--wrap=gai_strerror"
|
||||
fi
|
||||
if test -z "$gonkdir"; then
|
||||
WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=fork,--wrap=pthread_atfork,--wrap=raise"
|
||||
WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=memccpy,--wrap=memchr,--wrap=memrchr,--wrap=memcmp,--wrap=memcpy,--wrap=memmove,--wrap=memset,--wrap=memmem,--wrap=index,--wrap=strchr,--wrap=strrchr,--wrap=strlen,--wrap=strcmp,--wrap=strcpy,--wrap=strcat,--wrap=strcasecmp,--wrap=strncasecmp,--wrap=strstr,--wrap=strcasestr,--wrap=strtok,--wrap=strtok_r,--wrap=strerror,--wrap=strerror_r,--wrap=strnlen,--wrap=strncat,--wrap=strncmp,--wrap=strncpy,--wrap=strlcat,--wrap=strlcpy,--wrap=strcspn,--wrap=strpbrk,--wrap=strsep,--wrap=strspn,--wrap=strcoll,--wrap=strxfrm"
|
||||
fi
|
||||
if test "$MOZ_WIDGET_TOOLKIT" = gonk -a -n "$MOZ_NUWA_PROCESS"; then
|
||||
|
@ -7255,39 +7249,6 @@ if test "$OS_TARGET" = Android; then
|
|||
fi
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Use malloc wrapper lib
|
||||
dnl ========================================================
|
||||
MOZ_ARG_ENABLE_BOOL(wrap-malloc,
|
||||
[ --enable-wrap-malloc Wrap malloc calls (gnu linker only)],
|
||||
_WRAP_MALLOC=1,
|
||||
_WRAP_MALLOC= )
|
||||
|
||||
if test -n "$_WRAP_MALLOC"; then
|
||||
if test -n "$GNU_CC"; then
|
||||
WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=malloc,--wrap=calloc,--wrap=valloc,--wrap=free,--wrap=realloc,--wrap=memalign"
|
||||
WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=__builtin_new,--wrap=__builtin_vec_new,--wrap=__builtin_delete,--wrap=__builtin_vec_delete"
|
||||
WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=strdup,--wrap=strndup"
|
||||
WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=vasprintf,--wrap=asprintf"
|
||||
WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=posix_memalign,--wrap=malloc_usable_size"
|
||||
dnl Wrap operator new and operator delete on Android.
|
||||
if test "$OS_TARGET" = "Android"; then
|
||||
WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=_Znwj,--wrap=_Znaj,--wrap=_ZdlPv,--wrap=_ZdaPv"
|
||||
dnl Wrap the nothrow variants too.
|
||||
WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=_ZnwjRKSt9nothrow_t,--wrap=_ZnajRKSt9nothrow_t,--wrap=_ZdlPvRKSt9nothrow_t,--wrap=_ZdaPvRKSt9nothrow_t"
|
||||
fi
|
||||
else
|
||||
AC_MSG_ERROR([--enable-wrap-malloc is not supported for non-GNU toolchains])
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Location of malloc wrapper lib
|
||||
dnl ========================================================
|
||||
MOZ_ARG_WITH_STRING(wrap-malloc,
|
||||
[ --with-wrap-malloc=DIR Location of malloc wrapper library],
|
||||
WRAP_LDFLAGS="${WRAP_LDFLAGS} $withval")
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Use JS Call tracing
|
||||
dnl ========================================================
|
||||
|
@ -8938,6 +8899,8 @@ if test "$MOZ_DEBUG"; then
|
|||
fi
|
||||
AC_SUBST(MOZ_EM_DEBUG)
|
||||
|
||||
AC_SUBST(NSS_EXTRA_SYMBOLS_FILE)
|
||||
|
||||
if test -n "$COMPILE_ENVIRONMENT"; then
|
||||
AC_CHECK_FUNCS(posix_fadvise posix_fallocate)
|
||||
|
||||
|
@ -9136,9 +9099,6 @@ if test -z "$MOZ_NATIVE_JEMALLOC" -a "$MOZ_MEMORY" && test -n "$MOZ_JEMALLOC3" -
|
|||
fi
|
||||
if test -n "$MANGLE"; then
|
||||
MANGLED=
|
||||
if test -n "$_WRAP_MALLOC" -a -z "$JEMALLOC_WRAPPER"; then
|
||||
JEMALLOC_WRAPPER=__wrap_
|
||||
fi
|
||||
for mangle in ${MANGLE}; do
|
||||
if test -n "$MANGLED"; then
|
||||
MANGLED="$mangle:$JEMALLOC_WRAPPER$mangle,$MANGLED"
|
||||
|
@ -9232,11 +9192,6 @@ if test "$COMPILE_ENVIRONMENT" -a -z "$LIBXUL_SDK_DIR"; then
|
|||
|
||||
export WRAP_LDFLAGS
|
||||
|
||||
if test -n "$_WRAP_MALLOC"; then
|
||||
# Avoid doubling wrap malloc arguments
|
||||
_SUBDIR_CONFIG_ARGS="`echo $_SUBDIR_CONFIG_ARGS | sed -e 's/--enable-wrap-malloc *//'`"
|
||||
fi
|
||||
|
||||
if test -n "$MOZ_USING_CCACHE"; then
|
||||
# Avoid double prepending ccache by omitting --with-ccache in building NSPR.
|
||||
_SUBDIR_CONFIG_ARGS="`echo $_SUBDIR_CONFIG_ARGS | sed -e 's/--with-ccache[[^ ]]*//'`"
|
||||
|
|
|
@ -285,13 +285,6 @@ public:
|
|||
|
||||
void NotifyMediaTrackEnabled(MediaTrack* aTrack);
|
||||
|
||||
/**
|
||||
* Called by a DOMMediaStream when it has tracks available.
|
||||
* This allows us to setup audio and video outputs after the stream
|
||||
* has already reported that playback started, in case they are added late.
|
||||
*/
|
||||
void NotifyMediaStreamTracksAvailable(DOMMediaStream* aStream);
|
||||
|
||||
virtual bool IsNodeOfType(uint32_t aFlags) const MOZ_OVERRIDE;
|
||||
|
||||
/**
|
||||
|
@ -623,7 +616,6 @@ protected:
|
|||
|
||||
class MediaLoadListener;
|
||||
class StreamListener;
|
||||
class MediaStreamTracksAvailableCallback;
|
||||
|
||||
virtual void GetItemValueText(nsAString& text) MOZ_OVERRIDE;
|
||||
virtual void SetItemValueText(const nsAString& text) MOZ_OVERRIDE;
|
||||
|
@ -1026,9 +1018,6 @@ protected:
|
|||
nsMediaNetworkState mNetworkState;
|
||||
nsMediaReadyState mReadyState;
|
||||
|
||||
// Last value passed from codec or stream source to UpdateReadyStateForData.
|
||||
NextFrameStatus mLastNextFrameStatus;
|
||||
|
||||
enum LoadAlgorithmState {
|
||||
// No load algorithm instance is waiting for a source to be added to the
|
||||
// media in order to continue loading.
|
||||
|
|
|
@ -71,8 +71,6 @@
|
|||
#include "mozilla/dom/MediaSource.h"
|
||||
#include "MediaMetadataManager.h"
|
||||
#include "MediaSourceDecoder.h"
|
||||
#include "AudioStreamTrack.h"
|
||||
#include "VideoStreamTrack.h"
|
||||
|
||||
#include "AudioChannelService.h"
|
||||
|
||||
|
@ -666,10 +664,7 @@ void HTMLMediaElement::AbortExistingLoads()
|
|||
mHaveQueuedSelectResource = false;
|
||||
mSuspendedForPreloadNone = false;
|
||||
mDownloadSuspendedByCache = false;
|
||||
mHasAudio = false;
|
||||
mHasVideo = false;
|
||||
mSourcePointer = nullptr;
|
||||
mLastNextFrameStatus = NEXT_FRAME_UNINITIALIZED;
|
||||
|
||||
mTags = nullptr;
|
||||
|
||||
|
@ -903,39 +898,6 @@ void HTMLMediaElement::NotifyMediaTrackEnabled(MediaTrack* aTrack)
|
|||
}
|
||||
}
|
||||
|
||||
void HTMLMediaElement::NotifyMediaStreamTracksAvailable(DOMMediaStream* aStream)
|
||||
{
|
||||
if (!mSrcStream || mSrcStream != aStream) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool oldHasAudio = mHasAudio;
|
||||
bool oldHasVideo = mHasVideo;
|
||||
|
||||
nsAutoTArray<nsRefPtr<AudioStreamTrack>,1> audioTracks;
|
||||
aStream->GetAudioTracks(audioTracks);
|
||||
nsAutoTArray<nsRefPtr<VideoStreamTrack>,1> videoTracks;
|
||||
aStream->GetVideoTracks(videoTracks);
|
||||
|
||||
mHasAudio = !audioTracks.IsEmpty();
|
||||
mHasVideo = !videoTracks.IsEmpty();
|
||||
|
||||
if (!oldHasAudio && mHasAudio) {
|
||||
GetSrcMediaStream()->AddAudioOutput(this);
|
||||
GetSrcMediaStream()->SetAudioOutputVolume(this, float(mMuted ? 0.0 : mVolume));
|
||||
}
|
||||
if (!oldHasVideo && mHasVideo ) {
|
||||
VideoFrameContainer* container = GetVideoFrameContainer();
|
||||
if (container) {
|
||||
GetSrcMediaStream()->AddVideoOutput(container);
|
||||
}
|
||||
// mHasVideo changed so make sure the screen wakelock is updated
|
||||
NotifyOwnerDocumentActivityChanged();
|
||||
}
|
||||
|
||||
CheckAutoplayDataReady();
|
||||
}
|
||||
|
||||
void HTMLMediaElement::LoadFromSourceChildren()
|
||||
{
|
||||
NS_ASSERTION(mDelayingLoadEvent,
|
||||
|
@ -2025,7 +1987,6 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNo
|
|||
mCurrentLoadID(0),
|
||||
mNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY),
|
||||
mReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING),
|
||||
mLastNextFrameStatus(NEXT_FRAME_UNINITIALIZED),
|
||||
mLoadWaitStatus(NOT_WAITING),
|
||||
mVolume(1.0),
|
||||
mPreloadAction(PRELOAD_UNDEFINED),
|
||||
|
@ -2854,28 +2815,6 @@ private:
|
|||
bool mPendingNotifyOutput;
|
||||
};
|
||||
|
||||
class HTMLMediaElement::MediaStreamTracksAvailableCallback:
|
||||
public DOMMediaStream::OnTracksAvailableCallback
|
||||
{
|
||||
public:
|
||||
explicit MediaStreamTracksAvailableCallback(HTMLMediaElement* aElement,
|
||||
DOMMediaStream::TrackTypeHints aExpectedTracks = 0):
|
||||
DOMMediaStream::OnTracksAvailableCallback(aExpectedTracks),
|
||||
mElement(aElement)
|
||||
{}
|
||||
virtual void NotifyTracksAvailable(DOMMediaStream* aStream)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
|
||||
if (!mElement) {
|
||||
return;
|
||||
}
|
||||
mElement->NotifyMediaStreamTracksAvailable(aStream);
|
||||
}
|
||||
private:
|
||||
HTMLMediaElement* mElement;
|
||||
};
|
||||
|
||||
void HTMLMediaElement::SetupSrcMediaStreamPlayback(DOMMediaStream* aStream)
|
||||
{
|
||||
NS_ASSERTION(!mSrcStream && !mSrcStreamListener, "Should have been ended already");
|
||||
|
@ -2897,24 +2836,22 @@ void HTMLMediaElement::SetupSrcMediaStreamPlayback(DOMMediaStream* aStream)
|
|||
if (mPausedForInactiveDocumentOrChannel) {
|
||||
GetSrcMediaStream()->ChangeExplicitBlockerCount(1);
|
||||
}
|
||||
|
||||
mSrcStream->OnTracksAvailable(new MediaStreamTracksAvailableCallback(this, DOMMediaStream::HINT_CONTENTS_AUDIO));
|
||||
mSrcStream->OnTracksAvailable(new MediaStreamTracksAvailableCallback(this, DOMMediaStream::HINT_CONTENTS_VIDEO));
|
||||
|
||||
MediaInfo mediaInfo;
|
||||
mediaInfo.mAudio.mHasAudio = mHasAudio;
|
||||
mediaInfo.mVideo.mHasVideo = mHasVideo;
|
||||
MetadataLoaded(&mediaInfo, nullptr);
|
||||
|
||||
DispatchAsyncEvent(NS_LITERAL_STRING("suspend"));
|
||||
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
|
||||
|
||||
ChangeDelayLoadStatus(false);
|
||||
GetSrcMediaStream()->AddAudioOutput(this);
|
||||
GetSrcMediaStream()->SetAudioOutputVolume(this, float(mMuted ? 0.0 : mVolume));
|
||||
VideoFrameContainer* container = GetVideoFrameContainer();
|
||||
if (container) {
|
||||
GetSrcMediaStream()->AddVideoOutput(container);
|
||||
}
|
||||
|
||||
// Note: we must call DisconnectTrackListListeners(...) before dropping
|
||||
// mSrcStream
|
||||
mSrcStream->ConstructMediaTracks(AudioTracks(), VideoTracks());
|
||||
|
||||
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
|
||||
DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
|
||||
DispatchAsyncEvent(NS_LITERAL_STRING("loadedmetadata"));
|
||||
ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
|
||||
AddRemoveSelfReference();
|
||||
// FirstFrameLoaded() will be called when the stream has current data.
|
||||
}
|
||||
|
@ -2930,12 +2867,12 @@ void HTMLMediaElement::EndSrcMediaStreamPlayback()
|
|||
// Kill its reference to this element
|
||||
mSrcStreamListener->Forget();
|
||||
mSrcStreamListener = nullptr;
|
||||
if (stream && mHasAudio) {
|
||||
if (stream) {
|
||||
stream->RemoveAudioOutput(this);
|
||||
}
|
||||
VideoFrameContainer* container = GetVideoFrameContainer();
|
||||
if (container) {
|
||||
if (stream && mHasVideo) {
|
||||
if (stream) {
|
||||
stream->RemoveVideoOutput(container);
|
||||
}
|
||||
container->ClearCurrentFrame();
|
||||
|
@ -2987,11 +2924,6 @@ void HTMLMediaElement::MetadataLoaded(const MediaInfo* aInfo,
|
|||
mVideoFrameContainer->ForgetElement();
|
||||
mVideoFrameContainer = nullptr;
|
||||
}
|
||||
|
||||
if (IsVideo()) {
|
||||
// Update the screen wakelock in case mHasVideo changed
|
||||
NotifyOwnerDocumentActivityChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void HTMLMediaElement::FirstFrameLoaded()
|
||||
|
@ -2999,7 +2931,6 @@ void HTMLMediaElement::FirstFrameLoaded()
|
|||
NS_ASSERTION(!mSuspendedAfterFirstFrame, "Should not have already suspended");
|
||||
|
||||
ChangeDelayLoadStatus(false);
|
||||
UpdateReadyStateForData(NEXT_FRAME_UNAVAILABLE);
|
||||
|
||||
if (mDecoder && mAllowSuspendAfterFirstFrame && mPaused &&
|
||||
!HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay) &&
|
||||
|
@ -3162,18 +3093,10 @@ bool HTMLMediaElement::ShouldCheckAllowOrigin()
|
|||
|
||||
void HTMLMediaElement::UpdateReadyStateForData(MediaDecoderOwner::NextFrameStatus aNextFrame)
|
||||
{
|
||||
mLastNextFrameStatus = aNextFrame;
|
||||
|
||||
if (mReadyState < nsIDOMHTMLMediaElement::HAVE_METADATA) {
|
||||
// aNextFrame might have a next frame because the decoder can advance
|
||||
// on its own thread before MetadataLoaded gets a chance to run.
|
||||
// The arrival of more data can't change us out of this readyState.
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mHasAudio && !mHasVideo) {
|
||||
// No tracks available yet, don't advance from HAVE_METADATA
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3196,14 +3119,6 @@ void HTMLMediaElement::UpdateReadyStateForData(MediaDecoderOwner::NextFrameStatu
|
|||
return;
|
||||
}
|
||||
|
||||
if (mReadyState < nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA && mHasVideo) {
|
||||
VideoFrameContainer* container = GetVideoFrameContainer();
|
||||
if (container && mMediaSize == nsIntSize(-1,-1)) {
|
||||
// No frame has been set yet. Don't advance.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (aNextFrame != MediaDecoderOwner::NEXT_FRAME_AVAILABLE) {
|
||||
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA);
|
||||
if (!mWaitingFired && aNextFrame == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING) {
|
||||
|
@ -3344,15 +3259,14 @@ void HTMLMediaElement::ChangeNetworkState(nsMediaNetworkState aState)
|
|||
|
||||
bool HTMLMediaElement::CanActivateAutoplay()
|
||||
{
|
||||
// For stream inputs, we activate autoplay on HAVE_METADATA because
|
||||
// For stream inputs, we activate autoplay on HAVE_CURRENT_DATA because
|
||||
// this element itself might be blocking the stream from making progress by
|
||||
// being paused.
|
||||
return !mPausedForInactiveDocumentOrChannel &&
|
||||
mAutoplaying &&
|
||||
mPaused &&
|
||||
((mDecoder && mReadyState >= nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) ||
|
||||
(mSrcStream && mReadyState >= nsIDOMHTMLMediaElement::HAVE_METADATA)) &&
|
||||
(mHasAudio || mHasVideo) &&
|
||||
(mSrcStream && mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA)) &&
|
||||
HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay) &&
|
||||
mAutoplayEnabled &&
|
||||
!IsEditable();
|
||||
|
@ -3381,14 +3295,24 @@ void HTMLMediaElement::CheckAutoplayDataReady()
|
|||
|
||||
VideoFrameContainer* HTMLMediaElement::GetVideoFrameContainer()
|
||||
{
|
||||
if (mVideoFrameContainer)
|
||||
return mVideoFrameContainer;
|
||||
// If we have loaded the metadata, and the size of the video is still
|
||||
// (-1, -1), the media has no video. Don't go a create a video frame
|
||||
// container.
|
||||
if (mReadyState >= nsIDOMHTMLMediaElement::HAVE_METADATA &&
|
||||
mMediaSize == nsIntSize(-1, -1)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Only video frames need an image container.
|
||||
if (!IsVideo()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mHasVideo = true;
|
||||
|
||||
if (mVideoFrameContainer)
|
||||
return mVideoFrameContainer;
|
||||
|
||||
mVideoFrameContainer =
|
||||
new VideoFrameContainer(this, LayerManager::CreateAsynchronousImageContainer());
|
||||
|
||||
|
@ -3501,7 +3425,6 @@ void HTMLMediaElement::NotifyDecoderPrincipalChanged()
|
|||
void HTMLMediaElement::UpdateMediaSize(nsIntSize size)
|
||||
{
|
||||
mMediaSize = size;
|
||||
UpdateReadyStateForData(mLastNextFrameStatus);
|
||||
}
|
||||
|
||||
void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendEvents)
|
||||
|
|
|
@ -39,6 +39,9 @@ public:
|
|||
|
||||
// True if this reader is waiting media resource allocation
|
||||
virtual bool IsWaitingMediaResources() { return false; }
|
||||
// True if this reader is waiting for a Content Decryption Module to become
|
||||
// available.
|
||||
virtual bool IsWaitingOnCDMResource() { return false; }
|
||||
// True when this reader need to become dormant state
|
||||
virtual bool IsDormantNeeded() { return false; }
|
||||
// Release media resources they should be released in dormant state
|
||||
|
|
|
@ -16,9 +16,16 @@
|
|||
#include "nsContentUtils.h"
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsContentTypeParser.h"
|
||||
#ifdef MOZ_FMP4
|
||||
#include "MP4Decoder.h"
|
||||
#endif
|
||||
#ifdef XP_WIN
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#endif
|
||||
#include "nsContentCID.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "mozIGeckoMediaPluginService.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -107,15 +114,86 @@ MediaKeys::SetServerCertificate(const ArrayBufferViewOrArrayBuffer& aCert, Error
|
|||
}
|
||||
|
||||
static bool
|
||||
IsSupportedKeySystem(const nsAString& aKeySystem)
|
||||
HaveGMPFor(const nsCString& aKeySystem,
|
||||
const nsCString& aAPI,
|
||||
const nsCString& aTag = EmptyCString())
|
||||
{
|
||||
return aKeySystem.EqualsASCII("org.w3.clearkey") ||
|
||||
#ifdef XP_WIN
|
||||
(aKeySystem.EqualsASCII("com.adobe.access") &&
|
||||
IsVistaOrLater() &&
|
||||
Preferences::GetBool("media.eme.adobe-access.enabled", false)) ||
|
||||
nsCOMPtr<mozIGeckoMediaPluginService> mps =
|
||||
do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
||||
if (NS_WARN_IF(!mps)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(aKeySystem);
|
||||
if (!aTag.IsEmpty()) {
|
||||
tags.AppendElement(aTag);
|
||||
}
|
||||
// Note: EME plugins need a non-null nodeId here, as they must
|
||||
// not be shared across origins.
|
||||
bool hasPlugin = false;
|
||||
if (NS_FAILED(mps->HasPluginForAPI(aAPI,
|
||||
&tags,
|
||||
&hasPlugin))) {
|
||||
return false;
|
||||
}
|
||||
return hasPlugin;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsPlayableMP4Type(const nsAString& aContentType)
|
||||
{
|
||||
#ifdef MOZ_FMP4
|
||||
nsContentTypeParser parser(aContentType);
|
||||
nsAutoString mimeType;
|
||||
nsresult rv = parser.GetType(mimeType);
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
nsAutoString codecs;
|
||||
parser.GetParameter("codecs", codecs);
|
||||
|
||||
NS_ConvertUTF16toUTF8 mimeTypeUTF8(mimeType);
|
||||
return MP4Decoder::CanHandleMediaType(mimeTypeUTF8, codecs);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
false;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaKeys::IsTypeSupported(const nsAString& aKeySystem,
|
||||
const Optional<nsAString>& aInitDataType,
|
||||
const Optional<nsAString>& aContentType)
|
||||
{
|
||||
if (aKeySystem.EqualsLiteral("org.w3.clearkey") &&
|
||||
(!aInitDataType.WasPassed() || aInitDataType.Value().EqualsLiteral("cenc")) &&
|
||||
(!aContentType.WasPassed() || IsPlayableMP4Type(aContentType.Value())) &&
|
||||
HaveGMPFor(NS_LITERAL_CSTRING("org.w3.clearkey"),
|
||||
NS_LITERAL_CSTRING("eme-decrypt"))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
// Note: Adobe Access's GMP uses WMF to decode, so anything our MP4Reader
|
||||
// thinks it can play on Windows, the Access GMP should be able to play.
|
||||
if (aKeySystem.EqualsLiteral("com.adobe.access") &&
|
||||
Preferences::GetBool("media.eme.adobe-access.enabled", false) &&
|
||||
IsVistaOrLater() && // Win Vista and later only.
|
||||
(!aInitDataType.WasPassed() || aInitDataType.Value().EqualsLiteral("cenc")) &&
|
||||
(!aContentType.WasPassed() || IsPlayableMP4Type(aContentType.Value())) &&
|
||||
HaveGMPFor(NS_LITERAL_CSTRING("com.adobe.access"),
|
||||
NS_LITERAL_CSTRING("eme-decrypt")) &&
|
||||
HaveGMPFor(NS_LITERAL_CSTRING("com.adobe.access"),
|
||||
NS_LITERAL_CSTRING("decode-video"),
|
||||
NS_LITERAL_CSTRING("h264")) &&
|
||||
HaveGMPFor(NS_LITERAL_CSTRING("com.adobe.access"),
|
||||
NS_LITERAL_CSTRING("decode-audio"),
|
||||
NS_LITERAL_CSTRING("aac"))) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
@ -128,8 +206,16 @@ MediaKeys::IsTypeSupported(const GlobalObject& aGlobal,
|
|||
{
|
||||
// TODO: Should really get spec changed to this is async, so we can wait
|
||||
// for user to consent to running plugin.
|
||||
return IsSupportedKeySystem(aKeySystem) ? IsTypeSupportedResult::Maybe
|
||||
: IsTypeSupportedResult::_empty;
|
||||
bool supported = IsTypeSupported(aKeySystem, aInitDataType, aContentType);
|
||||
|
||||
EME_LOG("MediaKeys::IsTypeSupported keySystem='%s' initDataType='%s' contentType='%s' supported=%d",
|
||||
NS_ConvertUTF16toUTF8(aKeySystem).get(),
|
||||
(aInitDataType.WasPassed() ? NS_ConvertUTF16toUTF8(aInitDataType.Value()).get() : ""),
|
||||
(aContentType.WasPassed() ? NS_ConvertUTF16toUTF8(aContentType.Value()).get() : ""),
|
||||
supported);
|
||||
|
||||
return supported ? IsTypeSupportedResult::Probably
|
||||
: IsTypeSupportedResult::_empty;
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
|
@ -242,7 +328,7 @@ MediaKeys::Init(ErrorResult& aRv)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (!IsSupportedKeySystem(mKeySystem)) {
|
||||
if (!IsTypeSupported(mKeySystem)) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
@ -271,7 +357,7 @@ MediaKeys::Init(ErrorResult& aRv)
|
|||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
|
||||
mTopLevelPrincipal = top->GetExtantDoc()->NodePrincipal();
|
||||
|
||||
if (!mPrincipal || !mTopLevelPrincipal) {
|
||||
|
|
|
@ -124,6 +124,10 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
static bool IsTypeSupported(const nsAString& aKeySystem,
|
||||
const Optional<nsAString>& aInitDataType = Optional<nsAString>(),
|
||||
const Optional<nsAString>& aContentType = Optional<nsAString>());
|
||||
|
||||
bool IsInPrivateBrowsing();
|
||||
already_AddRefed<Promise> Init(ErrorResult& aRv);
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ public:
|
|||
// with a U and V plane that are half the size of the Y plane, i.e 8 bit,
|
||||
// 2x2 subsampled. Have the data pointers of each frame point to the
|
||||
// first plane, they'll always be zero'd memory anyway.
|
||||
uint8_t* frame = new uint8_t[mFrameWidth * mFrameHeight];
|
||||
nsAutoArrayPtr<uint8_t> frame(new uint8_t[mFrameWidth * mFrameHeight]);
|
||||
memset(frame, 0, mFrameWidth * mFrameHeight);
|
||||
VideoData::YCbCrBuffer buffer;
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ private:
|
|||
bool IsSupportedAudioMimeType(const char* aMimeType);
|
||||
void NotifyResourcesStatusChanged();
|
||||
bool IsWaitingOnCodecResource();
|
||||
bool IsWaitingOnCDMResource();
|
||||
virtual bool IsWaitingOnCDMResource() MOZ_OVERRIDE;
|
||||
|
||||
nsAutoPtr<mp4_demuxer::MP4Demuxer> mDemuxer;
|
||||
nsAutoPtr<PlatformDecoderModule> mPlatform;
|
||||
|
|
|
@ -61,6 +61,7 @@ PlatformDecoderModule::Init()
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
class CreateTaskQueueTask : public nsRunnable {
|
||||
public:
|
||||
NS_IMETHOD Run() {
|
||||
|
@ -81,7 +82,6 @@ CreateTaskQueue()
|
|||
return t->mTaskQueue.forget();
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
/* static */
|
||||
PlatformDecoderModule*
|
||||
PlatformDecoderModule::CreateCDMWrapper(CDMProxy* aProxy,
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace gmp {
|
|||
|
||||
GMPAudioDecoderParent::GMPAudioDecoderParent(GMPParent* aPlugin)
|
||||
: mIsOpen(false)
|
||||
, mShuttingDown(false)
|
||||
, mPlugin(aPlugin)
|
||||
, mCallback(nullptr)
|
||||
{
|
||||
|
@ -161,17 +162,19 @@ GMPAudioDecoderParent::Shutdown()
|
|||
LOGD(("%s: %p", __FUNCTION__, this));
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (mShuttingDown) {
|
||||
return NS_OK;
|
||||
}
|
||||
mShuttingDown = true;
|
||||
|
||||
// Notify client we're gone! Won't occur after Close()
|
||||
if (mCallback) {
|
||||
mCallback->Terminated();
|
||||
mCallback = nullptr;
|
||||
}
|
||||
|
||||
if (mIsOpen) {
|
||||
// Don't send DecodingComplete if we died
|
||||
mIsOpen = false;
|
||||
unused << SendDecodingComplete();
|
||||
}
|
||||
mIsOpen = false;
|
||||
unused << SendDecodingComplete();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ private:
|
|||
virtual bool Recv__delete__() MOZ_OVERRIDE;
|
||||
|
||||
bool mIsOpen;
|
||||
bool mShuttingDown;
|
||||
nsRefPtr<GMPParent> mPlugin;
|
||||
GMPAudioDecoderProxyCallback* mCallback;
|
||||
};
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace gmp {
|
|||
|
||||
GMPDecryptorParent::GMPDecryptorParent(GMPParent* aPlugin)
|
||||
: mIsOpen(false)
|
||||
, mShuttingDown(false)
|
||||
, mPlugin(aPlugin)
|
||||
, mCallback(nullptr)
|
||||
{
|
||||
|
@ -328,16 +329,19 @@ GMPDecryptorParent::Shutdown()
|
|||
{
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (mShuttingDown) {
|
||||
return;
|
||||
}
|
||||
mShuttingDown = true;
|
||||
|
||||
// Notify client we're gone! Won't occur after Close()
|
||||
if (mCallback) {
|
||||
mCallback->Terminated();
|
||||
mCallback = nullptr;
|
||||
}
|
||||
|
||||
if (mIsOpen) {
|
||||
mIsOpen = false;
|
||||
unused << SendDecryptingComplete();
|
||||
}
|
||||
mIsOpen = false;
|
||||
unused << SendDecryptingComplete();
|
||||
}
|
||||
|
||||
// Note: Keep this sync'd up with Shutdown
|
||||
|
|
|
@ -106,6 +106,7 @@ private:
|
|||
virtual bool Recv__delete__() MOZ_OVERRIDE;
|
||||
|
||||
bool mIsOpen;
|
||||
bool mShuttingDown;
|
||||
nsRefPtr<GMPParent> mPlugin;
|
||||
GMPDecryptorProxyCallback* mCallback;
|
||||
};
|
||||
|
|
|
@ -143,6 +143,7 @@ GeckoMediaPluginService::GeckoMediaPluginService()
|
|||
: mMutex("GeckoMediaPluginService::mMutex")
|
||||
, mShuttingDown(false)
|
||||
, mShuttingDownOnGMPThread(false)
|
||||
, mScannedPluginOnDisk(false)
|
||||
, mWaitingForPluginsAsyncShutdown(false)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
@ -590,7 +591,7 @@ GeckoMediaPluginService::UnloadPlugins()
|
|||
MutexAutoLock lock(mMutex);
|
||||
// Note: CloseActive is async; it will actually finish
|
||||
// shutting down when all the plugins have unloaded.
|
||||
for (uint32_t i = 0; i < mPlugins.Length(); i++) {
|
||||
for (size_t i = 0; i < mPlugins.Length(); i++) {
|
||||
mPlugins[i]->CloseActive(true);
|
||||
}
|
||||
mPlugins.Clear();
|
||||
|
@ -619,7 +620,7 @@ GeckoMediaPluginService::CrashPlugins()
|
|||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
for (uint32_t i = 0; i < mPlugins.Length(); i++) {
|
||||
for (size_t i = 0; i < mPlugins.Length(); i++) {
|
||||
mPlugins[i]->Crash();
|
||||
}
|
||||
}
|
||||
|
@ -652,6 +653,8 @@ GeckoMediaPluginService::LoadFromEnvironment()
|
|||
pos = next + 1;
|
||||
}
|
||||
}
|
||||
|
||||
mScannedPluginOnDisk = true;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -693,47 +696,88 @@ GeckoMediaPluginService::RemovePluginDirectory(const nsAString& aDirectory)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
class DummyRunnable : public nsRunnable {
|
||||
public:
|
||||
NS_IMETHOD Run() { return NS_OK; }
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginService::HasPluginForAPI(const nsACString& aNodeId,
|
||||
const nsACString& aAPI,
|
||||
GeckoMediaPluginService::HasPluginForAPI(const nsACString& aAPI,
|
||||
nsTArray<nsCString>* aTags,
|
||||
bool* aResult)
|
||||
{
|
||||
NS_ENSURE_ARG(aTags && aTags->Length() > 0);
|
||||
NS_ENSURE_ARG(aResult);
|
||||
|
||||
nsCString temp(aAPI);
|
||||
GMPParent *parent = SelectPluginForAPI(aNodeId, temp, *aTags, false);
|
||||
*aResult = !!parent;
|
||||
const char* env = nullptr;
|
||||
if (!mScannedPluginOnDisk && (env = PR_GetEnv("MOZ_GMP_PATH")) && *env) {
|
||||
// We have a MOZ_GMP_PATH environment variable which may specify the
|
||||
// location of plugins to load, and we haven't yet scanned the disk to
|
||||
// see if there are plugins there. Get the GMP thread, which will
|
||||
// cause an event to be dispatched to which scans for plugins. We
|
||||
// dispatch a sync event to the GMP thread here in order to wait until
|
||||
// after the GMP thread has scanned any paths in MOZ_GMP_PATH.
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
nsresult rv = GetThread(getter_AddRefs(thread));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
thread->Dispatch(new DummyRunnable(), NS_DISPATCH_SYNC);
|
||||
MOZ_ASSERT(mScannedPluginOnDisk, "Should have scanned MOZ_GMP_PATH by now");
|
||||
}
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
nsCString api(aAPI);
|
||||
GMPParent* gmp = FindPluginForAPIFrom(0, api, *aTags, nullptr);
|
||||
*aResult = (gmp != nullptr);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
GMPParent*
|
||||
GeckoMediaPluginService::FindPluginForAPIFrom(size_t aSearchStartIndex,
|
||||
const nsCString& aAPI,
|
||||
const nsTArray<nsCString>& aTags,
|
||||
size_t* aOutPluginIndex)
|
||||
{
|
||||
mMutex.AssertCurrentThreadOwns();
|
||||
for (size_t i = aSearchStartIndex; i < mPlugins.Length(); i++) {
|
||||
GMPParent* gmp = mPlugins[i];
|
||||
bool supportsAllTags = true;
|
||||
for (size_t t = 0; t < aTags.Length(); t++) {
|
||||
const nsCString& tag = aTags.ElementAt(t);
|
||||
if (!gmp->SupportsAPI(aAPI, tag)) {
|
||||
supportsAllTags = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!supportsAllTags) {
|
||||
continue;
|
||||
}
|
||||
if (aOutPluginIndex) {
|
||||
*aOutPluginIndex = i;
|
||||
}
|
||||
return gmp;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GMPParent*
|
||||
GeckoMediaPluginService::SelectPluginForAPI(const nsACString& aNodeId,
|
||||
const nsCString& aAPI,
|
||||
const nsTArray<nsCString>& aTags,
|
||||
bool aCloneCrossNodeIds)
|
||||
const nsTArray<nsCString>& aTags)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread || !aCloneCrossNodeIds,
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread,
|
||||
"Can't clone GMP plugins on non-GMP threads.");
|
||||
|
||||
GMPParent* gmpToClone = nullptr;
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
for (uint32_t i = 0; i < mPlugins.Length(); i++) {
|
||||
GMPParent* gmp = mPlugins[i];
|
||||
bool supportsAllTags = true;
|
||||
for (uint32_t t = 0; t < aTags.Length(); t++) {
|
||||
const nsCString& tag = aTags[t];
|
||||
if (!gmp->SupportsAPI(aAPI, tag)) {
|
||||
supportsAllTags = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!supportsAllTags) {
|
||||
continue;
|
||||
}
|
||||
size_t index = 0;
|
||||
GMPParent* gmp = nullptr;
|
||||
while ((gmp = FindPluginForAPIFrom(index, aAPI, aTags, &index))) {
|
||||
if (aNodeId.IsEmpty()) {
|
||||
if (gmp->CanBeSharedCrossNodeIds()) {
|
||||
return gmp;
|
||||
|
@ -744,15 +788,17 @@ GeckoMediaPluginService::SelectPluginForAPI(const nsACString& aNodeId,
|
|||
return gmp;
|
||||
}
|
||||
|
||||
// This GMP has the correct type but has the wrong origin; hold on to it
|
||||
// This GMP has the correct type but has the wrong nodeId; hold on to it
|
||||
// in case we need to clone it.
|
||||
gmpToClone = gmp;
|
||||
// Loop around and try the next plugin; it may be usable from aNodeId.
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
// Plugin exists, but we can't use it due to cross-origin separation. Create a
|
||||
// new one.
|
||||
if (aCloneCrossNodeIds && gmpToClone) {
|
||||
if (gmpToClone) {
|
||||
GMPParent* clone = ClonePlugin(gmpToClone);
|
||||
if (!aNodeId.IsEmpty()) {
|
||||
clone->SetNodeId(aNodeId);
|
||||
|
@ -847,7 +893,7 @@ GeckoMediaPluginService::RemoveOnGMPThread(const nsAString& aDirectory)
|
|||
}
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
for (uint32_t i = 0; i < mPlugins.Length(); ++i) {
|
||||
for (size_t i = 0; i < mPlugins.Length(); ++i) {
|
||||
nsCOMPtr<nsIFile> pluginpath = mPlugins[i]->GetDirectory();
|
||||
bool equals;
|
||||
if (NS_SUCCEEDED(directory->Equals(pluginpath, &equals)) && equals) {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "nsITimer.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
|
||||
template <class> struct already_AddRefed;
|
||||
|
||||
|
@ -49,8 +50,11 @@ private:
|
|||
|
||||
GMPParent* SelectPluginForAPI(const nsACString& aNodeId,
|
||||
const nsCString& aAPI,
|
||||
const nsTArray<nsCString>& aTags,
|
||||
bool aCloneCrossNodeIds = true);
|
||||
const nsTArray<nsCString>& aTags);
|
||||
GMPParent* FindPluginForAPIFrom(size_t aSearchStartIndex,
|
||||
const nsCString& aAPI,
|
||||
const nsTArray<nsCString>& aTags,
|
||||
size_t* aOutPluginIndex);
|
||||
|
||||
void UnloadPlugins();
|
||||
void CrashPlugins();
|
||||
|
@ -94,6 +98,10 @@ private:
|
|||
bool mShuttingDown;
|
||||
bool mShuttingDownOnGMPThread;
|
||||
|
||||
// True if we've inspected MOZ_GMP_PATH on the GMP thread and loaded any
|
||||
// plugins found there into mPlugins.
|
||||
Atomic<bool> mScannedPluginOnDisk;
|
||||
|
||||
template<typename T>
|
||||
class MainThreadOnly {
|
||||
public:
|
||||
|
|
|
@ -45,6 +45,7 @@ namespace gmp {
|
|||
GMPVideoDecoderParent::GMPVideoDecoderParent(GMPParent* aPlugin)
|
||||
: GMPSharedMemManager(aPlugin)
|
||||
, mIsOpen(false)
|
||||
, mShuttingDown(false)
|
||||
, mPlugin(aPlugin)
|
||||
, mCallback(nullptr)
|
||||
, mVideoHost(MOZ_THIS_IN_INITIALIZER_LIST())
|
||||
|
@ -187,6 +188,11 @@ GMPVideoDecoderParent::Shutdown()
|
|||
LOGD(("%s: %p", __FUNCTION__, this));
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (mShuttingDown) {
|
||||
return NS_OK;
|
||||
}
|
||||
mShuttingDown = true;
|
||||
|
||||
// Notify client we're gone! Won't occur after Close()
|
||||
if (mCallback) {
|
||||
mCallback->Terminated();
|
||||
|
@ -194,11 +200,8 @@ GMPVideoDecoderParent::Shutdown()
|
|||
}
|
||||
mVideoHost.DoneWithAPI();
|
||||
|
||||
if (mIsOpen) {
|
||||
// Don't send DecodingComplete if we died
|
||||
mIsOpen = false;
|
||||
unused << SendDecodingComplete();
|
||||
}
|
||||
mIsOpen = false;
|
||||
unused << SendDecodingComplete();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -77,6 +77,7 @@ private:
|
|||
virtual bool Recv__delete__() MOZ_OVERRIDE;
|
||||
|
||||
bool mIsOpen;
|
||||
bool mShuttingDown;
|
||||
nsRefPtr<GMPParent> mPlugin;
|
||||
GMPVideoDecoderCallbackProxy* mCallback;
|
||||
GMPVideoHostImpl mVideoHost;
|
||||
|
|
|
@ -52,6 +52,7 @@ namespace gmp {
|
|||
GMPVideoEncoderParent::GMPVideoEncoderParent(GMPParent *aPlugin)
|
||||
: GMPSharedMemManager(aPlugin),
|
||||
mIsOpen(false),
|
||||
mShuttingDown(false),
|
||||
mPlugin(aPlugin),
|
||||
mCallback(nullptr),
|
||||
mVideoHost(MOZ_THIS_IN_INITIALIZER_LIST())
|
||||
|
@ -220,17 +221,20 @@ GMPVideoEncoderParent::Shutdown()
|
|||
LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this));
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (mShuttingDown) {
|
||||
return;
|
||||
}
|
||||
mShuttingDown = true;
|
||||
|
||||
// Notify client we're gone! Won't occur after Close()
|
||||
if (mCallback) {
|
||||
mCallback->Terminated();
|
||||
mCallback = nullptr;
|
||||
}
|
||||
mVideoHost.DoneWithAPI();
|
||||
if (mIsOpen) {
|
||||
// Don't send EncodingComplete if we died
|
||||
mIsOpen = false;
|
||||
unused << SendEncodingComplete();
|
||||
}
|
||||
|
||||
mIsOpen = false;
|
||||
unused << SendEncodingComplete();
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -74,6 +74,7 @@ private:
|
|||
virtual bool Recv__delete__() MOZ_OVERRIDE;
|
||||
|
||||
bool mIsOpen;
|
||||
bool mShuttingDown;
|
||||
nsRefPtr<GMPParent> mPlugin;
|
||||
GMPVideoEncoderCallbackProxy* mCallback;
|
||||
GMPVideoHostImpl mVideoHost;
|
||||
|
|
|
@ -26,7 +26,7 @@ class GMPVideoHost;
|
|||
[ptr] native GMPDecryptorProxy(GMPDecryptorProxy);
|
||||
[ptr] native GMPAudioDecoderProxy(GMPAudioDecoderProxy);
|
||||
|
||||
[scriptable, uuid(b350d3b6-00c9-4602-bdfe-84c2be8d1e7a)]
|
||||
[scriptable, uuid(657443a4-6b5d-4181-98b0-56997b35bd57)]
|
||||
interface mozIGeckoMediaPluginService : nsISupports
|
||||
{
|
||||
|
||||
|
@ -40,9 +40,7 @@ interface mozIGeckoMediaPluginService : nsISupports
|
|||
* Callable on any thread
|
||||
*/
|
||||
[noscript]
|
||||
boolean hasPluginForAPI([optional] in ACString nodeId,
|
||||
in ACString api,
|
||||
in TagArray tags);
|
||||
boolean hasPluginForAPI(in ACString api, in TagArray tags);
|
||||
|
||||
/**
|
||||
* Get a video decoder that supports the specified tags.
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "gtest/gtest.h"
|
||||
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "GMPVideoDecoderProxy.h"
|
||||
#include "GMPVideoEncoderProxy.h"
|
||||
#include "GMPService.h"
|
||||
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gmp;
|
||||
|
||||
struct GMPTestRunner
|
||||
{
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPTestRunner)
|
||||
|
||||
void DoTest(void (GMPTestRunner::*aTestMethod)());
|
||||
void RunTestGMPTestCodec();
|
||||
void RunTestGMPCrossOrigin();
|
||||
|
||||
private:
|
||||
~GMPTestRunner() { }
|
||||
};
|
||||
|
||||
void
|
||||
GMPTestRunner::RunTestGMPTestCodec()
|
||||
{
|
||||
nsRefPtr<GeckoMediaPluginService> service =
|
||||
GeckoMediaPluginService::GetGeckoMediaPluginService();
|
||||
|
||||
GMPVideoHost* host = nullptr;
|
||||
GMPVideoDecoderProxy* decoder = nullptr;
|
||||
GMPVideoDecoderProxy* decoder2 = nullptr;
|
||||
GMPVideoEncoderProxy* encoder = nullptr;
|
||||
|
||||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
|
||||
|
||||
service->GetGMPVideoDecoder(&tags, NS_LITERAL_CSTRING("o"), &host, &decoder2);
|
||||
service->GetGMPVideoDecoder(&tags, NS_LITERAL_CSTRING(""), &host, &decoder);
|
||||
|
||||
service->GetGMPVideoEncoder(&tags, NS_LITERAL_CSTRING(""), &host, &encoder);
|
||||
|
||||
EXPECT_TRUE(host);
|
||||
EXPECT_TRUE(decoder);
|
||||
EXPECT_TRUE(decoder2);
|
||||
EXPECT_TRUE(encoder);
|
||||
|
||||
if (decoder) decoder->Close();
|
||||
if (decoder2) decoder2->Close();
|
||||
if (encoder) encoder->Close();
|
||||
}
|
||||
|
||||
void
|
||||
GMPTestRunner::RunTestGMPCrossOrigin()
|
||||
{
|
||||
nsRefPtr<GeckoMediaPluginService> service =
|
||||
GeckoMediaPluginService::GetGeckoMediaPluginService();
|
||||
|
||||
GMPVideoHost* host = nullptr;
|
||||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
|
||||
|
||||
GMPVideoDecoderProxy* decoder1 = nullptr;
|
||||
GMPVideoDecoderProxy* decoder2 = nullptr;
|
||||
GMPVideoEncoderProxy* encoder1 = nullptr;
|
||||
GMPVideoEncoderProxy* encoder2 = nullptr;
|
||||
|
||||
service->GetGMPVideoDecoder(&tags, NS_LITERAL_CSTRING("origin1"), &host, &decoder1);
|
||||
service->GetGMPVideoDecoder(&tags, NS_LITERAL_CSTRING("origin2"), &host, &decoder2);
|
||||
EXPECT_TRUE(!!decoder1 && !!decoder2 &&
|
||||
decoder1->ParentID() != decoder2->ParentID());
|
||||
|
||||
service->GetGMPVideoEncoder(&tags, NS_LITERAL_CSTRING("origin1"), &host, &encoder1);
|
||||
service->GetGMPVideoEncoder(&tags, NS_LITERAL_CSTRING("origin2"), &host, &encoder2);
|
||||
EXPECT_TRUE(!!encoder1 && !!encoder2 &&
|
||||
encoder1->ParentID() != encoder2->ParentID());
|
||||
|
||||
if (decoder2) decoder2->Close();
|
||||
if (encoder2) encoder2->Close();
|
||||
|
||||
service->GetGMPVideoDecoder(&tags, NS_LITERAL_CSTRING("origin1"), &host, &decoder2);
|
||||
EXPECT_TRUE(!!decoder1 && !!decoder2 &&
|
||||
decoder1->ParentID() == decoder2->ParentID());
|
||||
|
||||
service->GetGMPVideoEncoder(&tags, NS_LITERAL_CSTRING("origin1"), &host, &encoder2);
|
||||
EXPECT_TRUE(!!encoder1 && !!encoder2 &&
|
||||
encoder1->ParentID() == encoder2->ParentID());
|
||||
|
||||
if (decoder1) decoder1->Close();
|
||||
if (decoder2) decoder2->Close();
|
||||
if (encoder1) encoder1->Close();
|
||||
if (encoder2) encoder2->Close();
|
||||
}
|
||||
|
||||
void
|
||||
GMPTestRunner::DoTest(void (GMPTestRunner::*aTestMethod)())
|
||||
{
|
||||
nsRefPtr<GeckoMediaPluginService> service =
|
||||
GeckoMediaPluginService::GetGeckoMediaPluginService();
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
|
||||
service->GetThread(getter_AddRefs(thread));
|
||||
thread->Dispatch(NS_NewRunnableMethod(this, aTestMethod), NS_DISPATCH_SYNC);
|
||||
}
|
||||
|
||||
TEST(GeckoMediaPlugins, GMPTestCodec) {
|
||||
nsRefPtr<GMPTestRunner> runner = new GMPTestRunner();
|
||||
runner->DoTest(&GMPTestRunner::RunTestGMPTestCodec);
|
||||
}
|
||||
|
||||
TEST(GeckoMediaPlugins, GMPCrossOrigin) {
|
||||
nsRefPtr<GMPTestRunner> runner = new GMPTestRunner();
|
||||
runner->DoTest(&GMPTestRunner::RunTestGMPCrossOrigin);
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
UNIFIED_SOURCES += [
|
||||
'TestAudioCompactor.cpp',
|
||||
'TestGMPCrossOrigin.cpp',
|
||||
'TestTrackEncoder.cpp',
|
||||
'TestVideoSegment.cpp',
|
||||
'TestWebMBuffered.cpp'
|
||||
|
@ -25,6 +26,7 @@ include('/ipc/chromium/chromium-config.mozbuild')
|
|||
|
||||
LOCAL_INCLUDES += [
|
||||
'/content/media/encoder',
|
||||
'/content/media/gmp',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul-gtest'
|
||||
|
|
|
@ -187,4 +187,17 @@ MediaSourceDecoder::PrepareReaderInitialization()
|
|||
mReader->PrepareInitialization();
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
nsresult
|
||||
MediaSourceDecoder::SetCDMProxy(CDMProxy* aProxy)
|
||||
{
|
||||
nsresult rv = MediaDecoder::SetCDMProxy(aProxy);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = mReader->SetCDMProxy(aProxy);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -63,6 +63,10 @@ public:
|
|||
// registered TrackBuffers essential for initialization.
|
||||
void PrepareReaderInitialization();
|
||||
|
||||
#ifdef MOZ_EME
|
||||
virtual nsresult SetCDMProxy(CDMProxy* aProxy) MOZ_OVERRIDE;
|
||||
#endif
|
||||
|
||||
private:
|
||||
// The owning MediaSource holds a strong reference to this decoder, and
|
||||
// calls Attach/DetachMediaSource on this decoder to set and clear
|
||||
|
|
|
@ -329,6 +329,9 @@ MediaSourceReader::CreateSubDecoder(const nsACString& aType)
|
|||
MSE_DEBUG("MediaSourceReader(%p)::CreateSubDecoder subdecoder %p subreader %p",
|
||||
this, decoder.get(), reader.get());
|
||||
decoder->SetReader(reader);
|
||||
#ifdef MOZ_EME
|
||||
decoder->SetCDMProxy(mCDMProxy);
|
||||
#endif
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
|
@ -515,4 +518,20 @@ MediaSourceReader::IsEnded()
|
|||
return mEnded;
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
nsresult
|
||||
MediaSourceReader::SetCDMProxy(CDMProxy* aProxy)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
|
||||
mCDMProxy = aProxy;
|
||||
for (size_t i = 0; i < mTrackBuffers.Length(); i++) {
|
||||
nsresult rv = mTrackBuffers[i]->SetCDMProxy(aProxy);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -101,6 +101,10 @@ public:
|
|||
// Return true if the Ended method has been called
|
||||
bool IsEnded();
|
||||
|
||||
#ifdef MOZ_EME
|
||||
nsresult SetCDMProxy(CDMProxy* aProxy);
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool SwitchAudioReader(int64_t aTarget);
|
||||
bool SwitchVideoReader(int64_t aTarget);
|
||||
|
@ -123,6 +127,10 @@ private:
|
|||
nsRefPtr<TrackBuffer> mAudioTrack;
|
||||
nsRefPtr<TrackBuffer> mVideoTrack;
|
||||
|
||||
#ifdef MOZ_EME
|
||||
nsRefPtr<CDMProxy> mCDMProxy;
|
||||
#endif
|
||||
|
||||
// These are read and written on the decode task queue threads.
|
||||
int64_t mLastAudioTime;
|
||||
int64_t mLastVideoTime;
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
#include "MediaDecoderReader.h"
|
||||
#include "SourceBufferResource.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#ifdef MOZ_EME
|
||||
#include "mozilla/CDMProxy.h"
|
||||
#endif
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -81,6 +84,23 @@ public:
|
|||
mTaskQueue = aTaskQueue;
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
virtual nsresult SetCDMProxy(CDMProxy* aProxy)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
mCDMProxy = aProxy;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
virtual CDMProxy* GetCDMProxy() MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(OnDecodeThread() || NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
return mCDMProxy;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Given a time convert it into an approximate byte offset from the
|
||||
// cached data. Returns -1 if no such value is computable.
|
||||
int64_t ConvertToByteOffset(double aTime);
|
||||
|
@ -96,6 +116,10 @@ private:
|
|||
AbstractMediaDecoder* mParentDecoder;
|
||||
nsRefPtr<MediaDecoderReader> mReader;
|
||||
int64_t mMediaDuration;
|
||||
|
||||
#ifdef MOZ_EME
|
||||
nsRefPtr<CDMProxy> mCDMProxy;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -237,6 +237,7 @@ TrackBuffer::NewDecoder()
|
|||
mLastStartTimestamp = 0;
|
||||
mLastEndTimestamp = 0;
|
||||
|
||||
decoder->SetTaskQueue(mTaskQueue);
|
||||
return QueueInitializeDecoder(decoder);
|
||||
}
|
||||
|
||||
|
@ -247,7 +248,6 @@ TrackBuffer::QueueInitializeDecoder(SourceBufferDecoder* aDecoder)
|
|||
NS_NewRunnableMethodWithArg<SourceBufferDecoder*>(this,
|
||||
&TrackBuffer::InitializeDecoder,
|
||||
aDecoder);
|
||||
aDecoder->SetTaskQueue(mTaskQueue);
|
||||
if (NS_FAILED(mTaskQueue->Dispatch(task))) {
|
||||
MSE_DEBUG("MediaSourceReader(%p): Failed to enqueue decoder initialization task", this);
|
||||
RemoveDecoder(aDecoder);
|
||||
|
@ -272,8 +272,16 @@ TrackBuffer::InitializeDecoder(SourceBufferDecoder* aDecoder)
|
|||
MediaInfo mi;
|
||||
nsAutoPtr<MetadataTags> tags; // TODO: Handle metadata.
|
||||
nsresult rv = reader->ReadMetadata(&mi, getter_Transfers(tags));
|
||||
aDecoder->SetTaskQueue(nullptr);
|
||||
reader->SetIdle();
|
||||
|
||||
if (NS_SUCCEEDED(rv) && reader->IsWaitingOnCDMResource()) {
|
||||
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
|
||||
mWaitingDecoders.AppendElement(aDecoder);
|
||||
return;
|
||||
}
|
||||
|
||||
aDecoder->SetTaskQueue(nullptr);
|
||||
|
||||
if (NS_FAILED(rv) || (!mi.HasVideo() && !mi.HasAudio())) {
|
||||
// XXX: Need to signal error back to owning SourceBuffer.
|
||||
MSE_DEBUG("TrackBuffer(%p): Reader %p failed to initialize rv=%x audio=%d video=%d",
|
||||
|
@ -415,6 +423,31 @@ TrackBuffer::Decoders()
|
|||
return mInitializedDecoders;
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
nsresult
|
||||
TrackBuffer::SetCDMProxy(CDMProxy* aProxy)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
|
||||
|
||||
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
|
||||
nsresult rv = mDecoders[i]->SetCDMProxy(aProxy);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mWaitingDecoders.Length(); ++i) {
|
||||
CDMCaps::AutoLock caps(aProxy->Capabilites());
|
||||
caps.CallOnMainThreadWhenCapsAvailable(
|
||||
NS_NewRunnableMethodWithArg<SourceBufferDecoder*>(this,
|
||||
&TrackBuffer::QueueInitializeDecoder,
|
||||
mWaitingDecoders[i]));
|
||||
}
|
||||
|
||||
mWaitingDecoders.Clear();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG)
|
||||
void
|
||||
TrackBuffer::Dump(const char* aPath)
|
||||
|
|
|
@ -73,6 +73,10 @@ public:
|
|||
// TODO: Refactor to a cleaner interface between TrackBuffer and MediaSourceReader.
|
||||
const nsTArray<nsRefPtr<SourceBufferDecoder>>& Decoders();
|
||||
|
||||
#ifdef MOZ_EME
|
||||
nsresult SetCDMProxy(CDMProxy* aProxy);
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG)
|
||||
void Dump(const char* aPath);
|
||||
#endif
|
||||
|
@ -127,6 +131,10 @@ private:
|
|||
// Access protected by mParentDecoder's monitor.
|
||||
nsTArray<nsRefPtr<SourceBufferDecoder>> mInitializedDecoders;
|
||||
|
||||
// Decoders which are waiting on a Content Decryption Module to be able to
|
||||
// finish ReadMetadata.
|
||||
nsTArray<nsRefPtr<SourceBufferDecoder>> mWaitingDecoders;
|
||||
|
||||
// The decoder that the owning SourceBuffer is currently appending data to.
|
||||
nsRefPtr<SourceBufferDecoder> mCurrentDecoder;
|
||||
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
This XML file describes the encryption applied to |gizmo-frag-cenc*|. To
|
||||
generate the gizmo-frag-cenc files, run the following commands:
|
||||
|
||||
Encrypt gizmo.mp4 with the keys specified in this file, and output to |gizmo-cenc.mp4|
|
||||
MP4Box -crypt gizmo-frag-cenc.xml -out gizmo-cenc.mp4 gizmo.mp4
|
||||
|
||||
Fragment |gizmo-cenc.mp4| into 1000ms segments:
|
||||
MP4Box -dash 1000 -rap -segment-name gizmo-frag-cenc -subsegs-per-sidx 5 -rem 2 gizmo-cenc.mp4
|
||||
|
||||
The above command will generate a set of fragments in |gizmo-frag-cenc*.m4s|
|
||||
and a single |gizmo-frag-cencinit.mp4| containing just the init segment.
|
||||
|
||||
To cut down the duration, we throw out all but the first two segments:
|
||||
rm gizmo-frag-cenc[^12].m4s
|
||||
-->
|
||||
|
||||
<GPACDRM type="CENC AES-CTR">
|
||||
|
||||
<DRMInfo type="pssh" version="1">
|
||||
<!--
|
||||
SystemID specified in
|
||||
https://dvcs.w3.org/hg/html-media/raw-file/tip/encrypted-media/cenc-format.html
|
||||
-->
|
||||
<BS ID128="1077efecc0b24d02ace33c1e52e2fb4b" />
|
||||
<!-- Number of KeyIDs = 2 -->
|
||||
<BS bits="32" value="2" />
|
||||
<!-- KeyID -->
|
||||
<BS ID128="0x7e571d037e571d037e571d037e571d03" />
|
||||
<BS ID128="0x7e571d047e571d047e571d047e571d04" />
|
||||
</DRMInfo>
|
||||
|
||||
<CrypTrack trackID="1" isEncrypted="1" IV_size="16" saiSavedBox="senc"
|
||||
first_IV="0x00000000000000000000000000000000">
|
||||
<key KID="0x7e571d037e571d037e571d037e571d03"
|
||||
value="0x7e5733337e5733337e5733337e573333" />
|
||||
</CrypTrack>
|
||||
|
||||
<CrypTrack trackID="2" isEncrypted="1" IV_size="16" saiSavedBox="senc"
|
||||
first_IV="0x00000000000000000000000000000000">
|
||||
<key KID="0x7e571d047e571d047e571d047e571d04"
|
||||
value="0x7e5744447e5744447e5744447e574444" />
|
||||
</CrypTrack>
|
||||
|
||||
</GPACDRM>
|
||||
|
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -640,14 +640,28 @@ var gMetadataTests = [
|
|||
var gEMETests = [
|
||||
{
|
||||
name:"short-cenc.mp4",
|
||||
type:"video/mp4",
|
||||
type:"video/mp4; codecs=\"avc1.64000d,mp4a.40.2\"",
|
||||
keys: {
|
||||
// "keyid" : "key"
|
||||
"7e571d017e571d017e571d017e571d01" : "7e5711117e5711117e5711117e571111",
|
||||
"7e571d027e571d027e571d027e571d02" : "7e5722227e5722227e5722227e572222",
|
||||
},
|
||||
sessionType:"temporary",
|
||||
duration:0.47
|
||||
},
|
||||
// XXX Bug 1082239
|
||||
//{
|
||||
// name:"gizmo-frag-cencinit.mp4",
|
||||
// fragments: [ "gizmo-frag-cencinit.mp4", "gizmo-frag-cenc1.m4s", "gizmo-frag-cenc2.m4s" ],
|
||||
// type:"video/mp4; codecs=\"avc1.64000d,mp4a.40.2\"",
|
||||
// keys: {
|
||||
// // "keyid" : "key"
|
||||
// "7e571d037e571d037e571d037e571d03" : "7e5733337e5733337e5733337e573333",
|
||||
// "7e571d047e571d047e571d047e571d04" : "7e5744447e5744447e5744447e574444",
|
||||
// },
|
||||
// sessionType:"temporary",
|
||||
// duration:2.00,
|
||||
//},
|
||||
];
|
||||
|
||||
function checkMetadata(msg, e, test) {
|
||||
|
|
|
@ -140,6 +140,9 @@ support-files =
|
|||
dirac.ogg^headers^
|
||||
dynamic_redirect.sjs
|
||||
dynamic_resource.sjs
|
||||
gizmo-frag-cenc1.m4s
|
||||
gizmo-frag-cenc2.m4s
|
||||
gizmo-frag-cencinit.mp4
|
||||
file_access_controls.html
|
||||
fragment_noplay.js
|
||||
fragment_play.js
|
||||
|
@ -319,7 +322,6 @@ skip-if = buildapp == 'mulet' || os == 'win' # bug 894922
|
|||
[test_bug686942.html]
|
||||
[test_bug726904.html]
|
||||
[test_bug874897.html]
|
||||
[test_bug879717.html]
|
||||
[test_bug883173.html]
|
||||
[test_bug895091.html]
|
||||
[test_bug895305.html]
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for bug 879717, check that a video element can be drawn into a canvas directly on 'play' event</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>
|
||||
<video id="v1" autoplay />
|
||||
<video id="v2" autoplay />
|
||||
<canvas id="c1" />
|
||||
<canvas id="c2" />
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var media = getPlayableVideo(gSmallTests);
|
||||
|
||||
var checkDrawImage = function(video, canvas, name) {
|
||||
var exception = null;
|
||||
var exceptionName = "nothing";
|
||||
try {
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
||||
} catch (e) {
|
||||
exception = e;
|
||||
exceptionName = e.name;
|
||||
}
|
||||
ok(exception === null || video.ended,
|
||||
"drawImage shouldn't throw an exception on play of " + name + ", got " + exceptionName);
|
||||
};
|
||||
|
||||
if (media == null) {
|
||||
todo(false, "No media supported.");
|
||||
SimpleTest.finish();
|
||||
} else {
|
||||
v1.src = media.name;
|
||||
v2.mozSrcObject = v1.mozCaptureStream();
|
||||
|
||||
var v1Tested = false;
|
||||
var v2Tested = false;
|
||||
|
||||
v1.addEventListener('play', function() {
|
||||
checkDrawImage(v1, c1, media.name);
|
||||
|
||||
v1Tested = true;
|
||||
if (v2Tested) {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
});
|
||||
|
||||
v2.addEventListener('play', function() {
|
||||
checkDrawImage(v2, c2, "stream of " + media.name);
|
||||
|
||||
v2Tested = true;
|
||||
if (v1Tested) {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -104,46 +104,131 @@ function UpdateSessionFunc(test) {
|
|||
}
|
||||
}
|
||||
|
||||
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 startTest(test, token)
|
||||
{
|
||||
manager.started(test._token);
|
||||
|
||||
var v = document.createElement("video");
|
||||
manager.started(token);
|
||||
var gotEncrypted = false;
|
||||
var gotPlaying = false;
|
||||
|
||||
v.addEventListener("encrypted", function(ev) {
|
||||
info("got encrypted event");
|
||||
gotEncrypted = true;
|
||||
|
||||
info(token + " got encrypted event");
|
||||
ok(MediaKeys.isTypeSupported(KEYSYSTEM_TYPE, ev.initDataType, test.type),
|
||||
"MediaKeys should support this keysystem");
|
||||
token + " MediaKeys should support this keysystem");
|
||||
|
||||
MediaKeys.create(KEYSYSTEM_TYPE).then(function(mediaKeys) {
|
||||
info("created MediaKeys object ok");
|
||||
info(token + " created MediaKeys object ok");
|
||||
return v.setMediaKeys(mediaKeys);
|
||||
}, bail("failed to create MediaKeys object")).then(function() {
|
||||
info("set MediaKeys on <video> element ok");
|
||||
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);
|
||||
session.addEventListener("message", UpdateSessionFunc(test));
|
||||
session.generateRequest(ev.initDataType, ev.initData).then(function() {
|
||||
}, bail("Failed to initialise MediaKeySession"));
|
||||
}, bail(token + " Failed to initialise MediaKeySession"));
|
||||
|
||||
}, bail("Failed to set MediaKeys on <video> element"));
|
||||
}, bail(token + " Failed to set MediaKeys on <video> element"));
|
||||
});
|
||||
|
||||
v.addEventListener("playing", function () { gotPlaying = true; });
|
||||
|
||||
v.addEventListener("ended", function(ev) {
|
||||
ok(true, "got ended event");
|
||||
SimpleTest.finish();
|
||||
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");
|
||||
});
|
||||
|
||||
v.addEventListener("error", bail("got error event"));
|
||||
v.addEventListener("error", bail(token + " got error event"));
|
||||
|
||||
v.src = test.name;
|
||||
v.play();
|
||||
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 = [ ];
|
||||
var prefs = [
|
||||
[ "media.mediasource.enabled", true ],
|
||||
[ "media.mediasource.ignore_codecs", true ],
|
||||
];
|
||||
|
||||
if (/Linux/.test(navigator.userAgent) ||
|
||||
!document.createElement('video').canPlayType("video/mp4")) {
|
||||
|
|
|
@ -19,8 +19,6 @@ using namespace mozilla::dom;
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
static const TrackID TRACK_VIDEO = 2;
|
||||
|
||||
void
|
||||
FakeMediaStreamGraph::DispatchToMainThreadAfterStreamStateUpdate(already_AddRefed<nsIRunnable> aRunnable)
|
||||
{
|
||||
|
@ -34,7 +32,6 @@ CameraPreviewMediaStream::CameraPreviewMediaStream(DOMMediaStream* aWrapper)
|
|||
, mInvalidatePending(0)
|
||||
, mDiscardedFrames(0)
|
||||
, mRateLimit(false)
|
||||
, mTrackCreated(false)
|
||||
{
|
||||
SetGraphImpl(MediaStreamGraph::GetInstance());
|
||||
mFakeMediaStreamGraph = new FakeMediaStreamGraph();
|
||||
|
@ -114,22 +111,6 @@ CameraPreviewMediaStream::RemoveListener(MediaStreamListener* aListener)
|
|||
listener->NotifyEvent(mFakeMediaStreamGraph, MediaStreamListener::EVENT_REMOVED);
|
||||
}
|
||||
|
||||
void
|
||||
CameraPreviewMediaStream::OnPreviewStateChange(bool aActive)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (!mTrackCreated && aActive) {
|
||||
mTrackCreated = true;
|
||||
VideoSegment tmpSegment;
|
||||
uint32_t trackEvent = aActive ? MediaStreamListener::TRACK_EVENT_CREATED
|
||||
: MediaStreamListener::TRACK_EVENT_ENDED;
|
||||
for (uint32_t j = 0; j < mListeners.Length(); ++j) {
|
||||
MediaStreamListener* l = mListeners[j];
|
||||
l->NotifyQueuedTrackChanges(mFakeMediaStreamGraph, TRACK_VIDEO, 0, 0, trackEvent, tmpSegment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CameraPreviewMediaStream::Destroy()
|
||||
{
|
||||
|
|
|
@ -51,7 +51,6 @@ public:
|
|||
virtual void AddListener(MediaStreamListener* aListener) MOZ_OVERRIDE;
|
||||
virtual void RemoveListener(MediaStreamListener* aListener) MOZ_OVERRIDE;
|
||||
virtual void Destroy();
|
||||
void OnPreviewStateChange(bool aActive);
|
||||
|
||||
void Invalidate();
|
||||
|
||||
|
@ -68,7 +67,6 @@ protected:
|
|||
int32_t mInvalidatePending;
|
||||
uint32_t mDiscardedFrames;
|
||||
bool mRateLimit;
|
||||
bool mTrackCreated;
|
||||
nsRefPtr<FakeMediaStreamGraph> mFakeMediaStreamGraph;
|
||||
};
|
||||
|
||||
|
|
|
@ -218,8 +218,7 @@ nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId,
|
|||
mCurrentConfiguration = initialConfig.forget();
|
||||
|
||||
// Attach our DOM-facing media stream to our viewfinder stream.
|
||||
SetHintContents(HINT_CONTENTS_VIDEO);
|
||||
InitStreamCommon(mInput);
|
||||
mStream = mInput;
|
||||
MOZ_ASSERT(mWindow, "Shouldn't be created with a null window!");
|
||||
if (mWindow->GetExtantDoc()) {
|
||||
CombineWithPrincipal(mWindow->GetExtantDoc()->NodePrincipal());
|
||||
|
|
|
@ -137,7 +137,6 @@ DOMCameraControlListener::OnPreviewStateChange(PreviewState aState)
|
|||
MOZ_ASSERT_UNREACHABLE("Invalid preview state");
|
||||
return;
|
||||
}
|
||||
mStream->OnPreviewStateChange(aState == kPreviewStarted);
|
||||
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aState));
|
||||
}
|
||||
|
||||
|
|
|
@ -109,26 +109,18 @@ var Camera = {
|
|||
var blob = e.data;
|
||||
var img = new Image();
|
||||
var test = this._currentTest;
|
||||
var onPreviewStateChange = function(e) {
|
||||
if (e.newState === 'started') {
|
||||
ok(true, "viewfinder is ready and playing after resume");
|
||||
Camera.cameraObj.removeEventListener('previewstatechange', onPreviewStateChange);
|
||||
Camera._testsCompleted++;
|
||||
if(Camera._testsCompleted == Camera._tests.length) {
|
||||
ok(true, "test finishing");
|
||||
SimpleTest.finish();
|
||||
} else {
|
||||
Camera.runTests();
|
||||
}
|
||||
}
|
||||
}
|
||||
Camera.cameraObj.addEventListener('previewstatechange', onPreviewStateChange);
|
||||
img.onload = function Imgsize() {
|
||||
ok(this.width == test.pictureSize.width, "The image taken has the width " +
|
||||
this.width + " pictureSize width = " + test.pictureSize.width);
|
||||
ok(this.height == test.pictureSize.height, "The image taken has the height " +
|
||||
this.height + " picturesize height = " + test.pictureSize.height);
|
||||
Camera.cameraObj.resumePreview();
|
||||
Camera._testsCompleted++;
|
||||
if(Camera._testsCompleted == Camera._tests.length) {
|
||||
ok(true, "test finishing");
|
||||
SimpleTest.finish();
|
||||
} else {
|
||||
Camera.runTests();
|
||||
}
|
||||
}
|
||||
ok(blob.size > 100 , "Blob Size Gathered = " + blob.size);
|
||||
ok("image/" + test.fileFormat == blob.type, "Blob Type = " + blob.type);
|
||||
|
|
|
@ -248,7 +248,6 @@ private:
|
|||
bool ValidateTexStorage(GLenum target, GLsizei levels, GLenum internalformat,
|
||||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
const char* info);
|
||||
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WebGL2Context.h"
|
||||
#include "WebGLContextUtils.h"
|
||||
#include "GLContext.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
@ -115,14 +116,9 @@ WebGL2Context::ValidateTexStorage(GLenum target, GLsizei levels, GLenum internal
|
|||
if (depth < 1) { ErrorInvalidValue("%s: depth is < 1", info); return false; }
|
||||
if (levels < 1) { ErrorInvalidValue("%s: levels is < 1", info); return false; }
|
||||
|
||||
// The following check via FloorLog2 only requires a depth value if target is TEXTURE_3D.
|
||||
bool is3D = (target != LOCAL_GL_TEXTURE_3D);
|
||||
if (!is3D)
|
||||
depth = 1;
|
||||
|
||||
// GL_INVALID_OPERATION is generated if levels is greater than floor(log2(max(width, height, depth)))+1.
|
||||
if (FloorLog2(std::max(std::max(width, height), depth))+1 < levels) {
|
||||
ErrorInvalidOperation("%s: levels > floor(log2(max(width, height%s)))+1", info, is3D ? ", depth" : "");
|
||||
if (FloorLog2(std::max(std::max(width, height), depth)) + 1 < levels) {
|
||||
ErrorInvalidOperation("%s: too many levels for given texture dimensions", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -140,7 +136,7 @@ WebGL2Context::TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat
|
|||
|
||||
// GL_INVALID_ENUM is generated if target is not one of the accepted target enumerants.
|
||||
if (target != LOCAL_GL_TEXTURE_2D && target != LOCAL_GL_TEXTURE_CUBE_MAP)
|
||||
return ErrorInvalidEnum("texStorage2D: target is not TEXTURE_2D or TEXTURE_CUBE_MAP.");
|
||||
return ErrorInvalidEnum("texStorage2D: target is not TEXTURE_2D or TEXTURE_CUBE_MAP");
|
||||
|
||||
if (!ValidateTexStorage(target, levels, internalformat, width, height, 1, "texStorage2D"))
|
||||
return;
|
||||
|
@ -154,12 +150,12 @@ WebGL2Context::TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat
|
|||
for (size_t l = 0; l < size_t(levels); l++) {
|
||||
for (size_t f = 0; f < facesCount; f++) {
|
||||
tex->SetImageInfo(TexImageTargetForTargetAndFace(target, f),
|
||||
l, w, h,
|
||||
l, w, h, 1,
|
||||
internalformat,
|
||||
WebGLImageDataStatus::UninitializedImageData);
|
||||
}
|
||||
w = std::max(1, w/2);
|
||||
h = std::max(1, h/2);
|
||||
w = std::max(1, w / 2);
|
||||
h = std::max(1, h / 2);
|
||||
}
|
||||
|
||||
gl->fTexStorage2D(target, levels, internalformat, width, height);
|
||||
|
@ -169,17 +165,131 @@ void
|
|||
WebGL2Context::TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat,
|
||||
GLsizei width, GLsizei height, GLsizei depth)
|
||||
{
|
||||
MOZ_CRASH("Not Implemented.");
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
// GL_INVALID_ENUM is generated if target is not one of the accepted target enumerants.
|
||||
if (target != LOCAL_GL_TEXTURE_3D)
|
||||
return ErrorInvalidEnum("texStorage3D: target is not TEXTURE_3D");
|
||||
|
||||
if (!ValidateTexStorage(target, levels, internalformat, width, height, depth, "texStorage3D"))
|
||||
return;
|
||||
|
||||
WebGLTexture* tex = activeBoundTextureForTarget(target);
|
||||
tex->SetImmutable();
|
||||
|
||||
GLsizei w = width;
|
||||
GLsizei h = height;
|
||||
GLsizei d = depth;
|
||||
for (size_t l = 0; l < size_t(levels); l++) {
|
||||
tex->SetImageInfo(TexImageTargetForTargetAndFace(target, 0),
|
||||
l, w, h, d,
|
||||
internalformat,
|
||||
WebGLImageDataStatus::UninitializedImageData);
|
||||
w = std::max(1, w >> 1);
|
||||
h = std::max(1, h >> 1);
|
||||
d = std::max(1, d >> 1);
|
||||
}
|
||||
|
||||
gl->fTexStorage3D(target, levels, internalformat, width, height, depth);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::TexSubImage3D(GLenum target, GLint level,
|
||||
WebGL2Context::TexSubImage3D(GLenum rawTarget, GLint level,
|
||||
GLint xoffset, GLint yoffset, GLint zoffset,
|
||||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
GLenum format, GLenum type, const Nullable<dom::ArrayBufferView>& pixels,
|
||||
ErrorResult& rv)
|
||||
{
|
||||
MOZ_CRASH("Not Implemented.");
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (pixels.IsNull())
|
||||
return ErrorInvalidValue("texSubImage3D: pixels must not be null!");
|
||||
|
||||
const ArrayBufferView& view = pixels.Value();
|
||||
view.ComputeLengthAndData();
|
||||
|
||||
const WebGLTexImageFunc func = WebGLTexImageFunc::TexSubImage;
|
||||
const WebGLTexDimensions dims = WebGLTexDimensions::Tex3D;
|
||||
|
||||
if (!ValidateTexImageTarget(rawTarget, func, dims))
|
||||
return;
|
||||
|
||||
TexImageTarget texImageTarget(rawTarget);
|
||||
|
||||
WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget);
|
||||
if (!tex) {
|
||||
return ErrorInvalidOperation("texSubImage3D: no texture bound on active texture unit");
|
||||
}
|
||||
|
||||
if (!tex->HasImageInfoAt(texImageTarget, level)) {
|
||||
return ErrorInvalidOperation("texSubImage3D: no previously defined texture image");
|
||||
}
|
||||
|
||||
const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
|
||||
const TexInternalFormat existingEffectiveInternalFormat = imageInfo.EffectiveInternalFormat();
|
||||
TexInternalFormat existingUnsizedInternalFormat = LOCAL_GL_NONE;
|
||||
TexType existingType = LOCAL_GL_NONE;
|
||||
UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(existingEffectiveInternalFormat,
|
||||
&existingUnsizedInternalFormat,
|
||||
&existingType);
|
||||
|
||||
if (!ValidateTexImage(texImageTarget, level, existingEffectiveInternalFormat.get(),
|
||||
xoffset, yoffset, zoffset,
|
||||
width, height, depth,
|
||||
0, format, type, func, dims))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (type != existingType) {
|
||||
return ErrorInvalidOperation("texSubImage3D: type differs from that of the existing image");
|
||||
}
|
||||
|
||||
js::Scalar::Type jsArrayType = JS_GetArrayBufferViewType(view.Obj());
|
||||
void* data = view.Data();
|
||||
size_t dataLength = view.Length();
|
||||
|
||||
if (!ValidateTexInputData(type, jsArrayType, func, dims))
|
||||
return;
|
||||
|
||||
const size_t bitsPerTexel = GetBitsPerTexel(existingEffectiveInternalFormat);
|
||||
MOZ_ASSERT((bitsPerTexel % 8) == 0); // should not have compressed formats here.
|
||||
size_t srcTexelSize = bitsPerTexel / 8;
|
||||
|
||||
if (width == 0 || height == 0 || depth == 0)
|
||||
return; // no effect, we better return right now
|
||||
|
||||
CheckedUint32 checked_neededByteLength =
|
||||
GetImageSize(height, width, depth, srcTexelSize, mPixelStoreUnpackAlignment);
|
||||
|
||||
if (!checked_neededByteLength.isValid())
|
||||
return ErrorInvalidOperation("texSubImage2D: integer overflow computing the needed buffer size");
|
||||
|
||||
uint32_t bytesNeeded = checked_neededByteLength.value();
|
||||
|
||||
if (dataLength < bytesNeeded)
|
||||
return ErrorInvalidOperation("texSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, dataLength);
|
||||
|
||||
if (imageInfo.HasUninitializedImageData())
|
||||
tex->DoDeferredImageInitialization(texImageTarget, level);
|
||||
|
||||
GLenum driverType = LOCAL_GL_NONE;
|
||||
GLenum driverInternalFormat = LOCAL_GL_NONE;
|
||||
GLenum driverFormat = LOCAL_GL_NONE;
|
||||
DriverFormatsFromEffectiveInternalFormat(gl,
|
||||
existingEffectiveInternalFormat,
|
||||
&driverInternalFormat,
|
||||
&driverFormat,
|
||||
&driverType);
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fTexSubImage3D(texImageTarget.get(), level,
|
||||
xoffset, yoffset, zoffset,
|
||||
width, height, depth,
|
||||
driverFormat, driverType, data);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -345,6 +345,7 @@ WebGLContext::DestroyResourcesAndContext()
|
|||
|
||||
mBound2DTextures.Clear();
|
||||
mBoundCubeMapTextures.Clear();
|
||||
mBound3DTextures.Clear();
|
||||
mBoundArrayBuffer = nullptr;
|
||||
mBoundTransformFeedbackBuffer = nullptr;
|
||||
mCurrentProgram = nullptr;
|
||||
|
@ -1772,8 +1773,11 @@ bool WebGLContext::TexImageFromVideoElement(const TexImageTarget texImageTarget,
|
|||
type = LOCAL_GL_HALF_FLOAT;
|
||||
}
|
||||
|
||||
if (!ValidateTexImageFormatAndType(format, type, WebGLTexImageFunc::TexImage))
|
||||
if (!ValidateTexImageFormatAndType(format, type,
|
||||
WebGLTexImageFunc::TexImage, WebGLTexDimensions::Tex2D))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
HTMLVideoElement* video = HTMLVideoElement::FromContentOrNull(&elt);
|
||||
if (!video) {
|
||||
|
@ -1825,7 +1829,7 @@ bool WebGLContext::TexImageFromVideoElement(const TexImageTarget texImageTarget,
|
|||
TexInternalFormat effectiveinternalformat =
|
||||
EffectiveInternalFormatFromInternalFormatAndType(internalformat, type);
|
||||
MOZ_ASSERT(effectiveinternalformat != LOCAL_GL_NONE);
|
||||
tex->SetImageInfo(texImageTarget, level, srcImage->GetSize().width, srcImage->GetSize().height,
|
||||
tex->SetImageInfo(texImageTarget, level, srcImage->GetSize().width, srcImage->GetSize().height, 1,
|
||||
effectiveinternalformat, WebGLImageDataStatus::InitializedImageData);
|
||||
tex->Bind(TexImageTargetToTexTarget(texImageTarget));
|
||||
}
|
||||
|
@ -1869,6 +1873,7 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLContext,
|
|||
mExtensions,
|
||||
mBound2DTextures,
|
||||
mBoundCubeMapTextures,
|
||||
mBound3DTextures,
|
||||
mBoundArrayBuffer,
|
||||
mBoundTransformFeedbackBuffer,
|
||||
mCurrentProgram,
|
||||
|
|
|
@ -228,8 +228,16 @@ public:
|
|||
void DummyFramebufferOperation(const char *info);
|
||||
|
||||
WebGLTexture* activeBoundTextureForTarget(const TexTarget texTarget) const {
|
||||
return texTarget == LOCAL_GL_TEXTURE_2D ? mBound2DTextures[mActiveTexture]
|
||||
: mBoundCubeMapTextures[mActiveTexture];
|
||||
switch (texTarget.get()) {
|
||||
case LOCAL_GL_TEXTURE_2D:
|
||||
return mBound2DTextures[mActiveTexture];
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP:
|
||||
return mBoundCubeMapTextures[mActiveTexture];
|
||||
case LOCAL_GL_TEXTURE_3D:
|
||||
return mBound3DTextures[mActiveTexture];
|
||||
default:
|
||||
MOZ_CRASH("bad target");
|
||||
}
|
||||
}
|
||||
|
||||
/* Use this function when you have the texture image target, for example:
|
||||
|
@ -483,10 +491,12 @@ public:
|
|||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
auto dims = 2;
|
||||
|
||||
if (!ValidateTexImageTarget(dims, rawTexImgTarget, WebGLTexImageFunc::TexImage))
|
||||
if (!ValidateTexImageTarget(rawTexImgTarget,
|
||||
WebGLTexImageFunc::TexImage,
|
||||
WebGLTexDimensions::Tex2D))
|
||||
{
|
||||
return ErrorInvalidEnumInfo("texSubImage2D: target", rawTexImgTarget);
|
||||
}
|
||||
|
||||
const TexImageTarget texImageTarget(rawTexImgTarget);
|
||||
|
||||
|
@ -520,7 +530,7 @@ public:
|
|||
return TexImage2D_base(texImageTarget, level, internalformat,
|
||||
size.width, size.height, data->Stride(),
|
||||
0, format, type, data->GetData(), byteLength,
|
||||
-1, srcFormat, mPixelStorePremultiplyAlpha);
|
||||
js::Scalar::TypeMax, srcFormat, mPixelStorePremultiplyAlpha);
|
||||
}
|
||||
|
||||
void TexParameterf(GLenum target, GLenum pname, GLfloat param) {
|
||||
|
@ -552,8 +562,12 @@ public:
|
|||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateTexImageTarget(2, rawTexImageTarget, WebGLTexImageFunc::TexSubImage))
|
||||
if (!ValidateTexImageTarget(rawTexImageTarget,
|
||||
WebGLTexImageFunc::TexSubImage,
|
||||
WebGLTexDimensions::Tex2D))
|
||||
{
|
||||
return ErrorInvalidEnumInfo("texSubImage2D: target", rawTexImageTarget);
|
||||
}
|
||||
|
||||
const TexImageTarget texImageTarget(rawTexImageTarget);
|
||||
|
||||
|
@ -592,7 +606,7 @@ public:
|
|||
size.width, size.height,
|
||||
data->Stride(), format, type,
|
||||
data->GetData(), byteLength,
|
||||
-1, srcFormat, mPixelStorePremultiplyAlpha);
|
||||
js::Scalar::TypeMax, srcFormat, mPixelStorePremultiplyAlpha);
|
||||
|
||||
}
|
||||
|
||||
|
@ -836,6 +850,7 @@ private:
|
|||
public:
|
||||
void Disable(GLenum cap);
|
||||
void Enable(GLenum cap);
|
||||
bool GetStencilBits(GLint* out_stencilBits);
|
||||
JS::Value GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv);
|
||||
void GetParameter(JSContext* cx, GLenum pname,
|
||||
JS::MutableHandle<JS::Value> retval, ErrorResult& rv) {
|
||||
|
@ -971,6 +986,7 @@ protected:
|
|||
|
||||
static CheckedUint32 GetImageSize(GLsizei height,
|
||||
GLsizei width,
|
||||
GLsizei depth,
|
||||
uint32_t pixelSize,
|
||||
uint32_t alignment);
|
||||
|
||||
|
@ -1092,7 +1108,10 @@ protected:
|
|||
bool ValidateComparisonEnum(GLenum target, const char *info);
|
||||
bool ValidateStencilOpEnum(GLenum action, const char *info);
|
||||
bool ValidateFaceEnum(GLenum face, const char *info);
|
||||
bool ValidateTexInputData(GLenum type, int jsArrayType, WebGLTexImageFunc func);
|
||||
bool ValidateTexInputData(GLenum type,
|
||||
js::Scalar::Type jsArrayType,
|
||||
WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims);
|
||||
bool ValidateDrawModeEnum(GLenum mode, const char *info);
|
||||
bool ValidateAttribIndex(GLuint index, const char *info);
|
||||
bool ValidateStencilParamsForDrawCall();
|
||||
|
@ -1102,40 +1121,56 @@ protected:
|
|||
bool ValidateGLSLString(const nsAString& string, const char *info);
|
||||
|
||||
bool ValidateCopyTexImage(GLenum internalformat,
|
||||
WebGLTexImageFunc func);
|
||||
bool ValidateTexImage(GLuint dims, TexImageTarget texImageTarget,
|
||||
WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims);
|
||||
bool ValidateTexImage(TexImageTarget texImageTarget,
|
||||
GLint level, GLenum internalFormat,
|
||||
GLint xoffset, GLint yoffset, GLint zoffset,
|
||||
GLint width, GLint height, GLint depth,
|
||||
GLint border, GLenum format, GLenum type,
|
||||
WebGLTexImageFunc func);
|
||||
bool ValidateTexImageTarget(GLuint dims, GLenum target, WebGLTexImageFunc func);
|
||||
WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims);
|
||||
bool ValidateTexImageTarget(GLenum target,
|
||||
WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims);
|
||||
bool ValidateTexImageFormat(GLenum internalformat,
|
||||
WebGLTexImageFunc func);
|
||||
bool ValidateTexImageType(GLenum type, WebGLTexImageFunc func);
|
||||
bool ValidateTexImageFormatAndType(GLenum format, GLenum type, WebGLTexImageFunc func);
|
||||
WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims);
|
||||
bool ValidateTexImageType(GLenum type,
|
||||
WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims);
|
||||
bool ValidateTexImageFormatAndType(GLenum format,
|
||||
GLenum type,
|
||||
WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims);
|
||||
bool ValidateCompTexImageInternalFormat(GLenum format,
|
||||
WebGLTexImageFunc func);
|
||||
WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims);
|
||||
bool ValidateCopyTexImageInternalFormat(GLenum format,
|
||||
WebGLTexImageFunc func);
|
||||
WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims);
|
||||
bool ValidateTexImageSize(TexImageTarget target, GLint level,
|
||||
GLint width, GLint height, GLint depth,
|
||||
WebGLTexImageFunc func);
|
||||
WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims);
|
||||
bool ValidateTexSubImageSize(GLint x, GLint y, GLint z,
|
||||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
GLsizei baseWidth, GLsizei baseHeight, GLsizei baseDepth,
|
||||
WebGLTexImageFunc func);
|
||||
|
||||
WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims);
|
||||
bool ValidateCompTexImageSize(GLint level,
|
||||
GLenum internalformat,
|
||||
GLint xoffset, GLint yoffset,
|
||||
GLsizei width, GLsizei height,
|
||||
GLsizei levelWidth, GLsizei levelHeight,
|
||||
WebGLTexImageFunc func);
|
||||
WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims);
|
||||
bool ValidateCompTexImageDataSize(GLint level,
|
||||
GLenum internalformat,
|
||||
GLsizei width, GLsizei height,
|
||||
uint32_t byteLength, WebGLTexImageFunc func);
|
||||
uint32_t byteLength,
|
||||
WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims);
|
||||
|
||||
void Invalidate();
|
||||
void DestroyResourcesAndContext();
|
||||
|
@ -1143,6 +1178,7 @@ protected:
|
|||
void MakeContextCurrent() const;
|
||||
|
||||
// helpers
|
||||
|
||||
void TexImage2D_base(TexImageTarget target,
|
||||
GLint level,
|
||||
GLenum internalformat,
|
||||
|
@ -1150,7 +1186,7 @@ protected:
|
|||
GLenum format,
|
||||
GLenum type,
|
||||
void *data, uint32_t byteLength,
|
||||
int jsArrayType,
|
||||
js::Scalar::Type jsArrayType, // special value TypeMax used to mean no array
|
||||
WebGLTexelFormat srcFormat, bool srcPremultiplied);
|
||||
void TexSubImage2D_base(TexImageTarget target, GLint level,
|
||||
GLint xoffset, GLint yoffset,
|
||||
|
@ -1158,7 +1194,7 @@ protected:
|
|||
GLenum format,
|
||||
GLenum type,
|
||||
void *pixels, uint32_t byteLength,
|
||||
int jsArrayType,
|
||||
js::Scalar::Type jsArrayType, // special value TypeMax used to mean no array
|
||||
WebGLTexelFormat srcFormat, bool srcPremultiplied);
|
||||
void TexParameter_base(GLenum target, GLenum pname,
|
||||
GLint *intParamPtr, GLfloat *floatParamPtr);
|
||||
|
@ -1255,6 +1291,7 @@ protected:
|
|||
|
||||
nsTArray<WebGLRefPtr<WebGLTexture> > mBound2DTextures;
|
||||
nsTArray<WebGLRefPtr<WebGLTexture> > mBoundCubeMapTextures;
|
||||
nsTArray<WebGLRefPtr<WebGLTexture> > mBound3DTextures;
|
||||
|
||||
WebGLRefPtr<WebGLProgram> mCurrentProgram;
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "mozilla/dom/ImageData.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
#include "mozilla/Endian.h"
|
||||
#include "mozilla/fallible.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
@ -233,6 +234,12 @@ WebGLContext::BindTexture(GLenum rawTarget, WebGLTexture *newTex)
|
|||
case LOCAL_GL_TEXTURE_CUBE_MAP:
|
||||
currentTexPtr = &mBoundCubeMapTextures[mActiveTexture];
|
||||
break;
|
||||
case LOCAL_GL_TEXTURE_3D:
|
||||
if (!IsWebGL2()) {
|
||||
return ErrorInvalidEnum("bindTexture: target TEXTURE_3D is only available in WebGL version 2.0 or newer");
|
||||
}
|
||||
currentTexPtr = &mBound3DTextures[mActiveTexture];
|
||||
break;
|
||||
default:
|
||||
return ErrorInvalidEnumInfo("bindTexture: target", rawTarget);
|
||||
}
|
||||
|
@ -367,22 +374,25 @@ WebGLContext::CopyTexSubImage2D_base(TexImageTarget texImageTarget,
|
|||
GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0;
|
||||
GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;
|
||||
|
||||
const char* info = sub ? "copyTexSubImage2D" : "copyTexImage2D";
|
||||
WebGLTexImageFunc func = sub ? WebGLTexImageFunc::CopyTexSubImage : WebGLTexImageFunc::CopyTexImage;
|
||||
WebGLTexImageFunc func = sub
|
||||
? WebGLTexImageFunc::CopyTexSubImage
|
||||
: WebGLTexImageFunc::CopyTexImage;
|
||||
WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
|
||||
const char* info = InfoFrom(func, dims);
|
||||
|
||||
// TODO: This changes with color_buffer_float. Reassess when the
|
||||
// patch lands.
|
||||
if (!ValidateTexImage(2, texImageTarget, level, internalformat.get(),
|
||||
if (!ValidateTexImage(texImageTarget, level, internalformat.get(),
|
||||
xoffset, yoffset, 0,
|
||||
width, height, 0,
|
||||
0,
|
||||
LOCAL_GL_NONE, LOCAL_GL_NONE,
|
||||
func))
|
||||
func, dims))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateCopyTexImage(internalformat.get(), func))
|
||||
if (!ValidateCopyTexImage(internalformat.get(), func, dims))
|
||||
return;
|
||||
|
||||
if (!mBoundFramebuffer)
|
||||
|
@ -440,7 +450,7 @@ WebGLContext::CopyTexSubImage2D_base(TexImageTarget texImageTarget,
|
|||
|
||||
// first, we initialize the texture as black
|
||||
if (!sub) {
|
||||
tex->SetImageInfo(texImageTarget, level, width, height,
|
||||
tex->SetImageInfo(texImageTarget, level, width, height, 1,
|
||||
effectiveInternalFormat,
|
||||
WebGLImageDataStatus::UninitializedImageData);
|
||||
tex->DoDeferredImageInitialization(texImageTarget, level);
|
||||
|
@ -478,7 +488,7 @@ WebGLContext::CopyTexSubImage2D_base(TexImageTarget texImageTarget,
|
|||
}
|
||||
|
||||
if (!sub) {
|
||||
tex->SetImageInfo(texImageTarget, level, width, height,
|
||||
tex->SetImageInfo(texImageTarget, level, width, height, 1,
|
||||
effectiveInternalFormat,
|
||||
WebGLImageDataStatus::InitializedImageData);
|
||||
}
|
||||
|
@ -499,20 +509,21 @@ WebGLContext::CopyTexImage2D(GLenum rawTexImgTarget,
|
|||
|
||||
// copyTexImage2D only generates textures with type = UNSIGNED_BYTE
|
||||
const WebGLTexImageFunc func = WebGLTexImageFunc::CopyTexImage;
|
||||
const WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
|
||||
|
||||
if (!ValidateTexImageTarget(2, rawTexImgTarget, WebGLTexImageFunc::CopyTexImage))
|
||||
if (!ValidateTexImageTarget(rawTexImgTarget, func, dims))
|
||||
return;
|
||||
|
||||
if (!ValidateTexImage(2, rawTexImgTarget, level, internalformat,
|
||||
if (!ValidateTexImage(rawTexImgTarget, level, internalformat,
|
||||
0, 0, 0,
|
||||
width, height, 0,
|
||||
border, LOCAL_GL_NONE, LOCAL_GL_NONE,
|
||||
func))
|
||||
func, dims))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateCopyTexImage(internalformat, func))
|
||||
if (!ValidateCopyTexImage(internalformat, func, dims))
|
||||
return;
|
||||
|
||||
if (!mBoundFramebuffer)
|
||||
|
@ -698,7 +709,8 @@ WebGLContext::DeleteTexture(WebGLTexture *tex)
|
|||
GLuint activeTexture = mActiveTexture;
|
||||
for (int32_t i = 0; i < mGLMaxTextureUnits; i++) {
|
||||
if ((mBound2DTextures[i] == tex && tex->Target() == LOCAL_GL_TEXTURE_2D) ||
|
||||
(mBoundCubeMapTextures[i] == tex && tex->Target() == LOCAL_GL_TEXTURE_CUBE_MAP))
|
||||
(mBoundCubeMapTextures[i] == tex && tex->Target() == LOCAL_GL_TEXTURE_CUBE_MAP) ||
|
||||
(mBound3DTextures[i] == tex && tex->Target() == LOCAL_GL_TEXTURE_3D))
|
||||
{
|
||||
ActiveTexture(LOCAL_GL_TEXTURE0 + i);
|
||||
BindTexture(tex->Target().get(), static_cast<WebGLTexture*>(nullptr));
|
||||
|
@ -2144,7 +2156,7 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
|||
|
||||
// Check the pixels param size
|
||||
CheckedUint32 checked_neededByteLength =
|
||||
GetImageSize(height, width, bytesPerPixel, mPixelStorePackAlignment);
|
||||
GetImageSize(height, width, 1, bytesPerPixel, mPixelStorePackAlignment);
|
||||
|
||||
CheckedUint32 checked_plainRowSize = CheckedUint32(width) * bytesPerPixel;
|
||||
|
||||
|
@ -3309,15 +3321,16 @@ WebGLContext::CompressedTexImage2D(GLenum rawTexImgTarget,
|
|||
return;
|
||||
|
||||
const WebGLTexImageFunc func = WebGLTexImageFunc::CompTexImage;
|
||||
const WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
|
||||
|
||||
if (!ValidateTexImageTarget(2, rawTexImgTarget, WebGLTexImageFunc::CompTexImage))
|
||||
if (!ValidateTexImageTarget(rawTexImgTarget, func, dims))
|
||||
return;
|
||||
|
||||
if (!ValidateTexImage(2, rawTexImgTarget, level, internalformat,
|
||||
if (!ValidateTexImage(rawTexImgTarget, level, internalformat,
|
||||
0, 0, 0, width, height, 0,
|
||||
border, LOCAL_GL_NONE,
|
||||
LOCAL_GL_NONE,
|
||||
func))
|
||||
func, dims))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -3325,11 +3338,11 @@ WebGLContext::CompressedTexImage2D(GLenum rawTexImgTarget,
|
|||
view.ComputeLengthAndData();
|
||||
|
||||
uint32_t byteLength = view.Length();
|
||||
if (!ValidateCompTexImageDataSize(level, internalformat, width, height, byteLength, func)) {
|
||||
if (!ValidateCompTexImageDataSize(level, internalformat, width, height, byteLength, func, dims)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateCompTexImageSize(level, internalformat, 0, 0, width, height, width, height, func))
|
||||
if (!ValidateCompTexImageSize(level, internalformat, 0, 0, width, height, width, height, func, dims))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -3347,7 +3360,7 @@ WebGLContext::CompressedTexImage2D(GLenum rawTexImgTarget,
|
|||
MakeContextCurrent();
|
||||
gl->fCompressedTexImage2D(texImageTarget.get(), level, internalformat, width, height, border, byteLength, view.Data());
|
||||
|
||||
tex->SetImageInfo(texImageTarget, level, width, height, internalformat,
|
||||
tex->SetImageInfo(texImageTarget, level, width, height, 1, internalformat,
|
||||
WebGLImageDataStatus::InitializedImageData);
|
||||
}
|
||||
|
||||
|
@ -3361,16 +3374,17 @@ WebGLContext::CompressedTexSubImage2D(GLenum rawTexImgTarget, GLint level, GLint
|
|||
return;
|
||||
|
||||
const WebGLTexImageFunc func = WebGLTexImageFunc::CompTexSubImage;
|
||||
const WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
|
||||
|
||||
if (!ValidateTexImageTarget(2, rawTexImgTarget, WebGLTexImageFunc::CompTexSubImage))
|
||||
if (!ValidateTexImageTarget(rawTexImgTarget, func, dims))
|
||||
return;
|
||||
|
||||
if (!ValidateTexImage(2, rawTexImgTarget,
|
||||
if (!ValidateTexImage(rawTexImgTarget,
|
||||
level, internalformat,
|
||||
xoffset, yoffset, 0,
|
||||
width, height, 0,
|
||||
0, LOCAL_GL_NONE, LOCAL_GL_NONE,
|
||||
func))
|
||||
func, dims))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -3388,14 +3402,14 @@ WebGLContext::CompressedTexSubImage2D(GLenum rawTexImgTarget, GLint level, GLint
|
|||
view.ComputeLengthAndData();
|
||||
|
||||
uint32_t byteLength = view.Length();
|
||||
if (!ValidateCompTexImageDataSize(level, internalformat, width, height, byteLength, func))
|
||||
if (!ValidateCompTexImageDataSize(level, internalformat, width, height, byteLength, func, dims))
|
||||
return;
|
||||
|
||||
if (!ValidateCompTexImageSize(level, internalformat,
|
||||
xoffset, yoffset,
|
||||
width, height,
|
||||
levelInfo.Width(), levelInfo.Height(),
|
||||
func))
|
||||
func, dims))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -3647,19 +3661,20 @@ WebGLContext::TexImage2D_base(TexImageTarget texImageTarget, GLint level,
|
|||
GLenum format,
|
||||
GLenum type,
|
||||
void* data, uint32_t byteLength,
|
||||
int jsArrayType, // a TypedArray format enum, or -1 if not relevant
|
||||
js::Scalar::Type jsArrayType,
|
||||
WebGLTexelFormat srcFormat, bool srcPremultiplied)
|
||||
{
|
||||
const WebGLTexImageFunc func = WebGLTexImageFunc::TexImage;
|
||||
const WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
|
||||
|
||||
if (type == LOCAL_GL_HALF_FLOAT_OES) {
|
||||
type = LOCAL_GL_HALF_FLOAT;
|
||||
}
|
||||
|
||||
if (!ValidateTexImage(2, texImageTarget, level, internalformat,
|
||||
if (!ValidateTexImage(texImageTarget, level, internalformat,
|
||||
0, 0, 0,
|
||||
width, height, 0,
|
||||
border, format, type, func))
|
||||
border, format, type, func, dims))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -3675,7 +3690,7 @@ WebGLContext::TexImage2D_base(TexImageTarget texImageTarget, GLint level,
|
|||
"level must be zero");
|
||||
}
|
||||
|
||||
if (!ValidateTexInputData(type, jsArrayType, func))
|
||||
if (!ValidateTexInputData(type, jsArrayType, func, dims))
|
||||
return;
|
||||
|
||||
TexInternalFormat effectiveInternalFormat =
|
||||
|
@ -3701,7 +3716,7 @@ WebGLContext::TexImage2D_base(TexImageTarget texImageTarget, GLint level,
|
|||
}
|
||||
|
||||
CheckedUint32 checked_neededByteLength =
|
||||
GetImageSize(height, width, srcTexelSize, mPixelStoreUnpackAlignment);
|
||||
GetImageSize(height, width, 1, srcTexelSize, mPixelStoreUnpackAlignment);
|
||||
|
||||
CheckedUint32 checked_plainRowSize = CheckedUint32(width) * srcTexelSize;
|
||||
CheckedUint32 checked_alignedRowSize =
|
||||
|
@ -3755,7 +3770,12 @@ WebGLContext::TexImage2D_base(TexImageTarget texImageTarget, GLint level,
|
|||
else
|
||||
{
|
||||
size_t convertedDataSize = height * dstStride;
|
||||
convertedData = new uint8_t[convertedDataSize];
|
||||
convertedData = (uint8_t*)moz_malloc(convertedDataSize);
|
||||
if (!convertedData) {
|
||||
ErrorOutOfMemory("texImage2D: Ran out of memory when allocating"
|
||||
" a buffer for doing format conversion.");
|
||||
return;
|
||||
}
|
||||
if (!ConvertImage(width, height, srcStride, dstStride,
|
||||
static_cast<uint8_t*>(data), convertedData,
|
||||
actualSrcFormat, srcPremultiplied,
|
||||
|
@ -3781,7 +3801,7 @@ WebGLContext::TexImage2D_base(TexImageTarget texImageTarget, GLint level,
|
|||
// have NoImageData at this point.
|
||||
MOZ_ASSERT(imageInfoStatusIfSuccess != WebGLImageDataStatus::NoImageData);
|
||||
|
||||
tex->SetImageInfo(texImageTarget, level, width, height,
|
||||
tex->SetImageInfo(texImageTarget, level, width, height, 1,
|
||||
effectiveInternalFormat, imageInfoStatusIfSuccess);
|
||||
}
|
||||
|
||||
|
@ -3796,21 +3816,21 @@ WebGLContext::TexImage2D(GLenum rawTarget, GLint level,
|
|||
|
||||
void* data;
|
||||
uint32_t length;
|
||||
int jsArrayType;
|
||||
js::Scalar::Type jsArrayType;
|
||||
if (pixels.IsNull()) {
|
||||
data = nullptr;
|
||||
length = 0;
|
||||
jsArrayType = -1;
|
||||
jsArrayType = js::Scalar::TypeMax;
|
||||
} else {
|
||||
const ArrayBufferView& view = pixels.Value();
|
||||
view.ComputeLengthAndData();
|
||||
|
||||
data = view.Data();
|
||||
length = view.Length();
|
||||
jsArrayType = int(JS_GetArrayBufferViewType(view.Obj()));
|
||||
jsArrayType = JS_GetArrayBufferViewType(view.Obj());
|
||||
}
|
||||
|
||||
if (!ValidateTexImageTarget(2, rawTarget, WebGLTexImageFunc::TexImage))
|
||||
if (!ValidateTexImageTarget(rawTarget, WebGLTexImageFunc::TexImage, WebGLTexDimensions::Tex2D))
|
||||
return;
|
||||
|
||||
return TexImage2D_base(rawTarget, level, internalformat, width, height, 0, border, format, type,
|
||||
|
@ -3839,12 +3859,12 @@ WebGLContext::TexImage2D(GLenum rawTarget, GLint level,
|
|||
void* pixelData = arr.Data();
|
||||
const uint32_t pixelDataLength = arr.Length();
|
||||
|
||||
if (!ValidateTexImageTarget(2, rawTarget, WebGLTexImageFunc::TexImage))
|
||||
if (!ValidateTexImageTarget(rawTarget, WebGLTexImageFunc::TexImage, WebGLTexDimensions::Tex2D))
|
||||
return;
|
||||
|
||||
return TexImage2D_base(rawTarget, level, internalformat, pixels->Width(),
|
||||
pixels->Height(), 4*pixels->Width(), 0,
|
||||
format, type, pixelData, pixelDataLength, -1,
|
||||
format, type, pixelData, pixelDataLength, js::Scalar::TypeMax,
|
||||
WebGLTexelFormat::RGBA8, false);
|
||||
}
|
||||
|
||||
|
@ -3855,10 +3875,11 @@ WebGLContext::TexSubImage2D_base(TexImageTarget texImageTarget, GLint level,
|
|||
GLsizei width, GLsizei height, GLsizei srcStrideOrZero,
|
||||
GLenum format, GLenum type,
|
||||
void* data, uint32_t byteLength,
|
||||
int jsArrayType,
|
||||
js::Scalar::Type jsArrayType,
|
||||
WebGLTexelFormat srcFormat, bool srcPremultiplied)
|
||||
{
|
||||
const WebGLTexImageFunc func = WebGLTexImageFunc::TexSubImage;
|
||||
const WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
|
||||
|
||||
if (type == LOCAL_GL_HALF_FLOAT_OES) {
|
||||
type = LOCAL_GL_HALF_FLOAT;
|
||||
|
@ -3876,16 +3897,16 @@ WebGLContext::TexSubImage2D_base(TexImageTarget texImageTarget, GLint level,
|
|||
const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
|
||||
const TexInternalFormat existingEffectiveInternalFormat = imageInfo.EffectiveInternalFormat();
|
||||
|
||||
if (!ValidateTexImage(2, texImageTarget, level,
|
||||
if (!ValidateTexImage(texImageTarget, level,
|
||||
existingEffectiveInternalFormat.get(),
|
||||
xoffset, yoffset, 0,
|
||||
width, height, 0,
|
||||
0, format, type, func))
|
||||
0, format, type, func, dims))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateTexInputData(type, jsArrayType, func))
|
||||
if (!ValidateTexInputData(type, jsArrayType, func, dims))
|
||||
return;
|
||||
|
||||
if (type != TypeFromInternalFormat(existingEffectiveInternalFormat)) {
|
||||
|
@ -3905,7 +3926,7 @@ WebGLContext::TexSubImage2D_base(TexImageTarget texImageTarget, GLint level,
|
|||
return; // ES 2.0 says it has no effect, we better return right now
|
||||
|
||||
CheckedUint32 checked_neededByteLength =
|
||||
GetImageSize(height, width, srcTexelSize, mPixelStoreUnpackAlignment);
|
||||
GetImageSize(height, width, 1, srcTexelSize, mPixelStoreUnpackAlignment);
|
||||
|
||||
CheckedUint32 checked_plainRowSize = CheckedUint32(width) * srcTexelSize;
|
||||
|
||||
|
@ -3945,7 +3966,12 @@ WebGLContext::TexSubImage2D_base(TexImageTarget texImageTarget, GLint level,
|
|||
|
||||
if (!noConversion) {
|
||||
size_t convertedDataSize = height * dstStride;
|
||||
convertedData = new uint8_t[convertedDataSize];
|
||||
convertedData = (uint8_t*)moz_malloc(convertedDataSize);
|
||||
if (!convertedData) {
|
||||
ErrorOutOfMemory("texImage2D: Ran out of memory when allocating"
|
||||
" a buffer for doing format conversion.");
|
||||
return;
|
||||
}
|
||||
if (!ConvertImage(width, height, srcStride, dstStride,
|
||||
static_cast<const uint8_t*>(data), convertedData,
|
||||
actualSrcFormat, srcPremultiplied,
|
||||
|
@ -3985,7 +4011,7 @@ WebGLContext::TexSubImage2D(GLenum rawTarget, GLint level,
|
|||
const ArrayBufferView& view = pixels.Value();
|
||||
view.ComputeLengthAndData();
|
||||
|
||||
if (!ValidateTexImageTarget(2, rawTarget, WebGLTexImageFunc::TexSubImage))
|
||||
if (!ValidateTexImageTarget(rawTarget, WebGLTexImageFunc::TexSubImage, WebGLTexDimensions::Tex2D))
|
||||
return;
|
||||
|
||||
return TexSubImage2D_base(rawTarget, level, xoffset, yoffset,
|
||||
|
@ -4016,7 +4042,7 @@ WebGLContext::TexSubImage2D(GLenum target, GLint level,
|
|||
pixels->Width(), pixels->Height(),
|
||||
4*pixels->Width(), format, type,
|
||||
arr.Data(), arr.Length(),
|
||||
-1,
|
||||
js::Scalar::TypeMax,
|
||||
WebGLTexelFormat::RGBA8, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -70,6 +70,29 @@ StringValue(JSContext* cx, const char* chars, ErrorResult& rv)
|
|||
return JS::StringValue(str);
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::GetStencilBits(GLint* out_stencilBits)
|
||||
{
|
||||
*out_stencilBits = 0;
|
||||
if (mBoundFramebuffer) {
|
||||
if (mBoundFramebuffer->HasDepthStencilConflict()) {
|
||||
// Error, we don't know which stencil buffer's bits to use
|
||||
ErrorInvalidFramebufferOperation("getParameter: framebuffer has two stencil buffers bound");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mBoundFramebuffer->StencilAttachment().IsDefined() ||
|
||||
mBoundFramebuffer->DepthStencilAttachment().IsDefined())
|
||||
{
|
||||
*out_stencilBits = 8;
|
||||
}
|
||||
} else if (mOptions.stencil) {
|
||||
*out_stencilBits = 8;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JS::Value
|
||||
WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
|
||||
{
|
||||
|
@ -241,9 +264,26 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
|
|||
return JS::NumberValue(uint32_t(i));
|
||||
}
|
||||
// int
|
||||
case LOCAL_GL_STENCIL_CLEAR_VALUE:
|
||||
case LOCAL_GL_STENCIL_REF:
|
||||
case LOCAL_GL_STENCIL_BACK_REF:
|
||||
case LOCAL_GL_STENCIL_BACK_REF: {
|
||||
GLint stencilBits = 0;
|
||||
if (!GetStencilBits(&stencilBits))
|
||||
return JS::NullValue();
|
||||
|
||||
// Assuming stencils have 8 bits
|
||||
const GLint stencilMask = (1 << stencilBits) - 1;
|
||||
|
||||
GLint refValue = 0;
|
||||
gl->fGetIntegerv(pname, &refValue);
|
||||
|
||||
return JS::Int32Value(refValue & stencilMask);
|
||||
}
|
||||
case LOCAL_GL_STENCIL_BITS: {
|
||||
GLint stencilBits = 0;
|
||||
GetStencilBits(&stencilBits);
|
||||
return JS::Int32Value(stencilBits);
|
||||
}
|
||||
case LOCAL_GL_STENCIL_CLEAR_VALUE:
|
||||
case LOCAL_GL_UNPACK_ALIGNMENT:
|
||||
case LOCAL_GL_PACK_ALIGNMENT:
|
||||
case LOCAL_GL_SUBPIXEL_BITS:
|
||||
|
@ -257,8 +297,7 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
|
|||
case LOCAL_GL_GREEN_BITS:
|
||||
case LOCAL_GL_BLUE_BITS:
|
||||
case LOCAL_GL_ALPHA_BITS:
|
||||
case LOCAL_GL_DEPTH_BITS:
|
||||
case LOCAL_GL_STENCIL_BITS: {
|
||||
case LOCAL_GL_DEPTH_BITS: {
|
||||
GLint i = 0;
|
||||
gl->fGetIntegerv(pname, &i);
|
||||
return JS::Int32Value(i);
|
||||
|
|
|
@ -60,7 +60,8 @@ TexImageTargetToTexTarget(TexImageTarget texImageTarget)
|
|||
{
|
||||
switch (texImageTarget.get()) {
|
||||
case LOCAL_GL_TEXTURE_2D:
|
||||
return LOCAL_GL_TEXTURE_2D;
|
||||
case LOCAL_GL_TEXTURE_3D:
|
||||
return texImageTarget.get();
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
|
||||
|
@ -69,7 +70,7 @@ TexImageTargetToTexTarget(TexImageTarget texImageTarget)
|
|||
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
|
||||
return LOCAL_GL_TEXTURE_CUBE_MAP;
|
||||
default:
|
||||
MOZ_ASSERT(false, "Bad texture conversion");
|
||||
MOZ_ASSERT(false, "Bad texture target");
|
||||
// Should be caught by the constructor for TexTarget
|
||||
return LOCAL_GL_NONE;
|
||||
}
|
||||
|
@ -448,6 +449,7 @@ WebGLContext::ShouldGenerateWarnings() const
|
|||
CheckedUint32
|
||||
WebGLContext::GetImageSize(GLsizei height,
|
||||
GLsizei width,
|
||||
GLsizei depth,
|
||||
uint32_t pixelSize,
|
||||
uint32_t packOrUnpackAlignment)
|
||||
{
|
||||
|
@ -457,10 +459,12 @@ WebGLContext::GetImageSize(GLsizei height,
|
|||
CheckedUint32 checked_alignedRowSize = RoundedToNextMultipleOf(checked_plainRowSize, packOrUnpackAlignment);
|
||||
|
||||
// if height is 0, we don't need any memory to store this; without this check, we'll get an overflow
|
||||
CheckedUint32 checked_neededByteLength
|
||||
CheckedUint32 checked_2dImageSize
|
||||
= height <= 0 ? 0 : (height-1) * checked_alignedRowSize + checked_plainRowSize;
|
||||
|
||||
return checked_neededByteLength;
|
||||
// FIXME - we should honor UNPACK_IMAGE_HEIGHT
|
||||
CheckedUint32 checked_imageSize = checked_2dImageSize * depth;
|
||||
return checked_imageSize;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -705,6 +709,22 @@ AssertUintParamCorrect(gl::GLContext* gl, GLenum pname, GLuint shadow)
|
|||
MOZ_ASSERT(false, "Bad cached value.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AssertMaskedUintParamCorrect(gl::GLContext* gl, GLenum pname, GLuint mask, GLuint shadow)
|
||||
{
|
||||
GLuint val = 0;
|
||||
gl->GetUIntegerv(pname, &val);
|
||||
|
||||
const GLuint valMasked = val & mask;
|
||||
const GLuint shadowMasked = shadow & mask;
|
||||
|
||||
if (valMasked != shadowMasked) {
|
||||
printf_stderr("Failed 0x%04x shadow: Cached 0x%x/%u, should be 0x%x/%u.\n",
|
||||
pname, shadowMasked, shadowMasked, valMasked, valMasked);
|
||||
MOZ_ASSERT(false, "Bad cached value.");
|
||||
}
|
||||
}
|
||||
#else
|
||||
void
|
||||
AssertUintParamCorrect(gl::GLContext*, GLenum, GLuint)
|
||||
|
@ -802,8 +822,12 @@ WebGLContext::AssertCachedState()
|
|||
|
||||
AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_CLEAR_VALUE, mStencilClearValue);
|
||||
|
||||
AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_REF, mStencilRefFront);
|
||||
AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, mStencilRefBack);
|
||||
GLint stencilBits = 0;
|
||||
gl->fGetIntegerv(LOCAL_GL_STENCIL_BITS, &stencilBits);
|
||||
const GLuint stencilRefMask = (1 << stencilBits) - 1;
|
||||
|
||||
AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_REF, stencilRefMask, mStencilRefFront);
|
||||
AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, stencilRefMask, mStencilRefBack);
|
||||
|
||||
AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_VALUE_MASK, mStencilValueMaskFront);
|
||||
AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_VALUE_MASK, mStencilValueMaskBack);
|
||||
|
@ -826,4 +850,32 @@ WebGLContext::AssertCachedState()
|
|||
#endif
|
||||
}
|
||||
|
||||
const char*
|
||||
InfoFrom(WebGLTexImageFunc func, WebGLTexDimensions dims)
|
||||
{
|
||||
switch (dims) {
|
||||
case WebGLTexDimensions::Tex2D:
|
||||
switch (func) {
|
||||
case WebGLTexImageFunc::TexImage: return "texImage2D";
|
||||
case WebGLTexImageFunc::TexSubImage: return "texSubImage2D";
|
||||
case WebGLTexImageFunc::CopyTexImage: return "copyTexImage2D";
|
||||
case WebGLTexImageFunc::CopyTexSubImage: return "copyTexSubImage2D";
|
||||
case WebGLTexImageFunc::CompTexImage: return "compressedTexImage2D";
|
||||
case WebGLTexImageFunc::CompTexSubImage: return "compressedTexSubImage2D";
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
case WebGLTexDimensions::Tex3D:
|
||||
switch (func) {
|
||||
case WebGLTexImageFunc::TexSubImage: return "texSubImage3D";
|
||||
case WebGLTexImageFunc::CopyTexSubImage: return "copyTexSubImage3D";
|
||||
case WebGLTexImageFunc::CompTexSubImage: return "compressedTexSubImage3D";
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -106,6 +106,13 @@ WebGLContext::WebGLObjectAsJSObject(JSContext *cx, const WebGLObjectType *object
|
|||
return &v.toObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the displayable name for the texture function that is the
|
||||
* source for validation.
|
||||
*/
|
||||
const char*
|
||||
InfoFrom(WebGLTexImageFunc func, WebGLTexDimensions dims);
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // WEBGLCONTEXTUTILS_H_
|
||||
|
|
|
@ -61,27 +61,6 @@ BlockSizeFor(GLenum format, GLint* blockWidth, GLint* blockHeight)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the displayable name for the texture function that is the
|
||||
* source for validation.
|
||||
*/
|
||||
static const char*
|
||||
InfoFrom(WebGLTexImageFunc func)
|
||||
{
|
||||
// TODO: Account for dimensions (WebGL 2)
|
||||
switch (func) {
|
||||
case WebGLTexImageFunc::TexImage: return "texImage2D";
|
||||
case WebGLTexImageFunc::TexSubImage: return "texSubImage2D";
|
||||
case WebGLTexImageFunc::CopyTexImage: return "copyTexImage2D";
|
||||
case WebGLTexImageFunc::CopyTexSubImage: return "copyTexSubImage2D";
|
||||
case WebGLTexImageFunc::CompTexImage: return "compressedTexImage2D";
|
||||
case WebGLTexImageFunc::CompTexSubImage: return "compressedTexSubImage2D";
|
||||
default:
|
||||
MOZ_ASSERT(false, "Missing case for WebGLTexImageSource");
|
||||
return "(error)";
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
IsCompressedFunc(WebGLTexImageFunc func)
|
||||
{
|
||||
|
@ -94,13 +73,13 @@ IsCompressedFunc(WebGLTexImageFunc func)
|
|||
* name for \a glenum.
|
||||
*/
|
||||
static void
|
||||
ErrorInvalidEnumWithName(WebGLContext* ctx, const char* msg, GLenum glenum, WebGLTexImageFunc func)
|
||||
ErrorInvalidEnumWithName(WebGLContext* ctx, const char* msg, GLenum glenum, WebGLTexImageFunc func, WebGLTexDimensions dims)
|
||||
{
|
||||
const char* name = WebGLContext::EnumName(glenum);
|
||||
if (name)
|
||||
ctx->ErrorInvalidEnum("%s: %s %s", InfoFrom(func), msg, name);
|
||||
ctx->ErrorInvalidEnum("%s: %s %s", InfoFrom(func, dims), msg, name);
|
||||
else
|
||||
ctx->ErrorInvalidEnum("%s: %s 0x%04X", InfoFrom(func), msg, glenum);
|
||||
ctx->ErrorInvalidEnum("%s: %s 0x%04X", InfoFrom(func, dims), msg, glenum);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -386,7 +365,7 @@ WebGLContext::ValidateFramebufferAttachment(GLenum attachment, const char* funcN
|
|||
* taking into account enabled WebGL extensions.
|
||||
*/
|
||||
bool
|
||||
WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func)
|
||||
WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func, WebGLTexDimensions dims)
|
||||
{
|
||||
/* Core WebGL texture formats */
|
||||
if (format == LOCAL_GL_ALPHA ||
|
||||
|
@ -409,7 +388,7 @@ WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func)
|
|||
bool valid = IsWebGL2();
|
||||
if (!valid) {
|
||||
ErrorInvalidEnum("%s: invalid format %s: requires WebGL version 2.0 or newer",
|
||||
InfoFrom(func), EnumName(format));
|
||||
InfoFrom(func, dims), EnumName(format));
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
@ -420,7 +399,7 @@ WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func)
|
|||
{
|
||||
if (!IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture)) {
|
||||
ErrorInvalidEnum("%s: invalid format %s: need WEBGL_depth_texture enabled",
|
||||
InfoFrom(func), EnumName(format));
|
||||
InfoFrom(func, dims), EnumName(format));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -431,7 +410,7 @@ WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func)
|
|||
func == WebGLTexImageFunc::CopyTexImage ||
|
||||
func == WebGLTexImageFunc::CopyTexSubImage)
|
||||
{
|
||||
ErrorInvalidOperation("%s: format %s is not supported", InfoFrom(func), EnumName(format));
|
||||
ErrorInvalidOperation("%s: format %s is not supported", InfoFrom(func, dims), EnumName(format));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -443,7 +422,7 @@ WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func)
|
|||
/* Only core formats are valid for CopyTex(Sub)?Image */
|
||||
// TODO: Revisit this once color_buffer_(half_)?float lands
|
||||
if (IsCopyFunc(func)) {
|
||||
ErrorInvalidEnumWithName(this, "invalid format", format, func);
|
||||
ErrorInvalidEnumWithName(this, "invalid format", format, func, dims);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -454,11 +433,11 @@ WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func)
|
|||
bool validFormat = IsExtensionEnabled(WebGLExtensionID::EXT_sRGB);
|
||||
if (!validFormat)
|
||||
ErrorInvalidEnum("%s: invalid format %s: need EXT_sRGB enabled",
|
||||
InfoFrom(func), WebGLContext::EnumName(format));
|
||||
InfoFrom(func, dims), WebGLContext::EnumName(format));
|
||||
return validFormat;
|
||||
}
|
||||
|
||||
ErrorInvalidEnumWithName(this, "invalid format", format, func);
|
||||
ErrorInvalidEnumWithName(this, "invalid format", format, func, dims);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -467,19 +446,27 @@ WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func)
|
|||
* Check if the given texture target is valid for TexImage.
|
||||
*/
|
||||
bool
|
||||
WebGLContext::ValidateTexImageTarget(GLuint dims,
|
||||
GLenum target,
|
||||
WebGLTexImageFunc func)
|
||||
WebGLContext::ValidateTexImageTarget(GLenum target,
|
||||
WebGLTexImageFunc func, WebGLTexDimensions dims)
|
||||
{
|
||||
switch (dims) {
|
||||
case 2:
|
||||
case WebGLTexDimensions::Tex2D:
|
||||
if (target == LOCAL_GL_TEXTURE_2D ||
|
||||
IsTexImageCubemapTarget(target))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ErrorInvalidEnumWithName(this, "invalid target", target, func);
|
||||
ErrorInvalidEnumWithName(this, "invalid target", target, func, dims);
|
||||
return false;
|
||||
|
||||
case WebGLTexDimensions::Tex3D:
|
||||
if (target == LOCAL_GL_TEXTURE_3D)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ErrorInvalidEnumWithName(this, "invalid target", target, func, dims);
|
||||
return false;
|
||||
|
||||
default:
|
||||
|
@ -495,7 +482,8 @@ WebGLContext::ValidateTexImageTarget(GLuint dims,
|
|||
*/
|
||||
bool
|
||||
WebGLContext::ValidateTexImageType(GLenum type,
|
||||
WebGLTexImageFunc func)
|
||||
WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims)
|
||||
{
|
||||
/* Core WebGL texture types */
|
||||
if (type == LOCAL_GL_UNSIGNED_BYTE ||
|
||||
|
@ -518,7 +506,7 @@ WebGLContext::ValidateTexImageType(GLenum type,
|
|||
bool validType = IsWebGL2();
|
||||
if (!validType) {
|
||||
ErrorInvalidEnum("%s: invalid type %s: requires WebGL version 2.0 or newer",
|
||||
InfoFrom(func), WebGLContext::EnumName(type));
|
||||
InfoFrom(func, dims), WebGLContext::EnumName(type));
|
||||
}
|
||||
return validType;
|
||||
}
|
||||
|
@ -528,7 +516,7 @@ WebGLContext::ValidateTexImageType(GLenum type,
|
|||
bool validType = IsExtensionEnabled(WebGLExtensionID::OES_texture_float);
|
||||
if (!validType)
|
||||
ErrorInvalidEnum("%s: invalid type %s: need OES_texture_float enabled",
|
||||
InfoFrom(func), WebGLContext::EnumName(type));
|
||||
InfoFrom(func, dims), WebGLContext::EnumName(type));
|
||||
return validType;
|
||||
}
|
||||
|
||||
|
@ -537,7 +525,7 @@ WebGLContext::ValidateTexImageType(GLenum type,
|
|||
bool validType = IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float);
|
||||
if (!validType)
|
||||
ErrorInvalidEnum("%s: invalid type %s: need OES_texture_half_float enabled",
|
||||
InfoFrom(func), WebGLContext::EnumName(type));
|
||||
InfoFrom(func, dims), WebGLContext::EnumName(type));
|
||||
return validType;
|
||||
}
|
||||
|
||||
|
@ -549,11 +537,11 @@ WebGLContext::ValidateTexImageType(GLenum type,
|
|||
bool validType = IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture);
|
||||
if (!validType)
|
||||
ErrorInvalidEnum("%s: invalid type %s: need WEBGL_depth_texture enabled",
|
||||
InfoFrom(func), WebGLContext::EnumName(type));
|
||||
InfoFrom(func, dims), WebGLContext::EnumName(type));
|
||||
return validType;
|
||||
}
|
||||
|
||||
ErrorInvalidEnumWithName(this, "invalid type", type, func);
|
||||
ErrorInvalidEnumWithName(this, "invalid type", type, func, dims);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -568,19 +556,20 @@ WebGLContext::ValidateCompTexImageSize(GLint level,
|
|||
GLint xoffset, GLint yoffset,
|
||||
GLsizei width, GLsizei height,
|
||||
GLsizei levelWidth, GLsizei levelHeight,
|
||||
WebGLTexImageFunc func)
|
||||
WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims)
|
||||
{
|
||||
// Negative parameters must already have been handled above
|
||||
MOZ_ASSERT(xoffset >= 0 && yoffset >= 0 &&
|
||||
width >= 0 && height >= 0);
|
||||
|
||||
if (xoffset + width > (GLint) levelWidth) {
|
||||
ErrorInvalidValue("%s: xoffset + width must be <= levelWidth", InfoFrom(func));
|
||||
ErrorInvalidValue("%s: xoffset + width must be <= levelWidth", InfoFrom(func, dims));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (yoffset + height > (GLint) levelHeight) {
|
||||
ErrorInvalidValue("%s: yoffset + height must be <= levelHeight", InfoFrom(func));
|
||||
ErrorInvalidValue("%s: yoffset + height must be <= levelHeight", InfoFrom(func, dims));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -596,13 +585,13 @@ WebGLContext::ValidateCompTexImageSize(GLint level,
|
|||
/* offsets must be multiple of block size */
|
||||
if (xoffset % blockWidth != 0) {
|
||||
ErrorInvalidOperation("%s: xoffset must be multiple of %d",
|
||||
InfoFrom(func), blockWidth);
|
||||
InfoFrom(func, dims), blockWidth);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (yoffset % blockHeight != 0) {
|
||||
ErrorInvalidOperation("%s: yoffset must be multiple of %d",
|
||||
InfoFrom(func), blockHeight);
|
||||
InfoFrom(func, dims), blockHeight);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -618,13 +607,13 @@ WebGLContext::ValidateCompTexImageSize(GLint level,
|
|||
if (level == 0) {
|
||||
if (width % blockWidth != 0) {
|
||||
ErrorInvalidOperation("%s: width of level 0 must be multple of %d",
|
||||
InfoFrom(func), blockWidth);
|
||||
InfoFrom(func, dims), blockWidth);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (height % blockHeight != 0) {
|
||||
ErrorInvalidOperation("%s: height of level 0 must be multipel of %d",
|
||||
InfoFrom(func), blockHeight);
|
||||
InfoFrom(func, dims), blockHeight);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -632,14 +621,14 @@ WebGLContext::ValidateCompTexImageSize(GLint level,
|
|||
if (width % blockWidth != 0 && width > 2) {
|
||||
ErrorInvalidOperation("%s: width of level %d must be multiple"
|
||||
" of %d or 0, 1, 2",
|
||||
InfoFrom(func), level, blockWidth);
|
||||
InfoFrom(func, dims), level, blockWidth);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (height % blockHeight != 0 && height > 2) {
|
||||
ErrorInvalidOperation("%s: height of level %d must be multiple"
|
||||
" of %d or 0, 1, 2",
|
||||
InfoFrom(func), level, blockHeight);
|
||||
InfoFrom(func, dims), level, blockHeight);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -647,13 +636,13 @@ WebGLContext::ValidateCompTexImageSize(GLint level,
|
|||
if (IsSubFunc(func)) {
|
||||
if ((xoffset % blockWidth) != 0) {
|
||||
ErrorInvalidOperation("%s: xoffset must be multiple of %d",
|
||||
InfoFrom(func), blockWidth);
|
||||
InfoFrom(func, dims), blockWidth);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (yoffset % blockHeight != 0) {
|
||||
ErrorInvalidOperation("%s: yoffset must be multiple of %d",
|
||||
InfoFrom(func), blockHeight);
|
||||
InfoFrom(func, dims), blockHeight);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -668,7 +657,7 @@ WebGLContext::ValidateCompTexImageSize(GLint level,
|
|||
!is_pot_assuming_nonnegative(height))
|
||||
{
|
||||
ErrorInvalidValue("%s: width and height must be powers of two",
|
||||
InfoFrom(func));
|
||||
InfoFrom(func, dims));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -683,7 +672,9 @@ WebGLContext::ValidateCompTexImageSize(GLint level,
|
|||
bool
|
||||
WebGLContext::ValidateCompTexImageDataSize(GLint level, GLenum format,
|
||||
GLsizei width, GLsizei height,
|
||||
uint32_t byteLength, WebGLTexImageFunc func)
|
||||
uint32_t byteLength,
|
||||
WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims)
|
||||
{
|
||||
// negative width and height must already have been handled above
|
||||
MOZ_ASSERT(width >= 0 && height >= 0);
|
||||
|
@ -722,7 +713,7 @@ WebGLContext::ValidateCompTexImageDataSize(GLint level, GLenum format,
|
|||
}
|
||||
|
||||
if (!required_byteLength.isValid() || required_byteLength.value() != byteLength) {
|
||||
ErrorInvalidValue("%s: data size does not match dimensions", InfoFrom(func));
|
||||
ErrorInvalidValue("%s: data size does not match dimensions", InfoFrom(func, dims));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -738,7 +729,7 @@ WebGLContext::ValidateCompTexImageDataSize(GLint level, GLenum format,
|
|||
bool
|
||||
WebGLContext::ValidateTexImageSize(TexImageTarget texImageTarget, GLint level,
|
||||
GLint width, GLint height, GLint depth,
|
||||
WebGLTexImageFunc func)
|
||||
WebGLTexImageFunc func, WebGLTexDimensions dims)
|
||||
{
|
||||
MOZ_ASSERT(level >= 0, "level should already be validated");
|
||||
|
||||
|
@ -766,7 +757,7 @@ WebGLContext::ValidateTexImageSize(TexImageTarget texImageTarget, GLint level,
|
|||
* INVALID_VALUE is generated if the width and height
|
||||
* parameters are not equal."
|
||||
*/
|
||||
ErrorInvalidValue("%s: for cube map, width must equal height", InfoFrom(func));
|
||||
ErrorInvalidValue("%s: for cube map, width must equal height", InfoFrom(func, dims));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -778,12 +769,12 @@ WebGLContext::ValidateTexImageSize(TexImageTarget texImageTarget, GLint level,
|
|||
* INVALID_VALUE is generated."
|
||||
*/
|
||||
if (width < 0) {
|
||||
ErrorInvalidValue("%s: width must be >= 0", InfoFrom(func));
|
||||
ErrorInvalidValue("%s: width must be >= 0", InfoFrom(func, dims));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (height < 0) {
|
||||
ErrorInvalidValue("%s: height must be >= 0", InfoFrom(func));
|
||||
ErrorInvalidValue("%s: height must be >= 0", InfoFrom(func, dims));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -799,13 +790,13 @@ WebGLContext::ValidateTexImageSize(TexImageTarget texImageTarget, GLint level,
|
|||
*/
|
||||
if (width > (int) maxTexImageSize) {
|
||||
ErrorInvalidValue("%s: the maximum width for level %d is %u",
|
||||
InfoFrom(func), level, maxTexImageSize);
|
||||
InfoFrom(func, dims), level, maxTexImageSize);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (height > (int) maxTexImageSize) {
|
||||
ErrorInvalidValue("%s: tex maximum height for level %d is %u",
|
||||
InfoFrom(func), level, maxTexImageSize);
|
||||
InfoFrom(func, dims), level, maxTexImageSize);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -817,13 +808,13 @@ WebGLContext::ValidateTexImageSize(TexImageTarget texImageTarget, GLint level,
|
|||
if (level > 0) {
|
||||
if (!is_pot_assuming_nonnegative(width)) {
|
||||
ErrorInvalidValue("%s: level >= 0, width of %d must be a power of two.",
|
||||
InfoFrom(func), width);
|
||||
InfoFrom(func, dims), width);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_pot_assuming_nonnegative(height)) {
|
||||
ErrorInvalidValue("%s: level >= 0, height of %d must be a power of two.",
|
||||
InfoFrom(func), height);
|
||||
InfoFrom(func, dims), height);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -832,13 +823,13 @@ WebGLContext::ValidateTexImageSize(TexImageTarget texImageTarget, GLint level,
|
|||
// TODO: WebGL 2
|
||||
if (texImageTarget == LOCAL_GL_TEXTURE_3D) {
|
||||
if (depth < 0) {
|
||||
ErrorInvalidValue("%s: depth must be >= 0", InfoFrom(func));
|
||||
ErrorInvalidValue("%s: depth must be >= 0", InfoFrom(func, dims));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_pot_assuming_nonnegative(depth)) {
|
||||
if (depth > 0 && !is_pot_assuming_nonnegative(depth)) {
|
||||
ErrorInvalidValue("%s: level >= 0, depth of %d must be a power of two.",
|
||||
InfoFrom(func), depth);
|
||||
InfoFrom(func, dims), depth);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -854,7 +845,7 @@ bool
|
|||
WebGLContext::ValidateTexSubImageSize(GLint xoffset, GLint yoffset, GLint /*zoffset*/,
|
||||
GLsizei width, GLsizei height, GLsizei /*depth*/,
|
||||
GLsizei baseWidth, GLsizei baseHeight, GLsizei /*baseDepth*/,
|
||||
WebGLTexImageFunc func)
|
||||
WebGLTexImageFunc func, WebGLTexDimensions dims)
|
||||
{
|
||||
/* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
|
||||
* "Taking wt and ht to be the specified width and height of the
|
||||
|
@ -868,17 +859,17 @@ WebGLContext::ValidateTexSubImageSize(GLint xoffset, GLint yoffset, GLint /*zoff
|
|||
*/
|
||||
|
||||
if (xoffset < 0) {
|
||||
ErrorInvalidValue("%s: xoffset must be >= 0", InfoFrom(func));
|
||||
ErrorInvalidValue("%s: xoffset must be >= 0", InfoFrom(func, dims));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (yoffset < 0) {
|
||||
ErrorInvalidValue("%s: yoffset must be >= 0", InfoFrom(func));
|
||||
ErrorInvalidValue("%s: yoffset must be >= 0", InfoFrom(func, dims));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CanvasUtils::CheckSaneSubrectSize(xoffset, yoffset, width, height, baseWidth, baseHeight)) {
|
||||
ErrorInvalidValue("%s: subtexture rectangle out-of-bounds", InfoFrom(func));
|
||||
ErrorInvalidValue("%s: subtexture rectangle out-of-bounds", InfoFrom(func, dims));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -891,15 +882,17 @@ WebGLContext::ValidateTexSubImageSize(GLint xoffset, GLint yoffset, GLint /*zoff
|
|||
*/
|
||||
bool
|
||||
WebGLContext::ValidateTexImageFormatAndType(GLenum format,
|
||||
GLenum type, WebGLTexImageFunc func)
|
||||
GLenum type,
|
||||
WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims)
|
||||
{
|
||||
if (IsCompressedFunc(func) || IsCopyFunc(func))
|
||||
{
|
||||
MOZ_ASSERT(type == LOCAL_GL_NONE && format == LOCAL_GL_NONE);
|
||||
return true;
|
||||
}
|
||||
if (!ValidateTexImageFormat(format, func) ||
|
||||
!ValidateTexImageType(type, func))
|
||||
if (!ValidateTexImageFormat(format, func, dims) ||
|
||||
!ValidateTexImageType(type, func, dims))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -913,18 +906,19 @@ WebGLContext::ValidateTexImageFormatAndType(GLenum format,
|
|||
|
||||
if (!validCombo)
|
||||
ErrorInvalidOperation("%s: invalid combination of format %s and type %s",
|
||||
InfoFrom(func), WebGLContext::EnumName(format), WebGLContext::EnumName(type));
|
||||
InfoFrom(func, dims), WebGLContext::EnumName(format), WebGLContext::EnumName(type));
|
||||
|
||||
return validCombo;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::ValidateCompTexImageInternalFormat(GLenum format,
|
||||
WebGLTexImageFunc func)
|
||||
WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims)
|
||||
{
|
||||
if (!IsCompressedTextureFormat(format)) {
|
||||
ErrorInvalidEnum("%s: invalid compressed texture format: %s",
|
||||
InfoFrom(func), WebGLContext::EnumName(format));
|
||||
InfoFrom(func, dims), WebGLContext::EnumName(format));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -936,7 +930,7 @@ WebGLContext::ValidateCompTexImageInternalFormat(GLenum format,
|
|||
bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_atc);
|
||||
if (!validFormat)
|
||||
ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_atc enabled",
|
||||
InfoFrom(func), WebGLContext::EnumName(format));
|
||||
InfoFrom(func, dims), WebGLContext::EnumName(format));
|
||||
return validFormat;
|
||||
}
|
||||
|
||||
|
@ -945,7 +939,7 @@ WebGLContext::ValidateCompTexImageInternalFormat(GLenum format,
|
|||
bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_etc1);
|
||||
if (!validFormat)
|
||||
ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_etc1 enabled",
|
||||
InfoFrom(func), WebGLContext::EnumName(format));
|
||||
InfoFrom(func, dims), WebGLContext::EnumName(format));
|
||||
return validFormat;
|
||||
}
|
||||
|
||||
|
@ -958,7 +952,7 @@ WebGLContext::ValidateCompTexImageInternalFormat(GLenum format,
|
|||
bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_pvrtc);
|
||||
if (!validFormat)
|
||||
ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_pvrtc enabled",
|
||||
InfoFrom(func), WebGLContext::EnumName(format));
|
||||
InfoFrom(func, dims), WebGLContext::EnumName(format));
|
||||
return validFormat;
|
||||
}
|
||||
|
||||
|
@ -971,7 +965,7 @@ WebGLContext::ValidateCompTexImageInternalFormat(GLenum format,
|
|||
bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_s3tc);
|
||||
if (!validFormat)
|
||||
ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_s3tc enabled",
|
||||
InfoFrom(func), WebGLContext::EnumName(format));
|
||||
InfoFrom(func, dims), WebGLContext::EnumName(format));
|
||||
return validFormat;
|
||||
}
|
||||
|
||||
|
@ -980,7 +974,8 @@ WebGLContext::ValidateCompTexImageInternalFormat(GLenum format,
|
|||
|
||||
bool
|
||||
WebGLContext::ValidateCopyTexImageInternalFormat(GLenum format,
|
||||
WebGLTexImageFunc func)
|
||||
WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims)
|
||||
{
|
||||
bool valid = format == LOCAL_GL_RGBA ||
|
||||
format == LOCAL_GL_RGB ||
|
||||
|
@ -994,7 +989,7 @@ WebGLContext::ValidateCopyTexImageInternalFormat(GLenum format,
|
|||
// in CopyTexSubImage, the internalformat is part of existing state,
|
||||
// so this is an INVALID_OPERATION error.
|
||||
GenerateWarning("%s: invalid texture internal format: %s",
|
||||
InfoFrom(func), WebGLContext::EnumName(format));
|
||||
InfoFrom(func, dims), WebGLContext::EnumName(format));
|
||||
SynthesizeGLError(func == WebGLTexImageFunc::CopyTexImage
|
||||
? LOCAL_GL_INVALID_ENUM
|
||||
: LOCAL_GL_INVALID_OPERATION);
|
||||
|
@ -1009,19 +1004,28 @@ WebGLContext::ValidateCopyTexImageInternalFormat(GLenum format,
|
|||
* It is assumed that type has previously been validated.
|
||||
*/
|
||||
bool
|
||||
WebGLContext::ValidateTexInputData(GLenum type, int jsArrayType, WebGLTexImageFunc func)
|
||||
WebGLContext::ValidateTexInputData(GLenum type,
|
||||
js::Scalar::Type jsArrayType,
|
||||
WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims)
|
||||
{
|
||||
bool validInput = false;
|
||||
const char invalidTypedArray[] = "%s: invalid typed array type for given texture data type";
|
||||
|
||||
// We're using js::Scalar::TypeMax as dummy value when the tex source wasn't a
|
||||
// typed array.
|
||||
if (jsArrayType == js::Scalar::TypeMax) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// First, we check for packed types
|
||||
switch (type) {
|
||||
case LOCAL_GL_UNSIGNED_BYTE:
|
||||
validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Uint8);
|
||||
validInput = jsArrayType == js::Scalar::Uint8;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_BYTE:
|
||||
validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Int8);
|
||||
validInput = jsArrayType == js::Scalar::Int8;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_HALF_FLOAT:
|
||||
|
@ -1029,11 +1033,11 @@ WebGLContext::ValidateTexInputData(GLenum type, int jsArrayType, WebGLTexImageFu
|
|||
case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
|
||||
validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Uint16);
|
||||
validInput = jsArrayType == js::Scalar::Uint16;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_SHORT:
|
||||
validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Int16);
|
||||
validInput = jsArrayType == js::Scalar::Int16;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_UNSIGNED_INT:
|
||||
|
@ -1041,15 +1045,15 @@ WebGLContext::ValidateTexInputData(GLenum type, int jsArrayType, WebGLTexImageFu
|
|||
case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
|
||||
case LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV:
|
||||
case LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV:
|
||||
validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Uint32);
|
||||
validInput = jsArrayType == js::Scalar::Uint32;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_INT:
|
||||
validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Int32);
|
||||
validInput = jsArrayType == js::Scalar::Int32;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_FLOAT:
|
||||
validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Float32);
|
||||
validInput = jsArrayType == js::Scalar::Float32;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1057,7 +1061,7 @@ WebGLContext::ValidateTexInputData(GLenum type, int jsArrayType, WebGLTexImageFu
|
|||
}
|
||||
|
||||
if (!validInput)
|
||||
ErrorInvalidOperation(invalidTypedArray, InfoFrom(func));
|
||||
ErrorInvalidOperation(invalidTypedArray, InfoFrom(func, dims));
|
||||
|
||||
return validInput;
|
||||
}
|
||||
|
@ -1070,7 +1074,8 @@ WebGLContext::ValidateTexInputData(GLenum type, int jsArrayType, WebGLTexImageFu
|
|||
*/
|
||||
bool
|
||||
WebGLContext::ValidateCopyTexImage(GLenum format,
|
||||
WebGLTexImageFunc func)
|
||||
WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims)
|
||||
{
|
||||
MOZ_ASSERT(IsCopyFunc(func));
|
||||
|
||||
|
@ -1079,14 +1084,14 @@ WebGLContext::ValidateCopyTexImage(GLenum format,
|
|||
|
||||
if (mBoundFramebuffer) {
|
||||
if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
|
||||
ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", InfoFrom(func));
|
||||
ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", InfoFrom(func, dims));
|
||||
return false;
|
||||
}
|
||||
|
||||
GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
|
||||
if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) {
|
||||
ErrorInvalidOperation("%s: Read source attachment doesn't have the"
|
||||
" correct color/depth/stencil type.", InfoFrom(func));
|
||||
" correct color/depth/stencil type.", InfoFrom(func, dims));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1101,7 +1106,7 @@ WebGLContext::ValidateCopyTexImage(GLenum format,
|
|||
const GLComponents fboComps = GLComponents(fboFormat);
|
||||
if (!formatComps.IsSubsetOf(fboComps)) {
|
||||
ErrorInvalidOperation("%s: format %s is not a subset of the current framebuffer format, which is %s.",
|
||||
InfoFrom(func), EnumName(format), EnumName(fboFormat));
|
||||
InfoFrom(func, dims), EnumName(format), EnumName(fboFormat));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1114,7 +1119,7 @@ WebGLContext::ValidateCopyTexImage(GLenum format,
|
|||
*/
|
||||
// TODO: Texture dims is here for future expansion in WebGL 2.0
|
||||
bool
|
||||
WebGLContext::ValidateTexImage(GLuint dims, TexImageTarget texImageTarget,
|
||||
WebGLContext::ValidateTexImage(TexImageTarget texImageTarget,
|
||||
GLint level,
|
||||
GLenum internalFormat,
|
||||
GLint xoffset, GLint yoffset, GLint zoffset,
|
||||
|
@ -1122,9 +1127,10 @@ WebGLContext::ValidateTexImage(GLuint dims, TexImageTarget texImageTarget,
|
|||
GLint border,
|
||||
GLenum format,
|
||||
GLenum type,
|
||||
WebGLTexImageFunc func)
|
||||
WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims)
|
||||
{
|
||||
const char* info = InfoFrom(func);
|
||||
const char* info = InfoFrom(func, dims);
|
||||
|
||||
/* Check level */
|
||||
if (level < 0) {
|
||||
|
@ -1139,7 +1145,7 @@ WebGLContext::ValidateTexImage(GLuint dims, TexImageTarget texImageTarget,
|
|||
}
|
||||
|
||||
/* Check incoming image format and type */
|
||||
if (!ValidateTexImageFormatAndType(format, type, func))
|
||||
if (!ValidateTexImageFormatAndType(format, type, func, dims))
|
||||
return false;
|
||||
|
||||
if (!TexInternalFormat::IsValueLegal(internalFormat)) {
|
||||
|
@ -1150,11 +1156,11 @@ WebGLContext::ValidateTexImage(GLuint dims, TexImageTarget texImageTarget,
|
|||
UnsizedInternalFormatFromInternalFormat(internalFormat);
|
||||
|
||||
if (IsCompressedFunc(func)) {
|
||||
if (!ValidateCompTexImageInternalFormat(internalFormat, func)) {
|
||||
if (!ValidateCompTexImageInternalFormat(internalFormat, func, dims)) {
|
||||
return false;
|
||||
}
|
||||
} else if (IsCopyFunc(func)) {
|
||||
if (!ValidateCopyTexImageInternalFormat(unsizedInternalFormat.get(), func)) {
|
||||
if (!ValidateCopyTexImageInternalFormat(unsizedInternalFormat.get(), func, dims)) {
|
||||
return false;
|
||||
}
|
||||
} else if (format != unsizedInternalFormat) {
|
||||
|
@ -1189,7 +1195,7 @@ WebGLContext::ValidateTexImage(GLuint dims, TexImageTarget texImageTarget,
|
|||
}
|
||||
|
||||
/* Check texture image size */
|
||||
if (!ValidateTexImageSize(texImageTarget, level, width, height, 0, func))
|
||||
if (!ValidateTexImageSize(texImageTarget, level, width, height, 0, func, dims))
|
||||
return false;
|
||||
|
||||
/* 5.14.8 Texture objects - WebGL Spec.
|
||||
|
@ -1216,7 +1222,7 @@ WebGLContext::ValidateTexImage(GLuint dims, TexImageTarget texImageTarget,
|
|||
if (!ValidateTexSubImageSize(xoffset, yoffset, zoffset,
|
||||
width, height, depth,
|
||||
imageInfo.Width(), imageInfo.Height(), 0,
|
||||
func))
|
||||
func, dims))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1502,6 +1508,7 @@ WebGLContext::InitAndValidateGL()
|
|||
|
||||
mBound2DTextures.Clear();
|
||||
mBoundCubeMapTextures.Clear();
|
||||
mBound3DTextures.Clear();
|
||||
|
||||
mBoundArrayBuffer = nullptr;
|
||||
mBoundTransformFeedbackBuffer = nullptr;
|
||||
|
@ -1542,6 +1549,7 @@ WebGLContext::InitAndValidateGL()
|
|||
|
||||
mBound2DTextures.SetLength(mGLMaxTextureUnits);
|
||||
mBoundCubeMapTextures.SetLength(mGLMaxTextureUnits);
|
||||
mBound3DTextures.SetLength(mGLMaxTextureUnits);
|
||||
|
||||
if (MinCapabilityMode()) {
|
||||
mGLMaxTextureSize = MINVALUE_GL_MAX_TEXTURE_SIZE;
|
||||
|
|
|
@ -48,25 +48,32 @@ WebGLTexture::Delete() {
|
|||
LinkedListElement<WebGLTexture>::removeFrom(mContext->mTextures);
|
||||
}
|
||||
|
||||
int64_t
|
||||
size_t
|
||||
WebGLTexture::ImageInfo::MemoryUsage() const {
|
||||
if (mImageDataStatus == WebGLImageDataStatus::NoImageData)
|
||||
return 0;
|
||||
int64_t bitsPerTexel = GetBitsPerTexel(mEffectiveInternalFormat);
|
||||
return int64_t(mWidth) * int64_t(mHeight) * bitsPerTexel/8;
|
||||
size_t bitsPerTexel = GetBitsPerTexel(mEffectiveInternalFormat);
|
||||
return size_t(mWidth) * size_t(mHeight) * size_t(mDepth) * bitsPerTexel / 8;
|
||||
}
|
||||
|
||||
int64_t
|
||||
size_t
|
||||
WebGLTexture::MemoryUsage() const {
|
||||
if (IsDeleted())
|
||||
return 0;
|
||||
int64_t result = 0;
|
||||
size_t result = 0;
|
||||
for(size_t face = 0; face < mFacesCount; face++) {
|
||||
if (mHaveGeneratedMipmap) {
|
||||
// Each mipmap level is 1/4 the size of the previous level
|
||||
size_t level0MemoryUsage = ImageInfoAtFace(face, 0).MemoryUsage();
|
||||
// Each mipmap level is 1/(2^d) the size of the previous level,
|
||||
// where d is 2 or 3 depending on whether the images are 2D or 3D
|
||||
// 1 + x + x^2 + ... = 1/(1-x)
|
||||
// for x = 1/4, we get 1/(1-1/4) = 4/3
|
||||
result += ImageInfoAtFace(face, 0).MemoryUsage() * 4 / 3;
|
||||
// for x = 1/(2^2), we get 1/(1-1/4) = 4/3
|
||||
// for x = 1/(2^3), we get 1/(1-1/8) = 8/7
|
||||
size_t allLevelsMemoryUsage =
|
||||
mTarget == LOCAL_GL_TEXTURE_3D
|
||||
? level0MemoryUsage * 8 / 7
|
||||
: level0MemoryUsage * 4 / 3;
|
||||
result += allLevelsMemoryUsage;
|
||||
} else {
|
||||
for(size_t level = 0; level <= mMaxLevelWithCustomImages; level++)
|
||||
result += ImageInfoAtFace(face, level).MemoryUsage();
|
||||
|
@ -76,7 +83,8 @@ WebGLTexture::MemoryUsage() const {
|
|||
}
|
||||
|
||||
bool
|
||||
WebGLTexture::DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImageTarget) const {
|
||||
WebGLTexture::DoesMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImageTarget) const
|
||||
{
|
||||
if (mHaveGeneratedMipmap)
|
||||
return true;
|
||||
|
||||
|
@ -89,13 +97,18 @@ WebGLTexture::DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget
|
|||
const ImageInfo& actual = ImageInfoAt(texImageTarget, level);
|
||||
if (actual != expected)
|
||||
return false;
|
||||
expected.mWidth = std::max(1, expected.mWidth >> 1);
|
||||
expected.mHeight = std::max(1, expected.mHeight >> 1);
|
||||
expected.mWidth = std::max(1, expected.mWidth / 2);
|
||||
expected.mHeight = std::max(1, expected.mHeight / 2);
|
||||
expected.mDepth = std::max(1, expected.mDepth / 2);
|
||||
|
||||
// if the current level has size 1x1, we can stop here: the spec doesn't seem to forbid the existence
|
||||
// of extra useless levels.
|
||||
if (actual.mWidth == 1 && actual.mHeight == 1)
|
||||
if (actual.mWidth == 1 &&
|
||||
actual.mHeight == 1 &&
|
||||
actual.mDepth == 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// if we're here, we've exhausted all levels without finding a 1x1 image
|
||||
|
@ -123,7 +136,7 @@ WebGLTexture::Bind(TexTarget aTexTarget) {
|
|||
mContext->gl->fBindTexture(aTexTarget.get(), name);
|
||||
|
||||
if (firstTimeThisTextureIsBound) {
|
||||
mFacesCount = (aTexTarget == LOCAL_GL_TEXTURE_2D) ? 1 : 6;
|
||||
mFacesCount = (aTexTarget == LOCAL_GL_TEXTURE_CUBE_MAP) ? 6 : 1;
|
||||
EnsureMaxLevelWithCustomImagesAtLeast(0);
|
||||
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
|
||||
|
||||
|
@ -137,16 +150,15 @@ WebGLTexture::Bind(TexTarget aTexTarget) {
|
|||
|
||||
void
|
||||
WebGLTexture::SetImageInfo(TexImageTarget aTexImageTarget, GLint aLevel,
|
||||
GLsizei aWidth, GLsizei aHeight,
|
||||
GLsizei aWidth, GLsizei aHeight, GLsizei aDepth,
|
||||
TexInternalFormat aEffectiveInternalFormat, WebGLImageDataStatus aStatus)
|
||||
{
|
||||
MOZ_ASSERT(aDepth == 1 || aTexImageTarget == LOCAL_GL_TEXTURE_3D);
|
||||
MOZ_ASSERT(TexImageTargetToTexTarget(aTexImageTarget) == mTarget);
|
||||
if (TexImageTargetToTexTarget(aTexImageTarget) != mTarget)
|
||||
return;
|
||||
|
||||
EnsureMaxLevelWithCustomImagesAtLeast(aLevel);
|
||||
|
||||
ImageInfoAt(aTexImageTarget, aLevel) = ImageInfo(aWidth, aHeight, aEffectiveInternalFormat, aStatus);
|
||||
ImageInfoAt(aTexImageTarget, aLevel) = ImageInfo(aWidth, aHeight, aDepth, aEffectiveInternalFormat, aStatus);
|
||||
|
||||
if (aLevel > 0)
|
||||
SetCustomMipmap();
|
||||
|
@ -176,7 +188,7 @@ WebGLTexture::SetCustomMipmap() {
|
|||
ImageInfo imageInfo = ImageInfoAtFace(0, 0);
|
||||
NS_ASSERTION(imageInfo.IsPowerOfTwo(), "this texture is NPOT, so how could GenerateMipmap() ever accept it?");
|
||||
|
||||
GLsizei size = std::max(imageInfo.mWidth, imageInfo.mHeight);
|
||||
GLsizei size = std::max(std::max(imageInfo.mWidth, imageInfo.mHeight), imageInfo.mDepth);
|
||||
|
||||
// so, the size is a power of two, let's find its log in base 2.
|
||||
size_t maxLevel = 0;
|
||||
|
@ -187,8 +199,9 @@ WebGLTexture::SetCustomMipmap() {
|
|||
|
||||
for (size_t level = 1; level <= maxLevel; ++level) {
|
||||
// again, since the sizes are powers of two, no need for any max(1,x) computation
|
||||
imageInfo.mWidth >>= 1;
|
||||
imageInfo.mHeight >>= 1;
|
||||
imageInfo.mWidth = std::max(imageInfo.mWidth / 2, 1);
|
||||
imageInfo.mHeight = std::max(imageInfo.mHeight / 2, 1);
|
||||
imageInfo.mDepth = std::max(imageInfo.mDepth / 2, 1);
|
||||
for(size_t face = 0; face < mFacesCount; ++face)
|
||||
ImageInfoAtFace(face, level) = imageInfo;
|
||||
}
|
||||
|
@ -206,20 +219,21 @@ WebGLTexture::AreAllLevel0ImageInfosEqual() const {
|
|||
}
|
||||
|
||||
bool
|
||||
WebGLTexture::IsMipmapTexture2DComplete() const {
|
||||
if (mTarget != LOCAL_GL_TEXTURE_2D)
|
||||
return false;
|
||||
if (!ImageInfoAt(LOCAL_GL_TEXTURE_2D, 0).IsPositive())
|
||||
WebGLTexture::IsMipmapComplete() const {
|
||||
MOZ_ASSERT(mTarget == LOCAL_GL_TEXTURE_2D ||
|
||||
mTarget == LOCAL_GL_TEXTURE_3D);
|
||||
|
||||
if (!ImageInfoAtFace(0, 0).IsPositive())
|
||||
return false;
|
||||
if (mHaveGeneratedMipmap)
|
||||
return true;
|
||||
return DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(LOCAL_GL_TEXTURE_2D);
|
||||
return DoesMipmapHaveAllLevelsConsistentlyDefined(LOCAL_GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLTexture::IsCubeComplete() const {
|
||||
if (mTarget != LOCAL_GL_TEXTURE_CUBE_MAP)
|
||||
return false;
|
||||
MOZ_ASSERT(mTarget == LOCAL_GL_TEXTURE_CUBE_MAP);
|
||||
|
||||
const ImageInfo &first = ImageInfoAt(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0);
|
||||
if (!first.IsPositive() || !first.IsSquare())
|
||||
return false;
|
||||
|
@ -232,7 +246,7 @@ WebGLTexture::IsMipmapCubeComplete() const {
|
|||
return false;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
const TexImageTarget face = TexImageTargetForTargetAndFace(LOCAL_GL_TEXTURE_CUBE_MAP, i);
|
||||
if (!DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(face))
|
||||
if (!DoesMipmapHaveAllLevelsConsistentlyDefined(face))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -260,18 +274,20 @@ WebGLTexture::ResolvedFakeBlackStatus() {
|
|||
= "A texture is going to be rendered as if it were black, as per the OpenGL ES 2.0.24 spec section 3.8.2, "
|
||||
"because it";
|
||||
|
||||
if (mTarget == LOCAL_GL_TEXTURE_2D)
|
||||
if (mTarget == LOCAL_GL_TEXTURE_2D ||
|
||||
mTarget == LOCAL_GL_TEXTURE_3D)
|
||||
{
|
||||
int dim = mTarget == LOCAL_GL_TEXTURE_2D ? 2 : 3;
|
||||
if (DoesMinFilterRequireMipmap())
|
||||
{
|
||||
if (!IsMipmapTexture2DComplete()) {
|
||||
if (!IsMipmapComplete()) {
|
||||
mContext->GenerateWarning
|
||||
("%s is a 2D texture, with a minification filter requiring a mipmap, "
|
||||
"and is not mipmap complete (as defined in section 3.7.10).", msg_rendering_as_black);
|
||||
("%s is a %dD texture, with a minification filter requiring a mipmap, "
|
||||
"and is not mipmap complete (as defined in section 3.7.10).", msg_rendering_as_black, dim);
|
||||
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
|
||||
} else if (!ImageInfoBase().IsPowerOfTwo()) {
|
||||
mContext->GenerateWarning
|
||||
("%s is a 2D texture, with a minification filter requiring a mipmap, "
|
||||
("%s is a %dD texture, with a minification filter requiring a mipmap, "
|
||||
"and either its width or height is not a power of two.", msg_rendering_as_black);
|
||||
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
|
||||
}
|
||||
|
@ -280,14 +296,14 @@ WebGLTexture::ResolvedFakeBlackStatus() {
|
|||
{
|
||||
if (!ImageInfoBase().IsPositive()) {
|
||||
mContext->GenerateWarning
|
||||
("%s is a 2D texture and its width or height is equal to zero.",
|
||||
msg_rendering_as_black);
|
||||
("%s is a %dD texture and its width or height is equal to zero.",
|
||||
msg_rendering_as_black, dim);
|
||||
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
|
||||
} else if (!AreBothWrapModesClampToEdge() && !ImageInfoBase().IsPowerOfTwo()) {
|
||||
mContext->GenerateWarning
|
||||
("%s is a 2D texture, with a minification filter not requiring a mipmap, "
|
||||
("%s is a %dD texture, with a minification filter not requiring a mipmap, "
|
||||
"with its width or height not a power of two, and with a wrap mode "
|
||||
"different from CLAMP_TO_EDGE.", msg_rendering_as_black);
|
||||
"different from CLAMP_TO_EDGE.", msg_rendering_as_black, dim);
|
||||
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
|
||||
}
|
||||
}
|
||||
|
@ -455,8 +471,7 @@ ClearWithTempFB(WebGLContext* context, GLuint tex,
|
|||
TexInternalFormat baseInternalFormat,
|
||||
GLsizei width, GLsizei height)
|
||||
{
|
||||
if (texImageTarget != LOCAL_GL_TEXTURE_2D)
|
||||
return false;
|
||||
MOZ_ASSERT(texImageTarget == LOCAL_GL_TEXTURE_2D);
|
||||
|
||||
gl::GLContext* gl = context->GL();
|
||||
MOZ_ASSERT(gl->IsCurrent());
|
||||
|
@ -536,13 +551,15 @@ WebGLTexture::DoDeferredImageInitialization(TexImageTarget imageTarget, GLint le
|
|||
|
||||
// Try to clear with glCLear.
|
||||
|
||||
bool cleared = ClearWithTempFB(mContext, GLName(),
|
||||
imageTarget, level,
|
||||
imageInfo.mEffectiveInternalFormat,
|
||||
imageInfo.mHeight, imageInfo.mWidth);
|
||||
if (cleared) {
|
||||
SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData);
|
||||
return;
|
||||
if (imageTarget == LOCAL_GL_TEXTURE_2D) {
|
||||
bool cleared = ClearWithTempFB(mContext, GLName(),
|
||||
imageTarget, level,
|
||||
imageInfo.mEffectiveInternalFormat,
|
||||
imageInfo.mHeight, imageInfo.mWidth);
|
||||
if (cleared) {
|
||||
SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// That didn't work. Try uploading zeros then.
|
||||
|
@ -556,6 +573,7 @@ WebGLTexture::DoDeferredImageInitialization(TexImageTarget imageTarget, GLint le
|
|||
= WebGLContext::GetImageSize(
|
||||
imageInfo.mHeight,
|
||||
imageInfo.mWidth,
|
||||
imageInfo.mDepth,
|
||||
bytespertexel,
|
||||
mContext->mPixelStoreUnpackAlignment);
|
||||
MOZ_ASSERT(checked_byteLength.isValid()); // should have been checked earlier
|
||||
|
@ -570,16 +588,24 @@ WebGLTexture::DoDeferredImageInitialization(TexImageTarget imageTarget, GLint le
|
|||
&driverInternalFormat, &driverFormat, &driverType);
|
||||
|
||||
mContext->GetAndFlushUnderlyingGLErrors();
|
||||
if (mImmutable) {
|
||||
gl->fTexSubImage2D(imageTarget.get(), level, 0, 0,
|
||||
imageInfo.mWidth, imageInfo.mHeight,
|
||||
driverFormat, driverType,
|
||||
zeros);
|
||||
} else {
|
||||
gl->fTexImage2D(imageTarget.get(), level, driverInternalFormat,
|
||||
imageInfo.mWidth, imageInfo.mHeight,
|
||||
0, driverFormat, driverType,
|
||||
if (imageTarget == LOCAL_GL_TEXTURE_3D) {
|
||||
MOZ_ASSERT(mImmutable, "Shouldn't be possible to have non-immutable-format 3D textures in WebGL");
|
||||
gl->fTexSubImage3D(imageTarget.get(), level, 0, 0, 0,
|
||||
imageInfo.mWidth, imageInfo.mHeight, imageInfo.mDepth,
|
||||
driverFormat, driverType,
|
||||
zeros);
|
||||
} else {
|
||||
if (mImmutable) {
|
||||
gl->fTexSubImage2D(imageTarget.get(), level, 0, 0,
|
||||
imageInfo.mWidth, imageInfo.mHeight,
|
||||
driverFormat, driverType,
|
||||
zeros);
|
||||
} else {
|
||||
gl->fTexImage2D(imageTarget.get(), level, driverInternalFormat,
|
||||
imageInfo.mWidth, imageInfo.mHeight,
|
||||
0, driverFormat, driverType,
|
||||
zeros);
|
||||
}
|
||||
}
|
||||
GLenum error = mContext->GetAndFlushUnderlyingGLErrors();
|
||||
if (error) {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -68,15 +69,18 @@ public:
|
|||
public:
|
||||
ImageInfo()
|
||||
: mEffectiveInternalFormat(LOCAL_GL_NONE)
|
||||
, mDepth(0)
|
||||
, mImageDataStatus(WebGLImageDataStatus::NoImageData)
|
||||
{}
|
||||
|
||||
ImageInfo(GLsizei width,
|
||||
GLsizei height,
|
||||
GLsizei depth,
|
||||
TexInternalFormat effectiveInternalFormat,
|
||||
WebGLImageDataStatus status)
|
||||
: WebGLRectangleObject(width, height)
|
||||
, mEffectiveInternalFormat(effectiveInternalFormat)
|
||||
, mDepth(depth)
|
||||
, mImageDataStatus(status)
|
||||
{
|
||||
// shouldn't use this constructor to construct a null ImageInfo
|
||||
|
@ -87,6 +91,7 @@ public:
|
|||
return mImageDataStatus == a.mImageDataStatus &&
|
||||
mWidth == a.mWidth &&
|
||||
mHeight == a.mHeight &&
|
||||
mDepth == a.mDepth &&
|
||||
mEffectiveInternalFormat == a.mEffectiveInternalFormat;
|
||||
}
|
||||
bool operator!=(const ImageInfo& a) const {
|
||||
|
@ -96,7 +101,7 @@ public:
|
|||
return mWidth == mHeight;
|
||||
}
|
||||
bool IsPositive() const {
|
||||
return mWidth > 0 && mHeight > 0;
|
||||
return mWidth > 0 && mHeight > 0 && mDepth > 0;
|
||||
}
|
||||
bool IsPowerOfTwo() const {
|
||||
return is_pot_assuming_nonnegative(mWidth) &&
|
||||
|
@ -105,7 +110,7 @@ public:
|
|||
bool HasUninitializedImageData() const {
|
||||
return mImageDataStatus == WebGLImageDataStatus::UninitializedImageData;
|
||||
}
|
||||
int64_t MemoryUsage() const;
|
||||
size_t MemoryUsage() const;
|
||||
|
||||
TexInternalFormat EffectiveInternalFormat() const { return mEffectiveInternalFormat; }
|
||||
|
||||
|
@ -117,6 +122,14 @@ public:
|
|||
*/
|
||||
TexInternalFormat mEffectiveInternalFormat;
|
||||
|
||||
/*
|
||||
* Used only for 3D textures.
|
||||
* Note that mWidth and mHeight are inherited from WebGLRectangleObject.
|
||||
* It's a pity to store a useless mDepth on non-3D texture images, but
|
||||
* the size of GLsizei is negligible compared to the typical size of a texture image.
|
||||
*/
|
||||
GLsizei mDepth;
|
||||
|
||||
WebGLImageDataStatus mImageDataStatus;
|
||||
|
||||
friend class WebGLTexture;
|
||||
|
@ -124,14 +137,16 @@ public:
|
|||
|
||||
private:
|
||||
static size_t FaceForTarget(TexImageTarget texImageTarget) {
|
||||
if (texImageTarget == LOCAL_GL_TEXTURE_2D)
|
||||
if (texImageTarget == LOCAL_GL_TEXTURE_2D ||
|
||||
texImageTarget == LOCAL_GL_TEXTURE_3D)
|
||||
{
|
||||
return 0;
|
||||
|
||||
}
|
||||
return texImageTarget.get() - LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
|
||||
}
|
||||
|
||||
ImageInfo& ImageInfoAtFace(size_t face, GLint level) {
|
||||
MOZ_ASSERT(face < mFacesCount, "wrong face index, must be 0 for TEXTURE_2D and at most 5 for cube maps");
|
||||
MOZ_ASSERT(face < mFacesCount, "wrong face index, must be 0 for TEXTURE_2D or TEXTURE_3D, and at most 5 for cube maps");
|
||||
|
||||
// no need to check level as a wrong value would be caught by ElementAt().
|
||||
return mImageInfos.ElementAt(level * mFacesCount + face);
|
||||
|
@ -169,7 +184,7 @@ public:
|
|||
return ImageInfoAtFace(0, 0);
|
||||
}
|
||||
|
||||
int64_t MemoryUsage() const;
|
||||
size_t MemoryUsage() const;
|
||||
|
||||
void SetImageDataStatus(TexImageTarget imageTarget, GLint level, WebGLImageDataStatus newStatus) {
|
||||
MOZ_ASSERT(HasImageInfoAt(imageTarget, level));
|
||||
|
@ -214,14 +229,14 @@ protected:
|
|||
return mWrapS == LOCAL_GL_CLAMP_TO_EDGE && mWrapT == LOCAL_GL_CLAMP_TO_EDGE;
|
||||
}
|
||||
|
||||
bool DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImageTarget) const;
|
||||
bool DoesMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImageTarget) const;
|
||||
|
||||
public:
|
||||
|
||||
void Bind(TexTarget aTexTarget);
|
||||
|
||||
void SetImageInfo(TexImageTarget aTarget, GLint aLevel,
|
||||
GLsizei aWidth, GLsizei aHeight,
|
||||
GLsizei aWidth, GLsizei aHeight, GLsizei aDepth,
|
||||
TexInternalFormat aFormat, WebGLImageDataStatus aStatus);
|
||||
|
||||
void SetMinFilter(TexMinFilter aMinFilter) {
|
||||
|
@ -256,7 +271,7 @@ public:
|
|||
|
||||
bool AreAllLevel0ImageInfosEqual() const;
|
||||
|
||||
bool IsMipmapTexture2DComplete() const;
|
||||
bool IsMipmapComplete() const;
|
||||
|
||||
bool IsCubeComplete() const;
|
||||
|
||||
|
@ -277,9 +292,17 @@ public:
|
|||
inline TexImageTarget
|
||||
TexImageTargetForTargetAndFace(TexTarget target, size_t face)
|
||||
{
|
||||
return target == LOCAL_GL_TEXTURE_2D
|
||||
? LOCAL_GL_TEXTURE_2D
|
||||
: LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
|
||||
switch (target.get()) {
|
||||
case LOCAL_GL_TEXTURE_2D:
|
||||
case LOCAL_GL_TEXTURE_3D:
|
||||
MOZ_ASSERT(face == 0);
|
||||
return target.get();
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP:
|
||||
MOZ_ASSERT(face < 6);
|
||||
return LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -46,13 +46,13 @@ namespace mozilla {
|
|||
* reason why it needs to be faked (incomplete texture vs. uninitialized image data),
|
||||
* whereas the WebGL context can only know whether _any_ faking is currently needed at all.
|
||||
*/
|
||||
MOZ_BEGIN_ENUM_CLASS(WebGLContextFakeBlackStatus, int)
|
||||
MOZ_BEGIN_ENUM_CLASS(WebGLContextFakeBlackStatus, uint8_t)
|
||||
Unknown,
|
||||
NotNeeded,
|
||||
Needed
|
||||
MOZ_END_ENUM_CLASS(WebGLContextFakeBlackStatus)
|
||||
|
||||
MOZ_BEGIN_ENUM_CLASS(WebGLTextureFakeBlackStatus, int)
|
||||
MOZ_BEGIN_ENUM_CLASS(WebGLTextureFakeBlackStatus, uint8_t)
|
||||
Unknown,
|
||||
NotNeeded,
|
||||
IncompleteTexture,
|
||||
|
@ -65,7 +65,7 @@ MOZ_END_ENUM_CLASS(WebGLTextureFakeBlackStatus)
|
|||
* OpenGL ES 2.0 allows drawing without vertex attrib 0 array enabled, but
|
||||
* desktop OpenGL does not allow that.
|
||||
*/
|
||||
MOZ_BEGIN_ENUM_CLASS(WebGLVertexAttrib0Status, int)
|
||||
MOZ_BEGIN_ENUM_CLASS(WebGLVertexAttrib0Status, uint8_t)
|
||||
Default, // default status - no emulation needed
|
||||
EmulatedUninitializedArray, // need an artificial attrib 0 array, but contents may be left uninitialized
|
||||
EmulatedInitializedArray // need an artificial attrib 0 array, and contents must be initialized
|
||||
|
@ -81,7 +81,7 @@ MOZ_END_ENUM_CLASS(WebGLVertexAttrib0Status)
|
|||
* initialized. It is the state that renderbuffers are in after a renderbufferStorage call,
|
||||
* and it is the state that texture images are in after a texImage2D call with null data.
|
||||
*/
|
||||
MOZ_BEGIN_ENUM_CLASS(WebGLImageDataStatus, int)
|
||||
MOZ_BEGIN_ENUM_CLASS(WebGLImageDataStatus, uint8_t)
|
||||
NoImageData,
|
||||
UninitializedImageData,
|
||||
InitializedImageData
|
||||
|
@ -95,7 +95,7 @@ MOZ_END_ENUM_CLASS(WebGLImageDataStatus)
|
|||
* - additional source formats, depending on browser details, used when uploading
|
||||
* textures from DOM elements. See gfxImageSurface::Format().
|
||||
*/
|
||||
MOZ_BEGIN_ENUM_CLASS(WebGLTexelFormat, int)
|
||||
MOZ_BEGIN_ENUM_CLASS(WebGLTexelFormat, uint8_t)
|
||||
// returned by SurfaceFromElementResultToImageSurface to indicate absence of image data
|
||||
None,
|
||||
// common value for formats for which format conversions are not supported
|
||||
|
@ -130,7 +130,7 @@ MOZ_BEGIN_ENUM_CLASS(WebGLTexelFormat, int)
|
|||
RGBA32F // OES_texture_float
|
||||
MOZ_END_ENUM_CLASS(WebGLTexelFormat)
|
||||
|
||||
MOZ_BEGIN_ENUM_CLASS(WebGLTexImageFunc, int)
|
||||
MOZ_BEGIN_ENUM_CLASS(WebGLTexImageFunc, uint8_t)
|
||||
TexImage,
|
||||
TexSubImage,
|
||||
CopyTexImage,
|
||||
|
@ -139,6 +139,11 @@ MOZ_BEGIN_ENUM_CLASS(WebGLTexImageFunc, int)
|
|||
CompTexSubImage,
|
||||
MOZ_END_ENUM_CLASS(WebGLTexImageFunc)
|
||||
|
||||
MOZ_BEGIN_ENUM_CLASS(WebGLTexDimensions, uint8_t)
|
||||
Tex2D,
|
||||
Tex3D
|
||||
MOZ_END_ENUM_CLASS(WebGLTexDimensions)
|
||||
|
||||
// Please keep extensions in alphabetic order.
|
||||
MOZ_BEGIN_ENUM_CLASS(WebGLExtensionID, uint8_t)
|
||||
ANGLE_instanced_arrays,
|
||||
|
|
|
@ -180,6 +180,7 @@ ScopedBindTexture::Init(GLenum aTarget)
|
|||
mTarget = aTarget;
|
||||
mOldTex = 0;
|
||||
GLenum bindingTarget = (aTarget == LOCAL_GL_TEXTURE_2D) ? LOCAL_GL_TEXTURE_BINDING_2D
|
||||
: (aTarget == LOCAL_GL_TEXTURE_3D) ? LOCAL_GL_TEXTURE_BINDING_3D
|
||||
: (aTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) ? LOCAL_GL_TEXTURE_BINDING_RECTANGLE_ARB
|
||||
: (aTarget == LOCAL_GL_TEXTURE_CUBE_MAP) ? LOCAL_GL_TEXTURE_BINDING_CUBE_MAP
|
||||
: (aTarget == LOCAL_GL_TEXTURE_EXTERNAL) ? LOCAL_GL_TEXTURE_BINDING_EXTERNAL
|
||||
|
|
|
@ -174,6 +174,7 @@ else
|
|||
LIBXUL_DIST="$MOZ_BUILD_ROOT/dist"
|
||||
AC_DEFINE(JS_STANDALONE)
|
||||
fi
|
||||
|
||||
AC_SUBST(JS_STANDALONE)
|
||||
BUILDING_JS=1
|
||||
AC_SUBST(autoconfmk)
|
||||
|
|
|
@ -20,7 +20,11 @@ function logProxy(object) {
|
|||
return {proxy, log};
|
||||
}
|
||||
|
||||
for (var property of ["string-property", Symbol("symbol-property")]) {
|
||||
var properties = ["string-property"];
|
||||
if (typeof Symbol === 'function')
|
||||
properties.push(Symbol("symbol-property"));
|
||||
|
||||
for (var property of properties) {
|
||||
// Test 1: property is not present on object
|
||||
var {proxy, log} = logProxy({});
|
||||
var result = Object.prototype.propertyIsEnumerable.call(proxy, property);
|
||||
|
|
|
@ -273,7 +273,7 @@ nsTableFrame::RegisterPositionedTablePart(nsIFrame* aFrame)
|
|||
// the potential to break sites that apply 'position: relative' to those
|
||||
// parts, expecting nothing to happen. We warn at the console to make tracking
|
||||
// down the issue easy.
|
||||
if (nsGkAtoms::tableCellFrame != aFrame->GetType()) {
|
||||
if (!IS_TABLE_CELL(aFrame->GetType())) {
|
||||
nsIContent* content = aFrame->GetContent();
|
||||
nsPresContext* presContext = aFrame->PresContext();
|
||||
if (content && !presContext->HasWarnedAboutPositionedTableParts()) {
|
||||
|
|
|
@ -376,9 +376,6 @@ ClearKeyDecryptor::ClearKeyDecryptor(GMPDecryptorCallback* aCallback,
|
|||
ClearKeyDecryptor::~ClearKeyDecryptor()
|
||||
{
|
||||
CK_LOGD("ClearKeyDecryptor dtor; key ID = %08x...", *(uint32_t*)&mKey[0]);
|
||||
if (mThread) {
|
||||
mThread->Join();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
@ -390,13 +387,15 @@ ClearKeyDecryptor::AddRef()
|
|||
uint32_t
|
||||
ClearKeyDecryptor::Release()
|
||||
{
|
||||
if (!--mRefCnt) {
|
||||
uint32_t newCount = --mRefCnt;
|
||||
if (!newCount) {
|
||||
if (mThread) {
|
||||
mThread->Post(new DestroyTask(this));
|
||||
mThread->Join();
|
||||
} else {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
return mRefCnt;
|
||||
return newCount;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,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/. */
|
||||
|
||||
#include <algorithm>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
|
@ -62,7 +63,9 @@ ClearKeyUtils::DecryptAES(const vector<uint8_t>& aKey,
|
|||
vector<uint8_t> enc(encLen);
|
||||
oaes_encrypt(aes, &aIV[0], CLEARKEY_KEY_LEN, &enc[0], &encLen);
|
||||
|
||||
for (size_t j = 0; j < CLEARKEY_KEY_LEN; j++) {
|
||||
assert(encLen >= 2 * OAES_BLOCK_SIZE + CLEARKEY_KEY_LEN);
|
||||
size_t blockLen = std::min(aData.size() - i, CLEARKEY_KEY_LEN);
|
||||
for (size_t j = 0; j < blockLen; j++) {
|
||||
aData[i + j] ^= enc[2 * OAES_BLOCK_SIZE + j];
|
||||
}
|
||||
IncrementIV(aIV);
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define CLEARKEY_KEY_LEN 16
|
||||
#define CLEARKEY_KEY_LEN ((size_t)16)
|
||||
|
||||
#if 0
|
||||
void CK_Log(const char* aFmt, ...);
|
||||
|
|
|
@ -10,4 +10,6 @@ CLEARKEY_CDM_FILES = \
|
|||
clearkey.info \
|
||||
$(NULL)
|
||||
|
||||
MOZ_GLUE_LDFLAGS =
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -20,4 +20,6 @@ LOCAL_INCLUDES += [
|
|||
]
|
||||
|
||||
USE_STATIC_LIBS = True
|
||||
USE_LIBS += [ 'mozalloc' ]
|
||||
|
||||
DISABLE_STL_WRAPPING = True
|
||||
DEFINES['MOZ_NO_MOZALLOC'] = True
|
||||
|
|
|
@ -155,6 +155,16 @@ private:
|
|||
Vector<Sample> mCurrentSamples;
|
||||
MPEG4Extractor::TrackExtends mTrackExtends;
|
||||
|
||||
// XXX hack -- demuxer expects a track's trun to be seen before saio or
|
||||
// saiz. Here we store saiz/saio box offsets for parsing *after* the trun
|
||||
// has been parsed.
|
||||
struct AuxRange {
|
||||
off64_t mStart;
|
||||
off64_t mSize;
|
||||
};
|
||||
Vector<AuxRange> mDeferredSaiz;
|
||||
Vector<AuxRange> mDeferredSaio;
|
||||
|
||||
MPEG4Source(const MPEG4Source &);
|
||||
MPEG4Source &operator=(const MPEG4Source &);
|
||||
};
|
||||
|
@ -2606,16 +2616,20 @@ status_t MPEG4Source::parseChunk(off64_t *offset) {
|
|||
|
||||
case FOURCC('s', 'a', 'i', 'z'): {
|
||||
status_t err;
|
||||
if ((err = parseSampleAuxiliaryInformationSizes(data_offset, chunk_data_size)) != OK) {
|
||||
return err;
|
||||
if (mLastParsedTrackId == mTrackId) {
|
||||
if ((err = parseSampleAuxiliaryInformationSizes(data_offset, chunk_data_size)) != OK) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
*offset += chunk_size;
|
||||
break;
|
||||
}
|
||||
case FOURCC('s', 'a', 'i', 'o'): {
|
||||
status_t err;
|
||||
if ((err = parseSampleAuxiliaryInformationOffsets(data_offset, chunk_data_size)) != OK) {
|
||||
return err;
|
||||
if (mLastParsedTrackId == mTrackId) {
|
||||
if ((err = parseSampleAuxiliaryInformationOffsets(data_offset, chunk_data_size)) != OK) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
*offset += chunk_size;
|
||||
break;
|
||||
|
@ -2640,6 +2654,18 @@ status_t MPEG4Source::parseChunk(off64_t *offset) {
|
|||
status_t MPEG4Source::parseSampleAuxiliaryInformationSizes(off64_t offset, off64_t size) {
|
||||
ALOGV("parseSampleAuxiliaryInformationSizes");
|
||||
// 14496-12 8.7.12
|
||||
|
||||
if (mCurrentSamples.isEmpty()) {
|
||||
// XXX hack -- we haven't seen trun yet; defer parsing this box until
|
||||
// after trun.
|
||||
ALOGW("deferring processing of saiz box");
|
||||
AuxRange range;
|
||||
range.mStart = offset;
|
||||
range.mSize = size;
|
||||
mDeferredSaiz.add(range);
|
||||
return OK;
|
||||
}
|
||||
|
||||
uint8_t version;
|
||||
if (mDataSource->readAt(
|
||||
offset, &version, sizeof(version))
|
||||
|
@ -2702,6 +2728,18 @@ status_t MPEG4Source::parseSampleAuxiliaryInformationSizes(off64_t offset, off64
|
|||
status_t MPEG4Source::parseSampleAuxiliaryInformationOffsets(off64_t offset, off64_t size) {
|
||||
ALOGV("parseSampleAuxiliaryInformationOffsets");
|
||||
// 14496-12 8.7.13
|
||||
|
||||
if (mCurrentSamples.isEmpty()) {
|
||||
// XXX hack -- we haven't seen trun yet; defer parsing this box until
|
||||
// after trun.
|
||||
ALOGW("deferring processing of saio box");
|
||||
AuxRange range;
|
||||
range.mStart = offset;
|
||||
range.mSize = size;
|
||||
mDeferredSaio.add(range);
|
||||
return OK;
|
||||
}
|
||||
|
||||
uint8_t version;
|
||||
if (mDataSource->readAt(offset, &version, sizeof(version)) != 1) {
|
||||
return ERROR_IO;
|
||||
|
@ -2714,6 +2752,11 @@ status_t MPEG4Source::parseSampleAuxiliaryInformationOffsets(off64_t offset, off
|
|||
}
|
||||
offset += 3;
|
||||
|
||||
if (flags & 1) {
|
||||
// Skip uint32s aux_info_type and aux_info_type_parameter
|
||||
offset += 8;
|
||||
}
|
||||
|
||||
uint32_t entrycount;
|
||||
if (!mDataSource->getUInt32(offset, &entrycount)) {
|
||||
return ERROR_IO;
|
||||
|
@ -3096,6 +3139,13 @@ status_t MPEG4Source::parseTrackFragmentRun(off64_t offset, off64_t size) {
|
|||
|
||||
mTrackFragmentHeaderInfo.mDataOffset = dataOffset;
|
||||
|
||||
for (size_t i = 0; i < mDeferredSaio.size() && i < mDeferredSaiz.size(); i++) {
|
||||
const auto& saio = mDeferredSaio[i];
|
||||
const auto& saiz = mDeferredSaiz[i];
|
||||
parseSampleAuxiliaryInformationSizes(saiz.mStart, saiz.mSize);
|
||||
parseSampleAuxiliaryInformationOffsets(saio.mStart, saio.mSize);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -3538,6 +3588,8 @@ status_t MPEG4Source::fragmentedRead(
|
|||
}
|
||||
mCurrentMoofOffset = totalOffset;
|
||||
mCurrentSamples.clear();
|
||||
mDeferredSaio.clear();
|
||||
mDeferredSaiz.clear();
|
||||
mCurrentSampleIndex = 0;
|
||||
mTrackFragmentData.mPresent = false;
|
||||
parseChunk(&totalOffset);
|
||||
|
@ -3569,6 +3621,8 @@ status_t MPEG4Source::fragmentedRead(
|
|||
// move to next fragment
|
||||
off64_t nextMoof = mNextMoofOffset; // lastSample.offset + lastSample.size;
|
||||
mCurrentSamples.clear();
|
||||
mDeferredSaio.clear();
|
||||
mDeferredSaiz.clear();
|
||||
mCurrentSampleIndex = 0;
|
||||
mTrackFragmentData.mPresent = false;
|
||||
uint32_t hdr[2];
|
||||
|
|
|
@ -203,16 +203,14 @@ int VcmSIPCCBinding::getVideoCodecsGmp()
|
|||
// H.264 only for now
|
||||
bool has_gmp;
|
||||
nsresult rv;
|
||||
rv = gSelf->mGMPService->HasPluginForAPI(NS_LITERAL_CSTRING(""),
|
||||
NS_LITERAL_CSTRING("encode-video"),
|
||||
rv = gSelf->mGMPService->HasPluginForAPI(NS_LITERAL_CSTRING("encode-video"),
|
||||
&tags,
|
||||
&has_gmp);
|
||||
if (NS_FAILED(rv) || !has_gmp) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv = gSelf->mGMPService->HasPluginForAPI(NS_LITERAL_CSTRING(""),
|
||||
NS_LITERAL_CSTRING("decode-video"),
|
||||
rv = gSelf->mGMPService->HasPluginForAPI(NS_LITERAL_CSTRING("decode-video"),
|
||||
&tags,
|
||||
&has_gmp);
|
||||
if (NS_FAILED(rv) || !has_gmp) {
|
||||
|
|
|
@ -59,13 +59,9 @@
|
|||
* zone allocator anyways. Jemalloc-specific functions are also left
|
||||
* unprefixed.
|
||||
*
|
||||
* - On Android, both malloc implementation and duplication functions are
|
||||
* prefixed with "__wrap_". Additionally, C++ allocation functions
|
||||
* (operator new/delete) are also exported and prefixed with "__wrap_".
|
||||
* Jemalloc specific functions are left unprefixed.
|
||||
*
|
||||
* - On Gonk, all functions are left unprefixed. Additionally, C++ allocation
|
||||
* functions (operator new/delete) are also exported and unprefixed.
|
||||
* - On Android and Gonk, all functions are left unprefixed. Additionally,
|
||||
* C++ allocation functions (operator new/delete) are also exported and
|
||||
* unprefixed.
|
||||
*
|
||||
* - On other systems (mostly Linux), all functions are left unprefixed.
|
||||
*
|
||||
|
@ -79,9 +75,10 @@
|
|||
*
|
||||
* All these functions are meant to be called with no prefix from Gecko code.
|
||||
* In most cases, this is because that's how they are available at runtime.
|
||||
* However, on Android, "__wrap_" prefixing is left to the build-time linker
|
||||
* (with -Wl,--wrap), or to the mozmemory.h header for malloc_good_size and
|
||||
* jemalloc specific functions.
|
||||
* However, on Android, this relies on faulty.lib (the custom dynamic linker)
|
||||
* resolving mozglue symbols before libc symbols, which is guaranteed by the
|
||||
* way faulty.lib works (it respects the DT_NEEDED order, and libc always
|
||||
* appears after mozglue ; which we double check when building anyways)
|
||||
*
|
||||
*
|
||||
* Within libmozglue (when MOZ_MEMORY_IMPL is defined), all the functions
|
||||
|
@ -157,13 +154,6 @@
|
|||
# endif
|
||||
# endif
|
||||
|
||||
# if defined(MOZ_WIDGET_ANDROID)
|
||||
# ifndef mozmem_malloc_impl
|
||||
# define mozmem_malloc_impl(a) __wrap_ ## a
|
||||
# endif
|
||||
# define mozmem_dup_impl(a) __wrap_ ## a
|
||||
# endif
|
||||
|
||||
/* All other jemalloc3 functions are prefixed with "je_", except when
|
||||
* building against an unprefixed system jemalloc library */
|
||||
# define je_(a) je_ ## a
|
||||
|
|
|
@ -15,12 +15,8 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#ifdef MOZ_MEMORY
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
extern "C" int __wrap_posix_memalign(void** memptr, size_t alignment, size_t size);
|
||||
#else
|
||||
extern "C" int posix_memalign(void** memptr, size_t alignment, size_t size);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define MIN_VOLATILE_ALLOC_SIZE 8192
|
||||
|
||||
|
@ -68,11 +64,7 @@ heap_alloc:
|
|||
}
|
||||
|
||||
#ifdef MOZ_MEMORY
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
__wrap_posix_memalign(&mBuf, aAlignment, aSize);
|
||||
#else
|
||||
posix_memalign(&mBuf, aAlignment, aSize);
|
||||
#endif
|
||||
#else
|
||||
mBuf = memalign(aAlignment, aSize);
|
||||
#endif
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
MOZ_GLUE_LDFLAGS = # Don't link against mozglue
|
||||
WRAP_LDFLAGS = # Never wrap malloc function calls with -Wl,--wrap
|
|
@ -0,0 +1,6 @@
|
|||
# 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 = # Don't link against mozglue
|
||||
WRAP_LDFLAGS = # Never wrap malloc function calls with -Wl,--wrap
|
|
@ -104,7 +104,6 @@
|
|||
@BINPATH@/blocklist.xml
|
||||
#ifdef XP_UNIX
|
||||
@BINPATH@/run-mozilla.sh
|
||||
@BINPATH@/mozilla-xremote-client
|
||||
#endif
|
||||
|
||||
; [Components]
|
||||
|
|
|
@ -66,7 +66,6 @@ static std::vector<AtForkFuncs, SpecialAllocator<AtForkFuncs> > atfork;
|
|||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include "cpuacct.h"
|
||||
#define WRAP(x) x
|
||||
|
||||
#if ANDROID_VERSION < 17 || defined(MOZ_WIDGET_ANDROID)
|
||||
extern "C" NS_EXPORT int
|
||||
|
@ -80,12 +79,11 @@ timer_create(clockid_t, struct sigevent*, timer_t*)
|
|||
|
||||
#else
|
||||
#define cpuacct_add(x)
|
||||
#define WRAP(x) __wrap_##x
|
||||
#endif
|
||||
|
||||
#if ANDROID_VERSION < 17 || defined(MOZ_WIDGET_ANDROID)
|
||||
extern "C" NS_EXPORT int
|
||||
WRAP(pthread_atfork)(void (*prepare)(void), void (*parent)(void), void (*child)(void))
|
||||
pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))
|
||||
{
|
||||
AtForkFuncs funcs;
|
||||
funcs.prepare = prepare;
|
||||
|
@ -100,7 +98,7 @@ WRAP(pthread_atfork)(void (*prepare)(void), void (*parent)(void), void (*child)(
|
|||
extern "C" NS_EXPORT pid_t __fork(void);
|
||||
|
||||
extern "C" NS_EXPORT pid_t
|
||||
WRAP(fork)(void)
|
||||
fork(void)
|
||||
{
|
||||
pid_t pid;
|
||||
for (auto it = atfork.rbegin();
|
||||
|
@ -127,7 +125,7 @@ WRAP(fork)(void)
|
|||
#endif
|
||||
|
||||
extern "C" NS_EXPORT int
|
||||
WRAP(raise)(int sig)
|
||||
raise(int sig)
|
||||
{
|
||||
// Bug 741272: Bionic incorrectly uses kill(), which signals the
|
||||
// process, and thus could signal another thread (and let this one
|
||||
|
@ -262,3 +260,20 @@ extern "C" NS_EXPORT size_t __wrap_strspn(const char * a0, const char * a1) { re
|
|||
extern "C" NS_EXPORT int __wrap_strcoll(const char * a0, const char * a1) { return __real_strcoll(a0, a1); }
|
||||
extern "C" NS_EXPORT size_t __wrap_strxfrm(char * a0, const char * a1, size_t a2) { return __real_strxfrm(a0, a1, a2); }
|
||||
#endif
|
||||
|
||||
/* Flash plugin uses symbols that are not present in Android >= 4.4 */
|
||||
#ifndef MOZ_WIDGET_GONK
|
||||
namespace android {
|
||||
namespace VectorImpl {
|
||||
NS_EXPORT void reservedVectorImpl1(void) { }
|
||||
NS_EXPORT void reservedVectorImpl2(void) { }
|
||||
NS_EXPORT void reservedVectorImpl3(void) { }
|
||||
NS_EXPORT void reservedVectorImpl4(void) { }
|
||||
NS_EXPORT void reservedVectorImpl5(void) { }
|
||||
NS_EXPORT void reservedVectorImpl6(void) { }
|
||||
NS_EXPORT void reservedVectorImpl7(void) { }
|
||||
NS_EXPORT void reservedVectorImpl8(void) { }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -49,11 +49,6 @@ OS_LDFLAGS += -Wl,-weak_library,$(DEPTH)/memory/replace/dummy/$(DLL_PREFIX)repla
|
|||
endif
|
||||
endif
|
||||
|
||||
ifeq (android, $(MOZ_WIDGET_TOOLKIT))
|
||||
# To properly wrap jemalloc's pthread_atfork call.
|
||||
OS_LDFLAGS += -Wl,--wrap=pthread_atfork
|
||||
endif
|
||||
|
||||
ifdef MOZ_LINKER
|
||||
ifeq (arm, $(TARGET_CPU))
|
||||
OS_LDFLAGS += -Wl,-version-script,$(srcdir)/arm-eabi-filter
|
||||
|
|
|
@ -74,11 +74,6 @@ static int p_flags_to_mprot(Word flags)
|
|||
((flags & PF_R) ? PROT_READ : 0);
|
||||
}
|
||||
|
||||
void
|
||||
__void_stub(void)
|
||||
{
|
||||
}
|
||||
|
||||
} /* anonymous namespace */
|
||||
|
||||
/**
|
||||
|
@ -330,16 +325,6 @@ CustomElf::GetSymbolPtrInDeps(const char *symbol) const
|
|||
return FunctionPtr(sigaction);
|
||||
}
|
||||
|
||||
#define MISSING_FLASH_SYMNAME_START "_ZN7android10VectorImpl19reservedVectorImpl"
|
||||
|
||||
// Android changed some symbols that Flash depended on in 4.4,
|
||||
// so stub those out here
|
||||
if (strncmp(symbol,
|
||||
MISSING_FLASH_SYMNAME_START,
|
||||
sizeof(MISSING_FLASH_SYMNAME_START) - 1) == 0) {
|
||||
return FunctionPtr(__void_stub);
|
||||
}
|
||||
|
||||
void *sym;
|
||||
|
||||
unsigned long hash = Hash(symbol);
|
||||
|
|
|
@ -54,8 +54,12 @@ ArrayBufferInputStream::Available(uint64_t* aCount)
|
|||
if (mClosed) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
uint32_t buflen = JS_GetArrayBufferByteLength(mArrayBuffer->get());
|
||||
*aCount = buflen ? buflen - mPos : 0;
|
||||
if (mArrayBuffer) {
|
||||
uint32_t buflen = JS_GetArrayBufferByteLength(mArrayBuffer->get());
|
||||
*aCount = buflen ? buflen - mPos : 0;
|
||||
} else {
|
||||
*aCount = 0;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,9 +6,10 @@ support-files =
|
|||
user_agent.sjs
|
||||
user_agent_update.sjs
|
||||
|
||||
[test_arraybufferinputstream.html]
|
||||
[test_partially_cached_content.html]
|
||||
[test_uri_scheme.html]
|
||||
[test_user_agent_overrides.html]
|
||||
[test_user_agent_updates.html]
|
||||
[test_user_agent_updates_reset.html]
|
||||
[test_xhr_method_case.html]
|
||||
[test_xhr_method_case.html]
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
-->
|
||||
<head>
|
||||
<title>ArrayBuffer stream test</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">
|
||||
function neuter(ab)
|
||||
{
|
||||
var w = new Worker("data:application/javascript,");
|
||||
w.postMessage(ab, [ab]);
|
||||
}
|
||||
|
||||
function test()
|
||||
{
|
||||
var ab = new ArrayBuffer(4000);
|
||||
var ta = new Uint8Array(ab);
|
||||
ta[0] = 'a'.charCodeAt(0);
|
||||
|
||||
const Cc = SpecialPowers.Cc, Ci = SpecialPowers.Ci, Cr = SpecialPowers.Cr;
|
||||
var abis = Cc["@mozilla.org/io/arraybuffer-input-stream;1"]
|
||||
.createInstance(Ci.nsIArrayBufferInputStream);
|
||||
|
||||
var sis = Cc["@mozilla.org/scriptableinputstream;1"]
|
||||
.createInstance(Ci.nsIScriptableInputStream);
|
||||
sis.init(abis);
|
||||
|
||||
is(sis.read(1), "", "should read no data from an uninitialized ABIS");
|
||||
|
||||
abis.setData(ab, 0, 256 * 1024);
|
||||
|
||||
is(sis.read(1), "a", "should read 'a' after init");
|
||||
|
||||
neuter(ab);
|
||||
|
||||
SpecialPowers.forceGC();
|
||||
SpecialPowers.forceGC();
|
||||
|
||||
try
|
||||
{
|
||||
sis.read(1);
|
||||
ok(false, "reading from stream shouldn't have worked");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
ok(e.result === Cr.NS_BASE_STREAM_CLOSED,
|
||||
"neutering underneath an input stream should close it");
|
||||
}
|
||||
}
|
||||
|
||||
test();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -407,11 +407,11 @@ do { \
|
|||
#pragma GCC visibility push(default)
|
||||
|
||||
extern const char *
|
||||
__wrap_gai_strerror(int ecode);
|
||||
gai_strerror(int ecode);
|
||||
extern void
|
||||
__wrap_freeaddrinfo(struct addrinfo *ai);
|
||||
freeaddrinfo(struct addrinfo *ai);
|
||||
extern int
|
||||
__wrap_getaddrinfo(const char *hostname, const char *servname,
|
||||
getaddrinfo(const char *hostname, const char *servname,
|
||||
const struct addrinfo *hints, struct addrinfo **res);
|
||||
|
||||
int android_sdk_version;
|
||||
|
@ -431,7 +431,7 @@ static int honeycomb_or_later()
|
|||
}
|
||||
|
||||
const char *
|
||||
__wrap_gai_strerror(int ecode)
|
||||
gai_strerror(int ecode)
|
||||
{
|
||||
if (honeycomb_or_later())
|
||||
return gai_strerror(ecode);
|
||||
|
@ -441,7 +441,7 @@ __wrap_gai_strerror(int ecode)
|
|||
}
|
||||
|
||||
void
|
||||
__wrap_freeaddrinfo(struct addrinfo *ai)
|
||||
freeaddrinfo(struct addrinfo *ai)
|
||||
{
|
||||
struct addrinfo *next;
|
||||
|
||||
|
@ -533,7 +533,7 @@ _have_ipv4() {
|
|||
}
|
||||
|
||||
int
|
||||
__wrap_getaddrinfo(const char *hostname, const char *servname,
|
||||
getaddrinfo(const char *hostname, const char *servname,
|
||||
const struct addrinfo *hints, struct addrinfo **res)
|
||||
{
|
||||
struct addrinfo sentinel;
|
||||
|
@ -731,7 +731,7 @@ __wrap_getaddrinfo(const char *hostname, const char *servname,
|
|||
free:
|
||||
bad:
|
||||
if (sentinel.ai_next)
|
||||
__wrap_freeaddrinfo(sentinel.ai_next);
|
||||
freeaddrinfo(sentinel.ai_next);
|
||||
*res = NULL;
|
||||
return error;
|
||||
}
|
||||
|
@ -792,7 +792,7 @@ explore_fqdn(const struct addrinfo *pai, const char *hostname,
|
|||
|
||||
free:
|
||||
if (result)
|
||||
__wrap_freeaddrinfo(result);
|
||||
freeaddrinfo(result);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -860,7 +860,7 @@ explore_null(const struct addrinfo *pai, const char *servname,
|
|||
|
||||
free:
|
||||
if (sentinel.ai_next)
|
||||
__wrap_freeaddrinfo(sentinel.ai_next);
|
||||
freeaddrinfo(sentinel.ai_next);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -947,7 +947,7 @@ explore_numeric(const struct addrinfo *pai, const char *hostname,
|
|||
free:
|
||||
bad:
|
||||
if (sentinel.ai_next)
|
||||
__wrap_freeaddrinfo(sentinel.ai_next);
|
||||
freeaddrinfo(sentinel.ai_next);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -2005,7 +2005,7 @@ _gethtent(_pseudo_FILE * __restrict__ hostf, const char *name, const struct addr
|
|||
found:
|
||||
hints = *pai;
|
||||
hints.ai_flags = AI_NUMERICHOST;
|
||||
error = __wrap_getaddrinfo(addr, NULL, &hints, &res0);
|
||||
error = getaddrinfo(addr, NULL, &hints, &res0);
|
||||
if (error)
|
||||
goto again;
|
||||
for (res = res0; res; res = res->ai_next) {
|
||||
|
@ -2014,7 +2014,7 @@ found:
|
|||
|
||||
if (pai->ai_flags & AI_CANONNAME) {
|
||||
if (get_canonname(pai, res, cname) != 0) {
|
||||
__wrap_freeaddrinfo(res0);
|
||||
freeaddrinfo(res0);
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -664,6 +664,10 @@ class GTestCommands(MachCommandBase):
|
|||
# https://code.google.com/p/googletest/wiki/AdvancedGuide#Running_Test_Programs:_Advanced_Options
|
||||
gtest_env = {b'GTEST_FILTER': gtest_filter}
|
||||
|
||||
xre_path = os.path.join(self.topobjdir, "dist", "bin")
|
||||
gtest_env["MOZ_XRE_DIR"] = xre_path
|
||||
gtest_env["MOZ_GMP_PATH"] = os.path.join(xre_path, "gmp-fake", "1.0")
|
||||
|
||||
gtest_env[b"MOZ_RUN_GTEST"] = b"True"
|
||||
|
||||
if shuffle:
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
|
||||
#include "NSSErrorsService.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#ifndef MOZ_NO_MOZALLOC
|
||||
#include "mozilla/mozalloc_oom.h"
|
||||
#endif
|
||||
#include "mozilla/Scoped.h"
|
||||
#include "nsError.h"
|
||||
#include "nsDebug.h"
|
||||
|
@ -257,8 +259,11 @@ inline void
|
|||
SECITEM_AllocItem(SECItem & item, uint32_t len)
|
||||
{
|
||||
if (MOZ_UNLIKELY(!SECITEM_AllocItem(nullptr, &item, len))) {
|
||||
#ifndef MOZ_NO_MOZALLOC
|
||||
mozalloc_handle_oom(len);
|
||||
if (MOZ_UNLIKELY(!SECITEM_AllocItem(nullptr, &item, len))) {
|
||||
if (MOZ_UNLIKELY(!SECITEM_AllocItem(nullptr, &item, len)))
|
||||
#endif
|
||||
{
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,12 +19,12 @@
|
|||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/Exceptions.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsString.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
#include "nsExceptionHandler.h"
|
||||
#endif
|
||||
#include "nsStackWalk.h"
|
||||
#include "nsString.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -74,17 +74,46 @@ SandboxLogJSStack(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void SandboxPrintStackFrame(uint32_t aFrameNumber, void *aPC, void *aSP,
|
||||
void *aClosure)
|
||||
{
|
||||
char buf[1024];
|
||||
nsCodeAddressDetails details;
|
||||
|
||||
NS_DescribeCodeAddress(aPC, &details);
|
||||
NS_FormatCodeAddressDetails(buf, sizeof(buf), aFrameNumber, aPC, &details);
|
||||
SANDBOX_LOG_ERROR("frame %s", buf);
|
||||
}
|
||||
|
||||
static void
|
||||
SandboxLogCStack()
|
||||
{
|
||||
// Skip 3 frames: one for this module, one for the signal handler in
|
||||
// libmozsandbox, and one for the signal trampoline.
|
||||
//
|
||||
// Warning: this might not print any stack frames. NS_StackWalk
|
||||
// can't walk past the signal trampoline on ARM (bug 968531), and
|
||||
// x86 frame pointer walking may or may not work (bug 1082276).
|
||||
|
||||
NS_StackWalk(SandboxPrintStackFrame, /* skip */ 3, /* max */ 0,
|
||||
nullptr, 0, nullptr);
|
||||
SANDBOX_LOG_ERROR("end of stack.");
|
||||
}
|
||||
|
||||
static void
|
||||
SandboxCrash(int nr, siginfo_t *info, void *void_context)
|
||||
{
|
||||
pid_t pid = getpid(), tid = syscall(__NR_gettid);
|
||||
bool dumped = false;
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
bool dumped = CrashReporter::WriteMinidumpForSigInfo(nr, info, void_context);
|
||||
if (!dumped) {
|
||||
SANDBOX_LOG_ERROR("Failed to write minidump");
|
||||
}
|
||||
dumped = CrashReporter::WriteMinidumpForSigInfo(nr, info, void_context);
|
||||
#endif
|
||||
if (!dumped) {
|
||||
SANDBOX_LOG_ERROR("crash reporter is disabled (or failed);"
|
||||
" trying stack trace:");
|
||||
SandboxLogCStack();
|
||||
}
|
||||
|
||||
// Do this last, in case it crashes or deadlocks.
|
||||
SandboxLogJSStack();
|
||||
|
|
|
@ -82,7 +82,7 @@ TPSCmdLineHandler.prototype = {
|
|||
var TPSCmdLineFactory = {
|
||||
createInstance : function(outer, iid) {
|
||||
if (outer != null) {
|
||||
throw Components.results.NS_ERROR_NO_AGGREGATION;
|
||||
throw new Error(Components.results.NS_ERROR_NO_AGGREGATION);
|
||||
}
|
||||
|
||||
return new TPSCmdLineHandler().QueryInterface(iid);
|
||||
|
@ -127,10 +127,10 @@ var TPSCmdLineModule = {
|
|||
}
|
||||
|
||||
if (!iid.equals(Components.interfaces.nsIFactory)) {
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
throw new Error(Components.results.NS_ERROR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
throw new Error(Components.results.NS_ERROR_NO_INTERFACE);
|
||||
},
|
||||
|
||||
canUnload : function(compMgr) {
|
||||
|
|
|
@ -74,7 +74,7 @@ var Logger = {
|
|||
msg += "; " + this._potentialError;
|
||||
this._potentialError = null;
|
||||
}
|
||||
throw("ASSERTION FAILED! " + msg);
|
||||
throw new Error("ASSERTION FAILED! " + msg);
|
||||
},
|
||||
|
||||
AssertFalse: function(bool, msg, showPotentialError) {
|
||||
|
@ -83,7 +83,7 @@ var Logger = {
|
|||
|
||||
AssertEqual: function(val1, val2, msg) {
|
||||
if (val1 != val2)
|
||||
throw("ASSERTION FAILED! " + msg + "; expected " +
|
||||
throw new Error("ASSERTION FAILED! " + msg + "; expected " +
|
||||
JSON.stringify(val2) + ", got " + JSON.stringify(val1));
|
||||
},
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ Addon.prototype = {
|
|||
Logger.AssertTrue(addon.userDisabled, "add-on is enabled: " + addon.id);
|
||||
return true;
|
||||
} else if (state) {
|
||||
throw Error("Don't know how to handle state: " + state);
|
||||
throw new Error("Don't know how to handle state: " + state);
|
||||
} else {
|
||||
// No state, so just checking that it exists.
|
||||
return true;
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче