Merge fx-team with mozilla-central

This commit is contained in:
Gavin Sharp 2011-07-08 10:20:52 -04:00
commit 99ab3d837a
199 changed files with 5399 additions and 1120 deletions

View File

@ -595,6 +595,7 @@ var allTabs = {
delete this.tabCloseButton;
return this.tabCloseButton = document.getElementById("allTabs-tab-close-button");
},
get toolbarButton() document.getElementById("alltabs-button"),
get previews () this.container.getElementsByClassName("allTabs-preview"),
get isOpen () this.panel.state == "open" || this.panel.state == "showing",
@ -632,7 +633,7 @@ var allTabs = {
prefName: "browser.allTabs.previews",
readPref: function allTabs_readPref() {
var allTabsButton = document.getElementById("alltabs-button");
var allTabsButton = this.toolbarButton;
if (!allTabsButton)
return;
@ -697,6 +698,17 @@ var allTabs = {
},
open: function allTabs_open() {
var allTabsButton = this.toolbarButton;
if (allTabsButton &&
allTabsButton.getAttribute("type") == "menu") {
// Without setTimeout, the menupopup won't stay open when invoking
// "View > Show All Tabs" and the menu bar auto-hides.
setTimeout(function () {
allTabsButton.open = true;
}, 0);
return;
}
this.init();
if (this.isOpen)

View File

@ -1,5 +1,11 @@
function test() {
waitForExplicitFinish();
Services.prefs.setBoolPref(allTabs.prefName, true);
registerCleanupFunction(function () {
Services.prefs.clearUserPref(allTabs.prefName);
});
allTabs.init();
nextSequence();
}

View File

@ -9,7 +9,7 @@ pref("app.update.interval", 28800);
pref("app.update.download.backgroundInterval", 60);
// URL user can browse to manually if for some reason all update installation
// attempts fail.
pref("app.update.url.manual", "http://nightly.mozilla.org/");
pref("app.update.url.manual", "http://www.mozilla.com/firefox/channel/");
// A default value for the "More information about this update" link
// supplied in the "An update is available" page of the update wizard.
pref("app.update.url.details", "http://www.mozilla.org/projects/%APP%/");

View File

@ -45,6 +45,9 @@
@BINPATH@/@DLL_PREFIX@xpcom@DLL_SUFFIX@
@BINPATH@/@DLL_PREFIX@nspr4@DLL_SUFFIX@
@BINPATH@/@DLL_PREFIX@mozalloc@DLL_SUFFIX@
#ifdef MOZ_MEMORY_DARWIN
@BINPATH@/@DLL_PREFIX@jemalloc@DLL_SUFFIX@
#endif
#ifdef XP_MACOSX
@BINPATH@/XUL
#else

View File

@ -39,6 +39,7 @@ class DeviceManagerADB(DeviceManager):
def mkDir(self, name):
try:
self.checkCmd(["shell", "mkdir", name])
self.chmodDir(name)
return name
except:
return None

View File

@ -91,7 +91,6 @@ if __name__ == '__main__':
t.start()
automation.setServerInfo("localhost", PORT)
automation.initializeProfile(PROFILE_DIRECTORY)
browserEnv = automation.environment()
browserEnv["XPCOM_DEBUG_BREAK"] = "warn"
browserEnv["MOZ_JAR_LOG_DIR"] = MOZ_JAR_LOG_DIR
@ -102,6 +101,7 @@ if __name__ == '__main__':
for i in range(0, num_runs):
if num_runs != 1:
print "Starting profiling run %d of %d" % (i + 1, num_runs)
automation.initializeProfile(PROFILE_DIRECTORY)
status = automation.runApp(url, browserEnv, appPath, PROFILE_DIRECTORY, {},
debuggerInfo=debuggerInfo,
# the profiling HTML doesn't output anything,

View File

@ -59,7 +59,7 @@ public:
NS_DECL_NSIPRINCIPAL
NS_DECL_NSISERIALIZABLE
nsresult Init();
nsresult Init(JSPrincipals **jsprin);
nsSystemPrincipal();

View File

@ -3379,7 +3379,8 @@ nsresult nsScriptSecurityManager::Init()
nsRefPtr<nsSystemPrincipal> system = new nsSystemPrincipal();
NS_ENSURE_TRUE(system, NS_ERROR_OUT_OF_MEMORY);
rv = system->Init();
JSPrincipals *jsprin;
rv = system->Init(&jsprin);
NS_ENSURE_SUCCESS(rv, rv);
mSystemPrincipal = system;
@ -3406,6 +3407,8 @@ nsresult nsScriptSecurityManager::Init()
JS_SetRuntimeSecurityCallbacks(sRuntime, &securityCallbacks);
NS_ASSERTION(!oldcallbacks, "Someone else set security callbacks!");
JS_SetTrustedPrincipals(sRuntime, jsprin);
return NS_OK;
}
@ -3429,6 +3432,7 @@ nsScriptSecurityManager::Shutdown()
{
if (sRuntime) {
JS_SetRuntimeSecurityCallbacks(sRuntime, NULL);
JS_SetTrustedPrincipals(sRuntime, NULL);
sRuntime = nsnull;
}
sEnabledID = JSID_VOID;

View File

@ -314,7 +314,7 @@ nsSystemPrincipal::nsSystemPrincipal()
#define SYSTEM_PRINCIPAL_SPEC "[System Principal]"
nsresult
nsSystemPrincipal::Init()
nsSystemPrincipal::Init(JSPrincipals **jsprin)
{
// Use an nsCString so we only do the allocation once here and then
// share with nsJSPrincipals
@ -324,7 +324,11 @@ nsSystemPrincipal::Init()
return NS_ERROR_OUT_OF_MEMORY;
}
return mJSPrincipals.Init(this, str);
nsresult rv = mJSPrincipals.Init(this, str);
NS_ENSURE_SUCCESS(rv, rv);
*jsprin = &mJSPrincipals;
return NS_OK;
}
nsSystemPrincipal::~nsSystemPrincipal(void)

View File

@ -2053,6 +2053,7 @@ case "$target" in
else
MOZ_OPTIMIZE_FLAGS="-O3 -fno-omit-frame-pointer"
fi
MOZ_MEMORY=1
_PEDANTIC=
CFLAGS="$CFLAGS -fno-common"
CXXFLAGS="$CXXFLAGS -fno-common"
@ -7459,12 +7460,12 @@ else
;;
esac
if test "$OS_ARCH" != "Darwin"; then
if test "$OS_ARCH" != "WINNT"; then
dnl NB: this must be kept in sync with jemalloc.h
AC_DEFINE(HAVE_JEMALLOC_VALLOC)
AC_DEFINE(HAVE_JEMALLOC_POSIX_MEMALIGN)
AC_DEFINE(HAVE_JEMALLOC_MEMALIGN)
fi
AC_DEFINE(HAVE_JEMALLOC_POSIX_MEMALIGN)
AC_DEFINE(HAVE_JEMALLOC_MEMALIGN)
fi # MOZ_MEMORY
AC_SUBST(MOZ_MEMORY)
AC_SUBST(MOZ_MEMORY_LDFLAGS)

View File

@ -424,6 +424,11 @@ nsDOMFile::Initialize(nsISupports* aOwner,
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(exists, NS_ERROR_FILE_NOT_FOUND);
PRBool isDir;
rv = file->IsDirectory(&isDir);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_FALSE(isDir, NS_ERROR_FILE_IS_DIRECTORY);
mFile = file;
return NS_OK;
}

View File

@ -515,7 +515,6 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, PRBool aClone, PRBool aDeep,
nsnull;
nsCOMPtr<nsINode> clone;
PRBool isDeepDocumentClone = PR_FALSE;
if (aClone) {
rv = aNode->Clone(nodeInfo, getter_AddRefs(clone));
NS_ENSURE_SUCCESS(rv, rv);
@ -528,7 +527,6 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, PRBool aClone, PRBool aDeep,
NS_ENSURE_SUCCESS(rv, rv);
}
else if (aDeep && clone->IsNodeOfType(nsINode::eDOCUMENT)) {
isDeepDocumentClone = PR_TRUE;
// After cloning the document itself, we want to clone the children into
// the cloned document (somewhat like cloning and importing them into the
// cloned document).

View File

@ -502,6 +502,7 @@ _TEST_FILES2 = \
somedatas.resource \
somedatas.resource^headers^ \
delayedServerEvents.sjs \
test_bug664916.html \
test_bug666604.html \
$(NULL)

View File

@ -64,9 +64,18 @@ try {
var nonexistentfile = new File("i/sure/hope/this/does/not/exist/anywhere.txt");
ok(false, "This should never be reached!");
} catch (e) {
ok(true, "Attempt to construct a non-existent file should fail.")
ok(true, "Attempt to construct a non-existent file should fail.");
}
try {
var dir = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("CurWorkD", Components.interfaces.nsIFile);
var dirfile = new File(dir);
ok(false, "This should never be reached!");
} catch (e) {
ok(true, "Attempt to construct a file from a directory should fail.");
}
]]>
</script>

View File

@ -0,0 +1,40 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=664916
-->
<head>
<title>Test for Bug 664916</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=664916">Mozilla Bug 664916</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 664916 **/
var div = document.createElement("div");
var textNode = document.createTextNode("x")
var tagNameGetter = div.__lookupGetter__("tagName");
var tagName = "";
try {
tagName = tagNameGetter.call(textNode);
ok(false, "Should throw when calling tagname getter on text node");
} catch(e) {
ok(true, "Should throw when calling tagname getter on text node");
}
is(tagName, "", "Should not have changed tagName yet");
tagName = tagNameGetter.call(div);
is(tagName, "DIV", "Should get the right tag name");
</script>
</pre>
</body>
</html>

View File

@ -40,7 +40,6 @@
#include "WebGLContext.h"
#include "nsIConsoleService.h"
#include "nsIPrefService.h"
#include "nsServiceManagerUtils.h"
#include "nsIClassInfoImpl.h"
#include "nsContentUtils.h"
@ -68,10 +67,140 @@
#include "prenv.h"
#include "mozilla/Preferences.h"
using namespace mozilla;
using namespace mozilla::gl;
using namespace mozilla::layers;
WebGLMemoryReporter* WebGLMemoryReporter::sUniqueInstance = nsnull;
NS_MEMORY_REPORTER_IMPLEMENT(WebGLTextureMemoryUsed,
"webgl-texture-memory",
KIND_OTHER,
UNITS_BYTES,
WebGLMemoryReporter::GetTextureMemoryUsed,
"Memory used by WebGL textures. The OpenGL implementation is free to store these textures in either video memory or main memory. This measurement is only a lower bound, actual memory usage may be higher for example if the storage is strided.")
NS_MEMORY_REPORTER_IMPLEMENT(WebGLTextureCount,
"webgl-texture-count",
KIND_OTHER,
UNITS_COUNT,
WebGLMemoryReporter::GetTextureCount,
"Number of WebGL textures.")
NS_MEMORY_REPORTER_IMPLEMENT(WebGLBufferMemoryUsed,
"webgl-buffer-memory",
KIND_OTHER,
UNITS_BYTES,
WebGLMemoryReporter::GetBufferMemoryUsed,
"Memory used by WebGL buffers. The OpenGL implementation is free to store these buffers in either video memory or main memory. This measurement is only a lower bound, actual memory usage may be higher for example if the storage is strided.")
NS_MEMORY_REPORTER_IMPLEMENT(WebGLBufferCacheMemoryUsed,
"webgl-buffer-cache-memory",
KIND_HEAP,
UNITS_BYTES,
WebGLMemoryReporter::GetBufferCacheMemoryUsed,
"Memory used by WebGL buffer caches. The WebGL implementation caches the contents of element array buffers only. This adds up with the webgl-buffer-memory value, but contrary to it, this one represents bytes on the heap, not managed by OpenGL.")
NS_MEMORY_REPORTER_IMPLEMENT(WebGLBufferCount,
"webgl-buffer-count",
KIND_OTHER,
UNITS_COUNT,
WebGLMemoryReporter::GetBufferCount,
"Number of WebGL buffers.")
NS_MEMORY_REPORTER_IMPLEMENT(WebGLRenderbufferMemoryUsed,
"webgl-renderbuffer-memory",
KIND_OTHER,
UNITS_BYTES,
WebGLMemoryReporter::GetRenderbufferMemoryUsed,
"Memory used by WebGL renderbuffers. The OpenGL implementation is free to store these renderbuffers in either video memory or main memory. This measurement is only a lower bound, actual memory usage may be higher for example if the storage is strided.")
NS_MEMORY_REPORTER_IMPLEMENT(WebGLRenderbufferCount,
"webgl-renderbuffer-count",
KIND_OTHER,
UNITS_COUNT,
WebGLMemoryReporter::GetRenderbufferCount,
"Number of WebGL renderbuffers.")
NS_MEMORY_REPORTER_IMPLEMENT(WebGLShaderSourcesSize,
"webgl-shader-sources-size",
KIND_HEAP,
UNITS_BYTES,
WebGLMemoryReporter::GetShaderSourcesSize,
"Combined size of WebGL shader ASCII sources, cached on the heap. This should always be at most a few kilobytes, or dozen kilobytes for very shader-intensive WebGL demos.")
NS_MEMORY_REPORTER_IMPLEMENT(WebGLShaderTranslationLogsSize,
"webgl-shader-translationlogs-size",
KIND_HEAP,
UNITS_BYTES,
WebGLMemoryReporter::GetShaderTranslationLogsSize,
"Combined size of WebGL shader ASCII translation logs, cached on the heap.")
NS_MEMORY_REPORTER_IMPLEMENT(WebGLShaderCount,
"webgl-shader-count",
KIND_OTHER,
UNITS_COUNT,
WebGLMemoryReporter::GetShaderCount,
"Number of WebGL shaders.")
NS_MEMORY_REPORTER_IMPLEMENT(WebGLContextCount,
"webgl-context-count",
KIND_OTHER,
UNITS_COUNT,
WebGLMemoryReporter::GetContextCount,
"Number of WebGL contexts.")
WebGLMemoryReporter* WebGLMemoryReporter::UniqueInstance()
{
if (!sUniqueInstance) {
sUniqueInstance = new WebGLMemoryReporter;
}
return sUniqueInstance;
}
WebGLMemoryReporter::WebGLMemoryReporter()
: mTextureMemoryUsageReporter(new NS_MEMORY_REPORTER_NAME(WebGLTextureMemoryUsed))
, mTextureCountReporter(new NS_MEMORY_REPORTER_NAME(WebGLTextureCount))
, mBufferMemoryUsageReporter(new NS_MEMORY_REPORTER_NAME(WebGLBufferMemoryUsed))
, mBufferCacheMemoryUsageReporter(new NS_MEMORY_REPORTER_NAME(WebGLBufferCacheMemoryUsed))
, mBufferCountReporter(new NS_MEMORY_REPORTER_NAME(WebGLBufferCount))
, mRenderbufferMemoryUsageReporter(new NS_MEMORY_REPORTER_NAME(WebGLRenderbufferMemoryUsed))
, mRenderbufferCountReporter(new NS_MEMORY_REPORTER_NAME(WebGLRenderbufferCount))
, mShaderSourcesSizeReporter(new NS_MEMORY_REPORTER_NAME(WebGLShaderSourcesSize))
, mShaderTranslationLogsSizeReporter(new NS_MEMORY_REPORTER_NAME(WebGLShaderTranslationLogsSize))
, mShaderCountReporter(new NS_MEMORY_REPORTER_NAME(WebGLShaderCount))
, mContextCountReporter(new NS_MEMORY_REPORTER_NAME(WebGLContextCount))
{
NS_RegisterMemoryReporter(mTextureMemoryUsageReporter);
NS_RegisterMemoryReporter(mTextureCountReporter);
NS_RegisterMemoryReporter(mBufferMemoryUsageReporter);
NS_RegisterMemoryReporter(mBufferCacheMemoryUsageReporter);
NS_RegisterMemoryReporter(mBufferCountReporter);
NS_RegisterMemoryReporter(mRenderbufferMemoryUsageReporter);
NS_RegisterMemoryReporter(mRenderbufferCountReporter);
NS_RegisterMemoryReporter(mShaderSourcesSizeReporter);
NS_RegisterMemoryReporter(mShaderTranslationLogsSizeReporter);
NS_RegisterMemoryReporter(mShaderCountReporter);
NS_RegisterMemoryReporter(mContextCountReporter);
}
WebGLMemoryReporter::~WebGLMemoryReporter()
{
NS_UnregisterMemoryReporter(mTextureMemoryUsageReporter);
NS_UnregisterMemoryReporter(mTextureCountReporter);
NS_UnregisterMemoryReporter(mBufferMemoryUsageReporter);
NS_UnregisterMemoryReporter(mBufferCacheMemoryUsageReporter);
NS_UnregisterMemoryReporter(mBufferCountReporter);
NS_UnregisterMemoryReporter(mRenderbufferMemoryUsageReporter);
NS_UnregisterMemoryReporter(mRenderbufferCountReporter);
NS_UnregisterMemoryReporter(mShaderSourcesSizeReporter);
NS_UnregisterMemoryReporter(mShaderTranslationLogsSizeReporter);
NS_UnregisterMemoryReporter(mShaderCountReporter);
NS_UnregisterMemoryReporter(mContextCountReporter);
}
nsresult NS_NewCanvasRenderingContextWebGL(nsIDOMWebGLRenderingContext** aResult);
nsresult
@ -97,7 +226,7 @@ WebGLContext::WebGLContext()
mOptionsFrozen = PR_FALSE;
mActiveTexture = 0;
mSynthesizedGLError = LOCAL_GL_NO_ERROR;
mWebGLError = LOCAL_GL_NO_ERROR;
mPixelStoreFlipY = PR_FALSE;
mPixelStorePremultiplyAlpha = PR_FALSE;
mPixelStoreColorspaceConversion = BROWSER_DEFAULT_WEBGL;
@ -164,11 +293,14 @@ WebGLContext::WebGLContext()
// See OpenGL ES 2.0.25 spec, 6.2 State Tables, table 6.13
mPixelStorePackAlignment = 4;
mPixelStoreUnpackAlignment = 4;
WebGLMemoryReporter::AddWebGLContext(this);
}
WebGLContext::~WebGLContext()
{
DestroyResourcesAndContext();
WebGLMemoryReporter::RemoveWebGLContext(this);
}
static PLDHashOperator
@ -413,22 +545,20 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
DestroyResourcesAndContext();
// Get some prefs for some preferred/overriden things
nsCOMPtr<nsIPrefBranch> prefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
NS_ENSURE_TRUE(prefService != nsnull, NS_ERROR_FAILURE);
NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE);
PRBool forceOSMesa = PR_FALSE;
PRBool preferEGL = PR_FALSE;
PRBool preferOpenGL = PR_FALSE;
PRBool forceEnabled = PR_FALSE;
PRBool disabled = PR_FALSE;
PRBool verbose = PR_FALSE;
prefService->GetBoolPref("webgl.force_osmesa", &forceOSMesa);
prefService->GetBoolPref("webgl.prefer-egl", &preferEGL);
prefService->GetBoolPref("webgl.prefer-native-gl", &preferOpenGL);
prefService->GetBoolPref("webgl.force-enabled", &forceEnabled);
prefService->GetBoolPref("webgl.disabled", &disabled);
prefService->GetBoolPref("webgl.verbose", &verbose);
PRBool forceOSMesa =
Preferences::GetBool("webgl.force_osmesa", PR_FALSE);
PRBool preferEGL =
Preferences::GetBool("webgl.prefer-egl", PR_FALSE);
PRBool preferOpenGL =
Preferences::GetBool("webgl.prefer-native-gl", PR_FALSE);
PRBool forceEnabled =
Preferences::GetBool("webgl.force-enabled", PR_FALSE);
PRBool disabled =
Preferences::GetBool("webgl.disabled", PR_FALSE);
PRBool verbose =
Preferences::GetBool("webgl.verbose", PR_FALSE);
if (disabled)
return NS_ERROR_FAILURE;

View File

