зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to fx-team.
This commit is contained in:
Коммит
be7dc4f9b1
2
CLOBBER
2
CLOBBER
|
@ -18,4 +18,4 @@
|
|||
# Modifying this file will now automatically clobber the buildbot machines \o/
|
||||
#
|
||||
|
||||
Bug 922461 needs a clobber to regenerate code and survive bug 925243's FAIL_ON_WARNINGS annotation.
|
||||
Bug 915002 - Clobber needed for webidl updates for AppNotificationServiceOptions. One more time.
|
|
@ -887,18 +887,20 @@ var AlertsHelper = {
|
|||
}
|
||||
|
||||
let data = aMessage.data;
|
||||
let details = data.details;
|
||||
let listener = {
|
||||
mm: aMessage.target,
|
||||
title: data.title,
|
||||
text: data.text,
|
||||
manifestURL: data.manifestURL,
|
||||
manifestURL: details.manifestURL,
|
||||
imageURL: data.imageURL
|
||||
}
|
||||
};
|
||||
this.registerAppListener(data.uid, listener);
|
||||
|
||||
this.showNotification(data.imageURL, data.title, data.text,
|
||||
data.textClickable, null,
|
||||
data.uid, null, null, data.manifestURL);
|
||||
details.textClickable, null,
|
||||
data.uid, details.dir,
|
||||
details.lang, details.manifestURL);
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -65,17 +65,16 @@ AlertsService.prototype = {
|
|||
showAppNotification: function showAppNotification(aImageURL,
|
||||
aTitle,
|
||||
aText,
|
||||
aTextClickable,
|
||||
aManifestURL,
|
||||
aAlertListener,
|
||||
aId) {
|
||||
let uid = (aId == "") ? "app-notif-" + uuidGenerator.generateUUID() : aId;
|
||||
aDetails) {
|
||||
let uid = (aDetails.id == "") ?
|
||||
"app-notif-" + uuidGenerator.generateUUID() : aDetails.id;
|
||||
|
||||
this._listeners[uid] = {
|
||||
observer: aAlertListener,
|
||||
title: aTitle,
|
||||
text: aText,
|
||||
manifestURL: aManifestURL,
|
||||
manifestURL: aDetails.manifestURL,
|
||||
imageURL: aImageURL
|
||||
};
|
||||
|
||||
|
@ -83,9 +82,8 @@ AlertsService.prototype = {
|
|||
imageURL: aImageURL,
|
||||
title: aTitle,
|
||||
text: aText,
|
||||
textClickable: aTextClickable,
|
||||
manifestURL: aManifestURL,
|
||||
uid: uid
|
||||
uid: uid,
|
||||
details: aDetails
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"revision": "c7c750d66279bf2b7f9164d8b57d425a028e1fd9",
|
||||
"revision": "e2429ca17a0b77ddffdd69a96fd413449f71256e",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -29,10 +29,8 @@ libs:: $(FINAL_TARGET)/chrome/pdfjs.manifest $(FINAL_TARGET)/chrome/shumway.mani
|
|||
$(srcdir)/shumway \
|
||||
$(foreach exclude,$(exclude_files), -X $(srcdir)/shumway/$(exclude)) \
|
||||
$(FINAL_TARGET)/chrome
|
||||
$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py \
|
||||
$(FINAL_TARGET)/chrome.manifest "manifest chrome/pdfjs.manifest"
|
||||
$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py \
|
||||
$(FINAL_TARGET)/chrome.manifest "manifest chrome/shumway.manifest"
|
||||
$(call py_action,buildlist,$(FINAL_TARGET)/chrome.manifest "manifest chrome/pdfjs.manifest")
|
||||
$(call py_action,buildlist,$(FINAL_TARGET)/chrome.manifest "manifest chrome/shumway.manifest")
|
||||
|
||||
ifdef MOZ_METRO
|
||||
$(DIST)/bin/metro/chrome/pdfjs.manifest: $(GLOBAL_DEPS)
|
||||
|
@ -43,6 +41,5 @@ libs:: $(DIST)/bin/metro/chrome/pdfjs.manifest
|
|||
$(srcdir)/pdfjs \
|
||||
$(foreach exclude,$(exclude_files), -X $(srcdir)/pdfjs/$(exclude)) \
|
||||
$(DIST)/bin/metro/chrome
|
||||
$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py \
|
||||
$(DIST)/bin/metro/chrome.manifest "manifest chrome/pdfjs.manifest"
|
||||
$(call py_action,buildlist,$(DIST)/bin/metro/chrome.manifest "manifest chrome/pdfjs.manifest")
|
||||
endif
|
||||
|
|
|
@ -786,6 +786,7 @@ bin/libfreebl_32int64_3.so
|
|||
@BINPATH@/webapprt/modules/WebappRT.jsm
|
||||
@BINPATH@/webapprt/modules/WebappsHandler.jsm
|
||||
@BINPATH@/webapprt/modules/RemoteDebugger.jsm
|
||||
@BINPATH@/webapprt/modules/WebRTCHandler.jsm
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_METRO
|
||||
|
|
|
@ -4,21 +4,37 @@
|
|||
|
||||
var AlertsHelper = {
|
||||
_listener: null,
|
||||
_cookie: "",
|
||||
|
||||
showAlertNotification: function ah_show(aImageURL, aTitle, aText, aTextClickable, aCookie, aListener) {
|
||||
Services.obs.addObserver(this, "metro_native_toast_clicked", false);
|
||||
if (aListener) {
|
||||
Services.obs.addObserver(this, "metro_native_toast_clicked", false);
|
||||
Services.obs.addObserver(this, "metro_native_toast_dismissed", false);
|
||||
Services.obs.addObserver(this, "metro_native_toast_shown", false);
|
||||
}
|
||||
this._listener = aListener;
|
||||
this._cookie = aCookie;
|
||||
|
||||
Services.metro.showNativeToast(aTitle, aText, aImageURL);
|
||||
Services.metro.showNativeToast(aTitle, aText, aImageURL, aCookie);
|
||||
},
|
||||
|
||||
closeAlert: function ah_close() {
|
||||
if (this._listener) {
|
||||
Services.obs.removeObserver(this, "metro_native_toast_shown");
|
||||
Services.obs.removeObserver(this, "metro_native_toast_clicked");
|
||||
Services.obs.removeObserver(this, "metro_native_toast_dismissed");
|
||||
this._listener = null;
|
||||
}
|
||||
},
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
case "metro_native_toast_clicked":
|
||||
Services.obs.removeObserver(this, "metro_native_toast_clicked");
|
||||
this._listener.observe(null, "alertclickcallback", this._cookie);
|
||||
this._listener.observe(null, "alertclickcallback", aData);
|
||||
break;
|
||||
case "metro_native_toast_shown":
|
||||
this._listener.observe(null, "alertshow", aData);
|
||||
break;
|
||||
case "metro_native_toast_dismissed":
|
||||
this._listener.observe(null, "alertfinished", aData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,8 @@ AlertsService.prototype = {
|
|||
classID: Components.ID("{fe33c107-82a4-41d6-8c64-5353267e04c9}"),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAlertsService]),
|
||||
|
||||
showAlertNotification: function(aImageUrl, aTitle, aText, aTextClickable, aCookie, aAlertListener, aName) {
|
||||
showAlertNotification: function(aImageUrl, aTitle, aText, aTextClickable,
|
||||
aCookie, aAlertListener, aName, aDir, aLang) {
|
||||
let browser = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
try {
|
||||
browser.AlertsHelper.showAlertNotification(aImageUrl, aTitle, aText, aTextClickable, aCookie, aAlertListener);
|
||||
|
@ -33,6 +34,11 @@ AlertsService.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
closeAlert: function(aName) {
|
||||
let browser = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
browser.AlertsHelper.closeAlert();
|
||||
},
|
||||
|
||||
_getChromeWindow: function (aWindow) {
|
||||
let chromeWin = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
|
|
|
@ -9,12 +9,12 @@
|
|||
#undef Elf_Ehdr
|
||||
#undef Elf_Addr
|
||||
|
||||
#if BITS == 32
|
||||
#define Elf_Ehdr Elf32_Ehdr
|
||||
#define Elf_Addr Elf32_Addr
|
||||
#else
|
||||
#if defined(__LP64__)
|
||||
#define Elf_Ehdr Elf64_Ehdr
|
||||
#define Elf_Addr Elf64_Addr
|
||||
#else
|
||||
#define Elf_Ehdr Elf32_Ehdr
|
||||
#define Elf_Addr Elf32_Addr
|
||||
#endif
|
||||
|
||||
extern __attribute__((visibility("hidden"))) void original_init(int argc, char **argv, char **env);
|
||||
|
|
|
@ -30,6 +30,5 @@ $(CSRCS): %.c: ../inject.c
|
|||
|
||||
GARBAGE += $(CSRCS)
|
||||
|
||||
DEFINES += -DBITS=$(if $(HAVE_64BIT_OS),64,32)
|
||||
CFLAGS := -O2 -fno-stack-protector $(filter -m% -I%,$(CFLAGS))
|
||||
$(CPU)-noinit.$(OBJ_SUFFIX): DEFINES += -DNOINIT
|
||||
|
|
|
@ -14,14 +14,16 @@ import errno
|
|||
import re
|
||||
import logging
|
||||
from time import localtime
|
||||
from optparse import OptionParser
|
||||
from MozZipFile import ZipFile
|
||||
from cStringIO import StringIO
|
||||
from datetime import datetime
|
||||
|
||||
from utils import pushback_iter, lockFile
|
||||
from mozbuild.util import (
|
||||
lock_file,
|
||||
PushbackIter,
|
||||
)
|
||||
|
||||
from Preprocessor import Preprocessor
|
||||
from buildlist import addEntriesToListFile
|
||||
from mozbuild.action.buildlist import addEntriesToListFile
|
||||
if sys.platform == "win32":
|
||||
from ctypes import windll, WinError
|
||||
CreateHardLink = windll.kernel32.CreateHardLinkA
|
||||
|
@ -174,7 +176,7 @@ class JarMaker(object):
|
|||
'''updateManifest replaces the % in the chrome registration entries
|
||||
with the given chrome base path, and updates the given manifest file.
|
||||
'''
|
||||
lock = lockFile(manifestPath + '.lck')
|
||||
lock = lock_file(manifestPath + '.lck')
|
||||
try:
|
||||
myregister = dict.fromkeys(map(lambda s: s.replace('%', chromebasepath),
|
||||
register.iterkeys()))
|
||||
|
@ -215,7 +217,7 @@ class JarMaker(object):
|
|||
pp = self.pp.clone()
|
||||
pp.out = StringIO()
|
||||
pp.do_include(infile)
|
||||
lines = pushback_iter(pp.out.getvalue().splitlines())
|
||||
lines = PushbackIter(pp.out.getvalue().splitlines())
|
||||
try:
|
||||
while True:
|
||||
l = lines.next()
|
||||
|
@ -252,8 +254,8 @@ class JarMaker(object):
|
|||
'''Internal method called by makeJar to actually process a section
|
||||
of a jar.mn file.
|
||||
|
||||
jarfile is the basename of the jarfile or the directory name for
|
||||
flat output, lines is a pushback_iterator of the lines of jar.mn,
|
||||
jarfile is the basename of the jarfile or the directory name for
|
||||
flat output, lines is a PushbackIter of the lines of jar.mn,
|
||||
the remaining options are carried over from makeJar.
|
||||
'''
|
||||
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
# 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/.
|
||||
|
||||
import zipfile
|
||||
import time
|
||||
import binascii, struct
|
||||
import zlib
|
||||
import os
|
||||
from utils import lockFile
|
||||
import time
|
||||
import zipfile
|
||||
|
||||
from mozbuild.util import lock_file
|
||||
|
||||
|
||||
class ZipFile(zipfile.ZipFile):
|
||||
""" Class with methods to open, read, write, close, list zip files.
|
||||
|
@ -19,7 +19,7 @@ class ZipFile(zipfile.ZipFile):
|
|||
lock = False):
|
||||
if lock:
|
||||
assert isinstance(file, basestring)
|
||||
self.lockfile = lockFile(file + '.lck')
|
||||
self.lockfile = lock_file(file + '.lck')
|
||||
else:
|
||||
self.lockfile = None
|
||||
|
||||
|
|
|
@ -2,12 +2,7 @@ includedir := $(includedir)/$(MOZ_APP_NAME)-$(MOZ_APP_VERSION)
|
|||
idldir = $(datadir)/idl/$(MOZ_APP_NAME)-$(MOZ_APP_VERSION)
|
||||
installdir = $(libdir)/$(MOZ_APP_NAME)-$(MOZ_APP_VERSION)
|
||||
sdkdir = $(libdir)/$(MOZ_APP_NAME)-devel-$(MOZ_APP_VERSION)
|
||||
|
||||
ifndef INCLUDED_FUNCTIONS_MK
|
||||
include $(topsrcdir)/config/makefiles/functions.mk
|
||||
endif
|
||||
|
||||
DIST := $(call core_realpath,$(DEPTH)/dist)
|
||||
DIST = $(DEPTH)/dist
|
||||
|
||||
# We do magic with OBJ_SUFFIX in config.mk, the following ensures we don't
|
||||
# manually use it before config.mk inclusion
|
||||
|
|
|
@ -64,6 +64,10 @@ check-variable = $(if $(filter-out 0 1,$(words $($(x))z)),$(error Spaces are not
|
|||
|
||||
$(foreach x,$(CHECK_VARS),$(check-variable))
|
||||
|
||||
ifndef INCLUDED_FUNCTIONS_MK
|
||||
include $(topsrcdir)/config/makefiles/functions.mk
|
||||
endif
|
||||
|
||||
RM = rm -f
|
||||
|
||||
# LIBXUL_DIST is not defined under js/src, thus we make it mean DIST there.
|
||||
|
|
|
@ -25,8 +25,8 @@ ifdef IS_COMPONENT
|
|||
$(INSTALL) $(IFLAGS2) $(SHARED_LIBRARY) $(FINAL_TARGET)/components
|
||||
$(ELF_DYNSTR_GC) $(FINAL_TARGET)/components/$(SHARED_LIBRARY)
|
||||
ifndef NO_COMPONENTS_MANIFEST
|
||||
@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/chrome.manifest "manifest components/components.manifest"
|
||||
@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/components/components.manifest "binary-component $(SHARED_LIBRARY)"
|
||||
$(call py_action,buildlist,$(FINAL_TARGET)/chrome.manifest "manifest components/components.manifest")
|
||||
$(call py_action,buildlist,$(FINAL_TARGET)/components/components.manifest "binary-component $(SHARED_LIBRARY)")
|
||||
endif
|
||||
endif # IS_COMPONENT
|
||||
endif # SHARED_LIBRARY
|
||||
|
|
|
@ -57,6 +57,8 @@ xpidl_modules := @xpidl_modules@
|
|||
linked_xpt_files := $(addprefix $(idl_xpt_dir)/,$(addsuffix .xpt,$(xpidl_modules)))
|
||||
depends_files := $(foreach root,$(xpidl_modules),$(idl_deps_dir)/$(root).pp)
|
||||
|
||||
GARBAGE += $(linked_xpt_files) $(depends_files)
|
||||
|
||||
xpidl:: $(linked_xpt_files)
|
||||
|
||||
$(linked_xpt_files): $(process_py) $(call mkdir_deps,$(idl_deps_dir) $(dist_include_dir) $(idl_xpt_dir))
|
||||
|
|
|
@ -1314,8 +1314,8 @@ INSTALL_TARGETS += _XPT_NAME
|
|||
|
||||
ifndef NO_INTERFACES_MANIFEST
|
||||
libs:: $(call mkdir_deps,$(FINAL_TARGET)/components)
|
||||
@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/components/interfaces.manifest "interfaces $(XPT_NAME)"
|
||||
@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/chrome.manifest "manifest components/interfaces.manifest"
|
||||
$(call py_action,buildlist,$(FINAL_TARGET)/components/interfaces.manifest "interfaces $(XPT_NAME)")
|
||||
$(call py_action,buildlist,$(FINAL_TARGET)/chrome.manifest "manifest components/interfaces.manifest")
|
||||
endif
|
||||
endif
|
||||
|
||||
|
@ -1351,7 +1351,7 @@ endif
|
|||
EXTRA_MANIFESTS = $(filter %.manifest,$(EXTRA_COMPONENTS) $(EXTRA_PP_COMPONENTS))
|
||||
ifneq (,$(EXTRA_MANIFESTS))
|
||||
libs:: $(call mkdir_deps,$(FINAL_TARGET))
|
||||
$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/chrome.manifest $(patsubst %,"manifest components/%",$(notdir $(EXTRA_MANIFESTS)))
|
||||
$(call py_action,buildlist,$(FINAL_TARGET)/chrome.manifest $(patsubst %,"manifest components/%",$(notdir $(EXTRA_MANIFESTS))))
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
|
|
119
config/utils.py
119
config/utils.py
|
@ -1,119 +0,0 @@
|
|||
# >>sys.stderr, 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/.
|
||||
|
||||
'''Utility methods to be used by python build infrastructure.
|
||||
'''
|
||||
|
||||
import os
|
||||
import errno
|
||||
import sys
|
||||
import time
|
||||
import stat
|
||||
|
||||
class LockFile(object):
|
||||
'''LockFile is used by the lockFile method to hold the lock.
|
||||
|
||||
This object should not be used directly, but only through
|
||||
the lockFile method below.
|
||||
'''
|
||||
def __init__(self, lockfile):
|
||||
self.lockfile = lockfile
|
||||
def __del__(self):
|
||||
while True:
|
||||
try:
|
||||
os.remove(self.lockfile)
|
||||
break
|
||||
except OSError as e:
|
||||
if e.errno == errno.EACCES:
|
||||
# another process probably has the file open, we'll retry.
|
||||
# just a short sleep since we want to drop the lock ASAP
|
||||
# (but we need to let some other process close the file first)
|
||||
time.sleep(0.1)
|
||||
else:
|
||||
# re-raise unknown errors
|
||||
raise
|
||||
|
||||
def lockFile(lockfile, max_wait = 600):
|
||||
'''Create and hold a lockfile of the given name, with the given timeout.
|
||||
|
||||
To release the lock, delete the returned object.
|
||||
'''
|
||||
while True:
|
||||
try:
|
||||
fd = os.open(lockfile, os.O_EXCL | os.O_RDWR | os.O_CREAT)
|
||||
# we created the lockfile, so we're the owner
|
||||
break
|
||||
except OSError as e:
|
||||
if (e.errno == errno.EEXIST or
|
||||
(sys.platform == "win32" and e.errno == errno.EACCES)):
|
||||
pass
|
||||
else:
|
||||
# should not occur
|
||||
raise
|
||||
|
||||
try:
|
||||
# the lock file exists, try to stat it to get its age
|
||||
# and read its contents to report the owner PID
|
||||
f = open(lockfile, "r")
|
||||
s = os.stat(lockfile)
|
||||
except EnvironmentError as e:
|
||||
if e.errno == errno.ENOENT or e.errno == errno.EACCES:
|
||||
# we didn't create the lockfile, so it did exist, but it's
|
||||
# gone now. Just try again
|
||||
continue
|
||||
sys.exit("{0} exists but stat() failed: {1}"
|
||||
.format(lockfile, e.strerror))
|
||||
|
||||
# we didn't create the lockfile and it's still there, check
|
||||
# its age
|
||||
now = int(time.time())
|
||||
if now - s[stat.ST_MTIME] > max_wait:
|
||||
pid = f.readline().rstrip()
|
||||
sys.exit("{0} has been locked for more than "
|
||||
"{1} seconds (PID {2})".format(lockfile, max_wait, pid))
|
||||
|
||||
# it's not been locked too long, wait a while and retry
|
||||
f.close()
|
||||
time.sleep(1)
|
||||
|
||||
# if we get here. we have the lockfile. Convert the os.open file
|
||||
# descriptor into a Python file object and record our PID in it
|
||||
|
||||
f = os.fdopen(fd, "w")
|
||||
f.write("{0}\n".format(os.getpid()))
|
||||
f.close()
|
||||
return LockFile(lockfile)
|
||||
|
||||
class pushback_iter(object):
|
||||
'''Utility iterator that can deal with pushed back elements.
|
||||
|
||||
This behaves like a regular iterable, just that you can call
|
||||
iter.pushback(item)
|
||||
to get the given item as next item in the iteration.
|
||||
'''
|
||||
def __init__(self, iterable):
|
||||
self.it = iter(iterable)
|
||||
self.pushed_back = []
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __nonzero__(self):
|
||||
if self.pushed_back:
|
||||
return True
|
||||
|
||||
try:
|
||||
self.pushed_back.insert(0, self.it.next())
|
||||
except StopIteration:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def next(self):
|
||||
if self.pushed_back:
|
||||
return self.pushed_back.pop()
|
||||
return self.it.next()
|
||||
|
||||
def pushback(self, item):
|
||||
self.pushed_back.append(item)
|
114
configure.in
114
configure.in
|
@ -2498,83 +2498,8 @@ else
|
|||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
dnl Check for int64, uint, and uint_t.
|
||||
dnl ========================================================
|
||||
AC_MSG_CHECKING(for int64)
|
||||
AC_CACHE_VAL(ac_cv_int64,
|
||||
[AC_TRY_COMPILE([#include <stdio.h>
|
||||
#include <sys/types.h>],
|
||||
[int64 foo = 0;],
|
||||
[ac_cv_int64=true],
|
||||
[ac_cv_int64=false])])
|
||||
if test "$ac_cv_int64" = true ; then
|
||||
AC_DEFINE(HAVE_INT64)
|
||||
AC_MSG_RESULT(yes)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
AC_MSG_CHECKING(for uint)
|
||||
AC_CACHE_VAL(ac_cv_uint,
|
||||
[AC_TRY_COMPILE([#include <stdio.h>
|
||||
#include <sys/types.h>],
|
||||
[uint foo = 0;],
|
||||
[ac_cv_uint=true],
|
||||
[ac_cv_uint=false])])
|
||||
if test "$ac_cv_uint" = true ; then
|
||||
AC_DEFINE(HAVE_UINT)
|
||||
AC_MSG_RESULT(yes)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
AC_MSG_CHECKING(for uint_t)
|
||||
AC_CACHE_VAL(ac_cv_uint_t,
|
||||
[AC_TRY_COMPILE([#include <stdio.h>
|
||||
#include <sys/types.h>],
|
||||
[uint_t foo = 0;],
|
||||
[ac_cv_uint_t=true],
|
||||
[ac_cv_uint_t=false])])
|
||||
if test "$ac_cv_uint_t" = true ; then
|
||||
AC_DEFINE(HAVE_UINT_T)
|
||||
AC_MSG_RESULT(yes)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
dnl On the gcc trunk (as of 2001-02-09) _GNU_SOURCE, and thus __USE_GNU,
|
||||
dnl are defined when compiling C++ but not C. Since the result of this
|
||||
dnl test is used only in C++, do it in C++.
|
||||
AC_LANG_CPLUSPLUS
|
||||
|
||||
AC_MSG_CHECKING(for uname.domainname)
|
||||
AC_CACHE_VAL(ac_cv_have_uname_domainname_field,
|
||||
[AC_TRY_COMPILE([#include <sys/utsname.h>],
|
||||
[ struct utsname *res; char *domain;
|
||||
(void)uname(res); if (res != 0) { domain = res->domainname; } ],
|
||||
[ac_cv_have_uname_domainname_field=true],
|
||||
[ac_cv_have_uname_domainname_field=false])])
|
||||
|
||||
if test "$ac_cv_have_uname_domainname_field" = "true"; then
|
||||
AC_DEFINE(HAVE_UNAME_DOMAINNAME_FIELD)
|
||||
AC_MSG_RESULT(yes)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING(for uname.__domainname)
|
||||
AC_CACHE_VAL(ac_cv_have_uname_us_domainname_field,
|
||||
[AC_TRY_COMPILE([#include <sys/utsname.h>],
|
||||
[ struct utsname *res; char *domain;
|
||||
(void)uname(res); if (res != 0) { domain = res->__domainname; } ],
|
||||
[ac_cv_have_uname_us_domainname_field=true],
|
||||
[ac_cv_have_uname_us_domainname_field=false])])
|
||||
|
||||
if test "$ac_cv_have_uname_us_domainname_field" = "true"; then
|
||||
AC_DEFINE(HAVE_UNAME_US_DOMAINNAME_FIELD)
|
||||
AC_MSG_RESULT(yes)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
MOZ_CXX11
|
||||
|
||||
AC_LANG_C
|
||||
|
@ -3146,23 +3071,6 @@ dnl AC_CHECK_LIB(resolv, res_ninit, AC_DEFINE(HAVE_RES_NINIT)))
|
|||
fi
|
||||
|
||||
AC_LANG_CPLUSPLUS
|
||||
AC_CACHE_CHECK(
|
||||
[for gnu_get_libc_version()],
|
||||
ac_cv_func_gnu_get_libc_version,
|
||||
[AC_TRY_LINK([
|
||||
#ifdef HAVE_GNU_LIBC_VERSION_H
|
||||
#include <gnu/libc-version.h>
|
||||
#endif
|
||||
],
|
||||
[const char *glibc_version = gnu_get_libc_version();],
|
||||
[ac_cv_func_gnu_get_libc_version=yes],
|
||||
[ac_cv_func_gnu_get_libc_version=no]
|
||||
)]
|
||||
)
|
||||
|
||||
if test "$ac_cv_func_gnu_get_libc_version" = "yes"; then
|
||||
AC_DEFINE(HAVE_GNU_GET_LIBC_VERSION)
|
||||
fi
|
||||
|
||||
case $target_os in
|
||||
darwin*|mingw*|os2*)
|
||||
|
@ -6978,28 +6886,6 @@ if test -z "$MOZ_MEMORY"; then
|
|||
;;
|
||||
esac
|
||||
else
|
||||
dnl Don't try to run compiler tests on Windows
|
||||
if test "$OS_ARCH" = "WINNT"; then
|
||||
if test -z "$HAVE_64BIT_OS"; then
|
||||
AC_DEFINE_UNQUOTED([MOZ_MEMORY_SIZEOF_PTR_2POW], 2)
|
||||
else
|
||||
AC_DEFINE_UNQUOTED([MOZ_MEMORY_SIZEOF_PTR_2POW], 3)
|
||||
fi
|
||||
else
|
||||
AC_CHECK_SIZEOF([int *], [4])
|
||||
case "${ac_cv_sizeof_int_p}" in
|
||||
4)
|
||||
AC_DEFINE_UNQUOTED([MOZ_MEMORY_SIZEOF_PTR_2POW], 2)
|
||||
;;
|
||||
8)
|
||||
AC_DEFINE_UNQUOTED([MOZ_MEMORY_SIZEOF_PTR_2POW], 3)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([Unexpected pointer size])
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
AC_DEFINE(MOZ_MEMORY)
|
||||
if test -n "$MOZ_JEMALLOC3"; then
|
||||
AC_DEFINE(MOZ_JEMALLOC3)
|
||||
|
|
|
@ -1042,7 +1042,7 @@ CanvasRenderingContext2D::Render(gfxContext *ctx, GraphicsFilter aFilter, uint32
|
|||
if (!(aFlags & RenderFlagPremultAlpha)) {
|
||||
nsRefPtr<gfxASurface> curSurface = ctx->CurrentSurface();
|
||||
nsRefPtr<gfxImageSurface> gis = curSurface->GetAsImageSurface();
|
||||
NS_ABORT_IF_FALSE(gis, "If non-premult alpha, must be able to get image surface!");
|
||||
MOZ_ASSERT(gis, "If non-premult alpha, must be able to get image surface!");
|
||||
|
||||
gfxUtils::UnpremultiplyImageSurface(gis);
|
||||
}
|
||||
|
@ -3584,7 +3584,7 @@ CanvasRenderingContext2D::EnsureErrorTarget()
|
|||
}
|
||||
|
||||
RefPtr<DrawTarget> errorTarget = gfxPlatform::GetPlatform()->CreateOffscreenCanvasDrawTarget(IntSize(1, 1), FORMAT_B8G8R8A8);
|
||||
NS_ABORT_IF_FALSE(errorTarget, "Failed to allocate the error target!");
|
||||
MOZ_ASSERT(errorTarget, "Failed to allocate the error target!");
|
||||
|
||||
sErrorTarget = errorTarget;
|
||||
NS_ADDREF(sErrorTarget);
|
||||
|
|
|
@ -121,8 +121,7 @@ WebGLContext::WebGLContext()
|
|||
|
||||
mShaderValidation = true;
|
||||
|
||||
mBlackTexturesAreInitialized = false;
|
||||
mFakeBlackStatus = DoNotNeedFakeBlack;
|
||||
mFakeBlackStatus = WebGLContextFakeBlackStatus::NotNeeded;
|
||||
|
||||
mVertexAttrib0Vector[0] = 0;
|
||||
mVertexAttrib0Vector[1] = 0;
|
||||
|
@ -134,7 +133,7 @@ WebGLContext::WebGLContext()
|
|||
mFakeVertexAttrib0BufferObjectVector[3] = 1;
|
||||
mFakeVertexAttrib0BufferObjectSize = 0;
|
||||
mFakeVertexAttrib0BufferObject = 0;
|
||||
mFakeVertexAttrib0BufferStatus = VertexAttrib0Status::Default;
|
||||
mFakeVertexAttrib0BufferStatus = WebGLVertexAttrib0Status::Default;
|
||||
|
||||
// these are de default values, see 6.2 State tables in the OpenGL ES 2.0.25 spec
|
||||
mColorWriteMask[0] = 1;
|
||||
|
@ -264,11 +263,10 @@ WebGLContext::DestroyResourcesAndContext()
|
|||
while (!mQueries.isEmpty())
|
||||
mQueries.getLast()->DeleteOnce();
|
||||
|
||||
if (mBlackTexturesAreInitialized) {
|
||||
gl->fDeleteTextures(1, &mBlackTexture2D);
|
||||
gl->fDeleteTextures(1, &mBlackTextureCubeMap);
|
||||
mBlackTexturesAreInitialized = false;
|
||||
}
|
||||
mBlackOpaqueTexture2D = nullptr;
|
||||
mBlackOpaqueTextureCubeMap = nullptr;
|
||||
mBlackTransparentTexture2D = nullptr;
|
||||
mBlackTransparentTextureCubeMap = nullptr;
|
||||
|
||||
if (mFakeVertexAttrib0BufferObject) {
|
||||
gl->fDeleteBuffers(1, &mFakeVertexAttrib0BufferObject);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/Scoped.h"
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include "ForceDiscreteGPUHelperCGL.h"
|
||||
|
@ -83,8 +84,6 @@ namespace gfx {
|
|||
class SourceSurface;
|
||||
}
|
||||
|
||||
using WebGLTexelConversions::WebGLTexelFormat;
|
||||
|
||||
WebGLTexelFormat GetWebGLTexelFormat(GLenum format, GLenum type);
|
||||
|
||||
struct WebGLContextOptions {
|
||||
|
@ -798,15 +797,17 @@ private:
|
|||
// -----------------------------------------------------------------------------
|
||||
// PROTECTED
|
||||
protected:
|
||||
void SetDontKnowIfNeedFakeBlack() {
|
||||
mFakeBlackStatus = DontKnowIfNeedFakeBlack;
|
||||
void SetFakeBlackStatus(WebGLContextFakeBlackStatus x) {
|
||||
mFakeBlackStatus = x;
|
||||
}
|
||||
// Returns the current fake-black-status, except if it was Unknown,
|
||||
// in which case this function resolves it first, so it never returns Unknown.
|
||||
WebGLContextFakeBlackStatus ResolvedFakeBlackStatus();
|
||||
|
||||
bool NeedFakeBlack();
|
||||
void BindFakeBlackTextures();
|
||||
void UnbindFakeBlackTextures();
|
||||
|
||||
int WhatDoesVertexAttrib0Need();
|
||||
WebGLVertexAttrib0Status WhatDoesVertexAttrib0Need();
|
||||
bool DoFakeVertexAttrib0(GLuint vertexCount);
|
||||
void UndoFakeVertexAttrib0();
|
||||
void InvalidateFakeVertexAttrib0();
|
||||
|
@ -1090,16 +1091,35 @@ protected:
|
|||
uint32_t mPixelStorePackAlignment, mPixelStoreUnpackAlignment, mPixelStoreColorspaceConversion;
|
||||
bool mPixelStoreFlipY, mPixelStorePremultiplyAlpha;
|
||||
|
||||
FakeBlackStatus mFakeBlackStatus;
|
||||
WebGLContextFakeBlackStatus mFakeBlackStatus;
|
||||
|
||||
GLuint mBlackTexture2D, mBlackTextureCubeMap;
|
||||
bool mBlackTexturesAreInitialized;
|
||||
class FakeBlackTexture
|
||||
{
|
||||
gl::GLContext* mGL;
|
||||
GLuint mGLName;
|
||||
|
||||
public:
|
||||
FakeBlackTexture(gl::GLContext* gl, GLenum target, GLenum format);
|
||||
~FakeBlackTexture();
|
||||
GLuint GLName() const { return mGLName; }
|
||||
};
|
||||
|
||||
ScopedDeletePtr<FakeBlackTexture> mBlackOpaqueTexture2D,
|
||||
mBlackOpaqueTextureCubeMap,
|
||||
mBlackTransparentTexture2D,
|
||||
mBlackTransparentTextureCubeMap;
|
||||
|
||||
void BindFakeBlackTexturesHelper(
|
||||
GLenum target,
|
||||
const nsTArray<WebGLRefPtr<WebGLTexture> >& boundTexturesArray,
|
||||
ScopedDeletePtr<FakeBlackTexture> & opaqueTextureScopedPtr,
|
||||
ScopedDeletePtr<FakeBlackTexture> & transparentTextureScopedPtr);
|
||||
|
||||
GLfloat mVertexAttrib0Vector[4];
|
||||
GLfloat mFakeVertexAttrib0BufferObjectVector[4];
|
||||
size_t mFakeVertexAttrib0BufferObjectSize;
|
||||
GLuint mFakeVertexAttrib0BufferObject;
|
||||
int mFakeVertexAttrib0BufferStatus;
|
||||
WebGLVertexAttrib0Status mFakeVertexAttrib0BufferStatus;
|
||||
|
||||
GLint mStencilRefFront, mStencilRefBack;
|
||||
GLuint mStencilValueMaskFront, mStencilValueMaskBack,
|
||||
|
|
|
@ -383,8 +383,8 @@ WebGLContext::DeleteBuffer(WebGLBuffer *buffer)
|
|||
}
|
||||
|
||||
for (int32_t i = 0; i < mGLMaxVertexAttribs; i++) {
|
||||
if (mBoundVertexArray->mAttribBuffers[i].buf == buffer)
|
||||
mBoundVertexArray->mAttribBuffers[i].buf = nullptr;
|
||||
if (mBoundVertexArray->HasAttrib(i) && mBoundVertexArray->mAttribs[i].buf == buffer)
|
||||
mBoundVertexArray->mAttribs[i].buf = nullptr;
|
||||
}
|
||||
|
||||
buffer->RequestDelete();
|
||||
|
@ -481,7 +481,7 @@ WebGLContext::CheckedBufferData(GLenum target,
|
|||
} else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
|
||||
boundBuffer = mBoundVertexArray->mBoundElementArrayBuffer;
|
||||
}
|
||||
NS_ABORT_IF_FALSE(boundBuffer != nullptr, "no buffer bound for this target");
|
||||
MOZ_ASSERT(boundBuffer != nullptr, "no buffer bound for this target");
|
||||
|
||||
bool sizeChanges = uint32_t(size) != boundBuffer->ByteLength();
|
||||
if (sizeChanges) {
|
||||
|
|
|
@ -180,6 +180,13 @@ WebGLContext::GetExtension(JSContext *cx, const nsAString& aName, ErrorResult& r
|
|||
else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_depth_texture")) {
|
||||
ext = WEBGL_depth_texture;
|
||||
}
|
||||
|
||||
if (ext != WebGLExtensionID_unknown_extension) {
|
||||
GenerateWarning("getExtension('%s'): MOZ_ prefixed WebGL extension strings are deprecated. "
|
||||
"Support for them will be removed in the future. Use unprefixed extension strings. "
|
||||
"To get draft extensions, set the webgl.enable-draft-extensions preference.",
|
||||
name.get());
|
||||
}
|
||||
}
|
||||
|
||||
if (ext == WebGLExtensionID_unknown_extension) {
|
||||
|
|
|
@ -30,7 +30,7 @@ WebGLContext::Clear(GLbitfield mask)
|
|||
}
|
||||
|
||||
if (mBoundFramebuffer) {
|
||||
if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
|
||||
if (!mBoundFramebuffer->CheckAndInitializeAttachments())
|
||||
return ErrorInvalidFramebufferOperation("clear: incomplete framebuffer");
|
||||
|
||||
gl->fClear(mask);
|
||||
|
|
|
@ -52,15 +52,58 @@ using namespace mozilla::gl;
|
|||
static bool BaseTypeAndSizeFromUniformType(GLenum uType, GLenum *baseType, GLint *unitSize);
|
||||
static GLenum InternalFormatForFormatAndType(GLenum format, GLenum type, bool isGLES2);
|
||||
|
||||
//
|
||||
// WebGL API
|
||||
//
|
||||
|
||||
inline const WebGLRectangleObject *WebGLContext::FramebufferRectangleObject() const {
|
||||
return mBoundFramebuffer ? mBoundFramebuffer->RectangleObject()
|
||||
: static_cast<const WebGLRectangleObject*>(this);
|
||||
}
|
||||
|
||||
WebGLContext::FakeBlackTexture::FakeBlackTexture(GLContext *gl, GLenum target, GLenum format)
|
||||
: mGL(gl)
|
||||
, mGLName(0)
|
||||
{
|
||||
MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D || target == LOCAL_GL_TEXTURE_CUBE_MAP);
|
||||
MOZ_ASSERT(format == LOCAL_GL_RGB || format == LOCAL_GL_RGBA);
|
||||
|
||||
mGL->MakeCurrent();
|
||||
GLuint formerBinding = 0;
|
||||
gl->GetUIntegerv(target == LOCAL_GL_TEXTURE_2D
|
||||
? LOCAL_GL_TEXTURE_BINDING_2D
|
||||
: LOCAL_GL_TEXTURE_BINDING_CUBE_MAP,
|
||||
&formerBinding);
|
||||
gl->fGenTextures(1, &mGLName);
|
||||
gl->fBindTexture(target, mGLName);
|
||||
|
||||
// we allocate our zeros on the heap, and we overallocate (16 bytes instead of 4)
|
||||
// to minimize the risk of running into a driver bug in texImage2D, as it is
|
||||
// a bit unusual maybe to create 1x1 textures, and the stack may not have the alignment
|
||||
// that texImage2D expects.
|
||||
void* zeros = calloc(1, 16);
|
||||
if (target == LOCAL_GL_TEXTURE_2D) {
|
||||
gl->fTexImage2D(target, 0, format, 1, 1,
|
||||
0, format, LOCAL_GL_UNSIGNED_BYTE, zeros);
|
||||
} else {
|
||||
for (GLuint i = 0; i < 6; ++i) {
|
||||
gl->fTexImage2D(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, format, 1, 1,
|
||||
0, format, LOCAL_GL_UNSIGNED_BYTE, zeros);
|
||||
}
|
||||
}
|
||||
free(zeros);
|
||||
|
||||
gl->fBindTexture(target, formerBinding);
|
||||
}
|
||||
|
||||
WebGLContext::FakeBlackTexture::~FakeBlackTexture()
|
||||
{
|
||||
if (mGL) {
|
||||
mGL->MakeCurrent();
|
||||
mGL->fDeleteTextures(1, &mGLName);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// WebGL API
|
||||
//
|
||||
|
||||
void
|
||||
WebGLContext::ActiveTexture(GLenum texture)
|
||||
{
|
||||
|
@ -191,31 +234,47 @@ WebGLContext::BindRenderbuffer(GLenum target, WebGLRenderbuffer *wrb)
|
|||
}
|
||||
|
||||
void
|
||||
WebGLContext::BindTexture(GLenum target, WebGLTexture *tex)
|
||||
WebGLContext::BindTexture(GLenum target, WebGLTexture *newTex)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateObjectAllowDeletedOrNull("bindTexture", tex))
|
||||
if (!ValidateObjectAllowDeletedOrNull("bindTexture", newTex))
|
||||
return;
|
||||
|
||||
// silently ignore a deleted texture
|
||||
if (tex && tex->IsDeleted())
|
||||
if (newTex && newTex->IsDeleted())
|
||||
return;
|
||||
|
||||
WebGLRefPtr<WebGLTexture>* currentTexPtr = nullptr;
|
||||
|
||||
if (target == LOCAL_GL_TEXTURE_2D) {
|
||||
mBound2DTextures[mActiveTexture] = tex;
|
||||
currentTexPtr = &mBound2DTextures[mActiveTexture];
|
||||
} else if (target == LOCAL_GL_TEXTURE_CUBE_MAP) {
|
||||
mBoundCubeMapTextures[mActiveTexture] = tex;
|
||||
currentTexPtr = &mBoundCubeMapTextures[mActiveTexture];
|
||||
} else {
|
||||
return ErrorInvalidEnumInfo("bindTexture: target", target);
|
||||
}
|
||||
|
||||
SetDontKnowIfNeedFakeBlack();
|
||||
WebGLTextureFakeBlackStatus currentTexFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded;
|
||||
if (*currentTexPtr) {
|
||||
currentTexFakeBlackStatus = (*currentTexPtr)->ResolvedFakeBlackStatus();
|
||||
}
|
||||
WebGLTextureFakeBlackStatus newTexFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded;
|
||||
if (newTex) {
|
||||
newTexFakeBlackStatus = newTex->ResolvedFakeBlackStatus();
|
||||
}
|
||||
|
||||
*currentTexPtr = newTex;
|
||||
|
||||
if (currentTexFakeBlackStatus != newTexFakeBlackStatus) {
|
||||
SetFakeBlackStatus(WebGLContextFakeBlackStatus::Unknown);
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
if (tex)
|
||||
tex->Bind(target);
|
||||
if (newTex)
|
||||
newTex->Bind(target);
|
||||
else
|
||||
gl->fBindTexture(target, 0 /* == texturename */);
|
||||
}
|
||||
|
@ -508,7 +567,7 @@ WebGLContext::CopyTexImage2D(GLenum target,
|
|||
return ErrorInvalidOperation("copyTexImage2D: a base internal format of DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
|
||||
|
||||
if (mBoundFramebuffer)
|
||||
if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
|
||||
if (!mBoundFramebuffer->CheckAndInitializeAttachments())
|
||||
return ErrorInvalidFramebufferOperation("copyTexImage2D: incomplete framebuffer");
|
||||
|
||||
WebGLTexture *tex = activeBoundTextureForTarget(target);
|
||||
|
@ -537,12 +596,13 @@ WebGLContext::CopyTexImage2D(GLenum target,
|
|||
if (error) {
|
||||
GenerateWarning("copyTexImage2D generated error %s", ErrorName(error));
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CopyTexSubImage2D_base(target, level, internalformat, 0, 0, x, y, width, height, false);
|
||||
}
|
||||
|
||||
tex->SetImageInfo(target, level, width, height, internalformat, type);
|
||||
|
||||
tex->SetImageInfo(target, level, width, height, internalformat, type,
|
||||
WebGLImageDataStatus::InitializedImageData);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -617,9 +677,13 @@ WebGLContext::CopyTexSubImage2D(GLenum target,
|
|||
return ErrorInvalidOperation("copyTexSubImage2D: a base internal format of DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
|
||||
|
||||
if (mBoundFramebuffer)
|
||||
if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
|
||||
if (!mBoundFramebuffer->CheckAndInitializeAttachments())
|
||||
return ErrorInvalidFramebufferOperation("copyTexSubImage2D: incomplete framebuffer");
|
||||
|
||||
if (imageInfo.HasUninitializedImageData()) {
|
||||
tex->DoDeferredImageInitialization(target, level);
|
||||
}
|
||||
|
||||
return CopyTexSubImage2D_base(target, level, format, xoffset, yoffset, x, y, width, height, true);
|
||||
}
|
||||
|
||||
|
@ -805,7 +869,7 @@ WebGLContext::DepthRange(GLfloat zNear, GLfloat zFar)
|
|||
gl->fDepthRange(zNear, zFar);
|
||||
}
|
||||
|
||||
int
|
||||
WebGLVertexAttrib0Status
|
||||
WebGLContext::WhatDoesVertexAttrib0Need()
|
||||
{
|
||||
// here we may assume that mCurrentProgram != null
|
||||
|
@ -813,24 +877,24 @@ WebGLContext::WhatDoesVertexAttrib0Need()
|
|||
// work around Mac OSX crash, see bug 631420
|
||||
#ifdef XP_MACOSX
|
||||
if (gl->WorkAroundDriverBugs() &&
|
||||
mBoundVertexArray->mAttribBuffers[0].enabled &&
|
||||
mBoundVertexArray->IsAttribArrayEnabled(0) &&
|
||||
!mCurrentProgram->IsAttribInUse(0))
|
||||
{
|
||||
return VertexAttrib0Status::EmulatedUninitializedArray;
|
||||
return WebGLVertexAttrib0Status::EmulatedUninitializedArray;
|
||||
}
|
||||
#endif
|
||||
|
||||
return (gl->IsGLES2() || mBoundVertexArray->mAttribBuffers[0].enabled) ? VertexAttrib0Status::Default
|
||||
: mCurrentProgram->IsAttribInUse(0) ? VertexAttrib0Status::EmulatedInitializedArray
|
||||
: VertexAttrib0Status::EmulatedUninitializedArray;
|
||||
return (gl->IsGLES2() || mBoundVertexArray->IsAttribArrayEnabled(0)) ? WebGLVertexAttrib0Status::Default
|
||||
: mCurrentProgram->IsAttribInUse(0) ? WebGLVertexAttrib0Status::EmulatedInitializedArray
|
||||
: WebGLVertexAttrib0Status::EmulatedUninitializedArray;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::DoFakeVertexAttrib0(GLuint vertexCount)
|
||||
{
|
||||
int whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
|
||||
WebGLVertexAttrib0Status whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
|
||||
|
||||
if (whatDoesAttrib0Need == VertexAttrib0Status::Default)
|
||||
if (whatDoesAttrib0Need == WebGLVertexAttrib0Status::Default)
|
||||
return true;
|
||||
|
||||
if (!mAlreadyWarnedAboutFakeVertexAttrib0) {
|
||||
|
@ -860,8 +924,8 @@ WebGLContext::DoFakeVertexAttrib0(GLuint vertexCount)
|
|||
// we don't need it to be, then consider it OK
|
||||
bool vertexAttrib0BufferStatusOK =
|
||||
mFakeVertexAttrib0BufferStatus == whatDoesAttrib0Need ||
|
||||
(mFakeVertexAttrib0BufferStatus == VertexAttrib0Status::EmulatedInitializedArray &&
|
||||
whatDoesAttrib0Need == VertexAttrib0Status::EmulatedUninitializedArray);
|
||||
(mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray &&
|
||||
whatDoesAttrib0Need == WebGLVertexAttrib0Status::EmulatedUninitializedArray);
|
||||
|
||||
if (!vertexAttrib0BufferStatusOK ||
|
||||
mFakeVertexAttrib0BufferObjectSize < dataSize ||
|
||||
|
@ -882,7 +946,7 @@ WebGLContext::DoFakeVertexAttrib0(GLuint vertexCount)
|
|||
GLenum error = LOCAL_GL_NO_ERROR;
|
||||
UpdateWebGLErrorAndClearGLError();
|
||||
|
||||
if (mFakeVertexAttrib0BufferStatus == VertexAttrib0Status::EmulatedInitializedArray) {
|
||||
if (mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray) {
|
||||
nsAutoArrayPtr<GLfloat> array(new GLfloat[4 * vertexCount]);
|
||||
for(size_t i = 0; i < vertexCount; ++i) {
|
||||
array[4 * i + 0] = mVertexAttrib0Vector[0];
|
||||
|
@ -915,106 +979,120 @@ WebGLContext::DoFakeVertexAttrib0(GLuint vertexCount)
|
|||
void
|
||||
WebGLContext::UndoFakeVertexAttrib0()
|
||||
{
|
||||
int whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
|
||||
WebGLVertexAttrib0Status whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
|
||||
|
||||
if (whatDoesAttrib0Need == VertexAttrib0Status::Default)
|
||||
if (whatDoesAttrib0Need == WebGLVertexAttrib0Status::Default)
|
||||
return;
|
||||
|
||||
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundVertexArray->mAttribBuffers[0].buf ? mBoundVertexArray->mAttribBuffers[0].buf->GLName() : 0);
|
||||
gl->fVertexAttribPointer(0,
|
||||
mBoundVertexArray->mAttribBuffers[0].size,
|
||||
mBoundVertexArray->mAttribBuffers[0].type,
|
||||
mBoundVertexArray->mAttribBuffers[0].normalized,
|
||||
mBoundVertexArray->mAttribBuffers[0].stride,
|
||||
reinterpret_cast<const GLvoid *>(mBoundVertexArray->mAttribBuffers[0].byteOffset));
|
||||
if (mBoundVertexArray->HasAttrib(0) && mBoundVertexArray->mAttribs[0].buf) {
|
||||
const WebGLVertexAttribData& attrib0 = mBoundVertexArray->mAttribs[0];
|
||||
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, attrib0.buf->GLName());
|
||||
gl->fVertexAttribPointer(0,
|
||||
attrib0.size,
|
||||
attrib0.type,
|
||||
attrib0.normalized,
|
||||
attrib0.stride,
|
||||
reinterpret_cast<const GLvoid *>(attrib0.byteOffset));
|
||||
} else {
|
||||
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0);
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::NeedFakeBlack()
|
||||
WebGLContextFakeBlackStatus
|
||||
WebGLContext::ResolvedFakeBlackStatus()
|
||||
{
|
||||
// handle this case first, it's the generic case
|
||||
if (mFakeBlackStatus == DoNotNeedFakeBlack)
|
||||
return false;
|
||||
if (MOZ_LIKELY(mFakeBlackStatus == WebGLContextFakeBlackStatus::NotNeeded))
|
||||
return mFakeBlackStatus;
|
||||
|
||||
if (mFakeBlackStatus == DoNeedFakeBlack)
|
||||
return true;
|
||||
if (mFakeBlackStatus == WebGLContextFakeBlackStatus::Needed)
|
||||
return mFakeBlackStatus;
|
||||
|
||||
for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
|
||||
if ((mBound2DTextures[i] && mBound2DTextures[i]->NeedFakeBlack()) ||
|
||||
(mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->NeedFakeBlack()))
|
||||
if ((mBound2DTextures[i] && mBound2DTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) ||
|
||||
(mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded))
|
||||
{
|
||||
mFakeBlackStatus = DoNeedFakeBlack;
|
||||
return true;
|
||||
mFakeBlackStatus = WebGLContextFakeBlackStatus::Needed;
|
||||
return mFakeBlackStatus;
|
||||
}
|
||||
}
|
||||
|
||||
// we have exhausted all cases where we do need fakeblack, so if the status is still unknown,
|
||||
// that means that we do NOT need it.
|
||||
mFakeBlackStatus = DoNotNeedFakeBlack;
|
||||
return false;
|
||||
mFakeBlackStatus = WebGLContextFakeBlackStatus::NotNeeded;
|
||||
return mFakeBlackStatus;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::BindFakeBlackTexturesHelper(
|
||||
GLenum target,
|
||||
const nsTArray<WebGLRefPtr<WebGLTexture> > & boundTexturesArray,
|
||||
ScopedDeletePtr<FakeBlackTexture> & opaqueTextureScopedPtr,
|
||||
ScopedDeletePtr<FakeBlackTexture> & transparentTextureScopedPtr)
|
||||
{
|
||||
for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
|
||||
if (!boundTexturesArray[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
WebGLTextureFakeBlackStatus s = boundTexturesArray[i]->ResolvedFakeBlackStatus();
|
||||
MOZ_ASSERT(s != WebGLTextureFakeBlackStatus::Unknown);
|
||||
|
||||
if (MOZ_LIKELY(s == WebGLTextureFakeBlackStatus::NotNeeded)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool alpha = s == WebGLTextureFakeBlackStatus::UninitializedImageData &&
|
||||
FormatHasAlpha(boundTexturesArray[i]->ImageInfoBase().Format());
|
||||
ScopedDeletePtr<FakeBlackTexture>&
|
||||
blackTexturePtr = alpha
|
||||
? transparentTextureScopedPtr
|
||||
: opaqueTextureScopedPtr;
|
||||
|
||||
if (!blackTexturePtr) {
|
||||
GLenum format = alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
|
||||
blackTexturePtr
|
||||
= new FakeBlackTexture(gl, target, format);
|
||||
}
|
||||
|
||||
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
|
||||
gl->fBindTexture(target,
|
||||
blackTexturePtr->GLName());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::BindFakeBlackTextures()
|
||||
{
|
||||
// this is the generic case: try to return early
|
||||
if (!NeedFakeBlack())
|
||||
if (MOZ_LIKELY(ResolvedFakeBlackStatus() == WebGLContextFakeBlackStatus::NotNeeded))
|
||||
return;
|
||||
|
||||
if (!mBlackTexturesAreInitialized) {
|
||||
GLuint bound2DTex = 0;
|
||||
GLuint boundCubeTex = 0;
|
||||
gl->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, (GLint*) &bound2DTex);
|
||||
gl->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_CUBE_MAP, (GLint*) &boundCubeTex);
|
||||
|
||||
const uint8_t black[] = {0, 0, 0, 255};
|
||||
|
||||
gl->fGenTextures(1, &mBlackTexture2D);
|
||||
gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mBlackTexture2D);
|
||||
gl->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, 1, 1,
|
||||
0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, &black);
|
||||
|
||||
gl->fGenTextures(1, &mBlackTextureCubeMap);
|
||||
gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, mBlackTextureCubeMap);
|
||||
for (GLuint i = 0; i < 6; ++i) {
|
||||
gl->fTexImage2D(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, LOCAL_GL_RGBA, 1, 1,
|
||||
0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, &black);
|
||||
}
|
||||
|
||||
// Reset bound textures
|
||||
gl->fBindTexture(LOCAL_GL_TEXTURE_2D, bound2DTex);
|
||||
gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, boundCubeTex);
|
||||
|
||||
mBlackTexturesAreInitialized = true;
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
|
||||
if (mBound2DTextures[i] && mBound2DTextures[i]->NeedFakeBlack()) {
|
||||
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
|
||||
gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mBlackTexture2D);
|
||||
}
|
||||
if (mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->NeedFakeBlack()) {
|
||||
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
|
||||
gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, mBlackTextureCubeMap);
|
||||
}
|
||||
}
|
||||
BindFakeBlackTexturesHelper(LOCAL_GL_TEXTURE_2D,
|
||||
mBound2DTextures,
|
||||
mBlackOpaqueTexture2D,
|
||||
mBlackTransparentTexture2D);
|
||||
BindFakeBlackTexturesHelper(LOCAL_GL_TEXTURE_CUBE_MAP,
|
||||
mBoundCubeMapTextures,
|
||||
mBlackOpaqueTextureCubeMap,
|
||||
mBlackTransparentTextureCubeMap);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::UnbindFakeBlackTextures()
|
||||
{
|
||||
// this is the generic case: try to return early
|
||||
if (!NeedFakeBlack())
|
||||
if (MOZ_LIKELY(ResolvedFakeBlackStatus() == WebGLContextFakeBlackStatus::NotNeeded))
|
||||
return;
|
||||
|
||||
for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
|
||||
if (mBound2DTextures[i] && mBound2DTextures[i]->NeedFakeBlack()) {
|
||||
if (mBound2DTextures[i] && mBound2DTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) {
|
||||
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
|
||||
gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mBound2DTextures[i]->GLName());
|
||||
}
|
||||
if (mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->NeedFakeBlack()) {
|
||||
if (mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) {
|
||||
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
|
||||
gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, mBoundCubeMapTextures[i]->GLName());
|
||||
}
|
||||
|
@ -1951,7 +2029,7 @@ WebGLContext::IsTexture(WebGLTexture *tex)
|
|||
// Try to bind an attribute that is an array to location 0:
|
||||
bool WebGLContext::BindArrayAttribToLocation0(WebGLProgram *program)
|
||||
{
|
||||
if (mBoundVertexArray->mAttribBuffers[0].enabled) {
|
||||
if (mBoundVertexArray->IsAttribArrayEnabled(0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1962,7 +2040,7 @@ bool WebGLContext::BindArrayAttribToLocation0(WebGLProgram *program)
|
|||
itr != program->mActiveAttribMap.end();
|
||||
itr++) {
|
||||
int32_t index = itr->first;
|
||||
if (mBoundVertexArray->mAttribBuffers[index].enabled &&
|
||||
if (mBoundVertexArray->IsAttribArrayEnabled(index) &&
|
||||
index < leastArrayLocation)
|
||||
{
|
||||
leastArrayLocation = index;
|
||||
|
@ -2084,7 +2162,7 @@ WebGLContext::LinkProgram(WebGLProgram *program)
|
|||
shaderTypeName = "fragment";
|
||||
} else {
|
||||
// should have been validated earlier
|
||||
NS_ABORT();
|
||||
MOZ_ASSERT(false);
|
||||
shaderTypeName = "<unknown>";
|
||||
}
|
||||
|
||||
|
@ -2254,7 +2332,7 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
|||
|
||||
if (mBoundFramebuffer) {
|
||||
// prevent readback of arbitrary video memory through uninitialized renderbuffers!
|
||||
if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
|
||||
if (!mBoundFramebuffer->CheckAndInitializeAttachments())
|
||||
return ErrorInvalidFramebufferOperation("readPixels: incomplete framebuffer");
|
||||
}
|
||||
// Now that the errors are out of the way, on to actually reading
|
||||
|
@ -2440,7 +2518,7 @@ WebGLContext::RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei
|
|||
mBoundRenderbuffer->SetInternalFormat(internalformat);
|
||||
mBoundRenderbuffer->SetInternalFormatForGL(internalformatForGL);
|
||||
mBoundRenderbuffer->setDimensions(width, height);
|
||||
mBoundRenderbuffer->SetInitialized(false);
|
||||
mBoundRenderbuffer->SetImageDataStatus(WebGLImageDataStatus::UninitializedImageData);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2589,16 +2667,16 @@ WebGLContext::SurfaceFromElementResultToImageSurface(nsLayoutUtils::SurfaceFromE
|
|||
|
||||
switch (surf->Format()) {
|
||||
case gfxImageFormatARGB32:
|
||||
*format = WebGLTexelConversions::BGRA8; // careful, our ARGB means BGRA
|
||||
*format = WebGLTexelFormat::BGRA8; // careful, our ARGB means BGRA
|
||||
break;
|
||||
case gfxImageFormatRGB24:
|
||||
*format = WebGLTexelConversions::BGRX8; // careful, our RGB24 is not tightly packed. Whence BGRX8.
|
||||
*format = WebGLTexelFormat::BGRX8; // careful, our RGB24 is not tightly packed. Whence BGRX8.
|
||||
break;
|
||||
case gfxImageFormatA8:
|
||||
*format = WebGLTexelConversions::A8;
|
||||
*format = WebGLTexelFormat::A8;
|
||||
break;
|
||||
case gfxImageFormatRGB16_565:
|
||||
*format = WebGLTexelConversions::RGB565;
|
||||
*format = WebGLTexelFormat::RGB565;
|
||||
break;
|
||||
default:
|
||||
NS_ASSERTION(false, "Unsupported image format. Unimplemented.");
|
||||
|
@ -3303,7 +3381,8 @@ WebGLContext::CompressedTexImage2D(GLenum target, GLint level, GLenum internalfo
|
|||
}
|
||||
|
||||
gl->fCompressedTexImage2D(target, level, internalformat, width, height, border, byteLength, view.Data());
|
||||
tex->SetImageInfo(target, level, width, height, internalformat, LOCAL_GL_UNSIGNED_BYTE);
|
||||
tex->SetImageInfo(target, level, width, height, internalformat, LOCAL_GL_UNSIGNED_BYTE,
|
||||
WebGLImageDataStatus::InitializedImageData);
|
||||
|
||||
ReattachTextureToAnyFramebufferToWorkAroundBugs(tex, level);
|
||||
}
|
||||
|
@ -3401,6 +3480,10 @@ WebGLContext::CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset,
|
|||
}
|
||||
}
|
||||
|
||||
if (imageInfo.HasUninitializedImageData()) {
|
||||
tex->DoDeferredImageInitialization(target, level);
|
||||
}
|
||||
|
||||
gl->fCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, byteLength, view.Data());
|
||||
|
||||
return;
|
||||
|
@ -3588,7 +3671,7 @@ GLenum WebGLContext::CheckedTexImage2D(GLenum target,
|
|||
const GLvoid *data)
|
||||
{
|
||||
WebGLTexture *tex = activeBoundTextureForTarget(target);
|
||||
NS_ABORT_IF_FALSE(tex != nullptr, "no texture bound");
|
||||
MOZ_ASSERT(tex != nullptr, "no texture bound");
|
||||
|
||||
bool sizeMayChange = true;
|
||||
|
||||
|
@ -3676,7 +3759,7 @@ WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat,
|
|||
return;
|
||||
|
||||
WebGLTexelFormat dstFormat = GetWebGLTexelFormat(format, type);
|
||||
WebGLTexelFormat actualSrcFormat = srcFormat == WebGLTexelConversions::Auto ? dstFormat : srcFormat;
|
||||
WebGLTexelFormat actualSrcFormat = srcFormat == WebGLTexelFormat::Auto ? dstFormat : srcFormat;
|
||||
|
||||
uint32_t srcTexelSize = WebGLTexelConversions::TexelBytesForFormat(actualSrcFormat);
|
||||
|
||||
|
@ -3710,6 +3793,8 @@ WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat,
|
|||
|
||||
GLenum error = LOCAL_GL_NO_ERROR;
|
||||
|
||||
WebGLImageDataStatus imageInfoStatusIfSuccess = WebGLImageDataStatus::NoImageData;
|
||||
|
||||
if (byteLength) {
|
||||
size_t srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
|
||||
|
||||
|
@ -3737,76 +3822,11 @@ WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat,
|
|||
error = CheckedTexImage2D(target, level, internalformat,
|
||||
width, height, border, format, type, convertedData);
|
||||
}
|
||||
imageInfoStatusIfSuccess = WebGLImageDataStatus::InitializedImageData;
|
||||
} else {
|
||||
if (isDepthTexture && !gl->IsSupported(GLFeature::depth_texture)) {
|
||||
// There's only one way that we can we supporting depth textures without
|
||||
// supporting the regular depth_texture feature set: that's
|
||||
// with ANGLE_depth_texture.
|
||||
|
||||
// It should be impossible to get here without ANGLE_depth_texture support
|
||||
MOZ_ASSERT(gl->IsExtensionSupported(GLContext::ANGLE_depth_texture));
|
||||
// It should be impossible to get here with a target other than TEXTURE_2D,
|
||||
// a nonzero level, or non-null data
|
||||
MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D && level == 0 && data == nullptr);
|
||||
|
||||
// We start by calling texImage2D with null data, giving us an uninitialized texture,
|
||||
// which is all it can give us in this case.
|
||||
error = CheckedTexImage2D(LOCAL_GL_TEXTURE_2D, 0, internalformat, width, height,
|
||||
border, format, type, nullptr);
|
||||
|
||||
// We then proceed to initializing the texture by assembling a FBO.
|
||||
// We make it a color-less FBO, which isn't supported everywhere, but we should be
|
||||
// fine because we only need this to be successful on ANGLE which is said to support
|
||||
// that. Still, we want to gracefully handle failure in case the FBO is incomplete.
|
||||
|
||||
bool success = false;
|
||||
GLuint fb = 0;
|
||||
|
||||
// dummy do {...} while to be able to break
|
||||
do {
|
||||
gl->fGenFramebuffers(1, &fb);
|
||||
if (!fb)
|
||||
break;
|
||||
|
||||
ScopedBindFramebuffer autoBindFB(gl, fb);
|
||||
|
||||
gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
|
||||
LOCAL_GL_DEPTH_ATTACHMENT,
|
||||
LOCAL_GL_TEXTURE_2D,
|
||||
tex->GLName(),
|
||||
0);
|
||||
if (format == LOCAL_GL_DEPTH_STENCIL) {
|
||||
gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
|
||||
LOCAL_GL_STENCIL_ATTACHMENT,
|
||||
LOCAL_GL_TEXTURE_2D,
|
||||
tex->GLName(),
|
||||
0);
|
||||
}
|
||||
if (gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) != LOCAL_GL_FRAMEBUFFER_COMPLETE)
|
||||
break;
|
||||
|
||||
gl->ClearSafely();
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
gl->fDeleteFramebuffers(1, &fb);
|
||||
|
||||
if (!success) {
|
||||
return ErrorOutOfMemory("texImage2D: sorry, ran out of ways to initialize a depth texture.");
|
||||
}
|
||||
} else {
|
||||
// We need some zero pages, because GL doesn't guarantee the
|
||||
// contents of a texture allocated with nullptr data.
|
||||
// Hopefully calloc will just mmap zero pages here.
|
||||
void *tempZeroData = calloc(1, bytesNeeded);
|
||||
if (!tempZeroData)
|
||||
return ErrorOutOfMemory("texImage2D: could not allocate %d bytes (for zero fill)", bytesNeeded);
|
||||
|
||||
error = CheckedTexImage2D(target, level, internalformat,
|
||||
width, height, border, format, type, tempZeroData);
|
||||
|
||||
free(tempZeroData);
|
||||
}
|
||||
error = CheckedTexImage2D(target, level, internalformat,
|
||||
width, height, border, format, type, nullptr);
|
||||
imageInfoStatusIfSuccess = WebGLImageDataStatus::UninitializedImageData;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
|
@ -3814,7 +3834,12 @@ WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat,
|
|||
return;
|
||||
}
|
||||
|
||||
tex->SetImageInfo(target, level, width, height, format, type);
|
||||
// in all of the code paths above, we should have either initialized data,
|
||||
// or allocated data and left it uninitialized, but in any case we shouldn't
|
||||
// have NoImageData at this point.
|
||||
MOZ_ASSERT(imageInfoStatusIfSuccess != WebGLImageDataStatus::NoImageData);
|
||||
|
||||
tex->SetImageInfo(target, level, width, height, format, type, imageInfoStatusIfSuccess);
|
||||
|
||||
ReattachTextureToAnyFramebufferToWorkAroundBugs(tex, level);
|
||||
}
|
||||
|
@ -3832,7 +3857,7 @@ WebGLContext::TexImage2D(GLenum target, GLint level,
|
|||
pixels.IsNull() ? 0 : pixels.Value().Data(),
|
||||
pixels.IsNull() ? 0 : pixels.Value().Length(),
|
||||
pixels.IsNull() ? -1 : (int)JS_GetArrayBufferViewType(pixels.Value().Obj()),
|
||||
WebGLTexelConversions::Auto, false);
|
||||
WebGLTexelFormat::Auto, false);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -3852,7 +3877,7 @@ WebGLContext::TexImage2D(GLenum target, GLint level,
|
|||
return TexImage2D_base(target, level, internalformat, pixels->Width(),
|
||||
pixels->Height(), 4*pixels->Width(), 0,
|
||||
format, type, arr.Data(), arr.Length(), -1,
|
||||
WebGLTexelConversions::RGBA8, false);
|
||||
WebGLTexelFormat::RGBA8, false);
|
||||
}
|
||||
|
||||
|
||||
|
@ -3898,7 +3923,7 @@ WebGLContext::TexSubImage2D_base(GLenum target, GLint level,
|
|||
return;
|
||||
|
||||
WebGLTexelFormat dstFormat = GetWebGLTexelFormat(format, type);
|
||||
WebGLTexelFormat actualSrcFormat = srcFormat == WebGLTexelConversions::Auto ? dstFormat : srcFormat;
|
||||
WebGLTexelFormat actualSrcFormat = srcFormat == WebGLTexelFormat::Auto ? dstFormat : srcFormat;
|
||||
|
||||
uint32_t srcTexelSize = WebGLTexelConversions::TexelBytesForFormat(actualSrcFormat);
|
||||
|
||||
|
@ -3937,6 +3962,10 @@ WebGLContext::TexSubImage2D_base(GLenum target, GLint level,
|
|||
if (imageInfo.Format() != format || imageInfo.Type() != type)
|
||||
return ErrorInvalidOperation("texSubImage2D: format or type doesn't match the existing texture");
|
||||
|
||||
if (imageInfo.HasUninitializedImageData()) {
|
||||
tex->DoDeferredImageInitialization(target, level);
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
size_t srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
|
||||
|
@ -3984,7 +4013,7 @@ WebGLContext::TexSubImage2D(GLenum target, GLint level,
|
|||
width, height, 0, format, type,
|
||||
pixels.Value().Data(), pixels.Value().Length(),
|
||||
JS_GetArrayBufferViewType(pixels.Value().Obj()),
|
||||
WebGLTexelConversions::Auto, false);
|
||||
WebGLTexelFormat::Auto, false);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -4005,7 +4034,7 @@ WebGLContext::TexSubImage2D(GLenum target, GLint level,
|
|||
4*pixels->Width(), format, type,
|
||||
arr.Data(), arr.Length(),
|
||||
-1,
|
||||
WebGLTexelConversions::RGBA8, false);
|
||||
WebGLTexelFormat::RGBA8, false);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -4109,16 +4138,16 @@ WebGLTexelFormat mozilla::GetWebGLTexelFormat(GLenum format, GLenum type)
|
|||
if (format == LOCAL_GL_DEPTH_COMPONENT) {
|
||||
switch (type) {
|
||||
case LOCAL_GL_UNSIGNED_SHORT:
|
||||
return WebGLTexelConversions::D16;
|
||||
return WebGLTexelFormat::D16;
|
||||
case LOCAL_GL_UNSIGNED_INT:
|
||||
return WebGLTexelConversions::D32;
|
||||
return WebGLTexelFormat::D32;
|
||||
default:
|
||||
MOZ_CRASH("Invalid WebGL texture format/type?");
|
||||
}
|
||||
} else if (format == LOCAL_GL_DEPTH_STENCIL) {
|
||||
switch (type) {
|
||||
case LOCAL_GL_UNSIGNED_INT_24_8_EXT:
|
||||
return WebGLTexelConversions::D24S8;
|
||||
return WebGLTexelFormat::D24S8;
|
||||
default:
|
||||
MOZ_CRASH("Invalid WebGL texture format/type?");
|
||||
}
|
||||
|
@ -4128,47 +4157,47 @@ WebGLTexelFormat mozilla::GetWebGLTexelFormat(GLenum format, GLenum type)
|
|||
if (type == LOCAL_GL_UNSIGNED_BYTE) {
|
||||
switch (format) {
|
||||
case LOCAL_GL_RGBA:
|
||||
return WebGLTexelConversions::RGBA8;
|
||||
return WebGLTexelFormat::RGBA8;
|
||||
case LOCAL_GL_RGB:
|
||||
return WebGLTexelConversions::RGB8;
|
||||
return WebGLTexelFormat::RGB8;
|
||||
case LOCAL_GL_ALPHA:
|
||||
return WebGLTexelConversions::A8;
|
||||
return WebGLTexelFormat::A8;
|
||||
case LOCAL_GL_LUMINANCE:
|
||||
return WebGLTexelConversions::R8;
|
||||
return WebGLTexelFormat::R8;
|
||||
case LOCAL_GL_LUMINANCE_ALPHA:
|
||||
return WebGLTexelConversions::RA8;
|
||||
return WebGLTexelFormat::RA8;
|
||||
default:
|
||||
NS_ABORT_IF_FALSE(false, "Coding mistake?! Should never reach this point.");
|
||||
return WebGLTexelConversions::BadFormat;
|
||||
MOZ_ASSERT(false, "Coding mistake?! Should never reach this point.");
|
||||
return WebGLTexelFormat::BadFormat;
|
||||
}
|
||||
} else if (type == LOCAL_GL_FLOAT) {
|
||||
// OES_texture_float
|
||||
switch (format) {
|
||||
case LOCAL_GL_RGBA:
|
||||
return WebGLTexelConversions::RGBA32F;
|
||||
return WebGLTexelFormat::RGBA32F;
|
||||
case LOCAL_GL_RGB:
|
||||
return WebGLTexelConversions::RGB32F;
|
||||
return WebGLTexelFormat::RGB32F;
|
||||
case LOCAL_GL_ALPHA:
|
||||
return WebGLTexelConversions::A32F;
|
||||
return WebGLTexelFormat::A32F;
|
||||
case LOCAL_GL_LUMINANCE:
|
||||
return WebGLTexelConversions::R32F;
|
||||
return WebGLTexelFormat::R32F;
|
||||
case LOCAL_GL_LUMINANCE_ALPHA:
|
||||
return WebGLTexelConversions::RA32F;
|
||||
return WebGLTexelFormat::RA32F;
|
||||
default:
|
||||
NS_ABORT_IF_FALSE(false, "Coding mistake?! Should never reach this point.");
|
||||
return WebGLTexelConversions::BadFormat;
|
||||
MOZ_ASSERT(false, "Coding mistake?! Should never reach this point.");
|
||||
return WebGLTexelFormat::BadFormat;
|
||||
}
|
||||
} else {
|
||||
switch (type) {
|
||||
case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
|
||||
return WebGLTexelConversions::RGBA4444;
|
||||
return WebGLTexelFormat::RGBA4444;
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
|
||||
return WebGLTexelConversions::RGBA5551;
|
||||
return WebGLTexelFormat::RGBA5551;
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
|
||||
return WebGLTexelConversions::RGB565;
|
||||
return WebGLTexelFormat::RGB565;
|
||||
default:
|
||||
NS_ABORT_IF_FALSE(false, "Coding mistake?! Should never reach this point.");
|
||||
return WebGLTexelConversions::BadFormat;
|
||||
MOZ_ASSERT(false, "Coding mistake?! Should never reach this point.");
|
||||
return WebGLTexelFormat::BadFormat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -189,7 +189,7 @@ WebGLContext::ErrorName(GLenum error)
|
|||
case LOCAL_GL_NO_ERROR:
|
||||
return "NO_ERROR";
|
||||
default:
|
||||
NS_ABORT();
|
||||
MOZ_ASSERT(false);
|
||||
return "[unknown WebGL error!]";
|
||||
}
|
||||
}
|
||||
|
@ -221,8 +221,7 @@ WebGLContext::IsTextureFormatCompressed(GLenum format)
|
|||
return true;
|
||||
}
|
||||
|
||||
NS_NOTREACHED("Invalid WebGL texture format?");
|
||||
NS_ABORT();
|
||||
MOZ_ASSERT(false, "Invalid WebGL texture format?");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ WebGLProgram::UpdateInfo()
|
|||
mContext->gl->fGetActiveAttrib(mGLName, i, mAttribMaxNameLength, &attrnamelen, &attrsize, &attrtype, nameBuf);
|
||||
if (attrnamelen > 0) {
|
||||
GLint loc = mContext->gl->fGetAttribLocation(mGLName, nameBuf);
|
||||
NS_ABORT_IF_FALSE(loc >= 0, "major oops in managing the attributes of a WebGL program");
|
||||
MOZ_ASSERT(loc >= 0, "major oops in managing the attributes of a WebGL program");
|
||||
if (loc < mContext->mGLMaxVertexAttribs) {
|
||||
mAttribsInUse[loc] = true;
|
||||
} else {
|
||||
|
@ -491,7 +491,7 @@ uint32_t WebGLContext::GetBitsPerTexel(GLenum format, GLenum type)
|
|||
return 16;
|
||||
}
|
||||
|
||||
NS_ABORT();
|
||||
MOZ_ASSERT(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -766,7 +766,7 @@ WebGLContext::ValidateUniformSetter(const char* name, WebGLUniformLocation *loca
|
|||
|
||||
bool WebGLContext::ValidateAttribIndex(GLuint index, const char *info)
|
||||
{
|
||||
return mBoundVertexArray->EnsureAttribIndex(index, info);
|
||||
return mBoundVertexArray->EnsureAttrib(index, info);
|
||||
}
|
||||
|
||||
bool WebGLContext::ValidateStencilParamsForDrawCall()
|
||||
|
@ -998,7 +998,7 @@ WebGLContext::InitAndValidateGL()
|
|||
}
|
||||
|
||||
mDefaultVertexArray = new WebGLVertexArray(this);
|
||||
mDefaultVertexArray->mAttribBuffers.SetLength(mGLMaxVertexAttribs);
|
||||
mDefaultVertexArray->mAttribs.SetLength(mGLMaxVertexAttribs);
|
||||
mBoundVertexArray = mDefaultVertexArray;
|
||||
|
||||
return true;
|
||||
|
|
|
@ -196,7 +196,8 @@ WebGLContext::EnableVertexAttribArray(GLuint index)
|
|||
InvalidateBufferFetching();
|
||||
|
||||
gl->fEnableVertexAttribArray(index);
|
||||
mBoundVertexArray->mAttribBuffers[index].enabled = true;
|
||||
MOZ_ASSERT(mBoundVertexArray->HasAttrib(index)); // should have been validated earlier
|
||||
mBoundVertexArray->mAttribs[index].enabled = true;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -214,7 +215,8 @@ WebGLContext::DisableVertexAttribArray(GLuint index)
|
|||
if (index || gl->IsGLES2())
|
||||
gl->fDisableVertexAttribArray(index);
|
||||
|
||||
mBoundVertexArray->mAttribBuffers[index].enabled = false;
|
||||
MOZ_ASSERT(mBoundVertexArray->HasAttrib(index)); // should have been validated earlier
|
||||
mBoundVertexArray->mAttribs[index].enabled = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -225,7 +227,7 @@ WebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname,
|
|||
if (IsContextLost())
|
||||
return JS::NullValue();
|
||||
|
||||
if (!mBoundVertexArray->EnsureAttribIndex(index, "getVertexAttrib"))
|
||||
if (!ValidateAttribIndex(index, "getVertexAttrib"))
|
||||
return JS::NullValue();
|
||||
|
||||
MakeContextCurrent();
|
||||
|
@ -233,12 +235,12 @@ WebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname,
|
|||
switch (pname) {
|
||||
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
|
||||
{
|
||||
return WebGLObjectAsJSValue(cx, mBoundVertexArray->mAttribBuffers[index].buf.get(), rv);
|
||||
return WebGLObjectAsJSValue(cx, mBoundVertexArray->mAttribs[index].buf.get(), rv);
|
||||
}
|
||||
|
||||
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE:
|
||||
{
|
||||
return JS::Int32Value(mBoundVertexArray->mAttribBuffers[index].stride);
|
||||
return JS::Int32Value(mBoundVertexArray->mAttribs[index].stride);
|
||||
}
|
||||
|
||||
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE:
|
||||
|
@ -246,7 +248,7 @@ WebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname,
|
|||
if (!ValidateAttribIndex(index, "getVertexAttrib"))
|
||||
return JS::NullValue();
|
||||
|
||||
if (!mBoundVertexArray->mAttribBuffers[index].enabled)
|
||||
if (!mBoundVertexArray->mAttribs[index].enabled)
|
||||
return JS::Int32Value(4);
|
||||
|
||||
// Don't break; fall through.
|
||||
|
@ -265,7 +267,7 @@ WebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname,
|
|||
{
|
||||
if (IsExtensionEnabled(ANGLE_instanced_arrays))
|
||||
{
|
||||
return JS::Int32Value(mBoundVertexArray->mAttribBuffers[index].divisor);
|
||||
return JS::Int32Value(mBoundVertexArray->mAttribs[index].divisor);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -290,12 +292,12 @@ WebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname,
|
|||
|
||||
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED:
|
||||
{
|
||||
return JS::BooleanValue(mBoundVertexArray->mAttribBuffers[index].enabled);
|
||||
return JS::BooleanValue(mBoundVertexArray->mAttribs[index].enabled);
|
||||
}
|
||||
|
||||
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
|
||||
{
|
||||
return JS::BooleanValue(mBoundVertexArray->mAttribBuffers[index].normalized);
|
||||
return JS::BooleanValue(mBoundVertexArray->mAttribs[index].normalized);
|
||||
}
|
||||
|
||||
default:
|
||||
|
@ -321,7 +323,7 @@ WebGLContext::GetVertexAttribOffset(GLuint index, GLenum pname)
|
|||
return 0;
|
||||
}
|
||||
|
||||
return mBoundVertexArray->mAttribBuffers[index].byteOffset;
|
||||
return mBoundVertexArray->mAttribs[index].byteOffset;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -356,7 +358,7 @@ WebGLContext::VertexAttribPointer(GLuint index, GLint size, GLenum type,
|
|||
// requiredAlignment should always be a power of two.
|
||||
GLsizei requiredAlignmentMask = requiredAlignment - 1;
|
||||
|
||||
if ( !mBoundVertexArray->EnsureAttribIndex(index, "vertexAttribPointer") ) {
|
||||
if (!ValidateAttribIndex(index, "vertexAttribPointer")) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -387,7 +389,7 @@ WebGLContext::VertexAttribPointer(GLuint index, GLint size, GLenum type,
|
|||
return ErrorInvalidOperation("vertexAttribPointer: type must match bound VBO type: %d != %d", type, mBoundArrayBuffer->GLType());
|
||||
*/
|
||||
|
||||
WebGLVertexAttribData &vd = mBoundVertexArray->mAttribBuffers[index];
|
||||
WebGLVertexAttribData &vd = mBoundVertexArray->mAttribs[index];
|
||||
|
||||
vd.buf = mBoundArrayBuffer;
|
||||
vd.stride = stride;
|
||||
|
@ -409,11 +411,11 @@ WebGLContext::VertexAttribDivisor(GLuint index, GLuint divisor)
|
|||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if ( !mBoundVertexArray->EnsureAttribIndex(index, "vertexAttribDivisor") ) {
|
||||
if (!ValidateAttribIndex(index, "vertexAttribDivisor")) {
|
||||
return;
|
||||
}
|
||||
|
||||
WebGLVertexAttribData& vd = mBoundVertexArray->mAttribBuffers[index];
|
||||
WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[index];
|
||||
vd.divisor = divisor;
|
||||
|
||||
InvalidateBufferFetching();
|
||||
|
@ -498,7 +500,7 @@ bool WebGLContext::DrawArrays_check(GLint first, GLsizei count, GLsizei primcoun
|
|||
MakeContextCurrent();
|
||||
|
||||
if (mBoundFramebuffer) {
|
||||
if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers()) {
|
||||
if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
|
||||
ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
|
||||
return false;
|
||||
}
|
||||
|
@ -655,7 +657,7 @@ WebGLContext::DrawElements_check(GLsizei count, GLenum type, WebGLintptr byteOff
|
|||
MakeContextCurrent();
|
||||
|
||||
if (mBoundFramebuffer) {
|
||||
if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers()) {
|
||||
if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
|
||||
ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
|
||||
return false;
|
||||
}
|
||||
|
@ -756,10 +758,10 @@ WebGLContext::ValidateBufferFetching(const char *info)
|
|||
bool hasPerVertex = false;
|
||||
uint32_t maxVertices = UINT32_MAX;
|
||||
uint32_t maxInstances = UINT32_MAX;
|
||||
uint32_t attribs = mBoundVertexArray->mAttribBuffers.Length();
|
||||
uint32_t attribs = mBoundVertexArray->mAttribs.Length();
|
||||
|
||||
for (uint32_t i = 0; i < attribs; ++i) {
|
||||
const WebGLVertexAttribData& vd = mBoundVertexArray->mAttribBuffers[i];
|
||||
const WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[i];
|
||||
|
||||
// If the attrib array isn't enabled, there's nothing to check;
|
||||
// it's a static value.
|
||||
|
|
|
@ -51,11 +51,7 @@ WebGLFramebuffer::Attachment::HasAlpha() const {
|
|||
format = Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).Format();
|
||||
else if (Renderbuffer())
|
||||
format = Renderbuffer()->InternalFormat();
|
||||
return format == LOCAL_GL_RGBA ||
|
||||
format == LOCAL_GL_LUMINANCE_ALPHA ||
|
||||
format == LOCAL_GL_ALPHA ||
|
||||
format == LOCAL_GL_RGBA4 ||
|
||||
format == LOCAL_GL_RGB5_A1;
|
||||
return FormatHasAlpha(format);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -67,8 +63,27 @@ WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture *tex, GLenum target, GLin
|
|||
}
|
||||
|
||||
bool
|
||||
WebGLFramebuffer::Attachment::HasUninitializedRenderbuffer() const {
|
||||
return mRenderbufferPtr && !mRenderbufferPtr->Initialized();
|
||||
WebGLFramebuffer::Attachment::HasUninitializedImageData() const {
|
||||
if (mRenderbufferPtr) {
|
||||
return mRenderbufferPtr->HasUninitializedImageData();
|
||||
} else if (mTexturePtr) {
|
||||
if (!mTexturePtr->HasImageInfoAt(mTexImageTarget, mTexImageLevel))
|
||||
return false;
|
||||
return mTexturePtr->ImageInfoAt(mTexImageTarget, mTexImageLevel).HasUninitializedImageData();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLFramebuffer::Attachment::SetImageDataStatus(WebGLImageDataStatus newStatus) {
|
||||
if (mRenderbufferPtr) {
|
||||
mRenderbufferPtr->SetImageDataStatus(newStatus);
|
||||
} else if (mTexturePtr) {
|
||||
mTexturePtr->SetImageDataStatus(mTexImageTarget, mTexImageLevel, newStatus);
|
||||
} else {
|
||||
MOZ_ASSERT(false); // should not get here, worth crashing a debug build.
|
||||
}
|
||||
}
|
||||
|
||||
const WebGLRectangleObject*
|
||||
|
@ -143,7 +158,7 @@ WebGLFramebuffer::Attachment::IsComplete() const {
|
|||
MOZ_CRASH("Invalid WebGL attachment poin?");
|
||||
}
|
||||
|
||||
NS_ABORT(); // should never get there
|
||||
MOZ_ASSERT(false); // should never get there
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -315,14 +330,14 @@ WebGLFramebuffer::GetAttachment(GLenum attachment) const {
|
|||
return mStencilAttachment;
|
||||
|
||||
if (!CheckColorAttachementNumber(attachment, "getAttachment")) {
|
||||
NS_ABORT();
|
||||
MOZ_ASSERT(false);
|
||||
return mColorAttachments[0];
|
||||
}
|
||||
|
||||
uint32_t colorAttachmentId = uint32_t(attachment - LOCAL_GL_COLOR_ATTACHMENT0);
|
||||
|
||||
if (colorAttachmentId >= mColorAttachments.Length()) {
|
||||
NS_ABORT();
|
||||
MOZ_ASSERT(false);
|
||||
return mColorAttachments[0];
|
||||
}
|
||||
|
||||
|
@ -368,7 +383,7 @@ WebGLFramebuffer::DetachRenderbuffer(const WebGLRenderbuffer *rb) {
|
|||
}
|
||||
|
||||
bool
|
||||
WebGLFramebuffer::CheckAndInitializeRenderbuffers()
|
||||
WebGLFramebuffer::CheckAndInitializeAttachments()
|
||||
{
|
||||
MOZ_ASSERT(mContext->mBoundFramebuffer == this);
|
||||
// enforce WebGL section 6.5 which is WebGL-specific, hence OpenGL itself would not
|
||||
|
@ -387,16 +402,16 @@ WebGLFramebuffer::CheckAndInitializeRenderbuffers()
|
|||
size_t colorAttachmentCount = size_t(mColorAttachments.Length());
|
||||
|
||||
{
|
||||
bool hasUnitializedRenderbuffers = false;
|
||||
bool hasUnitializedAttachments = false;
|
||||
|
||||
for (size_t i = 0; i < colorAttachmentCount; i++) {
|
||||
hasUnitializedRenderbuffers |= mColorAttachments[i].HasUninitializedRenderbuffer();
|
||||
hasUnitializedAttachments |= mColorAttachments[i].HasUninitializedImageData();
|
||||
}
|
||||
|
||||
if (!hasUnitializedRenderbuffers &&
|
||||
!mDepthAttachment.HasUninitializedRenderbuffer() &&
|
||||
!mStencilAttachment.HasUninitializedRenderbuffer() &&
|
||||
!mDepthStencilAttachment.HasUninitializedRenderbuffer())
|
||||
if (!hasUnitializedAttachments &&
|
||||
!mDepthAttachment.HasUninitializedImageData() &&
|
||||
!mStencilAttachment.HasUninitializedImageData() &&
|
||||
!mDepthStencilAttachment.HasUninitializedImageData())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -420,21 +435,21 @@ WebGLFramebuffer::CheckAndInitializeRenderbuffers()
|
|||
|
||||
for (size_t i = 0; i < colorAttachmentCount; i++)
|
||||
{
|
||||
colorAttachmentsMask[i] = mColorAttachments[i].HasUninitializedRenderbuffer();
|
||||
colorAttachmentsMask[i] = mColorAttachments[i].HasUninitializedImageData();
|
||||
|
||||
if (colorAttachmentsMask[i]) {
|
||||
mask |= LOCAL_GL_COLOR_BUFFER_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
if (mDepthAttachment.HasUninitializedRenderbuffer() ||
|
||||
mDepthStencilAttachment.HasUninitializedRenderbuffer())
|
||||
if (mDepthAttachment.HasUninitializedImageData() ||
|
||||
mDepthStencilAttachment.HasUninitializedImageData())
|
||||
{
|
||||
mask |= LOCAL_GL_DEPTH_BUFFER_BIT;
|
||||
}
|
||||
|
||||
if (mStencilAttachment.HasUninitializedRenderbuffer() ||
|
||||
mDepthStencilAttachment.HasUninitializedRenderbuffer())
|
||||
if (mStencilAttachment.HasUninitializedImageData() ||
|
||||
mDepthStencilAttachment.HasUninitializedImageData())
|
||||
{
|
||||
mask |= LOCAL_GL_STENCIL_BUFFER_BIT;
|
||||
}
|
||||
|
@ -443,19 +458,16 @@ WebGLFramebuffer::CheckAndInitializeRenderbuffers()
|
|||
|
||||
for (size_t i = 0; i < colorAttachmentCount; i++)
|
||||
{
|
||||
if (colorAttachmentsMask[i]) {
|
||||
mColorAttachments[i].Renderbuffer()->SetInitialized(true);
|
||||
}
|
||||
if (mColorAttachments[i].HasUninitializedImageData())
|
||||
mColorAttachments[i].SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
|
||||
}
|
||||
|
||||
if (mDepthAttachment.HasUninitializedRenderbuffer())
|
||||
mDepthAttachment.Renderbuffer()->SetInitialized(true);
|
||||
|
||||
if (mStencilAttachment.HasUninitializedRenderbuffer())
|
||||
mStencilAttachment.Renderbuffer()->SetInitialized(true);
|
||||
|
||||
if (mDepthStencilAttachment.HasUninitializedRenderbuffer())
|
||||
mDepthStencilAttachment.Renderbuffer()->SetInitialized(true);
|
||||
if (mDepthAttachment.HasUninitializedImageData())
|
||||
mDepthAttachment.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
|
||||
if (mStencilAttachment.HasUninitializedImageData())
|
||||
mStencilAttachment.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
|
||||
if (mDepthStencilAttachment.HasUninitializedImageData())
|
||||
mDepthStencilAttachment.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -545,14 +557,11 @@ ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
|
|||
aName, aFlags);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_7(WebGLFramebuffer,
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_4(WebGLFramebuffer,
|
||||
mColorAttachments,
|
||||
mDepthAttachment.mTexturePtr,
|
||||
mDepthAttachment.mRenderbufferPtr,
|
||||
mStencilAttachment.mTexturePtr,
|
||||
mStencilAttachment.mRenderbufferPtr,
|
||||
mDepthStencilAttachment.mTexturePtr,
|
||||
mDepthStencilAttachment.mRenderbufferPtr)
|
||||
mDepthAttachment,
|
||||
mStencilAttachment,
|
||||
mDepthStencilAttachment)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLFramebuffer, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLFramebuffer, Release)
|
||||
|
|
|
@ -78,7 +78,8 @@ public:
|
|||
return mTexImageLevel;
|
||||
}
|
||||
|
||||
bool HasUninitializedRenderbuffer() const;
|
||||
bool HasUninitializedImageData() const;
|
||||
void SetImageDataStatus(WebGLImageDataStatus x);
|
||||
|
||||
void Reset() {
|
||||
mTexturePtr = nullptr;
|
||||
|
@ -161,7 +162,7 @@ public:
|
|||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebuffer)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLFramebuffer)
|
||||
|
||||
bool CheckAndInitializeRenderbuffers();
|
||||
bool CheckAndInitializeAttachments();
|
||||
|
||||
bool CheckColorAttachementNumber(GLenum attachment, const char * functionName) const;
|
||||
|
||||
|
|
|
@ -102,8 +102,8 @@ public:
|
|||
{ }
|
||||
|
||||
~WebGLRefCountedObject() {
|
||||
NS_ABORT_IF_FALSE(mWebGLRefCnt == 0, "destroying WebGL object still referenced by other WebGL objects");
|
||||
NS_ABORT_IF_FALSE(mDeletionStatus == Deleted, "Derived class destructor must call DeleteOnce()");
|
||||
MOZ_ASSERT(mWebGLRefCnt == 0, "destroying WebGL object still referenced by other WebGL objects");
|
||||
MOZ_ASSERT(mDeletionStatus == Deleted, "Derived class destructor must call DeleteOnce()");
|
||||
}
|
||||
|
||||
// called by WebGLRefPtr
|
||||
|
@ -113,7 +113,7 @@ public:
|
|||
|
||||
// called by WebGLRefPtr
|
||||
void WebGLRelease() {
|
||||
NS_ABORT_IF_FALSE(mWebGLRefCnt > 0, "releasing WebGL object with WebGL refcnt already zero");
|
||||
MOZ_ASSERT(mWebGLRefCnt > 0, "releasing WebGL object with WebGL refcnt already zero");
|
||||
--mWebGLRefCnt;
|
||||
MaybeDelete();
|
||||
}
|
||||
|
@ -215,12 +215,12 @@ public:
|
|||
}
|
||||
|
||||
T* operator->() const {
|
||||
NS_ABORT_IF_FALSE(mRawPtr != 0, "You can't dereference a nullptr WebGLRefPtr with operator->()!");
|
||||
MOZ_ASSERT(mRawPtr != 0, "You can't dereference a nullptr WebGLRefPtr with operator->()!");
|
||||
return get();
|
||||
}
|
||||
|
||||
T& operator*() const {
|
||||
NS_ABORT_IF_FALSE(mRawPtr != 0, "You can't dereference a nullptr WebGLRefPtr with operator*()!");
|
||||
MOZ_ASSERT(mRawPtr != 0, "You can't dereference a nullptr WebGLRefPtr with operator*()!");
|
||||
return *get();
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext *context)
|
|||
, mInternalFormat(0)
|
||||
, mInternalFormatForGL(0)
|
||||
, mHasEverBeenBound(false)
|
||||
, mInitialized(false)
|
||||
, mImageDataStatus(WebGLImageDataStatus::NoImageData)
|
||||
{
|
||||
SetIsDOMBinding();
|
||||
mContext->MakeContextCurrent();
|
||||
|
|
|
@ -33,8 +33,13 @@ public:
|
|||
bool HasEverBeenBound() { return mHasEverBeenBound; }
|
||||
void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; }
|
||||
|
||||
bool Initialized() const { return mInitialized; }
|
||||
void SetInitialized(bool aInitialized) { mInitialized = aInitialized; }
|
||||
bool HasUninitializedImageData() const { return mImageDataStatus == WebGLImageDataStatus::UninitializedImageData; }
|
||||
void SetImageDataStatus(WebGLImageDataStatus x) {
|
||||
// there is no way to go from having image data to not having any
|
||||
MOZ_ASSERT(x != WebGLImageDataStatus::NoImageData ||
|
||||
mImageDataStatus == WebGLImageDataStatus::NoImageData);
|
||||
mImageDataStatus = x;
|
||||
}
|
||||
|
||||
GLenum InternalFormat() const { return mInternalFormat; }
|
||||
void SetInternalFormat(GLenum aInternalFormat) { mInternalFormat = aInternalFormat; }
|
||||
|
@ -66,7 +71,7 @@ protected:
|
|||
GLenum mInternalFormat;
|
||||
GLenum mInternalFormatForGL;
|
||||
bool mHasEverBeenBound;
|
||||
bool mInitialized;
|
||||
WebGLImageDataStatus mImageDataStatus;
|
||||
|
||||
friend class WebGLFramebuffer;
|
||||
};
|
||||
|
|
|
@ -37,30 +37,30 @@ class WebGLImageConverter
|
|||
* texels with typed pointers and this value will tell us by how much we need
|
||||
* to increment these pointers to advance to the next texel.
|
||||
*/
|
||||
template<int Format>
|
||||
template<MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) Format>
|
||||
static size_t NumElementsPerTexelForFormat() {
|
||||
switch (Format) {
|
||||
case R8:
|
||||
case A8:
|
||||
case R32F:
|
||||
case A32F:
|
||||
case RGBA5551:
|
||||
case RGBA4444:
|
||||
case RGB565:
|
||||
case WebGLTexelFormat::R8:
|
||||
case WebGLTexelFormat::A8:
|
||||
case WebGLTexelFormat::R32F:
|
||||
case WebGLTexelFormat::A32F:
|
||||
case WebGLTexelFormat::RGBA5551:
|
||||
case WebGLTexelFormat::RGBA4444:
|
||||
case WebGLTexelFormat::RGB565:
|
||||
return 1;
|
||||
case RA8:
|
||||
case RA32F:
|
||||
case WebGLTexelFormat::RA8:
|
||||
case WebGLTexelFormat::RA32F:
|
||||
return 2;
|
||||
case RGB8:
|
||||
case RGB32F:
|
||||
case WebGLTexelFormat::RGB8:
|
||||
case WebGLTexelFormat::RGB32F:
|
||||
return 3;
|
||||
case RGBA8:
|
||||
case BGRA8:
|
||||
case BGRX8:
|
||||
case RGBA32F:
|
||||
case WebGLTexelFormat::RGBA8:
|
||||
case WebGLTexelFormat::BGRA8:
|
||||
case WebGLTexelFormat::BGRX8:
|
||||
case WebGLTexelFormat::RGBA32F:
|
||||
return 4;
|
||||
default:
|
||||
NS_ABORT_IF_FALSE(false, "Unknown texel format. Coding mistake?");
|
||||
MOZ_ASSERT(false, "Unknown texel format. Coding mistake?");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -73,9 +73,9 @@ class WebGLImageConverter
|
|||
* to return immediately in these cases to allow the compiler to avoid generating
|
||||
* useless code.
|
||||
*/
|
||||
template<WebGLTexelFormat SrcFormat,
|
||||
WebGLTexelFormat DstFormat,
|
||||
WebGLTexelPremultiplicationOp PremultiplicationOp>
|
||||
template<MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) SrcFormat,
|
||||
MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) DstFormat,
|
||||
MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelPremultiplicationOp) PremultiplicationOp>
|
||||
void run()
|
||||
{
|
||||
// check for never-called cases. We early-return to allow the compiler
|
||||
|
@ -86,7 +86,7 @@ class WebGLImageConverter
|
|||
// must check that and abort in that case. See WebGLContext::ConvertImage.
|
||||
|
||||
if (SrcFormat == DstFormat &&
|
||||
PremultiplicationOp == NoPremultiplicationOp)
|
||||
PremultiplicationOp == WebGLTexelPremultiplicationOp::None)
|
||||
{
|
||||
// Should have used a fast exit path earlier, rather than entering this function.
|
||||
// we explicitly return here to allow the compiler to avoid generating this code
|
||||
|
@ -98,11 +98,11 @@ class WebGLImageConverter
|
|||
// ImageData is always RGBA8. So all other SrcFormat will always satisfy DstFormat==SrcFormat,
|
||||
// so we can avoid compiling the code for all the unreachable paths.
|
||||
const bool CanSrcFormatComeFromDOMElementOrImageData
|
||||
= SrcFormat == BGRA8 ||
|
||||
SrcFormat == BGRX8 ||
|
||||
SrcFormat == A8 ||
|
||||
SrcFormat == RGB565 ||
|
||||
SrcFormat == RGBA8;
|
||||
= SrcFormat == WebGLTexelFormat::BGRA8 ||
|
||||
SrcFormat == WebGLTexelFormat::BGRX8 ||
|
||||
SrcFormat == WebGLTexelFormat::A8 ||
|
||||
SrcFormat == WebGLTexelFormat::RGB565 ||
|
||||
SrcFormat == WebGLTexelFormat::RGBA8;
|
||||
if (!CanSrcFormatComeFromDOMElementOrImageData &&
|
||||
SrcFormat != DstFormat)
|
||||
{
|
||||
|
@ -111,7 +111,7 @@ class WebGLImageConverter
|
|||
|
||||
// Likewise, only textures uploaded from DOM elements or ImageData can possibly have to be unpremultiplied.
|
||||
if (!CanSrcFormatComeFromDOMElementOrImageData &&
|
||||
PremultiplicationOp == Unpremultiply)
|
||||
PremultiplicationOp == WebGLTexelPremultiplicationOp::Unpremultiply)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ class WebGLImageConverter
|
|||
!HasColor(DstFormat))
|
||||
{
|
||||
|
||||
if (PremultiplicationOp != NoPremultiplicationOp)
|
||||
if (PremultiplicationOp != WebGLTexelPremultiplicationOp::None)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ class WebGLImageConverter
|
|||
|
||||
// end of early return cases.
|
||||
|
||||
NS_ABORT_IF_FALSE(!mAlreadyRun, "converter should be run only once!");
|
||||
MOZ_ASSERT(!mAlreadyRun, "converter should be run only once!");
|
||||
mAlreadyRun = true;
|
||||
|
||||
// gather some compile-time meta-data about the formats at hand.
|
||||
|
@ -146,9 +146,9 @@ class WebGLImageConverter
|
|||
typename DataTypeForFormat<DstFormat>::Type
|
||||
DstType;
|
||||
|
||||
const int IntermediateSrcFormat
|
||||
const MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) IntermediateSrcFormat
|
||||
= IntermediateFormat<SrcFormat>::Value;
|
||||
const int IntermediateDstFormat
|
||||
const MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) IntermediateDstFormat
|
||||
= IntermediateFormat<DstFormat>::Value;
|
||||
typedef
|
||||
typename DataTypeForFormat<IntermediateSrcFormat>::Type
|
||||
|
@ -160,8 +160,8 @@ class WebGLImageConverter
|
|||
const size_t NumElementsPerSrcTexel = NumElementsPerTexelForFormat<SrcFormat>();
|
||||
const size_t NumElementsPerDstTexel = NumElementsPerTexelForFormat<DstFormat>();
|
||||
const size_t MaxElementsPerTexel = 4;
|
||||
NS_ABORT_IF_FALSE(NumElementsPerSrcTexel <= MaxElementsPerTexel, "unhandled format");
|
||||
NS_ABORT_IF_FALSE(NumElementsPerDstTexel <= MaxElementsPerTexel, "unhandled format");
|
||||
MOZ_ASSERT(NumElementsPerSrcTexel <= MaxElementsPerTexel, "unhandled format");
|
||||
MOZ_ASSERT(NumElementsPerDstTexel <= MaxElementsPerTexel, "unhandled format");
|
||||
|
||||
// we assume that the strides are multiples of the sizeof of respective types.
|
||||
// this assumption will allow us to iterate over src and dst images using typed
|
||||
|
@ -169,9 +169,9 @@ class WebGLImageConverter
|
|||
// So this assumption allows us to write cleaner and safer code, but it might
|
||||
// not be true forever and if it eventually becomes wrong, we'll have to revert
|
||||
// to always iterating using uint8_t* pointers regardless of the types at hand.
|
||||
NS_ABORT_IF_FALSE(mSrcStride % sizeof(SrcType) == 0 &&
|
||||
mDstStride % sizeof(DstType) == 0,
|
||||
"Unsupported: texture stride is not a multiple of sizeof(type)");
|
||||
MOZ_ASSERT(mSrcStride % sizeof(SrcType) == 0 &&
|
||||
mDstStride % sizeof(DstType) == 0,
|
||||
"Unsupported: texture stride is not a multiple of sizeof(type)");
|
||||
const ptrdiff_t srcStrideInElements = mSrcStride / sizeof(SrcType);
|
||||
const ptrdiff_t dstStrideInElements = mDstStride / sizeof(DstType);
|
||||
|
||||
|
@ -213,7 +213,8 @@ class WebGLImageConverter
|
|||
return;
|
||||
}
|
||||
|
||||
template<WebGLTexelFormat SrcFormat, WebGLTexelFormat DstFormat>
|
||||
template<MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) SrcFormat,
|
||||
MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) DstFormat>
|
||||
void run(WebGLTexelPremultiplicationOp premultiplicationOp)
|
||||
{
|
||||
#define WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(PremultiplicationOp) \
|
||||
|
@ -221,17 +222,17 @@ class WebGLImageConverter
|
|||
return run<SrcFormat, DstFormat, PremultiplicationOp>();
|
||||
|
||||
switch (premultiplicationOp) {
|
||||
WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(NoPremultiplicationOp)
|
||||
WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(Premultiply)
|
||||
WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(Unpremultiply)
|
||||
WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(WebGLTexelPremultiplicationOp::None)
|
||||
WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(WebGLTexelPremultiplicationOp::Premultiply)
|
||||
WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(WebGLTexelPremultiplicationOp::Unpremultiply)
|
||||
default:
|
||||
NS_ABORT_IF_FALSE(false, "unhandled case. Coding mistake?");
|
||||
MOZ_ASSERT(false, "unhandled case. Coding mistake?");
|
||||
}
|
||||
|
||||
#undef WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP
|
||||
}
|
||||
|
||||
template<WebGLTexelFormat SrcFormat>
|
||||
template<MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) SrcFormat>
|
||||
void run(WebGLTexelFormat dstFormat,
|
||||
WebGLTexelPremultiplicationOp premultiplicationOp)
|
||||
{
|
||||
|
@ -240,21 +241,21 @@ class WebGLImageConverter
|
|||
return run<SrcFormat, DstFormat>(premultiplicationOp);
|
||||
|
||||
switch (dstFormat) {
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(R8)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(A8)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(R32F)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(A32F)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(RA8)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(RA32F)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(RGB8)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(RGB565)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(RGB32F)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(RGBA8)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(RGBA5551)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(RGBA4444)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(RGBA32F)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::R8)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::A8)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::R32F)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::A32F)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RA8)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RA32F)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGB8)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGB565)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGB32F)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBA8)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBA5551)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBA4444)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBA32F)
|
||||
default:
|
||||
NS_ABORT_IF_FALSE(false, "unhandled case. Coding mistake?");
|
||||
MOZ_ASSERT(false, "unhandled case. Coding mistake?");
|
||||
}
|
||||
|
||||
#undef WEBGLIMAGECONVERTER_CASE_DSTFORMAT
|
||||
|
@ -271,23 +272,23 @@ public:
|
|||
return run<SrcFormat>(dstFormat, premultiplicationOp);
|
||||
|
||||
switch (srcFormat) {
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(R8)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(A8)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(R32F)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(A32F)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(RA8)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(RA32F)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(RGB8)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(BGRX8) // source format only
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(RGB565)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(RGB32F)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(RGBA8)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(BGRA8)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(RGBA5551)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(RGBA4444)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(RGBA32F)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::R8)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::A8)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::R32F)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::A32F)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RA8)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RA32F)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGB8)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::BGRX8) // source format only
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGB565)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGB32F)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBA8)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::BGRA8)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBA5551)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBA4444)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBA32F)
|
||||
default:
|
||||
NS_ABORT_IF_FALSE(false, "unhandled case. Coding mistake?");
|
||||
MOZ_ASSERT(false, "unhandled case. Coding mistake?");
|
||||
}
|
||||
|
||||
#undef WEBGLIMAGECONVERTER_CASE_SRCFORMAT
|
||||
|
@ -335,7 +336,7 @@ WebGLContext::ConvertImage(size_t width, size_t height, size_t srcStride, size_t
|
|||
// So the case we're handling here is when even though no format conversion is needed,
|
||||
// we still might have to flip vertically and/or to adjust to a different stride.
|
||||
|
||||
NS_ABORT_IF_FALSE(mPixelStoreFlipY || srcStride != dstStride, "Performance trap -- should handle this case earlier, to avoid memcpy");
|
||||
MOZ_ASSERT(mPixelStoreFlipY || srcStride != dstStride, "Performance trap -- should handle this case earlier, to avoid memcpy");
|
||||
|
||||
size_t row_size = width * dstTexelSize; // doesn't matter, src and dst formats agree
|
||||
const uint8_t* ptr = src;
|
||||
|
@ -365,10 +366,10 @@ WebGLContext::ConvertImage(size_t width, size_t height, size_t srcStride, size_t
|
|||
WebGLImageConverter converter(width, height, src, dstStart, srcStride, signedDstStride);
|
||||
|
||||
const WebGLTexelPremultiplicationOp premultiplicationOp
|
||||
= FormatsRequireNoPremultiplicationOp ? NoPremultiplicationOp
|
||||
: (!srcPremultiplied && dstPremultiplied) ? Premultiply
|
||||
: (srcPremultiplied && !dstPremultiplied) ? Unpremultiply
|
||||
: NoPremultiplicationOp;
|
||||
= FormatsRequireNoPremultiplicationOp ? WebGLTexelPremultiplicationOp::None
|
||||
: (!srcPremultiplied && dstPremultiplied) ? WebGLTexelPremultiplicationOp::Premultiply
|
||||
: (srcPremultiplied && !dstPremultiplied) ? WebGLTexelPremultiplicationOp::Unpremultiply
|
||||
: WebGLTexelPremultiplicationOp::None;
|
||||
|
||||
converter.run(srcFormat, dstFormat, premultiplicationOp);
|
||||
|
||||
|
|
|
@ -34,47 +34,46 @@
|
|||
|
||||
#include "WebGLTypes.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined _MSC_VER
|
||||
#define FORCE_INLINE __forceinline
|
||||
#elif defined __GNUC__
|
||||
#define FORCE_INLINE __attribute__((always_inline)) inline
|
||||
#else
|
||||
#define FORCE_INLINE inline
|
||||
#endif
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace WebGLTexelConversions {
|
||||
|
||||
enum WebGLTexelPremultiplicationOp
|
||||
{
|
||||
NoPremultiplicationOp,
|
||||
MOZ_BEGIN_ENUM_CLASS(WebGLTexelPremultiplicationOp, int)
|
||||
None,
|
||||
Premultiply,
|
||||
Unpremultiply
|
||||
};
|
||||
MOZ_END_ENUM_CLASS(WebGLTexelPremultiplicationOp)
|
||||
|
||||
template<int Format>
|
||||
namespace WebGLTexelConversions {
|
||||
|
||||
// remove this as soon as B2G and Windows use newer compilers
|
||||
#ifdef MOZ_HAVE_CXX11_STRONG_ENUMS
|
||||
#define MOZ_ENUM_CLASS_INTEGER_TYPE(X) X
|
||||
#else
|
||||
#define MOZ_ENUM_CLASS_INTEGER_TYPE(X) X::Enum
|
||||
#endif
|
||||
|
||||
template<MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) Format>
|
||||
struct IsFloatFormat
|
||||
{
|
||||
static const bool Value =
|
||||
Format == RGBA32F ||
|
||||
Format == RGB32F ||
|
||||
Format == RA32F ||
|
||||
Format == R32F ||
|
||||
Format == A32F;
|
||||
Format == WebGLTexelFormat::RGBA32F ||
|
||||
Format == WebGLTexelFormat::RGB32F ||
|
||||
Format == WebGLTexelFormat::RA32F ||
|
||||
Format == WebGLTexelFormat::R32F ||
|
||||
Format == WebGLTexelFormat::A32F;
|
||||
};
|
||||
|
||||
template<int Format>
|
||||
template<MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) Format>
|
||||
struct Is16bppFormat
|
||||
{
|
||||
static const bool Value =
|
||||
Format == RGBA4444 ||
|
||||
Format == RGBA5551 ||
|
||||
Format == RGB565;
|
||||
Format == WebGLTexelFormat::RGBA4444 ||
|
||||
Format == WebGLTexelFormat::RGBA5551 ||
|
||||
Format == WebGLTexelFormat::RGB565;
|
||||
};
|
||||
|
||||
template<int Format,
|
||||
template<MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) Format,
|
||||
bool IsFloat = IsFloatFormat<Format>::Value,
|
||||
bool Is16bpp = Is16bppFormat<Format>::Value>
|
||||
struct DataTypeForFormat
|
||||
|
@ -82,83 +81,86 @@ struct DataTypeForFormat
|
|||
typedef uint8_t Type;
|
||||
};
|
||||
|
||||
template<int Format>
|
||||
template<MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) Format>
|
||||
struct DataTypeForFormat<Format, true, false>
|
||||
{
|
||||
typedef float Type;
|
||||
};
|
||||
|
||||
template<int Format>
|
||||
template<MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) Format>
|
||||
struct DataTypeForFormat<Format, false, true>
|
||||
{
|
||||
typedef uint16_t Type;
|
||||
};
|
||||
|
||||
template<int Format>
|
||||
template<MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) Format>
|
||||
struct IntermediateFormat
|
||||
{
|
||||
static const int Value = IsFloatFormat<Format>::Value ? RGBA32F : RGBA8;
|
||||
static const MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) Value
|
||||
= IsFloatFormat<Format>::Value
|
||||
? WebGLTexelFormat::RGBA32F
|
||||
: WebGLTexelFormat::RGBA8;
|
||||
};
|
||||
|
||||
inline size_t TexelBytesForFormat(int format) {
|
||||
inline size_t TexelBytesForFormat(WebGLTexelFormat format) {
|
||||
switch (format) {
|
||||
case WebGLTexelConversions::R8:
|
||||
case WebGLTexelConversions::A8:
|
||||
case WebGLTexelFormat::R8:
|
||||
case WebGLTexelFormat::A8:
|
||||
return 1;
|
||||
case WebGLTexelConversions::RA8:
|
||||
case WebGLTexelConversions::RGBA5551:
|
||||
case WebGLTexelConversions::RGBA4444:
|
||||
case WebGLTexelConversions::RGB565:
|
||||
case WebGLTexelConversions::D16:
|
||||
case WebGLTexelFormat::RA8:
|
||||
case WebGLTexelFormat::RGBA5551:
|
||||
case WebGLTexelFormat::RGBA4444:
|
||||
case WebGLTexelFormat::RGB565:
|
||||
case WebGLTexelFormat::D16:
|
||||
return 2;
|
||||
case WebGLTexelConversions::RGB8:
|
||||
case WebGLTexelFormat::RGB8:
|
||||
return 3;
|
||||
case WebGLTexelConversions::RGBA8:
|
||||
case WebGLTexelConversions::BGRA8:
|
||||
case WebGLTexelConversions::BGRX8:
|
||||
case WebGLTexelConversions::R32F:
|
||||
case WebGLTexelConversions::A32F:
|
||||
case WebGLTexelConversions::D32:
|
||||
case WebGLTexelConversions::D24S8:
|
||||
case WebGLTexelFormat::RGBA8:
|
||||
case WebGLTexelFormat::BGRA8:
|
||||
case WebGLTexelFormat::BGRX8:
|
||||
case WebGLTexelFormat::R32F:
|
||||
case WebGLTexelFormat::A32F:
|
||||
case WebGLTexelFormat::D32:
|
||||
case WebGLTexelFormat::D24S8:
|
||||
return 4;
|
||||
case WebGLTexelConversions::RA32F:
|
||||
case WebGLTexelFormat::RA32F:
|
||||
return 8;
|
||||
case WebGLTexelConversions::RGB32F:
|
||||
case WebGLTexelFormat::RGB32F:
|
||||
return 12;
|
||||
case WebGLTexelConversions::RGBA32F:
|
||||
case WebGLTexelFormat::RGBA32F:
|
||||
return 16;
|
||||
default:
|
||||
NS_ABORT_IF_FALSE(false, "Unknown texel format. Coding mistake?");
|
||||
MOZ_ASSERT(false, "Unknown texel format. Coding mistake?");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
FORCE_INLINE bool HasAlpha(int format) {
|
||||
return format == A8 ||
|
||||
format == A32F ||
|
||||
format == RA8 ||
|
||||
format == RA32F ||
|
||||
format == RGBA8 ||
|
||||
format == BGRA8 ||
|
||||
format == RGBA32F ||
|
||||
format == RGBA4444 ||
|
||||
format == RGBA5551;
|
||||
MOZ_ALWAYS_INLINE bool HasAlpha(WebGLTexelFormat format) {
|
||||
return format == WebGLTexelFormat::A8 ||
|
||||
format == WebGLTexelFormat::A32F ||
|
||||
format == WebGLTexelFormat::RA8 ||
|
||||
format == WebGLTexelFormat::RA32F ||
|
||||
format == WebGLTexelFormat::RGBA8 ||
|
||||
format == WebGLTexelFormat::BGRA8 ||
|
||||
format == WebGLTexelFormat::RGBA32F ||
|
||||
format == WebGLTexelFormat::RGBA4444 ||
|
||||
format == WebGLTexelFormat::RGBA5551;
|
||||
}
|
||||
|
||||
FORCE_INLINE bool HasColor(int format) {
|
||||
return format == R8 ||
|
||||
format == R32F ||
|
||||
format == RA8 ||
|
||||
format == RA32F ||
|
||||
format == RGB8 ||
|
||||
format == BGRX8 ||
|
||||
format == RGB565 ||
|
||||
format == RGB32F ||
|
||||
format == RGBA8 ||
|
||||
format == BGRA8 ||
|
||||
format == RGBA32F ||
|
||||
format == RGBA4444 ||
|
||||
format == RGBA5551;
|
||||
MOZ_ALWAYS_INLINE bool HasColor(WebGLTexelFormat format) {
|
||||
return format == WebGLTexelFormat::R8 ||
|
||||
format == WebGLTexelFormat::R32F ||
|
||||
format == WebGLTexelFormat::RA8 ||
|
||||
format == WebGLTexelFormat::RA32F ||
|
||||
format == WebGLTexelFormat::RGB8 ||
|
||||
format == WebGLTexelFormat::BGRX8 ||
|
||||
format == WebGLTexelFormat::RGB565 ||
|
||||
format == WebGLTexelFormat::RGB32F ||
|
||||
format == WebGLTexelFormat::RGBA8 ||
|
||||
format == WebGLTexelFormat::BGRA8 ||
|
||||
format == WebGLTexelFormat::RGBA32F ||
|
||||
format == WebGLTexelFormat::RGBA4444 ||
|
||||
format == WebGLTexelFormat::RGBA5551;
|
||||
}
|
||||
|
||||
|
||||
|
@ -170,16 +172,16 @@ FORCE_INLINE bool HasColor(int format) {
|
|||
//----------------------------------------------------------------------
|
||||
// Pixel unpacking routines.
|
||||
|
||||
template<int Format, typename SrcType, typename DstType>
|
||||
FORCE_INLINE void
|
||||
template<MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) Format, typename SrcType, typename DstType>
|
||||
MOZ_ALWAYS_INLINE void
|
||||
unpack(const SrcType* __restrict src,
|
||||
DstType* __restrict dst)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(false, "Unimplemented texture format conversion");
|
||||
MOZ_ASSERT(false, "Unimplemented texture format conversion");
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
unpack<RGBA8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
unpack<WebGLTexelFormat::RGBA8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
|
@ -187,8 +189,8 @@ unpack<RGBA8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restri
|
|||
dst[3] = src[3];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
unpack<RGB8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
unpack<WebGLTexelFormat::RGB8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
|
@ -196,8 +198,8 @@ unpack<RGB8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restric
|
|||
dst[3] = 0xFF;
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
unpack<BGRA8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
unpack<WebGLTexelFormat::BGRA8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
dst[0] = src[2];
|
||||
dst[1] = src[1];
|
||||
|
@ -205,8 +207,8 @@ unpack<BGRA8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restri
|
|||
dst[3] = src[3];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
unpack<BGRX8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
unpack<WebGLTexelFormat::BGRX8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
dst[0] = src[2];
|
||||
dst[1] = src[1];
|
||||
|
@ -214,8 +216,8 @@ unpack<BGRX8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restri
|
|||
dst[3] = 0xFF;
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
unpack<RGBA5551, uint16_t, uint8_t>(const uint16_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
unpack<WebGLTexelFormat::RGBA5551, uint16_t, uint8_t>(const uint16_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
uint16_t packedValue = src[0];
|
||||
uint8_t r = (packedValue >> 11) & 0x1F;
|
||||
|
@ -227,8 +229,8 @@ unpack<RGBA5551, uint16_t, uint8_t>(const uint16_t* __restrict src, uint8_t* __r
|
|||
dst[3] = (packedValue & 0x1) ? 0xFF : 0;
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
unpack<RGBA4444, uint16_t, uint8_t>(const uint16_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
unpack<WebGLTexelFormat::RGBA4444, uint16_t, uint8_t>(const uint16_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
uint16_t packedValue = src[0];
|
||||
uint8_t r = (packedValue >> 12) & 0x0F;
|
||||
|
@ -241,8 +243,8 @@ unpack<RGBA4444, uint16_t, uint8_t>(const uint16_t* __restrict src, uint8_t* __r
|
|||
dst[3] = (a << 4) | a;
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
unpack<RGB565, uint16_t, uint8_t>(const uint16_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
unpack<WebGLTexelFormat::RGB565, uint16_t, uint8_t>(const uint16_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
uint16_t packedValue = src[0];
|
||||
uint8_t r = (packedValue >> 11) & 0x1F;
|
||||
|
@ -254,8 +256,8 @@ unpack<RGB565, uint16_t, uint8_t>(const uint16_t* __restrict src, uint8_t* __res
|
|||
dst[3] = 0xFF;
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
unpack<R8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
unpack<WebGLTexelFormat::R8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[0];
|
||||
|
@ -263,8 +265,8 @@ unpack<R8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict
|
|||
dst[3] = 0xFF;
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
unpack<RA8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
unpack<WebGLTexelFormat::RA8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[0];
|
||||
|
@ -272,8 +274,8 @@ unpack<RA8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict
|
|||
dst[3] = src[1];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
unpack<A8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
unpack<WebGLTexelFormat::A8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
dst[0] = 0;
|
||||
dst[1] = 0;
|
||||
|
@ -281,8 +283,8 @@ unpack<A8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict
|
|||
dst[3] = src[0];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
unpack<RGBA32F, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
unpack<WebGLTexelFormat::RGBA32F, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
|
@ -290,8 +292,8 @@ unpack<RGBA32F, float, float>(const float* __restrict src, float* __restrict dst
|
|||
dst[3] = src[3];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
unpack<RGB32F, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
unpack<WebGLTexelFormat::RGB32F, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
|
@ -299,8 +301,8 @@ unpack<RGB32F, float, float>(const float* __restrict src, float* __restrict dst)
|
|||
dst[3] = 1.0f;
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
unpack<R32F, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
unpack<WebGLTexelFormat::R32F, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[0];
|
||||
|
@ -308,8 +310,8 @@ unpack<R32F, float, float>(const float* __restrict src, float* __restrict dst)
|
|||
dst[3] = 1.0f;
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
unpack<RA32F, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
unpack<WebGLTexelFormat::RA32F, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[0];
|
||||
|
@ -317,8 +319,8 @@ unpack<RA32F, float, float>(const float* __restrict src, float* __restrict dst)
|
|||
dst[3] = src[1];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
unpack<A32F, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
unpack<WebGLTexelFormat::A32F, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
dst[0] = 0;
|
||||
dst[1] = 0;
|
||||
|
@ -330,63 +332,66 @@ unpack<A32F, float, float>(const float* __restrict src, float* __restrict dst)
|
|||
// Pixel packing routines.
|
||||
//
|
||||
|
||||
template<int Format, int PremultiplicationOp, typename SrcType, typename DstType>
|
||||
FORCE_INLINE void
|
||||
template<MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) Format,
|
||||
MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelPremultiplicationOp) PremultiplicationOp,
|
||||
typename SrcType,
|
||||
typename DstType>
|
||||
MOZ_ALWAYS_INLINE void
|
||||
pack(const SrcType* __restrict src,
|
||||
DstType* __restrict dst)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(false, "Unimplemented texture format conversion");
|
||||
MOZ_ASSERT(false, "Unimplemented texture format conversion");
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<A8, NoPremultiplicationOp, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::A8, WebGLTexelPremultiplicationOp::None, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
dst[0] = src[3];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<A8, Premultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::A8, WebGLTexelPremultiplicationOp::Premultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
dst[0] = src[3];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<A8, Unpremultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::A8, WebGLTexelPremultiplicationOp::Unpremultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
dst[0] = src[3];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<R8, NoPremultiplicationOp, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::R8, WebGLTexelPremultiplicationOp::None, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<R8, Premultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::R8, WebGLTexelPremultiplicationOp::Premultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = src[3] / 255.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
dst[0] = srcR;
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<R8, Unpremultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::R8, WebGLTexelPremultiplicationOp::Unpremultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = src[3] ? 255.0f / src[3] : 1.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
dst[0] = srcR;
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<RA8, NoPremultiplicationOp, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::RA8, WebGLTexelPremultiplicationOp::None, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[3];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<RA8, Premultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::RA8, WebGLTexelPremultiplicationOp::Premultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = src[3] / 255.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
|
@ -395,8 +400,8 @@ pack<RA8, Premultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t*
|
|||
}
|
||||
|
||||
// FIXME: this routine is lossy and must be removed.
|
||||
template<> FORCE_INLINE void
|
||||
pack<RA8, Unpremultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::RA8, WebGLTexelPremultiplicationOp::Unpremultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = src[3] ? 255.0f / src[3] : 1.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
|
@ -404,16 +409,16 @@ pack<RA8, Unpremultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_
|
|||
dst[1] = src[3];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGB8, NoPremultiplicationOp, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::RGB8, WebGLTexelPremultiplicationOp::None, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[2];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGB8, Premultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::RGB8, WebGLTexelPremultiplicationOp::Premultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = src[3] / 255.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
|
@ -424,8 +429,8 @@ pack<RGB8, Premultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t
|
|||
dst[2] = srcB;
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGB8, Unpremultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::RGB8, WebGLTexelPremultiplicationOp::Unpremultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = src[3] ? 255.0f / src[3] : 1.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
|
@ -436,8 +441,8 @@ pack<RGB8, Unpremultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8
|
|||
dst[2] = srcB;
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGBA8, NoPremultiplicationOp, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::RGBA8, WebGLTexelPremultiplicationOp::None, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
|
@ -445,8 +450,8 @@ pack<RGBA8, NoPremultiplicationOp, uint8_t, uint8_t>(const uint8_t* __restrict s
|
|||
dst[3] = src[3];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGBA8, Premultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::RGBA8, WebGLTexelPremultiplicationOp::Premultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = src[3] / 255.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
|
@ -459,8 +464,8 @@ pack<RGBA8, Premultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_
|
|||
}
|
||||
|
||||
// FIXME: this routine is lossy and must be removed.
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGBA8, Unpremultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::RGBA8, WebGLTexelPremultiplicationOp::Unpremultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = src[3] ? 255.0f / src[3] : 1.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
|
@ -472,8 +477,8 @@ pack<RGBA8, Unpremultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint
|
|||
dst[3] = src[3];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGBA4444, NoPremultiplicationOp, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::RGBA4444, WebGLTexelPremultiplicationOp::None, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
{
|
||||
*dst = ( ((src[0] & 0xF0) << 8)
|
||||
| ((src[1] & 0xF0) << 4)
|
||||
|
@ -481,8 +486,8 @@ pack<RGBA4444, NoPremultiplicationOp, uint8_t, uint16_t>(const uint8_t* __restri
|
|||
| (src[3] >> 4) );
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGBA4444, Premultiply, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::RGBA4444, WebGLTexelPremultiplicationOp::Premultiply, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = src[3] / 255.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
|
@ -495,8 +500,8 @@ pack<RGBA4444, Premultiply, uint8_t, uint16_t>(const uint8_t* __restrict src, ui
|
|||
}
|
||||
|
||||
// FIXME: this routine is lossy and must be removed.
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGBA4444, Unpremultiply, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::RGBA4444, WebGLTexelPremultiplicationOp::Unpremultiply, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = src[3] ? 255.0f / src[3] : 1.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
|
@ -508,8 +513,8 @@ pack<RGBA4444, Unpremultiply, uint8_t, uint16_t>(const uint8_t* __restrict src,
|
|||
| (src[3] >> 4));
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGBA5551, NoPremultiplicationOp, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::RGBA5551, WebGLTexelPremultiplicationOp::None, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
{
|
||||
*dst = ( ((src[0] & 0xF8) << 8)
|
||||
| ((src[1] & 0xF8) << 3)
|
||||
|
@ -517,8 +522,8 @@ pack<RGBA5551, NoPremultiplicationOp, uint8_t, uint16_t>(const uint8_t* __restri
|
|||
| (src[3] >> 7));
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGBA5551, Premultiply, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::RGBA5551, WebGLTexelPremultiplicationOp::Premultiply, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = src[3] / 255.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
|
@ -531,8 +536,8 @@ pack<RGBA5551, Premultiply, uint8_t, uint16_t>(const uint8_t* __restrict src, ui
|
|||
}
|
||||
|
||||
// FIXME: this routine is lossy and must be removed.
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGBA5551, Unpremultiply, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::RGBA5551, WebGLTexelPremultiplicationOp::Unpremultiply, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = src[3] ? 255.0f / src[3] : 1.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
|
@ -544,16 +549,16 @@ pack<RGBA5551, Unpremultiply, uint8_t, uint16_t>(const uint8_t* __restrict src,
|
|||
| (src[3] >> 7));
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGB565, NoPremultiplicationOp, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::RGB565, WebGLTexelPremultiplicationOp::None, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
{
|
||||
*dst = ( ((src[0] & 0xF8) << 8)
|
||||
| ((src[1] & 0xFC) << 3)
|
||||
| ((src[2] & 0xF8) >> 3));
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGB565, Premultiply, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::RGB565, WebGLTexelPremultiplicationOp::Premultiply, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = src[3] / 255.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
|
@ -565,8 +570,8 @@ pack<RGB565, Premultiply, uint8_t, uint16_t>(const uint8_t* __restrict src, uint
|
|||
}
|
||||
|
||||
// FIXME: this routine is lossy and must be removed.
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGB565, Unpremultiply, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::RGB565, WebGLTexelPremultiplicationOp::Unpremultiply, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = src[3] ? 255.0f / src[3] : 1.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
|
@ -577,16 +582,16 @@ pack<RGB565, Unpremultiply, uint8_t, uint16_t>(const uint8_t* __restrict src, ui
|
|||
| ((srcB & 0xF8) >> 3));
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGB32F, NoPremultiplicationOp, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::RGB32F, WebGLTexelPremultiplicationOp::None, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[2];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGB32F, Premultiply, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::RGB32F, WebGLTexelPremultiplicationOp::Premultiply, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
float scaleFactor = src[3];
|
||||
dst[0] = src[0] * scaleFactor;
|
||||
|
@ -594,8 +599,8 @@ pack<RGB32F, Premultiply, float, float>(const float* __restrict src, float* __re
|
|||
dst[2] = src[2] * scaleFactor;
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGBA32F, NoPremultiplicationOp, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::RGBA32F, WebGLTexelPremultiplicationOp::None, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
|
@ -603,8 +608,8 @@ pack<RGBA32F, NoPremultiplicationOp, float, float>(const float* __restrict src,
|
|||
dst[3] = src[3];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGBA32F, Premultiply, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::RGBA32F, WebGLTexelPremultiplicationOp::Premultiply, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
float scaleFactor = src[3];
|
||||
dst[0] = src[0] * scaleFactor;
|
||||
|
@ -613,40 +618,40 @@ pack<RGBA32F, Premultiply, float, float>(const float* __restrict src, float* __r
|
|||
dst[3] = src[3];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<A32F, NoPremultiplicationOp, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::A32F, WebGLTexelPremultiplicationOp::None, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
dst[0] = src[3];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<A32F, Premultiply, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::A32F, WebGLTexelPremultiplicationOp::Premultiply, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
dst[0] = src[3];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<R32F, NoPremultiplicationOp, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::R32F, WebGLTexelPremultiplicationOp::None, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<R32F, Premultiply, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::R32F, WebGLTexelPremultiplicationOp::Premultiply, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
float scaleFactor = src[3];
|
||||
dst[0] = src[0] * scaleFactor;
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<RA32F, NoPremultiplicationOp, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::RA32F, WebGLTexelPremultiplicationOp::None, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[3];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<RA32F, Premultiply, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
pack<WebGLTexelFormat::RA32F, WebGLTexelPremultiplicationOp::Premultiply, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
float scaleFactor = src[3];
|
||||
dst[0] = src[0] * scaleFactor;
|
||||
|
@ -655,13 +660,13 @@ pack<RA32F, Premultiply, float, float>(const float* __restrict src, float* __res
|
|||
|
||||
/****** END CODE SHARED WITH WEBKIT ******/
|
||||
|
||||
template<typename SrcType, typename DstType> FORCE_INLINE void
|
||||
template<typename SrcType, typename DstType> MOZ_ALWAYS_INLINE void
|
||||
convertType(const SrcType* __restrict src, DstType* __restrict dst)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(false, "Unimplemented texture format conversion");
|
||||
MOZ_ASSERT(false, "Unimplemented texture format conversion");
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
convertType<uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
|
@ -670,7 +675,7 @@ convertType<uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict
|
|||
dst[3] = src[3];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
convertType<float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
|
@ -679,7 +684,7 @@ convertType<float, float>(const float* __restrict src, float* __restrict dst)
|
|||
dst[3] = src[3];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
template<> MOZ_ALWAYS_INLINE void
|
||||
convertType<uint8_t, float>(const uint8_t* __restrict src, float* __restrict dst)
|
||||
{
|
||||
const float scaleFactor = 1.f / 255.0f;
|
||||
|
@ -689,8 +694,6 @@ convertType<uint8_t, float>(const uint8_t* __restrict src, float* __restrict dst
|
|||
dst[3] = src[3] * scaleFactor;
|
||||
}
|
||||
|
||||
#undef FORCE_INLINE
|
||||
|
||||
} // end namespace WebGLTexelConversions
|
||||
|
||||
} // end namespace mozilla
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "WebGLContext.h"
|
||||
#include "WebGLTexture.h"
|
||||
#include "GLContext.h"
|
||||
#include "WebGLTexelConversions.h"
|
||||
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -27,7 +28,7 @@ WebGLTexture::WebGLTexture(WebGLContext *context)
|
|||
, mFacesCount(0)
|
||||
, mMaxLevelWithCustomImages(0)
|
||||
, mHaveGeneratedMipmap(false)
|
||||
, mFakeBlackStatus(DoNotNeedFakeBlack)
|
||||
, mFakeBlackStatus(WebGLTextureFakeBlackStatus::IncompleteTexture)
|
||||
{
|
||||
SetIsDOMBinding();
|
||||
mContext->MakeContextCurrent();
|
||||
|
@ -45,7 +46,7 @@ WebGLTexture::Delete() {
|
|||
|
||||
int64_t
|
||||
WebGLTexture::ImageInfo::MemoryUsage() const {
|
||||
if (!mIsDefined)
|
||||
if (mImageDataStatus == WebGLImageDataStatus::NoImageData)
|
||||
return 0;
|
||||
int64_t texelSizeInBits = WebGLContext::GetBitsPerTexel(mFormat, mType);
|
||||
return int64_t(mWidth) * int64_t(mHeight) * texelSizeInBits / 8;
|
||||
|
@ -97,12 +98,6 @@ WebGLTexture::DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(GLenum texImag
|
|||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLTexture::SetDontKnowIfNeedFakeBlack() {
|
||||
mFakeBlackStatus = DontKnowIfNeedFakeBlack;
|
||||
mContext->SetDontKnowIfNeedFakeBlack();
|
||||
}
|
||||
|
||||
void
|
||||
WebGLTexture::Bind(GLenum aTarget) {
|
||||
// this function should only be called by bindTexture().
|
||||
|
@ -124,7 +119,7 @@ WebGLTexture::Bind(GLenum aTarget) {
|
|||
if (firstTimeThisTextureIsBound) {
|
||||
mFacesCount = (mTarget == LOCAL_GL_TEXTURE_2D) ? 1 : 6;
|
||||
EnsureMaxLevelWithCustomImagesAtLeast(0);
|
||||
SetDontKnowIfNeedFakeBlack();
|
||||
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
|
||||
|
||||
// thanks to the WebKit people for finding this out: GL_TEXTURE_WRAP_R is not
|
||||
// present in GLES 2, but is present in GL and it seems as if for cube maps
|
||||
|
@ -139,26 +134,26 @@ WebGLTexture::Bind(GLenum aTarget) {
|
|||
void
|
||||
WebGLTexture::SetImageInfo(GLenum aTarget, GLint aLevel,
|
||||
GLsizei aWidth, GLsizei aHeight,
|
||||
GLenum aFormat, GLenum aType)
|
||||
GLenum aFormat, GLenum aType, WebGLImageDataStatus aStatus)
|
||||
{
|
||||
if ( (aTarget == LOCAL_GL_TEXTURE_2D) != (mTarget == LOCAL_GL_TEXTURE_2D) )
|
||||
return;
|
||||
|
||||
EnsureMaxLevelWithCustomImagesAtLeast(aLevel);
|
||||
|
||||
ImageInfoAt(aTarget, aLevel) = ImageInfo(aWidth, aHeight, aFormat, aType);
|
||||
ImageInfoAt(aTarget, aLevel) = ImageInfo(aWidth, aHeight, aFormat, aType, aStatus);
|
||||
|
||||
if (aLevel > 0)
|
||||
SetCustomMipmap();
|
||||
|
||||
SetDontKnowIfNeedFakeBlack();
|
||||
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLTexture::SetGeneratedMipmap() {
|
||||
if (!mHaveGeneratedMipmap) {
|
||||
mHaveGeneratedMipmap = true;
|
||||
SetDontKnowIfNeedFakeBlack();
|
||||
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -244,128 +239,209 @@ WebGLTexture::IsMipmapCubeComplete() const {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLTexture::NeedFakeBlack() {
|
||||
// handle this case first, it's the generic case
|
||||
if (mFakeBlackStatus == DoNotNeedFakeBlack)
|
||||
return false;
|
||||
|
||||
if (mFakeBlackStatus == DontKnowIfNeedFakeBlack) {
|
||||
// Determine if the texture needs to be faked as a black texture.
|
||||
// See 3.8.2 Shader Execution in the OpenGL ES 2.0.24 spec.
|
||||
|
||||
for (size_t face = 0; face < mFacesCount; ++face) {
|
||||
if (!ImageInfoAtFace(face, 0).mIsDefined) {
|
||||
// In case of undefined texture image, we don't print any message because this is a very common
|
||||
// and often legitimate case, for example when doing asynchronous texture loading.
|
||||
// An extreme case of this is the photowall google demo.
|
||||
// Exiting early here allows us to avoid making noise on valid webgl code.
|
||||
mFakeBlackStatus = DoNeedFakeBlack;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const char *msg_rendering_as_black
|
||||
= "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 (DoesMinFilterRequireMipmap())
|
||||
{
|
||||
if (!IsMipmapTexture2DComplete()) {
|
||||
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);
|
||||
mFakeBlackStatus = DoNeedFakeBlack;
|
||||
} else if (!ImageInfoAt(mTarget, 0).IsPowerOfTwo()) {
|
||||
mContext->GenerateWarning
|
||||
("%s is a 2D 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 = DoNeedFakeBlack;
|
||||
}
|
||||
}
|
||||
else // no mipmap required
|
||||
{
|
||||
if (!ImageInfoAt(mTarget, 0).IsPositive()) {
|
||||
mContext->GenerateWarning
|
||||
("%s is a 2D texture and its width or height is equal to zero.",
|
||||
msg_rendering_as_black);
|
||||
mFakeBlackStatus = DoNeedFakeBlack;
|
||||
} else if (!AreBothWrapModesClampToEdge() && !ImageInfoAt(mTarget, 0).IsPowerOfTwo()) {
|
||||
mContext->GenerateWarning
|
||||
("%s is a 2D 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);
|
||||
mFakeBlackStatus = DoNeedFakeBlack;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // cube map
|
||||
{
|
||||
bool areAllLevel0ImagesPOT = true;
|
||||
for (size_t face = 0; face < mFacesCount; ++face)
|
||||
areAllLevel0ImagesPOT &= ImageInfoAtFace(face, 0).IsPowerOfTwo();
|
||||
|
||||
if (DoesMinFilterRequireMipmap())
|
||||
{
|
||||
if (!IsMipmapCubeComplete()) {
|
||||
mContext->GenerateWarning("%s is a cube map texture, with a minification filter requiring a mipmap, "
|
||||
"and is not mipmap cube complete (as defined in section 3.7.10).",
|
||||
msg_rendering_as_black);
|
||||
mFakeBlackStatus = DoNeedFakeBlack;
|
||||
} else if (!areAllLevel0ImagesPOT) {
|
||||
mContext->GenerateWarning("%s is a cube map texture, with a minification filter requiring a mipmap, "
|
||||
"and either the width or the height of some level 0 image is not a power of two.",
|
||||
msg_rendering_as_black);
|
||||
mFakeBlackStatus = DoNeedFakeBlack;
|
||||
}
|
||||
}
|
||||
else // no mipmap required
|
||||
{
|
||||
if (!IsCubeComplete()) {
|
||||
mContext->GenerateWarning("%s is a cube map texture, with a minification filter not requiring a mipmap, "
|
||||
"and is not cube complete (as defined in section 3.7.10).",
|
||||
msg_rendering_as_black);
|
||||
mFakeBlackStatus = DoNeedFakeBlack;
|
||||
} else if (!AreBothWrapModesClampToEdge() && !areAllLevel0ImagesPOT) {
|
||||
mContext->GenerateWarning("%s is a cube map texture, with a minification filter not requiring a mipmap, "
|
||||
"with some level 0 image having width or height not a power of two, and with a wrap mode "
|
||||
"different from CLAMP_TO_EDGE.", msg_rendering_as_black);
|
||||
mFakeBlackStatus = DoNeedFakeBlack;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ImageInfoBase().mType == LOCAL_GL_FLOAT &&
|
||||
!Context()->IsExtensionEnabled(WebGLContext::OES_texture_float_linear))
|
||||
{
|
||||
if (mMinFilter == LOCAL_GL_LINEAR ||
|
||||
mMinFilter == LOCAL_GL_LINEAR_MIPMAP_LINEAR ||
|
||||
mMinFilter == LOCAL_GL_LINEAR_MIPMAP_NEAREST ||
|
||||
mMinFilter == LOCAL_GL_NEAREST_MIPMAP_LINEAR)
|
||||
{
|
||||
mContext->GenerateWarning("%s is a texture with a linear minification filter, "
|
||||
"which is not compatible with gl.FLOAT by default. "
|
||||
"Try enabling the OES_texture_float_linear extension if supported.", msg_rendering_as_black);
|
||||
mFakeBlackStatus = DoNeedFakeBlack;
|
||||
}
|
||||
else if (mMagFilter == LOCAL_GL_LINEAR)
|
||||
{
|
||||
mContext->GenerateWarning("%s is a texture with a linear magnification filter, "
|
||||
"which is not compatible with gl.FLOAT by default. "
|
||||
"Try enabling the OES_texture_float_linear extension if supported.", msg_rendering_as_black);
|
||||
mFakeBlackStatus = DoNeedFakeBlack;
|
||||
}
|
||||
}
|
||||
|
||||
// we have exhausted all cases where we do need fakeblack, so if the status is still unknown,
|
||||
// that means that we do NOT need it.
|
||||
if (mFakeBlackStatus == DontKnowIfNeedFakeBlack)
|
||||
mFakeBlackStatus = DoNotNeedFakeBlack;
|
||||
WebGLTextureFakeBlackStatus
|
||||
WebGLTexture::ResolvedFakeBlackStatus() {
|
||||
if (MOZ_LIKELY(mFakeBlackStatus != WebGLTextureFakeBlackStatus::Unknown)) {
|
||||
return mFakeBlackStatus;
|
||||
}
|
||||
|
||||
return mFakeBlackStatus == DoNeedFakeBlack;
|
||||
// Determine if the texture needs to be faked as a black texture.
|
||||
// See 3.8.2 Shader Execution in the OpenGL ES 2.0.24 spec.
|
||||
|
||||
for (size_t face = 0; face < mFacesCount; ++face) {
|
||||
if (ImageInfoAtFace(face, 0).mImageDataStatus == WebGLImageDataStatus::NoImageData) {
|
||||
// In case of undefined texture image, we don't print any message because this is a very common
|
||||
// and often legitimate case (asynchronous texture loading).
|
||||
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
|
||||
return mFakeBlackStatus;
|
||||
}
|
||||
}
|
||||
|
||||
const char *msg_rendering_as_black
|
||||
= "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 (DoesMinFilterRequireMipmap())
|
||||
{
|
||||
if (!IsMipmapTexture2DComplete()) {
|
||||
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);
|
||||
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
|
||||
} else if (!ImageInfoAt(mTarget, 0).IsPowerOfTwo()) {
|
||||
mContext->GenerateWarning
|
||||
("%s is a 2D 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;
|
||||
}
|
||||
}
|
||||
else // no mipmap required
|
||||
{
|
||||
if (!ImageInfoAt(mTarget, 0).IsPositive()) {
|
||||
mContext->GenerateWarning
|
||||
("%s is a 2D texture and its width or height is equal to zero.",
|
||||
msg_rendering_as_black);
|
||||
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
|
||||
} else if (!AreBothWrapModesClampToEdge() && !ImageInfoAt(mTarget, 0).IsPowerOfTwo()) {
|
||||
mContext->GenerateWarning
|
||||
("%s is a 2D 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);
|
||||
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // cube map
|
||||
{
|
||||
bool areAllLevel0ImagesPOT = true;
|
||||
for (size_t face = 0; face < mFacesCount; ++face)
|
||||
areAllLevel0ImagesPOT &= ImageInfoAtFace(face, 0).IsPowerOfTwo();
|
||||
|
||||
if (DoesMinFilterRequireMipmap())
|
||||
{
|
||||
if (!IsMipmapCubeComplete()) {
|
||||
mContext->GenerateWarning("%s is a cube map texture, with a minification filter requiring a mipmap, "
|
||||
"and is not mipmap cube complete (as defined in section 3.7.10).",
|
||||
msg_rendering_as_black);
|
||||
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
|
||||
} else if (!areAllLevel0ImagesPOT) {
|
||||
mContext->GenerateWarning("%s is a cube map texture, with a minification filter requiring a mipmap, "
|
||||
"and either the width or the height of some level 0 image is not a power of two.",
|
||||
msg_rendering_as_black);
|
||||
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
|
||||
}
|
||||
}
|
||||
else // no mipmap required
|
||||
{
|
||||
if (!IsCubeComplete()) {
|
||||
mContext->GenerateWarning("%s is a cube map texture, with a minification filter not requiring a mipmap, "
|
||||
"and is not cube complete (as defined in section 3.7.10).",
|
||||
msg_rendering_as_black);
|
||||
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
|
||||
} else if (!AreBothWrapModesClampToEdge() && !areAllLevel0ImagesPOT) {
|
||||
mContext->GenerateWarning("%s is a cube map texture, with a minification filter not requiring a mipmap, "
|
||||
"with some level 0 image having width or height not a power of two, and with a wrap mode "
|
||||
"different from CLAMP_TO_EDGE.", msg_rendering_as_black);
|
||||
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ImageInfoBase().mType == LOCAL_GL_FLOAT &&
|
||||
!Context()->IsExtensionEnabled(WebGLContext::OES_texture_float_linear))
|
||||
{
|
||||
if (mMinFilter == LOCAL_GL_LINEAR ||
|
||||
mMinFilter == LOCAL_GL_LINEAR_MIPMAP_LINEAR ||
|
||||
mMinFilter == LOCAL_GL_LINEAR_MIPMAP_NEAREST ||
|
||||
mMinFilter == LOCAL_GL_NEAREST_MIPMAP_LINEAR)
|
||||
{
|
||||
mContext->GenerateWarning("%s is a texture with a linear minification filter, "
|
||||
"which is not compatible with gl.FLOAT by default. "
|
||||
"Try enabling the OES_texture_float_linear extension if supported.", msg_rendering_as_black);
|
||||
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
|
||||
}
|
||||
else if (mMagFilter == LOCAL_GL_LINEAR)
|
||||
{
|
||||
mContext->GenerateWarning("%s is a texture with a linear magnification filter, "
|
||||
"which is not compatible with gl.FLOAT by default. "
|
||||
"Try enabling the OES_texture_float_linear extension if supported.", msg_rendering_as_black);
|
||||
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
|
||||
}
|
||||
}
|
||||
|
||||
// We have exhausted all cases of incomplete textures, where we would need opaque black.
|
||||
// We may still need transparent black in case of uninitialized image data.
|
||||
bool hasUninitializedImageData = false;
|
||||
for (size_t level = 0; level <= mMaxLevelWithCustomImages; ++level) {
|
||||
for (size_t face = 0; face < mFacesCount; ++face) {
|
||||
hasUninitializedImageData |= (ImageInfoAtFace(face, level).mImageDataStatus == WebGLImageDataStatus::UninitializedImageData);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasUninitializedImageData) {
|
||||
bool hasAnyInitializedImageData = false;
|
||||
for (size_t level = 0; level <= mMaxLevelWithCustomImages; ++level) {
|
||||
for (size_t face = 0; face < mFacesCount; ++face) {
|
||||
if (ImageInfoAtFace(face, level).mImageDataStatus == WebGLImageDataStatus::InitializedImageData) {
|
||||
hasAnyInitializedImageData = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasAnyInitializedImageData) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasAnyInitializedImageData) {
|
||||
// The texture contains some initialized image data, and some uninitialized image data.
|
||||
// In this case, we have no choice but to initialize all image data now. Fortunately,
|
||||
// in this case we know that we can't be dealing with a depth texture per WEBGL_depth_texture
|
||||
// and ANGLE_depth_texture (which allow only one image per texture) so we can assume that
|
||||
// glTexImage2D is able to upload data to images.
|
||||
for (size_t level = 0; level <= mMaxLevelWithCustomImages; ++level) {
|
||||
for (size_t face = 0; face < mFacesCount; ++face) {
|
||||
GLenum imageTarget = mTarget == LOCAL_GL_TEXTURE_2D
|
||||
? LOCAL_GL_TEXTURE_2D
|
||||
: LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
|
||||
const ImageInfo& imageInfo = ImageInfoAt(imageTarget, level);
|
||||
if (imageInfo.mImageDataStatus == WebGLImageDataStatus::UninitializedImageData) {
|
||||
DoDeferredImageInitialization(imageTarget, level);
|
||||
}
|
||||
}
|
||||
}
|
||||
mFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded;
|
||||
} else {
|
||||
// The texture only contains uninitialized image data. In this case,
|
||||
// we can use a black texture for it.
|
||||
mFakeBlackStatus = WebGLTextureFakeBlackStatus::UninitializedImageData;
|
||||
}
|
||||
}
|
||||
|
||||
// we have exhausted all cases where we do need fakeblack, so if the status is still unknown,
|
||||
// that means that we do NOT need it.
|
||||
if (mFakeBlackStatus == WebGLTextureFakeBlackStatus::Unknown) {
|
||||
mFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mFakeBlackStatus != WebGLTextureFakeBlackStatus::Unknown);
|
||||
return mFakeBlackStatus;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLTexture::DoDeferredImageInitialization(GLenum imageTarget, GLint level)
|
||||
{
|
||||
const ImageInfo& imageInfo = ImageInfoAt(imageTarget, level);
|
||||
MOZ_ASSERT(imageInfo.mImageDataStatus == WebGLImageDataStatus::UninitializedImageData);
|
||||
|
||||
mContext->MakeContextCurrent();
|
||||
gl::ScopedBindTexture autoBindTex(mContext->gl, GLName(), mTarget);
|
||||
|
||||
WebGLTexelFormat texelformat = GetWebGLTexelFormat(imageInfo.mFormat, imageInfo.mType);
|
||||
uint32_t texelsize = WebGLTexelConversions::TexelBytesForFormat(texelformat);
|
||||
CheckedUint32 checked_byteLength
|
||||
= WebGLContext::GetImageSize(
|
||||
imageInfo.mHeight,
|
||||
imageInfo.mWidth,
|
||||
texelsize,
|
||||
mContext->mPixelStoreUnpackAlignment);
|
||||
MOZ_ASSERT(checked_byteLength.isValid()); // should have been checked earlier
|
||||
void *zeros = calloc(1, checked_byteLength.value());
|
||||
GLenum error
|
||||
= mContext->CheckedTexImage2D(imageTarget, level, imageInfo.mFormat,
|
||||
imageInfo.mWidth, imageInfo.mHeight,
|
||||
0, imageInfo.mFormat, imageInfo.mType,
|
||||
zeros);
|
||||
|
||||
free(zeros);
|
||||
SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData);
|
||||
|
||||
if (error) {
|
||||
// Should only be OUT_OF_MEMORY. Anyway, there's no good way to recover from this here.
|
||||
MOZ_CRASH(); // errors on texture upload have been related to video memory exposure in the past.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTexture)
|
||||
|
|
|
@ -21,6 +21,15 @@ inline bool is_pot_assuming_nonnegative(GLsizei x)
|
|||
return x && (x & (x-1)) == 0;
|
||||
}
|
||||
|
||||
inline bool FormatHasAlpha(GLenum format)
|
||||
{
|
||||
return format == LOCAL_GL_RGBA ||
|
||||
format == LOCAL_GL_LUMINANCE_ALPHA ||
|
||||
format == LOCAL_GL_ALPHA ||
|
||||
format == LOCAL_GL_RGBA4 ||
|
||||
format == LOCAL_GL_RGB5_A1;
|
||||
}
|
||||
|
||||
// NOTE: When this class is switched to new DOM bindings, update the (then-slow)
|
||||
// WrapObject calls in GetParameter and GetFramebufferAttachmentParameter.
|
||||
class WebGLTexture MOZ_FINAL
|
||||
|
@ -66,28 +75,33 @@ protected:
|
|||
|
||||
public:
|
||||
|
||||
class ImageInfo : public WebGLRectangleObject {
|
||||
class ImageInfo
|
||||
: public WebGLRectangleObject
|
||||
{
|
||||
public:
|
||||
ImageInfo()
|
||||
: mFormat(0)
|
||||
, mType(0)
|
||||
, mIsDefined(false)
|
||||
, mImageDataStatus(WebGLImageDataStatus::NoImageData)
|
||||
{}
|
||||
|
||||
ImageInfo(GLsizei width, GLsizei height,
|
||||
GLenum format, GLenum type)
|
||||
GLenum format, GLenum type, WebGLImageDataStatus status)
|
||||
: WebGLRectangleObject(width, height)
|
||||
, mFormat(format)
|
||||
, mType(type)
|
||||
, mIsDefined(true)
|
||||
{}
|
||||
, mImageDataStatus(status)
|
||||
{
|
||||
// shouldn't use this constructor to construct a null ImageInfo
|
||||
MOZ_ASSERT(status != WebGLImageDataStatus::NoImageData);
|
||||
}
|
||||
|
||||
bool operator==(const ImageInfo& a) const {
|
||||
return mIsDefined == a.mIsDefined &&
|
||||
mWidth == a.mWidth &&
|
||||
mHeight == a.mHeight &&
|
||||
mFormat == a.mFormat &&
|
||||
mType == a.mType;
|
||||
return mImageDataStatus == a.mImageDataStatus &&
|
||||
mWidth == a.mWidth &&
|
||||
mHeight == a.mHeight &&
|
||||
mFormat == a.mFormat &&
|
||||
mType == a.mType;
|
||||
}
|
||||
bool operator!=(const ImageInfo& a) const {
|
||||
return !(*this == a);
|
||||
|
@ -102,12 +116,15 @@ public:
|
|||
return is_pot_assuming_nonnegative(mWidth) &&
|
||||
is_pot_assuming_nonnegative(mHeight); // negative sizes should never happen (caught in texImage2D...)
|
||||
}
|
||||
bool HasUninitializedImageData() const {
|
||||
return mImageDataStatus == WebGLImageDataStatus::UninitializedImageData;
|
||||
}
|
||||
int64_t MemoryUsage() const;
|
||||
GLenum Format() const { return mFormat; }
|
||||
GLenum Type() const { return mType; }
|
||||
protected:
|
||||
GLenum mFormat, mType;
|
||||
bool mIsDefined;
|
||||
WebGLImageDataStatus mImageDataStatus;
|
||||
|
||||
friend class WebGLTexture;
|
||||
};
|
||||
|
@ -149,12 +166,12 @@ public:
|
|||
|
||||
bool HasImageInfoAt(GLenum imageTarget, GLint level) const {
|
||||
MOZ_ASSERT(imageTarget);
|
||||
|
||||
|
||||
size_t face = FaceForTarget(imageTarget);
|
||||
CheckedUint32 checked_index = CheckedUint32(level) * mFacesCount + face;
|
||||
return checked_index.isValid() &&
|
||||
checked_index.value() < mImageInfos.Length() &&
|
||||
ImageInfoAt(imageTarget, level).mIsDefined;
|
||||
ImageInfoAt(imageTarget, level).mImageDataStatus != WebGLImageDataStatus::NoImageData;
|
||||
}
|
||||
|
||||
ImageInfo& ImageInfoBase() {
|
||||
|
@ -167,6 +184,20 @@ public:
|
|||
|
||||
int64_t MemoryUsage() const;
|
||||
|
||||
void SetImageDataStatus(GLenum imageTarget, GLint level, WebGLImageDataStatus newStatus) {
|
||||
MOZ_ASSERT(HasImageInfoAt(imageTarget, level));
|
||||
ImageInfo& imageInfo = ImageInfoAt(imageTarget, level);
|
||||
// there is no way to go from having image data to not having any
|
||||
MOZ_ASSERT(newStatus != WebGLImageDataStatus::NoImageData ||
|
||||
imageInfo.mImageDataStatus == WebGLImageDataStatus::NoImageData);
|
||||
if (imageInfo.mImageDataStatus != newStatus) {
|
||||
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
|
||||
}
|
||||
imageInfo.mImageDataStatus = newStatus;
|
||||
}
|
||||
|
||||
void DoDeferredImageInitialization(GLenum imageTarget, GLint level);
|
||||
|
||||
protected:
|
||||
|
||||
GLenum mTarget;
|
||||
|
@ -176,7 +207,7 @@ protected:
|
|||
nsTArray<ImageInfo> mImageInfos;
|
||||
|
||||
bool mHaveGeneratedMipmap;
|
||||
FakeBlackStatus mFakeBlackStatus;
|
||||
WebGLTextureFakeBlackStatus mFakeBlackStatus;
|
||||
|
||||
void EnsureMaxLevelWithCustomImagesAtLeast(size_t aMaxLevelWithCustomImages) {
|
||||
mMaxLevelWithCustomImages = std::max(mMaxLevelWithCustomImages, aMaxLevelWithCustomImages);
|
||||
|
@ -197,29 +228,27 @@ protected:
|
|||
|
||||
public:
|
||||
|
||||
void SetDontKnowIfNeedFakeBlack();
|
||||
|
||||
void Bind(GLenum aTarget);
|
||||
|
||||
void SetImageInfo(GLenum aTarget, GLint aLevel,
|
||||
GLsizei aWidth, GLsizei aHeight,
|
||||
GLenum aFormat, GLenum aType);
|
||||
GLenum aFormat, GLenum aType, WebGLImageDataStatus aStatus);
|
||||
|
||||
void SetMinFilter(GLenum aMinFilter) {
|
||||
mMinFilter = aMinFilter;
|
||||
SetDontKnowIfNeedFakeBlack();
|
||||
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
|
||||
}
|
||||
void SetMagFilter(GLenum aMagFilter) {
|
||||
mMagFilter = aMagFilter;
|
||||
SetDontKnowIfNeedFakeBlack();
|
||||
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
|
||||
}
|
||||
void SetWrapS(GLenum aWrapS) {
|
||||
mWrapS = aWrapS;
|
||||
SetDontKnowIfNeedFakeBlack();
|
||||
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
|
||||
}
|
||||
void SetWrapT(GLenum aWrapT) {
|
||||
mWrapT = aWrapT;
|
||||
SetDontKnowIfNeedFakeBlack();
|
||||
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
|
||||
}
|
||||
GLenum MinFilter() const { return mMinFilter; }
|
||||
|
||||
|
@ -243,7 +272,13 @@ public:
|
|||
|
||||
bool IsMipmapCubeComplete() const;
|
||||
|
||||
bool NeedFakeBlack();
|
||||
void SetFakeBlackStatus(WebGLTextureFakeBlackStatus x) {
|
||||
mFakeBlackStatus = x;
|
||||
mContext->SetFakeBlackStatus(WebGLContextFakeBlackStatus::Unknown);
|
||||
}
|
||||
// Returns the current fake-black-status, except if it was Unknown,
|
||||
// in which case this function resolves it first, so it never returns Unknown.
|
||||
WebGLTextureFakeBlackStatus ResolvedFakeBlackStatus();
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#ifndef WEBGLTYPES_H_
|
||||
#define WEBGLTYPES_H_
|
||||
|
||||
#include "mozilla/TypedEnum.h"
|
||||
|
||||
// Most WebIDL typedefs are identical to their OpenGL counterparts.
|
||||
#include "GLTypes.h"
|
||||
|
||||
|
@ -17,13 +19,73 @@ typedef bool WebGLboolean;
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
enum FakeBlackStatus { DoNotNeedFakeBlack, DoNeedFakeBlack, DontKnowIfNeedFakeBlack };
|
||||
/*
|
||||
* WebGLContextFakeBlackStatus and WebGLTextureFakeBlackStatus are enums to
|
||||
* track what needs to use a dummy 1x1 black texture, which we refer to as a
|
||||
* 'fake black' texture.
|
||||
*
|
||||
* There are generally two things that can cause us to use such 'fake black'
|
||||
* textures:
|
||||
*
|
||||
* (1) OpenGL ES rules on sampling incomplete textures specify that they
|
||||
* must be sampled as RGBA(0, 0, 0, 1) (opaque black). We have to implement these rules
|
||||
* ourselves, if only because we do not always run on OpenGL ES, and also
|
||||
* because this is dangerously close to the kind of case where we don't
|
||||
* want to trust the driver with corner cases of texture memory accesses.
|
||||
*
|
||||
* (2) OpenGL has cases where a renderbuffer, or a texture image, can contain
|
||||
* uninitialized image data. See below the comment about WebGLImageDataStatus.
|
||||
* WebGL must never have access to uninitialized image data. The WebGL 1 spec,
|
||||
* section 4.1 'Resource Restrictions', specifies that in any such case, the
|
||||
* uninitialized image data must be exposed to WebGL as if it were filled
|
||||
* with zero bytes, which means it's either opaque or transparent black
|
||||
* depending on whether the image format has alpha.
|
||||
*
|
||||
* Why are there _two_ separate enums there, WebGLContextFakeBlackStatus
|
||||
* and WebGLTextureFakeBlackStatus? That's because each texture must know the precise
|
||||
* 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)
|
||||
Unknown,
|
||||
NotNeeded,
|
||||
Needed
|
||||
MOZ_END_ENUM_CLASS(WebGLContextFakeBlackStatus)
|
||||
|
||||
struct VertexAttrib0Status {
|
||||
enum { Default, EmulatedUninitializedArray, EmulatedInitializedArray };
|
||||
};
|
||||
MOZ_BEGIN_ENUM_CLASS(WebGLTextureFakeBlackStatus, int)
|
||||
Unknown,
|
||||
NotNeeded,
|
||||
IncompleteTexture,
|
||||
UninitializedImageData
|
||||
MOZ_END_ENUM_CLASS(WebGLTextureFakeBlackStatus)
|
||||
|
||||
namespace WebGLTexelConversions {
|
||||
/*
|
||||
* Implementing WebGL (or OpenGL ES 2.0) on top of desktop OpenGL requires
|
||||
* emulating the vertex attrib 0 array when it's not enabled. Indeed,
|
||||
* 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)
|
||||
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
|
||||
MOZ_END_ENUM_CLASS(WebGLVertexAttrib0Status)
|
||||
|
||||
/*
|
||||
* Enum to track the status of image data (renderbuffer or texture image) presence
|
||||
* and initialization.
|
||||
*
|
||||
* - NoImageData is the initial state before any image data is allocated.
|
||||
* - InitializedImageData is the state after image data is allocated and initialized.
|
||||
* - UninitializedImageData is an intermediate state where data is allocated but not
|
||||
* 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)
|
||||
NoImageData,
|
||||
UninitializedImageData,
|
||||
InitializedImageData
|
||||
MOZ_END_ENUM_CLASS(WebGLImageDataStatus)
|
||||
|
||||
/*
|
||||
* The formats that may participate, either as source or destination formats,
|
||||
|
@ -33,8 +95,7 @@ namespace WebGLTexelConversions {
|
|||
* - additional source formats, depending on browser details, used when uploading
|
||||
* textures from DOM elements. See gfxImageSurface::Format().
|
||||
*/
|
||||
enum WebGLTexelFormat
|
||||
{
|
||||
MOZ_BEGIN_ENUM_CLASS(WebGLTexelFormat, int)
|
||||
// dummy error code returned by GetWebGLTexelFormat in error cases,
|
||||
// after assertion failure (so this never happens in debug builds)
|
||||
BadFormat,
|
||||
|
@ -64,9 +125,7 @@ enum WebGLTexelFormat
|
|||
RGBA5551,
|
||||
RGBA4444,
|
||||
RGBA32F // used for OES_texture_float extension
|
||||
};
|
||||
|
||||
} // end namespace WebGLTexelConversions
|
||||
MOZ_END_ENUM_CLASS(WebGLTexelFormat)
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ struct WebGLUniformInfo {
|
|||
case SH_FLOAT_MAT4:
|
||||
return 16;
|
||||
default:
|
||||
NS_ABORT(); // should never get here
|
||||
MOZ_ASSERT(false); // should never get here
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,10 +34,10 @@ void WebGLVertexArray::Delete() {
|
|||
}
|
||||
|
||||
mBoundElementArrayBuffer = nullptr;
|
||||
mAttribBuffers.Clear();
|
||||
mAttribs.Clear();
|
||||
}
|
||||
|
||||
bool WebGLVertexArray::EnsureAttribIndex(GLuint index, const char *info)
|
||||
bool WebGLVertexArray::EnsureAttrib(GLuint index, const char *info)
|
||||
{
|
||||
if (index >= GLuint(mContext->mGLMaxVertexAttribs)) {
|
||||
if (index == GLuint(-1)) {
|
||||
|
@ -49,15 +49,15 @@ bool WebGLVertexArray::EnsureAttribIndex(GLuint index, const char *info)
|
|||
}
|
||||
return false;
|
||||
}
|
||||
else if (index >= mAttribBuffers.Length()) {
|
||||
mAttribBuffers.SetLength(index + 1);
|
||||
else if (index >= mAttribs.Length()) {
|
||||
mAttribs.SetLength(index + 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(WebGLVertexArray,
|
||||
mAttribBuffers,
|
||||
mAttribs,
|
||||
mBoundElementArrayBuffer)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLVertexArray, AddRef)
|
||||
|
|
|
@ -59,7 +59,13 @@ public:
|
|||
void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; }
|
||||
GLuint GLName() const { return mGLName; }
|
||||
|
||||
bool EnsureAttribIndex(GLuint index, const char *info);
|
||||
bool EnsureAttrib(GLuint index, const char *info);
|
||||
bool HasAttrib(GLuint index) {
|
||||
return index < mAttribs.Length();
|
||||
}
|
||||
bool IsAttribArrayEnabled(GLuint index) {
|
||||
return HasAttrib(index) && mAttribs[index].enabled;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -71,7 +77,7 @@ private:
|
|||
|
||||
GLuint mGLName;
|
||||
bool mHasEverBeenBound;
|
||||
nsTArray<WebGLVertexAttribData> mAttribBuffers;
|
||||
nsTArray<WebGLVertexAttribData> mAttribs;
|
||||
WebGLRefPtr<WebGLBuffer> mBoundElementArrayBuffer;
|
||||
|
||||
|
||||
|
|
|
@ -608,5 +608,17 @@ AudioContext::Unmute() const
|
|||
mDestination->Unmute();
|
||||
}
|
||||
|
||||
AudioChannel
|
||||
AudioContext::MozAudioChannelType() const
|
||||
{
|
||||
return mDestination->MozAudioChannelType();
|
||||
}
|
||||
|
||||
void
|
||||
AudioContext::SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv)
|
||||
{
|
||||
mDestination->SetMozAudioChannelType(aValue, aRv);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#ifndef AudioContext_h_
|
||||
#define AudioContext_h_
|
||||
|
||||
#include "mozilla/dom/AudioContextBinding.h"
|
||||
#include "EnableWebAudioCheck.h"
|
||||
#include "MediaBufferDecoder.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
@ -238,6 +239,9 @@ public:
|
|||
|
||||
JSContext* GetJSContext() const;
|
||||
|
||||
AudioChannel MozAudioChannelType() const;
|
||||
void SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
void RemoveFromDecodeQueue(WebAudioDecodeJob* aDecodeJob);
|
||||
void ShutdownDecoder();
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
#include "OfflineAudioCompletionEvent.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -244,6 +246,7 @@ AudioDestinationNode::AudioDestinationNode(AudioContext* aContext,
|
|||
ChannelCountMode::Explicit,
|
||||
ChannelInterpretation::Speakers)
|
||||
, mFramesToProduce(aLength)
|
||||
, mAudioChannel(AudioChannel::Normal)
|
||||
{
|
||||
MediaStreamGraph* graph = aIsOffline ?
|
||||
MediaStreamGraph::CreateNonRealtimeInstance() :
|
||||
|
@ -256,10 +259,6 @@ AudioDestinationNode::AudioDestinationNode(AudioContext* aContext,
|
|||
mStream = graph->CreateAudioNodeStream(engine, MediaStreamGraph::EXTERNAL_STREAM);
|
||||
|
||||
if (!aIsOffline && UseAudioChannelService()) {
|
||||
mAudioChannelAgent = new AudioChannelAgent();
|
||||
mAudioChannelAgent->InitWithWeakCallback(nsIAudioChannelAgent::AUDIO_AGENT_CHANNEL_NORMAL,
|
||||
this);
|
||||
|
||||
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetOwner());
|
||||
if (target) {
|
||||
target->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"), this,
|
||||
|
@ -267,16 +266,7 @@ AudioDestinationNode::AudioDestinationNode(AudioContext* aContext,
|
|||
/* wantsUntrusted = */ false);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShell> docshell = do_GetInterface(GetOwner());
|
||||
if (docshell) {
|
||||
bool isActive = false;
|
||||
docshell->GetIsActive(&isActive);
|
||||
mAudioChannelAgent->SetVisibilityState(isActive);
|
||||
}
|
||||
|
||||
int32_t state = 0;
|
||||
mAudioChannelAgent->StartPlaying(&state);
|
||||
SetCanPlay(state == AudioChannelState::AUDIO_CHANNEL_STATE_NORMAL);
|
||||
CreateAudioChannelAgent();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -391,5 +381,117 @@ AudioDestinationNode::CanPlayChanged(int32_t aCanPlay)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
AudioChannel
|
||||
AudioDestinationNode::MozAudioChannelType() const
|
||||
{
|
||||
return mAudioChannel;
|
||||
}
|
||||
|
||||
void
|
||||
AudioDestinationNode::SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv)
|
||||
{
|
||||
if (Context()->IsOffline()) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aValue != mAudioChannel &&
|
||||
CheckAudioChannelPermissions(aValue)) {
|
||||
mAudioChannel = aValue;
|
||||
|
||||
if (mAudioChannelAgent) {
|
||||
CreateAudioChannelAgent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
AudioDestinationNode::CheckAudioChannelPermissions(AudioChannel aValue)
|
||||
{
|
||||
if (!Preferences::GetBool("media.useAudioChannelService")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Only normal channel doesn't need permission.
|
||||
if (aValue == AudioChannel::Normal) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> permissionManager =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
|
||||
if (!permissionManager) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(GetOwner());
|
||||
NS_ASSERTION(sop, "Window didn't QI to nsIScriptObjectPrincipal!");
|
||||
nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
|
||||
|
||||
uint32_t perm = nsIPermissionManager::UNKNOWN_ACTION;
|
||||
|
||||
nsCString channel;
|
||||
channel.AssignASCII(AudioChannelValues::strings[uint32_t(aValue)].value,
|
||||
AudioChannelValues::strings[uint32_t(aValue)].length);
|
||||
permissionManager->TestExactPermissionFromPrincipal(principal,
|
||||
nsCString(NS_LITERAL_CSTRING("audio-channel-") + channel).get(),
|
||||
&perm);
|
||||
|
||||
return perm == nsIPermissionManager::ALLOW_ACTION;
|
||||
}
|
||||
|
||||
void
|
||||
AudioDestinationNode::CreateAudioChannelAgent()
|
||||
{
|
||||
if (mAudioChannelAgent) {
|
||||
mAudioChannelAgent->StopPlaying();
|
||||
}
|
||||
|
||||
AudioChannelType type = AUDIO_CHANNEL_NORMAL;
|
||||
switch(mAudioChannel) {
|
||||
case AudioChannel::Normal:
|
||||
type = AUDIO_CHANNEL_NORMAL;
|
||||
break;
|
||||
|
||||
case AudioChannel::Content:
|
||||
type = AUDIO_CHANNEL_CONTENT;
|
||||
break;
|
||||
|
||||
case AudioChannel::Notification:
|
||||
type = AUDIO_CHANNEL_NOTIFICATION;
|
||||
break;
|
||||
|
||||
case AudioChannel::Alarm:
|
||||
type = AUDIO_CHANNEL_ALARM;
|
||||
break;
|
||||
|
||||
case AudioChannel::Telephony:
|
||||
type = AUDIO_CHANNEL_TELEPHONY;
|
||||
break;
|
||||
|
||||
case AudioChannel::Ringer:
|
||||
type = AUDIO_CHANNEL_RINGER;
|
||||
break;
|
||||
|
||||
case AudioChannel::Publicnotification:
|
||||
type = AUDIO_CHANNEL_PUBLICNOTIFICATION;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
mAudioChannelAgent = new AudioChannelAgent();
|
||||
mAudioChannelAgent->InitWithWeakCallback(type, this);
|
||||
|
||||
nsCOMPtr<nsIDocShell> docshell = do_GetInterface(GetOwner());
|
||||
if (docshell) {
|
||||
bool isActive = false;
|
||||
docshell->GetIsActive(&isActive);
|
||||
mAudioChannelAgent->SetVisibilityState(isActive);
|
||||
}
|
||||
|
||||
int32_t state = 0;
|
||||
mAudioChannelAgent->StartPlaying(&state);
|
||||
SetCanPlay(state == AudioChannelState::AUDIO_CHANNEL_STATE_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
#ifndef AudioDestinationNode_h_
|
||||
#define AudioDestinationNode_h_
|
||||
|
||||
#include "mozilla/dom/AudioContextBinding.h"
|
||||
#include "AudioNode.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsIAudioChannelAgent.h"
|
||||
#include "AudioChannelCommon.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -59,13 +61,22 @@ public:
|
|||
// nsIAudioChannelAgentCallback
|
||||
NS_IMETHOD CanPlayChanged(int32_t aCanPlay);
|
||||
|
||||
AudioChannel MozAudioChannelType() const;
|
||||
void SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
bool CheckAudioChannelPermissions(AudioChannel aValue);
|
||||
void CreateAudioChannelAgent();
|
||||
|
||||
void SetCanPlay(bool aCanPlay);
|
||||
|
||||
SelfReference<AudioDestinationNode> mOfflineRenderingRef;
|
||||
uint32_t mFramesToProduce;
|
||||
|
||||
nsCOMPtr<nsIAudioChannelAgent> mAudioChannelAgent;
|
||||
|
||||
// Audio Channel Type.
|
||||
AudioChannel mAudioChannel;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -110,3 +110,4 @@ support-files =
|
|||
[test_waveShaperNoCurve.html]
|
||||
[test_waveShaperZeroLengthCurve.html]
|
||||
[test_audioDestinationNode.html]
|
||||
[test_mozaudiochannel.html]
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for mozaudiochannel</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
function test_basic() {
|
||||
var ac = new AudioContext();
|
||||
ok(ac, "AudioContext created");
|
||||
|
||||
// Default
|
||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
||||
|
||||
// random wrong channel
|
||||
ac.mozAudioChannelType = "foo";
|
||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
||||
|
||||
// Unpermitted channels
|
||||
ac.mozAudioChannelType = "content";
|
||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
||||
|
||||
ac.mozAudioChannelType = "notification";
|
||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
||||
|
||||
ac.mozAudioChannelType = "alarm";
|
||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
||||
|
||||
ac.mozAudioChannelType = "telephony";
|
||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
||||
|
||||
ac.mozAudioChannelType = "ringer";
|
||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
||||
|
||||
ac.mozAudioChannelType = "publicnotification";
|
||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
||||
|
||||
runTest();
|
||||
}
|
||||
|
||||
function test_permission(aChannel) {
|
||||
var ac = new AudioContext();
|
||||
ok(ac, "AudioContext created");
|
||||
|
||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
||||
|
||||
SpecialPowers.pushPermissions(
|
||||
[{ "type": "audio-channel-" + aChannel, "allow": 1, "context": document }],
|
||||
function() {
|
||||
ac.mozAudioChannelType = aChannel;
|
||||
is(ac.mozAudioChannelType, aChannel, "Default ac channel == '" + aChannel + "'");
|
||||
runTest();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
var tests = [
|
||||
test_basic,
|
||||
|
||||
function() { test_permission("content"); },
|
||||
function() { test_permission("notification"); },
|
||||
function() { test_permission("alarm"); },
|
||||
function() { test_permission("telephony"); },
|
||||
function() { test_permission("ringer"); },
|
||||
function() { test_permission("publicnotification"); }
|
||||
];
|
||||
|
||||
function runTest() {
|
||||
if (!tests.length) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [["media.useAudioChannelService", true ]]}, runTest);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -7,14 +7,14 @@
|
|||
interface nsIObserver;
|
||||
|
||||
// Notification service that also provides the manifest URL
|
||||
[scriptable, uuid(61c4adf4-187d-4d18-937c-4df17bc01073)]
|
||||
[scriptable, uuid(50cb17d2-dc8a-4aa6-bcd3-94d76af14e20)]
|
||||
interface nsIAppNotificationService : nsISupports
|
||||
{
|
||||
void showAppNotification(in AString imageUrl,
|
||||
in AString title,
|
||||
in AString text,
|
||||
[optional] in boolean textClickable,
|
||||
[optional] in AString manifestURL,
|
||||
[optional] in nsIObserver alertListener,
|
||||
[optional] in AString id);
|
||||
in nsIObserver alertListener,
|
||||
// details should be a WebIDL
|
||||
// AppNotificationServiceOptions Dictionary object
|
||||
in jsval details);
|
||||
};
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "mozilla/dom/DesktopNotification.h"
|
||||
#include "mozilla/dom/DesktopNotificationBinding.h"
|
||||
#include "mozilla/dom/AppNotificationServiceOptionsBinding.h"
|
||||
#include "nsContentPermissionHelper.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "mozilla/dom/PBrowserChild.h"
|
||||
|
@ -91,11 +92,18 @@ DesktopNotification::PostDesktopNotification()
|
|||
nsCOMPtr<nsIAppsService> appsService = do_GetService("@mozilla.org/AppsService;1");
|
||||
nsString manifestUrl = EmptyString();
|
||||
appsService->GetManifestURLByLocalId(appId, manifestUrl);
|
||||
mozilla::AutoSafeJSContext cx;
|
||||
JS::RootedValue val(cx);
|
||||
AppNotificationServiceOptions ops;
|
||||
ops.mTextClickable = true;
|
||||
ops.mManifestURL = manifestUrl;
|
||||
|
||||
if (!ops.ToObject(cx, JS::NullPtr(), &val)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return appNotifier->ShowAppNotification(mIconURL, mTitle, mDescription,
|
||||
true,
|
||||
manifestUrl,
|
||||
mObserver,
|
||||
EmptyString());
|
||||
mObserver, val);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "PCOMContentPermissionRequestChild.h"
|
||||
#include "mozilla/dom/Notification.h"
|
||||
#include "mozilla/dom/AppNotificationServiceOptionsBinding.h"
|
||||
#include "mozilla/dom/OwningNonNull.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "TabChild.h"
|
||||
|
@ -375,11 +376,22 @@ Notification::ShowInternal()
|
|||
nsCOMPtr<nsIAppsService> appsService = do_GetService("@mozilla.org/AppsService;1");
|
||||
nsString manifestUrl = EmptyString();
|
||||
appsService->GetManifestURLByLocalId(appId, manifestUrl);
|
||||
mozilla::AutoSafeJSContext cx;
|
||||
JS::RootedValue val(cx);
|
||||
AppNotificationServiceOptions ops;
|
||||
ops.mTextClickable = true;
|
||||
ops.mManifestURL = manifestUrl;
|
||||
ops.mId = alertName;
|
||||
ops.mDir = DirectionToString(mDir);
|
||||
ops.mLang = mLang;
|
||||
|
||||
if (!ops.ToObject(cx, JS::NullPtr(), &val)) {
|
||||
NS_WARNING("Converting dict to object failed!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return appNotifier->ShowAppNotification(mIconUrl, mTitle, mBody,
|
||||
true,
|
||||
manifestUrl,
|
||||
observer,
|
||||
alertName);
|
||||
observer, val);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -9,7 +9,7 @@ var registrar = SpecialPowers.wrap(SpecialPowers.Components).manager.
|
|||
|
||||
var mockAlertsService = {
|
||||
showAlertNotification: function(imageUrl, title, text, textClickable,
|
||||
cookie, alertListener, name) {
|
||||
cookie, alertListener, name, bidi, lang) {
|
||||
// probably should do this async....
|
||||
SpecialPowers.wrap(alertListener).observe(null, "alertshow", cookie);
|
||||
|
||||
|
@ -20,9 +20,9 @@ var mockAlertsService = {
|
|||
SpecialPowers.wrap(alertListener).observe(null, "alertfinished", cookie);
|
||||
},
|
||||
|
||||
showAppNotification: function(imageUrl, title, text, textClickable,
|
||||
manifestURL, alertListener) {
|
||||
this.showAlertNotification(imageUrl, title, text, textClickable, "", alertListener, "");
|
||||
showAppNotification: function(imageUrl, title, text, alertListener, details) {
|
||||
this.showAlertNotification(imageUrl, title, text, details.textClickable, "",
|
||||
alertListener, details.name, details.dir, details.lang);
|
||||
},
|
||||
|
||||
QueryInterface: function(aIID) {
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/.
|
||||
*/
|
||||
|
||||
interface MozObserver;
|
||||
|
||||
dictionary AppNotificationServiceOptions {
|
||||
boolean textClickable = false;
|
||||
DOMString manifestURL = "";
|
||||
DOMString id = "";
|
||||
DOMString dir = "";
|
||||
DOMString lang = "";
|
||||
};
|
|
@ -98,4 +98,19 @@ partial interface AudioContext {
|
|||
optional unsigned long numberOfOutputChannels = 2);
|
||||
};
|
||||
|
||||
enum AudioChannel {
|
||||
"normal",
|
||||
"content",
|
||||
"notification",
|
||||
"alarm",
|
||||
"telephony",
|
||||
"ringer",
|
||||
"publicnotification",
|
||||
};
|
||||
|
||||
// Mozilla extensions
|
||||
partial interface AudioContext {
|
||||
// Read HTMLMediaElement.webidl for more information about this attribute.
|
||||
[Pref="media.useAudioChannelService", SetterThrows]
|
||||
attribute AudioChannel mozAudioChannelType;
|
||||
};
|
||||
|
|
|
@ -27,6 +27,7 @@ interface DummyInterface : EventTarget {
|
|||
void DOMWindowResizeEventDetail(optional DOMWindowResizeEventDetail arg);
|
||||
void WifiOptions(optional WifiCommandOptions arg1,
|
||||
optional WifiResultOptions arg2);
|
||||
void AppNotificationServiceOptions(optional AppNotificationServiceOptions arg);
|
||||
};
|
||||
|
||||
interface DummyInterfaceWorkers {
|
||||
|
|
|
@ -19,6 +19,7 @@ WEBIDL_FILES = [
|
|||
'AbstractWorker.webidl',
|
||||
'AnalyserNode.webidl',
|
||||
'AnimationEvent.webidl',
|
||||
'AppNotificationServiceOptions.webidl',
|
||||
'ArchiveReader.webidl',
|
||||
'ArchiveRequest.webidl',
|
||||
'Attr.webidl',
|
||||
|
|
|
@ -0,0 +1,425 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["WifiCommand"];
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/systemlibs.js");
|
||||
|
||||
const SUPP_PROP = "init.svc.wpa_supplicant";
|
||||
const WPA_SUPPLICANT = "wpa_supplicant";
|
||||
|
||||
this.WifiCommand = function(controlMessage) {
|
||||
var command = {};
|
||||
|
||||
//-------------------------------------------------
|
||||
// General commands.
|
||||
//-------------------------------------------------
|
||||
|
||||
command.loadDriver = function (callback) {
|
||||
voidControlMessage("load_driver", function(status) {
|
||||
callback(status);
|
||||
});
|
||||
};
|
||||
|
||||
command.unloadDriver = function (callback) {
|
||||
voidControlMessage("unload_driver", function(status) {
|
||||
callback(status);
|
||||
});
|
||||
};
|
||||
|
||||
command.startSupplicant = function (callback) {
|
||||
voidControlMessage("start_supplicant", callback);
|
||||
};
|
||||
|
||||
command.killSupplicant = function (callback) {
|
||||
// It is interesting to note that this function does exactly what
|
||||
// wifi_stop_supplicant does. Unforunately, on the Galaxy S2, Samsung
|
||||
// changed that function in a way that means that it doesn't recognize
|
||||
// wpa_supplicant as already running. Therefore, we have to roll our own
|
||||
// version here.
|
||||
stopProcess(SUPP_PROP, WPA_SUPPLICANT, callback);
|
||||
};
|
||||
|
||||
command.terminateSupplicant = function (callback) {
|
||||
doBooleanCommand("TERMINATE", "OK", callback);
|
||||
};
|
||||
|
||||
command.stopSupplicant = function (callback) {
|
||||
voidControlMessage("stop_supplicant", callback);
|
||||
};
|
||||
|
||||
command.listNetworks = function (callback) {
|
||||
doStringCommand("LIST_NETWORKS", callback);
|
||||
};
|
||||
|
||||
command.addNetwork = function (callback) {
|
||||
doIntCommand("ADD_NETWORK", callback);
|
||||
};
|
||||
|
||||
command.setNetworkVariable = function (netId, name, value, callback) {
|
||||
doBooleanCommand("SET_NETWORK " + netId + " " + name + " " +
|
||||
value, "OK", callback);
|
||||
};
|
||||
|
||||
command.getNetworkVariable = function (netId, name, callback) {
|
||||
doStringCommand("GET_NETWORK " + netId + " " + name, callback);
|
||||
};
|
||||
|
||||
command.removeNetwork = function (netId, callback) {
|
||||
doBooleanCommand("REMOVE_NETWORK " + netId, "OK", callback);
|
||||
};
|
||||
|
||||
command.enableNetwork = function (netId, disableOthers, callback) {
|
||||
doBooleanCommand((disableOthers ? "SELECT_NETWORK " : "ENABLE_NETWORK ") +
|
||||
netId, "OK", callback);
|
||||
};
|
||||
|
||||
command.disableNetwork = function (netId, callback) {
|
||||
doBooleanCommand("DISABLE_NETWORK " + netId, "OK", callback);
|
||||
};
|
||||
|
||||
command.status = function (callback) {
|
||||
doStringCommand("STATUS", callback);
|
||||
};
|
||||
|
||||
command.ping = function (callback) {
|
||||
doBooleanCommand("PING", "PONG", callback);
|
||||
};
|
||||
|
||||
command.scanResults = function (callback) {
|
||||
doStringCommand("SCAN_RESULTS", callback);
|
||||
};
|
||||
|
||||
command.disconnect = function (callback) {
|
||||
doBooleanCommand("DISCONNECT", "OK", callback);
|
||||
};
|
||||
|
||||
command.reconnect = function (callback) {
|
||||
doBooleanCommand("RECONNECT", "OK", callback);
|
||||
};
|
||||
|
||||
command.reassociate = function (callback) {
|
||||
doBooleanCommand("REASSOCIATE", "OK", callback);
|
||||
};
|
||||
|
||||
command.setBackgroundScan = function (enable, callback) {
|
||||
doBooleanCommand("SET pno " + (enable ? "1" : "0"),
|
||||
"OK",
|
||||
function(ok) {
|
||||
callback(true, ok);
|
||||
});
|
||||
};
|
||||
|
||||
command.doSetScanMode = function (setActive, callback) {
|
||||
doBooleanCommand(setActive ?
|
||||
"DRIVER SCAN-ACTIVE" :
|
||||
"DRIVER SCAN-PASSIVE", "OK", callback);
|
||||
};
|
||||
|
||||
command.scan = function (callback) {
|
||||
doBooleanCommand("SCAN", "OK", callback);
|
||||
};
|
||||
|
||||
command.setLogLevel = function (level, callback) {
|
||||
doBooleanCommand("LOG_LEVEL " + level, "OK", callback);
|
||||
};
|
||||
|
||||
command.getLogLevel = function (callback) {
|
||||
doStringCommand("LOG_LEVEL", callback);
|
||||
};
|
||||
|
||||
command.wpsPbc = function (callback) {
|
||||
doBooleanCommand("WPS_PBC", "OK", callback);
|
||||
};
|
||||
|
||||
command.wpsPin = function (detail, callback) {
|
||||
doStringCommand("WPS_PIN " +
|
||||
(detail.bssid === undefined ? "any" : detail.bssid) +
|
||||
(detail.pin === undefined ? "" : (" " + detail.pin)),
|
||||
callback);
|
||||
};
|
||||
|
||||
command.wpsCancel = function (callback) {
|
||||
doBooleanCommand("WPS_CANCEL", "OK", callback);
|
||||
};
|
||||
|
||||
command.startDriver = function (callback) {
|
||||
doBooleanCommand("DRIVER START", "OK");
|
||||
};
|
||||
|
||||
command.stopDriver = function (callback) {
|
||||
doBooleanCommand("DRIVER STOP", "OK");
|
||||
};
|
||||
|
||||
command.startPacketFiltering = function (callback) {
|
||||
var commandChain = ["DRIVER RXFILTER-ADD 0",
|
||||
"DRIVER RXFILTER-ADD 1",
|
||||
"DRIVER RXFILTER-ADD 3",
|
||||
"DRIVER RXFILTER-START"];
|
||||
|
||||
doBooleanCommandChain(commandChain, callback);
|
||||
};
|
||||
|
||||
command.stopPacketFiltering = function (callback) {
|
||||
var commandChain = ["DRIVER RXFILTER-STOP",
|
||||
"DRIVER RXFILTER-REMOVE 3",
|
||||
"DRIVER RXFILTER-REMOVE 1",
|
||||
"DRIVER RXFILTER-REMOVE 0"];
|
||||
|
||||
doBooleanCommandChain(commandChain, callback);
|
||||
};
|
||||
|
||||
command.doGetRssi = function (cmd, callback) {
|
||||
doCommand(cmd, function(data) {
|
||||
var rssi = -200;
|
||||
|
||||
if (!data.status) {
|
||||
// If we are associating, the reply is "OK".
|
||||
var reply = data.reply;
|
||||
if (reply !== "OK") {
|
||||
// Format is: <SSID> rssi XX". SSID can contain spaces.
|
||||
var offset = reply.lastIndexOf("rssi ");
|
||||
if (offset !== -1) {
|
||||
rssi = reply.substr(offset + 5) | 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
callback(rssi);
|
||||
});
|
||||
};
|
||||
|
||||
command.getRssi = function (callback) {
|
||||
command.doGetRssi("DRIVER RSSI", callback);
|
||||
};
|
||||
|
||||
command.getRssiApprox = function (callback) {
|
||||
command.doGetRssi("DRIVER RSSI-APPROX", callback);
|
||||
};
|
||||
|
||||
command.getLinkSpeed = function (callback) {
|
||||
doStringCommand("DRIVER LINKSPEED", function(reply) {
|
||||
if (reply) {
|
||||
reply = reply.split(" ")[1] | 0; // Format: LinkSpeed XX
|
||||
}
|
||||
callback(reply);
|
||||
});
|
||||
};
|
||||
|
||||
command.getConnectionInfoICS = function (callback) {
|
||||
doStringCommand("SIGNAL_POLL", function(reply) {
|
||||
if (!reply) {
|
||||
callback(null);
|
||||
return;
|
||||
}
|
||||
|
||||
let rval = {};
|
||||
var lines = reply.split("\n");
|
||||
for (let i = 0; i < lines.length; ++i) {
|
||||
let [key, value] = lines[i].split("=");
|
||||
switch (key.toUpperCase()) {
|
||||
case "RSSI":
|
||||
rval.rssi = value | 0;
|
||||
break;
|
||||
case "LINKSPEED":
|
||||
rval.linkspeed = value | 0;
|
||||
break;
|
||||
default:
|
||||
// Ignore.
|
||||
}
|
||||
}
|
||||
|
||||
callback(rval);
|
||||
});
|
||||
};
|
||||
|
||||
command.getMacAddress = function (callback) {
|
||||
doStringCommand("DRIVER MACADDR", function(reply) {
|
||||
if (reply) {
|
||||
reply = reply.split(" ")[2]; // Format: Macaddr = XX.XX.XX.XX.XX.XX
|
||||
}
|
||||
callback(reply);
|
||||
});
|
||||
};
|
||||
|
||||
command.setPowerModeICS = function (mode, callback) {
|
||||
doBooleanCommand("DRIVER POWERMODE " + (mode === "AUTO" ? 0 : 1), "OK", callback);
|
||||
};
|
||||
|
||||
command.setPowerModeJB = function (mode, callback) {
|
||||
doBooleanCommand("SET ps " + (mode === "AUTO" ? 1 : 0), "OK", callback);
|
||||
};
|
||||
|
||||
command.getPowerMode = function (callback) {
|
||||
doStringCommand("DRIVER GETPOWER", function(reply) {
|
||||
if (reply) {
|
||||
reply = (reply.split()[2]|0); // Format: powermode = XX
|
||||
}
|
||||
callback(reply);
|
||||
});
|
||||
};
|
||||
|
||||
command.setNumAllowedChannels = function (numChannels, callback) {
|
||||
doBooleanCommand("DRIVER SCAN-CHANNELS " + numChannels, "OK", callback);
|
||||
};
|
||||
|
||||
command.getNumAllowedChannels = function (callback) {
|
||||
doStringCommand("DRIVER SCAN-CHANNELS", function(reply) {
|
||||
if (reply) {
|
||||
reply = (reply.split()[2]|0); // Format: Scan-Channels = X
|
||||
}
|
||||
callback(reply);
|
||||
});
|
||||
};
|
||||
|
||||
command.setBluetoothCoexistenceMode = function (mode, callback) {
|
||||
doBooleanCommand("DRIVER BTCOEXMODE " + mode, "OK", callback);
|
||||
};
|
||||
|
||||
command.setBluetoothCoexistenceScanMode = function (mode, callback) {
|
||||
doBooleanCommand("DRIVER BTCOEXSCAN-" + (mode ? "START" : "STOP"),
|
||||
"OK", callback);
|
||||
};
|
||||
|
||||
command.saveConfig = function (callback) {
|
||||
// Make sure we never write out a value for AP_SCAN other than 1.
|
||||
doBooleanCommand("AP_SCAN 1", "OK", function(ok) {
|
||||
doBooleanCommand("SAVE_CONFIG", "OK", callback);
|
||||
});
|
||||
};
|
||||
|
||||
command.reloadConfig = function (callback) {
|
||||
doBooleanCommand("RECONFIGURE", "OK", callback);
|
||||
};
|
||||
|
||||
command.setScanResultHandling = function (mode, callback) {
|
||||
doBooleanCommand("AP_SCAN " + mode, "OK", callback);
|
||||
};
|
||||
|
||||
command.addToBlacklist = function (bssid, callback) {
|
||||
doBooleanCommand("BLACKLIST " + bssid, "OK", callback);
|
||||
};
|
||||
|
||||
command.clearBlacklist = function (callback) {
|
||||
doBooleanCommand("BLACKLIST clear", "OK", callback);
|
||||
};
|
||||
|
||||
command.setSuspendOptimizations = function (enabled, callback) {
|
||||
doBooleanCommand("DRIVER SETSUSPENDOPT " + (enabled ? 0 : 1),
|
||||
"OK", callback);
|
||||
};
|
||||
|
||||
command.connectToSupplicant = function(callback) {
|
||||
voidControlMessage("connect_to_supplicant", callback);
|
||||
};
|
||||
|
||||
command.closeSupplicantConnection = function(callback) {
|
||||
voidControlMessage("close_supplicant_connection", callback);
|
||||
};
|
||||
|
||||
command.getMacAddress = function(callback) {
|
||||
doStringCommand("DRIVER MACADDR", function(reply) {
|
||||
if (reply) {
|
||||
reply = reply.split(" ")[2]; // Format: Macaddr = XX.XX.XX.XX.XX.XX
|
||||
}
|
||||
callback(reply);
|
||||
});
|
||||
};
|
||||
|
||||
//--------------------------------------------------
|
||||
// Helper functions.
|
||||
//--------------------------------------------------
|
||||
|
||||
function voidControlMessage(cmd, callback) {
|
||||
controlMessage({ cmd: cmd }, function (data) {
|
||||
callback(data.status);
|
||||
});
|
||||
}
|
||||
|
||||
function doCommand(request, callback) {
|
||||
var msg = { cmd: "command",
|
||||
request: request };
|
||||
|
||||
controlMessage(msg, callback);
|
||||
}
|
||||
|
||||
function doIntCommand(request, callback) {
|
||||
doCommand(request, function(data) {
|
||||
callback(data.status ? -1 : (data.reply|0));
|
||||
});
|
||||
}
|
||||
|
||||
function doBooleanCommand(request, expected, callback) {
|
||||
doCommand(request, function(data) {
|
||||
callback(data.status ? false : (data.reply === expected));
|
||||
});
|
||||
}
|
||||
|
||||
function doStringCommand(request, callback) {
|
||||
doCommand(request, function(data) {
|
||||
callback(data.status ? null : data.reply);
|
||||
});
|
||||
}
|
||||
|
||||
function doBooleanCommandChain(commandChain, callback, i) {
|
||||
if (undefined === i) {
|
||||
i = 0;
|
||||
}
|
||||
|
||||
doBooleanCommand(commandChain[i], "OK", function(ok) {
|
||||
if (!ok) {
|
||||
return callback(false);
|
||||
}
|
||||
i++;
|
||||
if (i === commandChain.length || !commandChain[i]) {
|
||||
// Reach the end or empty command.
|
||||
return callback(true);
|
||||
}
|
||||
doBooleanCommandChain(commandChain, callback, i);
|
||||
});
|
||||
}
|
||||
|
||||
function stopProcess(service, process, callback) {
|
||||
var count = 0;
|
||||
var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
function tick() {
|
||||
let result = libcutils.property_get(service);
|
||||
if (result === null) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
if (result === "stopped" || ++count >= 5) {
|
||||
// Either we succeeded or ran out of time.
|
||||
timer = null;
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
// Else it's still running, continue waiting.
|
||||
timer.initWithCallback(tick, 1000, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
}
|
||||
|
||||
setProperty("ctl.stop", process, tick);
|
||||
}
|
||||
|
||||
// Wrapper around libcutils.property_set that returns true if setting the
|
||||
// value was successful.
|
||||
// Note that the callback is not called asynchronously.
|
||||
function setProperty(key, value, callback) {
|
||||
let ok = true;
|
||||
try {
|
||||
libcutils.property_set(key, value);
|
||||
} catch(e) {
|
||||
ok = false;
|
||||
}
|
||||
callback(ok);
|
||||
}
|
||||
|
||||
return command;
|
||||
};
|
|
@ -0,0 +1,211 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/systemlibs.js");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager",
|
||||
"@mozilla.org/network/manager;1",
|
||||
"nsINetworkManager");
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["WifiNetUtil"];
|
||||
|
||||
const DHCP_PROP = "init.svc.dhcpcd";
|
||||
const DHCP = "dhcpcd";
|
||||
|
||||
this.WifiNetUtil = function(controlMessage) {
|
||||
var util = {};
|
||||
|
||||
util.configureInterface = function(cfg, callback) {
|
||||
let message = { cmd: "ifc_configure",
|
||||
ifname: cfg.ifname,
|
||||
ipaddr: cfg.ipaddr,
|
||||
mask: cfg.mask,
|
||||
gateway: cfg.gateway,
|
||||
dns1: cfg.dns1,
|
||||
dns2: cfg.dns2 };
|
||||
|
||||
controlMessage(message, function(data) {
|
||||
callback(!data.status);
|
||||
});
|
||||
};
|
||||
|
||||
util.runDhcp = function (ifname, callback) {
|
||||
controlMessage({ cmd: "dhcp_do_request", ifname: ifname }, function(data) {
|
||||
var dhcpInfo = data.status ? null : data;
|
||||
util.runIpConfig(ifname, dhcpInfo, callback);
|
||||
});
|
||||
};
|
||||
|
||||
util.stopDhcp = function (ifname, callback) {
|
||||
// This function does exactly what dhcp_stop does. Unforunately, if we call
|
||||
// this function twice before the previous callback is returned. We may block
|
||||
// our self waiting for the callback. It slows down the wifi startup procedure.
|
||||
// Therefore, we have to roll our own version here.
|
||||
let dhcpService = DHCP_PROP + "_" + ifname;
|
||||
let suffix = (ifname.substr(0, 3) === "p2p") ? "p2p" : ifname;
|
||||
let processName = DHCP + "_" + suffix;
|
||||
stopProcess(dhcpService, processName, callback);
|
||||
};
|
||||
|
||||
util.enableInterface = function (ifname, callback) {
|
||||
controlMessage({ cmd: "ifc_enable", ifname: ifname }, function (data) {
|
||||
callback(!data.status);
|
||||
});
|
||||
};
|
||||
|
||||
util.disableInterface = function (ifname, callback) {
|
||||
controlMessage({ cmd: "ifc_disable", ifname: ifname }, function (data) {
|
||||
callback(!data.status);
|
||||
});
|
||||
};
|
||||
|
||||
util.startDhcpServer = function (range, callback) {
|
||||
gNetworkManager.setDhcpServer(true, range, function (error) {
|
||||
callback(!error);
|
||||
});
|
||||
};
|
||||
|
||||
util.stopDhcpServer = function (callback) {
|
||||
gNetworkManager.setDhcpServer(false, null, function (error) {
|
||||
callback(!error);
|
||||
});
|
||||
};
|
||||
|
||||
util.addHostRoute = function (ifname, route, callback) {
|
||||
controlMessage({ cmd: "ifc_add_host_route", ifname: ifname, route: route }, function(data) {
|
||||
callback(!data.status);
|
||||
});
|
||||
};
|
||||
|
||||
util.removeHostRoutes = function (ifname, callback) {
|
||||
controlMessage({ cmd: "ifc_remove_host_routes", ifname: ifname }, function(data) {
|
||||
callback(!data.status);
|
||||
});
|
||||
};
|
||||
|
||||
util.setDefaultRoute = function (ifname, route, callback) {
|
||||
controlMessage({ cmd: "ifc_set_default_route", ifname: ifname, route: route }, function(data) {
|
||||
callback(!data.status);
|
||||
});
|
||||
};
|
||||
|
||||
util.getDefaultRoute = function (ifname, callback) {
|
||||
controlMessage({ cmd: "ifc_get_default_route", ifname: ifname }, function(data) {
|
||||
callback(!data.route);
|
||||
});
|
||||
};
|
||||
|
||||
util.removeDefaultRoute = function (ifname, callback) {
|
||||
controlMessage({ cmd: "ifc_remove_default_route", ifname: ifname }, function(data) {
|
||||
callback(!data.status);
|
||||
});
|
||||
};
|
||||
|
||||
util.resetConnections = function (ifname, callback) {
|
||||
controlMessage({ cmd: "ifc_reset_connections", ifname: ifname }, function(data) {
|
||||
callback(!data.status);
|
||||
});
|
||||
};
|
||||
|
||||
util.releaseDhcpLease = function (ifname, callback) {
|
||||
controlMessage({ cmd: "dhcp_release_lease", ifname: ifname }, function(data) {
|
||||
callback(!data.status);
|
||||
});
|
||||
};
|
||||
|
||||
util.getDhcpError = function (callback) {
|
||||
controlMessage({ cmd: "dhcp_get_errmsg" }, function(data) {
|
||||
callback(data.error);
|
||||
});
|
||||
};
|
||||
|
||||
util.runDhcpRenew = function (ifname, callback) {
|
||||
controlMessage({ cmd: "dhcp_do_request", ifname: ifname }, function(data) {
|
||||
callback(data.status ? null : data);
|
||||
});
|
||||
};
|
||||
|
||||
util.runIpConfig = function (name, data, callback) {
|
||||
if (!data) {
|
||||
callback({ info: data });
|
||||
return;
|
||||
}
|
||||
|
||||
setProperty("net." + name + ".dns1", ipToString(data.dns1),
|
||||
function(ok) {
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
setProperty("net." + name + ".dns2", ipToString(data.dns2),
|
||||
function(ok) {
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
setProperty("net." + name + ".gw", ipToString(data.gateway),
|
||||
function(ok) {
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
callback({ info: data });
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
//--------------------------------------------------
|
||||
// Helper functions.
|
||||
//--------------------------------------------------
|
||||
|
||||
function stopProcess(service, process, callback) {
|
||||
var count = 0;
|
||||
var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
function tick() {
|
||||
let result = libcutils.property_get(service);
|
||||
if (result === null) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
if (result === "stopped" || ++count >= 5) {
|
||||
// Either we succeeded or ran out of time.
|
||||
timer = null;
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
// Else it's still running, continue waiting.
|
||||
timer.initWithCallback(tick, 1000, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
}
|
||||
|
||||
setProperty("ctl.stop", process, tick);
|
||||
}
|
||||
|
||||
// Wrapper around libcutils.property_set that returns true if setting the
|
||||
// value was successful.
|
||||
// Note that the callback is not called asynchronously.
|
||||
function setProperty(key, value, callback) {
|
||||
let ok = true;
|
||||
try {
|
||||
libcutils.property_set(key, value);
|
||||
} catch(e) {
|
||||
ok = false;
|
||||
}
|
||||
callback(ok);
|
||||
}
|
||||
|
||||
function ipToString(n) {
|
||||
return String((n >> 0) & 0xFF) + "." +
|
||||
((n >> 8) & 0xFF) + "." +
|
||||
((n >> 16) & 0xFF) + "." +
|
||||
((n >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
return util;
|
||||
};
|
|
@ -11,6 +11,8 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
|||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/systemlibs.js");
|
||||
Cu.import("resource://gre/modules/WifiCommand.jsm");
|
||||
Cu.import("resource://gre/modules/WifiNetUtil.jsm");
|
||||
|
||||
var DEBUG = false; // set to true to show debug messages.
|
||||
|
||||
|
@ -135,6 +137,9 @@ var WifiManager = (function() {
|
|||
manager.schedScanRecovery = schedScanRecovery;
|
||||
manager.driverDelay = driverDelay ? parseInt(driverDelay, 10) : DRIVER_READY_WAIT;
|
||||
|
||||
var wifiCommand = WifiCommand(controlMessage);
|
||||
var netUtil = WifiNetUtil(controlMessage);
|
||||
|
||||
// Callbacks to invoke when a reply arrives from the wifi service.
|
||||
var controlCallbacks = Object.create(null);
|
||||
var idgen = 0;
|
||||
|
@ -165,12 +170,6 @@ var WifiManager = (function() {
|
|||
|
||||
// Commands to the control worker.
|
||||
|
||||
function voidControlMessage(cmd, callback) {
|
||||
controlMessage({ cmd: cmd }, function (data) {
|
||||
callback(data.status);
|
||||
});
|
||||
}
|
||||
|
||||
var driverLoaded = false;
|
||||
|
||||
function loadDriver(callback) {
|
||||
|
@ -179,7 +178,7 @@ var WifiManager = (function() {
|
|||
return;
|
||||
}
|
||||
|
||||
voidControlMessage("load_driver", function(status) {
|
||||
wifiCommand.loadDriver(function (status) {
|
||||
driverLoaded = (status >= 0);
|
||||
callback(status)
|
||||
});
|
||||
|
@ -195,106 +194,12 @@ var WifiManager = (function() {
|
|||
return;
|
||||
}
|
||||
|
||||
voidControlMessage("unload_driver", function(status) {
|
||||
wifiCommand.unloadDriver(function(status) {
|
||||
driverLoaded = (status < 0);
|
||||
callback(status);
|
||||
});
|
||||
}
|
||||
|
||||
function startSupplicant(callback) {
|
||||
voidControlMessage("start_supplicant", callback);
|
||||
}
|
||||
|
||||
function terminateSupplicant(callback) {
|
||||
doBooleanCommand("TERMINATE", "OK", callback);
|
||||
}
|
||||
|
||||
function stopSupplicant(callback) {
|
||||
voidControlMessage("stop_supplicant", callback);
|
||||
}
|
||||
|
||||
function connectToSupplicant(callback) {
|
||||
voidControlMessage("connect_to_supplicant", callback);
|
||||
}
|
||||
|
||||
function closeSupplicantConnection(callback) {
|
||||
voidControlMessage("close_supplicant_connection", callback);
|
||||
}
|
||||
|
||||
function doCommand(request, callback) {
|
||||
controlMessage({ cmd: "command", request: request }, callback);
|
||||
}
|
||||
|
||||
function doIntCommand(request, callback) {
|
||||
doCommand(request, function(data) {
|
||||
callback(data.status ? -1 : (data.reply|0));
|
||||
});
|
||||
}
|
||||
|
||||
function doBooleanCommand(request, expected, callback) {
|
||||
doCommand(request, function(data) {
|
||||
callback(data.status ? false : (data.reply == expected));
|
||||
});
|
||||
}
|
||||
|
||||
function doStringCommand(request, callback) {
|
||||
doCommand(request, function(data) {
|
||||
callback(data.status ? null : data.reply);
|
||||
});
|
||||
}
|
||||
|
||||
function listNetworksCommand(callback) {
|
||||
doStringCommand("LIST_NETWORKS", callback);
|
||||
}
|
||||
|
||||
function addNetworkCommand(callback) {
|
||||
doIntCommand("ADD_NETWORK", callback);
|
||||
}
|
||||
|
||||
function setNetworkVariableCommand(netId, name, value, callback) {
|
||||
doBooleanCommand("SET_NETWORK " + netId + " " + name + " " + value, "OK", callback);
|
||||
}
|
||||
|
||||
function getNetworkVariableCommand(netId, name, callback) {
|
||||
doStringCommand("GET_NETWORK " + netId + " " + name, callback);
|
||||
}
|
||||
|
||||
function removeNetworkCommand(netId, callback) {
|
||||
doBooleanCommand("REMOVE_NETWORK " + netId, "OK", callback);
|
||||
}
|
||||
|
||||
function enableNetworkCommand(netId, disableOthers, callback) {
|
||||
doBooleanCommand((disableOthers ? "SELECT_NETWORK " : "ENABLE_NETWORK ") + netId, "OK", callback);
|
||||
}
|
||||
|
||||
function disableNetworkCommand(netId, callback) {
|
||||
doBooleanCommand("DISABLE_NETWORK " + netId, "OK", callback);
|
||||
}
|
||||
|
||||
function statusCommand(callback) {
|
||||
doStringCommand("STATUS", callback);
|
||||
}
|
||||
|
||||
function pingCommand(callback) {
|
||||
doBooleanCommand("PING", "PONG", callback);
|
||||
}
|
||||
|
||||
function scanResultsCommand(callback) {
|
||||
doStringCommand("SCAN_RESULTS", callback);
|
||||
}
|
||||
|
||||
function disconnectCommand(callback) {
|
||||
doBooleanCommand("DISCONNECT", "OK", callback);
|
||||
}
|
||||
|
||||
function reconnectCommand(callback) {
|
||||
doBooleanCommand("RECONNECT", "OK", callback);
|
||||
}
|
||||
|
||||
function reassociateCommand(callback) {
|
||||
doBooleanCommand("REASSOCIATE", "OK", callback);
|
||||
}
|
||||
|
||||
// A note about background scanning:
|
||||
// Normally, background scanning shouldn't be necessary as wpa_supplicant
|
||||
// has the capability to automatically schedule its own scans at appropriate
|
||||
|
@ -314,27 +219,19 @@ var WifiManager = (function() {
|
|||
}
|
||||
|
||||
manager.backgroundScanEnabled = doEnable;
|
||||
doBooleanCommand("SET pno " + (manager.backgroundScanEnabled ? "1" : "0"),
|
||||
"OK",
|
||||
function(ok) {
|
||||
callback(true, ok);
|
||||
});
|
||||
wifiCommand.setBackgroundScan(manager.backgroundScanEnabled, callback);
|
||||
}
|
||||
|
||||
var scanModeActive = false;
|
||||
|
||||
function doSetScanModeCommand(setActive, callback) {
|
||||
doBooleanCommand(setActive ? "DRIVER SCAN-ACTIVE" : "DRIVER SCAN-PASSIVE", "OK", callback);
|
||||
}
|
||||
|
||||
function scanCommand(forceActive, callback) {
|
||||
function scan(forceActive, callback) {
|
||||
if (forceActive && !scanModeActive) {
|
||||
// Note: we ignore errors from doSetScanMode.
|
||||
doSetScanModeCommand(true, function(ignore) {
|
||||
wifiCommand.doSetScanMode(true, function(ignore) {
|
||||
setBackgroundScan("OFF", function(turned, ignore) {
|
||||
reEnableBackgroundScan = turned;
|
||||
doBooleanCommand("SCAN", "OK", function(ok) {
|
||||
doSetScanModeCommand(false, function(ignore) {
|
||||
wifiCommand.scan(function(ok) {
|
||||
wifiCommand.doSetScanMode(false, function(ignore) {
|
||||
// The result of scanCommand is the result of the actual SCAN
|
||||
// request.
|
||||
callback(ok);
|
||||
|
@ -344,30 +241,23 @@ var WifiManager = (function() {
|
|||
});
|
||||
return;
|
||||
}
|
||||
doBooleanCommand("SCAN", "OK", callback);
|
||||
wifiCommand.scan(callback);
|
||||
}
|
||||
|
||||
var debugEnabled = false;
|
||||
function setLogLevel(level, callback) {
|
||||
doBooleanCommand("LOG_LEVEL " + level, "OK", callback);
|
||||
}
|
||||
|
||||
function syncDebug() {
|
||||
if (debugEnabled !== DEBUG) {
|
||||
let wanted = DEBUG;
|
||||
setLogLevel(wanted ? "DEBUG" : "INFO", function(ok) {
|
||||
wifiCommand.setLogLevel(wanted ? "DEBUG" : "INFO", function(ok) {
|
||||
if (ok)
|
||||
debugEnabled = wanted;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getLogLevel(callback) {
|
||||
doStringCommand("LOG_LEVEL", callback);
|
||||
}
|
||||
|
||||
function getDebugEnabled(callback) {
|
||||
getLogLevel(function(level) {
|
||||
wifiCommand.getLogLevel(function(level) {
|
||||
if (level === null) {
|
||||
debug("Unable to get wpa_supplicant's log level");
|
||||
callback(false);
|
||||
|
@ -389,256 +279,9 @@ var WifiManager = (function() {
|
|||
});
|
||||
}
|
||||
|
||||
function setScanModeCommand(setActive, callback) {
|
||||
function setScanMode(setActive, callback) {
|
||||
scanModeActive = setActive;
|
||||
doSetScanModeCommand(setActive, callback);
|
||||
}
|
||||
|
||||
function wpsPbcCommand(callback) {
|
||||
doBooleanCommand("WPS_PBC", "OK", callback);
|
||||
}
|
||||
|
||||
function wpsPinCommand(detail, callback) {
|
||||
doStringCommand("WPS_PIN " +
|
||||
(detail.bssid === undefined ? "any" : detail.bssid) +
|
||||
(detail.pin === undefined ? "" : (" " + detail.pin)),
|
||||
callback);
|
||||
}
|
||||
|
||||
function wpsCancelCommand(callback) {
|
||||
doBooleanCommand("WPS_CANCEL", "OK", callback);
|
||||
}
|
||||
|
||||
function startDriverCommand(callback) {
|
||||
doBooleanCommand("DRIVER START", "OK");
|
||||
}
|
||||
|
||||
function stopDriverCommand(callback) {
|
||||
doBooleanCommand("DRIVER STOP", "OK");
|
||||
}
|
||||
|
||||
function startPacketFiltering(callback) {
|
||||
doBooleanCommand("DRIVER RXFILTER-ADD 0", "OK", function(ok) {
|
||||
ok && doBooleanCommand("DRIVER RXFILTER-ADD 1", "OK", function(ok) {
|
||||
ok && doBooleanCommand("DRIVER RXFILTER-ADD 3", "OK", function(ok) {
|
||||
ok && doBooleanCommand("DRIVER RXFILTER-START", "OK", callback)
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function stopPacketFiltering(callback) {
|
||||
doBooleanCommand("DRIVER RXFILTER-STOP", "OK", function(ok) {
|
||||
ok && doBooleanCommand("DRIVER RXFILTER-REMOVE 3", "OK", function(ok) {
|
||||
ok && doBooleanCommand("DRIVER RXFILTER-REMOVE 1", "OK", function(ok) {
|
||||
ok && doBooleanCommand("DRIVER RXFILTER-REMOVE 0", "OK", callback)
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function doGetRssiCommand(cmd, callback) {
|
||||
doCommand(cmd, function(data) {
|
||||
var rssi = -200;
|
||||
|
||||
if (!data.status) {
|
||||
// If we are associating, the reply is "OK".
|
||||
var reply = data.reply;
|
||||
if (reply != "OK") {
|
||||
// Format is: <SSID> rssi XX". SSID can contain spaces.
|
||||
var offset = reply.lastIndexOf("rssi ");
|
||||
if (offset !== -1)
|
||||
rssi = reply.substr(offset + 5) | 0;
|
||||
}
|
||||
}
|
||||
callback(rssi);
|
||||
});
|
||||
}
|
||||
|
||||
function getRssiCommand(callback) {
|
||||
doGetRssiCommand("DRIVER RSSI", callback);
|
||||
}
|
||||
|
||||
function getRssiApproxCommand(callback) {
|
||||
doGetRssiCommand("DRIVER RSSI-APPROX", callback);
|
||||
}
|
||||
|
||||
function getLinkSpeedCommand(callback) {
|
||||
doStringCommand("DRIVER LINKSPEED", function(reply) {
|
||||
if (reply)
|
||||
reply = reply.split(" ")[1] | 0; // Format: LinkSpeed XX
|
||||
callback(reply);
|
||||
});
|
||||
}
|
||||
|
||||
function getConnectionInfoGB(callback) {
|
||||
var rval = {};
|
||||
getRssiApproxCommand(function(rssi) {
|
||||
rval.rssi = rssi;
|
||||
getLinkSpeedCommand(function(linkspeed) {
|
||||
rval.linkspeed = linkspeed;
|
||||
callback(rval);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getConnectionInfoICS(callback) {
|
||||
doStringCommand("SIGNAL_POLL", function(reply) {
|
||||
if (!reply) {
|
||||
callback(null);
|
||||
return;
|
||||
}
|
||||
|
||||
let rval = {};
|
||||
var lines = reply.split("\n");
|
||||
for (let i = 0; i < lines.length; ++i) {
|
||||
let [key, value] = lines[i].split("=");
|
||||
switch (key.toUpperCase()) {
|
||||
case "RSSI":
|
||||
rval.rssi = value | 0;
|
||||
break;
|
||||
case "LINKSPEED":
|
||||
rval.linkspeed = value | 0;
|
||||
break;
|
||||
default:
|
||||
// Ignore.
|
||||
}
|
||||
}
|
||||
|
||||
callback(rval);
|
||||
});
|
||||
}
|
||||
|
||||
function getMacAddressCommand(callback) {
|
||||
doStringCommand("DRIVER MACADDR", function(reply) {
|
||||
if (reply)
|
||||
reply = reply.split(" ")[2]; // Format: Macaddr = XX.XX.XX.XX.XX.XX
|
||||
callback(reply);
|
||||
});
|
||||
}
|
||||
|
||||
function setPowerModeCommandICS(mode, callback) {
|
||||
doBooleanCommand("DRIVER POWERMODE " + (mode === "AUTO" ? 0 : 1), "OK", callback);
|
||||
}
|
||||
|
||||
function setPowerModeCommandJB(mode, callback) {
|
||||
doBooleanCommand("SET ps " + (mode === "AUTO" ? 1 : 0), "OK", callback);
|
||||
}
|
||||
|
||||
function getPowerModeCommand(callback) {
|
||||
doStringCommand("DRIVER GETPOWER", function(reply) {
|
||||
if (reply)
|
||||
reply = (reply.split()[2]|0); // Format: powermode = XX
|
||||
callback(reply);
|
||||
});
|
||||
}
|
||||
|
||||
function setNumAllowedChannelsCommand(numChannels, callback) {
|
||||
doBooleanCommand("DRIVER SCAN-CHANNELS " + numChannels, "OK", callback);
|
||||
}
|
||||
|
||||
function getNumAllowedChannelsCommand(callback) {
|
||||
doStringCommand("DRIVER SCAN-CHANNELS", function(reply) {
|
||||
if (reply)
|
||||
reply = (reply.split()[2]|0); // Format: Scan-Channels = X
|
||||
callback(reply);
|
||||
});
|
||||
}
|
||||
|
||||
function setBluetoothCoexistenceModeCommand(mode, callback) {
|
||||
doBooleanCommand("DRIVER BTCOEXMODE " + mode, "OK", callback);
|
||||
}
|
||||
|
||||
function setBluetoothCoexistenceScanModeCommand(mode, callback) {
|
||||
doBooleanCommand("DRIVER BTCOEXSCAN-" + (mode ? "START" : "STOP"), "OK", callback);
|
||||
}
|
||||
|
||||
function saveConfigCommand(callback) {
|
||||
// Make sure we never write out a value for AP_SCAN other than 1
|
||||
doBooleanCommand("AP_SCAN 1", "OK", function(ok) {
|
||||
doBooleanCommand("SAVE_CONFIG", "OK", callback);
|
||||
});
|
||||
}
|
||||
|
||||
function reloadConfigCommand(callback) {
|
||||
doBooleanCommand("RECONFIGURE", "OK", callback);
|
||||
}
|
||||
|
||||
function setScanResultHandlingCommand(mode, callback) {
|
||||
doBooleanCommand("AP_SCAN " + mode, "OK", callback);
|
||||
}
|
||||
|
||||
function addToBlacklistCommand(bssid, callback) {
|
||||
doBooleanCommand("BLACKLIST " + bssid, "OK", callback);
|
||||
}
|
||||
|
||||
function clearBlacklistCommand(callback) {
|
||||
doBooleanCommand("BLACKLIST clear", "OK", callback);
|
||||
}
|
||||
|
||||
function setSuspendOptimizationsCommand(enabled, callback) {
|
||||
doBooleanCommand("DRIVER SETSUSPENDOPT " + (enabled ? 0 : 1), "OK", callback);
|
||||
}
|
||||
|
||||
// Wrapper around libcutils.property_set that returns true if setting the
|
||||
// value was successful.
|
||||
// Note that the callback is not called asynchronously.
|
||||
function setProperty(key, value, callback) {
|
||||
let ok = true;
|
||||
try {
|
||||
libcutils.property_set(key, value);
|
||||
} catch(e) {
|
||||
ok = false;
|
||||
}
|
||||
callback(ok);
|
||||
}
|
||||
|
||||
function enableInterface(ifname, callback) {
|
||||
controlMessage({ cmd: "ifc_enable", ifname: ifname }, function(data) {
|
||||
callback(!data.status);
|
||||
});
|
||||
}
|
||||
|
||||
function disableInterface(ifname, callback) {
|
||||
controlMessage({ cmd: "ifc_disable", ifname: ifname }, function(data) {
|
||||
callback(!data.status);
|
||||
});
|
||||
}
|
||||
|
||||
function addHostRoute(ifname, route, callback) {
|
||||
controlMessage({ cmd: "ifc_add_host_route", ifname: ifname, route: route }, function(data) {
|
||||
callback(!data.status);
|
||||
});
|
||||
}
|
||||
|
||||
function removeHostRoutes(ifname, callback) {
|
||||
controlMessage({ cmd: "ifc_remove_host_routes", ifname: ifname }, function(data) {
|
||||
callback(!data.status);
|
||||
});
|
||||
}
|
||||
|
||||
function setDefaultRoute(ifname, route, callback) {
|
||||
controlMessage({ cmd: "ifc_set_default_route", ifname: ifname, route: route }, function(data) {
|
||||
callback(!data.status);
|
||||
});
|
||||
}
|
||||
|
||||
function getDefaultRoute(ifname, callback) {
|
||||
controlMessage({ cmd: "ifc_get_default_route", ifname: ifname }, function(data) {
|
||||
callback(!data.route);
|
||||
});
|
||||
}
|
||||
|
||||
function removeDefaultRoute(ifname, callback) {
|
||||
controlMessage({ cmd: "ifc_remove_default_route", ifname: ifname }, function(data) {
|
||||
callback(!data.status);
|
||||
});
|
||||
}
|
||||
|
||||
function resetConnections(ifname, callback) {
|
||||
controlMessage({ cmd: "ifc_reset_connections", ifname: ifname }, function(data) {
|
||||
callback(!data.status);
|
||||
});
|
||||
wifiCommand.doSetScanMode(setActive, callback);
|
||||
}
|
||||
|
||||
var httpProxyConfig = Object.create(null);
|
||||
|
@ -713,8 +356,8 @@ var WifiManager = (function() {
|
|||
// and routing table is changed but still cannot connect to network
|
||||
// so the workaround here is disable interface the enable again to
|
||||
// trigger network reconnect with static ip.
|
||||
disableInterface(manager.ifname, function (ok) {
|
||||
enableInterface(manager.ifname, function (ok) {
|
||||
netUtil.disableInterface(manager.ifname, function (ok) {
|
||||
netUtil.enableInterface(manager.ifname, function (ok) {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -722,13 +365,6 @@ var WifiManager = (function() {
|
|||
}
|
||||
|
||||
var dhcpInfo = null;
|
||||
function runDhcp(ifname) {
|
||||
debug("Run Dhcp");
|
||||
controlMessage({ cmd: "dhcp_do_request", ifname: ifname }, function(data) {
|
||||
dhcpInfo = data.status ? null : data;
|
||||
runIpConfig(ifname, dhcpInfo);
|
||||
});
|
||||
}
|
||||
|
||||
function runStaticIp(ifname, key) {
|
||||
debug("Run static ip");
|
||||
|
@ -743,82 +379,20 @@ var WifiManager = (function() {
|
|||
|
||||
// Stop dhcpd when use static IP
|
||||
if (dhcpInfo != null) {
|
||||
stopDhcp(manager.ifname, function() {});
|
||||
netUtil.stopDhcp(manager.ifname, function() {});
|
||||
}
|
||||
|
||||
// Set ip, mask length, gateway, dns to network interface
|
||||
configureInterface(ifname,
|
||||
staticIpInfo.ipaddr,
|
||||
staticIpInfo.maskLength,
|
||||
staticIpInfo.gateway,
|
||||
staticIpInfo.dns1,
|
||||
staticIpInfo.dns2, function (data) {
|
||||
runIpConfig(ifname, staticIpInfo);
|
||||
});
|
||||
}
|
||||
|
||||
function stopProcess(service, process, callback) {
|
||||
var count = 0;
|
||||
var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
function tick() {
|
||||
let result = libcutils.property_get(service);
|
||||
if (result === null) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
if (result === "stopped" || ++count >= 5) {
|
||||
// Either we succeeded or ran out of time.
|
||||
timer = null;
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
// Else it's still running, continue waiting.
|
||||
timer.initWithCallback(tick, 1000, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
}
|
||||
|
||||
setProperty("ctl.stop", process, tick);
|
||||
}
|
||||
|
||||
function stopDhcp(ifname, callback) {
|
||||
// This function does exactly what dhcp_stop does. Unforunately, if we call
|
||||
// this function twice before the previous callback is returned. We may block
|
||||
// our self waiting for the callback. It slows down the wifi startup procedure.
|
||||
// Therefore, we have to roll our own version here.
|
||||
let dhcpService = DHCP_PROP + "_" + ifname;
|
||||
let suffix = (ifname.substr(0, 3) === "p2p") ? "p2p" : ifname;
|
||||
let processName = DHCP + "_" + suffix;
|
||||
stopProcess(dhcpService, processName, callback);
|
||||
}
|
||||
|
||||
function releaseDhcpLease(ifname, callback) {
|
||||
controlMessage({ cmd: "dhcp_release_lease", ifname: ifname }, function(data) {
|
||||
dhcpInfo = null;
|
||||
notify("dhcplost");
|
||||
callback(!data.status);
|
||||
});
|
||||
}
|
||||
|
||||
function getDhcpError(callback) {
|
||||
controlMessage({ cmd: "dhcp_get_errmsg" }, function(data) {
|
||||
callback(data.error);
|
||||
});
|
||||
}
|
||||
|
||||
function configureInterface(ifname, ipaddr, mask, gateway, dns1, dns2, callback) {
|
||||
let message = { cmd: "ifc_configure", ifname: ifname,
|
||||
ipaddr: ipaddr, mask: mask, gateway: gateway,
|
||||
dns1: dns1, dns2: dns2};
|
||||
controlMessage(message, function(data) {
|
||||
callback(!data.status);
|
||||
});
|
||||
}
|
||||
|
||||
function runDhcpRenew(ifname, callback) {
|
||||
controlMessage({ cmd: "dhcp_do_request", ifname: ifname }, function(data) {
|
||||
if (!data.status)
|
||||
dhcpInfo = data;
|
||||
callback(data.status ? null : data);
|
||||
netUtil.configureInterface( { ifname: ifname,
|
||||
ipaddr: staticIpInfo.ipaddr,
|
||||
mask: staticIpInfo.maskLength,
|
||||
gateway: staticIpInfo.gateway,
|
||||
dns1: staticIpInfo.dns1,
|
||||
dns2: staticIpInfo.dns2 }, function (data) {
|
||||
netUtil.runIpConfig(ifname, staticIpInfo, function(data) {
|
||||
dhcpInfo = data.info;
|
||||
notify("networkconnected", data);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -933,7 +507,7 @@ var WifiManager = (function() {
|
|||
retryTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
|
||||
retryTimer.initWithCallback(function(timer) {
|
||||
connectToSupplicant(connectCallback);
|
||||
wifiCommand.connectToSupplicant(connectCallback);
|
||||
}, 5000, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
return;
|
||||
}
|
||||
|
@ -945,13 +519,18 @@ var WifiManager = (function() {
|
|||
|
||||
manager.connectionDropped = function(callback) {
|
||||
// Reset network interface when connection drop
|
||||
configureInterface(manager.ifname, 0, 0, 0, 0, 0, function (data) {
|
||||
netUtil.configureInterface( { ifname: manager.ifname,
|
||||
ipaddr: 0,
|
||||
mask: 0,
|
||||
gateway: 0,
|
||||
dns1: 0,
|
||||
dns2: 0 }, function (data) {
|
||||
});
|
||||
|
||||
// If we got disconnected, kill the DHCP client in preparation for
|
||||
// reconnection.
|
||||
resetConnections(manager.ifname, function() {
|
||||
stopDhcp(manager.ifname, function() {
|
||||
netUtil.resetConnections(manager.ifname, function() {
|
||||
netUtil.stopDhcp(manager.ifname, function() {
|
||||
callback();
|
||||
});
|
||||
});
|
||||
|
@ -959,7 +538,7 @@ var WifiManager = (function() {
|
|||
|
||||
manager.start = function() {
|
||||
debug("detected SDK version " + sdkVersion);
|
||||
connectToSupplicant(connectCallback);
|
||||
wifiCommand.connectToSupplicant(connectCallback);
|
||||
}
|
||||
|
||||
function onconnected() {
|
||||
|
@ -977,37 +556,9 @@ var WifiManager = (function() {
|
|||
runStaticIp(manager.ifname, key);
|
||||
return;
|
||||
}
|
||||
runDhcp(manager.ifname);
|
||||
});
|
||||
}
|
||||
|
||||
function runIpConfig(name, data) {
|
||||
if (!data) {
|
||||
debug("IP config failed to run");
|
||||
notify("networkconnected", { info: data });
|
||||
return;
|
||||
}
|
||||
|
||||
setProperty("net." + name + ".dns1", ipToString(data.dns1),
|
||||
function(ok) {
|
||||
if (!ok) {
|
||||
debug("Unable to set net.<ifname>.dns1");
|
||||
return;
|
||||
}
|
||||
setProperty("net." + name + ".dns2", ipToString(data.dns2),
|
||||
function(ok) {
|
||||
if (!ok) {
|
||||
debug("Unable to set net.<ifname>.dns2");
|
||||
return;
|
||||
}
|
||||
setProperty("net." + name + ".gw", ipToString(data.gateway),
|
||||
function(ok) {
|
||||
if (!ok) {
|
||||
debug("Unable to set net.<ifname>.gw");
|
||||
return;
|
||||
}
|
||||
notify("networkconnected", { info: data });
|
||||
});
|
||||
netUtil.runDhcp(manager.ifname, function(data) {
|
||||
dhcpInfo = data.info;
|
||||
notify("networkconnected", data);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -1187,15 +738,6 @@ var WifiManager = (function() {
|
|||
return true;
|
||||
}
|
||||
|
||||
function killSupplicant(callback) {
|
||||
// It is interesting to note that this function does exactly what
|
||||
// wifi_stop_supplicant does. Unforunately, on the Galaxy S2, Samsung
|
||||
// changed that function in a way that means that it doesn't recognize
|
||||
// wpa_supplicant as already running. Therefore, we have to roll our own
|
||||
// version here.
|
||||
stopProcess(SUPP_PROP, WPA_SUPPLICANT, callback);
|
||||
}
|
||||
|
||||
function didConnectSupplicant(callback) {
|
||||
waitForEvent();
|
||||
|
||||
|
@ -1203,7 +745,7 @@ var WifiManager = (function() {
|
|||
getDebugEnabled(function(ok) {
|
||||
syncDebug();
|
||||
});
|
||||
statusCommand(function(status) {
|
||||
wifiCommand.status(function(status) {
|
||||
parseStatus(status);
|
||||
notify("supplicantconnection");
|
||||
callback();
|
||||
|
@ -1230,8 +772,8 @@ var WifiManager = (function() {
|
|||
return;
|
||||
}
|
||||
suppressEvents = true;
|
||||
killSupplicant(function() {
|
||||
disableInterface(manager.ifname, function (ok) {
|
||||
wifiCommand.killSupplicant(function() {
|
||||
netUtil.disableInterface(manager.ifname, function (ok) {
|
||||
suppressEvents = false;
|
||||
callback();
|
||||
});
|
||||
|
@ -1305,7 +847,7 @@ var WifiManager = (function() {
|
|||
|
||||
function doStartSupplicant() {
|
||||
cancelWaitForDriverReadyTimer();
|
||||
startSupplicant(function (status) {
|
||||
wifiCommand.startSupplicant(function (status) {
|
||||
if (status < 0) {
|
||||
unloadDriver(function() {
|
||||
callback(status);
|
||||
|
@ -1315,7 +857,7 @@ var WifiManager = (function() {
|
|||
}
|
||||
|
||||
manager.supplicantStarted = true;
|
||||
enableInterface(manager.ifname, function (ok) {
|
||||
netUtil.enableInterface(manager.ifname, function (ok) {
|
||||
callback(ok ? 0 : -1);
|
||||
});
|
||||
});
|
||||
|
@ -1335,12 +877,12 @@ var WifiManager = (function() {
|
|||
// Note these following calls ignore errors. If we fail to kill the
|
||||
// supplicant gracefully, then we need to continue telling it to die
|
||||
// until it does.
|
||||
terminateSupplicant(function (ok) {
|
||||
wifiCommand.terminateSupplicant(function (ok) {
|
||||
manager.connectionDropped(function () {
|
||||
stopSupplicant(function (status) {
|
||||
closeSupplicantConnection(function () {
|
||||
wifiCommand.stopSupplicant(function (status) {
|
||||
wifiCommand.closeSupplicantConnection(function () {
|
||||
manager.state = "UNINITIALIZED";
|
||||
disableInterface(manager.ifname, function (ok) {
|
||||
netUtil.disableInterface(manager.ifname, function (ok) {
|
||||
unloadDriver(callback);
|
||||
});
|
||||
});
|
||||
|
@ -1400,9 +942,9 @@ var WifiManager = (function() {
|
|||
}
|
||||
}
|
||||
|
||||
manager.disconnect = disconnectCommand;
|
||||
manager.reconnect = reconnectCommand;
|
||||
manager.reassociate = reassociateCommand;
|
||||
manager.disconnect = wifiCommand.disconnect;
|
||||
manager.reconnect = wifiCommand.reconnect;
|
||||
manager.reassociate = wifiCommand.reassociate;
|
||||
|
||||
var networkConfigurationFields = [
|
||||
"ssid", "bssid", "psk", "wep_key0", "wep_key1", "wep_key2", "wep_key3",
|
||||
|
@ -1416,7 +958,7 @@ var WifiManager = (function() {
|
|||
var done = 0;
|
||||
for (var n = 0; n < networkConfigurationFields.length; ++n) {
|
||||
let fieldName = networkConfigurationFields[n];
|
||||
getNetworkVariableCommand(netId, fieldName, function(value) {
|
||||
wifiCommand.getNetworkVariable(netId, fieldName, function(value) {
|
||||
if (value !== null)
|
||||
config[fieldName] = value;
|
||||
if (++done == networkConfigurationFields.length)
|
||||
|
@ -1440,7 +982,7 @@ var WifiManager = (function() {
|
|||
config[fieldName] === '*') {
|
||||
++done;
|
||||
} else {
|
||||
setNetworkVariableCommand(netId, fieldName, config[fieldName], function(ok) {
|
||||
wifiCommand.setNetworkVariable(netId, fieldName, config[fieldName], function(ok) {
|
||||
if (!ok)
|
||||
++errors;
|
||||
if (++done == networkConfigurationFields.length)
|
||||
|
@ -1453,7 +995,7 @@ var WifiManager = (function() {
|
|||
callback(false);
|
||||
}
|
||||
manager.getConfiguredNetworks = function(callback) {
|
||||
listNetworksCommand(function (reply) {
|
||||
wifiCommand.listNetworks(function (reply) {
|
||||
var networks = Object.create(null);
|
||||
var lines = reply.split("\n");
|
||||
if (lines.length === 1) {
|
||||
|
@ -1486,7 +1028,7 @@ var WifiManager = (function() {
|
|||
if (++done == lines.length - 1) {
|
||||
if (errors) {
|
||||
// If an error occured, delete the new netId.
|
||||
removeNetworkCommand(netId, function() {
|
||||
wifiCommand.removeNetwork(netId, function() {
|
||||
callback(null);
|
||||
});
|
||||
} else {
|
||||
|
@ -1498,11 +1040,11 @@ var WifiManager = (function() {
|
|||
});
|
||||
}
|
||||
manager.addNetwork = function(config, callback) {
|
||||
addNetworkCommand(function (netId) {
|
||||
wifiCommand.addNetwork(function (netId) {
|
||||
config.netId = netId;
|
||||
manager.setNetworkConfiguration(config, function (ok) {
|
||||
if (!ok) {
|
||||
removeNetworkCommand(netId, function() { callback(false); });
|
||||
wifiCommand.removeNetwork(netId, function() { callback(false); });
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1514,14 +1056,7 @@ var WifiManager = (function() {
|
|||
manager.setNetworkConfiguration(config, callback);
|
||||
}
|
||||
manager.removeNetwork = function(netId, callback) {
|
||||
removeNetworkCommand(netId, callback);
|
||||
}
|
||||
|
||||
function ipToString(n) {
|
||||
return String((n >> 0) & 0xFF) + "." +
|
||||
((n >> 8) & 0xFF) + "." +
|
||||
((n >> 16) & 0xFF) + "." +
|
||||
((n >> 24) & 0xFF);
|
||||
wifiCommand.removeNetwork(netId, callback);
|
||||
}
|
||||
|
||||
function stringToIp(string) {
|
||||
|
@ -1562,38 +1097,38 @@ var WifiManager = (function() {
|
|||
}
|
||||
|
||||
manager.saveConfig = function(callback) {
|
||||
saveConfigCommand(callback);
|
||||
wifiCommand.saveConfig(callback);
|
||||
}
|
||||
manager.enableNetwork = function(netId, disableOthers, callback) {
|
||||
enableNetworkCommand(netId, disableOthers, callback);
|
||||
wifiCommand.enableNetwork(netId, disableOthers, callback);
|
||||
}
|
||||
manager.disableNetwork = function(netId, callback) {
|
||||
disableNetworkCommand(netId, callback);
|
||||
wifiCommand.disableNetwork(netId, callback);
|
||||
}
|
||||
manager.getMacAddress = getMacAddressCommand;
|
||||
manager.getScanResults = scanResultsCommand;
|
||||
manager.getMacAddress = wifiCommand.getMacAddress;
|
||||
manager.getScanResults = wifiCommand.scanResults;
|
||||
manager.setScanMode = function(mode, callback) {
|
||||
setScanModeCommand(mode === "active", callback);
|
||||
setScanMode(mode === "active", callback); // Use our own version.
|
||||
}
|
||||
manager.setBackgroundScan = setBackgroundScan;
|
||||
manager.scan = scanCommand;
|
||||
manager.wpsPbc = wpsPbcCommand;
|
||||
manager.wpsPin = wpsPinCommand;
|
||||
manager.wpsCancel = wpsCancelCommand;
|
||||
manager.setBackgroundScan = setBackgroundScan; // Use our own version.
|
||||
manager.scan = scan; // Use our own version.
|
||||
manager.wpsPbc = wifiCommand.wpsPbc;
|
||||
manager.wpsPin = wifiCommand.wpsPin;
|
||||
manager.wpsCancel = wifiCommand.wpsCancel;
|
||||
manager.setPowerMode = (sdkVersion >= 16)
|
||||
? setPowerModeCommandJB
|
||||
: setPowerModeCommandICS;
|
||||
? wifiCommand.setPowerModeJB
|
||||
: wifiCommand.setPowerModeICS;
|
||||
manager.getHttpProxyNetwork = getHttpProxyNetwork;
|
||||
manager.setHttpProxy = setHttpProxy;
|
||||
manager.configureHttpProxy = configureHttpProxy;
|
||||
manager.setSuspendOptimizations = setSuspendOptimizationsCommand;
|
||||
manager.setSuspendOptimizations = wifiCommand.setSuspendOptimizations;
|
||||
manager.setStaticIpMode = setStaticIpMode;
|
||||
manager.getRssiApprox = getRssiApproxCommand;
|
||||
manager.getLinkSpeed = getLinkSpeedCommand;
|
||||
manager.getRssiApprox = wifiCommand.getRssiApprox;
|
||||
manager.getLinkSpeed = wifiCommand.getLinkSpeed;
|
||||
manager.getDhcpInfo = function() { return dhcpInfo; }
|
||||
manager.getConnectionInfo = (sdkVersion >= 15)
|
||||
? getConnectionInfoICS
|
||||
: getConnectionInfoGB;
|
||||
? wifiCommand.getConnectionInfoICS
|
||||
: wifiCommand.getConnectionInfoGB;
|
||||
|
||||
manager.isHandShakeState = function(state) {
|
||||
switch (state) {
|
||||
|
|
|
@ -22,6 +22,11 @@ EXTRA_COMPONENTS += [
|
|||
'WifiWorker.manifest',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'WifiCommand.jsm',
|
||||
'WifiNetUtil.jsm',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
CPP_SOURCES = [
|
||||
'NetUtils.cpp',
|
||||
|
|
|
@ -381,6 +381,83 @@ DrawTargetCG::CreateGradientStops(GradientStop *aStops, uint32_t aNumStops,
|
|||
return new GradientStopsCG(aStops, aNumStops, aExtendMode);
|
||||
}
|
||||
|
||||
static void
|
||||
UpdateLinearParametersToIncludePoint(double *min_t, double *max_t,
|
||||
CGPoint *start,
|
||||
double dx, double dy,
|
||||
double x, double y)
|
||||
{
|
||||
/**
|
||||
* Compute a parameter t such that a line perpendicular to the (dx,dy)
|
||||
* vector, passing through (start->x + dx*t, start->y + dy*t), also
|
||||
* passes through (x,y).
|
||||
*
|
||||
* Let px = x - start->x, py = y - start->y.
|
||||
* t is given by
|
||||
* (px - dx*t)*dx + (py - dy*t)*dy = 0
|
||||
*
|
||||
* Solving for t we get
|
||||
* numerator = dx*px + dy*py
|
||||
* denominator = dx^2 + dy^2
|
||||
* t = numerator/denominator
|
||||
*
|
||||
* In CalculateRepeatingGradientParams we know the length of (dx,dy)
|
||||
* is not zero. (This is checked in DrawLinearRepeatingGradient.)
|
||||
*/
|
||||
double px = x - start->x;
|
||||
double py = y - start->y;
|
||||
double numerator = dx * px + dy * py;
|
||||
double denominator = dx * dx + dy * dy;
|
||||
double t = numerator / denominator;
|
||||
|
||||
if (*min_t > t) {
|
||||
*min_t = t;
|
||||
}
|
||||
if (*max_t < t) {
|
||||
*max_t = t;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Repeat the gradient line such that lines extended perpendicular to the
|
||||
* gradient line at both start and end would completely enclose the drawing
|
||||
* extents.
|
||||
*/
|
||||
static void
|
||||
CalculateRepeatingGradientParams(CGPoint *aStart, CGPoint *aEnd,
|
||||
CGRect aExtents, int *aRepeatCount)
|
||||
{
|
||||
double t_min = 0.;
|
||||
double t_max = 0.;
|
||||
double dx = aEnd->x - aStart->x;
|
||||
double dy = aEnd->y - aStart->y;
|
||||
|
||||
double bounds_x1 = aExtents.origin.x;
|
||||
double bounds_y1 = aExtents.origin.y;
|
||||
double bounds_x2 = aExtents.origin.x + aExtents.size.width;
|
||||
double bounds_y2 = aExtents.origin.y + aExtents.size.height;
|
||||
|
||||
UpdateLinearParametersToIncludePoint(&t_min, &t_max, aStart, dx, dy,
|
||||
bounds_x1, bounds_y1);
|
||||
UpdateLinearParametersToIncludePoint(&t_min, &t_max, aStart, dx, dy,
|
||||
bounds_x2, bounds_y1);
|
||||
UpdateLinearParametersToIncludePoint(&t_min, &t_max, aStart, dx, dy,
|
||||
bounds_x2, bounds_y2);
|
||||
UpdateLinearParametersToIncludePoint(&t_min, &t_max, aStart, dx, dy,
|
||||
bounds_x1, bounds_y2);
|
||||
|
||||
// Move t_min and t_max to the nearest usable integer to try to avoid
|
||||
// subtle variations due to numerical instability, especially accidentally
|
||||
// cutting off a pixel. Extending the gradient repetitions is always safe.
|
||||
t_min = floor (t_min);
|
||||
t_max = ceil (t_max);
|
||||
aEnd->x = aStart->x + dx * t_max;
|
||||
aEnd->y = aStart->y + dy * t_max;
|
||||
aStart->x = aStart->x + dx * t_min;
|
||||
aStart->y = aStart->y + dy * t_min;
|
||||
|
||||
*aRepeatCount = t_max - t_min;
|
||||
}
|
||||
|
||||
static void
|
||||
DrawLinearRepeatingGradient(CGContextRef cg, const LinearGradientPattern &aPattern, const CGRect &aExtents)
|
||||
|
@ -389,32 +466,12 @@ DrawLinearRepeatingGradient(CGContextRef cg, const LinearGradientPattern &aPatte
|
|||
CGPoint startPoint = { aPattern.mBegin.x, aPattern.mBegin.y };
|
||||
CGPoint endPoint = { aPattern.mEnd.x, aPattern.mEnd.y };
|
||||
|
||||
// extend the gradient line in multiples of the existing length in both
|
||||
// directions until it crosses an edge of the extents box.
|
||||
double xDiff = aPattern.mEnd.x - aPattern.mBegin.x;
|
||||
double yDiff = aPattern.mEnd.y - aPattern.mBegin.y;
|
||||
|
||||
int repeatCount = 1;
|
||||
// if we don't have a line then we can't extend it
|
||||
if (xDiff || yDiff) {
|
||||
while (startPoint.x > aExtents.origin.x
|
||||
&& startPoint.y > aExtents.origin.y
|
||||
&& startPoint.x < (aExtents.origin.x+aExtents.size.width)
|
||||
&& startPoint.y < (aExtents.origin.y+aExtents.size.height))
|
||||
{
|
||||
startPoint.x -= xDiff;
|
||||
startPoint.y -= yDiff;
|
||||
repeatCount++;
|
||||
}
|
||||
while (endPoint.x > aExtents.origin.x
|
||||
&& endPoint.y > aExtents.origin.y
|
||||
&& endPoint.x < (aExtents.origin.x+aExtents.size.width)
|
||||
&& endPoint.y < (aExtents.origin.y+aExtents.size.height))
|
||||
{
|
||||
endPoint.x += xDiff;
|
||||
endPoint.y += yDiff;
|
||||
repeatCount++;
|
||||
}
|
||||
if (aPattern.mEnd.x != aPattern.mBegin.x ||
|
||||
aPattern.mEnd.y != aPattern.mBegin.y) {
|
||||
CalculateRepeatingGradientParams(&startPoint, &endPoint, aExtents,
|
||||
&repeatCount);
|
||||
}
|
||||
|
||||
double scale = 1./repeatCount;
|
||||
|
|
|
@ -2494,7 +2494,6 @@ public:
|
|||
#ifdef MOZ_WIDGET_GONK
|
||||
virtual EGLImage CreateEGLImageForNativeBuffer(void* buffer) = 0;
|
||||
virtual void DestroyEGLImage(EGLImage image) = 0;
|
||||
virtual EGLImage GetNullEGLImage() = 0;
|
||||
#endif
|
||||
|
||||
virtual already_AddRefed<TextureImage>
|
||||
|
@ -3579,13 +3578,13 @@ protected:
|
|||
|
||||
private:
|
||||
void Init(GLenum target) {
|
||||
MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D ||
|
||||
target == LOCAL_GL_TEXTURE_RECTANGLE_ARB);
|
||||
mTarget = target;
|
||||
mOldTex = 0;
|
||||
GLenum bindingTarget = (target == LOCAL_GL_TEXTURE_2D) ?
|
||||
LOCAL_GL_TEXTURE_BINDING_2D :
|
||||
LOCAL_GL_TEXTURE_BINDING_RECTANGLE_ARB;
|
||||
GLenum bindingTarget = (target == LOCAL_GL_TEXTURE_2D) ? LOCAL_GL_TEXTURE_BINDING_2D
|
||||
: (target == LOCAL_GL_TEXTURE_RECTANGLE_ARB) ? LOCAL_GL_TEXTURE_BINDING_RECTANGLE_ARB
|
||||
: (target == LOCAL_GL_TEXTURE_CUBE_MAP) ? LOCAL_GL_TEXTURE_BINDING_CUBE_MAP
|
||||
: LOCAL_GL_NONE;
|
||||
MOZ_ASSERT(bindingTarget != LOCAL_GL_NONE);
|
||||
mGL->GetUIntegerv(bindingTarget, &mOldTex);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
#include "GLContext.h"
|
||||
#include "mozilla/Util.h"
|
||||
// please add new includes below Qt, otherwise it break Qt build due malloc wrapper conflicts
|
||||
|
||||
#if defined(XP_UNIX)
|
||||
|
||||
|
@ -13,24 +12,12 @@
|
|||
#include <gdk/gdkx.h>
|
||||
// we're using default display for now
|
||||
#define GET_NATIVE_WINDOW(aWidget) (EGLNativeWindowType)GDK_WINDOW_XID((GdkWindow *) aWidget->GetNativeData(NS_NATIVE_WINDOW))
|
||||
#elif defined(MOZ_WIDGET_QT)
|
||||
#include <QtOpenGL/QGLContext>
|
||||
#define GLdouble_defined 1
|
||||
// we're using default display for now
|
||||
#define GET_NATIVE_WINDOW(aWidget) (EGLNativeWindowType)static_cast<QWidget*>(aWidget->GetNativeData(NS_NATIVE_SHELLWIDGET))->winId()
|
||||
#elif defined(MOZ_WIDGET_GONK)
|
||||
#define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW))
|
||||
#include "HwcComposer2D.h"
|
||||
#include "libdisplay/GonkDisplay.h"
|
||||
#endif
|
||||
|
||||
#if defined(MOZ_X11)
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include "mozilla/X11Util.h"
|
||||
#include "gfxXlibSurface.h"
|
||||
#endif
|
||||
|
||||
#if defined(ANDROID)
|
||||
/* from widget */
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
|
@ -114,6 +101,7 @@ public:
|
|||
#include "gfxPlatform.h"
|
||||
#include "GLContextProvider.h"
|
||||
#include "GLLibraryEGL.h"
|
||||
#include "TextureImageEGL.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
|
@ -123,23 +111,13 @@ public:
|
|||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
#if defined(MOZ_WIDGET_GONK)
|
||||
static bool gUseBackingSurface = true;
|
||||
#else
|
||||
static bool gUseBackingSurface = false;
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
extern nsIntRect gScreenBounds;
|
||||
#endif
|
||||
|
||||
#define EGL_DISPLAY() sEGLLibrary.Display()
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
|
||||
static GLLibraryEGL sEGLLibrary;
|
||||
|
||||
#define ADD_ATTR_2(_array, _k, _v) do { \
|
||||
(_array).AppendElement(_k); \
|
||||
(_array).AppendElement(_v); \
|
||||
|
@ -156,11 +134,6 @@ CreateSurfaceForWindow(nsIWidget *aWidget, EGLConfig config);
|
|||
|
||||
static bool
|
||||
CreateConfig(EGLConfig* aConfig);
|
||||
#ifdef MOZ_X11
|
||||
|
||||
static EGLConfig
|
||||
CreateEGLSurfaceForXSurface(gfxASurface* aSurface, EGLConfig* aConfig = nullptr);
|
||||
#endif
|
||||
|
||||
static EGLint gContextAttribs[] = {
|
||||
LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||
|
@ -336,13 +309,6 @@ public:
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
char propValue[PROPERTY_VALUE_MAX];
|
||||
property_get("ro.build.version.sdk", propValue, "0");
|
||||
if (atoi(propValue) < 15)
|
||||
gUseBackingSurface = false;
|
||||
#endif
|
||||
|
||||
bool current = MakeCurrent();
|
||||
if (!current) {
|
||||
gfx::LogFailure(NS_LITERAL_CSTRING(
|
||||
|
@ -444,26 +410,6 @@ public:
|
|||
{
|
||||
sEGLLibrary.fDestroyImage(EGL_DISPLAY(), image);
|
||||
}
|
||||
|
||||
EGLImage GetNullEGLImage() MOZ_OVERRIDE
|
||||
{
|
||||
if (!mNullGraphicBuffer.get()) {
|
||||
mNullGraphicBuffer
|
||||
= new android::GraphicBuffer(
|
||||
1, 1,
|
||||
PIXEL_FORMAT_RGB_565,
|
||||
GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_NEVER);
|
||||
EGLint attrs[] = {
|
||||
LOCAL_EGL_NONE, LOCAL_EGL_NONE
|
||||
};
|
||||
mNullEGLImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(),
|
||||
EGL_NO_CONTEXT,
|
||||
LOCAL_EGL_NATIVE_BUFFER_ANDROID,
|
||||
mNullGraphicBuffer->getNativeBuffer(),
|
||||
attrs);
|
||||
}
|
||||
return mNullEGLImage;
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual void MakeCurrent_EGLSurface(void* surf) {
|
||||
|
@ -494,32 +440,7 @@ public:
|
|||
// Assume that EGL has the same problem as WGL does,
|
||||
// where MakeCurrent with an already-current context is
|
||||
// still expensive.
|
||||
#ifndef MOZ_WIDGET_QT
|
||||
if (!mSurface) {
|
||||
// We need to be able to bind NO_SURFACE when we don't
|
||||
// have access to a surface. We won't be drawing to the screen
|
||||
// but we will be able to do things like resource releases.
|
||||
succeeded = sEGLLibrary.fMakeCurrent(EGL_DISPLAY(),
|
||||
EGL_NO_SURFACE, EGL_NO_SURFACE,
|
||||
EGL_NO_CONTEXT);
|
||||
if (!succeeded && sEGLLibrary.fGetError() == LOCAL_EGL_CONTEXT_LOST) {
|
||||
mContextLost = true;
|
||||
NS_WARNING("EGL context has been lost.");
|
||||
}
|
||||
NS_ASSERTION(succeeded, "Failed to make GL context current!");
|
||||
return succeeded;
|
||||
}
|
||||
#endif
|
||||
if (aForce || sEGLLibrary.fGetCurrentContext() != mContext) {
|
||||
#ifdef MOZ_WIDGET_QT
|
||||
// Shared Qt GL context need to be informed about context switch
|
||||
if (mSharedContext) {
|
||||
QGLContext* qglCtx = static_cast<QGLContext*>(static_cast<GLContextEGL*>(mSharedContext.get())->mPlatformContext);
|
||||
if (qglCtx) {
|
||||
qglCtx->doneCurrent();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
succeeded = sEGLLibrary.fMakeCurrent(EGL_DISPLAY(),
|
||||
mCurSurface, mCurSurface,
|
||||
mContext);
|
||||
|
@ -545,13 +466,6 @@ public:
|
|||
return sEGLLibrary.fGetCurrentContext() == mContext;
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_QT
|
||||
virtual bool
|
||||
RenewSurface() {
|
||||
/* We don't support renewing on QT because we don't create the surface ourselves */
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
virtual bool
|
||||
RenewSurface() {
|
||||
sEGLLibrary.fMakeCurrent(EGL_DISPLAY(), EGL_NO_SURFACE, EGL_NO_SURFACE,
|
||||
|
@ -572,7 +486,6 @@ public:
|
|||
mSurface, mSurface,
|
||||
mContext);
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual void
|
||||
ReleaseSurface() {
|
||||
|
@ -687,18 +600,6 @@ protected:
|
|||
bool mShareWithEGLImage;
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
nsRefPtr<HwcComposer2D> mHwc;
|
||||
|
||||
/* mNullEGLImage and mNullGraphicBuffer are a hack to unattach a gralloc buffer
|
||||
* from a texture, which we don't know how to do otherwise (at least in the
|
||||
* TEXTURE_EXTERNAL case --- in the TEXTURE_2D case we could also use TexImage2D).
|
||||
*
|
||||
* So mNullGraphicBuffer will be initialized once to be a 1x1 gralloc buffer,
|
||||
* and mNullEGLImage will be initialized once to be an EGLImage wrapping it.
|
||||
*
|
||||
* This happens in GetNullEGLImage().
|
||||
*/
|
||||
EGLImage mNullEGLImage;
|
||||
android::sp<android::GraphicBuffer> mNullGraphicBuffer;
|
||||
#endif
|
||||
|
||||
// A dummy texture ID that can be used when we need a texture object whose
|
||||
|
@ -1068,482 +969,6 @@ GLContextEGL::ResizeOffscreen(const gfxIntSize& aNewSize)
|
|||
return ResizeScreenBuffer(aNewSize);
|
||||
}
|
||||
|
||||
|
||||
static GLContextEGL *
|
||||
GetGlobalContextEGL()
|
||||
{
|
||||
return static_cast<GLContextEGL*>(GLContextProviderEGL::GetGlobalContext());
|
||||
}
|
||||
|
||||
static GLenum
|
||||
GLFormatForImage(gfxImageFormat aFormat)
|
||||
{
|
||||
switch (aFormat) {
|
||||
case gfxImageFormatARGB32:
|
||||
case gfxImageFormatRGB24:
|
||||
// Thebes only supports RGBX, not packed RGB.
|
||||
return LOCAL_GL_RGBA;
|
||||
case gfxImageFormatRGB16_565:
|
||||
return LOCAL_GL_RGB;
|
||||
case gfxImageFormatA8:
|
||||
return LOCAL_GL_LUMINANCE;
|
||||
default:
|
||||
NS_WARNING("Unknown GL format for Image format");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static GLenum
|
||||
GLTypeForImage(gfxImageFormat aFormat)
|
||||
{
|
||||
switch (aFormat) {
|
||||
case gfxImageFormatARGB32:
|
||||
case gfxImageFormatRGB24:
|
||||
case gfxImageFormatA8:
|
||||
return LOCAL_GL_UNSIGNED_BYTE;
|
||||
case gfxImageFormatRGB16_565:
|
||||
return LOCAL_GL_UNSIGNED_SHORT_5_6_5;
|
||||
default:
|
||||
NS_WARNING("Unknown GL format for Image format");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
class TextureImageEGL
|
||||
: public TextureImage
|
||||
{
|
||||
public:
|
||||
TextureImageEGL(GLuint aTexture,
|
||||
const nsIntSize& aSize,
|
||||
GLenum aWrapMode,
|
||||
ContentType aContentType,
|
||||
GLContext* aContext,
|
||||
Flags aFlags = TextureImage::NoFlags,
|
||||
TextureState aTextureState = Created,
|
||||
TextureImage::ImageFormat aImageFormat = gfxImageFormatUnknown)
|
||||
: TextureImage(aSize, aWrapMode, aContentType, aFlags)
|
||||
, mGLContext(aContext)
|
||||
, mUpdateFormat(aImageFormat)
|
||||
, mEGLImage(nullptr)
|
||||
, mTexture(aTexture)
|
||||
, mSurface(nullptr)
|
||||
, mConfig(nullptr)
|
||||
, mTextureState(aTextureState)
|
||||
, mBound(false)
|
||||
{
|
||||
if (mUpdateFormat == gfxImageFormatUnknown) {
|
||||
mUpdateFormat = gfxPlatform::GetPlatform()->OptimalFormatForContent(GetContentType());
|
||||
}
|
||||
|
||||
if (gUseBackingSurface) {
|
||||
if (mUpdateFormat != gfxImageFormatARGB32) {
|
||||
mTextureFormat = FORMAT_R8G8B8X8;
|
||||
} else {
|
||||
mTextureFormat = FORMAT_R8G8B8A8;
|
||||
}
|
||||
Resize(aSize);
|
||||
} else {
|
||||
if (mUpdateFormat == gfxImageFormatRGB16_565) {
|
||||
mTextureFormat = FORMAT_R8G8B8X8;
|
||||
} else if (mUpdateFormat == gfxImageFormatRGB24) {
|
||||
// RGB24 means really RGBX for Thebes, which means we have to
|
||||
// use the right shader and ignore the uninitialized alpha
|
||||
// value.
|
||||
mTextureFormat = FORMAT_B8G8R8X8;
|
||||
} else {
|
||||
mTextureFormat = FORMAT_B8G8R8A8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~TextureImageEGL()
|
||||
{
|
||||
GLContext *ctx = mGLContext;
|
||||
if (ctx->IsDestroyed() || !ctx->IsOwningThreadCurrent()) {
|
||||
ctx = ctx->GetSharedContext();
|
||||
}
|
||||
|
||||
// If we have a context, then we need to delete the texture;
|
||||
// if we don't have a context (either real or shared),
|
||||
// then they went away when the contex was deleted, because it
|
||||
// was the only one that had access to it.
|
||||
if (ctx && !ctx->IsDestroyed()) {
|
||||
ctx->MakeCurrent();
|
||||
ctx->fDeleteTextures(1, &mTexture);
|
||||
ReleaseTexImage();
|
||||
DestroyEGLSurface();
|
||||
}
|
||||
}
|
||||
|
||||
bool UsingDirectTexture()
|
||||
{
|
||||
return !!mBackingSurface;
|
||||
}
|
||||
|
||||
virtual void GetUpdateRegion(nsIntRegion& aForRegion)
|
||||
{
|
||||
if (mTextureState != Valid) {
|
||||
// if the texture hasn't been initialized yet, force the
|
||||
// client to paint everything
|
||||
aForRegion = nsIntRect(nsIntPoint(0, 0), mSize);
|
||||
}
|
||||
|
||||
if (UsingDirectTexture()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We can only draw a rectangle, not subregions due to
|
||||
// the way that our texture upload functions work. If
|
||||
// needed, we /could/ do multiple texture uploads if we have
|
||||
// non-overlapping rects, but that's a tradeoff.
|
||||
aForRegion = nsIntRegion(aForRegion.GetBounds());
|
||||
}
|
||||
|
||||
virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion)
|
||||
{
|
||||
NS_ASSERTION(!mUpdateSurface, "BeginUpdate() without EndUpdate()?");
|
||||
|
||||
// determine the region the client will need to repaint
|
||||
GetUpdateRegion(aRegion);
|
||||
mUpdateRect = aRegion.GetBounds();
|
||||
|
||||
//printf_stderr("BeginUpdate with updateRect [%d %d %d %d]\n", mUpdateRect.x, mUpdateRect.y, mUpdateRect.width, mUpdateRect.height);
|
||||
if (!nsIntRect(nsIntPoint(0, 0), mSize).Contains(mUpdateRect)) {
|
||||
NS_ERROR("update outside of image");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mBackingSurface) {
|
||||
mUpdateSurface = mBackingSurface;
|
||||
return mUpdateSurface;
|
||||
}
|
||||
|
||||
//printf_stderr("creating image surface %dx%d format %d\n", mUpdateRect.width, mUpdateRect.height, mUpdateFormat);
|
||||
|
||||
mUpdateSurface =
|
||||
new gfxImageSurface(gfxIntSize(mUpdateRect.width, mUpdateRect.height),
|
||||
mUpdateFormat);
|
||||
|
||||
mUpdateSurface->SetDeviceOffset(gfxPoint(-mUpdateRect.x, -mUpdateRect.y));
|
||||
|
||||
return mUpdateSurface;
|
||||
}
|
||||
|
||||
virtual void EndUpdate()
|
||||
{
|
||||
NS_ASSERTION(!!mUpdateSurface, "EndUpdate() without BeginUpdate()?");
|
||||
|
||||
if (mBackingSurface && mUpdateSurface == mBackingSurface) {
|
||||
#ifdef MOZ_X11
|
||||
if (mBackingSurface->GetType() == gfxSurfaceTypeXlib) {
|
||||
FinishX(DefaultXDisplay());
|
||||
}
|
||||
#endif
|
||||
|
||||
mBackingSurface->SetDeviceOffset(gfxPoint(0, 0));
|
||||
mTextureState = Valid;
|
||||
mUpdateSurface = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
//printf_stderr("EndUpdate: slow path");
|
||||
|
||||
// This is the slower path -- we didn't have any way to set up
|
||||
// a fast mapping between our cairo target surface and the GL
|
||||
// texture, so we have to upload data.
|
||||
|
||||
// Undo the device offset that BeginUpdate set; doesn't much
|
||||
// matter for us here, but important if we ever do anything
|
||||
// directly with the surface.
|
||||
mUpdateSurface->SetDeviceOffset(gfxPoint(0, 0));
|
||||
|
||||
nsRefPtr<gfxImageSurface> uploadImage = nullptr;
|
||||
gfxIntSize updateSize(mUpdateRect.width, mUpdateRect.height);
|
||||
|
||||
NS_ASSERTION(mUpdateSurface->GetType() == gfxSurfaceTypeImage &&
|
||||
mUpdateSurface->GetSize() == updateSize,
|
||||
"Upload image isn't an image surface when one is expected, or is wrong size!");
|
||||
|
||||
uploadImage = static_cast<gfxImageSurface*>(mUpdateSurface.get());
|
||||
|
||||
if (!uploadImage) {
|
||||
return;
|
||||
}
|
||||
|
||||
mGLContext->MakeCurrent();
|
||||
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
|
||||
|
||||
if (mTextureState != Valid) {
|
||||
NS_ASSERTION(mUpdateRect.x == 0 && mUpdateRect.y == 0 &&
|
||||
mUpdateRect.Size() == mSize,
|
||||
"Bad initial update on non-created texture!");
|
||||
|
||||
mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D,
|
||||
0,
|
||||
GLFormatForImage(mUpdateFormat),
|
||||
mUpdateRect.width,
|
||||
mUpdateRect.height,
|
||||
0,
|
||||
GLFormatForImage(uploadImage->Format()),
|
||||
GLTypeForImage(uploadImage->Format()),
|
||||
uploadImage->Data());
|
||||
} else {
|
||||
mGLContext->fTexSubImage2D(LOCAL_GL_TEXTURE_2D,
|
||||
0,
|
||||
mUpdateRect.x,
|
||||
mUpdateRect.y,
|
||||
mUpdateRect.width,
|
||||
mUpdateRect.height,
|
||||
GLFormatForImage(uploadImage->Format()),
|
||||
GLTypeForImage(uploadImage->Format()),
|
||||
uploadImage->Data());
|
||||
}
|
||||
|
||||
mUpdateSurface = nullptr;
|
||||
mTextureState = Valid;
|
||||
return; // mTexture is bound
|
||||
}
|
||||
|
||||
virtual bool DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom /* = nsIntPoint(0, 0) */)
|
||||
{
|
||||
nsIntRect bounds = aRegion.GetBounds();
|
||||
|
||||
nsIntRegion region;
|
||||
if (mTextureState != Valid) {
|
||||
bounds = nsIntRect(0, 0, mSize.width, mSize.height);
|
||||
region = nsIntRegion(bounds);
|
||||
} else {
|
||||
region = aRegion;
|
||||
}
|
||||
|
||||
mTextureFormat =
|
||||
mGLContext->UploadSurfaceToTexture(aSurf,
|
||||
region,
|
||||
mTexture,
|
||||
mTextureState == Created,
|
||||
bounds.TopLeft() + aFrom,
|
||||
false);
|
||||
|
||||
mTextureState = Valid;
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void BindTexture(GLenum aTextureUnit)
|
||||
{
|
||||
// Ensure the texture is allocated before it is used.
|
||||
if (mTextureState == Created) {
|
||||
Resize(mSize);
|
||||
}
|
||||
|
||||
mGLContext->fActiveTexture(aTextureUnit);
|
||||
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
|
||||
mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||
}
|
||||
|
||||
virtual GLuint GetTextureID()
|
||||
{
|
||||
// Ensure the texture is allocated before it is used.
|
||||
if (mTextureState == Created) {
|
||||
Resize(mSize);
|
||||
}
|
||||
return mTexture;
|
||||
};
|
||||
|
||||
virtual bool InUpdate() const { return !!mUpdateSurface; }
|
||||
|
||||
virtual void Resize(const nsIntSize& aSize)
|
||||
{
|
||||
NS_ASSERTION(!mUpdateSurface, "Resize() while in update?");
|
||||
|
||||
if (mSize == aSize && mTextureState != Created)
|
||||
return;
|
||||
|
||||
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
|
||||
|
||||
// Try to generate a backin surface first if we have the ability
|
||||
if (gUseBackingSurface) {
|
||||
CreateBackingSurface(gfxIntSize(aSize.width, aSize.height));
|
||||
}
|
||||
|
||||
if (!UsingDirectTexture()) {
|
||||
// If we don't have a backing surface or failed to obtain one,
|
||||
// use the GL Texture failsafe
|
||||
mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D,
|
||||
0,
|
||||
GLFormatForImage(mUpdateFormat),
|
||||
aSize.width,
|
||||
aSize.height,
|
||||
0,
|
||||
GLFormatForImage(mUpdateFormat),
|
||||
GLTypeForImage(mUpdateFormat),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
mTextureState = Allocated;
|
||||
mSize = aSize;
|
||||
}
|
||||
|
||||
bool BindTexImage()
|
||||
{
|
||||
if (mBound && !ReleaseTexImage())
|
||||
return false;
|
||||
|
||||
EGLBoolean success =
|
||||
sEGLLibrary.fBindTexImage(EGL_DISPLAY(),
|
||||
(EGLSurface)mSurface,
|
||||
LOCAL_EGL_BACK_BUFFER);
|
||||
|
||||
if (success == LOCAL_EGL_FALSE)
|
||||
return false;
|
||||
|
||||
mBound = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReleaseTexImage()
|
||||
{
|
||||
if (!mBound)
|
||||
return true;
|
||||
|
||||
EGLBoolean success =
|
||||
sEGLLibrary.fReleaseTexImage(EGL_DISPLAY(),
|
||||
(EGLSurface)mSurface,
|
||||
LOCAL_EGL_BACK_BUFFER);
|
||||
|
||||
if (success == LOCAL_EGL_FALSE)
|
||||
return false;
|
||||
|
||||
mBound = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual already_AddRefed<gfxASurface> GetBackingSurface()
|
||||
{
|
||||
nsRefPtr<gfxASurface> copy = mBackingSurface;
|
||||
return copy.forget();
|
||||
}
|
||||
|
||||
virtual bool CreateEGLSurface(gfxASurface* aSurface)
|
||||
{
|
||||
#ifdef MOZ_X11
|
||||
if (!aSurface) {
|
||||
NS_WARNING("no surface");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aSurface->GetType() != gfxSurfaceTypeXlib) {
|
||||
NS_WARNING("wrong surface type, must be xlib");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mSurface) {
|
||||
return true;
|
||||
}
|
||||
|
||||
EGLSurface surface = CreateEGLSurfaceForXSurface(aSurface, &mConfig);
|
||||
|
||||
if (!surface) {
|
||||
NS_WARNING("couldn't find X config for surface");
|
||||
return false;
|
||||
}
|
||||
|
||||
mSurface = surface;
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void DestroyEGLSurface(void)
|
||||
{
|
||||
if (!mSurface)
|
||||
return;
|
||||
|
||||
sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface);
|
||||
mSurface = nullptr;
|
||||
}
|
||||
|
||||
virtual bool CreateBackingSurface(const gfxIntSize& aSize)
|
||||
{
|
||||
ReleaseTexImage();
|
||||
DestroyEGLSurface();
|
||||
mBackingSurface = nullptr;
|
||||
|
||||
#ifdef MOZ_X11
|
||||
Display* dpy = DefaultXDisplay();
|
||||
XRenderPictFormat* renderFMT =
|
||||
gfxXlibSurface::FindRenderFormat(dpy, mUpdateFormat);
|
||||
|
||||
nsRefPtr<gfxXlibSurface> xsurface =
|
||||
gfxXlibSurface::Create(DefaultScreenOfDisplay(dpy),
|
||||
renderFMT,
|
||||
gfxIntSize(aSize.width, aSize.height));
|
||||
|
||||
XSync(dpy, False);
|
||||
mConfig = nullptr;
|
||||
|
||||
if (sEGLLibrary.HasKHRImagePixmap() &&
|
||||
mGLContext->IsExtensionSupported(GLContext::OES_EGL_image))
|
||||
{
|
||||
mEGLImage =
|
||||
sEGLLibrary.fCreateImage(EGL_DISPLAY(),
|
||||
EGL_NO_CONTEXT,
|
||||
LOCAL_EGL_NATIVE_PIXMAP,
|
||||
(EGLClientBuffer)xsurface->XDrawable(),
|
||||
nullptr);
|
||||
|
||||
if (!mEGLImage) {
|
||||
printf_stderr("couldn't create EGL image: ERROR (0x%04x)\n", sEGLLibrary.fGetError());
|
||||
return false;
|
||||
}
|
||||
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
|
||||
mGLContext->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, mEGLImage);
|
||||
sEGLLibrary.fDestroyImage(EGL_DISPLAY(), mEGLImage);
|
||||
mEGLImage = nullptr;
|
||||
} else {
|
||||
if (!CreateEGLSurface(xsurface)) {
|
||||
printf_stderr("ProviderEGL Failed create EGL surface: ERROR (0x%04x)\n", sEGLLibrary.fGetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!BindTexImage()) {
|
||||
printf_stderr("ProviderEGL Failed to bind teximage: ERROR (0x%04x)\n", sEGLLibrary.fGetError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
mBackingSurface = xsurface;
|
||||
|
||||
return mBackingSurface != nullptr;
|
||||
#endif
|
||||
|
||||
return mBackingSurface != nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
typedef gfxImageFormat ImageFormat;
|
||||
|
||||
GLContext* mGLContext;
|
||||
|
||||
nsIntRect mUpdateRect;
|
||||
ImageFormat mUpdateFormat;
|
||||
bool mUsingDirectTexture;
|
||||
nsRefPtr<gfxASurface> mBackingSurface;
|
||||
nsRefPtr<gfxASurface> mUpdateSurface;
|
||||
EGLImage mEGLImage;
|
||||
GLuint mTexture;
|
||||
EGLSurface mSurface;
|
||||
EGLConfig mConfig;
|
||||
TextureState mTextureState;
|
||||
|
||||
bool mBound;
|
||||
|
||||
virtual void ApplyFilter()
|
||||
{
|
||||
mGLContext->ApplyFilterToBoundTexture(mFilter);
|
||||
}
|
||||
};
|
||||
|
||||
already_AddRefed<TextureImage>
|
||||
GLContextEGL::CreateTextureImage(const nsIntSize& aSize,
|
||||
TextureImage::ContentType aContentType,
|
||||
|
@ -1581,8 +1006,6 @@ GLContextEGL::TileGenFunc(const nsIntSize& aSize,
|
|||
return teximage.forget();
|
||||
}
|
||||
|
||||
static nsRefPtr<GLContext> gGlobalContext;
|
||||
|
||||
static const EGLint kEGLConfigAttribsOffscreenPBuffer[] = {
|
||||
LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PBUFFER_BIT,
|
||||
LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
|
||||
|
@ -1737,25 +1160,11 @@ GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget)
|
|||
if (hasNativeContext && eglContext) {
|
||||
void* platformContext = eglContext;
|
||||
SurfaceCaps caps = SurfaceCaps::Any();
|
||||
#ifdef MOZ_WIDGET_QT
|
||||
int depth = gfxPlatform::GetPlatform()->GetScreenDepth();
|
||||
QGLContext* context = const_cast<QGLContext*>(QGLContext::currentContext());
|
||||
if (context && context->device()) {
|
||||
depth = context->device()->depth();
|
||||
}
|
||||
const QGLFormat& format = context->format();
|
||||
doubleBuffered = format.doubleBuffer();
|
||||
platformContext = context;
|
||||
caps.bpp16 = depth == 16 ? true : false;
|
||||
caps.alpha = format.rgba();
|
||||
caps.depth = format.depth();
|
||||
caps.stencil = format.stencil();
|
||||
#endif
|
||||
EGLConfig config = EGL_NO_CONFIG;
|
||||
EGLSurface surface = sEGLLibrary.fGetCurrentSurface(LOCAL_EGL_DRAW);
|
||||
nsRefPtr<GLContextEGL> glContext =
|
||||
new GLContextEGL(caps,
|
||||
gGlobalContext, false,
|
||||
nullptr, false,
|
||||
config, surface, eglContext);
|
||||
|
||||
if (!glContext->Init())
|
||||
|
@ -1765,10 +1174,6 @@ GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget)
|
|||
glContext->SetIsDoubleBuffered(doubleBuffered);
|
||||
glContext->SetPlatformContext(platformContext);
|
||||
|
||||
if (!gGlobalContext) {
|
||||
gGlobalContext = glContext;
|
||||
}
|
||||
|
||||
return glContext.forget();
|
||||
}
|
||||
|
||||
|
@ -1790,11 +1195,10 @@ GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
GLContextEGL* shareContext = GetGlobalContextEGL();
|
||||
SurfaceCaps caps = SurfaceCaps::Any();
|
||||
nsRefPtr<GLContextEGL> glContext =
|
||||
GLContextEGL::CreateGLContext(caps,
|
||||
shareContext, false,
|
||||
nullptr, false,
|
||||
config, surface);
|
||||
|
||||
if (!glContext) {
|
||||
|
@ -1841,11 +1245,10 @@ GLContextEGL::CreateEGLPBufferOffscreenContext(const gfxIntSize& size)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
GLContextEGL* shareContext = GetGlobalContextEGL();
|
||||
SurfaceCaps dummyCaps = SurfaceCaps::Any();
|
||||
nsRefPtr<GLContextEGL> glContext =
|
||||
GLContextEGL::CreateGLContext(dummyCaps,
|
||||
shareContext, true,
|
||||
nullptr, true,
|
||||
config, surface);
|
||||
if (!glContext) {
|
||||
NS_WARNING("Failed to create GLContext from PBuffer");
|
||||
|
@ -1862,110 +1265,12 @@ GLContextEGL::CreateEGLPBufferOffscreenContext(const gfxIntSize& size)
|
|||
return glContext.forget();
|
||||
}
|
||||
|
||||
#ifdef MOZ_X11
|
||||
EGLSurface
|
||||
CreateEGLSurfaceForXSurface(gfxASurface* aSurface, EGLConfig* aConfig)
|
||||
{
|
||||
gfxXlibSurface* xsurface = static_cast<gfxXlibSurface*>(aSurface);
|
||||
bool opaque =
|
||||
aSurface->GetContentType() == GFX_CONTENT_COLOR;
|
||||
|
||||
static EGLint pixmap_config_rgb[] = {
|
||||
LOCAL_EGL_TEXTURE_TARGET, LOCAL_EGL_TEXTURE_2D,
|
||||
LOCAL_EGL_TEXTURE_FORMAT, LOCAL_EGL_TEXTURE_RGB,
|
||||
LOCAL_EGL_NONE
|
||||
};
|
||||
|
||||
static EGLint pixmap_config_rgba[] = {
|
||||
LOCAL_EGL_TEXTURE_TARGET, LOCAL_EGL_TEXTURE_2D,
|
||||
LOCAL_EGL_TEXTURE_FORMAT, LOCAL_EGL_TEXTURE_RGBA,
|
||||
LOCAL_EGL_NONE
|
||||
};
|
||||
|
||||
EGLSurface surface = nullptr;
|
||||
if (aConfig && *aConfig) {
|
||||
if (opaque)
|
||||
surface = sEGLLibrary.fCreatePixmapSurface(EGL_DISPLAY(), *aConfig,
|
||||
(EGLNativePixmapType)xsurface->XDrawable(),
|
||||
pixmap_config_rgb);
|
||||
else
|
||||
surface = sEGLLibrary.fCreatePixmapSurface(EGL_DISPLAY(), *aConfig,
|
||||
(EGLNativePixmapType)xsurface->XDrawable(),
|
||||
pixmap_config_rgba);
|
||||
|
||||
if (surface != EGL_NO_SURFACE)
|
||||
return surface;
|
||||
}
|
||||
|
||||
EGLConfig configs[32];
|
||||
int numConfigs = 32;
|
||||
|
||||
static EGLint pixmap_config[] = {
|
||||
LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PIXMAP_BIT,
|
||||
LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
|
||||
LOCAL_EGL_DEPTH_SIZE, 0,
|
||||
LOCAL_EGL_BIND_TO_TEXTURE_RGB, LOCAL_EGL_TRUE,
|
||||
LOCAL_EGL_NONE
|
||||
};
|
||||
|
||||
if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(),
|
||||
pixmap_config,
|
||||
configs, numConfigs, &numConfigs)
|
||||
|| numConfigs == 0)
|
||||
{
|
||||
NS_WARNING("No EGL Config for pixmap!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (i = 0; i < numConfigs; ++i) {
|
||||
if (opaque)
|
||||
surface = sEGLLibrary.fCreatePixmapSurface(EGL_DISPLAY(), configs[i],
|
||||
(EGLNativePixmapType)xsurface->XDrawable(),
|
||||
pixmap_config_rgb);
|
||||
else
|
||||
surface = sEGLLibrary.fCreatePixmapSurface(EGL_DISPLAY(), configs[i],
|
||||
(EGLNativePixmapType)xsurface->XDrawable(),
|
||||
pixmap_config_rgba);
|
||||
|
||||
if (surface != EGL_NO_SURFACE)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!surface) {
|
||||
NS_WARNING("Failed to CreatePixmapSurface!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aConfig)
|
||||
*aConfig = configs[i];
|
||||
|
||||
return surface;
|
||||
}
|
||||
#endif
|
||||
|
||||
already_AddRefed<GLContextEGL>
|
||||
GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& size)
|
||||
{
|
||||
gfxASurface *thebesSurface = nullptr;
|
||||
EGLNativePixmapType pixmap = 0;
|
||||
|
||||
#ifdef MOZ_X11
|
||||
nsRefPtr<gfxXlibSurface> xsurface =
|
||||
gfxXlibSurface::Create(DefaultScreenOfDisplay(DefaultXDisplay()),
|
||||
gfxXlibSurface::FindRenderFormat(DefaultXDisplay(),
|
||||
gfxImageFormatRGB24),
|
||||
size);
|
||||
|
||||
// XSync required after gfxXlibSurface::Create, otherwise EGL will fail with BadDrawable error
|
||||
XSync(DefaultXDisplay(), False);
|
||||
if (xsurface->CairoStatus() != 0)
|
||||
return nullptr;
|
||||
|
||||
thebesSurface = xsurface;
|
||||
pixmap = (EGLNativePixmapType)xsurface->XDrawable();
|
||||
#endif
|
||||
|
||||
if (!pixmap) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1973,19 +1278,15 @@ GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& size)
|
|||
EGLSurface surface = 0;
|
||||
EGLConfig config = 0;
|
||||
|
||||
#ifdef MOZ_X11
|
||||
surface = CreateEGLSurfaceForXSurface(thebesSurface, &config);
|
||||
#endif
|
||||
if (!config) {
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(surface);
|
||||
|
||||
GLContextEGL* shareContext = GetGlobalContextEGL();
|
||||
SurfaceCaps dummyCaps = SurfaceCaps::Any();
|
||||
nsRefPtr<GLContextEGL> glContext =
|
||||
GLContextEGL::CreateGLContext(dummyCaps,
|
||||
shareContext, true,
|
||||
nullptr, true,
|
||||
config, surface);
|
||||
if (!glContext) {
|
||||
NS_WARNING("Failed to create GLContext from XSurface");
|
||||
|
@ -2017,18 +1318,11 @@ GLContextProviderEGL::CreateOffscreen(const gfxIntSize& size,
|
|||
|
||||
gfxIntSize dummySize = gfxIntSize(16, 16);
|
||||
nsRefPtr<GLContextEGL> glContext;
|
||||
#if defined(MOZ_X11)
|
||||
glContext = GLContextEGL::CreateEGLPixmapOffscreenContext(dummySize);
|
||||
#else
|
||||
glContext = GLContextEGL::CreateEGLPBufferOffscreenContext(dummySize);
|
||||
#endif
|
||||
|
||||
if (!glContext)
|
||||
return nullptr;
|
||||
|
||||
if (flags & ContextFlagsGlobal)
|
||||
return glContext.forget();
|
||||
|
||||
if (!glContext->InitOffscreen(size, caps))
|
||||
return nullptr;
|
||||
|
||||
|
@ -2062,7 +1356,6 @@ GLContextProviderEGL::GetGlobalContext(const ContextFlags)
|
|||
void
|
||||
GLContextProviderEGL::Shutdown()
|
||||
{
|
||||
gGlobalContext = nullptr;
|
||||
}
|
||||
|
||||
} /* namespace gl */
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
namespace mozilla {
|
||||
namespace gl {
|
||||
|
||||
GLLibraryEGL sEGLLibrary;
|
||||
|
||||
// should match the order of EGLExtensions, and be null-terminated.
|
||||
static const char *sExtensionNames[] = {
|
||||
"EGL_KHR_image_base",
|
||||
|
|
|
@ -530,6 +530,9 @@ private:
|
|||
bool mIsANGLE;
|
||||
};
|
||||
|
||||
extern GLLibraryEGL sEGLLibrary;
|
||||
#define EGL_DISPLAY() sEGLLibrary.Display()
|
||||
|
||||
} /* namespace gl */
|
||||
} /* namespace mozilla */
|
||||
|
||||
|
|
|
@ -0,0 +1,319 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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 "TextureImageEGL.h"
|
||||
#include "GLLibraryEGL.h"
|
||||
#include "GLContext.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "mozilla/gfx/Types.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
|
||||
static GLenum
|
||||
GLFormatForImage(gfxImageFormat aFormat)
|
||||
{
|
||||
switch (aFormat) {
|
||||
case gfxImageFormatARGB32:
|
||||
case gfxImageFormatRGB24:
|
||||
// Thebes only supports RGBX, not packed RGB.
|
||||
return LOCAL_GL_RGBA;
|
||||
case gfxImageFormatRGB16_565:
|
||||
return LOCAL_GL_RGB;
|
||||
case gfxImageFormatA8:
|
||||
return LOCAL_GL_LUMINANCE;
|
||||
default:
|
||||
NS_WARNING("Unknown GL format for Image format");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static GLenum
|
||||
GLTypeForImage(gfxImageFormat aFormat)
|
||||
{
|
||||
switch (aFormat) {
|
||||
case gfxImageFormatARGB32:
|
||||
case gfxImageFormatRGB24:
|
||||
case gfxImageFormatA8:
|
||||
return LOCAL_GL_UNSIGNED_BYTE;
|
||||
case gfxImageFormatRGB16_565:
|
||||
return LOCAL_GL_UNSIGNED_SHORT_5_6_5;
|
||||
default:
|
||||
NS_WARNING("Unknown GL format for Image format");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
TextureImageEGL::TextureImageEGL(GLuint aTexture,
|
||||
const nsIntSize& aSize,
|
||||
GLenum aWrapMode,
|
||||
ContentType aContentType,
|
||||
GLContext* aContext,
|
||||
Flags aFlags,
|
||||
TextureState aTextureState,
|
||||
TextureImage::ImageFormat aImageFormat)
|
||||
: TextureImage(aSize, aWrapMode, aContentType, aFlags)
|
||||
, mGLContext(aContext)
|
||||
, mUpdateFormat(aImageFormat)
|
||||
, mEGLImage(nullptr)
|
||||
, mTexture(aTexture)
|
||||
, mSurface(nullptr)
|
||||
, mConfig(nullptr)
|
||||
, mTextureState(aTextureState)
|
||||
, mBound(false)
|
||||
{
|
||||
if (mUpdateFormat == gfxImageFormatUnknown) {
|
||||
mUpdateFormat = gfxPlatform::GetPlatform()->OptimalFormatForContent(GetContentType());
|
||||
}
|
||||
|
||||
if (mUpdateFormat == gfxImageFormatRGB16_565) {
|
||||
mTextureFormat = gfx::FORMAT_R8G8B8X8;
|
||||
} else if (mUpdateFormat == gfxImageFormatRGB24) {
|
||||
// RGB24 means really RGBX for Thebes, which means we have to
|
||||
// use the right shader and ignore the uninitialized alpha
|
||||
// value.
|
||||
mTextureFormat = gfx::FORMAT_B8G8R8X8;
|
||||
} else {
|
||||
mTextureFormat = gfx::FORMAT_B8G8R8A8;
|
||||
}
|
||||
}
|
||||
|
||||
TextureImageEGL::~TextureImageEGL()
|
||||
{
|
||||
if (mGLContext->IsDestroyed() || !mGLContext->IsOwningThreadCurrent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have a context, then we need to delete the texture;
|
||||
// if we don't have a context (either real or shared),
|
||||
// then they went away when the contex was deleted, because it
|
||||
// was the only one that had access to it.
|
||||
mGLContext->MakeCurrent();
|
||||
mGLContext->fDeleteTextures(1, &mTexture);
|
||||
ReleaseTexImage();
|
||||
DestroyEGLSurface();
|
||||
}
|
||||
|
||||
void
|
||||
TextureImageEGL::GetUpdateRegion(nsIntRegion& aForRegion)
|
||||
{
|
||||
if (mTextureState != Valid) {
|
||||
// if the texture hasn't been initialized yet, force the
|
||||
// client to paint everything
|
||||
aForRegion = nsIntRect(nsIntPoint(0, 0), mSize);
|
||||
}
|
||||
|
||||
// We can only draw a rectangle, not subregions due to
|
||||
// the way that our texture upload functions work. If
|
||||
// needed, we /could/ do multiple texture uploads if we have
|
||||
// non-overlapping rects, but that's a tradeoff.
|
||||
aForRegion = nsIntRegion(aForRegion.GetBounds());
|
||||
}
|
||||
|
||||
gfxASurface*
|
||||
TextureImageEGL::BeginUpdate(nsIntRegion& aRegion)
|
||||
{
|
||||
NS_ASSERTION(!mUpdateSurface, "BeginUpdate() without EndUpdate()?");
|
||||
|
||||
// determine the region the client will need to repaint
|
||||
GetUpdateRegion(aRegion);
|
||||
mUpdateRect = aRegion.GetBounds();
|
||||
|
||||
//printf_stderr("BeginUpdate with updateRect [%d %d %d %d]\n", mUpdateRect.x, mUpdateRect.y, mUpdateRect.width, mUpdateRect.height);
|
||||
if (!nsIntRect(nsIntPoint(0, 0), mSize).Contains(mUpdateRect)) {
|
||||
NS_ERROR("update outside of image");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//printf_stderr("creating image surface %dx%d format %d\n", mUpdateRect.width, mUpdateRect.height, mUpdateFormat);
|
||||
|
||||
mUpdateSurface =
|
||||
new gfxImageSurface(gfxIntSize(mUpdateRect.width, mUpdateRect.height),
|
||||
mUpdateFormat);
|
||||
|
||||
mUpdateSurface->SetDeviceOffset(gfxPoint(-mUpdateRect.x, -mUpdateRect.y));
|
||||
|
||||
return mUpdateSurface;
|
||||
}
|
||||
|
||||
void
|
||||
TextureImageEGL::EndUpdate()
|
||||
{
|
||||
NS_ASSERTION(!!mUpdateSurface, "EndUpdate() without BeginUpdate()?");
|
||||
|
||||
//printf_stderr("EndUpdate: slow path");
|
||||
|
||||
// This is the slower path -- we didn't have any way to set up
|
||||
// a fast mapping between our cairo target surface and the GL
|
||||
// texture, so we have to upload data.
|
||||
|
||||
// Undo the device offset that BeginUpdate set; doesn't much
|
||||
// matter for us here, but important if we ever do anything
|
||||
// directly with the surface.
|
||||
mUpdateSurface->SetDeviceOffset(gfxPoint(0, 0));
|
||||
|
||||
nsRefPtr<gfxImageSurface> uploadImage = nullptr;
|
||||
gfxIntSize updateSize(mUpdateRect.width, mUpdateRect.height);
|
||||
|
||||
NS_ASSERTION(mUpdateSurface->GetType() == gfxSurfaceTypeImage &&
|
||||
mUpdateSurface->GetSize() == updateSize,
|
||||
"Upload image isn't an image surface when one is expected, or is wrong size!");
|
||||
|
||||
uploadImage = static_cast<gfxImageSurface*>(mUpdateSurface.get());
|
||||
|
||||
if (!uploadImage) {
|
||||
return;
|
||||
}
|
||||
|
||||
mGLContext->MakeCurrent();
|
||||
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
|
||||
|
||||
if (mTextureState != Valid) {
|
||||
NS_ASSERTION(mUpdateRect.x == 0 && mUpdateRect.y == 0 &&
|
||||
mUpdateRect.Size() == mSize,
|
||||
"Bad initial update on non-created texture!");
|
||||
|
||||
mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D,
|
||||
0,
|
||||
GLFormatForImage(mUpdateFormat),
|
||||
mUpdateRect.width,
|
||||
mUpdateRect.height,
|
||||
0,
|
||||
GLFormatForImage(uploadImage->Format()),
|
||||
GLTypeForImage(uploadImage->Format()),
|
||||
uploadImage->Data());
|
||||
} else {
|
||||
mGLContext->fTexSubImage2D(LOCAL_GL_TEXTURE_2D,
|
||||
0,
|
||||
mUpdateRect.x,
|
||||
mUpdateRect.y,
|
||||
mUpdateRect.width,
|
||||
mUpdateRect.height,
|
||||
GLFormatForImage(uploadImage->Format()),
|
||||
GLTypeForImage(uploadImage->Format()),
|
||||
uploadImage->Data());
|
||||
}
|
||||
|
||||
mUpdateSurface = nullptr;
|
||||
mTextureState = Valid;
|
||||
return; // mTexture is bound
|
||||
}
|
||||
|
||||
bool
|
||||
TextureImageEGL::DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom /* = nsIntPoint(0, 0) */)
|
||||
{
|
||||
nsIntRect bounds = aRegion.GetBounds();
|
||||
|
||||
nsIntRegion region;
|
||||
if (mTextureState != Valid) {
|
||||
bounds = nsIntRect(0, 0, mSize.width, mSize.height);
|
||||
region = nsIntRegion(bounds);
|
||||
} else {
|
||||
region = aRegion;
|
||||
}
|
||||
|
||||
mTextureFormat =
|
||||
mGLContext->UploadSurfaceToTexture(aSurf,
|
||||
region,
|
||||
mTexture,
|
||||
mTextureState == Created,
|
||||
bounds.TopLeft() + aFrom,
|
||||
false);
|
||||
|
||||
mTextureState = Valid;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TextureImageEGL::BindTexture(GLenum aTextureUnit)
|
||||
{
|
||||
// Ensure the texture is allocated before it is used.
|
||||
if (mTextureState == Created) {
|
||||
Resize(mSize);
|
||||
}
|
||||
|
||||
mGLContext->fActiveTexture(aTextureUnit);
|
||||
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
|
||||
mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||
}
|
||||
|
||||
void
|
||||
TextureImageEGL::Resize(const nsIntSize& aSize)
|
||||
{
|
||||
NS_ASSERTION(!mUpdateSurface, "Resize() while in update?");
|
||||
|
||||
if (mSize == aSize && mTextureState != Created)
|
||||
return;
|
||||
|
||||
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
|
||||
|
||||
mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D,
|
||||
0,
|
||||
GLFormatForImage(mUpdateFormat),
|
||||
aSize.width,
|
||||
aSize.height,
|
||||
0,
|
||||
GLFormatForImage(mUpdateFormat),
|
||||
GLTypeForImage(mUpdateFormat),
|
||||
nullptr);
|
||||
|
||||
mTextureState = Allocated;
|
||||
mSize = aSize;
|
||||
}
|
||||
|
||||
bool
|
||||
TextureImageEGL::BindTexImage()
|
||||
{
|
||||
if (mBound && !ReleaseTexImage())
|
||||
return false;
|
||||
|
||||
EGLBoolean success =
|
||||
sEGLLibrary.fBindTexImage(EGL_DISPLAY(),
|
||||
(EGLSurface)mSurface,
|
||||
LOCAL_EGL_BACK_BUFFER);
|
||||
|
||||
if (success == LOCAL_EGL_FALSE)
|
||||
return false;
|
||||
|
||||
mBound = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TextureImageEGL::ReleaseTexImage()
|
||||
{
|
||||
if (!mBound)
|
||||
return true;
|
||||
|
||||
EGLBoolean success =
|
||||
sEGLLibrary.fReleaseTexImage(EGL_DISPLAY(),
|
||||
(EGLSurface)mSurface,
|
||||
LOCAL_EGL_BACK_BUFFER);
|
||||
|
||||
if (success == LOCAL_EGL_FALSE)
|
||||
return false;
|
||||
|
||||
mBound = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TextureImageEGL::DestroyEGLSurface(void)
|
||||
{
|
||||
if (!mSurface)
|
||||
return;
|
||||
|
||||
sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface);
|
||||
mSurface = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
TextureImageEGL::ApplyFilter()
|
||||
{
|
||||
mGLContext->ApplyFilterToBoundTexture(mFilter);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef TEXTUREIMAGEEGL_H_
|
||||
#define TEXTUREIMAGEEGL_H_
|
||||
|
||||
#include "GLTextureImage.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
|
||||
class TextureImageEGL
|
||||
: public TextureImage
|
||||
{
|
||||
public:
|
||||
TextureImageEGL(GLuint aTexture,
|
||||
const nsIntSize& aSize,
|
||||
GLenum aWrapMode,
|
||||
ContentType aContentType,
|
||||
GLContext* aContext,
|
||||
Flags aFlags = TextureImage::NoFlags,
|
||||
TextureState aTextureState = Created,
|
||||
TextureImage::ImageFormat aImageFormat = gfxImageFormatUnknown);
|
||||
|
||||
virtual ~TextureImageEGL();
|
||||
|
||||
virtual void GetUpdateRegion(nsIntRegion& aForRegion);
|
||||
|
||||
virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion);
|
||||
|
||||
virtual void EndUpdate();
|
||||
|
||||
virtual bool DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom /* = nsIntPoint(0, 0) */);
|
||||
|
||||
virtual void BindTexture(GLenum aTextureUnit);
|
||||
|
||||
virtual GLuint GetTextureID()
|
||||
{
|
||||
// Ensure the texture is allocated before it is used.
|
||||
if (mTextureState == Created) {
|
||||
Resize(mSize);
|
||||
}
|
||||
return mTexture;
|
||||
};
|
||||
|
||||
virtual bool InUpdate() const { return !!mUpdateSurface; }
|
||||
|
||||
virtual void Resize(const nsIntSize& aSize);
|
||||
|
||||
bool BindTexImage();
|
||||
|
||||
bool ReleaseTexImage();
|
||||
|
||||
virtual bool CreateEGLSurface(gfxASurface* aSurface)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void DestroyEGLSurface(void);
|
||||
|
||||
protected:
|
||||
typedef gfxImageFormat ImageFormat;
|
||||
|
||||
GLContext* mGLContext;
|
||||
|
||||
nsIntRect mUpdateRect;
|
||||
ImageFormat mUpdateFormat;
|
||||
nsRefPtr<gfxASurface> mUpdateSurface;
|
||||
EGLImage mEGLImage;
|
||||
GLuint mTexture;
|
||||
EGLSurface mSurface;
|
||||
EGLConfig mConfig;
|
||||
TextureState mTextureState;
|
||||
|
||||
bool mBound;
|
||||
|
||||
virtual void ApplyFilter();
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TEXTUREIMAGEEGL_H_
|
|
@ -102,6 +102,7 @@ CPP_SOURCES += [
|
|||
'SharedSurface.cpp',
|
||||
'GLLibraryEGL.cpp',
|
||||
'SharedSurfaceEGL.cpp',
|
||||
'TextureImageEGL.cpp',
|
||||
'SharedSurfaceGL.cpp',
|
||||
'SurfaceFactory.cpp',
|
||||
'SurfaceStream.cpp',
|
||||
|
|
|
@ -705,6 +705,14 @@ CompositorOGL::SetRenderTarget(CompositingRenderTarget *aSurface)
|
|||
CompositingRenderTargetOGL* surface
|
||||
= static_cast<CompositingRenderTargetOGL*>(aSurface);
|
||||
if (mCurrentRenderTarget != surface) {
|
||||
// Restore the scissor rect that was active before we set the current
|
||||
// render target.
|
||||
mGLContext->PopScissorRect();
|
||||
|
||||
// Save the current scissor rect so that we can pop back to it when
|
||||
// changing the render target again.
|
||||
mGLContext->PushScissorRect();
|
||||
|
||||
surface->BindRenderTarget();
|
||||
mCurrentRenderTarget = surface;
|
||||
}
|
||||
|
@ -828,6 +836,9 @@ CompositorOGL::BeginFrame(const Rect *aClipRectIn, const gfxMatrix& aTransform,
|
|||
mGLContext->fScissor(aClipRectIn->x, aClipRectIn->y, aClipRectIn->width, aClipRectIn->height);
|
||||
}
|
||||
|
||||
// Save the current scissor rect so that SetRenderTarget can pop back to it.
|
||||
mGLContext->PushScissorRect();
|
||||
|
||||
// If the Android compositor is being used, this clear will be done in
|
||||
// DrawWindowUnderlay. Make sure the bits used here match up with those used
|
||||
// in mobile/android/base/gfx/LayerRenderer.java
|
||||
|
@ -1281,6 +1292,9 @@ CompositorOGL::EndFrame()
|
|||
return;
|
||||
}
|
||||
|
||||
// Restore the scissor rect that we saved in BeginFrame.
|
||||
mGLContext->PopScissorRect();
|
||||
|
||||
mCurrentRenderTarget = nullptr;
|
||||
|
||||
if (sDrawFPS && !mFPS) {
|
||||
|
|
|
@ -1,17 +1,13 @@
|
|||
installdir = $(libdir)/$(MOZ_APP_NAME)-$(MOZ_APP_VERSION)
|
||||
sdkdir = $(libdir)/$(MOZ_APP_NAME)-devel-$(MOZ_APP_VERSION)
|
||||
|
||||
ifndef INCLUDED_FUNCTIONS_MK
|
||||
include $(topsrcdir)/config/makefiles/functions.mk
|
||||
endif
|
||||
|
||||
ifneq (,$(filter /%,$(TOP_DIST)))
|
||||
DIST := $(call core_realpath,$(TOP_DIST))
|
||||
DIST = $(TOP_DIST)
|
||||
else
|
||||
ifeq (.,$(DEPTH))
|
||||
DIST := $(call core_realpath,$(TOP_DIST))
|
||||
DIST = $(TOP_DIST)
|
||||
else
|
||||
DIST := $(call core_realpath,$(DEPTH)/$(TOP_DIST))
|
||||
DIST = $(DEPTH)/$(TOP_DIST)
|
||||
endif
|
||||
endif
|
||||
|
||||
|
|
|
@ -64,6 +64,10 @@ check-variable = $(if $(filter-out 0 1,$(words $($(x))z)),$(error Spaces are not
|
|||
|
||||
$(foreach x,$(CHECK_VARS),$(check-variable))
|
||||
|
||||
ifndef INCLUDED_FUNCTIONS_MK
|
||||
include $(topsrcdir)/config/makefiles/functions.mk
|
||||
endif
|
||||
|
||||
RM = rm -f
|
||||
|
||||
# LIBXUL_DIST is not defined under js/src, thus we make it mean DIST there.
|
||||
|
|
|
@ -25,8 +25,8 @@ ifdef IS_COMPONENT
|
|||
$(INSTALL) $(IFLAGS2) $(SHARED_LIBRARY) $(FINAL_TARGET)/components
|
||||
$(ELF_DYNSTR_GC) $(FINAL_TARGET)/components/$(SHARED_LIBRARY)
|
||||
ifndef NO_COMPONENTS_MANIFEST
|
||||
@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/chrome.manifest "manifest components/components.manifest"
|
||||
@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/components/components.manifest "binary-component $(SHARED_LIBRARY)"
|
||||
$(call py_action,buildlist,$(FINAL_TARGET)/chrome.manifest "manifest components/components.manifest")
|
||||
$(call py_action,buildlist,$(FINAL_TARGET)/components/components.manifest "binary-component $(SHARED_LIBRARY)")
|
||||
endif
|
||||
endif # IS_COMPONENT
|
||||
endif # SHARED_LIBRARY
|
||||
|
|
|
@ -1314,8 +1314,8 @@ INSTALL_TARGETS += _XPT_NAME
|
|||
|
||||
ifndef NO_INTERFACES_MANIFEST
|
||||
libs:: $(call mkdir_deps,$(FINAL_TARGET)/components)
|
||||
@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/components/interfaces.manifest "interfaces $(XPT_NAME)"
|
||||
@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/chrome.manifest "manifest components/interfaces.manifest"
|
||||
$(call py_action,buildlist,$(FINAL_TARGET)/components/interfaces.manifest "interfaces $(XPT_NAME)")
|
||||
$(call py_action,buildlist,$(FINAL_TARGET)/chrome.manifest "manifest components/interfaces.manifest")
|
||||
endif
|
||||
endif
|
||||
|
||||
|
@ -1351,7 +1351,7 @@ endif
|
|||
EXTRA_MANIFESTS = $(filter %.manifest,$(EXTRA_COMPONENTS) $(EXTRA_PP_COMPONENTS))
|
||||
ifneq (,$(EXTRA_MANIFESTS))
|
||||
libs:: $(call mkdir_deps,$(FINAL_TARGET))
|
||||
$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/chrome.manifest $(patsubst %,"manifest components/%",$(notdir $(EXTRA_MANIFESTS)))
|
||||
$(call py_action,buildlist,$(FINAL_TARGET)/chrome.manifest $(patsubst %,"manifest components/%",$(notdir $(EXTRA_MANIFESTS))))
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
|
|
|
@ -2149,70 +2149,8 @@ if test "$ac_cv_header_sys_isa_defs_h" = yes; then
|
|||
AC_DEFINE(JS_HAVE_SYS_ISA_DEFS_H)
|
||||
fi
|
||||
|
||||
dnl Check for uint and uint_t.
|
||||
dnl ========================================================
|
||||
AC_MSG_CHECKING(for uint)
|
||||
AC_CACHE_VAL(ac_cv_uint,
|
||||
[AC_TRY_COMPILE([#include <stdio.h>
|
||||
#include <sys/types.h>],
|
||||
[uint foo = 0;],
|
||||
[ac_cv_uint=true],
|
||||
[ac_cv_uint=false])])
|
||||
if test "$ac_cv_uint" = true ; then
|
||||
AC_DEFINE(HAVE_UINT)
|
||||
AC_MSG_RESULT(yes)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
AC_MSG_CHECKING(for uint_t)
|
||||
AC_CACHE_VAL(ac_cv_uint_t,
|
||||
[AC_TRY_COMPILE([#include <stdio.h>
|
||||
#include <sys/types.h>],
|
||||
[uint_t foo = 0;],
|
||||
[ac_cv_uint_t=true],
|
||||
[ac_cv_uint_t=false])])
|
||||
if test "$ac_cv_uint_t" = true ; then
|
||||
AC_DEFINE(HAVE_UINT_T)
|
||||
AC_MSG_RESULT(yes)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
dnl On the gcc trunk (as of 2001-02-09) _GNU_SOURCE, and thus __USE_GNU,
|
||||
dnl are defined when compiling C++ but not C. Since the result of this
|
||||
dnl test is used only in C++, do it in C++.
|
||||
AC_LANG_CPLUSPLUS
|
||||
|
||||
AC_MSG_CHECKING(for uname.domainname)
|
||||
AC_CACHE_VAL(ac_cv_have_uname_domainname_field,
|
||||
[AC_TRY_COMPILE([#include <sys/utsname.h>],
|
||||
[ struct utsname *res; char *domain;
|
||||
(void)uname(res); if (res != 0) { domain = res->domainname; } ],
|
||||
[ac_cv_have_uname_domainname_field=true],
|
||||
[ac_cv_have_uname_domainname_field=false])])
|
||||
|
||||
if test "$ac_cv_have_uname_domainname_field" = "true"; then
|
||||
AC_DEFINE(HAVE_UNAME_DOMAINNAME_FIELD)
|
||||
AC_MSG_RESULT(yes)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING(for uname.__domainname)
|
||||
AC_CACHE_VAL(ac_cv_have_uname_us_domainname_field,
|
||||
[AC_TRY_COMPILE([#include <sys/utsname.h>],
|
||||
[ struct utsname *res; char *domain;
|
||||
(void)uname(res); if (res != 0) { domain = res->__domainname; } ],
|
||||
[ac_cv_have_uname_us_domainname_field=true],
|
||||
[ac_cv_have_uname_us_domainname_field=false])])
|
||||
|
||||
if test "$ac_cv_have_uname_us_domainname_field" = "true"; then
|
||||
AC_DEFINE(HAVE_UNAME_US_DOMAINNAME_FIELD)
|
||||
AC_MSG_RESULT(yes)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
MOZ_CXX11
|
||||
|
||||
dnl Check for .hidden assembler directive and visibility attribute.
|
||||
|
@ -2628,24 +2566,6 @@ dnl AC_CHECK_LIB(bind, res_ninit, AC_DEFINE(HAVE_RES_NINIT),
|
|||
dnl AC_CHECK_LIB(resolv, res_ninit, AC_DEFINE(HAVE_RES_NINIT)))
|
||||
fi
|
||||
|
||||
AC_LANG_CPLUSPLUS
|
||||
AC_CACHE_CHECK(
|
||||
[for gnu_get_libc_version()],
|
||||
ac_cv_func_gnu_get_libc_version,
|
||||
[AC_TRY_LINK([
|
||||
#ifdef HAVE_GNU_LIBC_VERSION_H
|
||||
#include <gnu/libc-version.h>
|
||||
#endif
|
||||
],
|
||||
[const char *glibc_version = gnu_get_libc_version();],
|
||||
[ac_cv_func_gnu_get_libc_version=yes],
|
||||
[ac_cv_func_gnu_get_libc_version=no]
|
||||
)]
|
||||
)
|
||||
|
||||
if test "$ac_cv_func_gnu_get_libc_version" = "yes"; then
|
||||
AC_DEFINE(HAVE_GNU_GET_LIBC_VERSION)
|
||||
fi
|
||||
AC_LANG_C
|
||||
|
||||
dnl **********************
|
||||
|
@ -3291,29 +3211,6 @@ if test "$NS_TRACE_MALLOC"; then
|
|||
fi
|
||||
|
||||
if test "$MOZ_MEMORY"; then
|
||||
|
||||
dnl Don't try to run compiler tests on Windows
|
||||
if test "$OS_ARCH" = "WINNT"; then
|
||||
if test -z "$HAVE_64BIT_OS"; then
|
||||
AC_DEFINE_UNQUOTED([MOZ_MEMORY_SIZEOF_PTR_2POW], 2)
|
||||
else
|
||||
AC_DEFINE_UNQUOTED([MOZ_MEMORY_SIZEOF_PTR_2POW], 3)
|
||||
fi
|
||||
else
|
||||
AC_CHECK_SIZEOF([int *], [4])
|
||||
case "${ac_cv_sizeof_int_p}" in
|
||||
4)
|
||||
AC_DEFINE_UNQUOTED([MOZ_MEMORY_SIZEOF_PTR_2POW], 2)
|
||||
;;
|
||||
8)
|
||||
AC_DEFINE_UNQUOTED([MOZ_MEMORY_SIZEOF_PTR_2POW], 3)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([Unexpected pointer size])
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
AC_DEFINE(MOZ_MEMORY)
|
||||
if test "x$MOZ_DEBUG" = "x1"; then
|
||||
AC_DEFINE(MOZ_MEMORY_DEBUG)
|
||||
|
|
|
@ -420,7 +420,7 @@ class RelocatablePtr : public EncapsulatedPtr<T>
|
|||
|
||||
~RelocatablePtr() {
|
||||
if (this->value)
|
||||
relocate(this->value->runtimeFromMainThread());
|
||||
relocate(this->value->runtimeFromAnyThread());
|
||||
}
|
||||
|
||||
RelocatablePtr<T> &operator=(T *v) {
|
||||
|
@ -430,7 +430,7 @@ class RelocatablePtr : public EncapsulatedPtr<T>
|
|||
this->value = v;
|
||||
post();
|
||||
} else if (this->value) {
|
||||
JSRuntime *rt = this->value->runtimeFromMainThread();
|
||||
JSRuntime *rt = this->value->runtimeFromAnyThread();
|
||||
this->value = v;
|
||||
relocate(rt);
|
||||
}
|
||||
|
@ -444,7 +444,7 @@ class RelocatablePtr : public EncapsulatedPtr<T>
|
|||
this->value = v.value;
|
||||
post();
|
||||
} else if (this->value) {
|
||||
JSRuntime *rt = this->value->runtimeFromMainThread();
|
||||
JSRuntime *rt = this->value->runtimeFromAnyThread();
|
||||
this->value = v;
|
||||
relocate(rt);
|
||||
}
|
||||
|
@ -712,7 +712,7 @@ class HeapValue : public EncapsulatedValue
|
|||
static void writeBarrierPost(const Value &value, Value *addr) {
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
if (value.isMarkable())
|
||||
shadowRuntimeFromMainThread(value)->gcStoreBufferPtr()->putValue(addr);
|
||||
shadowRuntimeFromAnyThread(value)->gcStoreBufferPtr()->putValue(addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -761,7 +761,7 @@ class RelocatableValue : public EncapsulatedValue
|
|||
~RelocatableValue()
|
||||
{
|
||||
if (value.isMarkable())
|
||||
relocate(runtimeFromMainThread(value));
|
||||
relocate(runtimeFromAnyThread(value));
|
||||
}
|
||||
|
||||
RelocatableValue &operator=(const Value &v) {
|
||||
|
@ -771,7 +771,7 @@ class RelocatableValue : public EncapsulatedValue
|
|||
value = v;
|
||||
post();
|
||||
} else if (value.isMarkable()) {
|
||||
JSRuntime *rt = runtimeFromMainThread(value);
|
||||
JSRuntime *rt = runtimeFromAnyThread(value);
|
||||
relocate(rt);
|
||||
value = v;
|
||||
} else {
|
||||
|
@ -787,7 +787,7 @@ class RelocatableValue : public EncapsulatedValue
|
|||
value = v.value;
|
||||
post();
|
||||
} else if (value.isMarkable()) {
|
||||
JSRuntime *rt = runtimeFromMainThread(value);
|
||||
JSRuntime *rt = runtimeFromAnyThread(value);
|
||||
relocate(rt);
|
||||
value = v.value;
|
||||
} else {
|
||||
|
@ -800,7 +800,7 @@ class RelocatableValue : public EncapsulatedValue
|
|||
void post() {
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
JS_ASSERT(value.isMarkable());
|
||||
shadowRuntimeFromMainThread(value)->gcStoreBufferPtr()->putRelocatableValue(&value);
|
||||
shadowRuntimeFromAnyThread(value)->gcStoreBufferPtr()->putRelocatableValue(&value);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -299,7 +299,7 @@ typedef unsigned char uint8_t;
|
|||
typedef unsigned uint32_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
typedef unsigned long long uintmax_t;
|
||||
#if defined(MOZ_MEMORY_SIZEOF_PTR_2POW) && (MOZ_MEMORY_SIZEOF_PTR_2POW == 3)
|
||||
#if defined(_WIN64)
|
||||
typedef long long ssize_t;
|
||||
#else
|
||||
typedef long ssize_t;
|
||||
|
@ -469,8 +469,8 @@ static const bool isthreaded = true;
|
|||
|
||||
/* Minimum alignment of non-tiny allocations is 2^QUANTUM_2POW_MIN bytes. */
|
||||
# define QUANTUM_2POW_MIN 4
|
||||
#ifdef MOZ_MEMORY_SIZEOF_PTR_2POW
|
||||
# define SIZEOF_PTR_2POW MOZ_MEMORY_SIZEOF_PTR_2POW
|
||||
#if defined(_WIN64) || defined(__LP64__)
|
||||
# define SIZEOF_PTR_2POW 3
|
||||
#else
|
||||
# define SIZEOF_PTR_2POW 2
|
||||
#endif
|
||||
|
|
|
@ -42,11 +42,7 @@
|
|||
|
||||
#include "nsNetCID.h"
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
#if !defined(__LP64__)
|
||||
#define BUILD_APPLEFILE_DECODER 1
|
||||
#endif
|
||||
#else
|
||||
#ifndef XP_MACOSX
|
||||
#define BUILD_BINHEX_DECODER 1
|
||||
#endif
|
||||
|
||||
|
@ -143,15 +139,6 @@ net_NewIncrementalDownload(nsISupports *, const nsIID &, void **);
|
|||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "nsStreamConverterService.h"
|
||||
|
||||
#ifdef BUILD_APPLEFILE_DECODER
|
||||
#include "nsAppleFileDecoder.h"
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsAppleFileDecoder)
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "nsMIMEHeaderParamImpl.h"
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsMIMEHeaderParamImpl)
|
||||
|
@ -376,6 +363,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsAndroidNetworkLinkService)
|
|||
nsresult NS_NewFTPDirListingConv(nsFTPDirListingConv** result);
|
||||
#endif
|
||||
|
||||
#include "nsStreamConverterService.h"
|
||||
#include "nsMultiMixedConv.h"
|
||||
#include "nsHTTPCompressConv.h"
|
||||
#include "mozTXTToHTMLConv.h"
|
||||
|
@ -721,9 +709,6 @@ NS_DEFINE_NAMED_CID(NS_MIMEINPUTSTREAM_CID);
|
|||
NS_DEFINE_NAMED_CID(NS_PROTOCOLPROXYSERVICE_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_STREAMCONVERTERSERVICE_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_DASHBOARD_CID);
|
||||
#ifdef BUILD_APPLEFILE_DECODER
|
||||
NS_DEFINE_NAMED_CID(NS_APPLEFILEDECODER_CID);
|
||||
#endif
|
||||
#ifdef NECKO_PROTOCOL_ftp
|
||||
NS_DEFINE_NAMED_CID(NS_FTPDIRLISTINGCONVERTER_CID);
|
||||
#endif
|
||||
|
@ -859,9 +844,6 @@ static const mozilla::Module::CIDEntry kNeckoCIDs[] = {
|
|||
{ &kNS_PROTOCOLPROXYSERVICE_CID, true, nullptr, nsProtocolProxyServiceConstructor },
|
||||
{ &kNS_STREAMCONVERTERSERVICE_CID, false, nullptr, CreateNewStreamConvServiceFactory },
|
||||
{ &kNS_DASHBOARD_CID, false, nullptr, mozilla::net::DashboardConstructor },
|
||||
#ifdef BUILD_APPLEFILE_DECODER
|
||||
{ &kNS_APPLEFILEDECODER_CID, false, nullptr, nsAppleFileDecoderConstructor },
|
||||
#endif
|
||||
#ifdef NECKO_PROTOCOL_ftp
|
||||
{ &kNS_FTPDIRLISTINGCONVERTER_CID, false, nullptr, CreateNewFTPDirListingConv },
|
||||
#endif
|
||||
|
@ -999,9 +981,6 @@ static const mozilla::Module::ContractIDEntry kNeckoContracts[] = {
|
|||
{ NS_PROTOCOLPROXYSERVICE_CONTRACTID, &kNS_PROTOCOLPROXYSERVICE_CID },
|
||||
{ NS_STREAMCONVERTERSERVICE_CONTRACTID, &kNS_STREAMCONVERTERSERVICE_CID },
|
||||
{ NS_DASHBOARD_CONTRACTID, &kNS_DASHBOARD_CID },
|
||||
#ifdef BUILD_APPLEFILE_DECODER
|
||||
{ NS_IAPPLEFILEDECODER_CONTRACTID, &kNS_APPLEFILEDECODER_CID },
|
||||
#endif
|
||||
#ifdef NECKO_PROTOCOL_ftp
|
||||
{ NS_ISTREAMCONVERTER_KEY FTP_TO_INDEX, &kNS_FTPDIRLISTINGCONVERTER_CID },
|
||||
#endif
|
||||
|
|
|
@ -13,11 +13,6 @@ XPIDL_SOURCES += [
|
|||
'nsITXTToHTMLConv.idl',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
XPIDL_SOURCES += [
|
||||
'nsIAppleFileDecoder.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'necko_strconv'
|
||||
|
||||
MODULE = 'necko'
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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 "nsIOutputStream.idl"
|
||||
|
||||
interface nsIFile;
|
||||
|
||||
%{C++
|
||||
#define NS_APPLEFILEDECODER_CID \
|
||||
{ /* 3a2bb281-64b8-11d5-9daa-bb433143c53c */ \
|
||||
0x3a2bb281, \
|
||||
0x64b8, \
|
||||
0x11d5, \
|
||||
{0x9d, 0xaa, 0xbb, 0x43, 0x31, 0x43, 0xc5, 0x3c} \
|
||||
}
|
||||
|
||||
#define NS_IAPPLEFILEDECODER_CONTRACTID "@mozilla.org/applefiledecoder;1"
|
||||
%}
|
||||
|
||||
|
||||
[scriptable, uuid(3a2bb280-64b8-11d5-9daa-bb433143c53c)]
|
||||
interface nsIAppleFileDecoder : nsIOutputStream {
|
||||
|
||||
/**
|
||||
* Initialize the Apple File Decoder Output stream.
|
||||
*
|
||||
* @param outputStream The output stream which the AppleFile Decoder will write to the data fork.
|
||||
* @param outputFile The output file which the AppleFile Decoder will write to the resource fork.
|
||||
*/
|
||||
void Initialize(in nsIOutputStream outputStream, in nsIFile outputFile);
|
||||
};
|
|
@ -12,13 +12,6 @@ CPP_SOURCES += [
|
|||
'nsStreamConverterService.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa' and CONFIG['OS_TEST'] != 'x86_64':
|
||||
# nsAppleFileDecoder.cpp has warnings I don't understand.
|
||||
FAIL_ON_WARNINGS = False
|
||||
CPP_SOURCES += [
|
||||
'nsAppleFileDecoder.cpp',
|
||||
]
|
||||
|
||||
LIBRARY_NAME = 'nkconv_s'
|
||||
|
||||
LIBXUL_LIBRARY = True
|
||||
|
|
|
@ -1,440 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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 "nsAppleFileDecoder.h"
|
||||
#include "prmem.h"
|
||||
#include "prnetdb.h"
|
||||
#include "nsCRT.h"
|
||||
|
||||
|
||||
NS_IMPL_ISUPPORTS2(nsAppleFileDecoder, nsIAppleFileDecoder, nsIOutputStream)
|
||||
|
||||
nsAppleFileDecoder::nsAppleFileDecoder()
|
||||
{
|
||||
m_state = parseHeaders;
|
||||
m_dataBufferLength = 0;
|
||||
m_dataBuffer = (unsigned char*) PR_MALLOC(MAX_BUFFERSIZE);
|
||||
m_entries = nullptr;
|
||||
m_rfRefNum = -1;
|
||||
m_totalDataForkWritten = 0;
|
||||
m_totalResourceForkWritten = 0;
|
||||
m_headerOk = false;
|
||||
|
||||
m_comment[0] = 0;
|
||||
memset(&m_dates, 0, sizeof(m_dates));
|
||||
memset(&m_finderInfo, 0, sizeof(m_dates));
|
||||
memset(&m_finderExtraInfo, 0, sizeof(m_dates));
|
||||
}
|
||||
|
||||
nsAppleFileDecoder::~nsAppleFileDecoder()
|
||||
{
|
||||
if (m_output)
|
||||
Close();
|
||||
|
||||
PR_FREEIF(m_dataBuffer);
|
||||
if (m_entries)
|
||||
delete [] m_entries;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAppleFileDecoder::Initialize(nsIOutputStream *outputStream, nsIFile *outputFile)
|
||||
{
|
||||
m_output = outputStream;
|
||||
|
||||
nsCOMPtr<nsILocalFileMac> macFile = do_QueryInterface(outputFile);
|
||||
bool saveFollowLinks;
|
||||
macFile->GetFollowLinks(&saveFollowLinks);
|
||||
macFile->SetFollowLinks(true);
|
||||
macFile->GetFSSpec(&m_fsFileSpec);
|
||||
macFile->SetFollowLinks(saveFollowLinks);
|
||||
|
||||
m_offset = 0;
|
||||
m_dataForkOffset = 0;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAppleFileDecoder::Close(void)
|
||||
{
|
||||
nsresult rv;
|
||||
rv = m_output->Close();
|
||||
|
||||
int32_t i;
|
||||
|
||||
if (m_rfRefNum != -1)
|
||||
FSClose(m_rfRefNum);
|
||||
|
||||
/* Check if the file is complete and if it's the case, write file attributes */
|
||||
if (m_headerOk)
|
||||
{
|
||||
bool dataOk = true; /* It's ok if the file doesn't have a datafork, therefore set it to true by default. */
|
||||
if (m_headers.magic == APPLESINGLE_MAGIC)
|
||||
{
|
||||
for (i = 0; i < m_headers.entriesCount; i ++)
|
||||
if (ENT_DFORK == m_entries[i].id)
|
||||
{
|
||||
dataOk = (bool)(m_totalDataForkWritten == m_entries[i].length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool resourceOk = FALSE;
|
||||
for (i = 0; i < m_headers.entriesCount; i ++)
|
||||
if (ENT_RFORK == m_entries[i].id)
|
||||
{
|
||||
resourceOk = (bool)(m_totalResourceForkWritten == m_entries[i].length);
|
||||
break;
|
||||
}
|
||||
|
||||
if (dataOk && resourceOk)
|
||||
{
|
||||
HFileInfo *fpb;
|
||||
CInfoPBRec cipbr;
|
||||
|
||||
fpb = (HFileInfo *) &cipbr;
|
||||
fpb->ioVRefNum = m_fsFileSpec.vRefNum;
|
||||
fpb->ioDirID = m_fsFileSpec.parID;
|
||||
fpb->ioNamePtr = m_fsFileSpec.name;
|
||||
fpb->ioFDirIndex = 0;
|
||||
PBGetCatInfoSync(&cipbr);
|
||||
|
||||
/* set finder info */
|
||||
memcpy(&fpb->ioFlFndrInfo, &m_finderInfo, sizeof (FInfo));
|
||||
memcpy(&fpb->ioFlXFndrInfo, &m_finderExtraInfo, sizeof (FXInfo));
|
||||
fpb->ioFlFndrInfo.fdFlags &= 0xfc00; /* clear flags maintained by finder */
|
||||
|
||||
/* set file dates */
|
||||
fpb->ioFlCrDat = m_dates.create - CONVERT_TIME;
|
||||
fpb->ioFlMdDat = m_dates.modify - CONVERT_TIME;
|
||||
fpb->ioFlBkDat = m_dates.backup - CONVERT_TIME;
|
||||
|
||||
/* update file info */
|
||||
fpb->ioDirID = fpb->ioFlParID;
|
||||
PBSetCatInfoSync(&cipbr);
|
||||
|
||||
/* set comment */
|
||||
IOParam vinfo;
|
||||
GetVolParmsInfoBuffer vp;
|
||||
DTPBRec dtp;
|
||||
|
||||
memset((void *) &vinfo, 0, sizeof (vinfo));
|
||||
vinfo.ioVRefNum = fpb->ioVRefNum;
|
||||
vinfo.ioBuffer = (Ptr) &vp;
|
||||
vinfo.ioReqCount = sizeof (vp);
|
||||
if (PBHGetVolParmsSync((HParmBlkPtr) &vinfo) == noErr && ((vp.vMAttrib >> bHasDesktopMgr) & 1))
|
||||
{
|
||||
memset((void *) &dtp, 0, sizeof (dtp));
|
||||
dtp.ioVRefNum = fpb->ioVRefNum;
|
||||
if (PBDTGetPath(&dtp) == noErr)
|
||||
{
|
||||
dtp.ioDTBuffer = (Ptr) &m_comment[1];
|
||||
dtp.ioNamePtr = fpb->ioNamePtr;
|
||||
dtp.ioDirID = fpb->ioDirID;
|
||||
dtp.ioDTReqCount = m_comment[0];
|
||||
if (PBDTSetCommentSync(&dtp) == noErr)
|
||||
PBDTFlushSync(&dtp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* setting m_headerOk to false will prevent us to reprocess the header in case the Close function is called several time*/
|
||||
m_headerOk = false;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAppleFileDecoder::Flush(void)
|
||||
{
|
||||
return m_output->Flush();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAppleFileDecoder::WriteFrom(nsIInputStream *inStr, uint32_t count, uint32_t *_retval)
|
||||
{
|
||||
return m_output->WriteFrom(inStr, count, _retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAppleFileDecoder::WriteSegments(nsReadSegmentFun reader, void * closure, uint32_t count, uint32_t *_retval)
|
||||
{
|
||||
return m_output->WriteSegments(reader, closure, count, _retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAppleFileDecoder::IsNonBlocking(bool *aNonBlocking)
|
||||
{
|
||||
return m_output->IsNonBlocking(aNonBlocking);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAppleFileDecoder::Write(const char *buffer, uint32_t bufferSize, uint32_t* writeCount)
|
||||
{
|
||||
/* WARNING: to simplify my life, I presume that I should get all appledouble headers in the first block,
|
||||
else I would have to implement a buffer */
|
||||
|
||||
const char * buffPtr = buffer;
|
||||
uint32_t dataCount;
|
||||
int32_t i;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
*writeCount = 0;
|
||||
|
||||
while (bufferSize > 0 && NS_SUCCEEDED(rv))
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case parseHeaders :
|
||||
dataCount = sizeof(ap_header) - m_dataBufferLength;
|
||||
if (dataCount > bufferSize)
|
||||
dataCount = bufferSize;
|
||||
memcpy(&m_dataBuffer[m_dataBufferLength], buffPtr, dataCount);
|
||||
m_dataBufferLength += dataCount;
|
||||
|
||||
if (m_dataBufferLength == sizeof(ap_header))
|
||||
{
|
||||
memcpy(&m_headers, m_dataBuffer, sizeof(ap_header));
|
||||
m_headers.magic = (int32_t)PR_ntohl((uint32_t)m_headers.magic);
|
||||
m_headers.version = (int32_t)PR_ntohl((uint32_t)m_headers.version);
|
||||
// m_headers.fill is required to be all zeroes; no endian issues
|
||||
m_headers.entriesCount =
|
||||
(int16_t)PR_ntohs((uint16_t)m_headers.entriesCount);
|
||||
|
||||
/* Check header to be sure we are dealing with the right kind of data, else just write it to the data fork. */
|
||||
if ((m_headers.magic == APPLEDOUBLE_MAGIC || m_headers.magic == APPLESINGLE_MAGIC) &&
|
||||
m_headers.version == VERSION && m_headers.entriesCount)
|
||||
{
|
||||
/* Just to be sure, the filler must contains only 0 */
|
||||
for (i = 0; i < 4 && m_headers.fill[i] == 0L; i ++)
|
||||
;
|
||||
if (i == 4)
|
||||
m_state = parseEntries;
|
||||
}
|
||||
m_dataBufferLength = 0;
|
||||
|
||||
if (m_state == parseHeaders)
|
||||
{
|
||||
dataCount = 0;
|
||||
m_state = parseWriteThrough;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case parseEntries :
|
||||
{
|
||||
if (!m_entries)
|
||||
{
|
||||
m_entries = new ap_entry[m_headers.entriesCount];
|
||||
if (!m_entries)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
uint32_t entriesSize = sizeof(ap_entry) * m_headers.entriesCount;
|
||||
dataCount = entriesSize - m_dataBufferLength;
|
||||
if (dataCount > bufferSize)
|
||||
dataCount = bufferSize;
|
||||
memcpy(&m_dataBuffer[m_dataBufferLength], buffPtr, dataCount);
|
||||
m_dataBufferLength += dataCount;
|
||||
|
||||
if (m_dataBufferLength == entriesSize)
|
||||
{
|
||||
for (i = 0; i < m_headers.entriesCount; i ++)
|
||||
{
|
||||
memcpy(&m_entries[i], &m_dataBuffer[i * sizeof(ap_entry)], sizeof(ap_entry));
|
||||
m_entries[i].id = (int32_t)PR_ntohl((uint32_t)m_entries[i].id);
|
||||
m_entries[i].offset =
|
||||
(int32_t)PR_ntohl((uint32_t)m_entries[i].offset);
|
||||
m_entries[i].length =
|
||||
(int32_t)PR_ntohl((uint32_t)m_entries[i].length);
|
||||
if (m_headers.magic == APPLEDOUBLE_MAGIC)
|
||||
{
|
||||
uint32_t offset = m_entries[i].offset + m_entries[i].length;
|
||||
if (offset > m_dataForkOffset)
|
||||
m_dataForkOffset = offset;
|
||||
}
|
||||
}
|
||||
m_headerOk = true;
|
||||
m_state = parseLookupPart;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case parseLookupPart :
|
||||
/* which part are we parsing? */
|
||||
m_currentPartID = -1;
|
||||
for (i = 0; i < m_headers.entriesCount; i ++)
|
||||
if (m_offset == m_entries[i].offset && m_entries[i].length)
|
||||
{
|
||||
m_currentPartID = m_entries[i].id;
|
||||
m_currentPartLength = m_entries[i].length;
|
||||
m_currentPartCount = 0;
|
||||
|
||||
switch (m_currentPartID)
|
||||
{
|
||||
case ENT_DFORK : m_state = parseDataFork; break;
|
||||
case ENT_RFORK : m_state = parseResourceFork; break;
|
||||
|
||||
case ENT_COMMENT :
|
||||
case ENT_DATES :
|
||||
case ENT_FINFO :
|
||||
m_dataBufferLength = 0;
|
||||
m_state = parsePart;
|
||||
break;
|
||||
|
||||
default : m_state = parseSkipPart; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_currentPartID == -1)
|
||||
{
|
||||
/* maybe is the datafork of an appledouble file? */
|
||||
if (m_offset == m_dataForkOffset)
|
||||
{
|
||||
m_currentPartID = ENT_DFORK;
|
||||
m_currentPartLength = -1;
|
||||
m_currentPartCount = 0;
|
||||
m_state = parseDataFork;
|
||||
}
|
||||
else
|
||||
dataCount = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case parsePart :
|
||||
dataCount = m_currentPartLength - m_dataBufferLength;
|
||||
if (dataCount > bufferSize)
|
||||
dataCount = bufferSize;
|
||||
memcpy(&m_dataBuffer[m_dataBufferLength], buffPtr, dataCount);
|
||||
m_dataBufferLength += dataCount;
|
||||
|
||||
if (m_dataBufferLength == m_currentPartLength)
|
||||
{
|
||||
switch (m_currentPartID)
|
||||
{
|
||||
case ENT_COMMENT :
|
||||
m_comment[0] = m_currentPartLength > 255 ? 255 : m_currentPartLength;
|
||||
memcpy(&m_comment[1], buffPtr, m_comment[0]);
|
||||
break;
|
||||
case ENT_DATES :
|
||||
if (m_currentPartLength == sizeof(m_dates)) {
|
||||
memcpy(&m_dates, buffPtr, m_currentPartLength);
|
||||
m_dates.create = (int32_t)PR_ntohl((uint32_t)m_dates.create);
|
||||
m_dates.modify = (int32_t)PR_ntohl((uint32_t)m_dates.modify);
|
||||
m_dates.backup = (int32_t)PR_ntohl((uint32_t)m_dates.backup);
|
||||
m_dates.access = (int32_t)PR_ntohl((uint32_t)m_dates.access);
|
||||
}
|
||||
break;
|
||||
case ENT_FINFO :
|
||||
if (m_currentPartLength == (sizeof(m_finderInfo) + sizeof(m_finderExtraInfo)))
|
||||
{
|
||||
memcpy(&m_finderInfo, buffPtr, sizeof(m_finderInfo));
|
||||
// OSType (four character codes) are still integers; swap them.
|
||||
m_finderInfo.fdType =
|
||||
(OSType)PR_ntohl((uint32_t)m_finderInfo.fdType);
|
||||
m_finderInfo.fdCreator =
|
||||
(OSType)PR_ntohl((uint32_t)m_finderInfo.fdCreator);
|
||||
m_finderInfo.fdFlags =
|
||||
(UInt16)PR_ntohs((uint16_t)m_finderInfo.fdFlags);
|
||||
m_finderInfo.fdLocation.v =
|
||||
(short)PR_ntohs((uint16_t)m_finderInfo.fdLocation.v);
|
||||
m_finderInfo.fdLocation.h =
|
||||
(short)PR_ntohs((uint16_t)m_finderInfo.fdLocation.h);
|
||||
m_finderInfo.fdFldr =
|
||||
(SInt16)PR_ntohs((uint16_t)m_finderInfo.fdFldr);
|
||||
|
||||
memcpy(&m_finderExtraInfo, buffPtr + sizeof(m_finderInfo), sizeof(m_finderExtraInfo));
|
||||
m_finderExtraInfo.fdIconID =
|
||||
(SInt16)PR_ntohs((uint16_t)m_finderExtraInfo.fdIconID);
|
||||
m_finderExtraInfo.fdReserved[0] =
|
||||
(SInt16)PR_ntohs((uint16_t)m_finderExtraInfo.fdReserved[0]);
|
||||
m_finderExtraInfo.fdReserved[1] =
|
||||
(SInt16)PR_ntohs((uint16_t)m_finderExtraInfo.fdReserved[1]);
|
||||
m_finderExtraInfo.fdReserved[2] =
|
||||
(SInt16)PR_ntohs((uint16_t)m_finderExtraInfo.fdReserved[2]);
|
||||
// fdScript is a byte
|
||||
// fdXFlags is a byte
|
||||
m_finderExtraInfo.fdComment =
|
||||
(SInt16)PR_ntohs((uint16_t)m_finderExtraInfo.fdComment);
|
||||
m_finderExtraInfo.fdPutAway =
|
||||
(SInt32)PR_ntohl((uint32_t)m_finderExtraInfo.fdPutAway);
|
||||
}
|
||||
break;
|
||||
}
|
||||
m_state = parseLookupPart;
|
||||
}
|
||||
break;
|
||||
|
||||
case parseSkipPart :
|
||||
dataCount = m_currentPartLength - m_currentPartCount;
|
||||
if (dataCount > bufferSize)
|
||||
dataCount = bufferSize;
|
||||
else
|
||||
m_state = parseLookupPart;
|
||||
break;
|
||||
|
||||
case parseDataFork :
|
||||
if (m_headers.magic == APPLEDOUBLE_MAGIC)
|
||||
dataCount = bufferSize;
|
||||
else
|
||||
{
|
||||
dataCount = m_currentPartLength - m_currentPartCount;
|
||||
if (dataCount > bufferSize)
|
||||
dataCount = bufferSize;
|
||||
else
|
||||
m_state = parseLookupPart;
|
||||
}
|
||||
|
||||
if (m_output)
|
||||
{
|
||||
uint32_t writeCount;
|
||||
rv = m_output->Write((const char *)buffPtr, dataCount, &writeCount);
|
||||
if (dataCount != writeCount)
|
||||
rv = NS_ERROR_FAILURE;
|
||||
m_totalDataForkWritten += dataCount;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case parseResourceFork :
|
||||
{
|
||||
dataCount = m_currentPartLength - m_currentPartCount;
|
||||
if (dataCount > bufferSize)
|
||||
dataCount = bufferSize;
|
||||
else
|
||||
m_state = parseLookupPart;
|
||||
|
||||
if (m_rfRefNum == -1)
|
||||
{
|
||||
if (noErr != FSpOpenRF(&m_fsFileSpec, fsWrPerm, &m_rfRefNum))
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
long count = dataCount;
|
||||
if (noErr != FSWrite(m_rfRefNum, &count, buffPtr) || count != dataCount)
|
||||
return NS_ERROR_FAILURE;
|
||||
m_totalResourceForkWritten += dataCount;
|
||||
}
|
||||
break;
|
||||
|
||||
case parseWriteThrough :
|
||||
dataCount = bufferSize;
|
||||
if (m_output)
|
||||
{
|
||||
uint32_t writeCount;
|
||||
rv = m_output->Write((const char *)buffPtr, dataCount, &writeCount);
|
||||
if (dataCount != writeCount)
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (dataCount)
|
||||
{
|
||||
*writeCount += dataCount;
|
||||
bufferSize -= dataCount;
|
||||
buffPtr += dataCount;
|
||||
m_currentPartCount += dataCount;
|
||||
m_offset += dataCount;
|
||||
dataCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsAppleFileDecoder_h__
|
||||
#define nsAppleFileDecoder_h__
|
||||
|
||||
#include "nsIAppleFileDecoder.h"
|
||||
#include "nsILocalFileMac.h"
|
||||
|
||||
/*
|
||||
** applefile definitions used
|
||||
*/
|
||||
#if PRAGMA_STRUCT_ALIGN
|
||||
#pragma options align=mac68k
|
||||
#endif
|
||||
|
||||
#define APPLESINGLE_MAGIC 0x00051600L
|
||||
#define APPLEDOUBLE_MAGIC 0x00051607L
|
||||
#define VERSION 0x00020000
|
||||
|
||||
#define NUM_ENTRIES 6
|
||||
|
||||
#define ENT_DFORK 1L
|
||||
#define ENT_RFORK 2L
|
||||
#define ENT_NAME 3L
|
||||
#define ENT_COMMENT 4L
|
||||
#define ENT_DATES 8L
|
||||
#define ENT_FINFO 9L
|
||||
|
||||
#define CONVERT_TIME 1265437696L
|
||||
|
||||
/*
|
||||
** data type used in the header decoder.
|
||||
*/
|
||||
typedef struct ap_header
|
||||
{
|
||||
int32_t magic;
|
||||
int32_t version;
|
||||
int32_t fill[4];
|
||||
int16_t entriesCount;
|
||||
|
||||
} ap_header;
|
||||
|
||||
typedef struct ap_entry
|
||||
{
|
||||
int32_t id;
|
||||
int32_t offset;
|
||||
int32_t length;
|
||||
|
||||
} ap_entry;
|
||||
|
||||
typedef struct ap_dates
|
||||
{
|
||||
int32_t create, modify, backup, access;
|
||||
|
||||
} ap_dates;
|
||||
|
||||
#if PRAGMA_STRUCT_ALIGN
|
||||
#pragma options align=reset
|
||||
#endif
|
||||
|
||||
/*
|
||||
**Error codes
|
||||
*/
|
||||
enum {
|
||||
errADNotEnoughData = -12099,
|
||||
errADNotSupported,
|
||||
errADBadVersion
|
||||
};
|
||||
|
||||
|
||||
class nsAppleFileDecoder : public nsIAppleFileDecoder
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOUTPUTSTREAM
|
||||
NS_DECL_NSIAPPLEFILEDECODER
|
||||
|
||||
nsAppleFileDecoder();
|
||||
virtual ~nsAppleFileDecoder();
|
||||
|
||||
private:
|
||||
#define MAX_BUFFERSIZE 1024
|
||||
enum ParserState {parseHeaders, parseEntries, parseLookupPart, parsePart, parseSkipPart,
|
||||
parseDataFork, parseResourceFork, parseWriteThrough};
|
||||
|
||||
nsCOMPtr<nsIOutputStream> m_output;
|
||||
FSSpec m_fsFileSpec;
|
||||
SInt16 m_rfRefNum;
|
||||
|
||||
unsigned char * m_dataBuffer;
|
||||
int32_t m_dataBufferLength;
|
||||
ParserState m_state;
|
||||
ap_header m_headers;
|
||||
ap_entry * m_entries;
|
||||
int32_t m_offset;
|
||||
int32_t m_dataForkOffset;
|
||||
int32_t m_totalDataForkWritten;
|
||||
int32_t m_totalResourceForkWritten;
|
||||
bool m_headerOk;
|
||||
|
||||
int32_t m_currentPartID;
|
||||
int32_t m_currentPartLength;
|
||||
int32_t m_currentPartCount;
|
||||
|
||||
Str255 m_comment;
|
||||
ap_dates m_dates;
|
||||
FInfo m_finderInfo;
|
||||
FXInfo m_finderExtraInfo;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
test_dirs := \
|
||||
mozbuild/mozbuild/test \
|
||||
mozbuild/mozbuild/test/action \
|
||||
mozbuild/mozbuild/test/backend \
|
||||
mozbuild/mozbuild/test/controller \
|
||||
mozbuild/mozbuild/test/compilation \
|
||||
|
|
|
@ -1,42 +1,49 @@
|
|||
# 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/.
|
||||
|
||||
'''A generic script to add entries to a file
|
||||
if the entry does not already exist.
|
||||
|
||||
Usage: buildlist.py <filename> <entry> [<entry> ...]
|
||||
'''
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
import os
|
||||
from utils import lockFile
|
||||
|
||||
def addEntriesToListFile(listFile, entries):
|
||||
"""Given a file |listFile| containing one entry per line,
|
||||
add each entry in |entries| to the file, unless it is already
|
||||
present."""
|
||||
lock = lockFile(listFile + ".lck")
|
||||
try:
|
||||
if os.path.exists(listFile):
|
||||
f = open(listFile)
|
||||
existing = set(x.strip() for x in f.readlines())
|
||||
f.close()
|
||||
else:
|
||||
existing = set()
|
||||
f = open(listFile, 'a')
|
||||
for e in entries:
|
||||
if e not in existing:
|
||||
f.write("{0}\n".format(e))
|
||||
existing.add(e)
|
||||
f.close()
|
||||
finally:
|
||||
lock = None
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 3:
|
||||
print("Usage: buildlist.py <list file> <entry> [<entry> ...]",
|
||||
file=sys.stderr)
|
||||
sys.exit(1)
|
||||
addEntriesToListFile(sys.argv[1], sys.argv[2:])
|
||||
# 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/.
|
||||
|
||||
'''A generic script to add entries to a file
|
||||
if the entry does not already exist.
|
||||
|
||||
Usage: buildlist.py <filename> <entry> [<entry> ...]
|
||||
'''
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
from mozbuild.util import lock_file
|
||||
|
||||
def addEntriesToListFile(listFile, entries):
|
||||
"""Given a file |listFile| containing one entry per line,
|
||||
add each entry in |entries| to the file, unless it is already
|
||||
present."""
|
||||
lock = lock_file(listFile + ".lck")
|
||||
try:
|
||||
if os.path.exists(listFile):
|
||||
f = open(listFile)
|
||||
existing = set(x.strip() for x in f.readlines())
|
||||
f.close()
|
||||
else:
|
||||
existing = set()
|
||||
f = open(listFile, 'a')
|
||||
for e in entries:
|
||||
if e not in existing:
|
||||
f.write("{0}\n".format(e))
|
||||
existing.add(e)
|
||||
f.close()
|
||||
finally:
|
||||
lock = None
|
||||
|
||||
|
||||
def main(args):
|
||||
if len(args) < 2:
|
||||
print("Usage: buildlist.py <list file> <entry> [<entry> ...]",
|
||||
file=sys.stderr)
|
||||
return 1
|
||||
|
||||
return addEntriesToListFile(args[0], args[1:])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv[1:]))
|
|
@ -1,3 +1,7 @@
|
|||
# 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/.
|
||||
|
||||
import unittest
|
||||
|
||||
import os, sys, os.path, time
|
||||
|
@ -5,7 +9,8 @@ from tempfile import mkdtemp
|
|||
from shutil import rmtree
|
||||
import mozunit
|
||||
|
||||
from buildlist import addEntriesToListFile
|
||||
from mozbuild.action.buildlist import addEntriesToListFile
|
||||
|
||||
|
||||
class TestBuildList(unittest.TestCase):
|
||||
"""
|
|
@ -11,10 +11,13 @@ import copy
|
|||
import errno
|
||||
import hashlib
|
||||
import os
|
||||
import stat
|
||||
import sys
|
||||
import time
|
||||
|
||||
from StringIO import StringIO
|
||||
|
||||
|
||||
if sys.version_info[0] == 3:
|
||||
str_type = str
|
||||
else:
|
||||
|
@ -370,3 +373,120 @@ class HierarchicalStringList(object):
|
|||
if not isinstance(v, str_type):
|
||||
raise ValueError(
|
||||
'Expected a list of strings, not an element of %s' % type(v))
|
||||
|
||||
|
||||
class LockFile(object):
|
||||
"""LockFile is used by the lock_file method to hold the lock.
|
||||
|
||||
This object should not be used directly, but only through
|
||||
the lock_file method below.
|
||||
"""
|
||||
|
||||
def __init__(self, lockfile):
|
||||
self.lockfile = lockfile
|
||||
|
||||
def __del__(self):
|
||||
while True:
|
||||
try:
|
||||
os.remove(self.lockfile)
|
||||
break
|
||||
except OSError as e:
|
||||
if e.errno == errno.EACCES:
|
||||
# Another process probably has the file open, we'll retry.
|
||||
# Just a short sleep since we want to drop the lock ASAP
|
||||
# (but we need to let some other process close the file
|
||||
# first).
|
||||
time.sleep(0.1)
|
||||
else:
|
||||
# Re-raise unknown errors
|
||||
raise
|
||||
|
||||
|
||||
def lock_file(lockfile, max_wait = 600):
|
||||
"""Create and hold a lockfile of the given name, with the given timeout.
|
||||
|
||||
To release the lock, delete the returned object.
|
||||
"""
|
||||
|
||||
# FUTURE This function and object could be written as a context manager.
|
||||
|
||||
while True:
|
||||
try:
|
||||
fd = os.open(lockfile, os.O_EXCL | os.O_RDWR | os.O_CREAT)
|
||||
# We created the lockfile, so we're the owner
|
||||
break
|
||||
except OSError as e:
|
||||
if (e.errno == errno.EEXIST or
|
||||
(sys.platform == "win32" and e.errno == errno.EACCES)):
|
||||
pass
|
||||
else:
|
||||
# Should not occur
|
||||
raise
|
||||
|
||||
try:
|
||||
# The lock file exists, try to stat it to get its age
|
||||
# and read its contents to report the owner PID
|
||||
f = open(lockfile, 'r')
|
||||
s = os.stat(lockfile)
|
||||
except EnvironmentError as e:
|
||||
if e.errno == errno.ENOENT or e.errno == errno.EACCES:
|
||||
# We didn't create the lockfile, so it did exist, but it's
|
||||
# gone now. Just try again
|
||||
continue
|
||||
|
||||
raise Exception('{0} exists but stat() failed: {1}'.format(
|
||||
lockfile, e.strerror))
|
||||
|
||||
# We didn't create the lockfile and it's still there, check
|
||||
# its age
|
||||
now = int(time.time())
|
||||
if now - s[stat.ST_MTIME] > max_wait:
|
||||
pid = f.readline().rstrip()
|
||||
raise Exception('{0} has been locked for more than '
|
||||
'{1} seconds (PID {2})'.format(lockfile, max_wait, pid))
|
||||
|
||||
# It's not been locked too long, wait a while and retry
|
||||
f.close()
|
||||
time.sleep(1)
|
||||
|
||||
# if we get here. we have the lockfile. Convert the os.open file
|
||||
# descriptor into a Python file object and record our PID in it
|
||||
f = os.fdopen(fd, 'w')
|
||||
f.write('{0}\n'.format(os.getpid()))
|
||||
f.close()
|
||||
|
||||
return LockFile(lockfile)
|
||||
|
||||
|
||||
class PushbackIter(object):
|
||||
'''Utility iterator that can deal with pushed back elements.
|
||||
|
||||
This behaves like a regular iterable, just that you can call
|
||||
iter.pushback(item) to get the given item as next item in the
|
||||
iteration.
|
||||
'''
|
||||
def __init__(self, iterable):
|
||||
self.it = iter(iterable)
|
||||
self.pushed_back = []
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __nonzero__(self):
|
||||
if self.pushed_back:
|
||||
return True
|
||||
|
||||
try:
|
||||
self.pushed_back.insert(0, self.it.next())
|
||||
except StopIteration:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def next(self):
|
||||
if self.pushed_back:
|
||||
return self.pushed_back.pop()
|
||||
return self.it.next()
|
||||
|
||||
def pushback(self, item):
|
||||
self.pushed_back.append(item)
|
||||
|
|
|
@ -12,6 +12,8 @@ endif
|
|||
|
||||
default::
|
||||
|
||||
include $(topsrcdir)/config/makefiles/functions.mk
|
||||
|
||||
NSS_LIBS = \
|
||||
nss3 \
|
||||
nssutil3 \
|
||||
|
|
|
@ -60,6 +60,7 @@ user_pref("extensions.installDistroAddons", false);
|
|||
|
||||
user_pref("geo.wifi.uri", "http://%(server)s/tests/dom/tests/mochitest/geolocation/network_geolocation.sjs");
|
||||
user_pref("geo.wifi.testing", true);
|
||||
user_pref("geo.wifi.logging.enabled", true);
|
||||
user_pref("geo.ignore.location_filter", true);
|
||||
|
||||
user_pref("camino.warn_when_closing", false); // Camino-only, harmless to others
|
||||
|
|
|
@ -110,10 +110,8 @@ nsUserInfo::GetDomain(char * *aDomain)
|
|||
return rv;
|
||||
}
|
||||
|
||||
#if defined(HAVE_UNAME_DOMAINNAME_FIELD)
|
||||
#if defined(__linux__)
|
||||
domainname = buf.domainname;
|
||||
#elif defined(HAVE_UNAME_US_DOMAINNAME_FIELD)
|
||||
domainname = buf.__domainname;
|
||||
#endif
|
||||
|
||||
if (domainname && domainname[0]) {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "mozilla/NullPtr.h"
|
||||
|
||||
using std::string;
|
||||
using std::istream;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "mozilla/NullPtr.h"
|
||||
#include "common/linux/http_upload.h"
|
||||
#include "crashreporter.h"
|
||||
#include "crashreporter_gtk_common.h"
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <cctype>
|
||||
|
||||
#include "mozilla/NullPtr.h"
|
||||
#include "crashreporter.h"
|
||||
#include "crashreporter_gtk_common.h"
|
||||
|
||||
|
|
|
@ -70,9 +70,6 @@
|
|||
|
||||
#ifdef XP_MACOSX
|
||||
#include "nsILocalFileMac.h"
|
||||
#ifndef __LP64__
|
||||
#include "nsIAppleFileDecoder.h"
|
||||
#endif
|
||||
#elif defined(XP_OS2)
|
||||
#include "nsILocalFileOS2.h"
|
||||
#endif
|
||||
|
|
|
@ -22,7 +22,7 @@ DEFINES += -DMOZILLA_OFFICIAL
|
|||
endif
|
||||
|
||||
libs:: $(call mkdir_deps,$(FINAL_TARGET))
|
||||
$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/chrome.manifest "resource webapprt ./"
|
||||
$(call py_action,buildlist,$(FINAL_TARGET)/chrome.manifest "resource webapprt ./")
|
||||
|
||||
GRE_MILESTONE := $(shell tail -n 1 $(topsrcdir)/config/milestone.txt 2>/dev/null || tail -1 $(topsrcdir)/config/milestone.txt)
|
||||
GRE_BUILDID := $(shell cat $(DEPTH)/config/buildid)
|
||||
|
|
|
@ -25,6 +25,7 @@ Cu.import("resource://gre/modules/osfile.jsm");
|
|||
// Initialize window-independent handling of webapps- notifications.
|
||||
Cu.import("resource://webapprt/modules/WebappsHandler.jsm");
|
||||
Cu.import("resource://webapprt/modules/WebappRT.jsm");
|
||||
Cu.import("resource://webapprt/modules/WebRTCHandler.jsm");
|
||||
|
||||
const PROFILE_DIR = OS.Constants.Path.profileDir;
|
||||
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = [];
|
||||
|
||||
let Cc = Components.classes;
|
||||
let Ci = Components.interfaces;
|
||||
let Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
function handleRequest(aSubject, aTopic, aData) {
|
||||
let { windowID, callID } = aSubject;
|
||||
let constraints = aSubject.getConstraints();
|
||||
let contentWindow = Services.wm.getOuterWindowWithId(windowID);
|
||||
|
||||
contentWindow.navigator.mozGetUserMediaDevices(
|
||||
constraints,
|
||||
function (devices) {
|
||||
prompt(contentWindow, callID, constraints.audio,
|
||||
constraints.video || constraints.picture,
|
||||
devices);
|
||||
},
|
||||
function (error) {
|
||||
denyRequest(callID, error);
|
||||
});
|
||||
}
|
||||
|
||||
function prompt(aWindow, aCallID, aAudioRequested, aVideoRequested, aDevices) {
|
||||
let audioDevices = [];
|
||||
let videoDevices = [];
|
||||
for (let device of aDevices) {
|
||||
device = device.QueryInterface(Ci.nsIMediaDevice);
|
||||
switch (device.type) {
|
||||
case "audio":
|
||||
if (aAudioRequested) {
|
||||
audioDevices.push(device);
|
||||
}
|
||||
break;
|
||||
|
||||
case "video":
|
||||
if (aVideoRequested) {
|
||||
videoDevices.push(device);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (audioDevices.length == 0 && videoDevices.length == 0) {
|
||||
denyRequest(aCallID);
|
||||
return;
|
||||
}
|
||||
|
||||
let params = {
|
||||
videoDevices: videoDevices,
|
||||
audioDevices: audioDevices,
|
||||
out: null
|
||||
};
|
||||
aWindow.openDialog("chrome://webapprt/content/getUserMediaDialog.xul", "",
|
||||
"chrome, dialog, modal", params).focus();
|
||||
|
||||
if (!params.out) {
|
||||
denyRequest(aCallID);
|
||||
return;
|
||||
}
|
||||
|
||||
let allowedDevices = Cc["@mozilla.org/supports-array;1"].
|
||||
createInstance(Ci.nsISupportsArray);
|
||||
let videoIndex = params.out.video;
|
||||
let audioIndex = params.out.audio;
|
||||
|
||||
if (videoIndex != -1) {
|
||||
allowedDevices.AppendElement(videoDevices[videoIndex]);
|
||||
}
|
||||
|
||||
if (audioIndex != -1) {
|
||||
allowedDevices.AppendElement(audioDevices[audioIndex]);
|
||||
}
|
||||
|
||||
if (allowedDevices.Count()) {
|
||||
Services.obs.notifyObservers(allowedDevices, "getUserMedia:response:allow",
|
||||
aCallID);
|
||||
} else {
|
||||
denyRequest(aCallID);
|
||||
}
|
||||
}
|
||||
|
||||
function denyRequest(aCallID, aError) {
|
||||
let msg = null;
|
||||
if (aError) {
|
||||
msg = Cc["@mozilla.org/supports-string;1"].
|
||||
createInstance(Ci.nsISupportsString);
|
||||
msg.data = aError;
|
||||
}
|
||||
|
||||
Services.obs.notifyObservers(msg, "getUserMedia:response:deny", aCallID);
|
||||
}
|
||||
|
||||
Services.obs.addObserver(handleRequest, "getUserMedia:request", false);
|
|
@ -0,0 +1,38 @@
|
|||
/* 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/. */
|
||||
|
||||
function onOK() {
|
||||
window.arguments[0].out = {
|
||||
video: document.getElementById("video").selectedItem.value,
|
||||
audio: document.getElementById("audio").selectedItem.value
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function onLoad() {
|
||||
let videoDevices = window.arguments[0].videoDevices;
|
||||
if (videoDevices.length) {
|
||||
let videoMenu = document.getElementById("video");
|
||||
for (let i = 0; i < videoDevices.length; i++) {
|
||||
videoMenu.appendItem(videoDevices[i].name, i);
|
||||
}
|
||||
videoMenu.selectedIndex = 1;
|
||||
} else {
|
||||
document.getElementById("videoGroup").hidden = true;
|
||||
}
|
||||
|
||||
let audioDevices = window.arguments[0].audioDevices;
|
||||
if (audioDevices.length) {
|
||||
let audioMenu = document.getElementById("audio");
|
||||
for (let i = 0; i < audioDevices.length; i++) {
|
||||
audioMenu.appendItem(audioDevices[i].name, i);
|
||||
}
|
||||
audioMenu.selectedIndex = 1;
|
||||
} else {
|
||||
document.getElementById("audioGroup").hidden = true;
|
||||
}
|
||||
|
||||
window.sizeToContent();
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
- You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
|
||||
<!DOCTYPE dialog [
|
||||
<!ENTITY % gum-askDTD SYSTEM "chrome://webapprt/locale/getUserMediaDialog.dtd">
|
||||
%gum-askDTD;
|
||||
]>
|
||||
|
||||
<dialog id="getUserMediaDialog" title="&getUserMediaDialog.title;"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
buttons="accept,cancel"
|
||||
buttonlabelaccept="&getUserMediaDialog.buttonlabelaccept;"
|
||||
buttonaccesskeyaccept="&getUserMediaDialog.buttonaccesskeyaccept;"
|
||||
onload="onLoad()"
|
||||
ondialogaccept="return onOK()"
|
||||
buttonlabelcancel="&getUserMediaDialog.buttonlabelcancel;"
|
||||
buttonaccesskeycancel="&getUserMediaDialog.buttonaccesskeycancel;">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://webapprt/content/getUserMediaDialog.js"/>
|
||||
|
||||
<groupbox id="videoGroup" flex="1">
|
||||
<caption label="&getUserMediaDialog.video.label;"/>
|
||||
<menulist id="video">
|
||||
<menupopup>
|
||||
<menuitem label="&getUserMediaDialog.video.noVideo;" value="-1"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
</groupbox>
|
||||
|
||||
<groupbox id="audioGroup" flex="1">
|
||||
<caption label="&getUserMediaDialog.audio.label;"/>
|
||||
<menulist id="audio">
|
||||
<menupopup>
|
||||
<menuitem label="&getUserMediaDialog.audio.noAudio;" value="-1"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
</groupbox>
|
||||
|
||||
</dialog>
|
|
@ -6,6 +6,8 @@ webapprt.jar:
|
|||
% content webapprt %content/
|
||||
* content/webapp.js (content/webapp.js)
|
||||
* content/webapp.xul (content/webapp.xul)
|
||||
content/getUserMediaDialog.xul (content/getUserMediaDialog.xul)
|
||||
content/getUserMediaDialog.js (content/getUserMediaDialog.js)
|
||||
content/mochitest-shared.js (content/mochitest-shared.js)
|
||||
content/mochitest.js (content/mochitest.js)
|
||||
content/mochitest.xul (content/mochitest.xul)
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<!-- 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/. -->
|
||||
|
||||
<!-- LOCALIZATION NOTE: These are localized strings for the getUserMedia dialog
|
||||
- to ask permissions in the webapp runtime. -->
|
||||
|
||||
<!ENTITY getUserMediaDialog.title "Media Sharing">
|
||||
<!ENTITY getUserMediaDialog.buttonlabelaccept "Share">
|
||||
<!ENTITY getUserMediaDialog.buttonaccesskeyaccept "S">
|
||||
<!ENTITY getUserMediaDialog.buttonlabelcancel "Cancel">
|
||||
<!ENTITY getUserMediaDialog.buttonaccesskeycancel "n">
|
||||
|
||||
<!ENTITY getUserMediaDialog.video.label "Select camera">
|
||||
<!ENTITY getUserMediaDialog.video.noVideo "No video">
|
||||
<!ENTITY getUserMediaDialog.audio.label "Select microphone">
|
||||
<!ENTITY getUserMediaDialog.audio.noAudio "No audio">
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче