Merge last PGO-green changeset of mozilla-inbound to mozilla-central

This commit is contained in:
Ed Morley 2012-03-03 13:13:15 +00:00
commit 3fd581145d
275 changed files with 5513 additions and 2206 deletions

View File

@ -53,6 +53,7 @@ _TEST_FILES =\
test_contextmenu.xul \
test_doc.html \
test_gencontent.html \
test_hidden.html \
test_list_editabledoc.html \
test_list.html \
test_menu.xul \

View File

@ -0,0 +1,135 @@
<!DOCTYPE html>
<html>
<head>
<title>@hidden attribute testing</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../role.js"></script>
<script type="application/javascript"
src="../events.js"></script>
<script type="application/javascript">
////////////////////////////////////////////////////////////////////////////
// Invokers
////////////////////////////////////////////////////////////////////////////
/**
* Set @hidden attribute
*/
function setHiddenAttr(aContainerID, aChildID)
{
this.eventSeq = [
new invokerChecker(EVENT_REORDER, getNode(aContainerID))
];
this.invoke = function setHiddenAttr_invoke()
{
var tree =
{ SECTION: [
{ ENTRY: [
] }
] };
testAccessibleTree(aContainerID, tree);
getNode(aChildID).setAttribute("hidden", "true");
}
this.finalCheck = function setHiddenAttr_finalCheck()
{
var tree =
{ SECTION: [
] };
testAccessibleTree(aContainerID, tree);
}
this.getID = function setHiddenAttr_getID()
{
return "Set @hidden attribute on input and test accessible tree for div";
}
}
/**
* Remove @hidden attribute
*/
function removeHiddenAttr(aContainerID, aChildID)
{
this.eventSeq = [
new invokerChecker(EVENT_REORDER, getNode(aContainerID))
];
this.invoke = function removeHiddenAttr_invoke()
{
var tree =
{ SECTION: [
] };
testAccessibleTree(aContainerID, tree);
getNode(aChildID).removeAttribute("hidden");
}
this.finalCheck = function removeHiddenAttr_finalCheck()
{
var tree =
{ SECTION: [
{ ENTRY: [
] }
] };
testAccessibleTree(aContainerID, tree);
}
this.getID = function removeHiddenAttr_getID()
{
return "Remove @hidden attribute on input and test accessible tree for div";
}
}
////////////////////////////////////////////////////////////////////////////
// Test
////////////////////////////////////////////////////////////////////////////
//gA11yEventDumpID = "eventdump"; // debug stuff
//gA11yEventDumpToConsole = true;
var gQueue = null;
function doTest()
{
gQueue = new eventQueue();
gQueue.push(new setHiddenAttr("container", "child"));
gQueue.push(new removeHiddenAttr("container", "child"));
gQueue.invoke(); // SimpleTest.finish() will be called in the end
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<div id="container"><input id="child"></div>
<div id="eventdump"></div>
</body>
</html>

View File

@ -389,6 +389,7 @@
@BINPATH@/components/nsWifiWorker.manifest
#endif
@BINPATH@/components/BrowserProfileMigrators.manifest
@BINPATH@/components/ProfileMigrator.js
@BINPATH@/components/ChromeProfileMigrator.js
@BINPATH@/components/FirefoxProfileMigrator.js
#ifdef XP_MACOSX

View File

@ -57,6 +57,8 @@ namespace std {
template ostream& ostream::_M_insert(double);
template ostream& ostream::_M_insert(long);
template ostream& ostream::_M_insert(unsigned long);
template ostream& ostream::_M_insert(long long);
template ostream& ostream::_M_insert(unsigned long long);
#ifdef DEBUG
template ostream& ostream::_M_insert(const void*);
#endif

View File

@ -7308,7 +7308,11 @@ if test "${OS_TARGET}" = "Android"; then
:
elif test "${OS_TARGET}" = "WINNT" -o "${OS_TARGET}" = "Darwin" -o "${OS_TARGET}" = "OS2"; then
dnl On Windows, OSX and OS2, we want to link all our binaries against mozglue
MOZ_GLUE_LDFLAGS='$(call EXPAND_LIBNAME_PATH,mozglue,$(LIBXUL_DIST)/lib)'
if test -z "$GNU_CC"; then
MOZ_GLUE_LDFLAGS='$(call EXPAND_LIBNAME_PATH,mozglue,$(LIBXUL_DIST)/lib)'
else
MOZ_GLUE_LDFLAGS='-L$(LIBXUL_DIST)/lib $(call EXPAND_LIBNAME,mozglue)'
fi
else
dnl On other Unix systems, we only want to link executables against mozglue
MOZ_GLUE_PROGRAM_LDFLAGS='$(MKSHLIB_FORCE_ALL) $(call EXPAND_LIBNAME_PATH,mozglue,$(LIBXUL_DIST)/lib) $(MKSHLIB_UNFORCE_ALL)'

View File

@ -42,7 +42,6 @@
#include "nsIContent.h"
#include "nsEventStates.h"
#include "nsDOMMemoryReporter.h"
class nsEventStateManager;
class nsGlobalWindow;

View File

@ -43,7 +43,6 @@
#include "nsChangeHint.h"
#include "nsINode.h"
#include "nsIDocument.h" // for IsInHTMLDocument
#include "nsDOMMemoryReporter.h"
// Forward declarations
class nsIAtom;

View File

@ -68,7 +68,6 @@
#include "nsEventStates.h"
#include "nsIStructuredCloneContainer.h"
#include "nsIBFCacheEntry.h"
#include "nsDOMMemoryReporter.h"
class nsIContent;
class nsPresContext;

View File

@ -49,7 +49,7 @@
#include "nsDOMError.h"
#include "nsDOMString.h"
#include "jspubtd.h"
#include "nsDOMMemoryReporter.h"
#include "nsWindowMemoryReporter.h"
#include "nsIVariant.h"
#include "nsGkAtoms.h"

View File

@ -86,7 +86,7 @@ interface nsIObjectLoadingContent : nsISupports
* account. The MIME type is required as some plugins (java) calculate
* this differently.
*/
nsIURI GetObjectBaseURI(in ACString aMimeType);
nsIURI getObjectBaseURI(in ACString aMimeType);
/**
* Returns the plugin instance if it has already been instantiated. This

View File

@ -45,7 +45,6 @@
#include "nsCOMPtr.h"
#include "nsIDocument.h"
#include "nsGenericElement.h" // DOMCI_NODE_DATA
#include "nsDOMMemoryReporter.h"
class nsCommentNode : public nsGenericDOMDataNode,
public nsIDOMComment

View File

@ -39,6 +39,7 @@
*/
#include "nsDOMSettableTokenList.h"
#include "dombindings.h"
nsDOMSettableTokenList::nsDOMSettableTokenList(nsGenericElement *aElement, nsIAtom* aAttrAtom)
@ -78,3 +79,10 @@ nsDOMSettableTokenList::SetValue(const nsAString& aValue)
return mElement->SetAttr(kNameSpaceID_None, mAttrAtom, aValue, true);
}
JSObject*
nsDOMSettableTokenList::WrapObject(JSContext *cx, XPCWrappedNativeScope *scope,
bool *triedToWrap)
{
return mozilla::dom::binding::DOMSettableTokenList::create(cx, scope, this,
triedToWrap);
}

View File

@ -59,6 +59,9 @@ public:
nsDOMSettableTokenList(nsGenericElement* aElement, nsIAtom* aAttrAtom);
virtual JSObject* WrapObject(JSContext *cx, XPCWrappedNativeScope *scope,
bool *triedToWrap);
protected:
virtual ~nsDOMSettableTokenList();
};

View File

@ -44,6 +44,7 @@
#include "nsContentUtils.h"
#include "nsDOMError.h"
#include "nsGenericElement.h"
#include "dombindings.h"
nsDOMTokenList::nsDOMTokenList(nsGenericElement *aElement, nsIAtom* aAttrAtom)
@ -52,21 +53,34 @@ nsDOMTokenList::nsDOMTokenList(nsGenericElement *aElement, nsIAtom* aAttrAtom)
{
// We don't add a reference to our element. If it goes away,
// we'll be told to drop our reference
SetIsProxy();
}
nsDOMTokenList::~nsDOMTokenList() { }
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMTokenList)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMTokenList)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMTokenList)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMTokenList)
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_TRACE_END
DOMCI_DATA(DOMTokenList, nsDOMTokenList)
NS_INTERFACE_TABLE_HEAD(nsDOMTokenList)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_TABLE1(nsDOMTokenList,
nsIDOMDOMTokenList)
NS_INTERFACE_TABLE_TO_MAP_SEGUE
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsDOMTokenList)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DOMTokenList)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsDOMTokenList)
NS_IMPL_RELEASE(nsDOMTokenList)
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMTokenList)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMTokenList)
void
nsDOMTokenList::DropReference()
@ -293,3 +307,12 @@ nsDOMTokenList::ToString(nsAString& aResult)
return NS_OK;
}
JSObject*
nsDOMTokenList::WrapObject(JSContext *cx, XPCWrappedNativeScope *scope,
bool *triedToWrap)
{
return mozilla::dom::binding::DOMTokenList::create(cx, scope, this,
triedToWrap);
}

View File

@ -46,16 +46,26 @@
class nsAttrValue;
class nsDOMTokenList : public nsIDOMDOMTokenList
class nsDOMTokenList : public nsIDOMDOMTokenList,
public nsWrapperCache
{
public:
NS_DECL_ISUPPORTS
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMTokenList)
NS_DECL_NSIDOMDOMTOKENLIST
nsDOMTokenList(nsGenericElement* aElement, nsIAtom* aAttrAtom);
void DropReference();
virtual JSObject* WrapObject(JSContext *cx, XPCWrappedNativeScope *scope,
bool *triedToWrap);
nsINode *GetParentObject()
{
return mElement;
}
protected:
~nsDOMTokenList();

View File

@ -9149,6 +9149,13 @@ nsIDocument::DocSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const
aWindowSizes->mDOM +=
nsINode::SizeOfExcludingThis(aWindowSizes->mMallocSizeOf);
if (mPresShell) {
mPresShell->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf,
&aWindowSizes->mLayoutArenas,
&aWindowSizes->mLayoutStyleSets,
&aWindowSizes->mLayoutTextRuns);
}
// Measurement of the following members may be added later if DMD finds it
// is worthwhile:
// - many!

View File

@ -50,7 +50,6 @@
#include "nsEventListenerManager.h"
#include "nsGenericElement.h"
#include "nsCycleCollectionParticipant.h"
#include "nsDOMMemoryReporter.h"
#include "nsISMILAttr.h"

View File

@ -152,7 +152,6 @@
#include "prprf.h"
#include "nsSVGFeatures.h"
#include "nsDOMMemoryReporter.h"
#include "nsWrapperCacheInlines.h"
#include "nsCycleCollector.h"
#include "xpcpublic.h"
@ -1981,7 +1980,7 @@ nsGenericElement::GetChildrenList()
return slots->mChildrenList;
}
nsIDOMDOMTokenList*
nsDOMTokenList*
nsGenericElement::GetClassList(nsresult *aResult)
{
*aResult = NS_ERROR_OUT_OF_MEMORY;
@ -2469,6 +2468,9 @@ nsGenericElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb, b
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mChildrenList");
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*, mChildrenList));
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mClassList");
cb.NoteXPCOMChild(mClassList.get());
}
void
@ -2483,6 +2485,10 @@ nsGenericElement::nsDOMSlots::Unlink(bool aIsXUL)
if (aIsXUL)
NS_IF_RELEASE(mControllers);
mChildrenList = nsnull;
if (mClassList) {
mClassList->DropReference();
mClassList = nsnull;
}
}
nsGenericElement::nsGenericElement(already_AddRefed<nsINodeInfo> aNodeInfo)

View File