@ -56,6 +56,7 @@
#include "nsWeakReference.h"
#include "nsIDOMHTMLElement.h"
#include "nsIJSNativeInitializer.h"
#include "nsIMemoryReporter.h"
#include "GLContextProvider.h"
#include "Layers.h"
@ -320,6 +321,8 @@ class WebGLContext :
public nsICanvasRenderingContextInternal,
public nsSupportsWeakReference
{
friend class WebGLMemoryReporter;
public:
WebGLContext();
virtual ~WebGLContext();
@ -367,6 +370,8 @@ public:
return ErrorInvalidEnum("%s: invalid enum value 0x%x", info, enumvalue);
}
nsresult ErrorOutOfMemory(const char *fmt = 0, ...);
const char *ErrorName(GLenum error);
WebGLTexture *activeBoundTextureForTarget(WebGLenum target) {
return target == LOCAL_GL_TEXTURE_2D ? mBound2DTextures[mActiveTexture]
@ -392,6 +397,23 @@ public:
// See section 2.2 in the WebGL spec.
void EnsureBackbufferClearedAsNeeded();
// checks for GL errors, clears any pending GL error, stores the current GL error in currentGLError,
// and copies it into mWebGLError if it doesn't already have an error set
void UpdateWebGLErrorAndClearGLError(GLenum *currentGLError) {
// get and clear GL error in ALL cases
*currentGLError = gl->GetAndClearError();
// only store in mWebGLError if is hasn't already recorded an error
if (!mWebGLError)
mWebGLError = *currentGLError;
}
// checks for GL errors, clears any pending GL error,
// and stores the current GL error into mWebGLError if it doesn't already have an error set
void UpdateWebGLErrorAndClearGLError() {
GLenum currentGLError;
UpdateWebGLErrorAndClearGLError(&currentGLError);
}
protected:
void SetDontKnowIfNeedFakeBlack() {
mFakeBlackStatus = DontKnowIfNeedFakeBlack;
@ -424,7 +446,7 @@ protected:
PRPackedBool mOptionsFrozen;
WebGLuint mActiveTexture;
WebGLenum mSynthesizedGLError;
WebGLenum mWebGLError;
// whether shader validation is supported
PRBool mShaderValidation;
@ -468,6 +490,8 @@ protected:
PRBool ValidateDrawModeEnum(WebGLenum mode, const char *info);
PRBool ValidateAttribIndex(WebGLuint index, const char *info);
PRBool ValidateStencilParamsForDrawCall();
static PRUint32 GetTexelSize(WebGLenum format, WebGLenum type);
void Invalidate();
void DestroyResourcesAndContext();
@ -548,6 +572,24 @@ protected:
PRInt32 MaxTextureSizeForTarget(WebGLenum target) const {
return target == LOCAL_GL_TEXTURE_2D ? mGLMaxTextureSize : mGLMaxCubeMapTextureSize;
}
/** like glBufferData but if the call may change the buffer size, checks any GL error generated
* by this glBufferData call and returns it */
GLenum CheckedBufferData(GLenum target,
GLsizeiptr size,
const GLvoid *data,
GLenum usage);
/** like glTexImage2D but if the call may change the texture size, checks any GL error generated
* by this glTexImage2D call and returns it */
GLenum CheckedTexImage2D(GLenum target,
GLint level,
GLenum internalFormat,
GLsizei width,
GLsizei height,
GLint border,
GLenum format,
GLenum type,
const GLvoid *data);
// the buffers bound to the current program's attribs
nsTArray<WebGLVertexAttribData> mAttribBuffers;
@ -659,10 +701,10 @@ protected:
: mWidth(0), mHeight(0) { }
public:
WebGLsizei width() { return mWidth; }
WebGLsizei width() const { return mWidth; }
void width(WebGLsizei value) { mWidth = value; }
WebGLsizei height() { return mHeight; }
WebGLsizei height() const { return mHeight; }
void height(WebGLsizei value) { mHeight = value; }
void setDimensions(WebGLsizei width, WebGLsizei height) {
@ -680,6 +722,10 @@ public:
}
}
bool HasSameDimensionsAs(const WebGLRectangleObject& other) const {
return width() == other.width() && height() == other.height();
}
protected:
WebGLsizei mWidth;
WebGLsizei mHeight;
@ -720,7 +766,7 @@ public:
WebGLContextBoundObject(context),
mName(name), mDeleted(PR_FALSE), mHasEverBeenBound(PR_FALSE),
mByteLength(0), mTarget(LOCAL_GL_NONE), mData(nsnull)
{ }
{}
~WebGLBuffer() {
Delete();
@ -843,7 +889,6 @@ NS_DEFINE_STATIC_IID_ACCESSOR(WebGLBuffer, WEBGLBUFFER_PRIVATE_IID)
class WebGLTexture :
public nsIWebGLTexture,
public WebGLZeroingObject,
public WebGLRectangleObject,
public WebGLContextBoundObject
{
public:
@ -890,8 +935,14 @@ protected:
// we store information about the various images that are part of
// this texture (cubemap faces, mipmap levels)
public:
struct ImageInfo {
ImageInfo() : mWidth(0), mHeight(0), mFormat(0), mType(0), mIsDefined(PR_FALSE) {}
ImageInfo(WebGLsizei width, WebGLsizei height,
WebGLenum format, WebGLenum type)
: mWidth(width), mHeight(height), mFormat(format), mType(type), mIsDefined(PR_TRUE) {}
PRBool operator==(const ImageInfo& a) const {
return mWidth == a.mWidth && mHeight == a.mHeight &&
mFormat == a.mFormat && mType == a.mType;
@ -909,13 +960,17 @@ protected:
return is_pot_assuming_nonnegative(mWidth) &&
is_pot_assuming_nonnegative(mHeight); // negative sizes should never happen (caught in texImage2D...)
}
PRInt64 MemoryUsage() const {
if (!mIsDefined)
return 0;
PRInt64 texelSize = WebGLContext::GetTexelSize(mFormat, mType);
return PRInt64(mWidth) * PRInt64(mHeight) * texelSize;
}
WebGLsizei mWidth, mHeight;
WebGLenum mFormat, mType;
PRBool mIsDefined;
};
public:
ImageInfo& ImageInfoAt(size_t level, size_t face = 0) {
#ifdef DEBUG
if (face >= mFacesCount)
@ -939,6 +994,22 @@ public:
return target == LOCAL_GL_TEXTURE_2D ? 0 : target - LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
}
PRInt64 MemoryUsage() const {
PRInt64 result = 0;
for(size_t face = 0; face < mFacesCount; face++) {
if (mHaveGeneratedMipmap) {
// Each mipmap level is 1/4 the size of the previous level
// 1 + x + x^2 + ... = 1/(1-x)
// for x = 1/4, we get 1/(1-1/4) = 4/3
result += ImageInfoAt(0, face).MemoryUsage() * 4 / 3;
} else {
for(size_t level = 0; level <= mMaxLevelWithCustomImages; level++)
result += ImageInfoAt(level, face).MemoryUsage();
}
}
return result;
}
protected:
WebGLenum mTarget;
@ -1035,7 +1106,7 @@ public:
void SetImageInfo(WebGLenum aTarget, WebGLint aLevel,
WebGLsizei aWidth, WebGLsizei aHeight,
WebGLenum aFormat = 0, WebGLenum aType = 0)
WebGLenum aFormat, WebGLenum aType)
{
if ( (aTarget == LOCAL_GL_TEXTURE_2D) != (mTarget == LOCAL_GL_TEXTURE_2D) )
return;
@ -1044,14 +1115,7 @@ public:
EnsureMaxLevelWithCustomImagesAtLeast(aLevel);
ImageInfo& imageInfo = ImageInfoAt(aLevel, face);
imageInfo.mWidth = aWidth;
imageInfo.mHeight = aHeight;
if (aFormat)
imageInfo.mFormat = aFormat;
if (aType)
imageInfo.mType = aType;
imageInfo.mIsDefined = PR_TRUE;
ImageInfoAt(aLevel, face) = ImageInfo(aWidth, aHeight, aFormat, aType);
if (aLevel > 0)
SetCustomMipmap();
@ -1466,6 +1530,7 @@ public:
WebGLContextBoundObject(context),
mName(name),
mInternalFormat(0),
mInternalFormatForGL(0),
mDeleted(PR_FALSE), mHasEverBeenBound(PR_FALSE), mInitialized(PR_FALSE)
{ }
@ -1485,6 +1550,32 @@ public:
WebGLenum InternalFormat() const { return mInternalFormat; }
void SetInternalFormat(WebGLenum aInternalFormat) { mInternalFormat = aInternalFormat; }
WebGLenum InternalFormatForGL() const { return mInternalFormatForGL; }
void SetInternalFormatForGL(WebGLenum aInternalFormatForGL) { mInternalFormatForGL = aInternalFormatForGL; }
PRInt64 MemoryUsage() const {
PRInt64 pixels = PRInt64(width()) * PRInt64(height());
switch (mInternalFormatForGL) {
case LOCAL_GL_STENCIL_INDEX8:
return pixels;
case LOCAL_GL_RGBA4:
case LOCAL_GL_RGB5_A1:
case LOCAL_GL_RGB565:
case LOCAL_GL_DEPTH_COMPONENT16:
return 2 * pixels;
case LOCAL_GL_RGB8:
case LOCAL_GL_DEPTH_COMPONENT24:
return 3*pixels;
case LOCAL_GL_RGBA8:
case LOCAL_GL_DEPTH24_STENCIL8:
return 4*pixels;
default:
break;
}
NS_ABORT();
return 0;
}
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBGLRENDERBUFFER
@ -1492,6 +1583,7 @@ public:
protected:
WebGLuint mName;
WebGLenum mInternalFormat;
WebGLenum mInternalFormatForGL;
PRBool mDeleted;
PRBool mHasEverBeenBound;
@ -1503,6 +1595,7 @@ protected:
NS_DEFINE_STATIC_IID_ACCESSOR(WebGLRenderbuffer, WEBGLRENDERBUFFER_PRIVATE_IID)
class WebGLFramebufferAttachment
: public WebGLRectangleObject
{
// deleting a texture or renderbuffer immediately detaches it
WebGLObjectRefPtr<WebGLTexture> mTexturePtr;
@ -1538,10 +1631,17 @@ public:
mRenderbufferPtr = nsnull;
mTextureLevel = level;
mTextureCubeMapFace = face;
if (tex) {
const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(level, face);
setDimensions(imageInfo.mWidth, imageInfo.mHeight);
} else {
setDimensions(0, 0);
}
}
void SetRenderbuffer(WebGLRenderbuffer *rb) {
mTexturePtr = nsnull;
mRenderbufferPtr = rb;
setDimensions(rb);
}
WebGLTexture *Texture() const {
return mTexturePtr.get();
@ -1591,7 +1691,6 @@ public:
class WebGLFramebuffer :
public nsIWebGLFramebuffer,
public WebGLZeroingObject,
public WebGLRectangleObject,
public WebGLContextBoundObject
{
public:
@ -1616,6 +1715,9 @@ public:
PRBool HasEverBeenBound() { return mHasEverBeenBound; }
void SetHasEverBeenBound(PRBool x) { mHasEverBeenBound = x; }
WebGLuint GLName() { return mName; }
WebGLsizei width() { return mColorAttachment.width(); }
WebGLsizei height() { return mColorAttachment.height(); }
nsresult FramebufferRenderbuffer(WebGLenum target,
WebGLenum attachment,
@ -1652,11 +1754,7 @@ public:
// finish checking that the 'attachment' parameter is among the allowed values
if (attachment != LOCAL_GL_COLOR_ATTACHMENT0)
return mContext->ErrorInvalidEnumInfo("framebufferRenderbuffer: attachment", attachment);
if (!isNull) {
// ReadPixels needs alpha and size information, but only
// for COLOR_ATTACHMENT0
setDimensions(wrb);
}
mColorAttachment.SetRenderbuffer(wrb);
break;
}
@ -1691,15 +1789,15 @@ public:
if (target != LOCAL_GL_FRAMEBUFFER)
return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: target", target);
if (!isNull && textarget != LOCAL_GL_TEXTURE_2D &&
if (textarget != LOCAL_GL_TEXTURE_2D &&
(textarget < LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X ||
textarget > LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))
textarget > LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))
return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: invalid texture target", textarget);
if (!isNull && level > 0)
if (level != 0)
return mContext->ErrorInvalidValue("framebufferTexture2D: level must be 0");
WebGLint face = (textarget == LOCAL_GL_TEXTURE_2D) ? 0 : textarget;
size_t face = WebGLTexture::FaceForTarget(textarget);
switch (attachment) {
case LOCAL_GL_DEPTH_ATTACHMENT:
mDepthAttachment.SetTexture(wtex, level, face);
@ -1714,9 +1812,6 @@ public:
if (attachment != LOCAL_GL_COLOR_ATTACHMENT0)
return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: attachment", attachment);
// keep data for readPixels, function only uses COLOR_ATTACHMENT0
setDimensions(wtex);
mColorAttachment.SetTexture(wtex, level, face);
break;
}
@ -1759,13 +1854,22 @@ public:
// some attachment is incompatible with its attachment point
return PR_TRUE;
}
else if (int(mDepthAttachment.IsNull()) +
int(mStencilAttachment.IsNull()) +
int(mDepthStencilAttachment.IsNull()) <= 1)
if (int(mDepthAttachment.IsNull()) +
int(mStencilAttachment.IsNull()) +
int(mDepthStencilAttachment.IsNull()) <= 1)
{
// has at least two among Depth, Stencil, DepthStencil
return PR_TRUE;
}
if (!mDepthAttachment.IsNull() && !mDepthAttachment.HasSameDimensionsAs(mColorAttachment))
return PR_TRUE;
if (!mStencilAttachment.IsNull() && !mStencilAttachment.HasSameDimensionsAs(mColorAttachment))
return PR_TRUE;
if (!mDepthStencilAttachment.IsNull() && !mDepthStencilAttachment.HasSameDimensionsAs(mColorAttachment))
return PR_TRUE;
else return PR_FALSE;
}
@ -2066,6 +2170,199 @@ WebGLContext::CanGetConcreteObject(const char *info,
return GetConcreteObject(info, aInterface, &aConcreteObject, isNull, isDeleted, PR_FALSE);
}
class WebGLMemoryReporter
{
WebGLMemoryReporter();
~WebGLMemoryReporter();
static WebGLMemoryReporter* sUniqueInstance;
// here we store plain pointers, not RefPtrs: we don't want the WebGLMemoryReporter unique instance to keep alive all
// WebGLContexts ever created.
typedef nsTArray<const WebGLContext*> ContextsArrayType;
ContextsArrayType mContexts;
nsIMemoryReporter *mTextureMemoryUsageReporter;
nsIMemoryReporter *mTextureCountReporter;
nsIMemoryReporter *mBufferMemoryUsageReporter;
nsIMemoryReporter *mBufferCacheMemoryUsageReporter;
nsIMemoryReporter *mBufferCountReporter;
nsIMemoryReporter *mRenderbufferMemoryUsageReporter;
nsIMemoryReporter *mRenderbufferCountReporter;
nsIMemoryReporter *mShaderSourcesSizeReporter;
nsIMemoryReporter *mShaderTranslationLogsSizeReporter;
nsIMemoryReporter *mShaderCountReporter;
nsIMemoryReporter *mContextCountReporter;
static WebGLMemoryReporter* UniqueInstance();
static ContextsArrayType & Contexts() { return UniqueInstance()->mContexts; }
public:
static void AddWebGLContext(const WebGLContext* c) {
Contexts().AppendElement(c);
}
static void RemoveWebGLContext(const WebGLContext* c) {
ContextsArrayType & contexts = Contexts();
contexts.RemoveElement(c);
if (contexts.IsEmpty()) {
delete sUniqueInstance;
sUniqueInstance = nsnull;
}
}
static PLDHashOperator TextureMemoryUsageFunction(const PRUint32&, WebGLTexture *aValue, void *aData)
{
PRInt64 *result = (PRInt64*) aData;
*result += aValue->MemoryUsage();
return PL_DHASH_NEXT;
}
static PRInt64 GetTextureMemoryUsed() {
const ContextsArrayType & contexts = Contexts();
PRInt64 result = 0;
for(size_t i = 0; i < contexts.Length(); ++i) {
PRInt64 textureMemoryUsageForThisContext = 0;
contexts[i]->mMapTextures.EnumerateRead(TextureMemoryUsageFunction, &textureMemoryUsageForThisContext);
result += textureMemoryUsageForThisContext;
}
return result;
}
static PRInt64 GetTextureCount() {
const ContextsArrayType & contexts = Contexts();
PRInt64 result = 0;
for(size_t i = 0; i < contexts.Length(); ++i) {
result += contexts[i]->mMapTextures.Count();
}
return result;
}
static PLDHashOperator BufferMemoryUsageFunction(const PRUint32&, WebGLBuffer *aValue, void *aData)
{
PRInt64 *result = (PRInt64*) aData;
*result += aValue->ByteLength();
return PL_DHASH_NEXT;
}
static PRInt64 GetBufferMemoryUsed() {
const ContextsArrayType & contexts = Contexts();
PRInt64 result = 0;
for(size_t i = 0; i < contexts.Length(); ++i) {
PRInt64 bufferMemoryUsageForThisContext = 0;
contexts[i]->mMapBuffers.EnumerateRead(BufferMemoryUsageFunction, &bufferMemoryUsageForThisContext);
result += bufferMemoryUsageForThisContext;
}
return result;
}
static PLDHashOperator BufferCacheMemoryUsageFunction(const PRUint32&, WebGLBuffer *aValue, void *aData)
{
PRInt64 *result = (PRInt64*) aData;
// element array buffers are cached in the WebGL implementation. Other buffers aren't.
if (aValue->Target() == LOCAL_GL_ELEMENT_ARRAY_BUFFER)
*result += aValue->ByteLength();
return PL_DHASH_NEXT;
}
static PRInt64 GetBufferCacheMemoryUsed() {
const ContextsArrayType & contexts = Contexts();
PRInt64 result = 0;
for(size_t i = 0; i < contexts.Length(); ++i) {
PRInt64 bufferCacheMemoryUsageForThisContext = 0;
contexts[i]->mMapBuffers.EnumerateRead(BufferCacheMemoryUsageFunction, &bufferCacheMemoryUsageForThisContext);
result += bufferCacheMemoryUsageForThisContext;
}
return result;
}
static PRInt64 GetBufferCount() {
const ContextsArrayType & contexts = Contexts();
PRInt64 result = 0;
for(size_t i = 0; i < contexts.Length(); ++i) {
result += contexts[i]->mMapBuffers.Count();
}
return result;
}
static PLDHashOperator RenderbufferMemoryUsageFunction(const PRUint32&, WebGLRenderbuffer *aValue, void *aData)
{
PRInt64 *result = (PRInt64*) aData;
*result += aValue->MemoryUsage();
return PL_DHASH_NEXT;
}
static PRInt64 GetRenderbufferMemoryUsed() {
const ContextsArrayType & contexts = Contexts();
PRInt64 result = 0;
for(size_t i = 0; i < contexts.Length(); ++i) {
PRInt64 bufferMemoryUsageForThisContext = 0;
contexts[i]->mMapRenderbuffers.EnumerateRead(RenderbufferMemoryUsageFunction, &bufferMemoryUsageForThisContext);
result += bufferMemoryUsageForThisContext;
}
return result;
}
static PRInt64 GetRenderbufferCount() {
const ContextsArrayType & contexts = Contexts();
PRInt64 result = 0;
for(size_t i = 0; i < contexts.Length(); ++i) {
result += contexts[i]->mMapRenderbuffers.Count();
}
return result;
}
static PLDHashOperator ShaderSourceSizeFunction(const PRUint32&, WebGLShader *aValue, void *aData)
{
PRInt64 *result = (PRInt64*) aData;
*result += aValue->Source().Length();
return PL_DHASH_NEXT;
}
static PLDHashOperator ShaderTranslationLogSizeFunction(const PRUint32&, WebGLShader *aValue, void *aData)
{
PRInt64 *result = (PRInt64*) aData;
*result += aValue->TranslationLog().Length();
return PL_DHASH_NEXT;
}
static PRInt64 GetShaderSourcesSize() {
const ContextsArrayType & contexts = Contexts();
PRInt64 result = 0;
for(size_t i = 0; i < contexts.Length(); ++i) {
PRInt64 shaderSourcesSizeForThisContext = 0;
contexts[i]->mMapShaders.EnumerateRead(ShaderSourceSizeFunction, &shaderSourcesSizeForThisContext);
result += shaderSourcesSizeForThisContext;
}
return result;
}
static PRInt64 GetShaderTranslationLogsSize() {
const ContextsArrayType & contexts = Contexts();
PRInt64 result = 0;
for(size_t i = 0; i < contexts.Length(); ++i) {
PRInt64 shaderTranslationLogsSizeForThisContext = 0;
contexts[i]->mMapShaders.EnumerateRead(ShaderTranslationLogSizeFunction, &shaderTranslationLogsSizeForThisContext);
result += shaderTranslationLogsSizeForThisContext;
}
return result;
}
static PRInt64 GetShaderCount() {
const ContextsArrayType & contexts = Contexts();
PRInt64 result = 0;
for(size_t i = 0; i < contexts.Length(); ++i) {
result += contexts[i]->mMapShaders.Count();
}
return result;
}
static PRInt64 GetContextCount() {
return Contexts().Length();
}
};
}
#endif

View File

@ -41,6 +41,7 @@
#include "WebGLContext.h"
#include "nsString.h"
#include "nsDebug.h"
#include "gfxImageSurface.h"
#include "gfxContext.h"
@ -367,6 +368,32 @@ WebGLContext::BlendFuncSeparate(WebGLenum srcRGB, WebGLenum dstRGB,
return NS_OK;
}
GLenum WebGLContext::CheckedBufferData(GLenum target,
GLsizeiptr size,
const GLvoid *data,
GLenum usage)
{
WebGLBuffer *boundBuffer = NULL;
if (target == LOCAL_GL_ARRAY_BUFFER) {
boundBuffer = mBoundArrayBuffer;
} else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
boundBuffer = mBoundElementArrayBuffer;
}
NS_ABORT_IF_FALSE(boundBuffer != nsnull, "no buffer bound for this target");
bool sizeChanges = PRUint32(size) != boundBuffer->ByteLength();
if (sizeChanges) {
UpdateWebGLErrorAndClearGLError();
gl->fBufferData(target, size, data, usage);
GLenum error = LOCAL_GL_NO_ERROR;
UpdateWebGLErrorAndClearGLError(&error);
return error;
} else {
gl->fBufferData(target, size, data, usage);
return LOCAL_GL_NO_ERROR;
}
}
NS_IMETHODIMP
WebGLContext::BufferData(PRInt32 dummy)
{
@ -406,13 +433,17 @@ WebGLContext::BufferData_size(WebGLenum target, WebGLsizei size, WebGLenum usage
return ErrorInvalidOperation("BufferData: no buffer bound!");
MakeContextCurrent();
GLenum error = CheckedBufferData(target, size, 0, usage);
if (error) {
LogMessageIfVerbose("bufferData generated error %s", ErrorName(error));
return NS_OK;
}
boundBuffer->SetByteLength(size);
boundBuffer->InvalidateCachedMaxElements();
if (!boundBuffer->ZeroDataIfElementArray())
return ErrorOutOfMemory("bufferData: out of memory");
boundBuffer->InvalidateCachedMaxElements();
gl->fBufferData(target, size, 0, usage);
return NS_OK;
}
@ -438,12 +469,19 @@ WebGLContext::BufferData_buf(WebGLenum target, JSObject *wb, WebGLenum usage)
MakeContextCurrent();
GLenum error = CheckedBufferData(target,
JS_GetArrayBufferByteLength(wb),
JS_GetArrayBufferData(wb),
usage);
if (error) {
LogMessageIfVerbose("bufferData generated error %s", ErrorName(error));
return NS_OK;
}
boundBuffer->SetByteLength(JS_GetArrayBufferByteLength(wb));
boundBuffer->InvalidateCachedMaxElements();
if (!boundBuffer->CopyDataIfElementArray(JS_GetArrayBufferData(wb)))
return ErrorOutOfMemory("bufferData: out of memory");
boundBuffer->InvalidateCachedMaxElements();
gl->fBufferData(target, JS_GetArrayBufferByteLength(wb), JS_GetArrayBufferData(wb), usage);
return NS_OK;
}
@ -469,12 +507,19 @@ WebGLContext::BufferData_array(WebGLenum target, js::TypedArray *wa, WebGLenum u
MakeContextCurrent();
GLenum error = CheckedBufferData(target,
wa->byteLength,
wa->data,
usage);
if (error) {
LogMessageIfVerbose("bufferData generated error %s", ErrorName(error));
return NS_OK;
}
boundBuffer->SetByteLength(wa->byteLength);
boundBuffer->InvalidateCachedMaxElements();
if (!boundBuffer->CopyDataIfElementArray(wa->data))
return ErrorOutOfMemory("bufferData: out of memory");
boundBuffer->InvalidateCachedMaxElements();
gl->fBufferData(target, wa->byteLength, wa->data, usage);
return NS_OK;
}
@ -685,9 +730,9 @@ WebGLContext::CopyTexSubImage2D_base(WebGLenum target,
if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, framebufferWidth, framebufferHeight)) {
if (sub)
gl->fCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
gl->fCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
else
gl->fCopyTexImage2D(target, level, internalformat, x, y, width, height, 0);
gl->fCopyTexImage2D(target, level, internalformat, x, y, width, height, 0);
} else {
// the rect doesn't fit in the framebuffer
@ -728,10 +773,11 @@ WebGLContext::CopyTexSubImage2D_base(WebGLenum target,
// now initialize the texture as black
if (sub)
gl->fTexSubImage2D(target, level, 0, 0, width, height, internalformat, LOCAL_GL_UNSIGNED_BYTE, tempZeroData);
gl->fTexSubImage2D(target, level, 0, 0, width, height,
internalformat, LOCAL_GL_UNSIGNED_BYTE, tempZeroData);
else
gl->fTexImage2D(target, level, internalformat, width, height, 0, internalformat, LOCAL_GL_UNSIGNED_BYTE, tempZeroData);
gl->fTexImage2D(target, level, internalformat, width, height,
0, internalformat, LOCAL_GL_UNSIGNED_BYTE, tempZeroData);
free(tempZeroData);
// if we are completely outside of the framebuffer, we can exit now with our black texture
@ -830,9 +876,31 @@ WebGLContext::CopyTexImage2D(WebGLenum target,
if (!tex)
return ErrorInvalidOperation("copyTexImage2D: no texture bound to this target");
tex->SetImageInfo(target, level, width, height);
const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(level, WebGLTexture::FaceForTarget(target));
return CopyTexSubImage2D_base(target, level, internalformat, 0, 0, x, y, width, height, false);
// copyTexImage2D only generates textures with type = UNSIGNED_BYTE
GLenum type = LOCAL_GL_UNSIGNED_BYTE;
bool sizeMayChange = width != imageInfo.mWidth ||
height != imageInfo.mHeight ||
internalformat != imageInfo.mFormat ||
type != imageInfo.mType;
if (sizeMayChange) {
UpdateWebGLErrorAndClearGLError();
CopyTexSubImage2D_base(target, level, internalformat, 0, 0, x, y, width, height, false);
GLenum error = LOCAL_GL_NO_ERROR;
UpdateWebGLErrorAndClearGLError(&error);
if (error) {
LogMessageIfVerbose("copyTexImage2D generated error %s", ErrorName(error));
return NS_OK;
}
} else {
CopyTexSubImage2D_base(target, level, internalformat, 0, 0, x, y, width, height, false);
}
tex->SetImageInfo(target, level, width, height, internalformat, type);
return NS_OK;
}
NS_IMETHODIMP
@ -2226,18 +2294,9 @@ WebGLContext::GetError(WebGLenum *_retval)
{
MakeContextCurrent();
// Always call glGetError to clear any pending
// real GL error.
WebGLenum err = gl->fGetError();
// mSynthesizedGLError has the first error that occurred,
// whether synthesized or real; if it's not NO_ERROR, use it.
if (mSynthesizedGLError != LOCAL_GL_NO_ERROR) {
err = mSynthesizedGLError;
mSynthesizedGLError = LOCAL_GL_NO_ERROR;
}
*_retval = err;
UpdateWebGLErrorAndClearGLError();
*_retval = mWebGLError;
mWebGLError = LOCAL_GL_NO_ERROR;
return NS_OK;
}
@ -3107,8 +3166,6 @@ WebGLContext::RenderbufferStorage(WebGLenum target, WebGLenum internalformat, We
if (!mBoundRenderbuffer || !mBoundRenderbuffer->GLName())
return ErrorInvalidOperation("renderbufferStorage called on renderbuffer 0");
MakeContextCurrent();
// certain OpenGL ES renderbuffer formats may not exist on desktop OpenGL
WebGLenum internalformatForGL = internalformat;
@ -3144,9 +3201,26 @@ WebGLContext::RenderbufferStorage(WebGLenum target, WebGLenum internalformat, We
return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", internalformat);
}
gl->fRenderbufferStorage(target, internalformatForGL, width, height);
MakeContextCurrent();
bool sizeChanges = width != mBoundRenderbuffer->width() ||
height != mBoundRenderbuffer->height() ||
internalformat != mBoundRenderbuffer->InternalFormat();
if (sizeChanges) {
UpdateWebGLErrorAndClearGLError();
gl->fRenderbufferStorage(target, internalformatForGL, width, height);
GLenum error = LOCAL_GL_NO_ERROR;
UpdateWebGLErrorAndClearGLError(&error);
if (error) {
LogMessageIfVerbose("bufferData generated error %s", ErrorName(error));
return NS_OK;
}
} else {
gl->fRenderbufferStorage(target, internalformatForGL, width, height);
}
mBoundRenderbuffer->SetInternalFormat(internalformat);
mBoundRenderbuffer->SetInternalFormatForGL(internalformatForGL);
mBoundRenderbuffer->setDimensions(width, height);
mBoundRenderbuffer->SetInitialized(PR_FALSE);
@ -4044,11 +4118,19 @@ WebGLContext::ShaderSource(nsIWebGLShader *sobj, const nsAString& source)
WebGLuint shadername;
if (!GetConcreteObjectAndGLName("shaderSource: shader", sobj, &shader, &shadername))
return NS_OK;
const nsPromiseFlatString& flatSource = PromiseFlatString(source);
if (!NS_IsAscii(nsPromiseFlatString(source).get()))
if (!NS_IsAscii(flatSource.get()))
return ErrorInvalidValue("shaderSource: non-ascii characters found in source");
shader->SetSource(NS_LossyConvertUTF16toASCII(source));
const nsCString& sourceCString = NS_LossyConvertUTF16toASCII(flatSource);
const PRUint32 maxSourceLength = (PRUint32(1)<<18) - 1;
if (sourceCString.Length() > maxSourceLength)
return ErrorInvalidValue("shaderSource: source has more than %d characters", maxSourceLength);
shader->SetSource(sourceCString);
shader->SetNeedsTranslation();
@ -4136,6 +4218,35 @@ WebGLContext::TexImage2D(PRInt32)
return NS_ERROR_FAILURE;
}
GLenum WebGLContext::CheckedTexImage2D(GLenum target,
GLint level,
GLenum internalFormat,
GLsizei width,
GLsizei height,
GLint border,
GLenum format,
GLenum type,
const GLvoid *data)
{
WebGLTexture *tex = activeBoundTextureForTarget(target);
NS_ABORT_IF_FALSE(tex != nsnull, "no texture bound");
const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(level, WebGLTexture::FaceForTarget(target));
bool sizeMayChange = width != imageInfo.mWidth ||
height != imageInfo.mHeight ||
format != imageInfo.mFormat ||
type != imageInfo.mType;
if (sizeMayChange) {
UpdateWebGLErrorAndClearGLError();
gl->fTexImage2D(target, level, internalFormat, width, height, border, format, type, data);
GLenum error = LOCAL_GL_NO_ERROR;
UpdateWebGLErrorAndClearGLError(&error);
return error;
} else {
gl->fTexImage2D(target, level, internalFormat, width, height, border, format, type, data);
return LOCAL_GL_NO_ERROR;
}
}
nsresult
WebGLContext::TexImage2D_base(WebGLenum target, WebGLint level, WebGLenum internalformat,
WebGLsizei width, WebGLsizei height, WebGLsizei srcStrideOrZero,
@ -4227,14 +4338,14 @@ WebGLContext::TexImage2D_base(WebGLenum target, WebGLint level, WebGLenum intern
if (!tex)
return ErrorInvalidOperation("texImage2D: no texture is bound to this target");
tex->SetImageInfo(target, level, width, height, format, type);
MakeContextCurrent();
// Handle ES2 and GL differences in floating point internal formats. Note that
// format == internalformat, as checked above and as required by ES.
internalformat = InternalFormatForFormatAndType(format, type, gl->IsGLES2());
GLenum error = LOCAL_GL_NO_ERROR;
if (byteLength) {
int dstFormat = GetWebGLTexelFormat(format, type);
int actualSrcFormat = srcFormat == WebGLTexelFormat::Auto ? dstFormat : srcFormat;
@ -4250,16 +4361,18 @@ WebGLContext::TexImage2D_base(WebGLenum target, WebGLint level, WebGLenum intern
!mPixelStoreFlipY)
{
// no conversion, no flipping, so we avoid copying anything and just pass the source pointer
gl->fTexImage2D(target, level, internalformat, width, height, border, format, type, data);
error = CheckedTexImage2D(target, level, internalformat,
width, height, border, format, type, data);
}
else
{
nsAutoArrayPtr<PRUint8> convertedData(new PRUint8[bytesNeeded]);
ConvertImage(width, height, srcStride, dstStride,
(PRUint8*)data, convertedData,
actualSrcFormat, srcPremultiplied,
dstFormat, mPixelStorePremultiplyAlpha, texelSize);
gl->fTexImage2D(target, level, internalformat, width, height, border, format, type, convertedData);
(PRUint8*)data, convertedData,
actualSrcFormat, srcPremultiplied,
dstFormat, mPixelStorePremultiplyAlpha, texelSize);
error = CheckedTexImage2D(target, level, internalformat,
width, height, border, format, type, convertedData);
}
} else {
// We need some zero pages, because GL doesn't guarantee the
@ -4269,12 +4382,18 @@ WebGLContext::TexImage2D_base(WebGLenum target, WebGLint level, WebGLenum intern
if (!tempZeroData)
return ErrorOutOfMemory("texImage2D: could not allocate %d bytes (for zero fill)", bytesNeeded);
gl->fTexImage2D(target, level, internalformat, width, height, border, format, type, tempZeroData);
error = CheckedTexImage2D(target, level, internalformat,
width, height, border, format, type, tempZeroData);
free(tempZeroData);
}
if (error) {
LogMessageIfVerbose("texImage2D generated error %s", ErrorName(error));
return NS_OK;
}
tex->setDimensions(width, height);
tex->SetImageInfo(target, level, width, height, format, type);
return NS_OK;
}
@ -4418,10 +4537,11 @@ WebGLContext::TexSubImage2D_base(WebGLenum target, WebGLint level,
if (!tex)
return ErrorInvalidOperation("texSubImage2D: no texture is bound to this target");
if (!CanvasUtils::CheckSaneSubrectSize(xoffset, yoffset, width, height, tex->width(), tex->height()))
size_t face = WebGLTexture::FaceForTarget(target);
const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(level, face);
if (!CanvasUtils::CheckSaneSubrectSize(xoffset, yoffset, width, height, imageInfo.mWidth, imageInfo.mHeight))
return ErrorInvalidValue("texSubImage2D: subtexture rectangle out of bounds");
MakeContextCurrent();
int dstFormat = GetWebGLTexelFormat(format, type);

View File

@ -46,10 +46,7 @@
#include "nsIJSContextStack.h"
#include "jsapi.h"
#include "nsIScriptSecurityManager.h"
#include "nsIPrefBranch.h"
#include "nsServiceManagerUtils.h"
#include "nsIPrefBranch.h"
#include "nsIPrefService.h"
#include "nsIVariant.h"
#include "nsIDOMDocument.h"
@ -59,6 +56,7 @@
#include "nsIDOMDataContainerEvent.h"
#include "nsContentUtils.h"
#include "mozilla/Preferences.h"
#if 0
#include "nsIContentURIGrouper.h"
@ -126,15 +124,13 @@ WebGLContext::SynthesizeGLError(WebGLenum err)
// but if there isn't, then we need to check for a gl error
// that may have occurred before this one and use that code
// instead.
MakeContextCurrent();
if (mSynthesizedGLError == LOCAL_GL_NO_ERROR) {
MakeContextCurrent();
UpdateWebGLErrorAndClearGLError();
mSynthesizedGLError = gl->fGetError();
if (mSynthesizedGLError == LOCAL_GL_NO_ERROR)
mSynthesizedGLError = err;
}
if (!mWebGLError)
mWebGLError = err;
return NS_OK;
}
@ -194,3 +190,24 @@ WebGLContext::ErrorOutOfMemory(const char *fmt, ...)
return SynthesizeGLError(LOCAL_GL_OUT_OF_MEMORY);
}
const char *
WebGLContext::ErrorName(GLenum error)
{
switch(error) {
case LOCAL_GL_INVALID_ENUM:
return "INVALID_ENUM";
case LOCAL_GL_INVALID_OPERATION:
return "INVALID_OPERATION";
case LOCAL_GL_INVALID_VALUE:
return "INVALID_VALUE";
case LOCAL_GL_OUT_OF_MEMORY:
return "OUT_OF_MEMORY";
case LOCAL_GL_INVALID_FRAMEBUFFER_OPERATION:
return "INVALID_FRAMEBUFFER_OPERATION";
case LOCAL_GL_NO_ERROR:
return "NO_ERROR";
default:
NS_ABORT();
return "[unknown WebGL error!]";
}
};

View File

@ -39,8 +39,7 @@
#include "WebGLContext.h"
#include "nsIPrefService.h"
#include "nsServiceManagerUtils.h"
#include "mozilla/Preferences.h"
#include "CheckedInt.h"
@ -329,6 +328,34 @@ PRBool WebGLContext::ValidateDrawModeEnum(WebGLenum mode, const char *info)
}
}
PRUint32 WebGLContext::GetTexelSize(WebGLenum format, WebGLenum type)
{
if (type == LOCAL_GL_UNSIGNED_BYTE || type == LOCAL_GL_FLOAT) {
int multiplier = type == LOCAL_GL_FLOAT ? 4 : 1;
switch (format) {
case LOCAL_GL_ALPHA:
case LOCAL_GL_LUMINANCE:
return 1 * multiplier;
case LOCAL_GL_LUMINANCE_ALPHA:
return 2 * multiplier;
case LOCAL_GL_RGB:
return 3 * multiplier;
case LOCAL_GL_RGBA:
return 4 * multiplier;
default:
break;
}
} else if (type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 ||
type == LOCAL_GL_UNSIGNED_SHORT_5_6_5)
{
return 2;
}
NS_ABORT();
return 0;
}
PRBool WebGLContext::ValidateTexFormatAndType(WebGLenum format, WebGLenum type, int jsArrayType,
PRUint32 *texelSize, const char *info)
{
@ -449,7 +476,7 @@ WebGLContext::InitAndValidateGL()
}
mActiveTexture = 0;
mSynthesizedGLError = LOCAL_GL_NO_ERROR;
mWebGLError = LOCAL_GL_NO_ERROR;
mAttribBuffers.Clear();
@ -519,7 +546,7 @@ WebGLContext::InitAndValidateGL()
// and check OpenGL error for INVALID_ENUM.
// before we start, we check that no error already occurred, to prevent hiding it in our subsequent error handling
error = gl->fGetError();
error = gl->GetAndClearError();
if (error != LOCAL_GL_NO_ERROR) {
LogMessage("GL error 0x%x occurred during WebGL context initialization!", error);
return PR_FALSE;
@ -572,10 +599,10 @@ WebGLContext::InitAndValidateGL()
}
// Check the shader validator pref
nsCOMPtr<nsIPrefBranch> prefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
NS_ENSURE_TRUE(prefService != nsnull, NS_ERROR_FAILURE);
NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE);
prefService->GetBoolPref("webgl.shader_validator", &mShaderValidation);
mShaderValidation =
Preferences::GetBool("webgl.shader_validator", mShaderValidation);
#if defined(USE_ANGLE)
// initialize shader translator
@ -587,9 +614,9 @@ WebGLContext::InitAndValidateGL()
}
#endif
// notice that the point of calling GetError here is not only to check for error,
// it is also to reset the error flag so that a subsequent WebGL getError call will give the correct result.
error = gl->fGetError();
// notice that the point of calling GetAndClearError here is not only to check for error,
// it is also to reset the error flags so that a subsequent WebGL getError call will give the correct result.
error = gl->GetAndClearError();
if (error != LOCAL_GL_NO_ERROR) {
LogMessage("GL error 0x%x occurred during WebGL context initialization!", error);
return PR_FALSE;

View File

@ -6,7 +6,6 @@ conformance/glsl-conformance.html
conformance/invalid-passed-params.html
conformance/more/conformance/quickCheckAPI.html
conformance/more/functions/copyTexImage2D.html
conformance/more/functions/copyTexSubImage2DBadArgs.html
conformance/more/functions/copyTexSubImage2D.html
conformance/more/functions/deleteBufferBadArgs.html
conformance/more/functions/texImage2DBadArgs.html

View File

@ -7,10 +7,8 @@ conformance/object-deletion-behaviour.html
conformance/read-pixels-test.html
conformance/tex-input-validation.html
conformance/tex-sub-image-2d-bad-args.html
conformance/uninitialized-test.html
conformance/more/functions/copyTexImage2D.html
conformance/more/functions/copyTexSubImage2D.html
conformance/more/functions/copyTexSubImage2DBadArgs.html
conformance/more/functions/deleteBufferBadArgs.html
conformance/more/functions/texImage2DBadArgs.html
conformance/more/functions/texSubImage2DBadArgs.html

View File

@ -4,11 +4,9 @@ conformance/invalid-passed-params.html
conformance/object-deletion-behaviour.html
conformance/read-pixels-test.html
conformance/tex-sub-image-2d-bad-args.html
conformance/uninitialized-test.html
conformance/more/conformance/quickCheckAPI.html
conformance/more/functions/copyTexImage2D.html
conformance/more/functions/copyTexSubImage2D.html
conformance/more/functions/copyTexSubImage2DBadArgs.html
conformance/more/functions/deleteBufferBadArgs.html
conformance/more/functions/texImage2DBadArgs.html
conformance/more/functions/texSubImage2DBadArgs.html

View File

@ -368,6 +368,7 @@ function start() {
testsExpectedToFail.push('conformance/gl-get-active-attribute.html'); // bug in NVIDIA 190.42, fixed in newer drivers
testsExpectedToFail.push('conformance/gl-uniform-bool.html'); // bug in NVIDIA 190.42, fixed in newer drivers
testsExpectedToFail.push('conformance/tex-image-and-sub-image-2d-with-array-buffer-view.html'); // ???
testsExpectedToFail.push('conformance/uninitialized-test.html'); // bug in NVIDIA 190.42, fixed in newer drivers
}
var testsToIgnore = [];

View File

@ -643,6 +643,12 @@ ImageDocument::CreateSyntheticDocument()
nsresult rv = MediaDocument::CreateSyntheticDocument();
NS_ENSURE_SUCCESS(rv, rv);
// We must declare the image as a block element. If we stay as
// an inline element, our parent LineBox will be inline too and
// ignore the available height during reflow.
// This is bad during printing, it means tall image frames won't know
// the size of the paper and cannot break into continuations along
// multiple pages.
Element* body = GetBodyElement();
if (!body) {
NS_WARNING("no body on image document!");
@ -650,6 +656,19 @@ ImageDocument::CreateSyntheticDocument()
}
nsCOMPtr<nsINodeInfo> nodeInfo;
nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::style, nsnull,
kNameSpaceID_XHTML,
nsIDOMNode::ELEMENT_NODE);
NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
nsRefPtr<nsGenericHTMLElement> styleContent = NS_NewHTMLStyleElement(nodeInfo.forget());
if (!styleContent) {
return NS_ERROR_OUT_OF_MEMORY;
}
styleContent->SetTextContent(NS_LITERAL_STRING("img { display: block; }"));
body->AppendChildTo(styleContent, PR_FALSE);
// Add the image element
nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::img, nsnull,
kNameSpaceID_XHTML,
nsIDOMNode::ELEMENT_NODE);

