mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-15 06:15:43 +00:00
Merge fx-team with mozilla-central
This commit is contained in:
commit
99ab3d837a
@ -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)
|
||||
|
@ -1,5 +1,11 @@
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
Services.prefs.setBoolPref(allTabs.prefName, true);
|
||||
registerCleanupFunction(function () {
|
||||
Services.prefs.clearUserPref(allTabs.prefName);
|
||||
});
|
||||
|
||||
allTabs.init();
|
||||
nextSequence();
|
||||
}
|
||||
|
@ -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%/");
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -59,7 +59,7 @@ public:
|
||||
NS_DECL_NSIPRINCIPAL
|
||||
NS_DECL_NSISERIALIZABLE
|
||||
|
||||
nsresult Init();
|
||||
nsresult Init(JSPrincipals **jsprin);
|
||||
|
||||
nsSystemPrincipal();
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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).
|
||||
|
@ -502,6 +502,7 @@ _TEST_FILES2 = \
|
||||
somedatas.resource \
|
||||
somedatas.resource^headers^ \
|
||||
delayedServerEvents.sjs \
|
||||
test_bug664916.html \
|
||||
test_bug666604.html \
|
||||
$(NULL)
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
40
content/base/test/test_bug664916.html
Normal file
40
content/base/test/test_bug664916.html
Normal 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>
|
@ -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;
|
||||
|
@ -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(¤tGLError);
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -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);
|
||||
|
@ -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!]";
|
||||
}
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 = [];
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -102,6 +102,7 @@ private:
|
||||
PRInt64 mDocIdentifier;
|
||||
PRInt32 mScrollPositionX;
|
||||
PRInt32 mScrollPositionY;
|
||||
PRPackedBool mURIWasModified;
|
||||
PRPackedBool mIsFrameNavigation;
|
||||
PRPackedBool mSaveLayoutState;
|
||||
PRPackedBool mExpired;
|
||||
|
@ -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)
|
||||
|
13
docshell/test/file_bug669671.sjs
Normal file
13
docshell/test/file_bug669671.sjs
Normal 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>');
|
||||
}
|
140
docshell/test/test_bug669671.html
Normal file
140
docshell/test/test_bug669671.html
Normal 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>
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
184
embedding/android/LauncherShortcuts.java.in
Normal file
184
embedding/android/LauncherShortcuts.java.in
Normal 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();
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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">
|
||||
|
20
embedding/android/resources/layout/launch_app_list.xml
Normal file
20
embedding/android/resources/layout/launch_app_list.xml
Normal 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>
|
17
embedding/android/resources/layout/launch_app_listitem.xml
Normal file
17
embedding/android/resources/layout/launch_app_listitem.xml
Normal 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>
|
@ -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>
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -40,6 +40,7 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
|
||||
|
@ -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 \
|
||||
|
3
js/src/jit-test/tests/basic/testBug668479.js
Normal file
3
js/src/jit-test/tests/basic/testBug668479.js
Normal file
@ -0,0 +1,3 @@
|
||||
function a() {
|
||||
with(a) eval("arguments[0]");
|
||||
} a();
|
12
js/src/jit-test/tests/basic/testOOMInAutoEnterCompartment.js
Normal file
12
js/src/jit-test/tests/basic/testOOMInAutoEnterCompartment.js
Normal file
@ -0,0 +1,12 @@
|
||||
foo = evalcx("(function foo() { foo.bar() })");
|
||||
foo.bar = evalcx("(function bar() {})");
|
||||
|
||||
function fatty() {
|
||||
try {
|
||||
fatty();
|
||||
} catch (e) {
|
||||
foo();
|
||||
}
|
||||
}
|
||||
|
||||
fatty();
|
15
js/src/jit-test/tests/basic/testOverOOMInFixupArity.js
Normal file
15
js/src/jit-test/tests/basic/testOverOOMInFixupArity.js
Normal 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);
|
@ -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,
|
||||
|
161
js/src/jsapi-tests/testChromeBuffer.cpp
Normal file
161
js/src/jsapi-tests/testChromeBuffer.cpp
Normal 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, ¶mName, 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, ¶mName,
|
||||
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, ¶mName, 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, ¶mName,
|
||||
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, ¶mName,
|
||||
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)
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/*
|
||||
|
@ -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
111
js/src/jscrashformat.h
Normal 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
280
js/src/jscrashreport.cpp
Normal 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, ®s, 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
59
js/src/jscrashreport.h
Normal 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___ */
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) */
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user