@ -597,7 +597,7 @@ public:
nsIContent* GetLastElementChild();
nsIContent* GetPreviousElementSibling();
nsIContent* GetNextElementSibling();
nsIDOMDOMTokenList* GetClassList(nsresult *aResult);
nsDOMTokenList* GetClassList(nsresult *aResult);
bool MozMatchesSelector(const nsAString& aSelector, nsresult* aResult);
/**

View File

@ -46,7 +46,6 @@
#define NS_MAPPEDATTRIBUTEELEMENT_H_
#include "nsStyledElement.h"
#include "nsDOMMemoryReporter.h"
class nsMappedAttributes;
struct nsRuleData;

View File

@ -1871,9 +1871,18 @@ nsObjectLoadingContent::GetObjectBaseURI(const nsACString & aMimeType, nsIURI**
codebase.AssignLiteral("/");
}
nsContentUtils::NewURIWithDocumentCharset(aURI, codebase,
thisContent->OwnerDoc(),
baseURI);
if (!codebase.IsEmpty()) {
nsresult rv = nsContentUtils::NewURIWithDocumentCharset(aURI, codebase,
thisContent->OwnerDoc(),
baseURI);
if (NS_SUCCEEDED(rv))
return rv;
NS_WARNING("GetObjectBaseURI: Could not resolve plugin's codebase to a URI, using baseURI instead");
}
// Codebase empty or build URI failed, just use baseURI
*aURI = NULL;
baseURI.swap(*aURI);
return NS_OK;
}

View File

@ -108,7 +108,6 @@ nsPlainTextSerializer::nsPlainTextSerializer()
mCiteQuoteLevel = 0;
mStructs = true; // will be read from prefs later
mHeaderStrategy = 1 /*indent increasingly*/; // ditto
mQuotesPreformatted = false; // ditto
mDontWrapAnyQuotes = false; // ditto
mHasWrittenCiteBlockquote = false;
mSpanLevel = 0;
@ -210,10 +209,6 @@ nsPlainTextSerializer::Init(PRUint32 aFlags, PRUint32 aWrapColumn,
mHeaderStrategy =
Preferences::GetInt(PREF_HEADER_STRATEGY, mHeaderStrategy);
// The quotesPreformatted pref is a temporary measure. See bug 69638.
mQuotesPreformatted =
Preferences::GetBool("editor.quotesPreformatted", mQuotesPreformatted);
// DontWrapAnyQuotes is set according to whether plaintext mail
// is wrapping to window width -- see bug 134439.
// We'll only want this if we're wrapping and formatted.
@ -1636,7 +1631,7 @@ nsPlainTextSerializer::Write(const nsAString& aStr)
// that does normal formatted text. The one for preformatted text calls
// Output directly while the other code path goes through AddToLine.
if ((mPreFormatted && !mWrapColumn) || IsInPre()
|| ((((!mQuotesPreformatted && mSpanLevel > 0) || mDontWrapAnyQuotes))
|| ((mSpanLevel > 0 || mDontWrapAnyQuotes)
&& mEmptyLines >= 0 && str.First() == PRUnichar('>'))) {
// No intelligent wrapping.

View File

@ -176,11 +176,9 @@ protected:
// Quotes need to be wrapped differently from non-quoted text,
// because quoted text has a few extra characters (e.g. ">> ")
// which makes the line length longer.
// Mail can represent quotes in different ways: it can wrap
// quotes in a <pre> (if editor.quotesPreformatted is set),
// or not wrapped in any special tag (if mail.compose.wrap_to_window_width)
// or in a <span> (if neither of the above are set).
bool mQuotesPreformatted; // expect quotes wrapped in <pre>
// Mail can represent quotes in different ways:
// Not wrapped in any special tag (if mail.compose.wrap_to_window_width)
// or in a <span>.
bool mDontWrapAnyQuotes; // no special quote markers
bool mStructs; // Output structs (pref)

View File

@ -48,7 +48,6 @@
#include "nsString.h"
#include "nsGenericElement.h"
#include "nsDOMMemoryReporter.h"
namespace mozilla {
namespace css {

View File

@ -48,7 +48,6 @@
#include "nsString.h"
#include "nsReadableUtils.h"
#include "nsTraceRefcnt.h"
#include "nsDOMMemoryReporter.h"
class nsString;
class nsCString;

View File

@ -45,7 +45,6 @@
#include "nsIAttribute.h"
#include "nsIDocument.h"
#include "nsThreadUtils.h"
#include "nsDOMMemoryReporter.h"
/**
* Class used to implement DOM text nodes

View File

@ -63,6 +63,7 @@
#include "Layers.h"
#include "CheckedInt.h"
#include "nsDataHashtable.h"
#ifdef XP_MACOSX
#include "ForceDiscreteGPUHelperCGL.h"
@ -1627,16 +1628,25 @@ public:
}
};
struct WebGLMappedIdentifier {
nsCString original, mapped; // ASCII strings
WebGLMappedIdentifier(const nsACString& o, const nsACString& m) : original(o), mapped(m) {}
};
class WebGLShader MOZ_FINAL
: public nsIWebGLShader
, public WebGLRefCountedObject<WebGLShader>
, public WebGLContextBoundObject
{
friend class WebGLContext;
friend class WebGLProgram;
public:
WebGLShader(WebGLContext *context, WebGLenum stype)
: WebGLContextBoundObject(context)
, mType(stype)
, mNeedsTranslation(true)
, mAttribMaxNameLength(0)
{
mContext->MakeContextCurrent();
mGLName = mContext->gl->fCreateShader(mType);
@ -1693,11 +1703,45 @@ protected:
WebGLuint mGLName;
WebGLenum mType;
nsString mSource;
nsCString mTranslationLog;
nsCString mTranslationLog; // The translation log should contain only ASCII characters
bool mNeedsTranslation;
WebGLMonotonicHandle mMonotonicHandle;
nsTArray<WebGLMappedIdentifier> mAttributes;
nsTArray<WebGLMappedIdentifier> mUniforms;
int mAttribMaxNameLength;
};
/** Takes an ASCII string like "foo[i]", turns it into "foo" and returns "[i]" in bracketPart
*
* \param string input/output: the string to split, becomes the string without the bracket part
* \param bracketPart output: gets the bracket part.
*
* Notice that if there are multiple brackets like "foo[i].bar[j]", only the last bracket is split.
*/
static bool SplitLastSquareBracket(nsACString& string, nsCString& bracketPart)
{
NS_ABORT_IF_FALSE(bracketPart.Length() == 0, "SplitLastSquareBracket must be called with empty bracketPart string");
char *string_start = string.BeginWriting();
char *s = string_start + string.Length() - 1;
if (*s != ']')
return false;
while (*s != '[' && s != string_start)
s--;
if (*s != '[')
return false;
bracketPart.Assign(s);
*s = 0;
string.EndWriting();
string.SetLength(s - string_start);
return true;
}
typedef nsDataHashtable<nsCStringHashKey, nsCString> CStringHash;
class WebGLProgram MOZ_FINAL
: public nsIWebGLProgram
, public WebGLRefCountedObject<WebGLProgram>
@ -1708,10 +1752,7 @@ public:
: WebGLContextBoundObject(context)
, mLinkStatus(false)
, mGeneration(0)
, mUniformMaxNameLength(0)
, mAttribMaxNameLength(0)
, mUniformCount(0)
, mAttribCount(0)
{
mContext->MakeContextCurrent();
mGLName = mContext->gl->fCreateProgram();
@ -1790,15 +1831,107 @@ public:
}
/* Called only after LinkProgram */
bool UpdateInfo(gl::GLContext *gl);
bool UpdateInfo();
/* Getters for cached program info */
WebGLint UniformMaxNameLength() const { return mUniformMaxNameLength; }
WebGLint AttribMaxNameLength() const { return mAttribMaxNameLength; }
WebGLint UniformCount() const { return mUniformCount; }
WebGLint AttribCount() const { return mAttribCount; }
bool IsAttribInUse(unsigned i) const { return mAttribsInUse[i]; }
/* Maps identifier |name| to the mapped identifier |*mappedName|
* Both are ASCII strings.
*/
void MapIdentifier(const nsACString& name, nsCString *mappedName) {
if (!mIdentifierMap) {
// if the identifier map doesn't exist yet, build it now
mIdentifierMap = new CStringHash;
mIdentifierMap->Init();
for (size_t i = 0; i < mAttachedShaders.Length(); i++) {
for (size_t j = 0; j < mAttachedShaders[i]->mAttributes.Length(); j++) {
const WebGLMappedIdentifier& attrib = mAttachedShaders[i]->mAttributes[j];
mIdentifierMap->Put(attrib.original, attrib.mapped);
}
for (size_t j = 0; j < mAttachedShaders[i]->mUniforms.Length(); j++) {
const WebGLMappedIdentifier& uniform = mAttachedShaders[i]->mUniforms[j];
mIdentifierMap->Put(uniform.original, uniform.mapped);
}
}
}
nsCString mutableName(name);
nsCString bracketPart;
bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart);
if (hadBracketPart)
mutableName.AppendLiteral("[0]");
if (mIdentifierMap->Get(mutableName, mappedName)) {
if (hadBracketPart) {
nsCString mappedBracketPart;
bool mappedHadBracketPart = SplitLastSquareBracket(*mappedName, mappedBracketPart);
if (mappedHadBracketPart)
mappedName->Append(bracketPart);
}
return;
}
// not found? We might be in the situation we have a uniform array name and the GL's glGetActiveUniform
// returned its name without [0], as is allowed by desktop GL but not in ES. Let's then try with [0].
mutableName.AppendLiteral("[0]");
if (mIdentifierMap->Get(mutableName, mappedName))
return;
// not found? return name unchanged. This case happens e.g. on bad user input, or when
// we're not using identifier mapping, or if we didn't store an identifier in the map because
// e.g. its mapping is trivial (as happens for short identifiers)
mappedName->Assign(name);
}
/* Un-maps mapped identifier |name| to the original identifier |*reverseMappedName|
* Both are ASCII strings.
*/
void ReverseMapIdentifier(const nsACString& name, nsCString *reverseMappedName) {
if (!mIdentifierReverseMap) {
// if the identifier reverse map doesn't exist yet, build it now
mIdentifierReverseMap = new CStringHash;
mIdentifierReverseMap->Init();
for (size_t i = 0; i < mAttachedShaders.Length(); i++) {
for (size_t j = 0; j < mAttachedShaders[i]->mAttributes.Length(); j++) {
const WebGLMappedIdentifier& attrib = mAttachedShaders[i]->mAttributes[j];
mIdentifierReverseMap->Put(attrib.mapped, attrib.original);
}
for (size_t j = 0; j < mAttachedShaders[i]->mUniforms.Length(); j++) {
const WebGLMappedIdentifier& uniform = mAttachedShaders[i]->mUniforms[j];
mIdentifierReverseMap->Put(uniform.mapped, uniform.original);
}
}
}
nsCString mutableName(name);
nsCString bracketPart;
bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart);
if (hadBracketPart)
mutableName.AppendLiteral("[0]");
if (mIdentifierReverseMap->Get(mutableName, reverseMappedName)) {
if (hadBracketPart) {
nsCString reverseMappedBracketPart;
bool reverseMappedHadBracketPart = SplitLastSquareBracket(*reverseMappedName, reverseMappedBracketPart);
if (reverseMappedHadBracketPart)
reverseMappedName->Append(bracketPart);
}
return;
}
// not found? We might be in the situation we have a uniform array name and the GL's glGetActiveUniform
// returned its name without [0], as is allowed by desktop GL but not in ES. Let's then try with [0].
mutableName.AppendLiteral("[0]");
if (mIdentifierReverseMap->Get(mutableName, reverseMappedName))
return;
// not found? return name unchanged. This case happens e.g. on bad user input, or when
// we're not using identifier mapping, or if we didn't store an identifier in the map because
// e.g. its mapping is trivial (as happens for short identifiers)
reverseMappedName->Assign(name);
}
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBGLPROGRAM
@ -1811,13 +1944,10 @@ protected:
CheckedUint32 mGeneration;
// post-link data
GLint mUniformMaxNameLength;
GLint mAttribMaxNameLength;
GLint mUniformCount;
GLint mAttribCount;
std::vector<bool> mAttribsInUse;
WebGLMonotonicHandle mMonotonicHandle;
nsAutoPtr<CStringHash> mIdentifierMap, mIdentifierReverseMap;
int mAttribMaxNameLength;
};
class WebGLRenderbuffer MOZ_FINAL
@ -2366,12 +2496,11 @@ class WebGLActiveInfo MOZ_FINAL
: public nsIWebGLActiveInfo
{
public:
WebGLActiveInfo(WebGLint size, WebGLenum type, const char *nameptr, PRUint32 namelength) :
WebGLActiveInfo(WebGLint size, WebGLenum type, const nsACString& name) :
mSize(size),
mType(type)
{
mName.AssignASCII(nameptr, namelength);
}
mType(type),
mName(NS_ConvertASCIItoUTF16(name))
{}
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBGLACTIVEINFO

View File

@ -121,7 +121,6 @@ NS_IMETHODIMP WebGLContext::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6) { \
MakeContextCurrent(); gl->f##glname(a1,a2,a3,a4,a5,a6); return NS_OK; \
}
//
// WebGL API
//
@ -181,7 +180,8 @@ WebGLContext::BindAttribLocation(nsIWebGLProgram *pobj, WebGLuint location, cons
return NS_OK;
WebGLuint progname;
if (!GetGLName<WebGLProgram>("bindAttribLocation: program", pobj, &progname))
WebGLProgram *prog;
if (!GetConcreteObjectAndGLName("bindAttribLocation: program", pobj, &prog, &progname))
return NS_OK;
if (!ValidateGLSLVariableName(name, "bindAttribLocation"))
@ -190,10 +190,12 @@ WebGLContext::BindAttribLocation(nsIWebGLProgram *pobj, WebGLuint location, cons
if (!ValidateAttribIndex(location, "bindAttribLocation"))
return NS_OK;
NS_LossyConvertUTF16toASCII cname(name);
nsCString mappedName;
prog->MapIdentifier(cname, &mappedName);
MakeContextCurrent();
gl->fBindAttribLocation(progname, location, NS_LossyConvertUTF16toASCII(name).get());
gl->fBindAttribLocation(progname, location, mappedName.get());
return NS_OK;
}
@ -1852,7 +1854,8 @@ WebGLContext::GetActiveAttrib(nsIWebGLProgram *pobj, PRUint32 index, nsIWebGLAct
*retval = nsnull;
WebGLuint progname;
if (!GetGLName<WebGLProgram>("getActiveAttrib: program", pobj, &progname))
WebGLProgram *prog;
if (!GetConcreteObjectAndGLName("getActiveAttrib: program", pobj, &prog, &progname))
return NS_OK;
MakeContextCurrent();
@ -1872,7 +1875,10 @@ WebGLContext::GetActiveAttrib(nsIWebGLProgram *pobj, PRUint32 index, nsIWebGLAct
return NS_OK;
}
WebGLActiveInfo *retActiveInfo = new WebGLActiveInfo(attrsize, attrtype, name.get(), len);
nsCString reverseMappedName;
prog->ReverseMapIdentifier(nsDependentCString(name), &reverseMappedName);
WebGLActiveInfo *retActiveInfo = new WebGLActiveInfo(attrsize, attrtype, reverseMappedName);
NS_ADDREF(*retval = retActiveInfo);
return NS_OK;
@ -1916,7 +1922,8 @@ WebGLContext::GetActiveUniform(nsIWebGLProgram *pobj, PRUint32 index, nsIWebGLAc
*retval = nsnull;
WebGLuint progname;
if (!GetGLName<WebGLProgram>("getActiveUniform: program", pobj, &progname))
WebGLProgram *prog;
if (!GetConcreteObjectAndGLName("getActiveUniform: program", pobj, &prog, &progname))
return NS_OK;
MakeContextCurrent();
@ -1926,17 +1933,20 @@ WebGLContext::GetActiveUniform(nsIWebGLProgram *pobj, PRUint32 index, nsIWebGLAc
if (len == 0)
*retval = nsnull;
nsAutoArrayPtr<char> name(new char[len + 3]); // +3 because we might have to append "[0]", see below
nsAutoArrayPtr<char> name(new char[len]);
GLint attrsize = 0;
GLuint attrtype = 0;
GLint usize = 0;
GLuint utype = 0;
gl->fGetActiveUniform(progname, index, len, &len, &attrsize, &attrtype, name);
if (len == 0 || attrsize == 0 || attrtype == 0) {
gl->fGetActiveUniform(progname, index, len, &len, &usize, &utype, name);
if (len == 0 || usize == 0 || utype == 0) {
*retval = nsnull;
return NS_OK;
}
nsCString reverseMappedName;
prog->ReverseMapIdentifier(nsDependentCString(name), &reverseMappedName);
// OpenGL ES 2.0 specifies that if foo is a uniform array, GetActiveUniform returns its name as "foo[0]".
// See section 2.10 page 35 in the OpenGL ES 2.0.24 specification:
//
@ -1950,16 +1960,11 @@ WebGLContext::GetActiveUniform(nsIWebGLProgram *pobj, PRUint32 index, nsIWebGLAc
// In principle we don't need to do that on OpenGL ES, but this is such a tricky difference between the ES and non-ES
// specs that it seems probable that some ES implementers will overlook it. Since the work-around is quite cheap,
// we do it unconditionally.
if (attrsize > 1 && name[len-1] != ']') {
name[len++] = '[';
name[len++] = '0';
name[len++] = ']';
}
WebGLActiveInfo *retActiveInfo = new WebGLActiveInfo(attrsize, attrtype, name.get(), len);
if (usize > 1 && reverseMappedName.CharAt(reverseMappedName.Length()-1) != ']')
reverseMappedName.AppendLiteral("[0]");
WebGLActiveInfo *retActiveInfo = new WebGLActiveInfo(usize, utype, reverseMappedName);
NS_ADDREF(*retval = retActiveInfo);
return NS_OK;
}
@ -2009,23 +2014,25 @@ WebGLContext::GetAttribLocation(nsIWebGLProgram *pobj,
const nsAString& name,
PRInt32 *retval)
{
if (!IsContextStable())
{
*retval = -1;
return NS_OK;
}
*retval = -1;
*retval = 0;
if (!IsContextStable())
return NS_OK;
WebGLuint progname;
if (!GetGLName<WebGLProgram>("getAttribLocation: program", pobj, &progname))
WebGLProgram *prog;
if (!GetConcreteObjectAndGLName("getAttribLocation: program", pobj, &prog, &progname))
return NS_OK;
if (!ValidateGLSLVariableName(name, "getAttribLocation"))
return NS_OK;
NS_LossyConvertUTF16toASCII cname(name);
nsCString mappedName;
prog->MapIdentifier(cname, &mappedName);
MakeContextCurrent();
*retval = gl->fGetAttribLocation(progname, NS_LossyConvertUTF16toASCII(name).get());
*retval = gl->fGetAttribLocation(progname, mappedName.get());
return NS_OK;
}
@ -2980,11 +2987,14 @@ WebGLContext::GetUniformLocation(nsIWebGLProgram *pobj, const nsAString& name, n
return NS_OK;
if (!ValidateGLSLVariableName(name, "getUniformLocation"))
return NS_OK;
return NS_OK;
NS_LossyConvertUTF16toASCII cname(name);
nsCString mappedName;
prog->MapIdentifier(cname, &mappedName);
MakeContextCurrent();
GLint intlocation = gl->fGetUniformLocation(progname, NS_LossyConvertUTF16toASCII(name).get());
GLint intlocation = gl->fGetUniformLocation(progname, mappedName.get());
WebGLUniformLocation *loc = nsnull;
if (intlocation >= 0)
@ -3251,18 +3261,16 @@ WebGLContext::LinkProgram(nsIWebGLProgram *pobj)
}
MakeContextCurrent();
gl->fLinkProgram(progname);
GLint ok;
gl->fGetProgramiv(progname, LOCAL_GL_LINK_STATUS, &ok);
if (ok) {
program->SetLinkStatus(true);
program->UpdateInfo(gl);
bool updateInfoSucceeded = program->UpdateInfo();
program->SetLinkStatus(updateInfoSucceeded);
} else {
program->SetLinkStatus(false);
}
return NS_OK;
}
@ -4387,6 +4395,20 @@ WebGLContext::CompileShader(nsIWebGLShader *sobj)
MakeContextCurrent();
ShShaderOutput targetShaderSourceLanguage = gl->IsGLES2() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT;
bool useShaderSourceTranslation = true;
#ifdef ANDROID
// see bug 709947. On Android, we can't use the ESSL backend because of strange crashes (might be
// an allocator mismatch). So we use the GLSL backend, and discard the output, instead just passing
// the original WebGL shader source to the GL (since that's ESSL already). The problem is that means
// we can't use shader translations on Android, in particular we can't use long identifier shortening,
// which means we can't reach 100% conformance. We need to fix that by debugging the ESSL backend
// memory crashes.
targetShaderSourceLanguage = SH_GLSL_OUTPUT;
useShaderSourceTranslation = false;
#endif
#if defined(USE_ANGLE)
if (shader->NeedsTranslation() && mShaderValidation) {
ShHandle compiler = 0;
@ -4404,20 +4426,6 @@ WebGLContext::CompileShader(nsIWebGLShader *sobj)
if (mEnabledExtensions[WebGL_OES_standard_derivatives])
resources.OES_standard_derivatives = 1;
// notice that on Android, we always use SH_GLSL_OUTPUT, we never use the ESSL backend.
// see bug 709947, the reason is that 1) we dont really need a ESSL backend since the
// source is already ESSL, and 2) we ran into massive Android crashes when we used the ESSL backend.
// But if we wanted to use shader transformations on ES platforms, we would have to use the
// ESSL backend
compiler = ShConstructCompiler((ShShaderType) shader->ShaderType(),
SH_WEBGL_SPEC,
#ifdef ANDROID
SH_GLSL_OUTPUT,
#else
gl->IsGLES2() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT,
#endif
&resources);
// We're storing an actual instance of StripComments because, if we don't, the
// cleanSource nsAString instance will be destroyed before the reference is
// actually used.
@ -4431,20 +4439,29 @@ WebGLContext::CompileShader(nsIWebGLShader *sobj)
// shaderSource() already checks that the source stripped of comments is in the
// 7-bit ASCII range, so we can skip the NS_IsAscii() check.
const nsCString& sourceCString = NS_LossyConvertUTF16toASCII(flatSource);
const PRUint32 maxSourceLength = (PRUint32(1)<<18) - 1;
if (sourceCString.Length() > maxSourceLength)
return ErrorInvalidValue("compileShader: source has more than %d characters", maxSourceLength);
const char *s = sourceCString.get();
int compileOptions = SH_OBJECT_CODE;
compiler = ShConstructCompiler((ShShaderType) shader->ShaderType(),
SH_WEBGL_SPEC,
targetShaderSourceLanguage,
&resources);
int compileOptions = 0;
if (useShaderSourceTranslation) {
compileOptions |= SH_OBJECT_CODE
| SH_MAP_LONG_VARIABLE_NAMES
| SH_ATTRIBUTES_UNIFORMS;
#ifdef XP_MACOSX
// work around bug 665578
if (!nsCocoaFeatures::OnLionOrLater() && gl->Vendor() == gl::GLContext::VendorATI)
compileOptions |= SH_EMULATE_BUILT_IN_FUNCTIONS;
// work around bug 665578
if (!nsCocoaFeatures::OnLionOrLater() && gl->Vendor() == gl::GLContext::VendorATI)
compileOptions |= SH_EMULATE_BUILT_IN_FUNCTIONS;
#endif
}
if (!ShCompile(compiler, &s, 1, compileOptions)) {
int len = 0;
@ -4462,11 +4479,50 @@ WebGLContext::CompileShader(nsIWebGLShader *sobj)
return NS_OK;
}
/* If the GL context is really GLES2, we want to use the original provided code,
* since it's actually GLES2. We still need to validate it however, which is
* why we ran it through the above, but we don't want the desktop GLSL.
*/
if (!gl->IsGLES2()) {
int num_attributes = 0;
ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTES, &num_attributes);
int num_uniforms = 0;
ShGetInfo(compiler, SH_ACTIVE_UNIFORMS, &num_uniforms);
int attrib_max_length = 0;
ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &attrib_max_length);
int uniform_max_length = 0;
ShGetInfo(compiler, SH_ACTIVE_UNIFORM_MAX_LENGTH, &uniform_max_length);
int mapped_max_length = 0;
ShGetInfo(compiler, SH_MAPPED_NAME_MAX_LENGTH, &mapped_max_length);
shader->mAttribMaxNameLength = attrib_max_length;
shader->mAttributes.Clear();
shader->mUniforms.Clear();
nsAutoArrayPtr<char> attribute_name(new char[attrib_max_length+1]);
nsAutoArrayPtr<char> uniform_name(new char[uniform_max_length+1]);
nsAutoArrayPtr<char> mapped_name(new char[mapped_max_length+1]);
if (useShaderSourceTranslation) {
for (int i = 0; i < num_attributes; i++) {
int length, size;
ShDataType type;
ShGetActiveAttrib(compiler, i,
&length, &size, &type,
attribute_name,
mapped_name);
shader->mAttributes.AppendElement(WebGLMappedIdentifier(
nsDependentCString(attribute_name),
nsDependentCString(mapped_name)));
}
for (int i = 0; i < num_uniforms; i++) {
int length, size;
ShDataType type;
ShGetActiveUniform(compiler, i,
&length, &size, &type,
uniform_name,
mapped_name);
shader->mUniforms.AppendElement(WebGLMappedIdentifier(
nsDependentCString(uniform_name),
nsDependentCString(mapped_name)));
}
int len = 0;
ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &len);
@ -4478,7 +4534,10 @@ WebGLContext::CompileShader(nsIWebGLShader *sobj)
const char *ts = translatedSrc2.get();
gl->fShaderSource(shadername, 1, &ts, NULL);
} else {
} else { // not useShaderSourceTranslation
// we just pass the raw untranslated shader source. We then can't use ANGLE idenfier mapping.
// that's really bad, as that means we can't be 100% conformant. We should work towards always
// using ANGLE identifier mapping.
gl->fShaderSource(shadername, 1, &s, NULL);
}

View File

@ -49,38 +49,46 @@
#include "angle/ShaderLang.h"
#endif
#include <algorithm>
using namespace mozilla;
/*
* Pull all the data out of the program that will be used by validate later on
* Pull data out of the program, post-linking
*/
bool
WebGLProgram::UpdateInfo(gl::GLContext *gl)
WebGLProgram::UpdateInfo()
{
gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &mAttribMaxNameLength);
gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH, &mUniformMaxNameLength);
gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_UNIFORMS, &mUniformCount);
gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES, &mAttribCount);
mIdentifierMap = nsnull;
mIdentifierReverseMap = nsnull;
GLint numVertexAttribs;
if (mContext->MinCapabilityMode()) {
numVertexAttribs = MINVALUE_GL_MAX_VERTEX_ATTRIBS;
} else {
gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_ATTRIBS, &numVertexAttribs);
}
mAttribsInUse.clear();
mAttribsInUse.resize(numVertexAttribs);
mAttribMaxNameLength = 0;
for (size_t i = 0; i < mAttachedShaders.Length(); i++)
mAttribMaxNameLength = NS_MAX(mAttribMaxNameLength, mAttachedShaders[i]->mAttribMaxNameLength);
GLint attribCount;
mContext->gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES, &attribCount);
mAttribsInUse.resize(mContext->mGLMaxVertexAttribs);
std::fill(mAttribsInUse.begin(), mAttribsInUse.end(), false);
nsAutoArrayPtr<char> nameBuf(new char[mAttribMaxNameLength]);
for (int i = 0; i < mAttribCount; ++i) {
for (int i = 0; i < attribCount; ++i) {
GLint attrnamelen;
GLint attrsize;
GLenum attrtype;
gl->fGetActiveAttrib(mGLName, i, mAttribMaxNameLength, &attrnamelen, &attrsize, &attrtype, nameBuf);
mContext->gl->fGetActiveAttrib(mGLName, i, mAttribMaxNameLength, &attrnamelen, &attrsize, &attrtype, nameBuf);
if (attrnamelen > 0) {
GLint loc = gl->fGetAttribLocation(mGLName, nameBuf);
mAttribsInUse[loc] = true;
GLint loc = mContext->gl->fGetAttribLocation(mGLName, nameBuf);
NS_ABORT_IF_FALSE(loc >= 0, "major oops in managing the attributes of a WebGL program");
if (loc < mContext->mGLMaxVertexAttribs) {
mAttribsInUse[loc] = true;
} else {
mContext->ErrorInvalidOperation("program exceeds MAX_VERTEX_ATTRIBS");
return false;
}
}
}
@ -334,7 +342,7 @@ bool WebGLContext::ValidateDrawModeEnum(WebGLenum mode, const char *info)
bool WebGLContext::ValidateGLSLVariableName(const nsAString& name, const char *info)
{
const PRUint32 maxSize = 255;
const PRUint32 maxSize = 256;
if (name.Length() > maxSize) {
ErrorInvalidValue("%s: identifier is %d characters long, exceeds the maximum allowed length of %d characters",
info, name.Length(), maxSize);

View File

@ -1,13 +1,7 @@
conformance/context/premultiplyalpha-test.html
conformance/glsl/misc/glsl-long-variable-names.html
conformance/glsl/misc/shader-with-256-character-identifier.frag.html
conformance/glsl/misc/shader-with-long-line.html
conformance/misc/uninitialized-test.html
conformance/programs/gl-get-active-attribute.html
conformance/textures/texture-mips.html
conformance/uniforms/gl-uniform-bool.html
conformance/more/conformance/quickCheckAPI-S_V.html
conformance/more/functions/uniformfArrayLen1.html
conformance/glsl/misc/attrib-location-length-limits.html
conformance/glsl/misc/uniform-location-length-limits.html
conformance/renderbuffers/framebuffer-object-attachment.html

View File

@ -1,11 +1,6 @@
conformance/context/premultiplyalpha-test.html
conformance/glsl/misc/glsl-function-nodes.html
conformance/glsl/misc/glsl-long-variable-names.html
conformance/glsl/misc/shader-with-256-character-identifier.frag.html
conformance/glsl/misc/shader-with-long-line.html
conformance/more/conformance/quickCheckAPI-S_V.html
conformance/glsl/misc/attrib-location-length-limits.html
conformance/glsl/misc/uniform-location-length-limits.html
conformance/programs/program-test.html
conformance/textures/texture-mips.html
conformance/textures/texture-npot.html

View File

@ -1,11 +1,6 @@
conformance/context/premultiplyalpha-test.html
conformance/glsl/functions/glsl-function-atan.html
conformance/glsl/functions/glsl-function-atan-xy.html
conformance/glsl/misc/glsl-long-variable-names.html
conformance/glsl/misc/shader-with-256-character-identifier.frag.html
conformance/glsl/misc/shader-with-long-line.html
conformance/more/conformance/quickCheckAPI-S_V.html
conformance/more/functions/uniformfArrayLen1.html
conformance/glsl/misc/attrib-location-length-limits.html
conformance/glsl/misc/struct-nesting-under-maximum.html
conformance/glsl/misc/uniform-location-length-limits.html
conformance/more/functions/uniformfArrayLen1.html

View File

@ -45,7 +45,6 @@
#include "nsFrameLoader.h"
#include "nsGkAtoms.h"
#include "nsContentCreatorFunctions.h"
#include "nsDOMMemoryReporter.h"
class nsIDOMAttr;
class nsIDOMEventListener;

View File

@ -14,7 +14,6 @@
#include "nsWeakPtr.h"
#include "nsVariant.h"
#include "nsContentUtils.h"
#include "nsDOMMemoryReporter.h"
#include "nsEventDispatcher.h"
#include "nsContentUtils.h"
#include "nsAsyncDOMEvent.h"

View File

@ -51,7 +51,6 @@
#include "nsIDocument.h"
#include "nsPresContext.h"
#include "nsHTMLDNSPrefetch.h"
#include "nsDOMMemoryReporter.h"
using namespace mozilla::dom;

View File

@ -43,7 +43,6 @@
#include "nsGkAtoms.h"
#include "nsStyleConsts.h"
#include "nsMappedAttributes.h"
#include "nsDOMMemoryReporter.h"
using namespace mozilla;

View File

@ -100,8 +100,8 @@ public:
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsHTMLOutputElement,
nsGenericHTMLFormElement)
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHTMLOutputElement,
nsGenericHTMLFormElement)
virtual nsXPCClassInfo* GetClassInfo();
protected:
@ -136,13 +136,26 @@ nsHTMLOutputElement::~nsHTMLOutputElement()
}
}
NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLOutputElement)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsHTMLOutputElement,
nsGenericHTMLFormElement)
if (tmp->mTokenList) {
tmp->mTokenList->DropReference();
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTokenList)
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLOutputElement,
nsGenericHTMLFormElement)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mTokenList,
nsDOMTokenList)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_ADDREF_INHERITED(nsHTMLOutputElement, nsGenericElement)
NS_IMPL_RELEASE_INHERITED(nsHTMLOutputElement, nsGenericElement)
DOMCI_NODE_DATA(HTMLOutputElement, nsHTMLOutputElement)
NS_INTERFACE_TABLE_HEAD(nsHTMLOutputElement)
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLOutputElement)
NS_HTML_CONTENT_INTERFACE_TABLE3(nsHTMLOutputElement,
nsIDOMHTMLOutputElement,
nsIMutationObserver,

View File

@ -41,7 +41,6 @@
#include "nsStyleConsts.h"
#include "nsIAtom.h"
#include "nsRuleData.h"
#include "nsDOMMemoryReporter.h"
class nsHTMLSpanElement : public nsGenericHTMLElement,
public nsIDOMHTMLElement

View File

@ -49,7 +49,6 @@
#include "nsChangeHint.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsDOMMemoryReporter.h"
#include "nsError.h"
#include "nsGenericElement.h"
#include "nsISupportsImpl.h"

View File

@ -40,8 +40,6 @@
#include "nsGkAtoms.h"
#include "nsIDocument.h"
#include "nsContentUtils.h"
#include "nsDOMMemoryReporter.h"
class nsXMLCDATASection : public nsGenericDOMDataNode,
public nsIDOMCDATASection

View File

@ -104,7 +104,7 @@ EXPORTS = \
nsWrapperCache.h \
nsContentPermissionHelper.h \
nsStructuredCloneContainer.h \
nsDOMMemoryReporter.h \
nsWindowMemoryReporter.h \
$(NULL)
EXPORTS_NAMESPACES = mozilla/dom
@ -139,7 +139,7 @@ CPPSRCS = \
nsStructuredCloneContainer.cpp \
nsDOMNavigationTiming.cpp \
nsPerformance.cpp \
nsDOMMemoryReporter.cpp \
nsWindowMemoryReporter.cpp \
DOMError.cpp \
DOMRequest.cpp \
Navigator.cpp \

View File

@ -140,7 +140,6 @@
#include "nsDOMError.h"
#include "nsIDOMDOMException.h"
#include "nsIDOMNode.h"
#include "nsIDOMNodeList.h"
#include "nsIDOMNamedNodeMap.h"
#include "nsIDOMDOMStringList.h"
#include "nsIDOMDOMTokenList.h"
@ -152,8 +151,6 @@
#include "nsIForm.h"
#include "nsIFormControl.h"
#include "nsIDOMHTMLFormElement.h"
#include "nsIDOMHTMLCollection.h"
#include "nsIHTMLCollection.h"
#include "nsHTMLDocument.h"
// Constraint Validation API helper includes
@ -168,12 +165,7 @@
#include "nsIObjectLoadingContent.h"
#include "nsIPluginHost.h"
// HTMLOptionsCollection includes
#include "nsIDOMHTMLOptionElement.h"
#include "nsIDOMHTMLOptionsCollection.h"
// ContentList includes
#include "nsContentList.h"
#include "nsGenericElement.h"
// Event related includes
@ -785,7 +777,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA(CDATASection, nsNodeSH, NODE_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(ProcessingInstruction, nsNodeSH,
NODE_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(NodeList, nsNodeListSH, ARRAY_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(NodeList, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(NamedNodeMap, nsNamedNodeMapSH,
ARRAY_SCRIPTABLE_FLAGS)
@ -824,13 +817,10 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA(HTMLDocument, nsHTMLDocumentSH,
DOCUMENT_SCRIPTABLE_FLAGS |
nsIXPCScriptable::WANT_GETPROPERTY)
NS_DEFINE_CLASSINFO_DATA(HTMLOptionsCollection,
nsHTMLOptionsCollectionSH,
ARRAY_SCRIPTABLE_FLAGS |
nsIXPCScriptable::WANT_SETPROPERTY)
NS_DEFINE_CLASSINFO_DATA(HTMLCollection,
nsHTMLCollectionSH,
ARRAY_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(HTMLOptionsCollection, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(HTMLCollection, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
// HTML element classes
NS_DEFINE_CLASSINFO_DATA(HTMLElement, nsElementSH,
@ -1041,7 +1031,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
ARRAY_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA_WITH_NAME(ContentList, HTMLCollection,
nsContentListSH, ARRAY_SCRIPTABLE_FLAGS)
nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(XMLStylesheetProcessingInstruction, nsNodeSH,
NODE_SCRIPTABLE_FLAGS)
@ -4460,7 +4451,7 @@ nsDOMClassInfo::GetArrayIndexFromId(JSContext *cx, jsid id, bool *aIsNumber)
*aIsNumber = false;
}
jsint i;
int i;
if (JSID_IS_INT(id)) {
i = JSID_TO_INT(id);
} else {
@ -8020,74 +8011,6 @@ nsArraySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
}
// NodeList scriptable helper
nsresult
nsNodeListSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
JSObject *globalObj, JSObject **parentObj)
{
nsINodeList* list = static_cast<nsINodeList*>(nativeObj);
#ifdef DEBUG
{
nsCOMPtr<nsINodeList> list_qi = do_QueryInterface(nativeObj);
// If this assertion fires the QI implementation for the object in
// question doesn't use the nsINodeList pointer as the nsISupports
// pointer. That must be fixed, or we'll crash...
NS_ASSERTION(list_qi == list, "Uh, fix QI!");
}
#endif
nsINode* native_parent = list->GetParentObject();
nsresult rv =
WrapNativeParent(cx, globalObj, native_parent, native_parent, parentObj);
NS_ENSURE_SUCCESS(rv, rv);
return NS_SUCCESS_ALLOW_SLIM_WRAPPERS;
}
nsresult
nsNodeListSH::GetLength(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, PRUint32 *length)
{
nsINodeList* list = static_cast<nsINodeList*>(GetNative(wrapper, obj));
#ifdef DEBUG
{
nsCOMPtr<nsINodeList> list_qi = do_QueryWrappedNative(wrapper, obj);
// If this assertion fires the QI implementation for the object in
// question doesn't use the nsINodeList pointer as the nsISupports
// pointer. That must be fixed, or we'll crash...
NS_ABORT_IF_FALSE(list_qi == list, "Uh, fix QI!");
}
#endif
return list->GetLength(length);
}
nsISupports*
nsNodeListSH::GetItemAt(nsISupports *aNative, PRUint32 aIndex,
nsWrapperCache **aCache, nsresult *aResult)
{
nsINodeList* list = static_cast<nsINodeList*>(aNative);
#ifdef DEBUG
{
nsCOMPtr<nsINodeList> list_qi = do_QueryInterface(aNative);
// If this assertion fires the QI implementation for the object in
// question doesn't use the nsINodeList pointer as the nsISupports
// pointer. That must be fixed, or we'll crash...
NS_ABORT_IF_FALSE(list_qi == list, "Uh, fix QI!");
}
#endif
nsINode *node;
*aCache = node = list->GetNodeAt(aIndex);
return node;
}
// StringList scriptable helper
nsresult
@ -8248,146 +8171,6 @@ nsNamedNodeMapSH::GetNamedItem(nsISupports *aNative, const nsAString& aName,
}
// HTMLCollection helper
nsresult
nsHTMLCollectionSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
JSObject *globalObj, JSObject **parentObj)
{
nsIHTMLCollection* list = static_cast<nsIHTMLCollection*>(nativeObj);
#ifdef DEBUG
{
nsCOMPtr<nsIHTMLCollection> list_qi = do_QueryInterface(nativeObj);
// If this assertion fires the QI implementation for the object in
// question doesn't use the nsIHTMLCollection pointer as the nsISupports
// pointer. That must be fixed, or we'll crash...
NS_ASSERTION(list_qi == list, "Uh, fix QI!");
}
#endif
nsINode* native_parent = list->GetParentObject();
nsresult rv =
WrapNativeParent(cx, globalObj, native_parent, native_parent, parentObj);
NS_ENSURE_SUCCESS(rv, rv);
return NS_SUCCESS_ALLOW_SLIM_WRAPPERS;
}
nsresult
nsHTMLCollectionSH::GetLength(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, PRUint32 *length)
{
nsIHTMLCollection* collection =
static_cast<nsIHTMLCollection*>(GetNative(wrapper, obj));
#ifdef DEBUG
{
nsCOMPtr<nsIHTMLCollection> collection_qi =
do_QueryWrappedNative(wrapper, obj);
// If this assertion fires the QI implementation for the object in
// question doesn't use the nsIHTMLCollection pointer as the nsISupports
// pointer. That must be fixed, or we'll crash...
NS_ABORT_IF_FALSE(collection_qi == collection, "Uh, fix QI!");
}
#endif
return collection->GetLength(length);
}
nsISupports*
nsHTMLCollectionSH::GetItemAt(nsISupports *aNative, PRUint32 aIndex,
nsWrapperCache **aCache, nsresult *aResult)
{
nsIHTMLCollection* collection = static_cast<nsIHTMLCollection*>(aNative);
#ifdef DEBUG
{
nsCOMPtr<nsIHTMLCollection> collection_qi = do_QueryInterface(aNative);
// If this assertion fires the QI implementation for the object in
// question doesn't use the nsIHTMLCollection pointer as the nsISupports
// pointer. That must be fixed, or we'll crash...
NS_ABORT_IF_FALSE(collection_qi == collection, "Uh, fix QI!");
}
#endif
nsINode *item;
*aCache = item = collection->GetNodeAt(aIndex);
return item;
}
nsISupports*
nsHTMLCollectionSH::GetNamedItem(nsISupports *aNative,
const nsAString& aName,
nsWrapperCache **aCache,
nsresult *aResult)
{
nsIHTMLCollection* collection = static_cast<nsIHTMLCollection*>(aNative);
#ifdef DEBUG
{
nsCOMPtr<nsIHTMLCollection> collection_qi = do_QueryInterface(aNative);
// If this assertion fires the QI implementation for the object in
// question doesn't use the nsIHTMLCollection pointer as the nsISupports
// pointer. That must be fixed, or we'll crash...
NS_ABORT_IF_FALSE(collection_qi == collection, "Uh, fix QI!");
}
#endif
return collection->GetNamedItem(aName, aCache);
}
// ContentList helper
nsresult
nsContentListSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
JSObject *globalObj, JSObject **parentObj)
{
nsContentList *contentList = nsContentList::FromSupports(nativeObj);
nsINode *native_parent = contentList->GetParentObject();
if (!native_parent) {
return NS_ERROR_FAILURE;
}
nsresult rv =
WrapNativeParent(cx, globalObj, native_parent, native_parent, parentObj);
NS_ENSURE_SUCCESS(rv, rv);
return NS_SUCCESS_ALLOW_SLIM_WRAPPERS;
}
nsresult
nsContentListSH::GetLength(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, PRUint32 *length)
{
nsContentList *list =
nsContentList::FromSupports(GetNative(wrapper, obj));
return list->GetLength(length);
}
nsISupports*
nsContentListSH::GetItemAt(nsISupports *aNative, PRUint32 aIndex,
nsWrapperCache **aCache, nsresult *aResult)
{
nsContentList *list = nsContentList::FromSupports(aNative);
nsIContent *item;
*aCache = item = list->GetNodeAt(aIndex);
return item;
}
nsISupports*
nsContentListSH::GetNamedItem(nsISupports *aNative, const nsAString& aName,
nsWrapperCache **aCache, nsresult *aResult)
{
nsContentList *list = nsContentList::FromSupports(aNative);
return list->GetNamedItem(aName, aCache);
}
NS_IMETHODIMP
nsDOMStringMapSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, PRUint32 flags,
@ -9917,31 +9700,6 @@ nsHTMLPluginObjElementSH::NewResolve(nsIXPConnectWrappedNative *wrapper,
_retval);
}
// HTMLOptionsCollection helper
NS_IMETHODIMP
nsHTMLOptionsCollectionSH::SetProperty(nsIXPConnectWrappedNative *wrapper,
JSContext *cx, JSObject *obj, jsid id,
jsval *vp, bool *_retval)
{
PRInt32 n = GetArrayIndexFromId(cx, id);
if (n < 0) {
return NS_OK;
}
nsCOMPtr<nsIDOMHTMLOptionsCollection> oc =
do_QueryWrappedNative(wrapper, obj);
NS_ENSURE_TRUE(oc, NS_ERROR_UNEXPECTED);
nsresult rv = nsHTMLSelectElementSH::SetOption(cx, vp, n, oc);
if (NS_SUCCEEDED(rv)) {
rv = NS_SUCCESS_I_DID_SOMETHING;
}
return rv;
}
// Plugin helper
nsISupports*

View File

@ -61,7 +61,6 @@ class DOMSVGTransformList;
class nsGlobalWindow;
class nsIDOMDocument;
class nsIDOMHTMLOptionsCollection;
class nsIDOMNodeList;
class nsIDOMSVGLength;
class nsIDOMSVGLengthList;
class nsIDOMSVGNumber;
@ -624,31 +623,6 @@ private:
};
// NodeList scriptable helper
class nsNodeListSH : public nsArraySH
{
protected:
nsNodeListSH(nsDOMClassInfoData* aData) : nsArraySH(aData)
{
}
public:
NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
JSObject *globalObj, JSObject **parentObj);
virtual nsresult GetLength(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, PRUint32 *length);
virtual nsISupports* GetItemAt(nsISupports *aNative, PRUint32 aIndex,
nsWrapperCache **aCache, nsresult *aResult);
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
{
return new nsNodeListSH(aData);
}
};
// NamedArray helper
class nsNamedArraySH : public nsArraySH
@ -711,70 +685,6 @@ public:
};
// HTMLCollection helper
class nsHTMLCollectionSH : public nsNamedArraySH
{
protected:
nsHTMLCollectionSH(nsDOMClassInfoData* aData) : nsNamedArraySH(aData)
{
}
virtual ~nsHTMLCollectionSH()
{
}
virtual nsresult GetLength(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, PRUint32 *length);
virtual nsISupports* GetItemAt(nsISupports *aNative, PRUint32 aIndex,
nsWrapperCache **aCache, nsresult *aResult);
// Override nsNamedArraySH::GetNamedItem()
virtual nsISupports* GetNamedItem(nsISupports *aNative,
const nsAString& aName,
nsWrapperCache **cache,
nsresult *aResult);
public:
NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
JSObject *globalObj, JSObject **parentObj);
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
{
return new nsHTMLCollectionSH(aData);
}
};
// ContentList helper
class nsContentListSH : public nsNamedArraySH
{
protected:
nsContentListSH(nsDOMClassInfoData* aData) : nsNamedArraySH(aData)
{
}
public:
NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
JSObject *globalObj, JSObject **parentObj);
virtual nsresult GetLength(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, PRUint32 *length);
virtual nsISupports* GetItemAt(nsISupports *aNative, PRUint32 aIndex,
nsWrapperCache **aCache, nsresult *aResult);
virtual nsISupports* GetNamedItem(nsISupports *aNative,
const nsAString& aName,
nsWrapperCache **cache,
nsresult *aResult);
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
{
return new nsContentListSH(aData);
}
};
// DOMStringMap helper for .dataset property on elements.
class nsDOMStringMapSH : public nsDOMGenericSH
@ -1007,31 +917,6 @@ public:
};
// HTMLOptionsCollection helper
class nsHTMLOptionsCollectionSH : public nsHTMLCollectionSH
{
protected:
nsHTMLOptionsCollectionSH(nsDOMClassInfoData* aData)
: nsHTMLCollectionSH(aData)
{
}
virtual ~nsHTMLOptionsCollectionSH()
{
}
public:
NS_IMETHOD SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, jsval *vp, bool *_retval);
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
{
return new nsHTMLOptionsCollectionSH(aData);
}
};
// Plugin helper
class nsPluginSH : public nsNamedArraySH