View File

@ -2170,16 +2170,8 @@ nsHTMLDocument::GetEmbeds(nsIDOMHTMLCollection** aEmbeds)
}
NS_IMETHODIMP
nsHTMLDocument::GetSelection(nsAString& aReturn)
nsHTMLDocument::GetSelection(nsISelection** aReturn)
{
aReturn.Truncate();
nsCOMPtr<nsIJSContextStack> stack = do_GetService("@mozilla.org/js/xpc/ContextStack;1");
JSContext* ccx = nsnull;
if (stack && NS_SUCCEEDED(stack->Peek(&ccx)) && ccx) {
JS_ReportWarning(ccx, "Deprecated method document.getSelection() called. Please use window.getSelection() instead.");
}
nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(GetScopeObject());
nsCOMPtr<nsPIDOMWindow> pwin = do_QueryInterface(window);
NS_ENSURE_TRUE(pwin, NS_OK);
@ -2188,17 +2180,8 @@ nsHTMLDocument::GetSelection(nsAString& aReturn)
pwin->GetOuterWindow()->GetCurrentInnerWindow() == pwin,
NS_OK);
nsCOMPtr<nsISelection> selection;
nsresult rv = window->GetSelection(getter_AddRefs(selection));
NS_ENSURE_TRUE(selection && NS_SUCCEEDED(rv), rv);
nsXPIDLString str;
rv = selection->ToString(getter_Copies(str));
aReturn.Assign(str);
return rv;
return window->GetSelection(aReturn);
}
NS_IMETHODIMP

