Merge inbound to m-c.

This commit is contained in:
Ryan VanderMeulen 2013-10-11 15:39:14 -04:00
commit abbd67c311
78 changed files with 2047 additions and 2559 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -30,7 +30,7 @@ WebGLContext::Clear(GLbitfield mask)
}
if (mBoundFramebuffer) {
if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
if (!mBoundFramebuffer->CheckAndInitializeAttachments())
return ErrorInvalidFramebufferOperation("clear: incomplete framebuffer");
gl->fClear(mask);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -48,7 +48,7 @@ WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext *context)
, mInternalFormat(0)
, mInternalFormatForGL(0)
, mHasEverBeenBound(false)
, mInitialized(false)
, mImageDataStatus(WebGLImageDataStatus::NoImageData)
{
SetIsDOMBinding();
mContext->MakeContextCurrent();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -110,3 +110,4 @@ support-files =
[test_waveShaperNoCurve.html]
[test_waveShaperZeroLengthCurve.html]
[test_audioDestinationNode.html]
[test_mozaudiochannel.html]

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -530,6 +530,9 @@ private:
bool mIsANGLE;
};
extern GLLibraryEGL sEGLLibrary;
#define EGL_DISPLAY() sEGLLibrary.Display()
} /* namespace gl */
} /* namespace mozilla */

319
gfx/gl/TextureImageEGL.cpp Normal file
View File

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

86
gfx/gl/TextureImageEGL.h Normal file
View File

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

View File