View File

@ -35,22 +35,22 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsDOMMemoryReporter.h"
#include "nsWindowMemoryReporter.h"
#include "nsGlobalWindow.h"
nsDOMMemoryMultiReporter::nsDOMMemoryMultiReporter()
nsWindowMemoryReporter::nsWindowMemoryReporter()
{
}
NS_IMPL_ISUPPORTS1(nsDOMMemoryMultiReporter, nsIMemoryMultiReporter)
NS_IMPL_ISUPPORTS1(nsWindowMemoryReporter, nsIMemoryMultiReporter)
/* static */
void
nsDOMMemoryMultiReporter::Init()
nsWindowMemoryReporter::Init()
{
// The memory reporter manager is going to own this object.
NS_RegisterMemoryMultiReporter(new nsDOMMemoryMultiReporter());
NS_RegisterMemoryMultiReporter(new nsWindowMemoryReporter());
}
static bool
@ -88,18 +88,11 @@ AppendWindowURI(nsGlobalWindow *aWindow, nsACString& aStr)
return true;
}
struct WindowTotals
{
WindowTotals() : mDom(0), mStyleSheets(0) {}
size_t mDom;
size_t mStyleSheets;
};
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(DOMStyleMallocSizeOf, "dom+style")
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(DOMStyleMallocSizeOf, "windows")
static void
CollectWindowReports(nsGlobalWindow *aWindow,
WindowTotals *aWindowTotals,
nsWindowSizes *aWindowTotalSizes,
nsIMemoryMultiReporterCallback *aCb,
nsISupports *aClosure)
{
@ -126,7 +119,7 @@ CollectWindowReports(nsGlobalWindow *aWindow,
// The path we give to the reporter callback for inner windows are
// as follows:
//
// explicit/dom+style/window-objects/<category>/top=<top-outer-id> (inner=<top-inner-id>)/inner-window(id=<id>, uri=<uri>)
// explicit/window-objects/<category>/top=<top-outer-id> (inner=<top-inner-id>)/inner-window(id=<id>, uri=<uri>)
//
// Where:
// - <category> is active, cached, or other, as described above.
@ -145,12 +138,12 @@ CollectWindowReports(nsGlobalWindow *aWindow,
//
// For outer windows we simply use:
//
// explicit/dom+style/window-objects/<category>/outer-windows
// explicit/window-objects/<category>/outer-windows
//
// Which gives us simple counts of how many outer windows (and their
// combined sizes) per category.
nsCAutoString windowPath("explicit/dom+style/window-objects/");
nsCAutoString windowPath("explicit/window-objects/");
nsIDocShell *docShell = aWindow->GetDocShell();
@ -199,28 +192,40 @@ CollectWindowReports(nsGlobalWindow *aWindow,
windowPath += NS_LITERAL_CSTRING("outer-windows");
}
if (windowSizes.mDOM > 0) {
nsCAutoString domPath(windowPath);
domPath += "/dom";
NS_NAMED_LITERAL_CSTRING(kWindowDesc,
"Memory used by a window and the DOM within it.");
aCb->Callback(EmptyCString(), domPath, nsIMemoryReporter::KIND_HEAP,
nsIMemoryReporter::UNITS_BYTES, windowSizes.mDOM,
kWindowDesc, aClosure);
aWindowTotals->mDom += windowSizes.mDOM;
}
#define REPORT(_path1, _path2, _amount, _desc) \
do { \
if (_amount > 0) { \
nsCAutoString path(_path1); \
path += _path2; \
aCb->Callback(EmptyCString(), path, nsIMemoryReporter::KIND_HEAP, \
nsIMemoryReporter::UNITS_BYTES, _amount, \
NS_LITERAL_CSTRING(_desc), aClosure); \
} \
} while (0)
if (windowSizes.mStyleSheets > 0) {
nsCAutoString styleSheetsPath(windowPath);
styleSheetsPath += "/style-sheets";
NS_NAMED_LITERAL_CSTRING(kStyleSheetsDesc,
"Memory used by style sheets within a window.");
aCb->Callback(EmptyCString(), styleSheetsPath,
nsIMemoryReporter::KIND_HEAP,
nsIMemoryReporter::UNITS_BYTES, windowSizes.mStyleSheets,
kStyleSheetsDesc, aClosure);
aWindowTotals->mStyleSheets += windowSizes.mStyleSheets;
}
REPORT(windowPath, "/dom", windowSizes.mDOM,
"Memory used by a window and the DOM within it.");
aWindowTotalSizes->mDOM += windowSizes.mDOM;
REPORT(windowPath, "/style-sheets", windowSizes.mStyleSheets,
"Memory used by style sheets within a window.");
aWindowTotalSizes->mStyleSheets += windowSizes.mStyleSheets;
REPORT(windowPath, "/layout/arenas", windowSizes.mLayoutArenas,
"Memory used by layout PresShell, PresContext, and other related "
"areas within a window.");
aWindowTotalSizes->mLayoutArenas += windowSizes.mLayoutArenas;
REPORT(windowPath, "/layout/style-sets", windowSizes.mLayoutStyleSets,
"Memory used by style sets within a window.");
aWindowTotalSizes->mLayoutStyleSets += windowSizes.mLayoutStyleSets;
REPORT(windowPath, "/layout/text-runs", windowSizes.mLayoutTextRuns,
"Memory used for text-runs (glyph layout) in the PresShell's frame "
"tree, within a window.");
aWindowTotalSizes->mLayoutTextRuns += windowSizes.mLayoutTextRuns;
#undef REPORT
}
typedef nsTArray< nsRefPtr<nsGlobalWindow> > WindowArray;
@ -235,15 +240,15 @@ GetWindows(const PRUint64& aId, nsGlobalWindow*& aWindow, void* aClosure)
}
NS_IMETHODIMP
nsDOMMemoryMultiReporter::GetName(nsACString &aName)
nsWindowMemoryReporter::GetName(nsACString &aName)
{
aName.AssignLiteral("dom+style");
aName.AssignLiteral("window-objects");
return NS_OK;
}
NS_IMETHODIMP
nsDOMMemoryMultiReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb,
nsISupports* aClosure)
nsWindowMemoryReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb,
nsISupports* aClosure)
{
nsGlobalWindow::WindowByIdTable* windowsById =
nsGlobalWindow::GetWindowsTable();
@ -257,32 +262,47 @@ nsDOMMemoryMultiReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb,
// Collect window memory usage.
nsRefPtr<nsGlobalWindow> *w = windows.Elements();
nsRefPtr<nsGlobalWindow> *end = w + windows.Length();
WindowTotals windowTotals;
nsWindowSizes windowTotalSizes(NULL);
for (; w != end; ++w) {
CollectWindowReports(*w, &windowTotals, aCb, aClosure);
CollectWindowReports(*w, &windowTotalSizes, aCb, aClosure);
}
NS_NAMED_LITERAL_CSTRING(kDomTotalWindowsDesc,
"Memory used for the DOM within windows. This is the sum of all windows' "
"'dom' numbers.");
aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING("dom-total-window"),
nsIMemoryReporter::KIND_OTHER,
nsIMemoryReporter::UNITS_BYTES, windowTotals.mDom,
kDomTotalWindowsDesc, aClosure);
#define REPORT(_path, _amount, _desc) \
do { \
aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), \
nsIMemoryReporter::KIND_OTHER, \
nsIMemoryReporter::UNITS_BYTES, _amount, \
NS_LITERAL_CSTRING(_desc), aClosure); \
} while (0)
NS_NAMED_LITERAL_CSTRING(kLayoutTotalWindowStyleSheetsDesc,
"Memory used for style sheets within windows. This is the sum of all windows' "
"'style-sheets' numbers.");
aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING("style-sheets-total-window"),
nsIMemoryReporter::KIND_OTHER,
nsIMemoryReporter::UNITS_BYTES, windowTotals.mStyleSheets,
kLayoutTotalWindowStyleSheetsDesc, aClosure);
REPORT("window-objects-dom", windowTotalSizes.mDOM,
"Memory used for the DOM within windows. "
"This is the sum of all windows' 'dom' numbers.");
REPORT("window-objects-style-sheets", windowTotalSizes.mStyleSheets,
"Memory used for style sheets within windows. "
"This is the sum of all windows' 'style-sheets' numbers.");
REPORT("window-objects-layout-arenas", windowTotalSizes.mLayoutArenas,
"Memory used by layout PresShell, PresContext, and other related "
"areas within windows. This is the sum of all windows' "
"'layout/arenas' numbers.");
REPORT("window-objects-layout-style-sets", windowTotalSizes.mLayoutStyleSets,
"Memory used for style sets within windows. "
"This is the sum of all windows' 'layout/style-sets' numbers.");
REPORT("window-objects-layout-text-runs", windowTotalSizes.mLayoutTextRuns,
"Memory used for text runs within windows. "
"This is the sum of all windows' 'layout/text-runs' numbers.");
#undef REPORT
return NS_OK;
}
NS_IMETHODIMP
nsDOMMemoryMultiReporter::GetExplicitNonHeap(PRInt64* aAmount)
nsWindowMemoryReporter::GetExplicitNonHeap(PRInt64* aAmount)
{
// This reporter only measures heap memory.
*aAmount = 0;

View File

@ -35,8 +35,8 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsDOMMemoryReporter_h__
#define nsDOMMemoryReporter_h__
#ifndef nsWindowMemoryReporter_h__
#define nsWindowMemoryReporter_h__
#include "nsIMemoryReporter.h"
@ -49,17 +49,19 @@
class nsWindowSizes {
public:
nsWindowSizes(nsMallocSizeOfFun aMallocSizeOf)
: mMallocSizeOf(aMallocSizeOf),
mDOM(0),
mStyleSheets(0)
{}
nsWindowSizes(nsMallocSizeOfFun aMallocSizeOf) {
memset(this, 0, sizeof(nsWindowSizes));
mMallocSizeOf = aMallocSizeOf;
}
nsMallocSizeOfFun mMallocSizeOf;
size_t mDOM;
size_t mStyleSheets;
size_t mLayoutArenas;
size_t mLayoutStyleSets;
size_t mLayoutTextRuns;
};
class nsDOMMemoryMultiReporter: public nsIMemoryMultiReporter
class nsWindowMemoryReporter: public nsIMemoryMultiReporter
{
public:
NS_DECL_ISUPPORTS
@ -69,8 +71,8 @@ public:
private:
// Protect ctor, use Init() instead.
nsDOMMemoryMultiReporter();
nsWindowMemoryReporter();
};
#endif // nsDOMMemoryReporter_h__
#endif // nsWindowMemoryReporter_h__

View File

@ -49,11 +49,11 @@ interface nsIDOMDOMTokenList : nsISupports
{
readonly attribute unsigned long length;
DOMString item(in unsigned long index);
[getter] DOMString item(in unsigned long index);
boolean contains([Null(Stringify)] in DOMString token);
void add([Null(Stringify)] in DOMString token);
void remove([Null(Stringify)] in DOMString token);
boolean toggle([Null(Stringify)] in DOMString token);
DOMString toString();
[stringifier] DOMString toString();
};

View File

@ -457,7 +457,7 @@ JSValToNPVariant(NPP npp, JSContext *cx, jsval val, NPVariant *variant)
INT32_TO_NPVARIANT(JSVAL_TO_INT(val), *variant);
} else if (JSVAL_IS_DOUBLE(val)) {
double d = JSVAL_TO_DOUBLE(val);
jsint i;
int i;
if (JS_DoubleIsInt32(d, &i)) {
INT32_TO_NPVARIANT(i, *variant);
} else {

View File

@ -157,14 +157,14 @@ NPIdentifierIsInt(NPIdentifier id)
return JSID_IS_INT(NPIdentifierToJSId(id));
}
inline jsint
inline int
NPIdentifierToInt(NPIdentifier id)
{
return JSID_TO_INT(NPIdentifierToJSId(id));
}
inline NPIdentifier
IntToNPIdentifier(jsint i)
IntToNPIdentifier(int i)
{
return JSIdToNPIdentifier(INT_TO_JSID(i));
}

View File

@ -94,16 +94,19 @@ function startTest()
// add a second key
localStorage.setItem("key2", "value2");
is(localStorage.length, 2, "The storage has two key-value pairs");
is(localStorage.key(1), "key1"); // This test might not be accurate because order is not preserved
is(localStorage.key(0), "key2");
is(localStorage.getItem("key1"), "value1");
is(localStorage.getItem("key2"), "value2");
var firstKey = localStorage.key(0);
var secondKey = localStorage.key(1);
ok((firstKey == 'key1' && secondKey == 'key2') ||
(firstKey == 'key2' && secondKey == 'key1'),
'Both keys should be present.');
// change the second key
localStorage.setItem("key2", "value2-2");
is(localStorage.length, 2, "The storage has two key-value pairs");
is(localStorage.key(1), "key1"); // After key value changes the order must be preserved
is(localStorage.key(0), "key2");
is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
is(localStorage.key(1), secondKey);
checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
is(localStorage.getItem("key1"), "value1");
@ -112,8 +115,8 @@ function startTest()
// change the first key
localStorage.setItem("key1", "value1-2");
is(localStorage.length, 2, "The storage has two key-value pairs");
is(localStorage.key(1), "key1"); // After key value changes the order must be preserved
is(localStorage.key(0), "key2");
is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
is(localStorage.key(1), secondKey);
checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
is(localStorage.getItem("key1"), "value1-2");

View File

@ -113,16 +113,19 @@ function doTest()
// add a second key
localStorage.setItem("key2", "value2");
is(localStorage.length, 2, "The storage has two key-value pairs");
is(localStorage.key(1), "key1"); // This test might not be accurate because order is not preserved
is(localStorage.key(0), "key2");
is(localStorage.getItem("key1"), "value1");
is(localStorage.getItem("key2"), "value2");
var firstKey = localStorage.key(0);
var secondKey = localStorage.key(1);
ok((firstKey == 'key1' && secondKey == 'key2') ||
(firstKey == 'key2' && secondKey == 'key1'),
'Both keys should be present.');
// change the second key
localStorage.setItem("key2", "value2-2");
is(localStorage.length, 2, "The storage has two key-value pairs");
is(localStorage.key(1), "key1"); // After key value changes the order must be preserved
is(localStorage.key(0), "key2");
is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
is(localStorage.key(1), secondKey);
checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
is(localStorage.getItem("key1"), "value1");
@ -131,8 +134,8 @@ function doTest()
// change the first key
localStorage.setItem("key1", "value1-2");
is(localStorage.length, 2, "The storage has two key-value pairs");
is(localStorage.key(1), "key1"); // After key value changes the order must be preserved
is(localStorage.key(0), "key2");
is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
is(localStorage.key(1), secondKey);
checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
is(localStorage.getItem("key1"), "value1-2");

View File

@ -104,16 +104,19 @@ function startTest()
// add a second key
localStorage.setItem("key2", "value2");
is(localStorage.length, 2, "The storage has two key-value pairs");
is(localStorage.key(1), "key1"); // This test might not be accurate because order is not preserved
is(localStorage.key(0), "key2");
is(localStorage.getItem("key1"), "value1");
is(localStorage.getItem("key2"), "value2");
var firstKey = localStorage.key(0);
var secondKey = localStorage.key(1);
ok((firstKey == 'key1' && secondKey == 'key2') ||
(firstKey == 'key2' && secondKey == 'key1'),
'Both keys should be present.');
// change the second key
localStorage.setItem("key2", "value2-2");
is(localStorage.length, 2, "The storage has two key-value pairs");
is(localStorage.key(1), "key1"); // After key value changes the order must be preserved
is(localStorage.key(0), "key2");
is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
is(localStorage.key(1), secondKey);
checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
is(localStorage.getItem("key1"), "value1");
@ -122,8 +125,8 @@ function startTest()
// change the first key
localStorage.setItem("key1", "value1-2");
is(localStorage.length, 2, "The storage has two key-value pairs");
is(localStorage.key(1), "key1"); // After key value changes the order must be preserved
is(localStorage.key(0), "key2");
is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
is(localStorage.key(1), secondKey);
checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
is(localStorage.getItem("key1"), "value1-2");

View File

@ -96,16 +96,19 @@ function startTest()
// add a second key
sessionStorage.setItem("key2", "value2");
is(sessionStorage.length, 2, "The storage has two key-value pairs");
is(sessionStorage.key(1), "key1"); // This test might not be accurate because order is not preserved
is(sessionStorage.key(0), "key2");
is(sessionStorage.getItem("key1"), "value1");
is(sessionStorage.getItem("key2"), "value2");
var firstKey = sessionStorage.key(0);
var secondKey = sessionStorage.key(1);
ok((firstKey == 'key1' && secondKey == 'key2') ||
(firstKey == 'key2' && secondKey == 'key1'),
'Both keys should be present.');
// change the second key
sessionStorage.setItem("key2", "value2-2");
is(sessionStorage.length, 2, "The storage has two key-value pairs");
is(sessionStorage.key(1), "key1"); // After key value changes the order must be preserved
is(sessionStorage.key(0), "key2");
is(sessionStorage.key(0), firstKey); // After key value changes the order must be preserved
is(sessionStorage.key(1), secondKey);
checkException(function() {sessionStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {sessionStorage.key(2);}, INDEX_SIZE_ERR);
is(sessionStorage.getItem("key1"), "value1");
@ -114,8 +117,8 @@ function startTest()
// change the first key
sessionStorage.setItem("key1", "value1-2");
is(sessionStorage.length, 2, "The storage has two key-value pairs");
is(sessionStorage.key(1), "key1"); // After key value changes the order must be preserved
is(sessionStorage.key(0), "key2");
is(sessionStorage.key(0), firstKey); // After key value changes the order must be preserved
is(sessionStorage.key(1), secondKey);
checkException(function() {sessionStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {sessionStorage.key(2);}, INDEX_SIZE_ERR);
is(sessionStorage.getItem("key1"), "value1-2");

View File

@ -46,7 +46,6 @@ nsComposeTxtSrvFilter::nsComposeTxtSrvFilter() :
{
mBlockQuoteAtom = do_GetAtom("blockquote");
mPreAtom = do_GetAtom("pre");
mSpanAtom = do_GetAtom("span");
mTableAtom = do_GetAtom("table");
mMozQuoteAtom = do_GetAtom("_moz_quote");
@ -79,7 +78,7 @@ nsComposeTxtSrvFilter::Skip(nsIDOMNode* aNode, bool *_retval)
*_retval = content->AttrValueIs(kNameSpaceID_None, mTypeAtom,
mCiteAtom, eIgnoreCase);
}
} else if (tag == mPreAtom || tag == mSpanAtom) {
} else if (tag == mSpanAtom) {
if (mIsForMail) {
*_retval = content->AttrValueIs(kNameSpaceID_None, mMozQuoteAtom,
mTrueAtom, eIgnoreCase);

View File

@ -66,8 +66,7 @@ public:
protected:
bool mIsForMail;
nsCOMPtr<nsIAtom> mBlockQuoteAtom;
nsCOMPtr<nsIAtom> mPreAtom; // mail plain text quotes are wrapped in pre tags
nsCOMPtr<nsIAtom> mSpanAtom; //or they may be wrapped in span tags (editor.quotesPreformatted).
nsCOMPtr<nsIAtom> mSpanAtom; // mail plain text quotes are wrapped in span tags
nsCOMPtr<nsIAtom> mMozQuoteAtom; // _moz_quote_
nsCOMPtr<nsIAtom> mTableAtom;
nsCOMPtr<nsIAtom> mClassAtom;

View File

@ -1968,94 +1968,63 @@ nsHTMLEditor::InsertAsPlaintextQuotation(const nsAString & aQuotedText,
if (mWrapToWindow)
return nsPlaintextEditor::InsertAsQuotation(aQuotedText, aNodeInserted);
nsresult rv;
// The quotesPreformatted pref is a temporary measure. See bug 69638.
// Eventually we'll pick one way or the other.
bool quotesInPre = false;
nsCOMPtr<nsIPrefBranch> prefBranch =
do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv) && prefBranch)
prefBranch->GetBoolPref("editor.quotesPreformatted", &quotesInPre);
nsCOMPtr<nsIDOMNode> preNode;
// get selection
nsCOMPtr<nsISelection> selection;
rv = GetSelection(getter_AddRefs(selection));
nsresult rv = GetSelection(getter_AddRefs(selection));
NS_ENSURE_SUCCESS(rv, rv);
if (!selection)
{
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
}
else
{
nsAutoEditBatch beginBatching(this);
nsAutoRules beginRulesSniffing(this, kOpInsertQuotation, nsIEditor::eNext);
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
// give rules a chance to handle or cancel
nsTextRulesInfo ruleInfo(nsTextEditRules::kInsertElement);
bool cancel, handled;
rv = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
NS_ENSURE_SUCCESS(rv, rv);
if (cancel) return NS_OK; // rules canceled the operation
if (!handled)
nsAutoEditBatch beginBatching(this);
nsAutoRules beginRulesSniffing(this, kOpInsertQuotation, nsIEditor::eNext);
// give rules a chance to handle or cancel
nsTextRulesInfo ruleInfo(nsTextEditRules::kInsertElement);
bool cancel, handled;
rv = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
NS_ENSURE_SUCCESS(rv, rv);
if (cancel) return NS_OK; // rules canceled the operation
if (!handled)
{
// Wrap the inserted quote in a <span> so it won't be wrapped:
rv = DeleteSelectionAndCreateNode(NS_LITERAL_STRING("span"), getter_AddRefs(preNode));
// If this succeeded, then set selection inside the pre
// so the inserted text will end up there.
// If it failed, we don't care what the return value was,
// but we'll fall through and try to insert the text anyway.
if (NS_SUCCEEDED(rv) && preNode)
{
// Wrap the inserted quote in a <pre> so it won't be wrapped:
nsAutoString tag;
if (quotesInPre)
tag.AssignLiteral("pre");
else
tag.AssignLiteral("span");
rv = DeleteSelectionAndCreateNode(tag, getter_AddRefs(preNode));
// If this succeeded, then set selection inside the pre
// so the inserted text will end up there.
// If it failed, we don't care what the return value was,
// but we'll fall through and try to insert the text anyway.
if (NS_SUCCEEDED(rv) && preNode)
// Add an attribute on the pre node so we'll know it's a quotation.
// Do this after the insertion, so that
nsCOMPtr<nsIDOMElement> preElement(do_QueryInterface(preNode));
if (preElement)
{
// Add an attribute on the pre node so we'll know it's a quotation.
// Do this after the insertion, so that
nsCOMPtr<nsIDOMElement> preElement (do_QueryInterface(preNode));
if (preElement)
{
preElement->SetAttribute(NS_LITERAL_STRING("_moz_quote"),
NS_LITERAL_STRING("true"));
if (quotesInPre)
{
// set style to not have unwanted vertical margins
preElement->SetAttribute(NS_LITERAL_STRING("style"),
NS_LITERAL_STRING("margin: 0 0 0 0px;"));
}
else
{
// turn off wrapping on spans
preElement->SetAttribute(NS_LITERAL_STRING("style"),
NS_LITERAL_STRING("white-space: pre;"));
}
}
// and set the selection inside it:
selection->Collapse(preNode, 0);
preElement->SetAttribute(NS_LITERAL_STRING("_moz_quote"),
NS_LITERAL_STRING("true"));
// turn off wrapping on spans
preElement->SetAttribute(NS_LITERAL_STRING("style"),
NS_LITERAL_STRING("white-space: pre;"));
}
// and set the selection inside it:
selection->Collapse(preNode, 0);
}
if (aAddCites)
rv = nsPlaintextEditor::InsertAsQuotation(aQuotedText, aNodeInserted);
else
rv = nsPlaintextEditor::InsertText(aQuotedText);
// Note that if !aAddCites, aNodeInserted isn't set.
// That's okay because the routines that use aAddCites
// don't need to know the inserted node.
if (aAddCites)
rv = nsPlaintextEditor::InsertAsQuotation(aQuotedText, aNodeInserted);
else
rv = nsPlaintextEditor::InsertText(aQuotedText);
// Note that if !aAddCites, aNodeInserted isn't set.
// That's okay because the routines that use aAddCites
// don't need to know the inserted node.
if (aNodeInserted && NS_SUCCEEDED(rv))
{
*aNodeInserted = preNode;
NS_IF_ADDREF(*aNodeInserted);
}
if (aNodeInserted && NS_SUCCEEDED(rv))
{
*aNodeInserted = preNode;
NS_IF_ADDREF(*aNodeInserted);
}
}
// Set the selection to just after the inserted node:
if (NS_SUCCEEDED(rv) && preNode)
{

View File

@ -106,8 +106,7 @@ nsTransactionItem::AddChild(nsTransactionItem *aTransactionItem)
NS_ENSURE_TRUE(aTransactionItem, NS_ERROR_NULL_POINTER);
if (!mUndoStack) {
mUndoStack = new nsTransactionStack();
NS_ENSURE_TRUE(mUndoStack, NS_ERROR_OUT_OF_MEMORY);
mUndoStack = new nsTransactionStack(nsTransactionStack::FOR_UNDO);
}
mUndoStack->Push(aTransactionItem);
@ -187,7 +186,9 @@ nsTransactionItem::GetChild(PRInt32 aIndex, nsTransactionItem **aChild)
if (numItems > 0 && aIndex < numItems) {
NS_ENSURE_TRUE(mUndoStack, NS_ERROR_FAILURE);
return mUndoStack->GetItem(aIndex, aChild);
nsRefPtr<nsTransactionItem> child = mUndoStack->GetItem(aIndex);
child.forget(aChild);
return *aChild ? NS_OK : NS_ERROR_FAILURE;
}
// Adjust the index for the redo stack:
@ -200,7 +201,9 @@ nsTransactionItem::GetChild(PRInt32 aIndex, nsTransactionItem **aChild)
NS_ENSURE_TRUE(mRedoStack && numItems != 0 && aIndex < numItems, NS_ERROR_FAILURE);
return mRedoStack->GetItem(numItems - aIndex - 1, aChild);
nsRefPtr<nsTransactionItem> child = mRedoStack->GetItem(aIndex);
child.forget(aChild);
return *aChild ? NS_OK : NS_ERROR_FAILURE;
}
nsresult
@ -243,20 +246,17 @@ nsTransactionItem::UndoChildren(nsTransactionManager *aTxMgr)
if (mUndoStack) {
if (!mRedoStack && mUndoStack) {
mRedoStack = new nsTransactionRedoStack();
NS_ENSURE_TRUE(mRedoStack, NS_ERROR_OUT_OF_MEMORY);
mRedoStack = new nsTransactionStack(nsTransactionStack::FOR_REDO);
}
/* Undo all of the transaction items children! */
result = mUndoStack->GetSize(&sz);
NS_ENSURE_SUCCESS(result, result);
sz = mUndoStack->GetSize();
while (sz-- > 0) {
result = mUndoStack->Peek(getter_AddRefs(item));
item = mUndoStack->Peek();
if (NS_FAILED(result) || !item) {
return result;
if (!item) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsITransaction> t;
@ -282,15 +282,8 @@ nsTransactionItem::UndoChildren(nsTransactionManager *aTxMgr)
result = item->UndoTransaction(aTxMgr);
if (NS_SUCCEEDED(result)) {
result = mUndoStack->Pop(getter_AddRefs(item));
if (NS_SUCCEEDED(result)) {
result = mRedoStack->Push(item);
/* XXX: If we got an error here, I doubt we can recover!
* XXX: Should we just push the item back on the undo stack?
*/
}
item = mUndoStack->Pop();
mRedoStack->Push(item);
}
nsresult result2 = aTxMgr->DidUndoNotify(t, result);
@ -331,22 +324,18 @@ nsTransactionItem::RedoChildren(nsTransactionManager *aTxMgr)
{
nsRefPtr<nsTransactionItem> item;
nsresult result = NS_OK;
PRInt32 sz = 0;
if (!mRedoStack)
return NS_OK;
/* Redo all of the transaction items children! */
result = mRedoStack->GetSize(&sz);
NS_ENSURE_SUCCESS(result, result);
PRInt32 sz = mRedoStack->GetSize();
while (sz-- > 0) {
result = mRedoStack->Peek(getter_AddRefs(item));
item = mRedoStack->Peek();
if (NS_FAILED(result) || !item) {
return result;
if (!item) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsITransaction> t;
@ -372,14 +361,8 @@ nsTransactionItem::RedoChildren(nsTransactionManager *aTxMgr)
result = item->RedoTransaction(aTxMgr);
if (NS_SUCCEEDED(result)) {
result = mRedoStack->Pop(getter_AddRefs(item));
if (NS_SUCCEEDED(result)) {
result = mUndoStack->Push(item);
// XXX: If we got an error here, I doubt we can recover!
// XXX: Should we just push the item back on the redo stack?
}
item = mRedoStack->Pop();
mUndoStack->Push(item);
}
nsresult result2 = aTxMgr->DidUndoNotify(t, result);
@ -402,7 +385,8 @@ nsTransactionItem::GetNumberOfUndoItems(PRInt32 *aNumItems)
return NS_OK;
}
return mUndoStack->GetSize(aNumItems);
*aNumItems = mUndoStack->GetSize();
return *aNumItems ? NS_OK : NS_ERROR_FAILURE;
}
nsresult
@ -415,7 +399,8 @@ nsTransactionItem::GetNumberOfRedoItems(PRInt32 *aNumItems)
return NS_OK;
}
return mRedoStack->GetSize(aNumItems);
*aNumItems = mRedoStack->GetSize();
return *aNumItems ? NS_OK : NS_ERROR_FAILURE;
}
nsresult

View File

@ -43,14 +43,13 @@
#include "nsCycleCollectionParticipant.h"
class nsTransactionStack;
class nsTransactionRedoStack;
class nsTransactionManager;
class nsTransactionItem
{
nsCOMPtr<nsITransaction> mTransaction;
nsTransactionStack *mUndoStack;
nsTransactionRedoStack *mRedoStack;
nsTransactionStack *mRedoStack;
nsAutoRefCnt mRefCnt;
public:

View File

@ -75,10 +75,10 @@ NS_IMETHODIMP nsTransactionList::GetNumItems(PRInt32 *aNumItems)
NS_ENSURE_TRUE(txMgr, NS_ERROR_FAILURE);
nsresult result = NS_ERROR_FAILURE;
nsresult result = NS_OK;
if (mTxnStack)
result = mTxnStack->GetSize(aNumItems);
*aNumItems = mTxnStack->GetSize();
else if (mTxnItem)
result = mTxnItem->GetNumberOfChildren(aNumItems);
@ -98,10 +98,10 @@ NS_IMETHODIMP nsTransactionList::ItemIsBatch(PRInt32 aIndex, bool *aIsBatch)
nsRefPtr<nsTransactionItem> item;
nsresult result = NS_ERROR_FAILURE;
nsresult result = NS_OK;
if (mTxnStack)
result = mTxnStack->GetItem(aIndex, getter_AddRefs(item));
item = mTxnStack->GetItem(aIndex);
else if (mTxnItem)
result = mTxnItem->GetChild(aIndex, getter_AddRefs(item));
@ -125,10 +125,10 @@ NS_IMETHODIMP nsTransactionList::GetItem(PRInt32 aIndex, nsITransaction **aItem)
nsRefPtr<nsTransactionItem> item;
nsresult result = NS_ERROR_FAILURE;
nsresult result = NS_OK;
if (mTxnStack)
result = mTxnStack->GetItem(aIndex, getter_AddRefs(item));
item = mTxnStack->GetItem(aIndex);
else if (mTxnItem)
result = mTxnItem->GetChild(aIndex, getter_AddRefs(item));
@ -152,10 +152,10 @@ NS_IMETHODIMP nsTransactionList::GetNumChildrenForItem(PRInt32 aIndex, PRInt32 *
nsRefPtr<nsTransactionItem> item;
nsresult result = NS_ERROR_FAILURE;
nsresult result = NS_OK;
if (mTxnStack)
result = mTxnStack->GetItem(aIndex, getter_AddRefs(item));
item = mTxnStack->GetItem(aIndex);
else if (mTxnItem)
result = mTxnItem->GetChild(aIndex, getter_AddRefs(item));
@ -179,10 +179,10 @@ NS_IMETHODIMP nsTransactionList::GetChildListForItem(PRInt32 aIndex, nsITransact
nsRefPtr<nsTransactionItem> item;
nsresult result = NS_ERROR_FAILURE;
nsresult result = NS_OK;
if (mTxnStack)
result = mTxnStack->GetItem(aIndex, getter_AddRefs(item));
item = mTxnStack->GetItem(aIndex);
else if (mTxnItem)
result = mTxnItem->GetChild(aIndex, getter_AddRefs(item));

View File

@ -48,6 +48,9 @@
nsTransactionManager::nsTransactionManager(PRInt32 aMaxTransactionCount)
: mMaxTransactionCount(aMaxTransactionCount)
, mDoStack(nsTransactionStack::FOR_UNDO)
, mUndoStack(nsTransactionStack::FOR_UNDO)
, mRedoStack(nsTransactionStack::FOR_REDO)
{
}
@ -120,17 +123,12 @@ NS_IMETHODIMP
nsTransactionManager::UndoTransaction()
{
nsresult result = NS_OK;
nsRefPtr<nsTransactionItem> tx;
// It is illegal to call UndoTransaction() while the transaction manager is
// executing a transaction's DoTransaction() method! If this happens,
// the UndoTransaction() request is ignored, and we return NS_ERROR_FAILURE.
result = mDoStack.Peek(getter_AddRefs(tx));
if (NS_FAILED(result)) {
return result;
}
nsRefPtr<nsTransactionItem> tx = mDoStack.Peek();
if (tx) {
return NS_ERROR_FAILURE;
@ -138,11 +136,7 @@ nsTransactionManager::UndoTransaction()
// Peek at the top of the undo stack. Don't remove the transaction
// until it has successfully completed.
result = mUndoStack.Peek(getter_AddRefs(tx));
if (NS_FAILED(result)) {
return result;
}
tx = mUndoStack.Peek();
// Bail if there's nothing on the stack.
if (!tx) {
@ -172,10 +166,8 @@ nsTransactionManager::UndoTransaction()
result = tx->UndoTransaction(this);
if (NS_SUCCEEDED(result)) {
result = mUndoStack.Pop(getter_AddRefs(tx));
if (NS_SUCCEEDED(result))
result = mRedoStack.Push(tx);
tx = mUndoStack.Pop();
mRedoStack.Push(tx);
}
nsresult result2 = DidUndoNotify(t, result);
@ -190,17 +182,12 @@ NS_IMETHODIMP
nsTransactionManager::RedoTransaction()
{
nsresult result = NS_OK;
nsRefPtr<nsTransactionItem> tx;
// It is illegal to call RedoTransaction() while the transaction manager is
// executing a transaction's DoTransaction() method! If this happens,
// the RedoTransaction() request is ignored, and we return NS_ERROR_FAILURE.
result = mDoStack.Peek(getter_AddRefs(tx));
if (NS_FAILED(result)) {
return result;
}
nsRefPtr<nsTransactionItem> tx = mDoStack.Peek();
if (tx) {
return NS_ERROR_FAILURE;
@ -208,11 +195,7 @@ nsTransactionManager::RedoTransaction()
// Peek at the top of the redo stack. Don't remove the transaction
// until it has successfully completed.
result = mRedoStack.Peek(getter_AddRefs(tx));
if (NS_FAILED(result)) {
return result;
}
tx = mRedoStack.Peek();
// Bail if there's nothing on the stack.
if (!tx) {
@ -242,10 +225,8 @@ nsTransactionManager::RedoTransaction()
result = tx->RedoTransaction(this);
if (NS_SUCCEEDED(result)) {
result = mRedoStack.Pop(getter_AddRefs(tx));
if (NS_SUCCEEDED(result))
result = mUndoStack.Push(tx);
tx = mRedoStack.Pop();
mUndoStack.Push(tx);
}
nsresult result2 = DidRedoNotify(t, result);
@ -307,7 +288,6 @@ nsTransactionManager::BeginBatch()
NS_IMETHODIMP
nsTransactionManager::EndBatch()
{
nsRefPtr<nsTransactionItem> tx;
nsCOMPtr<nsITransaction> ti;
nsresult result;
@ -322,11 +302,7 @@ nsTransactionManager::EndBatch()
// future when we allow users to execute a transaction when beginning
// a batch!!!!
result = mDoStack.Peek(getter_AddRefs(tx));
if (NS_FAILED(result)) {
return result;
}
nsRefPtr<nsTransactionItem> tx = mDoStack.Peek();
if (tx)
tx->GetTransaction(getter_AddRefs(ti));
@ -360,13 +336,15 @@ nsTransactionManager::EndBatch()
NS_IMETHODIMP
nsTransactionManager::GetNumberOfUndoItems(PRInt32 *aNumItems)
{
return mUndoStack.GetSize(aNumItems);
*aNumItems = mUndoStack.GetSize();
return NS_OK;
}
NS_IMETHODIMP
nsTransactionManager::GetNumberOfRedoItems(PRInt32 *aNumItems)
{
return mRedoStack.GetSize(aNumItems);
*aNumItems = mRedoStack.GetSize();
return NS_OK;
}
NS_IMETHODIMP
@ -383,8 +361,6 @@ NS_IMETHODIMP
nsTransactionManager::SetMaxTransactionCount(PRInt32 aMaxCount)
{
PRInt32 numUndoItems = 0, numRedoItems = 0, total = 0;
nsRefPtr<nsTransactionItem> tx;
nsresult result;
// It is illegal to call SetMaxTransactionCount() while the transaction
// manager is executing a transaction's DoTransaction() method because
@ -392,11 +368,7 @@ nsTransactionManager::SetMaxTransactionCount(PRInt32 aMaxCount)
// SetMaxTransactionCount() request is ignored, and we return
// NS_ERROR_FAILURE.
result = mDoStack.Peek(getter_AddRefs(tx));
if (NS_FAILED(result)) {
return result;
}
nsRefPtr<nsTransactionItem> tx = mDoStack.Peek();
if (tx) {
return NS_ERROR_FAILURE;
@ -407,20 +379,12 @@ nsTransactionManager::SetMaxTransactionCount(PRInt32 aMaxCount)
if (aMaxCount < 0) {
mMaxTransactionCount = -1;
return result;
return NS_OK;
}
result = mUndoStack.GetSize(&numUndoItems);
numUndoItems = mUndoStack.GetSize();
if (NS_FAILED(result)) {
return result;
}
result = mRedoStack.GetSize(&numRedoItems);
if (NS_FAILED(result)) {
return result;
}
numRedoItems = mRedoStack.GetSize();
total = numUndoItems + numRedoItems;
@ -430,17 +394,17 @@ nsTransactionManager::SetMaxTransactionCount(PRInt32 aMaxCount)
if (aMaxCount > total ) {
mMaxTransactionCount = aMaxCount;
return result;
return NS_OK;
}
// Try getting rid of some transactions on the undo stack! Start at
// the bottom of the stack and pop towards the top.
while (numUndoItems > 0 && (numRedoItems + numUndoItems) > aMaxCount) {
result = mUndoStack.PopBottom(getter_AddRefs(tx));
tx = mUndoStack.PopBottom();
if (NS_FAILED(result) || !tx) {
return result;
if (!tx) {
return NS_ERROR_FAILURE;
}
--numUndoItems;
@ -450,10 +414,10 @@ nsTransactionManager::SetMaxTransactionCount(PRInt32 aMaxCount)
// the bottom of the stack and pop towards the top.
while (numRedoItems > 0 && (numRedoItems + numUndoItems) > aMaxCount) {
result = mRedoStack.PopBottom(getter_AddRefs(tx));
tx = mRedoStack.PopBottom();
if (NS_FAILED(result) || !tx) {
return result;
if (!tx) {
return NS_ERROR_FAILURE;
}
--numRedoItems;
@ -461,23 +425,22 @@ nsTransactionManager::SetMaxTransactionCount(PRInt32 aMaxCount)
mMaxTransactionCount = aMaxCount;
return result;
return NS_OK;
}
NS_IMETHODIMP
nsTransactionManager::PeekUndoStack(nsITransaction **aTransaction)
{
nsRefPtr<nsTransactionItem> tx;
nsresult result;
NS_ENSURE_TRUE(aTransaction, NS_ERROR_NULL_POINTER);
*aTransaction = 0;
result = mUndoStack.Peek(getter_AddRefs(tx));
nsRefPtr<nsTransactionItem> tx = mUndoStack.Peek();
if (NS_FAILED(result) || !tx) {
return result;
if (!tx) {
return NS_OK;
}
result = tx->GetTransaction(aTransaction);
@ -488,17 +451,16 @@ nsTransactionManager::PeekUndoStack(nsITransaction **aTransaction)
NS_IMETHODIMP
nsTransactionManager::PeekRedoStack(nsITransaction **aTransaction)
{
nsRefPtr<nsTransactionItem> tx;
nsresult result;
NS_ENSURE_TRUE(aTransaction, NS_ERROR_NULL_POINTER);
*aTransaction = 0;
result = mRedoStack.Peek(getter_AddRefs(tx));
nsRefPtr<nsTransactionItem> tx = mRedoStack.Peek();
if (NS_FAILED(result) || !tx) {
return result;
if (!tx) {
return NS_OK;
}
result = tx->GetTransaction(aTransaction);
@ -549,13 +511,15 @@ nsTransactionManager::RemoveListener(nsITransactionListener *aListener)
nsresult
nsTransactionManager::ClearUndoStack()
{
return mUndoStack.Clear();
mUndoStack.Clear();
return NS_OK;
}
nsresult
nsTransactionManager::ClearRedoStack()
{
return mRedoStack.Clear();
mRedoStack.Clear();
return NS_OK;
}
nsresult
@ -802,16 +766,12 @@ nsTransactionManager::BeginTransaction(nsITransaction *aTransaction)
return NS_ERROR_OUT_OF_MEMORY;
}
result = mDoStack.Push(tx);
if (NS_FAILED(result)) {
return result;
}
mDoStack.Push(tx);
result = tx->DoTransaction();
if (NS_FAILED(result)) {
mDoStack.Pop(getter_AddRefs(tx));
tx = mDoStack.Pop();
return result;
}
@ -822,13 +782,12 @@ nsresult
nsTransactionManager::EndTransaction()
{
nsCOMPtr<nsITransaction> tint;
nsRefPtr<nsTransactionItem> tx;
nsresult result = NS_OK;
result = mDoStack.Pop(getter_AddRefs(tx));
nsRefPtr<nsTransactionItem> tx = mDoStack.Pop();
if (NS_FAILED(result) || !tx)
return result;
if (!tx)
return NS_ERROR_FAILURE;
result = tx->GetTransaction(getter_AddRefs(tint));
@ -864,13 +823,11 @@ nsTransactionManager::EndTransaction()
return result;
}
nsRefPtr<nsTransactionItem> top;
// Check if there is a transaction on the do stack. If there is,
// the current transaction is a "sub" transaction, and should
// be added to the transaction at the top of the do stack.
result = mDoStack.Peek(getter_AddRefs(top));
nsRefPtr<nsTransactionItem> top = mDoStack.Peek();
if (top) {
result = top->AddChild(tx);
@ -890,8 +847,7 @@ nsTransactionManager::EndTransaction()
// Check if we can coalesce this transaction with the one at the top
// of the undo stack.
top = 0;
result = mUndoStack.Peek(getter_AddRefs(top));
top = mUndoStack.Peek();
if (tint && top) {
bool didMerge = false;
@ -929,27 +885,16 @@ nsTransactionManager::EndTransaction()
// Check to see if we've hit the max level of undo. If so,
// pop the bottom transaction off the undo stack and release it!
PRInt32 sz = 0;
result = mUndoStack.GetSize(&sz);
PRInt32 sz = mUndoStack.GetSize();
if (mMaxTransactionCount > 0 && sz >= mMaxTransactionCount) {
nsRefPtr<nsTransactionItem> overflow;
result = mUndoStack.PopBottom(getter_AddRefs(overflow));
// XXX: What do we do in the case where this fails?
nsRefPtr<nsTransactionItem> overflow = mUndoStack.PopBottom();
}
// Push the transaction on the undo stack:
result = mUndoStack.Push(tx);
mUndoStack.Push(tx);
if (NS_FAILED(result)) {
// XXX: What do we do in the case where a clear fails?
// Remove the transaction from the stack, and release it?
}
return result;
return NS_OK;
}

View File

@ -48,7 +48,6 @@ class nsITransaction;
class nsITransactionListener;
class nsTransactionItem;
class nsTransactionStack;
class nsTransactionRedoStack;
/** implementation of a transaction manager object.
*
@ -61,7 +60,7 @@ private:
PRInt32 mMaxTransactionCount;
nsTransactionStack mDoStack;
nsTransactionStack mUndoStack;
nsTransactionRedoStack mRedoStack;
nsTransactionStack mRedoStack;
nsCOMArray<nsITransactionListener> mListeners;
public:

View File

@ -41,115 +41,82 @@
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "mozilla/Util.h"
nsTransactionStack::nsTransactionStack()
nsTransactionStack::nsTransactionStack(nsTransactionStack::Type aType)
: mQue(0)
, mType(aType)
{
}
}
nsTransactionStack::~nsTransactionStack()
{
Clear();
}
nsresult
void
nsTransactionStack::Push(nsTransactionItem *aTransaction)
{
NS_ENSURE_TRUE(aTransaction, NS_ERROR_NULL_POINTER);
if (!aTransaction) {
return;
}
/* nsDeque's Push() method adds new items at the back
* of the deque.
*/
NS_ADDREF(aTransaction);
mQue.Push(aTransaction);
return NS_OK;
}
nsresult
nsTransactionStack::Pop(nsTransactionItem **aTransaction)
already_AddRefed<nsTransactionItem>
nsTransactionStack::Pop()
{
NS_ENSURE_TRUE(aTransaction, NS_ERROR_NULL_POINTER);
/* nsDeque is a FIFO, so the top of our stack is actually
* the back of the deque.
*/
*aTransaction = (nsTransactionItem *)mQue.Pop();
return NS_OK;
return static_cast<nsTransactionItem*> (mQue.Pop());
}
nsresult
nsTransactionStack::PopBottom(nsTransactionItem **aTransaction)
already_AddRefed<nsTransactionItem>
nsTransactionStack::PopBottom()
{
NS_ENSURE_TRUE(aTransaction, NS_ERROR_NULL_POINTER);
/* nsDeque is a FIFO, so the bottom of our stack is actually
* the front of the deque.
*/
*aTransaction = (nsTransactionItem *)mQue.PopFront();
return NS_OK;
return static_cast<nsTransactionItem*> (mQue.PopFront());
}
nsresult
nsTransactionStack::Peek(nsTransactionItem **aTransaction)
already_AddRefed<nsTransactionItem>
nsTransactionStack::Peek()
{
NS_ENSURE_TRUE(aTransaction, NS_ERROR_NULL_POINTER);
if (!mQue.GetSize()) {
*aTransaction = 0;
return NS_OK;
nsTransactionItem* transaction = nsnull;
if (mQue.GetSize()) {
NS_IF_ADDREF(transaction = static_cast<nsTransactionItem*>(mQue.Last()));
}
NS_IF_ADDREF(*aTransaction = static_cast<nsTransactionItem*>(mQue.Last()));
return NS_OK;
return transaction;
}
nsresult
nsTransactionStack::GetItem(PRInt32 aIndex, nsTransactionItem **aTransaction)
already_AddRefed<nsTransactionItem>
nsTransactionStack::GetItem(PRInt32 aIndex)
{
NS_ENSURE_TRUE(aTransaction, NS_ERROR_NULL_POINTER);
nsTransactionItem* transaction = nsnull;
if (aIndex >= 0 && aIndex < mQue.GetSize()) {
NS_IF_ADDREF(transaction =
static_cast<nsTransactionItem*>(mQue.ObjectAt(aIndex)));
}
if (aIndex < 0 || aIndex >= mQue.GetSize())
return NS_ERROR_FAILURE;
NS_IF_ADDREF(*aTransaction =
static_cast<nsTransactionItem*>(mQue.ObjectAt(aIndex)));
return NS_OK;
return transaction;
}
nsresult
nsTransactionStack::Clear(void)
void
nsTransactionStack::Clear()
{
nsRefPtr<nsTransactionItem> tx;
nsresult result = NS_OK;
/* Pop all transactions off the stack and release them. */
result = Pop(getter_AddRefs(tx));
NS_ENSURE_SUCCESS(result, result);
while (tx) {
result = Pop(getter_AddRefs(tx));
NS_ENSURE_SUCCESS(result, result);
}
return NS_OK;
}
nsresult
nsTransactionStack::GetSize(PRInt32 *aStackSize)
{
NS_ENSURE_TRUE(aStackSize, NS_ERROR_NULL_POINTER);
*aStackSize = mQue.GetSize();
return NS_OK;
do {
tx = mType == FOR_UNDO ? Pop() : PopBottom();
} while (tx);
}
void
@ -164,32 +131,3 @@ nsTransactionStack::DoTraverse(nsCycleCollectionTraversalCallback &cb)
}
}
}
nsTransactionRedoStack::~nsTransactionRedoStack()
{
Clear();
}
nsresult
nsTransactionRedoStack::Clear(void)
{
nsRefPtr<nsTransactionItem> tx;
nsresult result = NS_OK;
/* When clearing a Redo stack, we have to clear from the
* bottom of the stack towards the top!
*/
result = PopBottom(getter_AddRefs(tx));
NS_ENSURE_SUCCESS(result, result);
while (tx) {
result = PopBottom(getter_AddRefs(tx));
NS_ENSURE_SUCCESS(result, result);
}
return NS_OK;
}

View File

@ -39,36 +39,32 @@
#define nsTransactionStack_h__
#include "nsDeque.h"
#include "nsCOMPtr.h"
class nsTransactionItem;
class nsTransactionStack
{
nsDeque mQue;
public:
enum Type { FOR_UNDO, FOR_REDO };
nsTransactionStack();
virtual ~nsTransactionStack();
explicit nsTransactionStack(Type aType);
~nsTransactionStack();
virtual nsresult Push(nsTransactionItem *aTransactionItem);
virtual nsresult Pop(nsTransactionItem **aTransactionItem);
virtual nsresult PopBottom(nsTransactionItem **aTransactionItem);
virtual nsresult Peek(nsTransactionItem **aTransactionItem);
virtual nsresult GetItem(PRInt32 aIndex, nsTransactionItem **aTransactionItem);
virtual nsresult Clear(void);
virtual nsresult GetSize(PRInt32 *aStackSize);
void Push(nsTransactionItem *aTransactionItem);
already_AddRefed<nsTransactionItem> Pop();
already_AddRefed<nsTransactionItem> PopBottom();
already_AddRefed<nsTransactionItem> Peek();
already_AddRefed<nsTransactionItem> GetItem(PRInt32 aIndex);
void Clear();
PRInt32 GetSize() { return mQue.GetSize(); }
void DoUnlink() { Clear(); }
void DoTraverse(nsCycleCollectionTraversalCallback &cb);
};
class nsTransactionRedoStack: public nsTransactionStack
{
public:
virtual ~nsTransactionRedoStack();
virtual nsresult Clear(void);
private:
nsDeque mQue;
const Type mType;
};
#endif // nsTransactionStack_h__

View File

@ -35,6 +35,8 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef MOZILLA_GFX_USERDATA_H_
#define MOZILLA_GFX_USERDATA_H_
#include <stdlib.h>
#include "mozilla/mozalloc.h"
@ -56,6 +58,9 @@ public:
/* Attaches untyped userData associated with key. destroy is called on destruction */
void Add(UserDataKey *key, void *userData, destroyFunc destroy)
{
// XXX we should really warn if user data with key has already been added,
// since in that case Get() will return the old user data!
// We could keep entries in a std::vector instead of managing it by hand
// but that would propagate an stl dependency out which we'd rather not
// do (see bug 666609). Plus, the entries array is expect to stay small
@ -69,7 +74,22 @@ public:
count++;
}
//XXX: we probably want to add a way to remove Keys
/* Remove and return user data associated with key, without destroying it */
void* Remove(UserDataKey *key)
{
for (int i=0; i<count; i++) {
if (key == entries[i].key) {
void *userData = entries[i].userData;
// decrement before looping so entries[i+1] doesn't read past the end:
--count;
for (;i<count; i++) {
entries[i] = entries[i+1];
}
return userData;
}
}
return NULL;
}
/* Retrives the userData for the associated key */
void *Get(UserDataKey *key)
@ -105,4 +125,4 @@ private:
}
}
#endif /* MOZILLA_GFX_USERDATA_H_ */

View File

@ -84,6 +84,7 @@ CPPSRCS = \
ValidateLimitations.cpp \
ForLoopUnroll.cpp \
MapLongVariableNames.cpp \
spooky.cpp \
BuiltInFunctionEmulator.cpp \
$(NULL)

View File

@ -7,11 +7,11 @@ Current revision: r963
In this order:
angle-renaming-debug.patch - rename debug.h to compilerdebug.h to avoid conflict in our makefiles
angle-intrinsic-msvc2005.patch - work around a MSVC 2005 compile error
angle-limit-identifiers-to-250-chars.patch - see bug 675625
angle-use-xmalloc.patch - see bug 680840. Can drop this patch whenever the new preprocessor lands.
angle-castrate-bug-241.patch - see bug 699033 / angle bug 241
angle-enforce-readpixels-spec.patch - see bug 724476.
angle-impl-read-bgra.patch - see bug 724476.
gfx/angle/angle-long-identifier-hash-spooky.patch - see bug 676071
In addition to these patches, the Makefile.in files are ours, they're not present in upsteam ANGLE.

View File

@ -1,21 +0,0 @@
# HG changeset patch
# Parent 761ca19e4ce1afe03e58beaea20149ba1ef243c4
diff --git a/gfx/angle/src/compiler/preprocessor/length_limits.h b/gfx/angle/src/compiler/preprocessor/length_limits.h
--- a/gfx/angle/src/compiler/preprocessor/length_limits.h
+++ b/gfx/angle/src/compiler/preprocessor/length_limits.h
@@ -10,12 +10,14 @@
#if !defined(__LENGTH_LIMITS_H)
#define __LENGTH_LIMITS_H 1
// These constants are factored out from the rest of the headers to
// make it easier to reference them from the compiler sources.
// These lengths do not include the NULL terminator.
-#define MAX_SYMBOL_NAME_LEN 256
+// see bug 675625: NVIDIA driver crash with lengths >= 253
+// this is only an interim fix, the real fix is name mapping, see ANGLE bug 144 / r619
+#define MAX_SYMBOL_NAME_LEN 250
#define MAX_STRING_LEN 511
#endif // !(defined(__LENGTH_LIMITS_H)

View File

@ -0,0 +1,756 @@
# HG changeset patch
# Parent 69255fe4cb94f1681bc9200db37c0ad3de171abc
diff --git a/gfx/angle/Makefile.in b/gfx/angle/Makefile.in
--- a/gfx/angle/Makefile.in
+++ b/gfx/angle/Makefile.in
@@ -79,16 +79,17 @@ CPPSRCS = \
SymbolTable.cpp \
VariableInfo.cpp \
compilerdebug.cpp \
ossource_nspr.cpp \
util.cpp \
ValidateLimitations.cpp \
ForLoopUnroll.cpp \
MapLongVariableNames.cpp \
+ spooky.cpp \
BuiltInFunctionEmulator.cpp \
$(NULL)
# flex/yacc generated files
CPPSRCS += \
glslang_lex.cpp \
glslang_tab.cpp \
$(NULL)
diff --git a/gfx/angle/src/compiler/MapLongVariableNames.cpp b/gfx/angle/src/compiler/MapLongVariableNames.cpp
--- a/gfx/angle/src/compiler/MapLongVariableNames.cpp
+++ b/gfx/angle/src/compiler/MapLongVariableNames.cpp
@@ -1,27 +1,30 @@
//
// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "compiler/MapLongVariableNames.h"
+#include "spooky.h"
namespace {
TString mapLongName(int id, const TString& name, bool isGlobal)
{
ASSERT(name.size() > MAX_SHORTENED_IDENTIFIER_SIZE);
TStringStream stream;
- stream << "webgl_";
- if (isGlobal)
- stream << "g";
- stream << id << "_";
- stream << name.substr(0, MAX_SHORTENED_IDENTIFIER_SIZE - stream.str().size());
+ uint64 hash = SpookyHash::Hash64(name.data(), name.length(), 0);
+ stream << "webgl_"
+ << name.substr(0, 9)
+ << "_"
+ << std::hex
+ << hash;
+ ASSERT(stream.str().length() == MAX_SHORTENED_IDENTIFIER_SIZE);
return stream.str();
}
LongNameMap* gLongNameMapInstance = NULL;
} // anonymous namespace
LongNameMap::LongNameMap()
diff --git a/gfx/angle/src/compiler/spooky.cpp b/gfx/angle/src/compiler/spooky.cpp
new file mode 100644
--- /dev/null
+++ b/gfx/angle/src/compiler/spooky.cpp
@@ -0,0 +1,348 @@
+// Spooky Hash
+// A 128-bit noncryptographic hash, for checksums and table lookup
+// By Bob Jenkins. Public domain.
+// Oct 31 2010: published framework, disclaimer ShortHash isn't right
+// Nov 7 2010: disabled ShortHash
+// Oct 31 2011: replace End, ShortMix, ShortEnd, enable ShortHash again
+
+#include <memory.h>
+#include <string.h>
+#include "spooky.h"
+
+#define ALLOW_UNALIGNED_READS 1
+
+//
+// short hash ... it could be used on any message,
+// but it's used by Spooky just for short messages.
+//
+void SpookyHash::Short(
+ const void *message,
+ size_t length,
+ uint64 *hash1,
+ uint64 *hash2)
+{
+ uint64 buf[sc_numVars];
+ union
+ {
+ const uint8 *p8;
+ uint32 *p32;
+ uint64 *p64;
+ size_t i;
+ } u;
+
+ u.p8 = (const uint8 *)message;
+
+ if (!ALLOW_UNALIGNED_READS && (u.i & 0x7))
+ {
+ memcpy(buf, message, length);
+ u.p64 = buf;
+ }
+
+ size_t remainder = length%32;
+ uint64 a=*hash1;
+ uint64 b=*hash2;
+ uint64 c=sc_const;
+ uint64 d=sc_const;
+
+ if (length > 15)
+ {
+ const uint64 *end = u.p64 + (length/32)*4;
+
+ // handle all complete sets of 32 bytes
+ for (; u.p64 < end; u.p64 += 4)
+ {
+ c += u.p64[0];
+ d += u.p64[1];
+ ShortMix(a,b,c,d);
+ a += u.p64[2];
+ b += u.p64[3];
+ }
+
+ //Handle the case of 16+ remaining bytes.
+ if (remainder >= 16)
+ {
+ c += u.p64[0];
+ d += u.p64[1];
+ ShortMix(a,b,c,d);
+ u.p64 += 2;
+ remainder -= 16;
+ }
+ }
+
+ // Handle the last 0..15 bytes, and its length
+ d = ((uint64)length) << 56;
+ switch (remainder)
+ {
+ case 15:
+ d += ((uint64)u.p8[14]) << 48;
+ case 14:
+ d += ((uint64)u.p8[13]) << 40;
+ case 13:
+ d += ((uint64)u.p8[12]) << 32;
+ case 12:
+ d += u.p32[2];
+ c += u.p64[0];
+ break;
+ case 11:
+ d += ((uint64)u.p8[10]) << 16;
+ case 10:
+ d += ((uint64)u.p8[9]) << 8;
+ case 9:
+ d += (uint64)u.p8[8];
+ case 8:
+ c += u.p64[0];
+ break;
+ case 7:
+ c += ((uint64)u.p8[6]) << 48;
+ case 6:
+ c += ((uint64)u.p8[5]) << 40;
+ case 5:
+ c += ((uint64)u.p8[4]) << 32;
+ case 4:
+ c += u.p32[0];
+ break;
+ case 3:
+ c += ((uint64)u.p8[2]) << 16;
+ case 2:
+ c += ((uint64)u.p8[1]) << 8;
+ case 1:
+ c += (uint64)u.p8[0];
+ break;
+ case 0:
+ c += sc_const;
+ d += sc_const;
+ }
+ ShortEnd(a,b,c,d);
+ *hash1 = a;
+ *hash2 = b;
+}
+
+
+
+
+// do the whole hash in one call
+void SpookyHash::Hash128(
+ const void *message,
+ size_t length,
+ uint64 *hash1,
+ uint64 *hash2)
+{
+ if (length < sc_bufSize)
+ {
+ Short(message, length, hash1, hash2);
+ return;
+ }
+
+ uint64 h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11;
+ uint64 buf[sc_numVars];
+ uint64 *end;
+ union
+ {
+ const uint8 *p8;
+ uint64 *p64;
+ size_t i;
+ } u;
+ size_t remainder;
+
+ h0=h3=h6=h9 = *hash1;
+ h1=h4=h7=h10 = *hash2;
+ h2=h5=h8=h11 = sc_const;
+
+ u.p8 = (const uint8 *)message;
+ end = u.p64 + (length/sc_blockSize)*sc_numVars;
+
+ // handle all whole sc_blockSize blocks of bytes
+ if (ALLOW_UNALIGNED_READS || ((u.i & 0x7) == 0))
+ {
+ while (u.p64 < end)
+ {
+ Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
+ u.p64 += sc_numVars;
+ }
+ }
+ else
+ {
+ while (u.p64 < end)
+ {
+ memcpy(buf, u.p64, sc_blockSize);
+ Mix(buf, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
+ u.p64 += sc_numVars;
+ }
+ }
+
+ // handle the last partial block of sc_blockSize bytes
+ remainder = (length - ((const uint8 *)end-(const uint8 *)message));
+ memcpy(buf, end, remainder);
+ memset(((uint8 *)buf)+remainder, 0, sc_blockSize-remainder);
+ ((uint8 *)buf)[sc_blockSize-1] = remainder;
+ Mix(buf, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
+
+ // do some final mixing
+ End(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
+ *hash1 = h0;
+ *hash2 = h1;
+}
+
+
+
+// init spooky state
+void SpookyHash::Init(uint64 seed1, uint64 seed2)
+{
+ m_length = 0;
+ m_remainder = 0;
+ m_state[0] = seed1;
+ m_state[1] = seed2;
+}
+
+
+// add a message fragment to the state
+void SpookyHash::Update(const void *message, size_t length)
+{
+ uint64 h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11;
+ size_t newLength = length + m_remainder;
+ uint8 remainder;
+ union
+ {
+ const uint8 *p8;
+ uint64 *p64;
+ size_t i;
+ } u;
+ const uint64 *end;
+
+ // Is this message fragment too short? If it is, stuff it away.
+ if (newLength < sc_bufSize)
+ {
+ memcpy(&((uint8 *)m_data)[m_remainder], message, length);
+ m_length = length + m_length;
+ m_remainder = (uint8)newLength;
+ return;
+ }
+
+ // init the variables
+ if (m_length < sc_bufSize)
+ {
+ h0=h3=h6=h9 = m_state[0];
+ h1=h4=h7=h10 = m_state[1];
+ h2=h5=h8=h11 = sc_const;
+ }
+ else
+ {
+ h0 = m_state[0];
+ h1 = m_state[1];
+ h2 = m_state[2];
+ h3 = m_state[3];
+ h4 = m_state[4];
+ h5 = m_state[5];
+ h6 = m_state[6];
+ h7 = m_state[7];
+ h8 = m_state[8];
+ h9 = m_state[9];
+ h10 = m_state[10];
+ h11 = m_state[11];
+ }
+ m_length = length + m_length;
+
+ // if we've got anything stuffed away, use it now
+ if (m_remainder)
+ {
+ uint8 prefix = sc_bufSize-m_remainder;
+ memcpy(&(((uint8 *)m_data)[m_remainder]), message, prefix);
+ u.p64 = m_data;
+ Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
+ Mix(&u.p64[sc_numVars], h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
+ u.p8 = ((const uint8 *)message) + prefix;
+ length -= prefix;
+ }
+ else
+ {
+ u.p8 = (const uint8 *)message;
+ }
+
+ // handle all whole blocks of sc_blockSize bytes
+ end = u.p64 + (length/sc_blockSize)*sc_numVars;
+ remainder = (uint8)(length-((const uint8 *)end-u.p8));
+ if (ALLOW_UNALIGNED_READS || (u.i & 0x7) == 0)
+ {
+ while (u.p64 < end)
+ {
+ Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
+ u.p64 += sc_numVars;
+ }
+ }
+ else
+ {
+ while (u.p64 < end)
+ {
+ memcpy(m_data, u.p8, sc_blockSize);
+ Mix(m_data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
+ u.p64 += sc_numVars;
+ }
+ }
+
+ // stuff away the last few bytes
+ m_remainder = remainder;
+ memcpy(m_data, end, remainder);
+
+ // stuff away the variables
+ m_state[0] = h0;
+ m_state[1] = h1;
+ m_state[2] = h2;
+ m_state[3] = h3;
+ m_state[4] = h4;
+ m_state[5] = h5;
+ m_state[6] = h6;
+ m_state[7] = h7;
+ m_state[8] = h8;
+ m_state[9] = h9;
+ m_state[10] = h10;
+ m_state[11] = h11;
+}
+
+
+// report the hash for the concatenation of all message fragments so far
+void SpookyHash::Final(uint64 *hash1, uint64 *hash2)
+{
+ // init the variables
+ if (m_length < sc_bufSize)
+ {
+ Short( m_data, m_length, hash1, hash2);
+ return;
+ }
+
+ const uint64 *data = (const uint64 *)m_data;
+ uint8 remainder = m_remainder;
+
+ uint64 h0 = m_state[0];
+ uint64 h1 = m_state[1];
+ uint64 h2 = m_state[2];
+ uint64 h3 = m_state[3];
+ uint64 h4 = m_state[4];
+ uint64 h5 = m_state[5];
+ uint64 h6 = m_state[6];
+ uint64 h7 = m_state[7];
+ uint64 h8 = m_state[8];
+ uint64 h9 = m_state[9];
+ uint64 h10 = m_state[10];
+ uint64 h11 = m_state[11];
+
+ if (remainder >= sc_blockSize)
+ {
+ // m_data can contain two blocks; handle any whole first block
+ Mix(data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
+ data += sc_numVars;
+ remainder -= sc_blockSize;
+ }
+
+ // mix in the last partial block, and the length mod sc_blockSize
+ memset(&((uint8 *)data)[remainder], 0, (sc_blockSize-remainder));
+
+ ((uint8 *)data)[sc_blockSize-1] = remainder;
+ Mix(data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
+
+ // do some final mixing
+ End(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
+
+ *hash1 = h0;
+ *hash2 = h1;
+}
+
diff --git a/gfx/angle/src/compiler/spooky.h b/gfx/angle/src/compiler/spooky.h
new file mode 100644
--- /dev/null
+++ b/gfx/angle/src/compiler/spooky.h
@@ -0,0 +1,293 @@
+//
+// SpookyHash: a 128-bit noncryptographic hash function
+// By Bob Jenkins, public domain
+// Oct 31 2010: alpha, framework + SpookyHash::Mix appears right
+// Oct 31 2011: alpha again, Mix only good to 2^^69 but rest appears right
+// Dec 31 2011: beta, improved Mix, tested it for 2-bit deltas
+// Feb 2 2012: production, same bits as beta
+// Feb 5 2012: adjusted definitions of uint* to be more portable
+//
+// Up to 4 bytes/cycle for long messages. Reasonably fast for short messages.
+// All 1 or 2 bit deltas achieve avalanche within 1% bias per output bit.
+//
+// This was developed for and tested on 64-bit x86-compatible processors.
+// It assumes the processor is little-endian. There is a macro
+// controlling whether unaligned reads are allowed (by default they are).
+// This should be an equally good hash on big-endian machines, but it will
+// compute different results on them than on little-endian machines.
+//
+// Google's CityHash has similar specs to SpookyHash, and CityHash is faster
+// on some platforms. MD4 and MD5 also have similar specs, but they are orders
+// of magnitude slower. CRCs are two or more times slower, but unlike
+// SpookyHash, they have nice math for combining the CRCs of pieces to form
+// the CRCs of wholes. There are also cryptographic hashes, but those are even
+// slower than MD5.
+//
+
+#include <stddef.h>
+
+#ifdef _MSC_VER
+# define INLINE __forceinline
+ typedef unsigned __int64 uint64;
+ typedef unsigned __int32 uint32;
+ typedef unsigned __int16 uint16;
+ typedef unsigned __int8 uint8;
+#else
+# include <stdint.h>
+# define INLINE inline
+ typedef uint64_t uint64;
+ typedef uint32_t uint32;
+ typedef uint16_t uint16;
+ typedef uint8_t uint8;
+#endif
+
+
+class SpookyHash
+{
+public:
+ //
+ // SpookyHash: hash a single message in one call, produce 128-bit output
+ //
+ static void Hash128(
+ const void *message, // message to hash
+ size_t length, // length of message in bytes
+ uint64 *hash1, // in/out: in seed 1, out hash value 1
+ uint64 *hash2); // in/out: in seed 2, out hash value 2
+
+ //
+ // Hash64: hash a single message in one call, return 64-bit output
+ //
+ static uint64 Hash64(
+ const void *message, // message to hash
+ size_t length, // length of message in bytes
+ uint64 seed) // seed
+ {
+ uint64 hash1 = seed;
+ Hash128(message, length, &hash1, &seed);
+ return hash1;
+ }
+
+ //
+ // Hash32: hash a single message in one call, produce 32-bit output
+ //
+ static uint32 Hash32(
+ const void *message, // message to hash
+ size_t length, // length of message in bytes
+ uint32 seed) // seed
+ {
+ uint64 hash1 = seed, hash2 = seed;
+ Hash128(message, length, &hash1, &hash2);
+ return (uint32)hash1;
+ }
+
+ //
+ // Init: initialize the context of a SpookyHash
+ //
+ void Init(
+ uint64 seed1, // any 64-bit value will do, including 0
+ uint64 seed2); // different seeds produce independent hashes
+
+ //
+ // Update: add a piece of a message to a SpookyHash state
+ //
+ void Update(
+ const void *message, // message fragment
+ size_t length); // length of message fragment in bytes
+
+
+ //
+ // Final: compute the hash for the current SpookyHash state
+ //
+ // This does not modify the state; you can keep updating it afterward
+ //
+ // The result is the same as if SpookyHash() had been called with
+ // all the pieces concatenated into one message.
+ //
+ void Final(
+ uint64 *hash1, // out only: first 64 bits of hash value.
+ uint64 *hash2); // out only: second 64 bits of hash value.
+
+ //
+ // left rotate a 64-bit value by k bytes
+ //
+ static INLINE uint64 Rot64(uint64 x, int k)
+ {
+ return (x << k) | (x >> (64 - k));
+ }
+
+ //
+ // This is used if the input is 96 bytes long or longer.
+ //
+ // The internal state is fully overwritten every 96 bytes.
+ // Every input bit appears to cause at least 128 bits of entropy
+ // before 96 other bytes are combined, when run forward or backward
+ // For every input bit,
+ // Two inputs differing in just that input bit
+ // Where "differ" means xor or subtraction
+ // And the base value is random
+ // When run forward or backwards one Mix
+ // I tried 3 pairs of each; they all differed by at least 212 bits.
+ //
+ static INLINE void Mix(
+ const uint64 *data,
+ uint64 &s0, uint64 &s1, uint64 &s2, uint64 &s3,
+ uint64 &s4, uint64 &s5, uint64 &s6, uint64 &s7,
+ uint64 &s8, uint64 &s9, uint64 &s10,uint64 &s11)
+ {
+ s0 += data[0]; s2 ^= s10; s11 ^= s0; s0 = Rot64(s0,11); s11 += s1;
+ s1 += data[1]; s3 ^= s11; s0 ^= s1; s1 = Rot64(s1,32); s0 += s2;
+ s2 += data[2]; s4 ^= s0; s1 ^= s2; s2 = Rot64(s2,43); s1 += s3;
+ s3 += data[3]; s5 ^= s1; s2 ^= s3; s3 = Rot64(s3,31); s2 += s4;
+ s4 += data[4]; s6 ^= s2; s3 ^= s4; s4 = Rot64(s4,17); s3 += s5;
+ s5 += data[5]; s7 ^= s3; s4 ^= s5; s5 = Rot64(s5,28); s4 += s6;
+ s6 += data[6]; s8 ^= s4; s5 ^= s6; s6 = Rot64(s6,39); s5 += s7;
+ s7 += data[7]; s9 ^= s5; s6 ^= s7; s7 = Rot64(s7,57); s6 += s8;
+ s8 += data[8]; s10 ^= s6; s7 ^= s8; s8 = Rot64(s8,55); s7 += s9;
+ s9 += data[9]; s11 ^= s7; s8 ^= s9; s9 = Rot64(s9,54); s8 += s10;
+ s10 += data[10]; s0 ^= s8; s9 ^= s10; s10 = Rot64(s10,22); s9 += s11;
+ s11 += data[11]; s1 ^= s9; s10 ^= s11; s11 = Rot64(s11,46); s10 += s0;
+ }
+
+ //
+ // Mix all 12 inputs together so that h0, h1 are a hash of them all.
+ //
+ // For two inputs differing in just the input bits
+ // Where "differ" means xor or subtraction
+ // And the base value is random, or a counting value starting at that bit
+ // The final result will have each bit of h0, h1 flip
+ // For every input bit,
+ // with probability 50 +- .3%
+ // For every pair of input bits,
+ // with probability 50 +- 3%
+ //
+ // This does not rely on the last Mix() call having already mixed some.
+ // Two iterations was almost good enough for a 64-bit result, but a
+ // 128-bit result is reported, so End() does three iterations.
+ //
+ static INLINE void EndPartial(
+ uint64 &h0, uint64 &h1, uint64 &h2, uint64 &h3,
+ uint64 &h4, uint64 &h5, uint64 &h6, uint64 &h7,
+ uint64 &h8, uint64 &h9, uint64 &h10,uint64 &h11)
+ {
+ h11+= h1; h2 ^= h11; h1 = Rot64(h1,44);
+ h0 += h2; h3 ^= h0; h2 = Rot64(h2,15);
+ h1 += h3; h4 ^= h1; h3 = Rot64(h3,34);
+ h2 += h4; h5 ^= h2; h4 = Rot64(h4,21);
+ h3 += h5; h6 ^= h3; h5 = Rot64(h5,38);
+ h4 += h6; h7 ^= h4; h6 = Rot64(h6,33);
+ h5 += h7; h8 ^= h5; h7 = Rot64(h7,10);
+ h6 += h8; h9 ^= h6; h8 = Rot64(h8,13);
+ h7 += h9; h10^= h7; h9 = Rot64(h9,38);
+ h8 += h10; h11^= h8; h10= Rot64(h10,53);
+ h9 += h11; h0 ^= h9; h11= Rot64(h11,42);
+ h10+= h0; h1 ^= h10; h0 = Rot64(h0,54);
+ }
+
+ static INLINE void End(
+ uint64 &h0, uint64 &h1, uint64 &h2, uint64 &h3,
+ uint64 &h4, uint64 &h5, uint64 &h6, uint64 &h7,
+ uint64 &h8, uint64 &h9, uint64 &h10,uint64 &h11)
+ {
+ EndPartial(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
+ EndPartial(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
+ EndPartial(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
+ }
+
+ //
+ // The goal is for each bit of the input to expand into 128 bits of
+ // apparent entropy before it is fully overwritten.
+ // n trials both set and cleared at least m bits of h0 h1 h2 h3
+ // n: 2 m: 29
+ // n: 3 m: 46
+ // n: 4 m: 57
+ // n: 5 m: 107
+ // n: 6 m: 146
+ // n: 7 m: 152
+ // when run forwards or backwards
+ // for all 1-bit and 2-bit diffs
+ // with diffs defined by either xor or subtraction
+ // with a base of all zeros plus a counter, or plus another bit, or random
+ //
+ static INLINE void ShortMix(uint64 &h0, uint64 &h1, uint64 &h2, uint64 &h3)
+ {
+ h2 = Rot64(h2,50); h2 += h3; h0 ^= h2;
+ h3 = Rot64(h3,52); h3 += h0; h1 ^= h3;
+ h0 = Rot64(h0,30); h0 += h1; h2 ^= h0;
+ h1 = Rot64(h1,41); h1 += h2; h3 ^= h1;
+ h2 = Rot64(h2,54); h2 += h3; h0 ^= h2;
+ h3 = Rot64(h3,48); h3 += h0; h1 ^= h3;
+ h0 = Rot64(h0,38); h0 += h1; h2 ^= h0;
+ h1 = Rot64(h1,37); h1 += h2; h3 ^= h1;
+ h2 = Rot64(h2,62); h2 += h3; h0 ^= h2;
+ h3 = Rot64(h3,34); h3 += h0; h1 ^= h3;
+ h0 = Rot64(h0,5); h0 += h1; h2 ^= h0;
+ h1 = Rot64(h1,36); h1 += h2; h3 ^= h1;
+ }
+
+ //
+ // Mix all 4 inputs together so that h0, h1 are a hash of them all.
+ //
+ // For two inputs differing in just the input bits
+ // Where "differ" means xor or subtraction
+ // And the base value is random, or a counting value starting at that bit
+ // The final result will have each bit of h0, h1 flip
+ // For every input bit,
+ // with probability 50 +- .3% (it is probably better than that)
+ // For every pair of input bits,
+ // with probability 50 +- .75% (the worst case is approximately that)
+ //
+ static INLINE void ShortEnd(uint64 &h0, uint64 &h1, uint64 &h2, uint64 &h3)
+ {
+ h3 ^= h2; h2 = Rot64(h2,15); h3 += h2;
+ h0 ^= h3; h3 = Rot64(h3,52); h0 += h3;
+ h1 ^= h0; h0 = Rot64(h0,26); h1 += h0;
+ h2 ^= h1; h1 = Rot64(h1,51); h2 += h1;
+ h3 ^= h2; h2 = Rot64(h2,28); h3 += h2;
+ h0 ^= h3; h3 = Rot64(h3,9); h0 += h3;
+ h1 ^= h0; h0 = Rot64(h0,47); h1 += h0;
+ h2 ^= h1; h1 = Rot64(h1,54); h2 += h1;
+ h3 ^= h2; h2 = Rot64(h2,32); h3 += h2;
+ h0 ^= h3; h3 = Rot64(h3,25); h0 += h3;
+ h1 ^= h0; h0 = Rot64(h0,63); h1 += h0;
+ }
+
+private:
+
+ //
+ // Short is used for messages under 192 bytes in length
+ // Short has a low startup cost, the normal mode is good for long
+ // keys, the cost crossover is at about 192 bytes. The two modes were
+ // held to the same quality bar.
+ //
+ static void Short(
+ const void *message,
+ size_t length,
+ uint64 *hash1,
+ uint64 *hash2);
+
+ // number of uint64's in internal state
+ static const size_t sc_numVars = 12;
+
+ // size of the internal state
+ static const size_t sc_blockSize = sc_numVars*8;
+
+ // size of buffer of unhashed data, in bytes
+ static const size_t sc_bufSize = 2*sc_blockSize;
+
+ //
+ // sc_const: a constant which:
+ // * is not zero
+ // * is odd
+ // * is a not-very-regular mix of 1's and 0's
+ // * does not need any other special mathematical properties
+ //
+ static const uint64 sc_const = 0xdeadbeefdeadbeefLL;
+
+ uint64 m_data[2*sc_numVars]; // unhashed data, for partial messages
+ uint64 m_state[sc_numVars]; // internal state of the hash
+ size_t m_length; // total length of the input so far
+ uint8 m_remainder; // length of unhashed data stashed in m_data
+};
+
+
+
diff --git a/gfx/angle/src/libEGL/Makefile.in b/gfx/angle/src/libEGL/Makefile.in
--- a/gfx/angle/src/libEGL/Makefile.in
+++ b/gfx/angle/src/libEGL/Makefile.in
@@ -91,16 +91,17 @@ CPPSRCS = \
SymbolTable.cpp \
VariableInfo.cpp \
compilerdebug.cpp \
ossource_win.cpp \
util.cpp \
ValidateLimitations.cpp \
ForLoopUnroll.cpp \
MapLongVariableNames.cpp \
+ spooky.cpp \
BuiltInFunctionEmulator.cpp \
$(NULL)
# flex/yacc generated files
CPPSRCS += \
glslang_lex.cpp \
glslang_tab.cpp \
$(NULL)
diff --git a/gfx/angle/src/libGLESv2/Makefile.in b/gfx/angle/src/libGLESv2/Makefile.in
--- a/gfx/angle/src/libGLESv2/Makefile.in
+++ b/gfx/angle/src/libGLESv2/Makefile.in
@@ -91,16 +91,17 @@ CPPSRCS = \
SymbolTable.cpp \
VariableInfo.cpp \
compilerdebug.cpp \
ossource_win.cpp \
util.cpp \
ValidateLimitations.cpp \
ForLoopUnroll.cpp \
MapLongVariableNames.cpp \
+ spooky.cpp \
BuiltInFunctionEmulator.cpp \
$(NULL)
# flex/yacc generated files
CPPSRCS += \
glslang_lex.cpp \
glslang_tab.cpp \
$(NULL)

View File

@ -5,6 +5,7 @@
//
#include "compiler/MapLongVariableNames.h"
#include "spooky.h"
namespace {
@ -12,11 +13,13 @@ TString mapLongName(int id, const TString& name, bool isGlobal)
{
ASSERT(name.size() > MAX_SHORTENED_IDENTIFIER_SIZE);
TStringStream stream;
stream << "webgl_";
if (isGlobal)
stream << "g";
stream << id << "_";
stream << name.substr(0, MAX_SHORTENED_IDENTIFIER_SIZE - stream.str().size());
uint64 hash = SpookyHash::Hash64(name.data(), name.length(), 0);
stream << "webgl_"
<< name.substr(0, 9)
<< "_"
<< std::hex
<< hash;
ASSERT(stream.str().length() == MAX_SHORTENED_IDENTIFIER_SIZE);
return stream.str();
}

View File

@ -15,9 +15,7 @@
// make it easier to reference them from the compiler sources.
// These lengths do not include the NULL terminator.
// see bug 675625: NVIDIA driver crash with lengths >= 253
// this is only an interim fix, the real fix is name mapping, see ANGLE bug 144 / r619
#define MAX_SYMBOL_NAME_LEN 250
#define MAX_SYMBOL_NAME_LEN 256
#define MAX_STRING_LEN 511
#endif // !(defined(__LENGTH_LIMITS_H)

View File

@ -0,0 +1,348 @@
// Spooky Hash
// A 128-bit noncryptographic hash, for checksums and table lookup
// By Bob Jenkins. Public domain.
// Oct 31 2010: published framework, disclaimer ShortHash isn't right
// Nov 7 2010: disabled ShortHash
// Oct 31 2011: replace End, ShortMix, ShortEnd, enable ShortHash again
#include <memory.h>
#include <string.h>
#include "spooky.h"
#define ALLOW_UNALIGNED_READS 1
//
// short hash ... it could be used on any message,
// but it's used by Spooky just for short messages.
//
void SpookyHash::Short(
const void *message,
size_t length,
uint64 *hash1,
uint64 *hash2)
{
uint64 buf[sc_numVars];
union
{
const uint8 *p8;
uint32 *p32;
uint64 *p64;
size_t i;
} u;
u.p8 = (const uint8 *)message;
if (!ALLOW_UNALIGNED_READS && (u.i & 0x7))
{
memcpy(buf, message, length);
u.p64 = buf;
}
size_t remainder = length%32;
uint64 a=*hash1;
uint64 b=*hash2;
uint64 c=sc_const;
uint64 d=sc_const;
if (length > 15)
{
const uint64 *end = u.p64 + (length/32)*4;
// handle all complete sets of 32 bytes
for (; u.p64 < end; u.p64 += 4)
{
c += u.p64[0];
d += u.p64[1];
ShortMix(a,b,c,d);
a += u.p64[2];
b += u.p64[3];
}
//Handle the case of 16+ remaining bytes.
if (remainder >= 16)
{
c += u.p64[0];
d += u.p64[1];
ShortMix(a,b,c,d);
u.p64 += 2;
remainder -= 16;
}
}
// Handle the last 0..15 bytes, and its length
d = ((uint64)length) << 56;
switch (remainder)
{
case 15:
d += ((uint64)u.p8[14]) << 48;
case 14:
d += ((uint64)u.p8[13]) << 40;
case 13:
d += ((uint64)u.p8[12]) << 32;
case 12:
d += u.p32[2];
c += u.p64[0];
break;
case 11:
d += ((uint64)u.p8[10]) << 16;
case 10:
d += ((uint64)u.p8[9]) << 8;
case 9:
d += (uint64)u.p8[8];
case 8:
c += u.p64[0];
break;
case 7:
c += ((uint64)u.p8[6]) << 48;
case 6:
c += ((uint64)u.p8[5]) << 40;
case 5:
c += ((uint64)u.p8[4]) << 32;
case 4:
c += u.p32[0];
break;
case 3:
c += ((uint64)u.p8[2]) << 16;
case 2:
c += ((uint64)u.p8[1]) << 8;
case 1:
c += (uint64)u.p8[0];
break;
case 0:
c += sc_const;
d += sc_const;
}
ShortEnd(a,b,c,d);
*hash1 = a;
*hash2 = b;
}
// do the whole hash in one call
void SpookyHash::Hash128(
const void *message,
size_t length,
uint64 *hash1,
uint64 *hash2)
{
if (length < sc_bufSize)
{
Short(message, length, hash1, hash2);
return;
}
uint64 h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11;
uint64 buf[sc_numVars];
uint64 *end;
union
{
const uint8 *p8;
uint64 *p64;
size_t i;
} u;
size_t remainder;
h0=h3=h6=h9 = *hash1;
h1=h4=h7=h10 = *hash2;
h2=h5=h8=h11 = sc_const;
u.p8 = (const uint8 *)message;
end = u.p64 + (length/sc_blockSize)*sc_numVars;
// handle all whole sc_blockSize blocks of bytes
if (ALLOW_UNALIGNED_READS || ((u.i & 0x7) == 0))
{
while (u.p64 < end)
{
Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
u.p64 += sc_numVars;
}
}
else
{
while (u.p64 < end)
{
memcpy(buf, u.p64, sc_blockSize);
Mix(buf, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
u.p64 += sc_numVars;
}
}
// handle the last partial block of sc_blockSize bytes
remainder = (length - ((const uint8 *)end-(const uint8 *)message));
memcpy(buf, end, remainder);
memset(((uint8 *)buf)+remainder, 0, sc_blockSize-remainder);
((uint8 *)buf)[sc_blockSize-1] = remainder;
Mix(buf, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
// do some final mixing
End(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
*hash1 = h0;
*hash2 = h1;
}
// init spooky state
void SpookyHash::Init(uint64 seed1, uint64 seed2)
{
m_length = 0;
m_remainder = 0;
m_state[0] = seed1;
m_state[1] = seed2;
}
// add a message fragment to the state
void SpookyHash::Update(const void *message, size_t length)
{
uint64 h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11;
size_t newLength = length + m_remainder;
uint8 remainder;
union
{
const uint8 *p8;
uint64 *p64;
size_t i;
} u;
const uint64 *end;
// Is this message fragment too short? If it is, stuff it away.
if (newLength < sc_bufSize)
{
memcpy(&((uint8 *)m_data)[m_remainder], message, length);
m_length = length + m_length;
m_remainder = (uint8)newLength;
return;
}
// init the variables
if (m_length < sc_bufSize)
{
h0=h3=h6=h9 = m_state[0];
h1=h4=h7=h10 = m_state[1];
h2=h5=h8=h11 = sc_const;
}
else
{
h0 = m_state[0];
h1 = m_state[1];
h2 = m_state[2];
h3 = m_state[3];
h4 = m_state[4];
h5 = m_state[5];
h6 = m_state[6];
h7 = m_state[7];
h8 = m_state[8];
h9 = m_state[9];
h10 = m_state[10];
h11 = m_state[11];
}
m_length = length + m_length;
// if we've got anything stuffed away, use it now
if (m_remainder)
{
uint8 prefix = sc_bufSize-m_remainder;
memcpy(&(((uint8 *)m_data)[m_remainder]), message, prefix);
u.p64 = m_data;
Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
Mix(&u.p64[sc_numVars], h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
u.p8 = ((const uint8 *)message) + prefix;
length -= prefix;
}
else
{
u.p8 = (const uint8 *)message;
}
// handle all whole blocks of sc_blockSize bytes
end = u.p64 + (length/sc_blockSize)*sc_numVars;
remainder = (uint8)(length-((const uint8 *)end-u.p8));
if (ALLOW_UNALIGNED_READS || (u.i & 0x7) == 0)
{
while (u.p64 < end)
{
Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
u.p64 += sc_numVars;
}
}
else
{
while (u.p64 < end)
{
memcpy(m_data, u.p8, sc_blockSize);
Mix(m_data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
u.p64 += sc_numVars;
}
}
// stuff away the last few bytes
m_remainder = remainder;
memcpy(m_data, end, remainder);
// stuff away the variables
m_state[0] = h0;
m_state[1] = h1;
m_state[2] = h2;
m_state[3] = h3;
m_state[4] = h4;
m_state[5] = h5;
m_state[6] = h6;
m_state[7] = h7;
m_state[8] = h8;
m_state[9] = h9;
m_state[10] = h10;
m_state[11] = h11;
}
// report the hash for the concatenation of all message fragments so far
void SpookyHash::Final(uint64 *hash1, uint64 *hash2)
{
// init the variables
if (m_length < sc_bufSize)
{
Short( m_data, m_length, hash1, hash2);
return;
}
const uint64 *data = (const uint64 *)m_data;
uint8 remainder = m_remainder;
uint64 h0 = m_state[0];
uint64 h1 = m_state[1];
uint64 h2 = m_state[2];
uint64 h3 = m_state[3];
uint64 h4 = m_state[4];
uint64 h5 = m_state[5];
uint64 h6 = m_state[6];
uint64 h7 = m_state[7];
uint64 h8 = m_state[8];
uint64 h9 = m_state[9];
uint64 h10 = m_state[10];
uint64 h11 = m_state[11];
if (remainder >= sc_blockSize)
{
// m_data can contain two blocks; handle any whole first block
Mix(data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
data += sc_numVars;
remainder -= sc_blockSize;
}
// mix in the last partial block, and the length mod sc_blockSize
memset(&((uint8 *)data)[remainder], 0, (sc_blockSize-remainder));
((uint8 *)data)[sc_blockSize-1] = remainder;
Mix(data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
// do some final mixing
End(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
*hash1 = h0;
*hash2 = h1;
}

View File

@ -0,0 +1,293 @@
//
// SpookyHash: a 128-bit noncryptographic hash function
// By Bob Jenkins, public domain
// Oct 31 2010: alpha, framework + SpookyHash::Mix appears right
// Oct 31 2011: alpha again, Mix only good to 2^^69 but rest appears right
// Dec 31 2011: beta, improved Mix, tested it for 2-bit deltas
// Feb 2 2012: production, same bits as beta
// Feb 5 2012: adjusted definitions of uint* to be more portable
//
// Up to 4 bytes/cycle for long messages. Reasonably fast for short messages.
// All 1 or 2 bit deltas achieve avalanche within 1% bias per output bit.
//
// This was developed for and tested on 64-bit x86-compatible processors.
// It assumes the processor is little-endian. There is a macro
// controlling whether unaligned reads are allowed (by default they are).
// This should be an equally good hash on big-endian machines, but it will
// compute different results on them than on little-endian machines.
//
// Google's CityHash has similar specs to SpookyHash, and CityHash is faster
// on some platforms. MD4 and MD5 also have similar specs, but they are orders
// of magnitude slower. CRCs are two or more times slower, but unlike
// SpookyHash, they have nice math for combining the CRCs of pieces to form
// the CRCs of wholes. There are also cryptographic hashes, but those are even
// slower than MD5.
//
#include <stddef.h>
#ifdef _MSC_VER
# define INLINE __forceinline
typedef unsigned __int64 uint64;
typedef unsigned __int32 uint32;
typedef unsigned __int16 uint16;
typedef unsigned __int8 uint8;
#else
# include <stdint.h>
# define INLINE inline
typedef uint64_t uint64;
typedef uint32_t uint32;
typedef uint16_t uint16;
typedef uint8_t uint8;
#endif
class SpookyHash
{
public:
//
// SpookyHash: hash a single message in one call, produce 128-bit output
//
static void Hash128(
const void *message, // message to hash
size_t length, // length of message in bytes
uint64 *hash1, // in/out: in seed 1, out hash value 1
uint64 *hash2); // in/out: in seed 2, out hash value 2
//
// Hash64: hash a single message in one call, return 64-bit output
//
static uint64 Hash64(
const void *message, // message to hash
size_t length, // length of message in bytes
uint64 seed) // seed
{
uint64 hash1 = seed;
Hash128(message, length, &hash1, &seed);
return hash1;
}
//
// Hash32: hash a single message in one call, produce 32-bit output
//
static uint32 Hash32(
const void *message, // message to hash
size_t length, // length of message in bytes
uint32 seed) // seed
{
uint64 hash1 = seed, hash2 = seed;
Hash128(message, length, &hash1, &hash2);
return (uint32)hash1;
}
//
// Init: initialize the context of a SpookyHash
//
void Init(
uint64 seed1, // any 64-bit value will do, including 0
uint64 seed2); // different seeds produce independent hashes
//
// Update: add a piece of a message to a SpookyHash state
//
void Update(
const void *message, // message fragment
size_t length); // length of message fragment in bytes
//
// Final: compute the hash for the current SpookyHash state
//
// This does not modify the state; you can keep updating it afterward
//
// The result is the same as if SpookyHash() had been called with
// all the pieces concatenated into one message.
//
void Final(
uint64 *hash1, // out only: first 64 bits of hash value.
uint64 *hash2); // out only: second 64 bits of hash value.
//
// left rotate a 64-bit value by k bytes
//
static INLINE uint64 Rot64(uint64 x, int k)
{
return (x << k) | (x >> (64 - k));
}
//
// This is used if the input is 96 bytes long or longer.
//
// The internal state is fully overwritten every 96 bytes.
// Every input bit appears to cause at least 128 bits of entropy
// before 96 other bytes are combined, when run forward or backward
// For every input bit,
// Two inputs differing in just that input bit
// Where "differ" means xor or subtraction
// And the base value is random
// When run forward or backwards one Mix
// I tried 3 pairs of each; they all differed by at least 212 bits.
//
static INLINE void Mix(
const uint64 *data,
uint64 &s0, uint64 &s1, uint64 &s2, uint64 &s3,
uint64 &s4, uint64 &s5, uint64 &s6, uint64 &s7,
uint64 &s8, uint64 &s9, uint64 &s10,uint64 &s11)
{
s0 += data[0]; s2 ^= s10; s11 ^= s0; s0 = Rot64(s0,11); s11 += s1;
s1 += data[1]; s3 ^= s11; s0 ^= s1; s1 = Rot64(s1,32); s0 += s2;
s2 += data[2]; s4 ^= s0; s1 ^= s2; s2 = Rot64(s2,43); s1 += s3;
s3 += data[3]; s5 ^= s1; s2 ^= s3; s3 = Rot64(s3,31); s2 += s4;
s4 += data[4]; s6 ^= s2; s3 ^= s4; s4 = Rot64(s4,17); s3 += s5;
s5 += data[5]; s7 ^= s3; s4 ^= s5; s5 = Rot64(s5,28); s4 += s6;
s6 += data[6]; s8 ^= s4; s5 ^= s6; s6 = Rot64(s6,39); s5 += s7;
s7 += data[7]; s9 ^= s5; s6 ^= s7; s7 = Rot64(s7,57); s6 += s8;
s8 += data[8]; s10 ^= s6; s7 ^= s8; s8 = Rot64(s8,55); s7 += s9;
s9 += data[9]; s11 ^= s7; s8 ^= s9; s9 = Rot64(s9,54); s8 += s10;
s10 += data[10]; s0 ^= s8; s9 ^= s10; s10 = Rot64(s10,22); s9 += s11;
s11 += data[11]; s1 ^= s9; s10 ^= s11; s11 = Rot64(s11,46); s10 += s0;
}
//
// Mix all 12 inputs together so that h0, h1 are a hash of them all.
//
// For two inputs differing in just the input bits
// Where "differ" means xor or subtraction
// And the base value is random, or a counting value starting at that bit
// The final result will have each bit of h0, h1 flip
// For every input bit,
// with probability 50 +- .3%
// For every pair of input bits,
// with probability 50 +- 3%
//
// This does not rely on the last Mix() call having already mixed some.
// Two iterations was almost good enough for a 64-bit result, but a
// 128-bit result is reported, so End() does three iterations.
//
static INLINE void EndPartial(
uint64 &h0, uint64 &h1, uint64 &h2, uint64 &h3,
uint64 &h4, uint64 &h5, uint64 &h6, uint64 &h7,
uint64 &h8, uint64 &h9, uint64 &h10,uint64 &h11)
{
h11+= h1; h2 ^= h11; h1 = Rot64(h1,44);
h0 += h2; h3 ^= h0; h2 = Rot64(h2,15);
h1 += h3; h4 ^= h1; h3 = Rot64(h3,34);
h2 += h4; h5 ^= h2; h4 = Rot64(h4,21);
h3 += h5; h6 ^= h3; h5 = Rot64(h5,38);
h4 += h6; h7 ^= h4; h6 = Rot64(h6,33);
h5 += h7; h8 ^= h5; h7 = Rot64(h7,10);
h6 += h8; h9 ^= h6; h8 = Rot64(h8,13);
h7 += h9; h10^= h7; h9 = Rot64(h9,38);
h8 += h10; h11^= h8; h10= Rot64(h10,53);
h9 += h11; h0 ^= h9; h11= Rot64(h11,42);
h10+= h0; h1 ^= h10; h0 = Rot64(h0,54);
}
static INLINE void End(
uint64 &h0, uint64 &h1, uint64 &h2, uint64 &h3,
uint64 &h4, uint64 &h5, uint64 &h6, uint64 &h7,
uint64 &h8, uint64 &h9, uint64 &h10,uint64 &h11)
{
EndPartial(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
EndPartial(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
EndPartial(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
}
//
// The goal is for each bit of the input to expand into 128 bits of
// apparent entropy before it is fully overwritten.
// n trials both set and cleared at least m bits of h0 h1 h2 h3
// n: 2 m: 29
// n: 3 m: 46
// n: 4 m: 57
// n: 5 m: 107
// n: 6 m: 146
// n: 7 m: 152
// when run forwards or backwards
// for all 1-bit and 2-bit diffs
// with diffs defined by either xor or subtraction
// with a base of all zeros plus a counter, or plus another bit, or random
//
static INLINE void ShortMix(uint64 &h0, uint64 &h1, uint64 &h2, uint64 &h3)
{
h2 = Rot64(h2,50); h2 += h3; h0 ^= h2;
h3 = Rot64(h3,52); h3 += h0; h1 ^= h3;
h0 = Rot64(h0,30); h0 += h1; h2 ^= h0;
h1 = Rot64(h1,41); h1 += h2; h3 ^= h1;
h2 = Rot64(h2,54); h2 += h3; h0 ^= h2;
h3 = Rot64(h3,48); h3 += h0; h1 ^= h3;
h0 = Rot64(h0,38); h0 += h1; h2 ^= h0;
h1 = Rot64(h1,37); h1 += h2; h3 ^= h1;
h2 = Rot64(h2,62); h2 += h3; h0 ^= h2;
h3 = Rot64(h3,34); h3 += h0; h1 ^= h3;
h0 = Rot64(h0,5); h0 += h1; h2 ^= h0;
h1 = Rot64(h1,36); h1 += h2; h3 ^= h1;
}
//
// Mix all 4 inputs together so that h0, h1 are a hash of them all.
//
// For two inputs differing in just the input bits
// Where "differ" means xor or subtraction
// And the base value is random, or a counting value starting at that bit
// The final result will have each bit of h0, h1 flip
// For every input bit,
// with probability 50 +- .3% (it is probably better than that)
// For every pair of input bits,
// with probability 50 +- .75% (the worst case is approximately that)
//
static INLINE void ShortEnd(uint64 &h0, uint64 &h1, uint64 &h2, uint64 &h3)
{
h3 ^= h2; h2 = Rot64(h2,15); h3 += h2;
h0 ^= h3; h3 = Rot64(h3,52); h0 += h3;
h1 ^= h0; h0 = Rot64(h0,26); h1 += h0;
h2 ^= h1; h1 = Rot64(h1,51); h2 += h1;
h3 ^= h2; h2 = Rot64(h2,28); h3 += h2;
h0 ^= h3; h3 = Rot64(h3,9); h0 += h3;
h1 ^= h0; h0 = Rot64(h0,47); h1 += h0;
h2 ^= h1; h1 = Rot64(h1,54); h2 += h1;
h3 ^= h2; h2 = Rot64(h2,32); h3 += h2;
h0 ^= h3; h3 = Rot64(h3,25); h0 += h3;
h1 ^= h0; h0 = Rot64(h0,63); h1 += h0;
}
private:
//
// Short is used for messages under 192 bytes in length
// Short has a low startup cost, the normal mode is good for long
// keys, the cost crossover is at about 192 bytes. The two modes were
// held to the same quality bar.
//
static void Short(
const void *message,
size_t length,
uint64 *hash1,
uint64 *hash2);
// number of uint64's in internal state
static const size_t sc_numVars = 12;
// size of the internal state
static const size_t sc_blockSize = sc_numVars*8;
// size of buffer of unhashed data, in bytes
static const size_t sc_bufSize = 2*sc_blockSize;
//
// sc_const: a constant which:
// * is not zero
// * is odd
// * is a not-very-regular mix of 1's and 0's
// * does not need any other special mathematical properties
//
static const uint64 sc_const = 0xdeadbeefdeadbeefLL;
uint64 m_data[2*sc_numVars]; // unhashed data, for partial messages
uint64 m_state[sc_numVars]; // internal state of the hash
size_t m_length; // total length of the input so far
uint8 m_remainder; // length of unhashed data stashed in m_data
};

View File

@ -96,6 +96,7 @@ CPPSRCS = \
ValidateLimitations.cpp \
ForLoopUnroll.cpp \
MapLongVariableNames.cpp \
spooky.cpp \
BuiltInFunctionEmulator.cpp \
$(NULL)

View File

@ -96,6 +96,7 @@ CPPSRCS = \
ValidateLimitations.cpp \
ForLoopUnroll.cpp \
MapLongVariableNames.cpp \
spooky.cpp \
BuiltInFunctionEmulator.cpp \
$(NULL)

View File

@ -13,7 +13,7 @@
* License.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* Portions created by the Initial Developer are Copyright (C) 2012
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):

View File

@ -253,7 +253,6 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
{ (PRFuncPtr*) &mSymbols.fTexParameteri, { "TexParameteri", NULL } },
{ (PRFuncPtr*) &mSymbols.fTexParameterf, { "TexParameterf", NULL } },
{ (PRFuncPtr*) &mSymbols.fGetString, { "GetString", NULL } },
{ (PRFuncPtr*) &mSymbols.fGetTexLevelParameteriv, { "GetTexLevelParameteriv", NULL } },
{ (PRFuncPtr*) &mSymbols.fGetTexParameterfv, { "GetTexParameterfv", NULL } },
{ (PRFuncPtr*) &mSymbols.fGetTexParameteriv, { "GetTexParameteriv", NULL } },
{ (PRFuncPtr*) &mSymbols.fGetUniformfv, { "GetUniformfv", "GetUniformfvARB", NULL } },
@ -499,6 +498,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
// Load developer symbols, don't fail if we can't find them.
SymLoadStruct auxSymbols[] = {
{ (PRFuncPtr*) &mSymbols.fGetTexImage, { "GetTexImage", NULL } },
{ (PRFuncPtr*) &mSymbols.fGetTexLevelParameteriv, { "GetTexLevelParameteriv", NULL } },
{ NULL, { NULL } },
};
LoadSymbols(&auxSymbols[0], trygl, prefix);

View File

@ -2136,6 +2136,10 @@ public:
void fGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params)
{
if (!mSymbols.fGetTexLevelParameteriv) {
*params = 0;
return;
}
BEFORE_GL_CALL;
mSymbols.fGetTexLevelParameteriv(target, level, pname, params);
AFTER_GL_CALL;

View File

@ -2630,11 +2630,7 @@ GLContextProviderEGL::CreateOffscreen(const gfxIntSize& aSize,
if (!glContext) {
return nsnull;
}
if (!glContext->GetSharedContext()) {
// no point in returning anything if sharing failed, we can't
// render from this
return nsnull;
}
if (!gUseBackingSurface && !glContext->ResizeOffscreenFBO(glContext->OffscreenActualSize(), true)) {
// we weren't able to create the initial
// offscreen FBO, so this is dead

View File

@ -50,7 +50,7 @@ RenderColorLayer(ColorLayer* aLayer, LayerManagerOGL *aManager,
// XXX we might be able to improve performance by using glClear
nsIntRect visibleRect = aLayer->GetEffectiveVisibleRegion().GetBounds();
/* Multiply color by the layer opacity, as the shader
* ignores layer opacity and expects a final color to
* write to the color buffer. This saves a needless
@ -77,14 +77,14 @@ void
ColorLayerOGL::RenderLayer(int,
const nsIntPoint& aOffset)
{
return RenderColorLayer(this, mOGLManager, aOffset);
RenderColorLayer(this, mOGLManager, aOffset);
}
void
ShadowColorLayerOGL::RenderLayer(int,
const nsIntPoint& aOffset)
{
return RenderColorLayer(this, mOGLManager, aOffset);
RenderColorLayer(this, mOGLManager, aOffset);
}

View File

@ -45,6 +45,7 @@
#include "nsColor.h"
#include "nsCoord.h"
#include "gfxContext.h"
#include "mozilla/gfx/UserData.h"
struct nsPoint;
class nsIntRegion;
@ -58,6 +59,9 @@ typedef enum {
class nsRenderingContext
{
typedef mozilla::gfx::UserData UserData;
typedef mozilla::gfx::UserDataKey UserDataKey;
public:
nsRenderingContext() : mP2A(0.) {}
// ~nsRenderingContext() {}
@ -136,6 +140,16 @@ public:
void DrawString(const PRUnichar *aString, PRUint32 aLength,
nscoord aX, nscoord aY);
void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) {
mUserData.Add(key, userData, destroy);
}
void *GetUserData(UserDataKey *key) {
return mUserData.Get(key);
}
void *RemoveUserData(UserDataKey *key) {
return mUserData.Remove(key);
}
protected:
PRInt32 GetMaxChunkLength();
@ -144,6 +158,8 @@ protected:
nsRefPtr<nsFontMetrics> mFontMetrics;
double mP2A; // cached app units per device pixel value
UserData mUserData;
};
#endif // NSRENDERINGCONTEXT__H__

View File

@ -1718,12 +1718,19 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
// request.
nsCOMPtr<nsIStreamListener> listener = pl;
if (corsmode != imgIRequest::CORS_NONE) {
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgLoader::LoadImage -- Setting up a CORS load",
this));
bool withCredentials = corsmode == imgIRequest::CORS_USE_CREDENTIALS;
nsCOMPtr<nsIStreamListener> corsproxy =
new nsCORSListenerProxy(pl, aLoadingPrincipal, newChannel,
withCredentials, &rv);
if (NS_FAILED(rv)) {
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgLoader::LoadImage -- nsCORSListenerProxy "
"creation failed: 0x%x\n", this, rv));
request->CancelAndAbort(rv);
return NS_ERROR_FAILURE;
}

View File

@ -0,0 +1,2 @@
<!DOCTYPE html>
<img crossorigin src="data:a/a,">

View File

@ -25,3 +25,4 @@ HTTP load delayedframe.sjs
load 681190.html
load 694165-1.xhtml
load 732319-1.html

View File

@ -1141,7 +1141,7 @@ static JS_ALWAYS_INLINE bool IsNegative(Type i)
return IsNegativeImpl<Type, numeric_limits<Type>::is_signed>::Test(i);
}
// Implicitly convert val to bool, allowing JSBool, jsint, and double
// Implicitly convert val to bool, allowing JSBool, int, and double
// arguments numerically equal to 0 or 1.
static bool
jsvalToBool(JSContext* cx, jsval val, bool* result)
@ -1151,7 +1151,7 @@ jsvalToBool(JSContext* cx, jsval val, bool* result)
return true;
}
if (JSVAL_IS_INT(val)) {
jsint i = JSVAL_TO_INT(val);
int32_t i = JSVAL_TO_INT(val);
*result = i != 0;
return i == 0 || i == 1;
}
@ -1165,7 +1165,7 @@ jsvalToBool(JSContext* cx, jsval val, bool* result)
return false;
}
// Implicitly convert val to IntegerType, allowing JSBool, jsint, double,
// Implicitly convert val to IntegerType, allowing JSBool, int, double,
// Int64, UInt64, and CData integer types 't' where all values of 't' are
// representable by IntegerType.
template<class IntegerType>
@ -1177,7 +1177,7 @@ jsvalToInteger(JSContext* cx, jsval val, IntegerType* result)
if (JSVAL_IS_INT(val)) {
// Make sure the integer fits in the alotted precision, and has the right
// sign.
jsint i = JSVAL_TO_INT(val);
int32_t i = JSVAL_TO_INT(val);
return ConvertExact(i, result);
}
if (JSVAL_IS_DOUBLE(val)) {
@ -1246,7 +1246,7 @@ jsvalToInteger(JSContext* cx, jsval val, IntegerType* result)
return false;
}
// Implicitly convert val to FloatType, allowing jsint, double,
// Implicitly convert val to FloatType, allowing int, double,
// Int64, UInt64, and CData numeric types 't' where all values of 't' are
// representable by FloatType.
template<class FloatType>
@ -1359,7 +1359,7 @@ StringToInteger(JSContext* cx, JSString* string, IntegerType* result)
return true;
}
// Implicitly convert val to IntegerType, allowing jsint, double,
// Implicitly convert val to IntegerType, allowing int, double,
// Int64, UInt64, and optionally a decimal or hexadecimal string argument.
// (This is common code shared by jsvalToSize and the Int64/UInt64 constructors.)
template<class IntegerType>
@ -1374,7 +1374,7 @@ jsvalToBigInteger(JSContext* cx,
if (JSVAL_IS_INT(val)) {
// Make sure the integer fits in the alotted precision, and has the right
// sign.
jsint i = JSVAL_TO_INT(val);
int32_t i = JSVAL_TO_INT(val);
return ConvertExact(i, result);
}
if (JSVAL_IS_DOUBLE(val)) {
@ -1421,7 +1421,7 @@ jsvalToSize(JSContext* cx, jsval val, bool allowString, size_t* result)
return Convert<size_t>(double(*result)) == *result;
}
// Implicitly convert val to IntegerType, allowing jsint, double,
// Implicitly convert val to IntegerType, allowing int, double,
// Int64, UInt64, and optionally a decimal or hexadecimal string argument.
// (This is common code shared by jsvalToSize and the Int64/UInt64 constructors.)
template<class IntegerType>
@ -1436,7 +1436,7 @@ jsidToBigInteger(JSContext* cx,
if (JSID_IS_INT(val)) {
// Make sure the integer fits in the alotted precision, and has the right
// sign.
jsint i = JSID_TO_INT(val);
int32_t i = JSID_TO_INT(val);
return ConvertExact(i, result);
}
if (allowString && JSID_IS_STRING(val)) {
@ -1525,9 +1525,9 @@ static bool
jsvalToPtrExplicit(JSContext* cx, jsval val, uintptr_t* result)
{
if (JSVAL_IS_INT(val)) {
// jsint always fits in intptr_t. If the integer is negative, cast through
// int32_t always fits in intptr_t. If the integer is negative, cast through
// an intptr_t intermediate to sign-extend.
jsint i = JSVAL_TO_INT(val);
int32_t i = JSVAL_TO_INT(val);
*result = i < 0 ? uintptr_t(intptr_t(i)) : uintptr_t(i);
return true;
}
@ -1650,7 +1650,7 @@ ConvertToJS(JSContext* cx,
case TYPE_##name: { \
type value = *static_cast<type*>(data); \
if (sizeof(type) < 4) \
*result = INT_TO_JSVAL(jsint(value)); \
*result = INT_TO_JSVAL(int32_t(value)); \
else if (!JS_NewNumberValue(cx, double(value), result)) \
return false; \
break; \
@ -2929,7 +2929,7 @@ CType::GetSafeSize(JSObject* obj, size_t* result)
jsval size = JS_GetReservedSlot(obj, SLOT_SIZE);
// The "size" property can be a jsint, a double, or JSVAL_VOID
// The "size" property can be an int, a double, or JSVAL_VOID
// (for arrays of undefined length), and must always fit in a size_t.
if (JSVAL_IS_INT(size)) {
*result = JSVAL_TO_INT(size);
@ -2953,7 +2953,7 @@ CType::GetSize(JSObject* obj)
JS_ASSERT(!JSVAL_IS_VOID(size));
// The "size" property can be a jsint, a double, or JSVAL_VOID
// The "size" property can be an int, a double, or JSVAL_VOID
// (for arrays of undefined length), and must always fit in a size_t.
// For callers who know it can never be JSVAL_VOID, return a size_t directly.
if (JSVAL_IS_INT(size))
@ -2968,7 +2968,7 @@ CType::IsSizeDefined(JSObject* obj)
jsval size = JS_GetReservedSlot(obj, SLOT_SIZE);
// The "size" property can be a jsint, a double, or JSVAL_VOID
// The "size" property can be an int, a double, or JSVAL_VOID
// (for arrays of undefined length), and must always fit in a size_t.
JS_ASSERT(JSVAL_IS_INT(size) || JSVAL_IS_DOUBLE(size) || JSVAL_IS_VOID(size));
return !JSVAL_IS_VOID(size);
@ -3599,7 +3599,7 @@ ArrayType::CreateInternal(JSContext* cx,
jsval sizeVal = JSVAL_VOID;
jsval lengthVal = JSVAL_VOID;
if (lengthDefined) {
// Check for overflow, and convert to a jsint or double as required.
// Check for overflow, and convert to an int or double as required.
size_t size = length * baseSize;
if (length > 0 && size / length != baseSize) {
JS_ReportError(cx, "size overflow");
@ -3750,7 +3750,7 @@ ArrayType::GetSafeLength(JSObject* obj, size_t* result)
jsval length = JS_GetReservedSlot(obj, SLOT_LENGTH);
// The "length" property can be a jsint, a double, or JSVAL_VOID
// The "length" property can be an int, a double, or JSVAL_VOID
// (for arrays of undefined length), and must always fit in a size_t.
if (JSVAL_IS_INT(length)) {
*result = JSVAL_TO_INT(length);
@ -3775,7 +3775,7 @@ ArrayType::GetLength(JSObject* obj)
JS_ASSERT(!JSVAL_IS_VOID(length));
// The "length" property can be a jsint, a double, or JSVAL_VOID
// The "length" property can be an int, a double, or JSVAL_VOID
// (for arrays of undefined length), and must always fit in a size_t.
// For callers who know it can never be JSVAL_VOID, return a size_t directly.
if (JSVAL_IS_INT(length))

View File

@ -775,7 +775,7 @@ frontend::DefineCompileTimeConstant(JSContext *cx, BytecodeEmitter *bce, JSAtom
}
StmtInfo *
frontend::LexicalLookup(TreeContext *tc, JSAtom *atom, jsint *slotp, StmtInfo *stmt)
frontend::LexicalLookup(TreeContext *tc, JSAtom *atom, int *slotp, StmtInfo *stmt)
{
if (!stmt)
stmt = tc->topScopeStmt;
@ -1007,8 +1007,8 @@ BytecodeEmitter::shouldNoteClosedName(ParseNode *pn)
*
* The function returns -1 on failures.
*/
static jsint
AdjustBlockSlot(JSContext *cx, BytecodeEmitter *bce, jsint slot)
static int
AdjustBlockSlot(JSContext *cx, BytecodeEmitter *bce, int slot)
{
JS_ASSERT((jsuint) slot < bce->maxStackDepth);
if (bce->inFunction()) {
@ -1160,7 +1160,7 @@ BindKnownGlobal(JSContext *cx, BytecodeEmitter *bce, ParseNode *dn, ParseNode *p
// Otherwise, find the atom's index by using the originating bce's
// global use table.
index = globalbce->globalUses[dn->pn_cookie.asInteger()].slot;
index = globalbce->globalUses[dn->pn_cookie.slot()].slot;
}
if (!bce->addGlobalUse(atom, index, &pn->pn_cookie))
@ -1350,7 +1350,7 @@ BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
}
/* Optimize accesses to undeclared globals. */
if (!bce->mightAliasLocals() && !TryConvertToGname(bce, pn, &op))
if (!TryConvertToGname(bce, pn, &op))
return JS_TRUE;
jsatomid _;
@ -1852,7 +1852,7 @@ EmitNameOp(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSBool callContex
} else {
if (!pn->pn_cookie.isFree()) {
JS_ASSERT(JOF_OPTYPE(op) != JOF_ATOM);
EMIT_UINT16_IMM_OP(op, pn->pn_cookie.asInteger());
EMIT_UINT16_IMM_OP(op, pn->pn_cookie.slot());
} else {
if (!EmitAtomOp(cx, pn, op, bce))
return JS_FALSE;
@ -2261,7 +2261,7 @@ EmitNumberOp(JSContext *cx, double dval, BytecodeEmitter *bce)
return Emit1(cx, bce, JSOP_ZERO) >= 0;
if (ival == 1)
return Emit1(cx, bce, JSOP_ONE) >= 0;
if ((jsint)(int8_t)ival == ival)
if ((int)(int8_t)ival == ival)
return Emit2(cx, bce, JSOP_INT8, (jsbytecode)(int8_t)ival) >= 0;
u = (uint32_t)ival;
@ -2474,7 +2474,7 @@ EmitSwitch(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
continue;
}
i = pn3->pn_pval->toInt32();
if ((jsuint)(i + (jsint)JS_BIT(15)) >= (jsuint)JS_BIT(16)) {
if ((jsuint)(i + (int)JS_BIT(15)) >= (jsuint)JS_BIT(16)) {
switchOp = JSOP_LOOKUPSWITCH;
continue;
}
@ -2684,7 +2684,7 @@ EmitSwitch(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
savepc = bce->next();
bce->current->next = pc + 1;
if (switchOp == JSOP_TABLESWITCH) {
for (i = 0; i < (jsint)tableLength; i++) {
for (i = 0; i < (int)tableLength; i++) {
pn3 = table[i];
if (pn3 &&
(pn4 = pn3->pn_left) != NULL &&
@ -2764,7 +2764,7 @@ EmitSwitch(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
pc += 2 * JUMP_OFFSET_LEN;
/* Fill in the jump table, if there is one. */
for (i = 0; i < (jsint)tableLength; i++) {
for (i = 0; i < (int)tableLength; i++) {
pn3 = table[i];
off = pn3 ? pn3->pn_offset - top : 0;
SET_JUMP_OFFSET(pc, off);
@ -3019,14 +3019,14 @@ EmitDestructuringLHS(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmit
case JSOP_SETLOCAL:
{
jsuint slot = pn->pn_cookie.asInteger();
uint16_t slot = pn->pn_cookie.slot();
EMIT_UINT16_IMM_OP(JSOP_SETLOCALPOP, slot);
break;
}
case JSOP_SETARG:
{
jsuint slot = pn->pn_cookie.asInteger();
uint16_t slot = pn->pn_cookie.slot();
EMIT_UINT16_IMM_OP(pn->getOp(), slot);
if (Emit1(cx, bce, JSOP_POP) < 0)
return JS_FALSE;
@ -3334,7 +3334,7 @@ EmitGroupAssignment(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp,
for (pn = lhs->pn_head; pn; pn = pn->pn_next, ++i) {
/* MaybeEmitGroupAssignment requires lhs->pn_count <= rhs->pn_count. */
JS_ASSERT(i < limit);
jsint slot = AdjustBlockSlot(cx, bce, i);
int slot = AdjustBlockSlot(cx, bce, i);
if (slot < 0)
return JS_FALSE;
EMIT_UINT16_IMM_OP(JSOP_GETLOCAL, slot);
@ -3658,7 +3658,8 @@ EmitAssignment(JSContext *cx, BytecodeEmitter *bce, ParseNode *lhs, JSOp op, Par
if (!BindNameToSlot(cx, bce, lhs))
return false;
if (!lhs->pn_cookie.isFree()) {
atomIndex = lhs->pn_cookie.asInteger();
JS_ASSERT(lhs->pn_cookie.level() == 0);
atomIndex = lhs->pn_cookie.slot();
} else {
if (!bce->makeAtomIndex(lhs->pn_atom, &atomIndex))
return false;
@ -6507,7 +6508,7 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
#endif /* JS_HAS_BLOCK_SCOPE */
#if JS_HAS_GENERATORS
case PNK_ARRAYPUSH: {
jsint slot;
int slot;
/*
* The array object's stack index is in bce->arrayCompDepth. See below

View File

@ -168,7 +168,7 @@ struct StmtInfo {
#define TCF_IN_FOR_INIT 0x10 /* parsing init expr of for; exclude 'in' */
#define TCF_FUN_SETS_OUTER_NAME 0x20 /* function set outer name (lexical or free) */
#define TCF_FUN_PARAM_ARGUMENTS 0x40 /* function has parameter named arguments */
#define TCF_FUN_LOCAL_ARGUMENTS 0x80 /* function has local named arguments */
#define TCF_FUN_LOCAL_ARGUMENTS 0x80 /* function may contain a local named arguments */
#define TCF_FUN_USES_ARGUMENTS 0x100 /* function uses arguments except as a
parameter name */
#define TCF_FUN_HEAVYWEIGHT 0x200 /* function needs Call object per call */
@ -789,7 +789,7 @@ DefineCompileTimeConstant(JSContext *cx, BytecodeEmitter *bce, JSAtom *atom, Par
* found. Otherwise return null.
*/
StmtInfo *
LexicalLookup(TreeContext *tc, JSAtom *atom, jsint *slotp, StmtInfo *stmt = NULL);
LexicalLookup(TreeContext *tc, JSAtom *atom, int *slotp, StmtInfo *stmt = NULL);
/*
* Emit code into bce for the tree rooted at pn.

View File

@ -6080,6 +6080,9 @@ Parser::qualifiedSuffix(ParseNode *pn)
if (!pn2)
return NULL;
/* This qualifiedSuffice may refer to 'arguments'. */
tc->flags |= (TCF_FUN_HEAVYWEIGHT | TCF_FUN_LOCAL_ARGUMENTS);
/* Left operand of :: must be evaluated if it is an identifier. */
if (pn->isOp(JSOP_QNAMEPART))
pn->setOp(JSOP_NAME);
@ -6124,7 +6127,7 @@ Parser::qualifiedIdentifier()
return NULL;
if (tokenStream.matchToken(TOK_DBLCOLON)) {
/* Hack for bug 496316. Slowing down E4X won't make it go away, alas. */
tc->flags |= TCF_FUN_HEAVYWEIGHT;
tc->flags |= (TCF_FUN_HEAVYWEIGHT | TCF_FUN_LOCAL_ARGUMENTS);
pn = qualifiedSuffix(pn);
}
return pn;
@ -6639,7 +6642,7 @@ Parser::propertyQualifiedIdentifier()
JS_ASSERT(tokenStream.peekToken() == TOK_DBLCOLON);
/* Deoptimize QualifiedIdentifier properties to avoid tricky analysis. */
tc->flags |= TCF_FUN_HEAVYWEIGHT;
tc->flags |= (TCF_FUN_HEAVYWEIGHT | TCF_FUN_LOCAL_ARGUMENTS);
PropertyName *name = tokenStream.currentToken().name();
ParseNode *node = NameNode::create(PNK_NAME, name, tc);

View File

@ -0,0 +1,5 @@
function g(s) {
return eval(s)
}
f = g("(function(){({x:function::arguments})})")
f()

View File

@ -0,0 +1,5 @@
function h(s) {
return eval(s)
}
f = h("(function(){function::arguments=[]})")
for (a in f()) {}

View File

@ -0,0 +1,29 @@
// When multiple frames have onPop handlers, they are called in the correct order.
var g = newGlobal('new-compartment');
g.eval("function f() { debugger; }");
g.eval("function g() { f(); }");
g.eval("function h() { g(); }");
g.eval("function i() { h(); }");
var dbg = new Debugger(g);
var log;
function logger(frame, mark) {
return function (completion) {
assertEq(this, frame);
assertEq('return' in completion, true);
log += mark;
};
}
dbg.onEnterFrame = function handleEnter(f) {
log += "(" + f.callee.name;
// Note that this establishes a distinct function object as each
// frame's onPop handler. Thus, a pass proves that each frame is
// remembering its handler separately.
f.onPop = logger(f, f.callee.name + ")");
};
dbg.onDebuggerStatement = function handleDebugger(f) {
log += 'd';
};
log = '';
g.i();
assertEq(log, "(i(h(g(fdf)g)h)i)");

View File

@ -0,0 +1,20 @@
// Clearing a frame's onPop handler works.
var g = newGlobal('new-compartment');
g.eval("function f() { debugger; }");
var dbg = new Debugger(g);
var log;
dbg.onEnterFrame = function handleEnter(f) {
log += "(";
f.onPop = function handlePop() {
assertEq("handlePop was called", "handlePop should never be called");
};
};
dbg.onDebuggerStatement = function handleDebugger(f) {
log += "d";
assertEq(typeof f.onPop, "function");
f.onPop = undefined;
};
log = '';
g.f();
assertEq(log, "(d");

View File

@ -0,0 +1,32 @@
// When an exception is propagated out of multiple frames, their onPop
// and onExceptionUnwind handlers are called in the correct order.
var g = newGlobal('new-compartment');
g.eval("function f() { throw 'mud'; }");
g.eval("function g() { f(); }");
g.eval("function h() { g(); }");
g.eval("function i() { h(); }");
var dbg = new Debugger(g);
var log;
function makePopHandler(label) {
return function handlePop(completion) {
log += label;
assertEq(completion.throw, "mud");
};
}
dbg.onEnterFrame = function handleEnter(f) {
log += "(" + f.callee.name;
f.onPop = makePopHandler(")" + f.callee.name);
};
dbg.onExceptionUnwind = function handleExceptionUnwind(f, x) {
assertEq(x, 'mud');
log += "u" + f.callee.name;
};
log = '';
try {
g.i();
} catch (x) {
log += 'c';
assertEq(x, "mud");
}
assertEq(log, "(i(h(g(fuf)fug)guh)hui)ic");

View File

@ -0,0 +1,30 @@
// When a termination is propagated out of multiple frames, their onPop
// handlers are called in the correct order, and no onExceptionUnwind
// handlers are called.
var g = newGlobal('new-compartment');
g.eval("function f() { terminate(); }");
g.eval("function g() { f(); }");
g.eval("function h() { g(); }");
g.eval("function i() { h(); }");
var dbg = new Debugger(g);
var log;
var count = 0;
function makePopHandler(label, resumption) {
return function handlePop(completion) {
log += label;
assertEq(completion, null);
return resumption;
};
}
dbg.onEnterFrame = function handleEnter(f) {
log += "(" + f.callee.name;
f.onPop = makePopHandler(f.callee.name + ")",
count++ == 0 ? { return: 'king' } : undefined);
};
dbg.onExceptionUnwind = function handleExceptionUnwind(f, x) {
log += 'u';
};
log = '';
assertEq(g.i(), 'king');
assertEq(log, "(i(h(g(ff)g)h)i)");

View File

@ -0,0 +1,25 @@
var g = newGlobal('new-compartment');
var dbg = new Debugger(g);
g.debuggerGlobal = this;
var log;
dbg.onEnterFrame = function handleEnter(f) {
log += '(';
f.onPop = function handlePop(c) {
log += ')';
assertEq(c.throw, "election");
};
};
dbg.onExceptionUnwind = function handleExceptionUnwind(f, x) {
log += 'u';
assertEq(x, "election");
};
log = '';
try {
g.eval("try { throw 'election'; } finally { debuggerGlobal.log += 'f'; }");
} catch (x) {
log += 'c';
assertEq(x, 'election');
}
assertEq(log, '(ufu)c');

View File

@ -0,0 +1,19 @@
// dbg.getNewestFrame in an onPop handler returns the frame being popped.
var g = newGlobal('new-compartment');
g.eval("function f() { debugger; }");
g.eval("function g() { f(); }");
g.eval("function h() { g(); }");
g.eval("function i() { h(); }");
var dbg = new Debugger(g);
var log;
dbg.onEnterFrame = function handleEnter(f) {
log += "(" + f.callee.name;
f.onPop = function handlePop(c) {
log += ")" + f.callee.name;
assertEq(dbg.getNewestFrame(), this);
};
};
log = '';
g.i();
assertEq(log, "(i(h(g(f)f)g)h)i");

View File

@ -0,0 +1,30 @@
// Trying to set an onPop handler on a dead frame throws an exception.
var g = newGlobal('new-compartment');
g.eval("function f() { }");
g.eval("function g() { f(); }");
g.eval("function h() { g(); }");
g.eval("function i() { h(); }");
var dbg = new Debugger(g);
var log;
var frames = [];
dbg.onEnterFrame = function handleEnter(f) {
log += "(";
assertEq(f.live, true);
frames.push(f);
};
log = '';
g.i();
assertEq(log, "((((");
assertEq(frames.length, 4);
for (i = 0; i < frames.length; i++) {
assertEq(frames[i].live, false);
var set = false;
try {
frames[i].onPop = function unappreciated() { };
set = true; // don't assert in a 'try' block
} catch (x) {
assertEq(x instanceof Error, true);
}
assertEq(set, false);
}

View File

@ -0,0 +1,16 @@
// Setting onPop handlers from a 'debugger' statement handler works.
var g = newGlobal('new-compartment');
var dbg = new Debugger(g);
var log;
dbg.onDebuggerStatement = function handleDebugger(frame) {
assertEq(frame.type, "eval");
log += 'd';
frame.onPop = function handlePop(c) {
log += ')';
};
};
log = '';
g.eval('debugger;');
assertEq(log, 'd)');

View File

@ -0,0 +1,23 @@
// Setting onPop handlers from an onExceptionUnwind handler works.
var g = newGlobal('new-compartment');
var dbg = new Debugger(g);
var log;
dbg.onExceptionUnwind = function handleUnwind(frame) {
log += 'u';
assertEq(frame.type, "eval");
frame.onPop = function handleCallPop(c) {
log += ')';
assertEq(c.throw, 'up');
};
};
log = "";
try {
g.eval("throw 'up';");
log += '-';
} catch (x) {
log += 'c';
assertEq(x, 'up');
}
assertEq(log, 'u)c');

View File

@ -0,0 +1,22 @@
// Setting onPop handlers from an onStep handler works.
var g = newGlobal('new-compartment');
var dbg = new Debugger(g);
var log;
dbg.onDebuggerStatement = function handleDebugger(frame) {
log += 'd';
assertEq(frame.type, "eval");
frame.onStep = function handleStep() {
log += 's';
this.onStep = undefined;
this.onPop = function handlePop() {
log += ')';
};
};
};
log = "";
g.flag = false;
g.eval('debugger; flag = true');
assertEq(log, 'ds)');
assertEq(g.flag, true);

View File

@ -0,0 +1,22 @@
// Setting onPop handlers from breakpoint handlers works.
var g = newGlobal('new-compartment');
g.eval("function f(){ return 'to normalcy'; }");
var dbg = new Debugger(g);
var log;
// Set a breakpoint at the start of g.f
var gf = dbg.addDebuggee(g.f); // addDebuggee used as Debugger.Object factory
var fStartOffset = gf.script.getLineOffsets(gf.script.startLine)[0];
gf.script.setBreakpoint(fStartOffset, {
hit: function handleHit(frame) {
log += 'b';
frame.onPop = function handlePop(c) {
log += ')';
assertEq(c.return, "to normalcy");
};
}
});
log = "";
assertEq(g.f(), "to normalcy");
assertEq(log, "b)");

View File

@ -0,0 +1,21 @@
// Setting an onPop handler from an onPop handler doesn't throw, but the
// new handler doesn't fire.
var g = newGlobal('new-compartment');
var dbg = new Debugger(g);
var log;
dbg.onDebuggerStatement = function handleDebugger(frame) {
log += 'd';
assertEq(frame.type, "eval");
frame.onPop = function firstHandlePop(c) {
log +=')';
assertEq(c.return, 'on investment');
this.onPop = function secondHandlePop(c) {
assertEq("secondHandlePop was called", "secondHandlePop should never be called");
};
};
};
log = "";
g.eval("debugger; 'on investment';");
assertEq(log, 'd)');

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