View File

@ -1263,6 +1263,17 @@ nsresult nsOggReader::SeekBisection(PRInt64 aTarget,
SEEK_LOG(PR_LOG_DEBUG, ("Backing off %d bytes, backsteps=%d",
static_cast<PRInt32>(PAGE_STEP * pow(2.0, backsteps)), backsteps));
guess -= PAGE_STEP * static_cast<ogg_int64_t>(pow(2.0, backsteps));
if (guess <= startOffset) {
// We've tried to backoff to before the start offset of our seek
// range. This means we couldn't find a seek termination position
// near the end of the seek range, so just set the seek termination
// condition, and break out of the bisection loop. We'll begin
// decoding from the start of the seek range.
interval = 0;
break;
}
backsteps = NS_MIN(backsteps + 1, maxBackStep);
// We reset mustBackoff. If we still need to backoff further, it will
// be set to PR_TRUE again.
@ -1329,14 +1340,14 @@ nsresult nsOggReader::SeekBisection(PRInt64 aTarget,
ogg_int64_t granulepos = ogg_page_granulepos(&page);
if (HasAudio() &&
granulepos != -1 &&
granulepos > 0 &&
serial == mVorbisState->mSerial &&
audioTime == -1) {
audioTime = mVorbisState->Time(granulepos);
}
if (HasVideo() &&
granulepos != -1 &&
granulepos > 0 &&
serial == mTheoraState->mSerial &&
videoTime == -1) {
videoTime = mTheoraState->StartTime(granulepos);

View File

@ -43,8 +43,7 @@
#include "nsWebMReader.h"
#include "VideoUtils.h"
#include "nsTimeRanges.h"
#include "nsIServiceManager.h"
#include "nsIPrefService.h"
#include "mozilla/Preferences.h"
using namespace mozilla;
using namespace mozilla::layers;
@ -309,9 +308,9 @@ nsresult nsWebMReader::ReadMetadata(nsVideoInfo* aInfo)
break;
}
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
PRInt32 forceStereoMode;
if (NS_SUCCEEDED(prefs->GetIntPref("media.webm.force_stereo_mode", &forceStereoMode))) {
if (NS_SUCCEEDED(Preferences::GetInt("media.webm.force_stereo_mode",
&forceStereoMode))) {
switch (forceStereoMode) {
case 1:
mInfo.mStereoMode = STEREO_MODE_LEFT_RIGHT;

View File

@ -124,7 +124,7 @@ DOMSVGAnimatedLengthList::InternalBaseValListWillChangeTo(const SVGLengthList& a
nsRefPtr<DOMSVGAnimatedLengthList> kungFuDeathGrip;
if (mBaseVal) {
if (!aNewValue.Length()) {
if (aNewValue.Length() < mBaseVal->Length()) {
// InternalListLengthWillChange might clear last reference to |this|.
// Retain a temporary reference to keep from dying before returning.
kungFuDeathGrip = this;

View File

@ -123,7 +123,7 @@ DOMSVGAnimatedNumberList::InternalBaseValListWillChangeTo(const SVGNumberList& a
nsRefPtr<DOMSVGAnimatedNumberList> kungFuDeathGrip;
if (mBaseVal) {
if (!aNewValue.Length()) {
if (aNewValue.Length() < mBaseVal->Length()) {
// InternalListLengthWillChange might clear last reference to |this|.
// Retain a temporary reference to keep from dying before returning.
kungFuDeathGrip = this;

View File

@ -119,7 +119,7 @@ DOMSVGLengthList::InternalListLengthWillChange(PRUint32 aNewLength)
}
nsRefPtr<DOMSVGLengthList> kungFuDeathGrip;
if (oldLength && !aNewLength) {
if (aNewLength < oldLength) {
// RemovingFromList() might clear last reference to |this|.
// Retain a temporary reference to keep from dying before returning.
kungFuDeathGrip = this;

View File

@ -119,7 +119,7 @@ DOMSVGNumberList::InternalListLengthWillChange(PRUint32 aNewLength)
}
nsRefPtr<DOMSVGNumberList> kungFuDeathGrip;
if (oldLength && !aNewLength) {
if (aNewLength < oldLength) {
// RemovingFromList() might clear last reference to |this|.
// Retain a temporary reference to keep from dying before returning.
kungFuDeathGrip = this;

View File

@ -156,7 +156,7 @@ DOMSVGPathSegList::InternalListWillChangeTo(const SVGPathData& aNewValue)
PRUint32 newSegType;
nsRefPtr<DOMSVGPathSegList> kungFuDeathGrip;
if (length && aNewValue.IsEmpty()) {
if (aNewValue.Length() < length) {
// RemovingFromList() might clear last reference to |this|.
// Retain a temporary reference to keep from dying before returning.
kungFuDeathGrip = this;

View File

@ -148,7 +148,7 @@ DOMSVGPointList::InternalListWillChangeTo(const SVGPointList& aNewValue)
}
nsRefPtr<DOMSVGPointList> kungFuDeathGrip;
if (oldLength && !newLength) {
if (newLength < oldLength) {
// RemovingFromList() might clear last reference to |this|.
// Retain a temporary reference to keep from dying before returning.
kungFuDeathGrip = this;

View File

@ -55,7 +55,6 @@
#include "nsStyleUtil.h"
#include "nsSVGUtils.h"
#include "nsServiceManagerUtils.h"
#include "nsIPrefService.h"
#include "mozilla/Preferences.h"
using namespace mozilla;
@ -72,14 +71,7 @@ nsSVGFeatures::HaveFeature(nsISupports* aObject, const nsAString& aFeature)
return PR_FALSE;
}
}
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
if (prefs) {
PRBool js;
if (NS_SUCCEEDED(prefs->GetBoolPref("javascript.enabled", &js))) {
return js;
}
}
return PR_FALSE;
return Preferences::GetBool("javascript.enabled", PR_FALSE);
}
#define SVG_SUPPORTED_FEATURE(str) if (aFeature.EqualsLiteral(str)) return PR_TRUE;
#define SVG_UNSUPPORTED_FEATURE(str)

View File

@ -9192,7 +9192,17 @@ nsresult nsDocShell::DoChannelLoad(nsIChannel * aChannel,
// Load attributes depend on load type...
switch (mLoadType) {
case LOAD_HISTORY:
loadFlags |= nsIRequest::VALIDATE_NEVER;
{
// Only send VALIDATE_NEVER if mLSHE's URI was never changed via
// push/replaceState (bug 669671).
PRBool uriModified = PR_FALSE;
if (mLSHE) {
mLSHE->GetURIWasModified(&uriModified);
}
if (!uriModified)
loadFlags |= nsIRequest::VALIDATE_NEVER;
}
break;
case LOAD_RELOAD_CHARSET_CHANGE:
@ -9854,6 +9864,15 @@ nsDocShell::AddState(nsIVariant *aData, const nsAString& aTitle,
newSHEntry->SetStateData(scContainer);
newSHEntry->SetPostData(nsnull);
// If this push/replaceState changed the document's current URI and the new
// URI differs from the old URI in more than the hash, or if the old
// SHEntry's URI was modified in this way by a push/replaceState call
// set URIWasModified to true for the current SHEntry (bug 669671).
PRBool sameExceptHashes = PR_TRUE, oldURIWasModified = PR_FALSE;
newURI->EqualsExceptRef(mCurrentURI, &sameExceptHashes);
oldOSHE->GetURIWasModified(&oldURIWasModified);
newSHEntry->SetURIWasModified(!sameExceptHashes || oldURIWasModified);
// Step 5: If aReplace is false, indicating that we're doing a pushState
// rather than a replaceState, notify bfcache that we've added a page to
// the history so it can evict content viewers if appropriate.

View File

@ -59,7 +59,7 @@ class nsDocShellEditorData;
[ptr] native nsDocShellEditorDataPtr(nsDocShellEditorData);
[scriptable, uuid(5f3ebf43-6944-45fb-b1b1-78a05bf9370b)]
[scriptable, uuid(b92d403e-f5ec-4b81-b0e3-6e6c241cef2d)]
interface nsISHEntry : nsIHistoryEntry
{
/** URI for the document */
@ -169,6 +169,19 @@ interface nsISHEntry : nsIHistoryEntry
* is a session history entry for
*/
attribute ACString contentType;
/**
* If we created this SHEntry via history.pushState or modified it via
* history.replaceState, and if we changed the SHEntry's URI via the
* push/replaceState call, and if the SHEntry's new URI differs from its
* old URI by more than just the hash, then we set this field to true.
*
* Additionally, if this SHEntry was created by calling pushState from a
* SHEntry whose URI was modified, this SHEntry's URIWasModified field is
* true.
*
*/
attribute boolean URIWasModified;
/** Set/Get scrollers' positon in anchored pages */
void setScrollPosition(in long x, in long y);

View File

@ -108,6 +108,7 @@ nsSHEntry::nsSHEntry()
, mDocIdentifier(gEntryDocIdentifier++)
, mScrollPositionX(0)
, mScrollPositionY(0)
, mURIWasModified(PR_FALSE)
, mIsFrameNavigation(PR_FALSE)
, mSaveLayoutState(PR_TRUE)
, mExpired(PR_FALSE)
@ -132,6 +133,7 @@ nsSHEntry::nsSHEntry(const nsSHEntry &other)
, mDocIdentifier(other.mDocIdentifier)
, mScrollPositionX(0) // XXX why not copy?
, mScrollPositionY(0) // XXX why not copy?
, mURIWasModified(other.mURIWasModified)
, mIsFrameNavigation(other.mIsFrameNavigation)
, mSaveLayoutState(other.mSaveLayoutState)
, mExpired(other.mExpired)
@ -208,6 +210,18 @@ NS_IMETHODIMP nsSHEntry::GetScrollPosition(PRInt32 *x, PRInt32 *y)
return NS_OK;
}
NS_IMETHODIMP nsSHEntry::GetURIWasModified(PRBool* aOut)
{
*aOut = mURIWasModified;
return NS_OK;
}
NS_IMETHODIMP nsSHEntry::SetURIWasModified(PRBool aIn)
{
mURIWasModified = aIn;
return NS_OK;
}
NS_IMETHODIMP nsSHEntry::GetURI(nsIURI** aURI)
{
*aURI = mURI;

View File

@ -102,6 +102,7 @@ private:
PRInt64 mDocIdentifier;
PRInt32 mScrollPositionX;
PRInt32 mScrollPositionY;
PRPackedBool mURIWasModified;
PRPackedBool mIsFrameNavigation;
PRPackedBool mSaveLayoutState;
PRPackedBool mExpired;

View File

@ -116,6 +116,8 @@ _TEST_FILES = \
test_bug668513.html \
bug668513_redirect.html \
bug668513_redirect.html^headers^ \
test_bug669671.html \
file_bug669671.sjs \
$(NULL)
ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)

View File

@ -0,0 +1,13 @@
function handleRequest(request, response)
{
var count = parseInt(getState('count'));
if (!count)
count = 0;
setState('count', count + 1 + '');
response.setHeader('Content-Type', 'text/html', false);
response.setHeader('Cache-Control', 'max-age=0');
response.write('<html><body onload="opener.onChildLoad()" ' +
'onunload="parseInt(\'0\')">' +
count + '</body></html>');
}

View File

@ -0,0 +1,140 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=669671
-->
<head>
<title>Test for Bug 669671</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=669671">Mozilla Bug 669671</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript;version=1.7">
/**
* Test for Bug 669671.
*
* This is a bit complicated. We have a script, file_bug669671.sjs, which counts
* how many times it's loaded and returns that count in the body of an HTML
* document. For brevity, call this page X.
*
* X is sent with Cache-Control: max-age=0 and can't be bfcached (it has an
* onunload handler). Our test does the following in a popup:
*
* 1) Load X?pushed, to prime the cache.
* 2) Navigate to X.
* 3) Call pushState and navigate from X to X?pushed.
* 4) Navigate to X?navigated.
* 5) Go back (to X?pushed).
*
* We do all this work so we can check that in step 5, we fetch X?pushed from
* the network -- we shouldn't use our cached copy, because of the
* cache-control header X sends.
*
* Then we go back and repeat the whole process but call history.replaceState
* instead of pushState. And for good measure, we test once more, this time
* modifying only the hash of the URI using replaceState. In this case, we
* *should* load from the cache.
*
**/
SimpleTest.waitForExplicitFinish();
function onChildLoad()
{
SimpleTest.executeSoon(function() { gGen.next() });
}
var _loadCount = 0;
function checkPopupLoadCount()
{
is(popup.document.body.innerHTML, _loadCount + '', 'Load count');
// We normally want to increment _loadCount here. But if the test fails
// because we didn't do a load we should have, let's not cause a cascade of
// failures by incrementing _loadCount.
var origCount = _loadCount;
if (popup.document.body.innerHTML >= _loadCount + '')
_loadCount++;
return origCount;
}
function test()
{
// Step 1 - The popup's body counts how many times we've requested the
// resource. This is the first time we've requested it, so it should be '0'.
checkPopupLoadCount();
// Step 2 - We'll get another onChildLoad when this finishes.
popup.location = 'file_bug669671.sjs';
yield;
// Step 3 - Call pushState and change the URI back to ?pushed.
checkPopupLoadCount();
popup.history.pushState('', '', '?pushed');
// Step 4 - Navigate away. This should trigger another onChildLoad.
popup.location = 'file_bug669671.sjs?navigated-1';
yield;
// Step 5 - Go back. This should result in another onload (because the file is
// not in bfcache) and should be the fourth time we've requested the sjs file.
checkPopupLoadCount();
popup.back();
yield;
// This is the check which was failing before we fixed the bug.
checkPopupLoadCount();
popup.close();
// Do the whole thing again, but with replaceState.
popup = window.open('file_bug669671.sjs?replaced');
yield;
checkPopupLoadCount();
popup.location = 'file_bug669671.sjs';
yield;
checkPopupLoadCount();
popup.history.replaceState('', '', '?replaced');
popup.location = 'file_bug669671.sjs?navigated-2';
yield;
checkPopupLoadCount();
popup.back();
yield;
checkPopupLoadCount();
popup.close();
// Once more, with feeling. Notice that we don't have to prime the cache
// with an extra load here, because X and X#hash share the same cache entry.
popup = window.open('file_bug669671.sjs?hash-test');
yield;
var initialCount = checkPopupLoadCount();
popup.history.replaceState('', '', '#hash');
popup.location = 'file_bug669671.sjs?navigated-3';
yield;
checkPopupLoadCount();
popup.back();
yield;
is(popup.document.body.innerHTML, initialCount + '',
'Load count (should be cached)');
popup.close();
SimpleTest.finish();
yield;
}
// This will call into onChildLoad once it loads.
var popup = window.open('file_bug669671.sjs?pushed');
var gGen = test();
</script>
</pre>
</body>
</html>

View File

@ -54,31 +54,31 @@ nsDOMMemoryReporter::Init()
}
NS_IMETHODIMP
nsDOMMemoryReporter::GetProcess(char** aProcess)
nsDOMMemoryReporter::GetProcess(nsACString &aProcess)
{
// "" means the main process.
*aProcess = strdup("");
aProcess.Truncate();
return NS_OK;
}
NS_IMETHODIMP
nsDOMMemoryReporter::GetPath(char** aMemoryPath)
nsDOMMemoryReporter::GetPath(nsACString &aMemoryPath)
{
*aMemoryPath = strdup("explicit/dom");
aMemoryPath.AssignLiteral("explicit/dom");
return NS_OK;
}
NS_IMETHODIMP
nsDOMMemoryReporter::GetKind(int* aKind)
nsDOMMemoryReporter::GetKind(PRInt32* aKind)
{
*aKind = KIND_HEAP;
return NS_OK;
}
NS_IMETHODIMP
nsDOMMemoryReporter::GetDescription(char** aDescription)
nsDOMMemoryReporter::GetDescription(nsACString &aDescription)
{
*aDescription = strdup("Memory used by the DOM.");
aDescription.AssignLiteral("Memory used by the DOM.");
return NS_OK;
}

View File

@ -44,16 +44,10 @@
class nsDOMMemoryReporter: public nsIMemoryReporter {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIMEMORYREPORTER
static void Init();
NS_IMETHOD GetProcess(char** aProcess);
NS_IMETHOD GetPath(char** aMemoryPath);
NS_IMETHOD GetKind(int* aKnd);
NS_IMETHOD GetDescription(char** aDescription);
NS_IMETHOD GetUnits(PRInt32* aUnits);
NS_IMETHOD GetAmount(PRInt64* aAmount);
private:
// Protect ctor, use Init() instead.
nsDOMMemoryReporter();

View File

@ -185,7 +185,10 @@ static PRTime sMaxChromeScriptRunTime;
static nsIScriptSecurityManager *sSecurityManager;
// nsMemoryPressureObserver observes the memory-pressure notifications
// and forces a garbage collection and cycle collection when it happens.
// and forces a garbage collection and cycle collection when it happens, if
// the appropriate pref is set.
static PRBool sGCOnMemoryPressure;
class nsMemoryPressureObserver : public nsIObserver
{
@ -200,8 +203,10 @@ NS_IMETHODIMP
nsMemoryPressureObserver::Observe(nsISupports* aSubject, const char* aTopic,
const PRUnichar* aData)
{
nsJSContext::GarbageCollectNow();
nsJSContext::CycleCollectNow();
if (sGCOnMemoryPressure) {
nsJSContext::GarbageCollectNow();
nsJSContext::CycleCollectNow();
}
return NS_OK;
}
@ -3795,6 +3800,10 @@ nsJSRuntime::Init()
if (!obs)
return NS_ERROR_FAILURE;
Preferences::AddBoolVarCache(&sGCOnMemoryPressure,
"javascript.options.gc_on_memory_pressure",
PR_TRUE);
nsIObserver* memPressureObserver = new nsMemoryPressureObserver();
NS_ENSURE_TRUE(memPressureObserver, NS_ERROR_OUT_OF_MEMORY);
obs->AddObserver(memPressureObserver, "memory-pressure", PR_FALSE);

View File

@ -49,8 +49,9 @@
*
* @see <http://www.whatwg.org/html/>
*/
interface nsISelection;
[scriptable, uuid(3c0ca40f-72c5-4d15-935e-ccaff7953f2c)]
[scriptable, uuid(3ab3e856-361d-435a-8a4d-b462799945cd)]
interface nsIDOMHTMLDocument : nsIDOMDocument
{
readonly attribute DOMString URL;
@ -132,7 +133,7 @@ interface nsIDOMHTMLDocument : nsIDOMDocument
// DOM Range
DOMString getSelection();
nsISelection getSelection();
// Mozilla extensions

View File

@ -363,11 +363,11 @@ ContentChild::RecvPMemoryReportRequestConstructor(PMemoryReportRequestChild* chi
PRInt32 units;
PRInt64 amount;
nsCString desc;
r->GetPath(getter_Copies(path));
r->GetPath(path);
r->GetKind(&kind);
r->GetUnits(&units);
r->GetAmount(&amount);
r->GetDescription(getter_Copies(desc));
r->GetDescription(desc);
MemoryReport memreport(process, path, kind, units, amount, desc);
reports.AppendElement(memreport);
@ -377,13 +377,13 @@ ContentChild::RecvPMemoryReportRequestConstructor(PMemoryReportRequestChild* chi
// one, whereupon the callback will turn each measurement into a
// MemoryReport.
mgr->EnumerateMultiReporters(getter_AddRefs(e));
MemoryReportsWrapper wrappedReports(&reports);
MemoryReportCallback cb(process);
nsRefPtr<MemoryReportsWrapper> wrappedReports =
new MemoryReportsWrapper(&reports);
nsRefPtr<MemoryReportCallback> cb = new MemoryReportCallback(process);
while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) {
nsCOMPtr<nsIMemoryMultiReporter> r;
e->GetNext(getter_AddRefs(r));
r->CollectReports(&cb, &wrappedReports);
r->CollectReports(cb, wrappedReports);
}
child->Send__delete__(child, reports);

View File

@ -89,6 +89,7 @@
<action android:name="org.mozilla.gecko.restart"/>
</intent-filter>
</activity>
#if MOZ_CRASHREPORTER
<activity android:name="CrashReporter"
android:label="@string/crash_reporter_title"
@ -98,5 +99,14 @@
</intent-filter>
</activity>
#endif
<activity android:name="LauncherShortcuts"
android:label="@string/launcher_shortcuts_title">
<!-- This intent-filter allows your shortcuts to be created in the launcher. -->
<intent-filter>
<action android:name="android.intent.action.CREATE_SHORTCUT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -303,7 +303,7 @@ abstract public class GeckoApp
Log.i("GeckoApp", "Intent : ACTION_MAIN");
GeckoAppShell.sendEventToGecko(new GeckoEvent(""));
}
else if (action.equals("org.mozilla.fennec.WEBAPP")) {
else if (action.equals("org.mozilla.gecko.WEBAPP")) {
String uri = intent.getStringExtra("args");
GeckoAppShell.sendEventToGecko(new GeckoEvent(uri));
Log.i("GeckoApp","Intent : WEBAPP - " + uri);

View File

@ -678,7 +678,7 @@ public class GeckoAppShell
Log.w("GeckoAppJava", "installWebApplication for " + aURI + " [" + aTitle + "]");
// the intent to be launched by the shortcut
Intent shortcutIntent = new Intent("org.mozilla.fennec.WEBAPP");
Intent shortcutIntent = new Intent("org.mozilla.gecko.WEBAPP");
shortcutIntent.setClassName(GeckoApp.mAppContext,
GeckoApp.mAppContext.getPackageName() + ".App");
shortcutIntent.putExtra("args", "--webapp=" + aURI);

View File

@ -0,0 +1,184 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com>
* Wes Johnston <wjohnston@mozilla.com>
* Mark Finkle <mfinkle@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#filter substitution
package @ANDROID_PACKAGE_NAME@;
import java.io.*;
import org.mozilla.gecko.*;
import android.os.*;
import android.content.*;
import android.app.*;
import android.text.*;
import android.util.*;
import android.widget.*;
import android.database.sqlite.*;
import android.database.*;
import android.view.*;
import android.net.Uri;
import android.graphics.*;
public class LauncherShortcuts extends ListActivity {
public static final String CREATE_SHORTCUT = "org.mozilla.gecko.CREATE_SHORTCUT";
public class LauncherCursorAdapter extends SimpleCursorAdapter {
private Cursor _cursor;
private Context _context;
public LauncherCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
// Using the older, deprecated constructor so we can work on API < 11
super(context, layout, c, from, to);
_cursor = c;
_context = context;
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
ImageView imageView = (ImageView) view.findViewById(R.id.favicon);
String favicon = cursor.getString(3);
byte[] raw = Base64.decode(favicon.substring(22), Base64.DEFAULT);
Bitmap bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeByteArray(raw, 0, raw.length), 48, 48, true);
imageView.setImageBitmap(bitmap);
super.bindView(view, context, cursor);
}
}
private Cursor getCursor(Context context) {
File home = new File(context.getFilesDir(), "mozilla");
if (!home.exists())
return null;
File profile = null;
String[] files = home.list();
for (int i = 0; i < files.length; i++) {
if (files[i].endsWith(".default")) {
profile = new File(home, files[i]);
break;
}
}
if (profile == null)
return null;
File webapps = new File(profile, "webapps.sqlite");
if (!webapps.exists())
return null;
Log.i("LauncherShortcuts", "Opening: " + webapps.getPath());
mDb = SQLiteDatabase.openDatabase(webapps.getPath(), null, SQLiteDatabase.OPEN_READONLY | SQLiteDatabase.NO_LOCALIZED_COLLATORS);
return mDb.rawQuery("SELECT rowid as _id, title, uri, icon FROM webapps", null);
}
private Cursor mCursor;
private SQLiteDatabase mDb;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.launch_app_list);
final Intent intent = getIntent();
final String action = intent.getAction();
if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) {
mCursor = getCursor(this);
if (mCursor != null) {
// After selecting an item, the empty view can flash on screen. Clear
// the text so we don't see it.
TextView emptyText = (TextView)findViewById(android.R.id.empty);
emptyText.setText("");
// Load the list using a custom adapter so we can create the bitmaps
ListAdapter adapter = new LauncherCursorAdapter(
this,
R.layout.launch_app_listitem,
mCursor,
new String[] {"title"},
new int[] {R.id.title}
);
setListAdapter(adapter);
}
}
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
mCursor.moveToPosition(position);
Intent shortcutintent = new Intent("org.mozilla.gecko.WEBAPP");
shortcutintent.setClass(this, App.class);
shortcutintent.putExtra("args", "--webapp=" + mCursor.getString(2));
Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, mCursor.getString(1));
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutintent);
String favicon = mCursor.getString(3);
byte[] raw = Base64.decode(favicon.substring(22), Base64.DEFAULT);
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int size;
switch (dm.densityDpi) {
case DisplayMetrics.DENSITY_MEDIUM:
size = 48;
break;
case DisplayMetrics.DENSITY_HIGH:
size = 72;
break;
default:
size = 72;
}
Bitmap bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeByteArray(raw, 0, raw.length), size, size, true);
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, bitmap);
// Now, return the result to the launcher
setResult(RESULT_OK, intent);
mDb.close();
mCursor.close();
finish();
}
}

View File

@ -59,6 +59,7 @@ PROCESSEDJAVAFILES = \
App.java \
Restarter.java \
NotificationHandler.java \
LauncherShortcuts.java \
$(NULL)
@ -116,6 +117,8 @@ RES_LAYOUT = \
res/layout/notification_progress.xml \
res/layout/notification_progress_text.xml \
res/layout/notification_icon_text.xml \
res/layout/launch_app_list.xml \
res/layout/launch_app_listitem.xml \
$(NULL)
RES_VALUES = res/values/colors.xml res/values/themes.xml

View File

@ -16,3 +16,6 @@
<!ENTITY sending_crash_report "Sending crash report\u2026">
<!ENTITY exit_label "Exit">
<!ENTITY continue_label "Continue">
<!ENTITY launcher_shortcuts_title "&brandShortName; Web Apps">
<!ENTITY launcher_shortcuts_empty "No web apps were found">

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="3dip"
android:orientation="vertical"
android:windowIsFloating="true">
<ListView android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawSelectorOnTop="false"/>
<TextView android:id="@android:id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/launcher_shortcuts_empty"/>
</LinearLayout>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="6dip"
android:orientation="horizontal">
<ImageView
android:id="@+id/favicon"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginRight="6dip"/>
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"/>
</LinearLayout>

View File

@ -21,4 +21,7 @@
<string name="sending_crash_report">&sending_crash_report;</string>
<string name="exit_label">&exit_label;</string>
<string name="continue_label">&continue_label;</string>
<string name="launcher_shortcuts_title">&launcher_shortcuts_title;</string>
<string name="launcher_shortcuts_empty">&launcher_shortcuts_empty;</string>
</resources>

View File

@ -626,6 +626,10 @@ public:
/*
* Create a path builder with the specified fillmode.
*
* We need the fill mode up front because of Direct2D.
* ID2D1SimplifiedGeometrySink requires the fill mode
* to be set before calling BeginFigure().
*/
virtual TemporaryRef<PathBuilder> CreatePathBuilder(FillRule aFillRule = FILL_WINDING) const = 0;

View File

@ -366,19 +366,21 @@ ShadowCanvasLayerOGL::RenderLayer(int aPreviousFrameBuffer,
{
mOGLManager->MakeCurrent();
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexImage->Texture());
ColorTextureLayerProgram *program =
mOGLManager->GetColorTextureLayerProgram(mTexImage->GetShaderProgramType());
ApplyFilter(mFilter);
program->Activate();
program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0), mTexImage->GetSize()));
program->SetLayerTransform(GetEffectiveTransform());
program->SetLayerOpacity(GetEffectiveOpacity());
program->SetRenderOffset(aOffset);
program->SetTextureUnit(0);
mOGLManager->BindAndDrawQuad(program, mNeedsYFlip ? true : false);
mTexImage->BeginTileIteration();
do {
TextureImage::ScopedBindTexture texBind(mTexImage, LOCAL_GL_TEXTURE0);
program->SetLayerQuadRect(mTexImage->GetTileRect());
mOGLManager->BindAndDrawQuad(program, mNeedsYFlip); // FIXME flip order of tiles?
} while (mTexImage->NextTile());
}

View File

@ -938,20 +938,20 @@ ShadowImageLayerOGL::RenderLayer(int aPreviousFrameBuffer,
{
mOGLManager->MakeCurrent();
LayerProgram* program;
if (mTexImage) {
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexImage->Texture());
ColorTextureLayerProgram *colorProgram =
mOGLManager->GetColorTextureLayerProgram(mTexImage->GetShaderProgramType());
ApplyFilter(mFilter);
colorProgram->Activate();
colorProgram->SetTextureUnit(0);
colorProgram->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0), mTexImage->GetSize()));
program = colorProgram;
mTexImage->BeginTileIteration();
do {
TextureImage::ScopedBindTexture texBind(mTexImage, LOCAL_GL_TEXTURE0);
ApplyFilter(mFilter);
colorProgram->SetLayerQuadRect(mTexImage->GetTileRect());
mOGLManager->BindAndDrawQuad(colorProgram);
} while (mTexImage->NextTile());
} else {
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mYUVTexture[0].GetTextureID());
@ -962,7 +962,7 @@ ShadowImageLayerOGL::RenderLayer(int aPreviousFrameBuffer,
gl()->fActiveTexture(LOCAL_GL_TEXTURE2);
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mYUVTexture[2].GetTextureID());
ApplyFilter(mFilter);
YCbCrTextureLayerProgram *yuvProgram = mOGLManager->GetYCbCrLayerProgram();
yuvProgram->Activate();
@ -970,24 +970,14 @@ ShadowImageLayerOGL::RenderLayer(int aPreviousFrameBuffer,
mPictureRect.width,
mPictureRect.height));
yuvProgram->SetYCbCrTextureUnits(0, 1, 2);
yuvProgram->SetLayerTransform(GetEffectiveTransform());
yuvProgram->SetLayerOpacity(GetEffectiveOpacity());
yuvProgram->SetRenderOffset(aOffset);
program = yuvProgram;
program->SetLayerTransform(GetEffectiveTransform());
program->SetLayerOpacity(GetEffectiveOpacity());
program->SetRenderOffset(aOffset);
mOGLManager->BindAndDrawQuadWithTextureRect(program,
mOGLManager->BindAndDrawQuadWithTextureRect(yuvProgram,
mPictureRect,
nsIntSize(mSize.width, mSize.height));
return;
}
program->SetLayerTransform(GetEffectiveTransform());
program->SetLayerOpacity(GetEffectiveOpacity());
program->SetRenderOffset(aOffset);
mOGLManager->BindAndDrawQuad(program);
}
}

View File

@ -141,10 +141,6 @@ ThebesLayerBufferOGL::RenderTo(const nsIntPoint& aOffset,
mTexImageOnWhite->EndUpdate();
}
// Bind textures.
TextureImage::ScopedBindTexture texBind(mTexImage, LOCAL_GL_TEXTURE0);
TextureImage::ScopedBindTexture texOnWhiteBind(mTexImageOnWhite, LOCAL_GL_TEXTURE1);
PRInt32 passes = mTexImageOnWhite ? 2 : 1;
for (PRInt32 pass = 1; pass <= passes; ++pass) {
LayerProgram *program;
@ -194,17 +190,42 @@ ThebesLayerBufferOGL::RenderTo(const nsIntPoint& aOffset,
} else {
renderRegion = &visibleRegion;
}
nsIntRegionRectIterator iter(*renderRegion);
while (const nsIntRect *iterRect = iter.Next()) {
nsIntRect quadRect = *iterRect;
program->SetLayerQuadRect(quadRect);
quadRect.MoveBy(-GetOriginOffset());
aManager->BindAndDrawQuadWithTextureRect(program, quadRect,
mTexImage->GetSize(),
mTexImage->GetWrapMode());
mTexImage->BeginTileIteration();
if (mTexImageOnWhite) {
mTexImageOnWhite->BeginTileIteration();
NS_ASSERTION(mTexImageOnWhite->GetTileRect() == mTexImage->GetTileRect(), "component alpha textures should be the same size.");
}
nsIntRegion region(*renderRegion);
nsIntPoint origin = GetOriginOffset();
region.MoveBy(-origin); // translate into TexImage space, buffer origin might not be at texture (0,0)
do {
nsIntRect textureRect = mTexImage->GetTileRect();
textureRect.MoveBy(region.GetBounds().x, region.GetBounds().y);
nsIntRegion subregion(region);
subregion.And(region, textureRect); // region this texture is visible in
if (subregion.IsEmpty()) {
continue;
}
// Bind textures.
TextureImage::ScopedBindTexture texBind(mTexImage, LOCAL_GL_TEXTURE0);
TextureImage::ScopedBindTexture texOnWhiteBind(mTexImageOnWhite, LOCAL_GL_TEXTURE1);
nsIntRegionRectIterator iter(subregion);
while (const nsIntRect *iterRect = iter.Next()) {
nsIntRect regionRect = *iterRect; // one rectangle of this texture's region
// translate into the correct place for this texture sub-region
nsIntRect screenRect = regionRect;
screenRect.MoveBy(origin);
program->SetLayerQuadRect(screenRect);
regionRect.MoveBy(-mTexImage->GetTileRect().TopLeft()); // get region of tile
aManager->BindAndDrawQuadWithTextureRect(program, regionRect,
textureRect.Size(),
mTexImage->GetWrapMode());
}
} while (mTexImage->NextTile());
}
if (mTexImageOnWhite) {

View File

@ -130,6 +130,12 @@ public:
* overflow area is required by the native widget. Otherwise it will
* fill in aResult with the desired overflow area, in appunits, relative
* to the frame origin, and return PR_TRUE.
*
* This overflow area is used to determine what area needs to be
* repainted when the widget changes. However, it does not affect the
* widget's size or what area is reachable by scrollbars. (In other
* words, in layout terms, it affects visual overflow but not
* scrollable overflow.)
*/
virtual PRBool GetWidgetOverflow(nsDeviceContext* aContext,
nsIFrame* aFrame,

View File

@ -52,6 +52,7 @@
#include "GLContextProvider.h"
#include "gfxCrashReporterUtils.h"
#include "gfxUtils.h"
#include "mozilla/Util.h" // for DebugOnly
@ -636,7 +637,7 @@ void
BasicTextureImage::BindTexture(GLenum aTextureUnit)
{
mGLContext->fActiveTexture(aTextureUnit);
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, Texture());
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
}
@ -659,7 +660,7 @@ BasicTextureImage::FinishedSurfaceUpload()
}
bool
BasicTextureImage::DirectUpdate(gfxASurface *aSurf, const nsIntRegion& aRegion)
BasicTextureImage::DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom /* = nsIntPoint(0, 0) */)
{
nsIntRect bounds = aRegion.GetBounds();
nsIntRegion region;
@ -675,7 +676,7 @@ BasicTextureImage::DirectUpdate(gfxASurface *aSurf, const nsIntRegion& aRegion)
region,
mTexture,
mTextureState == Created,
bounds.TopLeft(),
bounds.TopLeft() + aFrom,
PR_FALSE);
mTextureState = Valid;
return true;
@ -702,6 +703,202 @@ BasicTextureImage::Resize(const nsIntSize& aSize)
mSize = aSize;
}
TiledTextureImage::TiledTextureImage(GLContext* aGL,
nsIntSize aSize,
TextureImage::ContentType aContentType,
PRBool aUseNearestFilter)
: TextureImage(aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, aUseNearestFilter)
, mCurrentImage(0)
, mInUpdate(PR_FALSE)
, mGL(aGL)
, mUseNearestFilter(aUseNearestFilter)
, mTextureState(Created)
{
mTileSize = mGL->GetMaxTextureSize();
if (aSize != nsIntSize(0,0)) {
Resize(aSize);
}
}
TiledTextureImage::~TiledTextureImage()
{
}
bool
TiledTextureImage::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;
}
PRBool result = PR_TRUE;
for (unsigned i = 0; i < mImages.Length(); i++) {
unsigned int xPos = (i % mColumns) * mTileSize;
unsigned int yPos = (i / mColumns) * mTileSize;
nsIntRegion tileRegion;
tileRegion.And(region, nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize())); // intersect with tile
if (tileRegion.IsEmpty())
continue;
tileRegion.MoveBy(-xPos, -yPos); // translate into tile local space
result &= mImages[i]->DirectUpdate(aSurf,
tileRegion,
aFrom + nsIntPoint(xPos, yPos));
}
mShaderType = mImages[0]->GetShaderProgramType();
mIsRGBFormat = mImages[0]->IsRGB();
mTextureState = Valid;
return result;
}
gfxASurface*
TiledTextureImage::BeginUpdate(nsIntRegion& aRegion)
{
NS_ASSERTION(!mInUpdate, "nested update");
mInUpdate = PR_TRUE;
if (mTextureState != Valid)
{
// if the texture hasn't been initialized yet, or something important
// changed, we need to recreate our backing surface and force the
// client to paint everything
mUpdateRegion = nsIntRect(nsIntPoint(0, 0), mSize);
} else {
mUpdateRegion = aRegion;
}
for (unsigned i = 0; i < mImages.Length(); i++) {
unsigned int xPos = (i % mColumns) * mTileSize;
unsigned int yPos = (i / mColumns) * mTileSize;
nsIntRegion imageRegion = nsIntRegion(nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize()));
// a single Image can handle this update request
if (imageRegion.Contains(aRegion)) {
// adjust for tile offset
aRegion.MoveBy(-xPos, -yPos);
// forward the actual call
nsRefPtr<gfxASurface> surface = mImages[i]->BeginUpdate(aRegion);
// caller expects container space
aRegion.MoveBy(xPos, yPos);
// we don't have a temp surface
mUpdateSurface = nsnull;
// remember which image to EndUpdate
mCurrentImage = i;
return surface.get();
}
}
// update covers multiple Images - create a temp surface to paint in
gfxASurface::gfxImageFormat format =
(GetContentType() == gfxASurface::CONTENT_COLOR) ?
gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32;
nsIntRect bounds = aRegion.GetBounds();
mUpdateSurface = gfxPlatform::GetPlatform()->
CreateOffscreenSurface(gfxIntSize(bounds.width, bounds.height), gfxASurface::ContentFromFormat(format));
mUpdateSurface->SetDeviceOffset(gfxPoint(-bounds.x, -bounds.y));
return mUpdateSurface;
}
void
TiledTextureImage::EndUpdate()
{
NS_ASSERTION(mInUpdate, "EndUpdate not in update");
if (!mUpdateSurface) { // update was to a single TextureImage
mImages[mCurrentImage]->EndUpdate();
mInUpdate = PR_FALSE;
mTextureState = Valid;
mShaderType = mImages[mCurrentImage]->GetShaderProgramType();
mIsRGBFormat = mImages[mCurrentImage]->IsRGB();
return;
}
// upload tiles from temp surface
for (unsigned i = 0; i < mImages.Length(); i++) {
unsigned int xPos = (i % mColumns) * mTileSize;
unsigned int yPos = (i / mColumns) * mTileSize;
nsIntRect imageRect = nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize());
nsIntRegion subregion;
subregion.And(mUpdateRegion, imageRect);
if (subregion.IsEmpty())
continue;
subregion.MoveBy(-xPos, -yPos); // Tile-local space
// copy tile from temp surface
gfxASurface* surf = mImages[i]->BeginUpdate(subregion);
nsRefPtr<gfxContext> ctx = new gfxContext(surf);
gfxUtils::ClipToRegion(ctx, subregion);
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->SetSource(mUpdateSurface, gfxPoint(-xPos, -yPos));
ctx->Paint();
mImages[i]->EndUpdate();
}
mUpdateSurface = nsnull;
mInUpdate = PR_FALSE;
mShaderType = mImages[0]->GetShaderProgramType();
mIsRGBFormat = mImages[0]->IsRGB();
}
void TiledTextureImage::BeginTileIteration()
{
mCurrentImage = 0;
}
PRBool TiledTextureImage::NextTile()
{
if (mCurrentImage + 1 < mImages.Length()) {
mCurrentImage++;
return PR_TRUE;
}
return PR_FALSE;
}
nsIntRect TiledTextureImage::GetTileRect()
{
nsIntRect rect = mImages[mCurrentImage]->GetTileRect();
unsigned int xPos = (mCurrentImage % mColumns) * mTileSize;
unsigned int yPos = (mCurrentImage / mColumns) * mTileSize;
rect.MoveTo(xPos, yPos);
return rect;
}
void
TiledTextureImage::BindTexture(GLenum aTextureUnit)
{
mImages[mCurrentImage]->BindTexture(aTextureUnit);
}
/*
* simple resize, just discards everything. we can be more clever just
* adding or discarding tiles, but do we want this?
*/
void TiledTextureImage::Resize(const nsIntSize& aSize)
{
if (mSize == aSize && mTextureState != Created) {
return;
}
mSize = aSize;
mImages.Clear();
// calculate rows and columns, rounding up
mColumns = (aSize.width + mTileSize - 1) / mTileSize;
mRows = (aSize.height + mTileSize - 1) / mTileSize;
for (unsigned int row = 0; row < mRows; row++) {
for (unsigned int col = 0; col < mColumns; col++) {
nsIntSize size( // use tilesize first, then the remainder
(col+1) * mTileSize > (unsigned int)aSize.width ? aSize.width % mTileSize : mTileSize,
(row+1) * mTileSize > (unsigned int)aSize.height ? aSize.height % mTileSize : mTileSize);
nsRefPtr<TextureImage> teximg =
mGL->TileGenFunc(size, mContentType, mUseNearestFilter);
mImages.AppendElement(teximg.forget());
}
}
mTextureState = Allocated;
}
PRBool
GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize)
{
@ -1245,6 +1442,9 @@ GLContext::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect,
NS_ASSERTION(!aSrc->InUpdate(), "Source texture is in update!");
NS_ASSERTION(!aDst->InUpdate(), "Destination texture is in update!");
if (aSrcRect.IsEmpty() || aDstRect.IsEmpty())
return;
// only save/restore this stuff on Qualcomm Adreno, to work
// around an apparent bug
int savedFb = 0;
@ -1255,57 +1455,114 @@ GLContext::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect,
fDisable(LOCAL_GL_SCISSOR_TEST);
fDisable(LOCAL_GL_BLEND);
SetBlitFramebufferForDestTexture(aDst->Texture());
// 2.0 means scale up by two
float blitScaleX = float(aDstRect.width) / float(aSrcRect.width);
float blitScaleY = float(aDstRect.height) / float(aSrcRect.height);
UseBlitProgram();
// We start iterating over all destination tiles
aDst->BeginTileIteration();
do {
// calculate portion of the tile that is going to be painted to
nsIntRect dstSubRect;
nsIntRect dstTextureRect = aDst->GetTileRect();
dstSubRect.IntersectRect(aDstRect, dstTextureRect);
nsIntSize srcSize = aSrc->GetSize();
nsIntSize dstSize = aDst->GetSize();
// this tile is not part of the destination rectangle aDstRect
if (dstSubRect.IsEmpty())
continue;
PushViewportRect(nsIntRect(0, 0, dstSize.width, dstSize.height));
// (*) transform the rect of this tile into the rectangle defined by aSrcRect...
nsIntRect dstInSrcRect(dstSubRect);
dstInSrcRect.MoveBy(-aDstRect.TopLeft());
// ...which might be of different size, hence scale accordingly
dstInSrcRect.ScaleRoundOut(1.0f / blitScaleX, 1.0f / blitScaleY);
dstInSrcRect.MoveBy(aSrcRect.TopLeft());
float dx0 = 2.0 * float(aDstRect.x) / float(dstSize.width) - 1.0;
float dy0 = 2.0 * float(aDstRect.y) / float(dstSize.height) - 1.0;
float dx1 = 2.0 * float(aDstRect.x + aDstRect.width) / float(dstSize.width) - 1.0;
float dy1 = 2.0 * float(aDstRect.y + aDstRect.height) / float(dstSize.height) - 1.0;
SetBlitFramebufferForDestTexture(aDst->GetTextureID());
UseBlitProgram();
RectTriangles rects;
if (aSrc->GetWrapMode() == LOCAL_GL_REPEAT) {
rects.addRect(/* dest rectangle */
dx0, dy0, dx1, dy1,
/* tex coords */
aSrcRect.x / float(srcSize.width),
aSrcRect.y / float(srcSize.height),
aSrcRect.XMost() / float(srcSize.width),
aSrcRect.YMost() / float(srcSize.height));
} else {
DecomposeIntoNoRepeatTriangles(aSrcRect, srcSize, rects);
aSrc->BeginTileIteration();
// now iterate over all tiles in the source Image...
do {
// calculate portion of the source tile that is in the source rect
nsIntRect srcSubRect;
nsIntRect srcTextureRect = aSrc->GetTileRect();
srcSubRect.IntersectRect(aSrcRect, srcTextureRect);
// now put the coords into the d[xy]0 .. d[xy]1 coordinate space
// from the 0..1 that it comes out of decompose
RectTriangles::vert_coord* v = (RectTriangles::vert_coord*)rects.vertexPointer();
for (int i = 0; i < rects.elements(); ++i) {
v[i].x = (v[i].x * (dx1 - dx0)) + dx0;
v[i].y = (v[i].y * (dy1 - dy0)) + dy0;
}
}
// this tile is not part of the source rect
if (srcSubRect.IsEmpty()) {
continue;
}
// calculate intersection of source rect with destination rect
srcSubRect.IntersectRect(srcSubRect, dstInSrcRect);
// this tile does not overlap the current destination tile
if (srcSubRect.IsEmpty()) {
continue;
}
// We now have the intersection of
// the current source tile
// and the desired source rectangle
// and the destination tile
// and the desired destination rectange
// in destination space.
// We need to transform this back into destination space, inverting the transform from (*)
nsIntRect srcSubInDstRect(srcSubRect);
srcSubInDstRect.MoveBy(-aSrcRect.TopLeft());
srcSubInDstRect.ScaleRoundOut(blitScaleX, blitScaleY);
srcSubInDstRect.MoveBy(aDstRect.TopLeft());
// we transform these rectangles to be relative to the current src and dst tiles, respectively
nsIntSize srcSize = srcTextureRect.Size();
nsIntSize dstSize = dstTextureRect.Size();
srcSubRect.MoveBy(-srcTextureRect.x, -srcTextureRect.y);
srcSubInDstRect.MoveBy(-dstTextureRect.x, -dstTextureRect.y);
fActiveTexture(LOCAL_GL_TEXTURE0);
fBindTexture(LOCAL_GL_TEXTURE_2D, aSrc->Texture());
float dx0 = 2.0 * float(srcSubInDstRect.x) / float(dstSize.width) - 1.0;
float dy0 = 2.0 * float(srcSubInDstRect.y) / float(dstSize.height) - 1.0;
float dx1 = 2.0 * float(srcSubInDstRect.x + srcSubInDstRect.width) / float(dstSize.width) - 1.0;
float dy1 = 2.0 * float(srcSubInDstRect.y + srcSubInDstRect.height) / float(dstSize.height) - 1.0;
PushViewportRect(nsIntRect(0, 0, dstSize.width, dstSize.height));
fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
RectTriangles rects;
if (aSrc->GetWrapMode() == LOCAL_GL_REPEAT) {
rects.addRect(/* dest rectangle */
dx0, dy0, dx1, dy1,
/* tex coords */
srcSubRect.x / float(srcSize.width),
srcSubRect.y / float(srcSize.height),
srcSubRect.XMost() / float(srcSize.width),
srcSubRect.YMost() / float(srcSize.height));
} else {
DecomposeIntoNoRepeatTriangles(srcSubRect, srcSize, rects);
fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.vertexPointer());
fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.texCoordPointer());
// now put the coords into the d[xy]0 .. d[xy]1 coordinate space
// from the 0..1 that it comes out of decompose
RectTriangles::vert_coord* v = (RectTriangles::vert_coord*)rects.vertexPointer();
fEnableVertexAttribArray(0);
fEnableVertexAttribArray(1);
for (unsigned int i = 0; i < rects.elements(); ++i) {
v[i].x = (v[i].x * (dx1 - dx0)) + dx0;
v[i].y = (v[i].y * (dy1 - dy0)) + dy0;
}
}
fDrawArrays(LOCAL_GL_TRIANGLES, 0, rects.elements());
TextureImage::ScopedBindTexture texBind(aSrc, LOCAL_GL_TEXTURE0);
fDisableVertexAttribArray(0);
fDisableVertexAttribArray(1);
fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.vertexPointer());
fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.texCoordPointer());
fEnableVertexAttribArray(0);
fEnableVertexAttribArray(1);
fDrawArrays(LOCAL_GL_TRIANGLES, 0, rects.elements());
fDisableVertexAttribArray(0);
fDisableVertexAttribArray(1);
PopViewportRect();
} while (aSrc->NextTile());
} while (aDst->NextTile());
fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, NULL);
fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, NULL);
@ -1325,8 +1582,6 @@ GLContext::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect,
fEnable(LOCAL_GL_SCISSOR_TEST);
fEnable(LOCAL_GL_BLEND);
PopViewportRect();
}
static unsigned int