@ -102,6 +102,7 @@ CPP_SOURCES += [
'SharedSurface.cpp',
'GLLibraryEGL.cpp',
'SharedSurfaceEGL.cpp',
'TextureImageEGL.cpp',
'SharedSurfaceGL.cpp',
'SurfaceFactory.cpp',
'SurfaceStream.cpp',

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -13,11 +13,6 @@ XPIDL_SOURCES += [
'nsITXTToHTMLConv.idl',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
XPIDL_SOURCES += [
'nsIAppleFileDecoder.idl',
]
XPIDL_MODULE = 'necko_strconv'
MODULE = 'necko'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,6 +16,7 @@
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include "mozilla/NullPtr.h"
using std::string;
using std::istream;

View File

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

View File

@ -11,6 +11,7 @@
#include <cctype>
#include "mozilla/NullPtr.h"
#include "crashreporter.h"
#include "crashreporter_gtk_common.h"

View File

@ -70,9 +70,6 @@
#ifdef XP_MACOSX
#include "nsILocalFileMac.h"
#ifndef __LP64__
#include "nsIAppleFileDecoder.h"
#endif
#elif defined(XP_OS2)
#include "nsILocalFileOS2.h"
#endif

View File

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

View File

@ -12,7 +12,7 @@
* implementation of this interface for non-Windows systems, for testing and
* development purposes only.
*/
[scriptable, uuid(fa6750a2-f0fe-411c-af23-1cd6d2fdeceb)]
[scriptable, uuid(25524bde-8b30-4b49-8d67-7070c790aada)]
interface nsIWinMetroUtils : nsISupports
{
/* return constants for the handPreference property */
@ -49,7 +49,7 @@ interface nsIWinMetroUtils : nsISupports
/**
* Displays a native Windows 8 toast.
*/
void showNativeToast(in AString aTitle, in AString aMessage, in AString anImage);
void showNativeToast(in AString aTitle, in AString aMessage, in AString anImage, in AString aCookie);
/**
* Secondary tiles are a Windows 8 specific feature for pinning new tiles

View File

@ -16,8 +16,16 @@ using namespace mozilla;
using namespace ABI::Windows::UI::Notifications;
typedef __FITypedEventHandler_2_Windows__CUI__CNotifications__CToastNotification_IInspectable_t ToastActivationHandler;
typedef __FITypedEventHandler_2_Windows__CUI__CNotifications__CToastNotification_Windows__CUI__CNotifications__CToastDismissedEventArgs ToastDismissHandler;
void
ToastNotificationHandler::DisplayNotification(HSTRING title,
HSTRING msg,
HSTRING imagePath,
const nsAString& aCookie)
{
mCookie = aCookie;
void ToastNotificationHandler::DisplayNotification(HSTRING title, HSTRING msg, HSTRING imagePath) {
ComPtr<IToastNotificationManagerStatics> toastNotificationManagerStatics;
AssertHRESULT(GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_Notifications_ToastNotificationManager).Get(),
toastNotificationManagerStatics.GetAddressOf()));
@ -57,10 +65,15 @@ void ToastNotificationHandler::DisplayNotification(HSTRING title, HSTRING msg, H
EventRegistrationToken activatedToken;
AssertHRESULT(notification->add_Activated(Callback<ToastActivationHandler>(this,
&ToastNotificationHandler::OnActivate).Get(), &activatedToken));
EventRegistrationToken dismissedToken;
AssertHRESULT(notification->add_Dismissed(Callback<ToastDismissHandler>(this,
&ToastNotificationHandler::OnDismiss).Get(), &dismissedToken));
ComPtr<IToastNotifier> notifier;
toastNotificationManagerStatics->CreateToastNotifier(&notifier);
notifier->Show(notification.Get());
MetroUtils::FireObserver("metro_native_toast_shown", mCookie.get());
}
void ToastNotificationHandler::SetNodeValueString(HSTRING inputString, ComPtr<IXmlNode> node, ComPtr<IXmlDocument> xml) {
@ -73,6 +86,14 @@ void ToastNotificationHandler::SetNodeValueString(HSTRING inputString, ComPtr<IX
}
HRESULT ToastNotificationHandler::OnActivate(IToastNotification *notification, IInspectable *inspectable) {
MetroUtils::FireObserver("metro_native_toast_clicked");
MetroUtils::FireObserver("metro_native_toast_clicked", mCookie.get());
return S_OK;
}
HRESULT
ToastNotificationHandler::OnDismiss(IToastNotification *notification,
IToastDismissedEventArgs* aArgs)
{
MetroUtils::FireObserver("metro_native_toast_dismissed", mCookie.get());
return S_OK;
}

View File

@ -8,11 +8,13 @@
#include <windows.ui.notifications.h>
#include <windows.data.xml.dom.h>
#include "mozwrlbase.h"
#include "nsString.h"
using namespace Microsoft::WRL;
class ToastNotificationHandler {
typedef ABI::Windows::UI::Notifications::IToastNotification IToastNotification;
typedef ABI::Windows::UI::Notifications::IToastDismissedEventArgs IToastDismissedEventArgs;
typedef ABI::Windows::Data::Xml::Dom::IXmlNode IXmlNode;
typedef ABI::Windows::Data::Xml::Dom::IXmlDocument IXmlDocument;
@ -21,6 +23,11 @@ class ToastNotificationHandler {
ToastNotificationHandler() {};
~ToastNotificationHandler() {};
void DisplayNotification(HSTRING title, HSTRING msg, HSTRING imagePath);
void DisplayNotification(HSTRING title, HSTRING msg, HSTRING imagePath, const nsAString& aCookie);
HRESULT OnActivate(IToastNotification *notification, IInspectable *inspectable);
HRESULT OnDismiss(IToastNotification *notification,
IToastDismissedEventArgs* aArgs);
private:
nsString mCookie;
};

View File

@ -345,7 +345,8 @@ nsWinMetroUtils::LaunchInDesktop(const nsAString &aPath, const nsAString &aArgum
NS_IMETHODIMP
nsWinMetroUtils::ShowNativeToast(const nsAString &aTitle,
const nsAString &aMessage, const nsAString &anImage)
const nsAString &aMessage, const nsAString &anImage,
const nsAString &aCookie)
{
// Firefox is in the foreground, no need for a notification.
if (::GetActiveWindow() == ::GetForegroundWindow()) {
@ -358,7 +359,7 @@ nsWinMetroUtils::ShowNativeToast(const nsAString &aTitle,
HSTRING title = HStringReference(aTitle.BeginReading()).Get();
HSTRING msg = HStringReference(aMessage.BeginReading()).Get();
HSTRING imagePath = HStringReference(anImage.BeginReading()).Get();
notification_handler->DisplayNotification(title, msg, imagePath);
notification_handler->DisplayNotification(title, msg, imagePath, aCookie);
return NS_OK;
}

View File

@ -251,7 +251,7 @@ static const uint32_t CPU_TYPE = CPU_TYPE_POWERPC64;
#error Unsupported CPU type
#endif
#ifdef HAVE_64BIT_OS
#ifdef __LP64__
#undef LC_SEGMENT
#define LC_SEGMENT LC_SEGMENT_64
#undef MH_MAGIC

View File

@ -6,3 +6,6 @@ export::
$(call SUBMAKE,xpidl-parser,$(DEPTH)/xpcom/idl-parser)
$(call py_action,process_install_manifest,$(DIST)/idl $(DEPTH)/_build_manifests/install/dist_idl)
$(call SUBMAKE,xpidl,$(DEPTH)/config/makefiles/xpidl)
clean clobber realclean clobber_all distclean::
$(call SUBMAKE,$@,$(DEPTH)/config/makefiles/xpidl)