View File

@ -75,8 +75,12 @@ typedef char realGLboolean;
#include "GLContextSymbols.h"
namespace mozilla {
namespace gl {
namespace layers {
class LayerManagerOGL;
class ColorTextureLayerProgram;
};
namespace gl {
class GLContext;
class LibrarySymbolLoader
@ -156,6 +160,13 @@ class TextureImage
{
NS_INLINE_DECL_REFCOUNTING(TextureImage)
public:
enum TextureState
{
Created, // Texture created, but has not had glTexImage called to initialize it.
Allocated, // Texture memory exists, but contents are invalid.
Valid // Texture fully ready to use.
};
typedef gfxASurface::gfxContentType ContentType;
virtual ~TextureImage() {}
@ -191,6 +202,22 @@ public:
*/
virtual void EndUpdate() = 0;
/**
* The Image may contain several textures for different regions (tiles).
* These functions iterate over each sub texture image tile.
*/
virtual void BeginTileIteration() {
};
virtual PRBool NextTile() {
return PR_FALSE;
};
virtual nsIntRect GetTileRect() {
return nsIntRect(nsIntPoint(0,0), mSize);
};
virtual GLuint GetTextureID() = 0;
/**
* Set this TextureImage's size, and ensure a texture has been
* allocated. Must not be called between BeginUpdate and EndUpdate.
@ -206,7 +233,12 @@ public:
EndUpdate();
}
virtual bool DirectUpdate(gfxASurface *aSurf, const nsIntRegion& aRegion) =0;
/**
* aSurf - the source surface to update from
* aRegion - the region in this image to update
* aFrom - offset in the source to update from
*/
virtual bool DirectUpdate(gfxASurface *aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom = nsIntPoint(0,0)) = 0;
virtual void BindTexture(GLenum aTextureUnit) = 0;
virtual void ReleaseTexture() {};
@ -233,16 +265,6 @@ public:
TextureImage *mTexture;
};
/**
* Return this TextureImage's texture ID for use with GL APIs.
* Callers are responsible for properly binding the texture etc.
*
* The texture is only texture complete after either Resize
* or a matching pair of BeginUpdate/EndUpdate have been called.
* Otherwise, a texture ID may be returned, but the texture
* may not be texture complete.
*/
GLuint Texture() { return mTexture; }
/**
* Returns the shader program type that should be used to render
@ -279,17 +301,15 @@ protected:
* TextureImage from GLContext::CreateTextureImage(). That is,
* clients must not be given partially-constructed TextureImages.
*/
TextureImage(GLuint aTexture, const nsIntSize& aSize,
TextureImage(const nsIntSize& aSize,
GLenum aWrapMode, ContentType aContentType,
PRBool aIsRGB = PR_FALSE)
: mTexture(aTexture)
, mSize(aSize)
: mSize(aSize)
, mWrapMode(aWrapMode)
, mContentType(aContentType)
, mIsRGBFormat(aIsRGB)
{}
GLuint mTexture;
nsIntSize mSize;
GLenum mWrapMode;
ContentType mContentType;
@ -318,25 +338,19 @@ public:
GLenum aWrapMode,
ContentType aContentType,
GLContext* aContext)
: TextureImage(aTexture, aSize, aWrapMode, aContentType)
: TextureImage(aSize, aWrapMode, aContentType)
, mTexture(aTexture)
, mTextureState(Created)
, mGLContext(aContext)
, mUpdateOffset(0, 0)
{}
enum TextureState
{
Created, // Texture created, but has not had glTexImage called to initialize it.
Allocated, // Texture memory exists, but contents are invalid.
Valid // Texture fully ready to use.
};
virtual void BindTexture(GLenum aTextureUnit);
virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion);
virtual void EndUpdate();
virtual bool DirectUpdate(gfxASurface *aSurf, const nsIntRegion& aRegion);
virtual bool DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom = nsIntPoint(0,0));
virtual GLuint GetTextureID() { return mTexture; };
// Returns a surface to draw into
virtual already_AddRefed<gfxASurface>
GetSurfaceForUpdate(const gfxIntSize& aSize, ImageFormat aFmt);
@ -354,6 +368,7 @@ public:
virtual void Resize(const nsIntSize& aSize);
protected:
GLuint mTexture;
TextureState mTextureState;
GLContext* mGLContext;
nsRefPtr<gfxASurface> mUpdateSurface;
@ -363,6 +378,47 @@ protected:
nsIntPoint mUpdateOffset;
};
/**
* A container class that complements many sub TextureImages into a big TextureImage.
* Aims to behave just like the real thing.
*/
class TiledTextureImage
: public TextureImage
{
public:
TiledTextureImage(GLContext* aGL, nsIntSize aSize,
TextureImage::ContentType aContentType, PRBool aUseNearestFilter = PR_FALSE);
~TiledTextureImage();
void DumpDiv();
virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion);
virtual void EndUpdate();
virtual void Resize(const nsIntSize& aSize);
virtual void BeginTileIteration();
virtual PRBool NextTile();
virtual nsIntRect GetTileRect();
virtual GLuint GetTextureID() {
return mImages[mCurrentImage]->GetTextureID();
};
virtual bool DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom = nsIntPoint(0,0));
virtual PRBool InUpdate() const { return mInUpdate; };
virtual void BindTexture(GLenum);
protected:
unsigned int mCurrentImage;
nsTArray< nsRefPtr<TextureImage> > mImages;
bool mInUpdate;
nsIntSize mSize;
unsigned int mTileSize;
unsigned int mRows, mColumns;
GLContext* mGL;
PRBool mUseNearestFilter;
// A temporary surface to faciliate cross-tile updates.
nsRefPtr<gfxASurface> mUpdateSurface;
// The region of update requested
nsIntRegion mUpdateRegion;
TextureState mTextureState;
};
struct THEBES_API ContextFormat
{
static const ContextFormat BasicRGBA32Format;
@ -706,6 +762,21 @@ public:
GLenum aWrapMode,
PRBool aUseNearestFilter=PR_FALSE);
/**
* In EGL we want to use Tiled Texture Images, which we return
* from CreateTextureImage above.
* Inside TiledTextureImage we need to create actual images and to
* prevent infinite recursion we need to differentiate the two
* functions.
**/
virtual already_AddRefed<TextureImage>
TileGenFunc(const nsIntSize& aSize,
TextureImage::ContentType aContentType,
PRBool aUseNearestFilter = PR_FALSE)
{
return nsnull;
};
/**
* Read the image data contained in aTexture, and return it as an ImageSurface.
* If GL_RGBA is given as the format, a ImageFormatARGB32 surface is returned.
@ -995,6 +1066,21 @@ protected:
GLint mMaxRenderbufferSize;
public:
/** \returns the first GL error, and guarantees that all GL error flags are cleared,
* i.e. that a subsequent GetError call will return NO_ERROR
*/
GLenum GetAndClearError() {
// the first error is what we want to return
GLenum error = fGetError();
if (error) {
// clear all pending errors
while(fGetError()) {}
}
return error;
}
#ifdef DEBUG
@ -1012,6 +1098,7 @@ protected:
GLenum mGLError;
public:
void BeforeGLCall(const char* glFunction) {
if (mDebugMode) {
// since the static member variable sCurrentGLContext is not thread-local as it should,

View File

@ -821,13 +821,18 @@ public:
{
return sEGLLibrary.fSwapBuffers(EGL_DISPLAY(), mSurface);
}
// GLContext interface - returns Tiled Texture Image in our case
virtual already_AddRefed<TextureImage>
CreateTextureImage(const nsIntSize& aSize,
TextureImage::ContentType aContentType,
GLenum aWrapMode,
PRBool aUseNearestFilter=PR_FALSE);
// a function to generate Tiles for Tiled Texture Image
virtual already_AddRefed<TextureImage>
TileGenFunc(const nsIntSize& aSize,
TextureImage::ContentType aContentType,
PRBool aUseNearestFilter = PR_FALSE);
// hold a reference to the given surface
// for the lifetime of this context.
void HoldSurface(gfxASurface *aSurf) {
@ -1108,7 +1113,8 @@ public:
GLenum aWrapMode,
ContentType aContentType,
GLContext* aContext)
: TextureImage(aTexture, aSize, aWrapMode, aContentType)
: TextureImage(aSize, aWrapMode, aContentType)
, mTexture(aTexture)
, mGLContext(aContext)
, mUpdateFormat(gfxASurface::ImageFormatUnknown)
, mSurface(nsnull)
@ -1302,10 +1308,10 @@ public:
return; // mTexture is bound
}
virtual bool DirectUpdate(gfxASurface *aSurf, const nsIntRegion& aRegion)
virtual bool DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom /* = nsIntPoint(0, 0) */)
{
nsIntRect bounds = aRegion.GetBounds();
nsIntRegion region;
if (!mCreated) {
bounds = nsIntRect(0, 0, mSize.width, mSize.height);
@ -1319,7 +1325,7 @@ public:
if (mUpdateSurface) {
nsRefPtr<gfxContext> ctx = new gfxContext(mUpdateSurface);
gfxUtils::ClipToRegion(ctx, aRegion);
ctx->SetSource(aSurf);
ctx->SetSource(aSurf, gfxPoint(-aFrom.x, -aFrom.y));
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->Paint();
mUpdateSurface = nsnull;
@ -1331,7 +1337,7 @@ public:
region,
mTexture,
!mCreated,
bounds.TopLeft(),
bounds.TopLeft() + aFrom,
PR_FALSE);
}
@ -1342,10 +1348,14 @@ public:
virtual void BindTexture(GLenum aTextureUnit)
{
mGLContext->fActiveTexture(aTextureUnit);
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, Texture());
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
}
virtual GLuint GetTextureID() {
return mTexture;
};
virtual PRBool InUpdate() const { return !!mUpdateSurface; }
virtual void Resize(const nsIntSize& aSize)
@ -1576,6 +1586,7 @@ protected:
nsRefPtr<gfxASurface> mUpdateSurface;
EGLSurface mSurface;
EGLConfig mConfig;
GLuint mTexture;
EGLImageKHR mImageKHR;
PRPackedBool mCreated;
@ -1588,6 +1599,15 @@ GLContextEGL::CreateTextureImage(const nsIntSize& aSize,
TextureImage::ContentType aContentType,
GLenum aWrapMode,
PRBool aUseNearestFilter)
{
nsRefPtr<TextureImage> t = new gl::TiledTextureImage(this, aSize, aContentType);
return t.forget();
};
already_AddRefed<TextureImage>
GLContextEGL::TileGenFunc(const nsIntSize& aSize,
TextureImage::ContentType aContentType,
PRBool aUseNearestFilter)
{
MakeCurrent();
@ -1598,13 +1618,13 @@ GLContextEGL::CreateTextureImage(const nsIntSize& aSize,
fBindTexture(LOCAL_GL_TEXTURE_2D, texture);
nsRefPtr<TextureImageEGL> teximage =
new TextureImageEGL(texture, aSize, aWrapMode, aContentType, this);
new TextureImageEGL(texture, aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, this);
GLint texfilter = aUseNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter);
fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter);
fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, aWrapMode);
fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, aWrapMode);
fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
return teximage.forget();
}

View File

@ -552,11 +552,12 @@ public:
mInUpdate = PR_FALSE;
}
virtual bool DirectUpdate(gfxASurface* aSurface, const nsIntRegion& aRegion)
virtual bool DirectUpdate(gfxASurface* aSurface, const nsIntRegion& aRegion, const nsIntPoint& aFrom)
{
nsRefPtr<gfxContext> ctx = new gfxContext(mUpdateSurface);
gfxUtils::ClipToRegion(ctx, aRegion);
ctx->SetSource(aSurface);
ctx->SetSource(aSurface, aFrom);
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->Paint();
return true;
@ -565,7 +566,7 @@ public:
virtual void BindTexture(GLenum aTextureUnit)
{
mGLContext->fActiveTexture(aTextureUnit);
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, Texture());
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
sGLXLibrary.BindTexImage(mPixmap);
mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
}
@ -583,6 +584,10 @@ public:
virtual PRBool InUpdate() const { return mInUpdate; }
virtual GLuint GetTextureID() {
return mTexture;
};
private:
TextureImageGLX(GLuint aTexture,
const nsIntSize& aSize,
@ -591,11 +596,12 @@ private:
GLContext* aContext,
gfxASurface* aSurface,
GLXPixmap aPixmap)
: TextureImage(aTexture, aSize, aWrapMode, aContentType)
: TextureImage(aSize, aWrapMode, aContentType)
, mGLContext(aContext)
, mUpdateSurface(aSurface)
, mPixmap(aPixmap)
, mInUpdate(PR_FALSE)
, mTexture(aTexture)
{
if (aSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA) {
mShaderType = gl::RGBALayerProgramType;
@ -608,6 +614,7 @@ private:
nsRefPtr<gfxASurface> mUpdateSurface;
GLXPixmap mPixmap;
PRPackedBool mInUpdate;
GLuint mTexture;
};
already_AddRefed<TextureImage>

View File

@ -600,13 +600,13 @@ public:
NS_DECL_ISUPPORTS
NS_IMETHOD GetProcess(char **process) {
*process = strdup("");
NS_IMETHOD GetProcess(nsACString &process) {
process.Truncate();
return NS_OK;
}
NS_IMETHOD GetPath(char **memoryPath) {
*memoryPath = strdup(SurfaceMemoryReporterPathForType(mType));
NS_IMETHOD GetPath(nsACString &path) {
path.Assign(SurfaceMemoryReporterPathForType(mType));
return NS_OK;
}
@ -625,8 +625,8 @@ public:
return NS_OK;
}
NS_IMETHOD GetDescription(char **desc) {
*desc = strdup("Memory used by gfx surface of the given type.");
NS_IMETHOD GetDescription(nsACString &desc) {
desc.AssignLiteral("Memory used by gfx surface of the given type.");
return NS_OK;
}

View File

@ -481,8 +481,10 @@ bool Channel::ChannelImpl::ProcessIncomingMessages() {
// Process messages from input buffer.
const char *p;
const char *overflowp;
const char *end;
if (input_overflow_buf_.empty()) {
overflowp = NULL;
p = input_buf_;
end = p + bytes_read;
} else {
@ -493,7 +495,7 @@ bool Channel::ChannelImpl::ProcessIncomingMessages() {
return false;
}
input_overflow_buf_.append(input_buf_, bytes_read);
p = input_overflow_buf_.data();
overflowp = p = input_overflow_buf_.data();
end = p + input_overflow_buf_.size();
}
@ -571,7 +573,15 @@ bool Channel::ChannelImpl::ProcessIncomingMessages() {
break;
}
}
input_overflow_buf_.assign(p, end - p);
if (end == p) {
input_overflow_buf_.clear();
} else if (!overflowp) {
// p is from input_buf_
input_overflow_buf_.assign(p, end - p);
} else if (p > overflowp) {
// p is from input_overflow_buf_
input_overflow_buf_.erase(0, p - overflowp);
}
input_overflow_fds_ = std::vector<int>(&fds[fds_i], &fds[num_fds]);
// When the input data buffer is empty, the overflow fds should be too. If

View File

@ -40,6 +40,7 @@
#include <math.h>
#include "nsString.h"
#include "nsIMemoryReporter.h"
#include "mozilla/ipc/SharedMemory.h"

View File

@ -150,6 +150,7 @@ CPPSRCS = \
jsgcmark.cpp \
jsgcchunk.cpp \
jsgcstats.cpp \
jscrashreport.cpp \
jshash.cpp \
jsinterp.cpp \
jsinvoke.cpp \
@ -206,6 +207,7 @@ INSTALLED_HEADERS = \
jsclone.h \
jscntxt.h \
jscompat.h \
jscrashreport.h \
jsdate.h \
jsdbgapi.h \
jsdhash.h \

View File

@ -0,0 +1,3 @@
function a() {
with(a) eval("arguments[0]");
} a();

View File

@ -0,0 +1,12 @@
foo = evalcx("(function foo() { foo.bar() })");
foo.bar = evalcx("(function bar() {})");
function fatty() {
try {
fatty();
} catch (e) {
foo();
}
}
fatty();

View File

@ -0,0 +1,15 @@
function foo() {
bar(1,2,3,4,5,6,7,8,9);
}
function bar() {
foo(1,2,3,4,5,6,7,8,9);
}
var caught = false;
try {
foo();
} catch (e) {
caught = true;
}
assertEq(caught, true);

View File

@ -86,6 +86,7 @@ CPPSRCS = \
testXDR.cpp \
testCustomIterator.cpp \
testExternalStrings.cpp \
testChromeBuffer.cpp \
$(NULL)
# Disabled: an entirely unrelated test seems to cause this to fail. Moreover,

View File

@ -0,0 +1,161 @@
#include "tests.h"
JSPrincipals system_principals = {
(char *)"", NULL, NULL, 1, NULL, NULL
};
JSClass global_class = {
"global",
JSCLASS_IS_GLOBAL | JSCLASS_GLOBAL_FLAGS,
JS_PropertyStub,
JS_PropertyStub,
JS_PropertyStub,
JS_StrictPropertyStub,
JS_EnumerateStub,
JS_ResolveStub,
JS_ConvertStub,
JS_FinalizeStub,
JSCLASS_NO_OPTIONAL_MEMBERS
};
JS::Anchor<JSObject *> trusted_glob, trusted_fun;
JSBool
CallTrusted(JSContext *cx, uintN argc, jsval *vp)
{
if (!JS_SaveFrameChain(cx))
return JS_FALSE;
JSBool ok = JS_FALSE;
{
JSAutoEnterCompartment ac;
ok = ac.enter(cx, trusted_glob.get());
if (!ok)
goto out;
ok = JS_CallFunctionValue(cx, NULL, OBJECT_TO_JSVAL(trusted_fun.get()),
0, NULL, vp);
}
out:
JS_RestoreFrameChain(cx);
return ok;
}
BEGIN_TEST(testChromeBuffer)
{
JS_SetTrustedPrincipals(rt, &system_principals);
JSFunction *fun;
JSObject *o;
CHECK(o = JS_NewCompartmentAndGlobalObject(cx, &global_class, &system_principals));
trusted_glob.set(o);
/*
* Check that, even after untrusted content has exhausted the stack, code
* compiled with "trusted principals" can run using reserved trusted-only
* buffer space.
*/
{
{
JSAutoEnterCompartment ac;
CHECK(ac.enter(cx, trusted_glob.get()));
const char *paramName = "x";
const char *bytes = "return x ? 1 + trusted(x-1) : 0";
CHECK(fun = JS_CompileFunctionForPrincipals(cx, trusted_glob.get(), &system_principals,
"trusted", 1, &paramName, bytes, strlen(bytes),
"", 0));
trusted_fun.set(JS_GetFunctionObject(fun));
}
jsval v = OBJECT_TO_JSVAL(trusted_fun.get());
CHECK(JS_WrapValue(cx, &v));
const char *paramName = "trusted";
const char *bytes = "try { "
" return untrusted(trusted); "
"} catch (e) { "
" return trusted(100); "
"} ";
CHECK(fun = JS_CompileFunction(cx, global, "untrusted", 1, &paramName,
bytes, strlen(bytes), "", 0));
jsval rval;
CHECK(JS_CallFunction(cx, NULL, fun, 1, &v, &rval));
CHECK(JSVAL_TO_INT(rval) == 100);
}
/*
* Check that content called from chrome in the reserved-buffer space
* immediately ooms.
*/
{
{
JSAutoEnterCompartment ac;
CHECK(ac.enter(cx, trusted_glob.get()));
const char *paramName = "untrusted";
const char *bytes = "try { "
" untrusted(); "
"} catch (e) { "
" return 'From trusted: ' + e; "
"} ";
CHECK(fun = JS_CompileFunctionForPrincipals(cx, trusted_glob.get(), &system_principals,
"trusted", 1, &paramName, bytes, strlen(bytes),
"", 0));
trusted_fun.set(JS_GetFunctionObject(fun));
}
jsval v = OBJECT_TO_JSVAL(trusted_fun.get());
CHECK(JS_WrapValue(cx, &v));
const char *paramName = "trusted";
const char *bytes = "try { "
" return untrusted(trusted); "
"} catch (e) { "
" return trusted(untrusted); "
"} ";
CHECK(fun = JS_CompileFunction(cx, global, "untrusted", 1, &paramName,
bytes, strlen(bytes), "", 0));
jsval rval;
CHECK(JS_CallFunction(cx, NULL, fun, 1, &v, &rval));
JSBool match;
CHECK(JS_StringEqualsAscii(cx, JSVAL_TO_STRING(rval), "From trusted: InternalError: too much recursion", &match));
CHECK(match);
}
/*
* Check that JS_SaveFrameChain called on the way from content to chrome
* (say, as done by XPCJSContextSTack::Push) works.
*/
{
{
JSAutoEnterCompartment ac;
CHECK(ac.enter(cx, trusted_glob.get()));
const char *bytes = "return 42";
CHECK(fun = JS_CompileFunctionForPrincipals(cx, trusted_glob.get(), &system_principals,
"trusted", 0, NULL, bytes, strlen(bytes),
"", 0));
trusted_fun.set(JS_GetFunctionObject(fun));
}
JSFunction *fun = JS_NewFunction(cx, CallTrusted, 0, 0, global, "callTrusted");
JS::Anchor<JSObject *> callTrusted(JS_GetFunctionObject(fun));
const char *paramName = "f";
const char *bytes = "try { "
" return untrusted(trusted); "
"} catch (e) { "
" return f(); "
"} ";
CHECK(fun = JS_CompileFunction(cx, global, "untrusted", 1, &paramName,
bytes, strlen(bytes), "", 0));
jsval arg = OBJECT_TO_JSVAL(callTrusted.get());
jsval rval;
CHECK(JS_CallFunction(cx, NULL, fun, 1, &arg, &rval));
CHECK(JSVAL_TO_INT(rval) == 42);
}
return true;
}
END_TEST(testChromeBuffer)

View File

@ -637,7 +637,8 @@ static JSBool js_NewRuntimeWasCalled = JS_FALSE;
#endif
JSRuntime::JSRuntime()
: gcChunkAllocator(&defaultGCChunkAllocator)
: gcChunkAllocator(&defaultGCChunkAllocator),
trustedPrincipals_(NULL)
{
/* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
JS_INIT_CLIST(&contextList);
@ -4152,6 +4153,12 @@ JS_GetSecurityCallbacks(JSContext *cx)
: cx->runtime->securityCallbacks;
}
JS_PUBLIC_API(void)
JS_SetTrustedPrincipals(JSRuntime *rt, JSPrincipals *prin)
{
rt->setTrustedPrincipals(prin);
}
JS_PUBLIC_API(JSFunction *)
JS_NewFunction(JSContext *cx, JSNative native, uintN nargs, uintN flags,
JSObject *parent, const char *name)

View File

@ -1183,6 +1183,16 @@ extern JS_PUBLIC_API(JSBool)
JS_SetCTypesCallbacks(JSContext *cx, JSObject *ctypesObj, JSCTypesCallbacks *callbacks);
#endif
typedef JSBool
(* JSEnumerateDiagnosticMemoryCallback)(void *ptr, size_t length);
/*
* Enumerate memory regions that contain diagnostic information
* intended to be included in crash report minidumps.
*/
extern JS_PUBLIC_API(void)
JS_EnumerateDiagnosticMemoryRegions(JSEnumerateDiagnosticMemoryCallback callback);
/*
* Macros to hide interpreter stack layout details from a JSFastNative using
* its jsval *vp parameter. The stack layout underlying invocation can't change
@ -2594,6 +2604,21 @@ JS_SetContextSecurityCallbacks(JSContext *cx, JSSecurityCallbacks *callbacks);
extern JS_PUBLIC_API(JSSecurityCallbacks *)
JS_GetSecurityCallbacks(JSContext *cx);
/*
* Code running with "trusted" principals will be given a deeper stack
* allocation than ordinary scripts. This allows trusted script to run after
* untrusted script has exhausted the stack. This function sets the
* runtime-wide trusted principal.
*
* This principals is not held (via JS_HoldPrincipals/JS_DropPrincipals) since
* there is no available JSContext. Instead, the caller must ensure that the
* given principals stays valid for as long as 'rt' may point to it. If the
* principals would be destroyed before 'rt', JS_SetTrustedPrincipals must be
* called again, passing NULL for 'prin'.
*/
extern JS_PUBLIC_API(void)
JS_SetTrustedPrincipals(JSRuntime *rt, JSPrincipals *prin);
/************************************************************************/
/*

View File

@ -412,6 +412,12 @@ struct JSRuntime {
/* Compartment that is currently involved in per-compartment GC */
JSCompartment *gcCurrentCompartment;
/*
* If this is non-NULL, all marked objects must belong to this compartment.
* This is used to look for compartment bugs.
*/
JSCompartment *gcCheckCompartment;
/*
* We can pack these flags as only the GC thread writes to them. Atomic
* updates to packed bytes are not guaranteed, so stores issued by one
@ -597,6 +603,12 @@ struct JSRuntime {
#define JS_THREAD_DATA(cx) (&(cx)->runtime->threadData)
#endif
private:
JSPrincipals *trustedPrincipals_;
public:
void setTrustedPrincipals(JSPrincipals *p) { trustedPrincipals_ = p; }
JSPrincipals *trustedPrincipals() const { return trustedPrincipals_; }
/*
* Object shape (property cache structural type) identifier generator.
*

111
js/src/jscrashformat.h Normal file
View File

@ -0,0 +1,111 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=4 sw=4 et tw=99:
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
* May 28, 2008.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef jscrashformat_h___
#define jscrashformat_h___
#include <string.h>
namespace js {
namespace crash {
const static int crash_cookie_len = 16;
const static char crash_cookie[crash_cookie_len] = "*J*S*CRASHDATA*";
/* These values are used for CrashHeader::id. */
enum {
JS_CRASH_STACK_GC = 0x400,
JS_CRASH_STACK_ERROR = 0x401,
JS_CRASH_RING = 0x800
};
/*
* All the data here will be stored directly in the minidump, so we use
* platform-independent types. We also ensure that the size of every field is a
* multiple of 8 bytes, to guarantee that they won't be padded.
*/
struct CrashHeader
{
char cookie[crash_cookie_len];
/* id of the crash data, chosen from the enum above. */
uint64 id;
CrashHeader(uint64 id) : id(id) { memcpy(cookie, crash_cookie, crash_cookie_len); }
};
struct CrashRegisters
{
uint64 ip, sp, bp;
};
const static int crash_buffer_size = 32 * 1024;
struct CrashStack
{
CrashStack(uint64 id) : header(id) {}
CrashHeader header;
uint64 snaptime; /* Unix time when the stack was snapshotted. */
CrashRegisters regs; /* Register contents for the snapshot. */
uint64 stack_base; /* Base address of stack at the time of snapshot. */
uint64 stack_len; /* Extent of the stack. */
char stack[crash_buffer_size]; /* Contents of the stack. */
};
struct CrashRing
{
CrashRing(uint64 id) : header(id), offset(0) { memset(buffer, 0, sizeof(buffer)); }
CrashHeader header;
uint64 offset; /* Next byte to be written in the buffer. */
char buffer[crash_buffer_size];
};
/* These are the tag values for each entry in the CrashRing. */
enum {
JS_CRASH_TAG_GC = 0x200
};
} /* namespace crash */
} /* namespace js */
#endif

280
js/src/jscrashreport.cpp Normal file
View File

@ -0,0 +1,280 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=4 sw=4 et tw=99:
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
* May 28, 2008.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "jsapi.h"
#include "jscntxt.h"
#include "jscrashreport.h"
#include "jscrashformat.h"
#include <time.h>
namespace js {
namespace crash {
const static int stack_snapshot_max_size = 32768;
#if defined(XP_WIN)
#include <Windows.h>
static bool
GetStack(uint64 *stack, uint64 *stack_len, CrashRegisters *regs, char *buffer, size_t size)
{
/* Try to figure out how big the stack is. */
char dummy;
MEMORY_BASIC_INFORMATION info;
if (VirtualQuery(reinterpret_cast<LPCVOID>(&dummy), &info, sizeof(info)) == 0)
return false;
if (info.State != MEM_COMMIT)
return false;
/* 256 is a fudge factor to account for the rest of GetStack's frame. */
uint64 p = uint64(&dummy) - 256;
uint64 len = stack_snapshot_max_size;
if (p + len > uint64(info.BaseAddress) + info.RegionSize)
len = uint64(info.BaseAddress) + info.RegionSize - p;
if (len > size)
len = size;
*stack = p;
*stack_len = len;
/* Get the register state. */
#if JS_BITS_PER_WORD == 32
uint32 vip, vsp, vbp;
__asm {
Label:
mov [vbp], ebp;
mov [vsp], esp;
mov eax, [Label];
mov [vip], eax;
}
regs->ip = vip;
regs->sp = vsp;
regs->bp = vbp;
#else
CONTEXT context;
RtlCaptureContext(&context);
regs->ip = context.Rip;
regs->sp = context.Rsp;
regs->bp = context.Rbp;
#endif
memcpy(buffer, (void *)p, len);
return true;
}
#elif defined(__linux__) && (defined(__x86_64__) || defined(__i386__))
#include <unistd.h>
#include <ucontext.h>
#include <sys/mman.h>
static bool
GetStack(uint64 *stack, uint64 *stack_len, CrashRegisters *regs, char *buffer, size_t size)
{
/* 256 is a fudge factor to account for the rest of GetStack's frame. */
char dummy;
uint64 p = uint64(&dummy) - 256;
uint64 pgsz = getpagesize();
uint64 len = stack_snapshot_max_size;
p &= ~(pgsz - 1);
/* Try to figure out how big the stack is. */
while (len > 0) {
if (mlock((const void *)p, len) == 0) {
munlock((const void *)p, len);
break;
}
len -= pgsz;
}
if (len > size)
len = size;
*stack = p;
*stack_len = len;
/* Get the register state. */
ucontext_t context;
if (getcontext(&context) != 0)
return false;
#if JS_BITS_PER_WORD == 64
regs->sp = (uint64)context.uc_mcontext.gregs[REG_RSP];
regs->bp = (uint64)context.uc_mcontext.gregs[REG_RBP];
regs->ip = (uint64)context.uc_mcontext.gregs[REG_RIP];
#elif JS_BITS_PER_WORD == 32
regs->sp = (uint64)context.uc_mcontext.gregs[REG_ESP];
regs->bp = (uint64)context.uc_mcontext.gregs[REG_EBP];
regs->ip = (uint64)context.uc_mcontext.gregs[REG_EIP];
#endif
memcpy(buffer, (void *)p, len);
return true;
}
#else
static bool
GetStack(uint64 *stack, uint64 *stack_len, CrashRegisters *regs, char *buffer, size_t size)
{
return false;
}
#endif
class Stack : private CrashStack
{
public:
Stack(uint64 id);
bool snapshot();
};
Stack::Stack(uint64 id)
: CrashStack(id)
{
}
bool
Stack::snapshot()
{
snaptime = time(NULL);
return GetStack(&stack_base, &stack_len, &regs, stack, sizeof(stack));
}
class Ring : private CrashRing
{
public:
Ring(uint64 id);
void push(uint64 tag, void *data, size_t size);
private:
size_t bufferSize() { return crash_buffer_size; }
void copyBytes(void *data, size_t size);
};
Ring::Ring(uint64 id)
: CrashRing(id)
{
}
void
Ring::push(uint64 tag, void *data, size_t size)
{
uint64 t = time(NULL);
copyBytes(&tag, sizeof(uint64));
copyBytes(&t, sizeof(uint64));
copyBytes(data, size);
uint64 mysize = size;
copyBytes(&mysize, sizeof(uint64));
}
void
Ring::copyBytes(void *data, size_t size)
{
if (size >= bufferSize())
size = bufferSize();
if (offset + size > bufferSize()) {
size_t first = bufferSize() - offset;
size_t second = size - first;
memcpy(&buffer[offset], data, first);
memcpy(buffer, (char *)data + first, second);
offset = second;
} else {
memcpy(&buffer[offset], data, size);
offset += size;
}
}
static bool gInitialized;
static Stack gGCStack(JS_CRASH_STACK_GC);
static Stack gErrorStack(JS_CRASH_STACK_ERROR);
static Ring gRingBuffer(JS_CRASH_RING);
} /* namespace crash */
} /* namespace js */
using namespace js;
using namespace js::crash;
JS_FRIEND_API(void)
js_SnapshotGCStack()
{
if (gInitialized)
gGCStack.snapshot();
}
JS_FRIEND_API(void)
js_SnapshotErrorStack()
{
if (gInitialized)
gErrorStack.snapshot();
}
JS_FRIEND_API(void)
js_SaveCrashData(uint64 tag, void *ptr, size_t size)
{
if (gInitialized)
gRingBuffer.push(tag, ptr, size);
}
JS_PUBLIC_API(void)
JS_EnumerateDiagnosticMemoryRegions(JSEnumerateDiagnosticMemoryCallback callback)
{
#if 1
if (!gInitialized) {
gInitialized = true;
(*callback)(&gGCStack, sizeof(gGCStack));
(*callback)(&gErrorStack, sizeof(gErrorStack));
(*callback)(&gRingBuffer, sizeof(gRingBuffer));
}
#endif
}

59
js/src/jscrashreport.h Normal file
View File

@ -0,0 +1,59 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=4 sw=4 et tw=99:
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
* May 28, 2008.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef jscrashreport_h___
#define jscrashreport_h___
#include "jstypes.h"
JS_BEGIN_EXTERN_C
JS_FRIEND_API(void)
js_SnapshotGCStack();
JS_FRIEND_API(void)
js_SnapshotErrorStack();
JS_FRIEND_API(void)
js_SaveCrashData(uint64 tag, void *ptr, size_t size);
JS_END_EXTERN_C
#endif /* jscrashreport_h___ */

View File

@ -186,7 +186,7 @@ js_GetArgsProperty(JSContext *cx, StackFrame *fp, jsid id, Value *vp)
js::ArgumentsObject *
ArgumentsObject::create(JSContext *cx, uint32 argc, JSObject &callee)
{
JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
JS_ASSERT(argc <= StackSpace::ARGS_LENGTH_MAX);
JSObject *proto;
if (!js_GetClassPrototype(cx, callee.getGlobal(), JSProto_Object, &proto))
@ -242,15 +242,15 @@ JSObject *
js_GetArgsObject(JSContext *cx, StackFrame *fp)
{
/*
* We must be in a function activation; the function must be lightweight
* or else fp must have a variable object.
* Arguments and Call objects are owned by the enclosing non-eval function
* frame, thus any eval frames must be skipped before testing hasArgsObj.
*/
JS_ASSERT_IF(fp->fun()->isHeavyweight(), fp->hasCallObj());
JS_ASSERT(fp->isFunctionFrame());
while (fp->isEvalInFunction())
fp = fp->prev();
/* Create an arguments object for fp only if it lacks one. */
JS_ASSERT_IF(fp->fun()->isHeavyweight(), fp->hasCallObj());
if (fp->hasArgsObj())
return &fp->argsObj();
@ -2119,7 +2119,7 @@ js_fun_apply(JSContext *cx, uintN argc, Value *vp)
LeaveTrace(cx);
/* Step 6. */
uintN n = uintN(JS_MIN(length, JS_ARGS_LENGTH_MAX));
uintN n = uintN(JS_MIN(length, StackSpace::ARGS_LENGTH_MAX));
InvokeArgsGuard args;
if (!cx->stack.pushInvokeArgs(cx, n, &args))
@ -2223,7 +2223,7 @@ CallOrConstructBoundFunction(JSContext *cx, uintN argc, Value *vp)
uintN argslen;
const Value *boundArgs = obj->getBoundFunctionArguments(argslen);
if (argc + argslen > JS_ARGS_LENGTH_MAX) {
if (argc + argslen > StackSpace::ARGS_LENGTH_MAX) {
js_ReportAllocationOverflow(cx);
return false;
}

View File

@ -576,25 +576,6 @@ js_PutArgsObject(js::StackFrame *fp);
inline bool
js_IsNamedLambda(JSFunction *fun) { return (fun->flags & JSFUN_LAMBDA) && fun->atom; }
/*
* Maximum supported value of arguments.length. It bounds the maximum number of
* arguments that can be supplied via the second (so-called |argArray|) param
* to Function.prototype.apply. This value also bounds the number of elements
* parsed in an array initialiser.
*
* The thread's stack is the limiting factor for this number. It is currently
* 2MB, which fits a little less than 2^19 arguments (once the stack frame,
* callstack, etc. are included). Pick a max args length that is a little less.
*/
const uint32 JS_ARGS_LENGTH_MAX = JS_BIT(19) - 1024;
/*
* JSSLOT_ARGS_LENGTH stores ((argc << 1) | overwritten_flag) as an Int32
* Value. Thus (JS_ARGS_LENGTH_MAX << 1) | 1 must be less than JSVAL_INT_MAX.
*/
JS_STATIC_ASSERT(JS_ARGS_LENGTH_MAX <= JS_BIT(30));
JS_STATIC_ASSERT(((JS_ARGS_LENGTH_MAX << 1) | 1) <= JSVAL_INT_MAX);
extern JSBool
js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp);

View File

@ -60,6 +60,8 @@
#include "jsapi.h"
#include "jsatom.h"
#include "jscompartment.h"
#include "jscrashreport.h"
#include "jscrashformat.h"
#include "jscntxt.h"
#include "jsversion.h"
#include "jsdbgapi.h"
@ -239,9 +241,7 @@ Arena::finalize(JSContext *cx)
if (!newFreeSpanStart)
newFreeSpanStart = thing;
t->finalize(cx);
#ifdef DEBUG
memset(t, JS_FREE_PATTERN, sizeof(T));
#endif
}
}
}
@ -2662,6 +2662,12 @@ GCCycle(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIMER_P
(*c)->setGCLastBytes((*c)->gcBytes, gckind);
}
struct GCCrashData
{
int isRegen;
int isCompartment;
};
void
js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
{
@ -2683,6 +2689,11 @@ js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
RecordNativeStackTopForGC(cx);
GCCrashData crashData;
crashData.isRegen = rt->shapeGen & SHAPE_OVERFLOW_BIT;
crashData.isCompartment = !!comp;
js_SaveCrashData(crash::JS_CRASH_TAG_GC, &crashData, sizeof(crashData));
GCTIMER_BEGIN(rt, comp);
do {
@ -2721,6 +2732,8 @@ js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
rt->gcChunkAllocationSinceLastGC = false;
GCTIMER_END(gckind == GC_LAST_CONTEXT);
js_SnapshotGCStack();
}
namespace js {

View File

@ -115,6 +115,12 @@ Mark(JSTracer *trc, T *thing)
JS_ASSERT(thing->arenaHeader()->compartment);
JS_ASSERT(thing->arenaHeader()->compartment->rt == rt);
if (rt->gcCheckCompartment && thing->compartment() != rt->gcCheckCompartment &&
thing->compartment() != rt->atomsCompartment)
{
JS_Assert("compartment mismatch in GC", __FILE__, __LINE__);
}
/*
* Don't mark things outside a compartment if we are in a per-compartment
* GC.
@ -158,6 +164,16 @@ MarkObject(JSTracer *trc, JSObject &obj, const char *name)
Mark(trc, &obj);
}
void
MarkCrossCompartmentObject(JSTracer *trc, JSObject &obj, const char *name)
{
JSRuntime *rt = trc->context->runtime;
if (rt->gcCurrentCompartment && rt->gcCurrentCompartment != obj.compartment())
return;
MarkObject(trc, obj, name);
}
void
MarkObjectWithPrinter(JSTracer *trc, JSObject &obj, JSTraceNamePrinter printer,
const void *arg, size_t index)
@ -351,6 +367,22 @@ MarkValue(JSTracer *trc, const js::Value &v, const char *name)
MarkValueRaw(trc, v);
}
void
MarkCrossCompartmentValue(JSTracer *trc, const js::Value &v, const char *name)
{
if (v.isMarkable()) {
js::gc::Cell *cell = (js::gc::Cell *)v.toGCThing();
unsigned kind = v.gcKind();
if (kind == JSTRACE_STRING && ((JSString *)cell)->isStaticAtom())
return;
JSRuntime *rt = trc->context->runtime;
if (rt->gcCurrentCompartment && cell->compartment() != rt->gcCurrentCompartment)
return;
MarkValue(trc, v, name);
}
}
void
MarkValueRange(JSTracer *trc, Value *beg, Value *end, const char *name)
{
@ -748,6 +780,9 @@ MarkChildren(JSTracer *trc, JSXML *xml)
void
GCMarker::drainMarkStack()
{
JSRuntime *rt = context->runtime;
rt->gcCheckCompartment = rt->gcCurrentCompartment;
while (!isMarkStackEmpty()) {
while (!ropeStack.isEmpty())
ScanRope(this, ropeStack.pop());
@ -772,6 +807,8 @@ GCMarker::drainMarkStack()
markDelayedChildren();
}
}
rt->gcCheckCompartment = NULL;
}
} /* namespace js */

View File

@ -62,6 +62,13 @@ MarkString(JSTracer *trc, JSString *str, const char *name);
void
MarkObject(JSTracer *trc, JSObject &obj, const char *name);
/*
* Mark an object that may be in a different compartment from the compartment
* being GC'd. (Although it won't be marked if it's in the wrong compartment.)
*/
void
MarkCrossCompartmentObject(JSTracer *trc, JSObject &obj, const char *name);
void
MarkObjectWithPrinter(JSTracer *trc, JSObject &obj, JSTraceNamePrinter printer,
const void *arg, size_t index);
@ -102,6 +109,13 @@ MarkValueRaw(JSTracer *trc, const js::Value &v);
void
MarkValue(JSTracer *trc, const js::Value &v, const char *name);
/*
* Mark a value that may be in a different compartment from the compartment
* being GC'd. (Although it won't be marked if it's in the wrong compartment.)
*/
void
MarkCrossCompartmentValue(JSTracer *trc, const js::Value &v, const char *name);
void
MarkValueRange(JSTracer *trc, Value *beg, Value *end, const char *name);

View File

@ -625,7 +625,7 @@ Invoke(JSContext *cx, const CallArgs &argsRef, MaybeConstruct construct)
/* N.B. Must be kept in sync with InvokeSessionGuard::start/invoke */
CallArgs args = argsRef;
JS_ASSERT(args.argc() <= JS_ARGS_LENGTH_MAX);
JS_ASSERT(args.argc() <= StackSpace::ARGS_LENGTH_MAX);
if (args.calleev().isPrimitive()) {
js_ReportIsNotFunction(cx, &args.calleev(), ToReportFlags(construct));
@ -746,7 +746,7 @@ InvokeSessionGuard::start(JSContext *cx, const Value &calleev, const Value &this
/* Hoist dynamic checks from CheckStackAndEnterMethodJIT. */
JS_CHECK_RECURSION(cx, return false);
stackLimit_ = stack.space().getStackLimit(cx);
stackLimit_ = stack.space().getStackLimit(cx, REPORT_ERROR);
if (!stackLimit_)
return false;
@ -4095,7 +4095,7 @@ BEGIN_CASE(JSOP_FUNAPPLY)
}
JSScript *newScript = fun->script();
if (!cx->stack.pushInlineFrame(cx, regs, args, *callee, fun, newScript, construct, OOMCheck()))
if (!cx->stack.pushInlineFrame(cx, regs, args, *callee, fun, newScript, construct))
goto error;
/* Refresh local js::Interpret state. */
@ -5310,7 +5310,7 @@ BEGIN_CASE(JSOP_INITELEM)
if (rref.isMagic(JS_ARRAY_HOLE)) {
JS_ASSERT(obj->isArray());
JS_ASSERT(JSID_IS_INT(id));
JS_ASSERT(jsuint(JSID_TO_INT(id)) < JS_ARGS_LENGTH_MAX);
JS_ASSERT(jsuint(JSID_TO_INT(id)) < StackSpace::ARGS_LENGTH_MAX);
if (js_GetOpcode(cx, script, regs.pc + JSOP_INITELEM_LENGTH) == JSOP_ENDINIT &&
!js_SetLengthProperty(cx, obj, (jsuint) (JSID_TO_INT(id) + 1))) {
goto error;

View File

@ -8302,7 +8302,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot)
matched = tokenStream.matchToken(TOK_RB, TSF_OPERAND);
if (!matched) {
for (index = 0; ; index++) {
if (index == JS_ARGS_LENGTH_MAX) {
if (index == StackSpace::ARGS_LENGTH_MAX) {
reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_ARRAY_INIT_TOO_BIG);
return NULL;
}

View File

@ -980,11 +980,11 @@ static void
proxy_TraceObject(JSTracer *trc, JSObject *obj)
{
obj->getProxyHandler()->trace(trc, obj);
MarkValue(trc, obj->getProxyPrivate(), "private");
MarkValue(trc, obj->getProxyExtra(), "extra");
MarkCrossCompartmentValue(trc, obj->getProxyPrivate(), "private");
MarkCrossCompartmentValue(trc, obj->getProxyExtra(), "extra");
if (obj->isFunctionProxy()) {
MarkValue(trc, GetCall(obj), "call");
MarkValue(trc, GetConstruct(obj), "construct");
MarkCrossCompartmentValue(trc, GetCall(obj), "call");
MarkCrossCompartmentValue(trc, GetConstruct(obj), "construct");
}
}
@ -992,8 +992,8 @@ static void
proxy_TraceFunction(JSTracer *trc, JSObject *obj)
{
proxy_TraceObject(trc, obj);
MarkValue(trc, GetCall(obj), "call");
MarkValue(trc, GetConstruct(obj), "construct");
MarkCrossCompartmentValue(trc, GetCall(obj), "call");
MarkCrossCompartmentValue(trc, GetConstruct(obj), "construct");
}
static JSBool

View File

@ -55,7 +55,6 @@
#include "jsatom.h"
#include "jscntxt.h"
#include "jsdbgapi.h"
#include "jsfun.h" /* for JS_ARGS_LENGTH_MAX */
#include "jslock.h"
#include "jsnum.h"
#include "jsobj.h"

View File

@ -61,7 +61,6 @@
#include "jsbool.h"
#include "jsbuiltins.h"
#include "jscntxt.h"
#include "jsfun.h" /* for JS_ARGS_LENGTH_MAX */
#include "jsgc.h"
#include "jsinterp.h"
#include "jslock.h"
@ -3101,7 +3100,7 @@ static JSBool
str_fromCharCode(JSContext *cx, uintN argc, Value *vp)
{
Value *argv = JS_ARGV(cx, vp);
JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
JS_ASSERT(argc <= StackSpace::ARGS_LENGTH_MAX);
if (argc == 1) {
uint16_t code;
if (!ValueToUint16(cx, argv[0], &code))

View File

@ -5739,8 +5739,7 @@ SynthesizeFrame(JSContext* cx, const FrameInfo& fi, JSObject* callee)
/* Push a frame for the call. */
CallArgs args = CallArgsFromSp(fi.get_argc(), regs.sp);
cx->stack.pushInlineFrame(cx, regs, args, *callee, newfun, newscript,
MaybeConstructFromBool(fi.is_constructing()),
NoCheck());
MaybeConstructFromBool(fi.is_constructing()));
#ifdef DEBUG
/* These should be initialized by FlushNativeStackFrame. */
@ -6635,7 +6634,8 @@ ExecuteTree(JSContext* cx, TraceMonitor* tm, TreeFragment* f,
#endif
JS_ASSERT(f->root == f && f->code());
if (!ScopeChainCheck(cx, f) || !cx->stack.space().ensureEnoughSpaceToEnterTrace()) {
if (!ScopeChainCheck(cx, f) ||
!cx->stack.space().ensureEnoughSpaceToEnterTrace(cx)) {
*lrp = NULL;
return true;
}

View File

@ -45,6 +45,7 @@
#define jsutil_h___
#include "jstypes.h"
#include "jscrashreport.h"
#include "mozilla/Util.h"
#include <stdlib.h>
#include <string.h>
@ -59,6 +60,8 @@ JS_BEGIN_EXTERN_C
} \
JS_END_MACRO
#define JS_FREE_PATTERN 0xDA
#ifdef DEBUG
#define JS_ASSERT(expr) \
@ -80,8 +83,6 @@ JS_BEGIN_EXTERN_C
# define JS_THREADSAFE_ASSERT(expr) ((void) 0)
# endif
#define JS_FREE_PATTERN 0xDA
#else
#define JS_ASSERT(expr) ((void) 0)
@ -220,6 +221,12 @@ extern JS_PUBLIC_DATA(JSUint32) OOM_counter; /* data race, who cares. */
#define JS_OOM_POSSIBLY_FAIL() do {} while(0)
#endif
static JS_INLINE void *js_record_oom(void *p) {
if (!p)
js_SnapshotErrorStack();
return p;
}
/*
* SpiderMonkey code should not be calling these allocation functions directly.
* Instead, all calls should go through JSRuntime, JSContext or OffTheBooks.
@ -227,17 +234,17 @@ extern JS_PUBLIC_DATA(JSUint32) OOM_counter; /* data race, who cares. */
*/
static JS_INLINE void* js_malloc(size_t bytes) {
JS_OOM_POSSIBLY_FAIL();
return malloc(bytes);
return js_record_oom(malloc(bytes));
}
static JS_INLINE void* js_calloc(size_t bytes) {
JS_OOM_POSSIBLY_FAIL();
return calloc(bytes, 1);
return js_record_oom(calloc(bytes, 1));
}
static JS_INLINE void* js_realloc(void* p, size_t bytes) {
JS_OOM_POSSIBLY_FAIL();
return realloc(p, bytes);
return js_record_oom(realloc(p, bytes));
}
static JS_INLINE void js_free(void* p) {
@ -670,6 +677,16 @@ PodEqual(T *one, T *two, size_t len)
return !memcmp(one, two, len * sizeof(T));
}
/*
* Ordinarily, a function taking a JSContext* 'cx' paremter reports errors on
* the context. In some cases, functions optionally report and indicate this by
* taking a nullable 'maybecx' parameter. In some cases, though, a function
* always needs a 'cx', but optionally reports. This option is presented by the
* MaybeReportError.
*/
enum MaybeReportError { REPORT_ERROR = true, DONT_REPORT_ERROR = false };
} /* namespace js */
#endif /* defined(__cplusplus) */

View File

@ -399,7 +399,7 @@ ForceFrame::enter()
JSObject *scopeChain = target->getGlobal();
JS_ASSERT(scopeChain->isNative());
return context->stack.pushDummyFrame(context, *scopeChain, frame);
return context->stack.pushDummyFrame(context, REPORT_ERROR, *scopeChain, frame);
}
AutoCompartment::AutoCompartment(JSContext *cx, JSObject *target)
@ -424,13 +424,23 @@ AutoCompartment::enter()
if (origin != destination) {
LeaveTrace(context);
context->compartment = destination;
JSObject *scopeChain = target->getGlobal();
JS_ASSERT(scopeChain->isNative());
frame.construct();
if (!context->stack.pushDummyFrame(context, *scopeChain, &frame.ref())) {
/*
* Set the compartment eagerly so that pushDummyFrame associates the
* resource allocation request with 'destination' instead of 'origin'.
* (This is important when content has overflowed the stack and chrome
* is preparing to run JS to throw up a slow script dialog.) However,
* if an exception is thrown, we need it to be in origin's compartment
* so be careful to only report after restoring.
*/
context->compartment = destination;
if (!context->stack.pushDummyFrame(context, DONT_REPORT_ERROR, *scopeChain, &frame.ref())) {
context->compartment = origin;
js_ReportOverRecursed(context);
return false;
}
@ -758,4 +768,10 @@ JSCrossCompartmentWrapper::defaultValue(JSContext *cx, JSObject *wrapper, JSType
return call.origin->wrap(cx, vp);
}
void
JSCrossCompartmentWrapper::trace(JSTracer *trc, JSObject *wrapper)
{
MarkCrossCompartmentObject(trc, *wrappedObject(wrapper), "wrappedObject");
}
JSCrossCompartmentWrapper JSCrossCompartmentWrapper::singleton(0u);

View File

@ -153,6 +153,8 @@ class JS_FRIEND_API(JSCrossCompartmentWrapper) : public JSWrapper {
virtual JSString *fun_toString(JSContext *cx, JSObject *wrapper, uintN indent);
virtual bool defaultValue(JSContext *cx, JSObject *wrapper, JSType hint, js::Value *vp);
virtual void trace(JSTracer *trc, JSObject *wrapper);
static JSCrossCompartmentWrapper singleton;
};

View File

@ -202,9 +202,8 @@ void JS_FASTCALL
stubs::HitStackQuota(VMFrame &f)
{
/* Include space to push another frame. */
uintN nvals = f.fp()->script()->nslots + VALUES_PER_STACK_FRAME;
JS_ASSERT(f.regs.sp == f.fp()->base());
if (f.cx->stack.space().tryBumpLimit(NULL, f.regs.sp, nvals, &f.stackLimit))
f.stackLimit = f.cx->stack.space().getStackLimit(f.cx, DONT_REPORT_ERROR);
if (f.stackLimit)
return;
f.cx->stack.popFrameAfterOverflow();
@ -240,14 +239,15 @@ stubs::FixupArity(VMFrame &f, uint32 nactual)
/* Reserve enough space for a callee frame. */
CallArgs args = CallArgsFromSp(nactual, f.regs.sp);
StackFrame *fp = cx->stack.getFixupFrame(cx, f.regs, args, fun, script, ncode,
construct, LimitCheck(&f.stackLimit));
StackFrame *fp = cx->stack.getFixupFrame(cx, DONT_REPORT_ERROR, args, fun,
script, ncode, construct, &f.stackLimit);
if (!fp) {
/*
* The PC is not coherent with the current frame, so fix it up for
* exception handling.
*/
f.regs.pc = f.jit()->nativeToPC(ncode);
js_ReportOverRecursed(cx);
THROWV(NULL);
}
@ -316,8 +316,7 @@ UncachedInlineCall(VMFrame &f, MaybeConstruct construct, void **pret, bool *unji
JSScript *newscript = newfun->script();
/* Get pointer to new frame/slots, prepare arguments. */
LimitCheck check(&f.stackLimit);
if (!cx->stack.pushInlineFrame(cx, f.regs, args, callee, newfun, newscript, construct, check))
if (!cx->stack.pushInlineFrame(cx, f.regs, args, callee, newfun, newscript, construct, &f.stackLimit))
return false;
/* Scope with a call object parented by callee's parent. */

View File

@ -709,7 +709,7 @@ CheckStackAndEnterMethodJIT(JSContext *cx, StackFrame *fp, void *code)
{
JS_CHECK_RECURSION(cx, return false);
Value *stackLimit = cx->stack.space().getStackLimit(cx);
Value *stackLimit = cx->stack.space().getStackLimit(cx, REPORT_ERROR);
if (!stackLimit)
return false;

View File

@ -1096,7 +1096,7 @@ ic::SplatApplyArgs(VMFrame &f)
THROWV(false);
/* Step 6. */
n = Min(length, JS_ARGS_LENGTH_MAX);
n = Min(length, StackSpace::ARGS_LENGTH_MAX);
if (!BumpStack(f, n))
THROWV(false);
@ -1151,7 +1151,7 @@ ic::SplatApplyArgs(VMFrame &f)
JS_ASSERT(!JS_ON_TRACE(cx));
/* Step 6. */
uintN n = uintN(JS_MIN(length, JS_ARGS_LENGTH_MAX));
uintN n = uintN(JS_MIN(length, StackSpace::ARGS_LENGTH_MAX));
intN delta = n - 1;
if (delta > 0 && !BumpStack(f, delta))

View File

@ -1299,7 +1299,7 @@ stubs::InitElem(VMFrame &f, uint32 last)
if (rref.isMagic(JS_ARRAY_HOLE)) {
JS_ASSERT(obj->isArray());
JS_ASSERT(JSID_IS_INT(id));
JS_ASSERT(jsuint(JSID_TO_INT(id)) < JS_ARGS_LENGTH_MAX);
JS_ASSERT(jsuint(JSID_TO_INT(id)) < StackSpace::ARGS_LENGTH_MAX);
if (last && !js_SetLengthProperty(cx, obj, (jsuint) (JSID_TO_INT(id) + 1)))
THROW();
} else {

View File

@ -4797,6 +4797,13 @@ EnableStackWalkingAssertion(JSContext *cx, uintN argc, jsval *vp)
return true;
}
static JSBool
GetMaxArgs(JSContext *cx, uintN arg, jsval *vp)
{
JS_SET_RVAL(cx, vp, INT_TO_JSVAL(StackSpace::ARGS_LENGTH_MAX));
return JS_TRUE;
}
static JSFunctionSpec shell_functions[] = {
JS_FN("version", Version, 0,0),
JS_FN("revertVersion", RevertVersion, 0,0),
@ -4897,6 +4904,7 @@ static JSFunctionSpec shell_functions[] = {
JS_FN("newGlobal", NewGlobal, 1,0),
JS_FN("parseLegacyJSON",ParseLegacyJSON,1,0),
JS_FN("enableStackWalkingAssertion",EnableStackWalkingAssertion,1,0),
JS_FN("getMaxArgs", GetMaxArgs, 0,0),
JS_FS_END
};
@ -5042,6 +5050,7 @@ static const char *const shell_help_messages[] = {
" code. If your test isn't ridiculously thorough, such that performing this\n"
" assertion increases test duration by an order of magnitude, you shouldn't\n"
" use this.",
"getMaxArgs() Return the maximum number of supported args for a call.",
/* Keep these last: see the static assertion below. */
#ifdef MOZ_PROFILING
@ -6046,6 +6055,21 @@ MaybeOverrideOutFileFromEnv(const char* const envVar,
}
}
JSBool
ShellPrincipalsSubsume(JSPrincipals *, JSPrincipals *)
{
return JS_TRUE;
}
JSPrincipals shellTrustedPrincipals = {
(char *)"[shell trusted principals]",
NULL,
NULL,
1,
NULL, /* nobody should be destroying this */
ShellPrincipalsSubsume
};
int
main(int argc, char **argv, char **envp)
{
@ -6132,6 +6156,8 @@ main(int argc, char **argv, char **envp)
if (!rt)
return 1;
JS_SetTrustedPrincipals(rt, &shellTrustedPrincipals);
if (!InitWatchdog(rt))
return 1;

View File

@ -19,7 +19,6 @@ script regress-345961.js
script regress-348810.js
script regress-350256-01.js
script regress-350256-02.js
silentfail script regress-350256-03.js
script regress-360681-01.js
script regress-360681-02.js
script regress-364104.js

Some files were not shown because too many files have changed in this diff Show More