diff --git a/accessible/tests/mochitest/treeupdate/Makefile.in b/accessible/tests/mochitest/treeupdate/Makefile.in index fa6cee59a5a0..bc214701fda3 100644 --- a/accessible/tests/mochitest/treeupdate/Makefile.in +++ b/accessible/tests/mochitest/treeupdate/Makefile.in @@ -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 \ diff --git a/accessible/tests/mochitest/treeupdate/test_hidden.html b/accessible/tests/mochitest/treeupdate/test_hidden.html new file mode 100644 index 000000000000..2adb9efeb108 --- /dev/null +++ b/accessible/tests/mochitest/treeupdate/test_hidden.html @@ -0,0 +1,135 @@ + + + +
+++ + + + + + + + diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index b796cec7b4d4..0b3ea8164033 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -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 diff --git a/build/stdc++compat.cpp b/build/stdc++compat.cpp index a7f73af95564..7cf6f09c38c7 100644 --- a/build/stdc++compat.cpp +++ b/build/stdc++compat.cpp @@ -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 diff --git a/configure.in b/configure.in index e97f2169c3f4..b90bda149ce9 100644 --- a/configure.in +++ b/configure.in @@ -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)' diff --git a/content/base/public/Element.h b/content/base/public/Element.h index 3796aca2b8ef..5d0f0e408c70 100644 --- a/content/base/public/Element.h +++ b/content/base/public/Element.h @@ -42,7 +42,6 @@ #include "nsIContent.h" #include "nsEventStates.h" -#include "nsDOMMemoryReporter.h" class nsEventStateManager; class nsGlobalWindow; diff --git a/content/base/public/nsIContent.h b/content/base/public/nsIContent.h index 750578917e37..e0f24d397f94 100644 --- a/content/base/public/nsIContent.h +++ b/content/base/public/nsIContent.h @@ -43,7 +43,6 @@ #include "nsChangeHint.h" #include "nsINode.h" #include "nsIDocument.h" // for IsInHTMLDocument -#include "nsDOMMemoryReporter.h" // Forward declarations class nsIAtom; diff --git a/content/base/public/nsIDocument.h b/content/base/public/nsIDocument.h index 40dfd3595aab..5402e6ef1f31 100644 --- a/content/base/public/nsIDocument.h +++ b/content/base/public/nsIDocument.h @@ -68,7 +68,6 @@ #include "nsEventStates.h" #include "nsIStructuredCloneContainer.h" #include "nsIBFCacheEntry.h" -#include "nsDOMMemoryReporter.h" class nsIContent; class nsPresContext; diff --git a/content/base/public/nsINode.h b/content/base/public/nsINode.h index 5992075bb973..3aeb7e94e395 100644 --- a/content/base/public/nsINode.h +++ b/content/base/public/nsINode.h @@ -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" diff --git a/content/base/public/nsIObjectLoadingContent.idl b/content/base/public/nsIObjectLoadingContent.idl index 92a15adf1cd4..a30fb8893214 100644 --- a/content/base/public/nsIObjectLoadingContent.idl +++ b/content/base/public/nsIObjectLoadingContent.idl @@ -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 diff --git a/content/base/src/nsCommentNode.cpp b/content/base/src/nsCommentNode.cpp index d15afcaefc8e..3193ac7c43a8 100644 --- a/content/base/src/nsCommentNode.cpp +++ b/content/base/src/nsCommentNode.cpp @@ -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 diff --git a/content/base/src/nsDOMSettableTokenList.cpp b/content/base/src/nsDOMSettableTokenList.cpp index d7b07fbfbc0b..2bd34a12915d 100644 --- a/content/base/src/nsDOMSettableTokenList.cpp +++ b/content/base/src/nsDOMSettableTokenList.cpp @@ -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); +} diff --git a/content/base/src/nsDOMSettableTokenList.h b/content/base/src/nsDOMSettableTokenList.h index 1189394731e7..537bbd81a237 100644 --- a/content/base/src/nsDOMSettableTokenList.h +++ b/content/base/src/nsDOMSettableTokenList.h @@ -59,6 +59,9 @@ public: nsDOMSettableTokenList(nsGenericElement* aElement, nsIAtom* aAttrAtom); + virtual JSObject* WrapObject(JSContext *cx, XPCWrappedNativeScope *scope, + bool *triedToWrap); + protected: virtual ~nsDOMSettableTokenList(); }; diff --git a/content/base/src/nsDOMTokenList.cpp b/content/base/src/nsDOMTokenList.cpp index db92dc6d32be..0d98f6ac1fb9 100644 --- a/content/base/src/nsDOMTokenList.cpp +++ b/content/base/src/nsDOMTokenList.cpp @@ -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); +} + diff --git a/content/base/src/nsDOMTokenList.h b/content/base/src/nsDOMTokenList.h index e70d003d6512..df1f41d7d87b 100644 --- a/content/base/src/nsDOMTokenList.h +++ b/content/base/src/nsDOMTokenList.h @@ -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(); diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 376420990f1b..451cfe23c116 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -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! diff --git a/content/base/src/nsGenericDOMDataNode.h b/content/base/src/nsGenericDOMDataNode.h index 577bb995175b..34570e75cbe7 100644 --- a/content/base/src/nsGenericDOMDataNode.h +++ b/content/base/src/nsGenericDOMDataNode.h @@ -50,7 +50,6 @@ #include "nsEventListenerManager.h" #include "nsGenericElement.h" #include "nsCycleCollectionParticipant.h" -#include "nsDOMMemoryReporter.h" #include "nsISMILAttr.h" diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp index a90de207aba0..e03df4da2b11 100644 --- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -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
(if editor.quotesPreformatted is set),
- // or not wrapped in any special tag (if mail.compose.wrap_to_window_width)
- // or in a (if neither of the above are set).
- bool mQuotesPreformatted; // expect quotes wrapped in
+ // Mail can represent quotes in different ways:
+ // Not wrapped in any special tag (if mail.compose.wrap_to_window_width)
+ // or in a .
bool mDontWrapAnyQuotes; // no special quote markers
bool mStructs; // Output structs (pref)
diff --git a/content/base/src/nsStyledElement.h b/content/base/src/nsStyledElement.h
index 8e64ef2cfb45..373a4e54a5a5 100644
--- a/content/base/src/nsStyledElement.h
+++ b/content/base/src/nsStyledElement.h
@@ -48,7 +48,6 @@
#include "nsString.h"
#include "nsGenericElement.h"
-#include "nsDOMMemoryReporter.h"
namespace mozilla {
namespace css {
diff --git a/content/base/src/nsTextFragment.h b/content/base/src/nsTextFragment.h
index cab42623d88a..922f0d74a501 100644
--- a/content/base/src/nsTextFragment.h
+++ b/content/base/src/nsTextFragment.h
@@ -48,7 +48,6 @@
#include "nsString.h"
#include "nsReadableUtils.h"
#include "nsTraceRefcnt.h"
-#include "nsDOMMemoryReporter.h"
class nsString;
class nsCString;
diff --git a/content/base/src/nsTextNode.h b/content/base/src/nsTextNode.h
index 3db87a2b76b2..7f05ab4e7de1 100644
--- a/content/base/src/nsTextNode.h
+++ b/content/base/src/nsTextNode.h
@@ -45,7 +45,6 @@
#include "nsIAttribute.h"
#include "nsIDocument.h"
#include "nsThreadUtils.h"
-#include "nsDOMMemoryReporter.h"
/**
* Class used to implement DOM text nodes
diff --git a/content/canvas/src/WebGLContext.h b/content/canvas/src/WebGLContext.h
index 652fc89e7630..6ee014477a6e 100644
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -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
, 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 mAttributes;
+ nsTArray 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 CStringHash;
+
class WebGLProgram MOZ_FINAL
: public nsIWebGLProgram
, public WebGLRefCountedObject
@@ -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 mAttribsInUse;
WebGLMonotonicHandle mMonotonicHandle;
+ nsAutoPtr 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
diff --git a/content/canvas/src/WebGLContextGL.cpp b/content/canvas/src/WebGLContextGL.cpp
index d6988a0be192..d76744a99d6c 100644
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -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("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("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("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 name(new char[len + 3]); // +3 because we might have to append "[0]", see below
+ nsAutoArrayPtr 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("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 attribute_name(new char[attrib_max_length+1]);
+ nsAutoArrayPtr uniform_name(new char[uniform_max_length+1]);
+ nsAutoArrayPtr 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);
}
diff --git a/content/canvas/src/WebGLContextValidate.cpp b/content/canvas/src/WebGLContextValidate.cpp
index 8ab4cad07060..9fb37bb08bf6 100644
--- a/content/canvas/src/WebGLContextValidate.cpp
+++ b/content/canvas/src/WebGLContextValidate.cpp
@@ -49,38 +49,46 @@
#include "angle/ShaderLang.h"
#endif
+#include
+
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 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);
diff --git a/content/canvas/test/webgl/failing_tests_linux.txt b/content/canvas/test/webgl/failing_tests_linux.txt
index 5701831fd4c5..dd0dda4b38fe 100644
--- a/content/canvas/test/webgl/failing_tests_linux.txt
+++ b/content/canvas/test/webgl/failing_tests_linux.txt
@@ -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
\ No newline at end of file
diff --git a/content/canvas/test/webgl/failing_tests_mac.txt b/content/canvas/test/webgl/failing_tests_mac.txt
index eaabd7f6f1e8..a67c6b7c2b32 100644
--- a/content/canvas/test/webgl/failing_tests_mac.txt
+++ b/content/canvas/test/webgl/failing_tests_mac.txt
@@ -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
diff --git a/content/canvas/test/webgl/failing_tests_windows.txt b/content/canvas/test/webgl/failing_tests_windows.txt
index 01cf372bf404..78fbcd46f2d0 100644
--- a/content/canvas/test/webgl/failing_tests_windows.txt
+++ b/content/canvas/test/webgl/failing_tests_windows.txt
@@ -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
\ No newline at end of file
+conformance/more/functions/uniformfArrayLen1.html
diff --git a/content/html/content/src/nsGenericHTMLElement.h b/content/html/content/src/nsGenericHTMLElement.h
index bfd7a92fe3b2..6c7bb6d26b1e 100644
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -45,7 +45,6 @@
#include "nsFrameLoader.h"
#include "nsGkAtoms.h"
#include "nsContentCreatorFunctions.h"
-#include "nsDOMMemoryReporter.h"
class nsIDOMAttr;
class nsIDOMEventListener;
diff --git a/content/html/content/src/nsGenericHTMLFrameElement.cpp b/content/html/content/src/nsGenericHTMLFrameElement.cpp
index e9c19f70c384..80855ca4663d 100644
--- a/content/html/content/src/nsGenericHTMLFrameElement.cpp
+++ b/content/html/content/src/nsGenericHTMLFrameElement.cpp
@@ -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"
diff --git a/content/html/content/src/nsHTMLAnchorElement.cpp b/content/html/content/src/nsHTMLAnchorElement.cpp
index 689e73ba3b1c..995fdf960d53 100644
--- a/content/html/content/src/nsHTMLAnchorElement.cpp
+++ b/content/html/content/src/nsHTMLAnchorElement.cpp
@@ -51,7 +51,6 @@
#include "nsIDocument.h"
#include "nsPresContext.h"
#include "nsHTMLDNSPrefetch.h"
-#include "nsDOMMemoryReporter.h"
using namespace mozilla::dom;
diff --git a/content/html/content/src/nsHTMLDivElement.cpp b/content/html/content/src/nsHTMLDivElement.cpp
index a4055abb2baf..4de7233e7803 100644
--- a/content/html/content/src/nsHTMLDivElement.cpp
+++ b/content/html/content/src/nsHTMLDivElement.cpp
@@ -43,7 +43,6 @@
#include "nsGkAtoms.h"
#include "nsStyleConsts.h"
#include "nsMappedAttributes.h"
-#include "nsDOMMemoryReporter.h"
using namespace mozilla;
diff --git a/content/html/content/src/nsHTMLOutputElement.cpp b/content/html/content/src/nsHTMLOutputElement.cpp
index 5dcf0d6d0d29..f000a5a24173 100644
--- a/content/html/content/src/nsHTMLOutputElement.cpp
+++ b/content/html/content/src/nsHTMLOutputElement.cpp
@@ -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,
diff --git a/content/html/content/src/nsHTMLSpanElement.cpp b/content/html/content/src/nsHTMLSpanElement.cpp
index fafd926fcdb9..5c82b2488f57 100644
--- a/content/html/content/src/nsHTMLSpanElement.cpp
+++ b/content/html/content/src/nsHTMLSpanElement.cpp
@@ -41,7 +41,6 @@
#include "nsStyleConsts.h"
#include "nsIAtom.h"
#include "nsRuleData.h"
-#include "nsDOMMemoryReporter.h"
class nsHTMLSpanElement : public nsGenericHTMLElement,
public nsIDOMHTMLElement
diff --git a/content/svg/content/src/nsSVGElement.h b/content/svg/content/src/nsSVGElement.h
index 680cbe711916..afe2583d7468 100644
--- a/content/svg/content/src/nsSVGElement.h
+++ b/content/svg/content/src/nsSVGElement.h
@@ -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"
diff --git a/content/xml/content/src/nsXMLCDATASection.cpp b/content/xml/content/src/nsXMLCDATASection.cpp
index 6938aad767d0..fef8146b38c1 100644
--- a/content/xml/content/src/nsXMLCDATASection.cpp
+++ b/content/xml/content/src/nsXMLCDATASection.cpp
@@ -40,8 +40,6 @@
#include "nsGkAtoms.h"
#include "nsIDocument.h"
#include "nsContentUtils.h"
-#include "nsDOMMemoryReporter.h"
-
class nsXMLCDATASection : public nsGenericDOMDataNode,
public nsIDOMCDATASection
diff --git a/dom/base/Makefile.in b/dom/base/Makefile.in
index 21bab887cf83..6537634d4ded 100644
--- a/dom/base/Makefile.in
+++ b/dom/base/Makefile.in
@@ -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 \
diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp
index 808746e37d68..e61de3c35085 100644
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -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(nativeObj);
-#ifdef DEBUG
- {
- nsCOMPtr 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(GetNative(wrapper, obj));
-#ifdef DEBUG
- {
- nsCOMPtr 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(aNative);
-#ifdef DEBUG
- {
- nsCOMPtr 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(nativeObj);
-#ifdef DEBUG
- {
- nsCOMPtr 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(GetNative(wrapper, obj));
-#ifdef DEBUG
- {
- nsCOMPtr 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(aNative);
-#ifdef DEBUG
- {
- nsCOMPtr 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(aNative);
-#ifdef DEBUG
- {
- nsCOMPtr 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 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*
diff --git a/dom/base/nsDOMClassInfo.h b/dom/base/nsDOMClassInfo.h
index a0e7151ad515..1d8799556eba 100644
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -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
diff --git a/dom/base/nsDOMMemoryReporter.cpp b/dom/base/nsWindowMemoryReporter.cpp
similarity index 62%
rename from dom/base/nsDOMMemoryReporter.cpp
rename to dom/base/nsWindowMemoryReporter.cpp
index 1afd158faf53..8d8bd1bdddfb 100644
--- a/dom/base/nsDOMMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -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//top= (inner=)/inner-window(id=, uri=)
+ // explicit/window-objects//top= (inner=)/inner-window(id=, uri=)
//
// Where:
// - 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//outer-windows
+ // explicit/window-objects//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 > 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 *w = windows.Elements();
nsRefPtr *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;
diff --git a/dom/base/nsDOMMemoryReporter.h b/dom/base/nsWindowMemoryReporter.h
similarity index 85%
rename from dom/base/nsDOMMemoryReporter.h
rename to dom/base/nsWindowMemoryReporter.h
index 8ffed5515c42..bf9497ce5744 100644
--- a/dom/base/nsDOMMemoryReporter.h
+++ b/dom/base/nsWindowMemoryReporter.h
@@ -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__
diff --git a/dom/interfaces/core/nsIDOMDOMTokenList.idl b/dom/interfaces/core/nsIDOMDOMTokenList.idl
index fc926b4b8c13..c2404fca3317 100644
--- a/dom/interfaces/core/nsIDOMDOMTokenList.idl
+++ b/dom/interfaces/core/nsIDOMDOMTokenList.idl
@@ -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();
};
diff --git a/dom/plugins/base/nsJSNPRuntime.cpp b/dom/plugins/base/nsJSNPRuntime.cpp
index 77aa05e68a21..3cf54dfcce18 100644
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -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 {
diff --git a/dom/plugins/base/nsNPAPIPlugin.h b/dom/plugins/base/nsNPAPIPlugin.h
index e9b492a4eb5b..d6a140f1c949 100644
--- a/dom/plugins/base/nsNPAPIPlugin.h
+++ b/dom/plugins/base/nsNPAPIPlugin.h
@@ -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));
}
diff --git a/dom/tests/mochitest/localstorage/test_localStorageBase.html b/dom/tests/mochitest/localstorage/test_localStorageBase.html
index 20cb6daeb51c..4632fe9cc421 100644
--- a/dom/tests/mochitest/localstorage/test_localStorageBase.html
+++ b/dom/tests/mochitest/localstorage/test_localStorageBase.html
@@ -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");
diff --git a/dom/tests/mochitest/localstorage/test_localStorageBasePrivateBrowsing.html b/dom/tests/mochitest/localstorage/test_localStorageBasePrivateBrowsing.html
index bdaacd1a1012..2122b9306b6e 100644
--- a/dom/tests/mochitest/localstorage/test_localStorageBasePrivateBrowsing.html
+++ b/dom/tests/mochitest/localstorage/test_localStorageBasePrivateBrowsing.html
@@ -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");
diff --git a/dom/tests/mochitest/localstorage/test_localStorageBaseSessionOnly.html b/dom/tests/mochitest/localstorage/test_localStorageBaseSessionOnly.html
index 6c505a5c4e23..1fded5cda0e5 100644
--- a/dom/tests/mochitest/localstorage/test_localStorageBaseSessionOnly.html
+++ b/dom/tests/mochitest/localstorage/test_localStorageBaseSessionOnly.html
@@ -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");
diff --git a/dom/tests/mochitest/sessionstorage/test_sessionStorageBase.html b/dom/tests/mochitest/sessionstorage/test_sessionStorageBase.html
index 9e84bed8d65a..abad6d6b2263 100644
--- a/dom/tests/mochitest/sessionstorage/test_sessionStorageBase.html
+++ b/dom/tests/mochitest/sessionstorage/test_sessionStorageBase.html
@@ -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");
diff --git a/editor/composer/src/nsComposeTxtSrvFilter.cpp b/editor/composer/src/nsComposeTxtSrvFilter.cpp
index 4e0e65452622..c9ba9f71ba2e 100644
--- a/editor/composer/src/nsComposeTxtSrvFilter.cpp
+++ b/editor/composer/src/nsComposeTxtSrvFilter.cpp
@@ -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);
diff --git a/editor/composer/src/nsComposeTxtSrvFilter.h b/editor/composer/src/nsComposeTxtSrvFilter.h
index a1af364c5ca8..dbd1b91eacc9 100644
--- a/editor/composer/src/nsComposeTxtSrvFilter.h
+++ b/editor/composer/src/nsComposeTxtSrvFilter.h
@@ -66,8 +66,7 @@ public:
protected:
bool mIsForMail;
nsCOMPtr mBlockQuoteAtom;
- nsCOMPtr mPreAtom; // mail plain text quotes are wrapped in pre tags
- nsCOMPtr mSpanAtom; //or they may be wrapped in span tags (editor.quotesPreformatted).
+ nsCOMPtr mSpanAtom; // mail plain text quotes are wrapped in span tags
nsCOMPtr mMozQuoteAtom; // _moz_quote_
nsCOMPtr mTableAtom;
nsCOMPtr mClassAtom;
diff --git a/editor/libeditor/html/nsHTMLDataTransfer.cpp b/editor/libeditor/html/nsHTMLDataTransfer.cpp
index ca2dbf9807f0..0e1b0696e83b 100644
--- a/editor/libeditor/html/nsHTMLDataTransfer.cpp
+++ b/editor/libeditor/html/nsHTMLDataTransfer.cpp
@@ -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 prefBranch =
- do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
- if (NS_SUCCEEDED(rv) && prefBranch)
- prefBranch->GetBoolPref("editor.quotesPreformatted", "esInPre);
-
nsCOMPtr preNode;
// get selection
nsCOMPtr 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 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 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 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 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)
{
diff --git a/editor/txmgr/src/nsTransactionItem.cpp b/editor/txmgr/src/nsTransactionItem.cpp
index 6b28fb77d4b4..a124be822613 100644
--- a/editor/txmgr/src/nsTransactionItem.cpp
+++ b/editor/txmgr/src/nsTransactionItem.cpp
@@ -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 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 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 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 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 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
diff --git a/editor/txmgr/src/nsTransactionItem.h b/editor/txmgr/src/nsTransactionItem.h
index 3b43413a6551..6098e9d890a7 100644
--- a/editor/txmgr/src/nsTransactionItem.h
+++ b/editor/txmgr/src/nsTransactionItem.h
@@ -43,14 +43,13 @@
#include "nsCycleCollectionParticipant.h"
class nsTransactionStack;
-class nsTransactionRedoStack;
class nsTransactionManager;
class nsTransactionItem
{
nsCOMPtr mTransaction;
nsTransactionStack *mUndoStack;
- nsTransactionRedoStack *mRedoStack;
+ nsTransactionStack *mRedoStack;
nsAutoRefCnt mRefCnt;
public:
diff --git a/editor/txmgr/src/nsTransactionList.cpp b/editor/txmgr/src/nsTransactionList.cpp
index cd803960aff0..72369414f86c 100644
--- a/editor/txmgr/src/nsTransactionList.cpp
+++ b/editor/txmgr/src/nsTransactionList.cpp
@@ -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 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 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 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 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));
diff --git a/editor/txmgr/src/nsTransactionManager.cpp b/editor/txmgr/src/nsTransactionManager.cpp
index 127fb540c0ce..85b43228cfc9 100644
--- a/editor/txmgr/src/nsTransactionManager.cpp
+++ b/editor/txmgr/src/nsTransactionManager.cpp
@@ -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 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 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 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 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 tx;
nsCOMPtr 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 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 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 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 tx;
nsresult result;
NS_ENSURE_TRUE(aTransaction, NS_ERROR_NULL_POINTER);
*aTransaction = 0;
- result = mUndoStack.Peek(getter_AddRefs(tx));
+ nsRefPtr 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 tx;
nsresult result;
NS_ENSURE_TRUE(aTransaction, NS_ERROR_NULL_POINTER);
*aTransaction = 0;
- result = mRedoStack.Peek(getter_AddRefs(tx));
+ nsRefPtr 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 tint;
- nsRefPtr tx;
nsresult result = NS_OK;
- result = mDoStack.Pop(getter_AddRefs(tx));
+ nsRefPtr 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 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 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 overflow;
-
- result = mUndoStack.PopBottom(getter_AddRefs(overflow));
-
- // XXX: What do we do in the case where this fails?
+ nsRefPtr 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;
}
diff --git a/editor/txmgr/src/nsTransactionManager.h b/editor/txmgr/src/nsTransactionManager.h
index 54bbe89ff609..d8fd5f645f69 100644
--- a/editor/txmgr/src/nsTransactionManager.h
+++ b/editor/txmgr/src/nsTransactionManager.h
@@ -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 mListeners;
public:
diff --git a/editor/txmgr/src/nsTransactionStack.cpp b/editor/txmgr/src/nsTransactionStack.cpp
index 6f4e3379b7e9..642c65037977 100644
--- a/editor/txmgr/src/nsTransactionStack.cpp
+++ b/editor/txmgr/src/nsTransactionStack.cpp
@@ -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
+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 (mQue.Pop());
}
-nsresult
-nsTransactionStack::PopBottom(nsTransactionItem **aTransaction)
+already_AddRefed
+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 (mQue.PopFront());
}
-nsresult
-nsTransactionStack::Peek(nsTransactionItem **aTransaction)
+already_AddRefed
+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(mQue.Last()));
}
- NS_IF_ADDREF(*aTransaction = static_cast(mQue.Last()));
-
- return NS_OK;
+ return transaction;
}
-nsresult
-nsTransactionStack::GetItem(PRInt32 aIndex, nsTransactionItem **aTransaction)
+already_AddRefed
+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(mQue.ObjectAt(aIndex)));
+ }
- if (aIndex < 0 || aIndex >= mQue.GetSize())
- return NS_ERROR_FAILURE;
-
- NS_IF_ADDREF(*aTransaction =
- static_cast(mQue.ObjectAt(aIndex)));
-
- return NS_OK;
+ return transaction;
}
-nsresult
-nsTransactionStack::Clear(void)
+void
+nsTransactionStack::Clear()
{
nsRefPtr 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 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;
-}
-
diff --git a/editor/txmgr/src/nsTransactionStack.h b/editor/txmgr/src/nsTransactionStack.h
index 1ce084a10dd5..9070cf7f417a 100644
--- a/editor/txmgr/src/nsTransactionStack.h
+++ b/editor/txmgr/src/nsTransactionStack.h
@@ -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 Pop();
+ already_AddRefed PopBottom();
+ already_AddRefed Peek();
+ already_AddRefed 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__
diff --git a/gfx/2d/UserData.h b/gfx/2d/UserData.h
index fb2e56f98181..72f096e0aec5 100644
--- a/gfx/2d/UserData.h
+++ b/gfx/2d/UserData.h
@@ -35,6 +35,8 @@
*
* ***** END LICENSE BLOCK ***** */
+#ifndef MOZILLA_GFX_USERDATA_H_
+#define MOZILLA_GFX_USERDATA_H_
#include
#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= 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)
diff --git a/gfx/angle/angle-long-identifier-hash-spooky.patch b/gfx/angle/angle-long-identifier-hash-spooky.patch
new file mode 100644
index 000000000000..c55d58129f79
--- /dev/null
+++ b/gfx/angle/angle-long-identifier-hash-spooky.patch
@@ -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
++#include
++#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
++
++#ifdef _MSC_VER
++# define INLINE __forceinline
++ typedef unsigned __int64 uint64;
++ typedef unsigned __int32 uint32;
++ typedef unsigned __int16 uint16;
++ typedef unsigned __int8 uint8;
++#else
++# include
++# 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)
diff --git a/gfx/angle/src/compiler/MapLongVariableNames.cpp b/gfx/angle/src/compiler/MapLongVariableNames.cpp
index 0c7e1a9cb809..3852743fb47f 100644
--- a/gfx/angle/src/compiler/MapLongVariableNames.cpp
+++ b/gfx/angle/src/compiler/MapLongVariableNames.cpp
@@ -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();
}
diff --git a/gfx/angle/src/compiler/preprocessor/length_limits.h b/gfx/angle/src/compiler/preprocessor/length_limits.h
index fdeffe02ea92..4f1f71319fce 100644
--- a/gfx/angle/src/compiler/preprocessor/length_limits.h
+++ b/gfx/angle/src/compiler/preprocessor/length_limits.h
@@ -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)
diff --git a/gfx/angle/src/compiler/spooky.cpp b/gfx/angle/src/compiler/spooky.cpp
new file mode 100644
index 000000000000..f6d78f276f5a
--- /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
+#include
+#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
index 000000000000..cafd52e47d92
--- /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
+
+#ifdef _MSC_VER
+# define INLINE __forceinline
+ typedef unsigned __int64 uint64;
+ typedef unsigned __int32 uint32;
+ typedef unsigned __int16 uint16;
+ typedef unsigned __int8 uint8;
+#else
+# include
+# 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
index b023ce716601..33355da8dd54 100644
--- a/gfx/angle/src/libEGL/Makefile.in
+++ b/gfx/angle/src/libEGL/Makefile.in
@@ -96,6 +96,7 @@ CPPSRCS = \
ValidateLimitations.cpp \
ForLoopUnroll.cpp \
MapLongVariableNames.cpp \
+ spooky.cpp \
BuiltInFunctionEmulator.cpp \
$(NULL)
diff --git a/gfx/angle/src/libGLESv2/Makefile.in b/gfx/angle/src/libGLESv2/Makefile.in
index 3c78abbe667a..8def09b2f5b1 100644
--- a/gfx/angle/src/libGLESv2/Makefile.in
+++ b/gfx/angle/src/libGLESv2/Makefile.in
@@ -96,6 +96,7 @@ CPPSRCS = \
ValidateLimitations.cpp \
ForLoopUnroll.cpp \
MapLongVariableNames.cpp \
+ spooky.cpp \
BuiltInFunctionEmulator.cpp \
$(NULL)
diff --git a/gfx/gl/ForceDiscreteGPUHelperCGL.h b/gfx/gl/ForceDiscreteGPUHelperCGL.h
index 0b58c6cbcd7e..f92fc22299a9 100644
--- a/gfx/gl/ForceDiscreteGPUHelperCGL.h
+++ b/gfx/gl/ForceDiscreteGPUHelperCGL.h
@@ -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):
diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp
index 3eab2cb8c035..68dda711e2a1 100644
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -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);
diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h
index b4dda84795fe..faa12d19e13f 100644
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -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;
diff --git a/gfx/gl/GLContextProviderEGL.cpp b/gfx/gl/GLContextProviderEGL.cpp
index 966295972466..2f7e2c9c6502 100644
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -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
diff --git a/gfx/layers/opengl/ColorLayerOGL.cpp b/gfx/layers/opengl/ColorLayerOGL.cpp
index bf45085c435a..075048adcf30 100644
--- a/gfx/layers/opengl/ColorLayerOGL.cpp
+++ b/gfx/layers/opengl/ColorLayerOGL.cpp
@@ -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);
}
diff --git a/gfx/src/nsRenderingContext.h b/gfx/src/nsRenderingContext.h
index 31d16f4a8087..3296f72e227f 100644
--- a/gfx/src/nsRenderingContext.h
+++ b/gfx/src/nsRenderingContext.h
@@ -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 mFontMetrics;
double mP2A; // cached app units per device pixel value
+
+ UserData mUserData;
};
#endif // NSRENDERINGCONTEXT__H__
diff --git a/image/src/imgLoader.cpp b/image/src/imgLoader.cpp
index 9a3596664df5..36c8e6a19191 100644
--- a/image/src/imgLoader.cpp
+++ b/image/src/imgLoader.cpp
@@ -1718,12 +1718,19 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
// request.
nsCOMPtr 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 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;
}
diff --git a/image/test/crashtests/732319-1.html b/image/test/crashtests/732319-1.html
new file mode 100644
index 000000000000..b9d9c6de87b3
--- /dev/null
+++ b/image/test/crashtests/732319-1.html
@@ -0,0 +1,2 @@
+
+
diff --git a/image/test/crashtests/crashtests.list b/image/test/crashtests/crashtests.list
index f31a2d9e6e1a..a462023fa839 100644
--- a/image/test/crashtests/crashtests.list
+++ b/image/test/crashtests/crashtests.list
@@ -25,3 +25,4 @@ HTTP load delayedframe.sjs
load 681190.html
load 694165-1.xhtml
+load 732319-1.html
diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp
index 5fe284919b64..ee2f85ed7750 100644
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -1141,7 +1141,7 @@ static JS_ALWAYS_INLINE bool IsNegative(Type i)
return IsNegativeImpl::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
@@ -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
@@ -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
@@ -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(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
@@ -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(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))
diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp
index 118ddfaaf4ee..1569daa043c0 100644
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -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
diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h
index d581e357a8a0..c3c1710c2df4 100644
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -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.
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index 1d99f4d62d03..81a6de860cf4 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -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);
diff --git a/js/src/jit-test/tests/basic/bug731724.js b/js/src/jit-test/tests/basic/bug731724.js
new file mode 100644
index 000000000000..120c69934019
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug731724.js
@@ -0,0 +1,5 @@
+function g(s) {
+ return eval(s)
+}
+f = g("(function(){({x:function::arguments})})")
+f()
diff --git a/js/src/jit-test/tests/basic/bug731745.js b/js/src/jit-test/tests/basic/bug731745.js
new file mode 100644
index 000000000000..47fd470505f5
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug731745.js
@@ -0,0 +1,5 @@
+function h(s) {
+ return eval(s)
+}
+f = h("(function(){function::arguments=[]})")
+for (a in f()) {}
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-01.js b/js/src/jit-test/tests/debug/Frame-onPop-01.js
new file mode 100644
index 000000000000..f85c6498ddae
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-01.js
@@ -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)");
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-02.js b/js/src/jit-test/tests/debug/Frame-onPop-02.js
new file mode 100644
index 000000000000..8d39f02f8d99
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-02.js
@@ -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");
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-03.js b/js/src/jit-test/tests/debug/Frame-onPop-03.js
new file mode 100644
index 000000000000..fc5bea972c27
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-03.js
@@ -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");
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-04.js b/js/src/jit-test/tests/debug/Frame-onPop-04.js
new file mode 100644
index 000000000000..884d78dcff6b
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-04.js
@@ -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)");
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-05.js b/js/src/jit-test/tests/debug/Frame-onPop-05.js
new file mode 100644
index 000000000000..8336713ebb57
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-05.js
@@ -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');
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-06.js b/js/src/jit-test/tests/debug/Frame-onPop-06.js
new file mode 100644
index 000000000000..10bef72c6bde
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-06.js
@@ -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");
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-07.js b/js/src/jit-test/tests/debug/Frame-onPop-07.js
new file mode 100644
index 000000000000..93b869d24a7f
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-07.js
@@ -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);
+}
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-08.js b/js/src/jit-test/tests/debug/Frame-onPop-08.js
new file mode 100644
index 000000000000..e11b48247b28
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-08.js
@@ -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)');
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-09.js b/js/src/jit-test/tests/debug/Frame-onPop-09.js
new file mode 100644
index 000000000000..902a295d2b8c
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-09.js
@@ -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');
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-10.js b/js/src/jit-test/tests/debug/Frame-onPop-10.js
new file mode 100644
index 000000000000..8a245a0623f2
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-10.js
@@ -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);
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-11.js b/js/src/jit-test/tests/debug/Frame-onPop-11.js
new file mode 100644
index 000000000000..0d2eeed88630
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-11.js
@@ -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)");
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-12.js b/js/src/jit-test/tests/debug/Frame-onPop-12.js
new file mode 100644
index 000000000000..976a3d75b890
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-12.js
@@ -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)');
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-13.js b/js/src/jit-test/tests/debug/Frame-onPop-13.js
new file mode 100644
index 000000000000..887ddb09d85d
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-13.js
@@ -0,0 +1,37 @@
+// One can set onPop handlers on some frames but not others.
+var g = newGlobal('new-compartment');
+g.eval("function f(n) { if (n > 0) f(n-1); else debugger; }");
+var dbg = new Debugger(g);
+var log;
+
+Debugger.Frame.prototype.nthOlder = function nthOlder(n) {
+ var f = this;
+ while (n-- > 0)
+ f = f.older;
+ return f;
+};
+
+dbg.onEnterFrame = function handleEnter(f) {
+ log += "(" + f.arguments[0];
+};
+
+function makePopHandler(n) {
+ return function handlePop(c) {
+ log += ")" + this.arguments[0];
+ assertEq(this.arguments[0], n);
+ };
+}
+
+dbg.onDebuggerStatement = function handleDebugger(f) {
+ // Set onPop handers on some frames, and leave others alone. Vary the
+ // spacing.
+ f.nthOlder(2).onPop = makePopHandler(2);
+ f.nthOlder(3).onPop = makePopHandler(3);
+ f.nthOlder(5).onPop = makePopHandler(5);
+ f.nthOlder(8).onPop = makePopHandler(8);
+ f.nthOlder(13).onPop = makePopHandler(13);
+};
+
+log = '';
+g.f(20);
+assertEq(log, "(20(19(18(17(16(15(14(13(12(11(10(9(8(7(6(5(4(3(2(1(0)2)3)5)8)13");
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-14.js b/js/src/jit-test/tests/debug/Frame-onPop-14.js
new file mode 100644
index 000000000000..8aa1bcec34e7
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-14.js
@@ -0,0 +1,25 @@
+// A frame's onPop handler is called only once, even if it is for a function
+// called from a loop.
+var g = newGlobal('new-compartment');
+var dbg = new Debugger(g);
+var log;
+
+var count;
+dbg.onDebuggerStatement = function handleDebug(frame) {
+ log += 'd';
+ assertEq(frame.type, "call");
+ count++;
+ if (count == 10) {
+ frame.onPop = function handlePop(c) {
+ log += ')' + this.arguments[0];
+ assertEq(c.return, "snifter");
+ };
+ }
+};
+
+g.eval("function f(n) { debugger; return 'snifter'; }");
+log = '';
+count = 0;
+g.eval("for (i = 0; i < 20; i++) f(i);");
+assertEq(count, 20);
+assertEq(log, "dddddddddd)9dddddddddd");
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-15.js b/js/src/jit-test/tests/debug/Frame-onPop-15.js
new file mode 100644
index 000000000000..ea791b8e2689
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-15.js
@@ -0,0 +1,32 @@
+// Each resumption of a generator gets a fresh frame, whose onPop handler
+// fires the next time the generator yields.
+// This is not the behavior the spec requests, but it's what we do for the
+// moment, and it's good to check that at least we don't crash.
+var g = newGlobal('new-compartment');
+var dbg = new Debugger(g);
+var log;
+
+var debuggerFrames = [];
+var poppedFrames = [];
+dbg.onDebuggerStatement = function handleDebugger(frame) {
+ log += 'd';
+ assertEq(frame.type, "call");
+
+ assertEq(debuggerFrames.indexOf(frame), -1);
+ assertEq(poppedFrames.indexOf(frame), -1);
+ debuggerFrames.push(frame);
+
+ if (frame.eval('i').return % 3 == 0) {
+ frame.onPop = function handlePop(c) {
+ log += ')' + c.return;
+ assertEq(debuggerFrames.indexOf(this) != -1, true);
+ assertEq(poppedFrames.indexOf(this), -1);
+ poppedFrames.push(this);
+ };
+ }
+};
+
+g.eval("function g() { for (var i = 0; i < 10; i++) { debugger; yield i; } }");
+log ='';
+assertEq(g.eval("var t = 0; for (j in g()) t += j; t;"), 45);
+assertEq(log, "d)0ddd)3ddd)6ddd)9");
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-16.js b/js/src/jit-test/tests/debug/Frame-onPop-16.js
new file mode 100644
index 000000000000..fca8d4a1acf9
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-16.js
@@ -0,0 +1,18 @@
+// onPop handlers fire even on frames that make tail calls.
+var g = newGlobal('new-compartment');
+var dbg = new Debugger(g);
+var log;
+
+g.eval('function f(n) { if (n > 0) f(n-1); else debugger; }');
+
+dbg.onEnterFrame = function handleEnter(frame) {
+ log += '(';
+ frame.onPop = function handlePop(c) {
+ log += ')';
+ assertEq(typeof c == "object" && 'return' in c, true);
+ };
+};
+
+log = '';
+g.f(10);
+assertEq(log, "((((((((((()))))))))))");
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-17.js b/js/src/jit-test/tests/debug/Frame-onPop-17.js
new file mode 100644
index 000000000000..ab3710779213
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-17.js
@@ -0,0 +1,40 @@
+// onPop surfaces.
+load(libdir + "asserts.js");
+
+var g = newGlobal('new-compartment');
+var dbg = new Debugger(g);
+
+// Assigning a bogus value to Debugger.Frame.prototype.onPop raises a TypeError.
+function test(badValue) {
+ print("store " + uneval(badValue) + " in Debugger.Frame.prototype.onPop");
+
+ var log;
+ dbg.onDebuggerStatement = function handleDebugger(frame) {
+ log += "d";
+ assertThrowsInstanceOf(function () { frame.onPop = badValue; }, TypeError);
+ };
+
+ log = "";
+ g.eval("debugger");
+ assertEq(log, "d");
+}
+
+test(null);
+test(false);
+test(1);
+test("stringy");
+test({});
+test([]);
+
+// Getting and setting the prototype's onPop is an error.
+assertThrowsInstanceOf(function () { Debugger.Frame.prototype.onPop; }, TypeError);
+assertThrowsInstanceOf(
+ function () { Debugger.Frame.prototype.onPop = function () {}; },
+ TypeError);
+
+// The getters and setters correctly check the type of their 'this' argument.
+var descriptor = Object.getOwnPropertyDescriptor(Debugger.Frame.prototype, 'onPop');
+assertEq(descriptor.configurable, true);
+assertEq(descriptor.enumerable, false);
+assertThrowsInstanceOf(function () { descriptor.get.call({}); }, TypeError);
+assertThrowsInstanceOf(function () { descriptor.set.call({}, function() {}); }, TypeError);
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-18.js b/js/src/jit-test/tests/debug/Frame-onPop-18.js
new file mode 100644
index 000000000000..fb32ec6101a3
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-18.js
@@ -0,0 +1,22 @@
+// A garbage collection in the debugger compartment does not disturb onPop
+// handlers.
+var g = newGlobal('new-compartment');
+var dbg = new Debugger(g);
+var log;
+
+dbg.onEnterFrame = function handleEnter(frame) {
+ log += '(';
+ frame.onPop = function handlePop(completion) {
+ log += ')';
+ };
+};
+
+dbg.onDebuggerStatement = function handleDebugger (frame) {
+ log += 'd';
+ // GC in the debugger's compartment only.
+ gc(dbg);
+};
+
+log = '';
+assertEq(g.eval('debugger; 42;'), 42);
+assertEq(log, '(d)');
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-19.js b/js/src/jit-test/tests/debug/Frame-onPop-19.js
new file mode 100644
index 000000000000..879678326797
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-19.js
@@ -0,0 +1,16 @@
+// A garbage collection in the debuggee compartment does not disturb onPop
+// handlers.
+var g = newGlobal('new-compartment');
+var dbg = new Debugger(g);
+var log;
+
+dbg.onEnterFrame = function handleEnter(frame) {
+ log += '(';
+ frame.onPop = function handlePop(completion) {
+ log += ')';
+ };
+};
+
+log = '';
+assertEq(g.eval('gc(this); 42;'), 42);
+assertEq(log, '()');
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-20.js b/js/src/jit-test/tests/debug/Frame-onPop-20.js
new file mode 100644
index 000000000000..a3b03c9452d1
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-20.js
@@ -0,0 +1,15 @@
+// A global garbage collection does not disturb onPop handlers.
+var g = newGlobal('new-compartment');
+var dbg = new Debugger(g);
+var log;
+
+dbg.onEnterFrame = function handleEnter(frame) {
+ log += '(';
+ frame.onPop = function handlePop(completion) {
+ log += ')';
+ };
+};
+
+log = '';
+assertEq(g.eval('gc(); 42;'), 42);
+assertEq(log, '()');
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-21.js b/js/src/jit-test/tests/debug/Frame-onPop-21.js
new file mode 100644
index 000000000000..a8a9d8f8d4ce
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-21.js
@@ -0,0 +1,30 @@
+// frame.eval works from an onPop handler.
+var g = newGlobal('new-compartment');
+g.eval('function f(a,b) { var x = "entablature", y; debugger; return x+y+a+b; }');
+
+var dbg = new Debugger(g);
+var log;
+
+dbg.onDebuggerStatement = function handleDebugger(frame) {
+ log += 'd';
+ frame.onPop = handlePop;
+};
+
+function handlePop(c) {
+ log += ')';
+
+ // Arguments must be live.
+ assertEq(this.eval('a').return, 'frieze');
+ assertEq(this.eval('b = "architrave"').return, 'architrave');
+ assertEq(this.eval('arguments[1]').return, 'architrave');
+ assertEq(this.eval('b').return, 'architrave');
+
+ // function-scope variables must be live.
+ assertEq(this.eval('x').return, 'entablature');
+ assertEq(this.eval('y = "cornice"').return, 'cornice');
+ assertEq(this.eval('y').return, 'cornice');
+}
+
+log = '';
+g.eval('f("frieze", "stylobate")');
+assertEq(log, 'd)');
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-disabled.js b/js/src/jit-test/tests/debug/Frame-onPop-disabled.js
new file mode 100644
index 000000000000..1a3181038329
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-disabled.js
@@ -0,0 +1,44 @@
+// An onPop handler in a disabled Debugger's frame shouldn't fire.
+
+var g = newGlobal('new-compartment');
+var dbg = new Debugger(g);
+g.eval('function f() { debugger; }');
+var log;
+dbg.onEnterFrame = function handleEnterFrame(f) {
+ log += '(';
+ assertEq(f.callee.name, 'f');
+ f.onPop = function handlePop(c) {
+ log += ')';
+ assertEq(dbg.enabled, true);
+ };
+};
+
+var enable;
+dbg.onDebuggerStatement = function handleDebugger(f) {
+ dbg.enabled = enable;
+}
+
+
+// This should fire the onEnterFrame and onPop handlers.
+log = 'a';
+enable = true;
+g.f();
+
+// This should fire the onEnterFrame handler, but not the onPop.
+log += 'b';
+enable = false;
+g.f();
+
+// This should fire neither.
+log += 'c';
+dbg.enabled = false;
+enable = false;
+g.f();
+
+// This should fire both again.
+log += 'd';
+dbg.enabled = true;
+enable = true;
+g.f();
+
+assertEq(log, 'a()b(cd()');
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-error-error.js b/js/src/jit-test/tests/debug/Frame-onPop-error-error.js
new file mode 100644
index 000000000000..db99069b375e
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-error-error.js
@@ -0,0 +1,60 @@
+// |jit-test| error: TestComplete
+// onPop can request a termination when stopped for a termination
+
+var g = newGlobal('new-compartment');
+var dbg = new Debugger(g);
+
+// We use Debugger.Frame.prototype.eval and ignore the outer 'eval' frame so we
+// can catch the termination.
+
+function test(type, provocation) {
+ // Help people figure out which 'test' call failed.
+ print("type: " + uneval(type));
+ print("provocation: " + uneval(provocation));
+
+ var log;
+ dbg.onEnterFrame = function handleFirstFrame(f) {
+ log += 'f';
+ dbg.onDebuggerStatement = function handleDebugger(f) {
+ log += 'd';
+ return null;
+ };
+
+ dbg.onEnterFrame = function handleSecondFrame(f) {
+ log += 'e';
+ assertEq(f.type, 'eval');
+
+ dbg.onEnterFrame = function handleThirdFrame(f) {
+ log += '(';
+ assertEq(f.type, type);
+
+ dbg.onEnterFrame = function handleExtraFrames(f) {
+ // This should never be called.
+ assertEq(false, true);
+ };
+
+ f.onPop = function handlePop(c) {
+ log += ')';
+ assertEq(c, null);
+ return null;
+ };
+ };
+ };
+
+ assertEq(f.eval(provocation), null);
+ };
+
+ log = '';
+ // This causes handleFirstFrame to be called.
+ assertEq(typeof g.eval('eval'), 'function');
+ assertEq(log, 'fe(d)');
+
+ print();
+}
+
+g.eval('function f() { debugger; return \'termination fail\'; }');
+test('call', 'f();');
+test('call', 'new f;');
+test('eval', 'eval(\'debugger; \\\'termination fail\\\';\');');
+test('global', 'evaluate(\'debugger; \\\'termination fail\\\';\');');
+throw 'TestComplete';
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-error-return.js b/js/src/jit-test/tests/debug/Frame-onPop-error-return.js
new file mode 100644
index 000000000000..ad08fd7f5735
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-error-return.js
@@ -0,0 +1,47 @@
+// |jit-test| error: TestComplete
+// onPop can change a termination into a normal return.
+
+var g = newGlobal('new-compartment');
+var dbg = new Debugger(g);
+
+function test(type, provocation) {
+ var log;
+ var wasConstructing;
+
+ // Help people figure out which 'test' call failed.
+ print("type: " + uneval(type));
+ print("provocation: " + uneval(provocation));
+
+ dbg.onDebuggerStatement = function handleDebuggerStatement(f) {
+ log += 'd';
+ return null;
+ };
+
+ dbg.onEnterFrame = function handleEnterFrame(f) {
+ log += '(';
+ assertEq(f.type, type);
+ wasConstructing = f.constructing;
+ f.onPop = function handlePop(c) {
+ log += ')';
+ assertEq(c, null);
+ return { return: 'favor' };
+ };
+ };
+
+ log = '';
+ var result = provocation();
+ if (wasConstructing)
+ assertEq(typeof result, "object");
+ else
+ assertEq(result, 'favor');
+ assertEq(log, "(d)");
+
+ print();
+}
+
+g.eval("function f() { debugger; return 'termination fail'; }");
+test("call", g.f);
+test("call", function () { return new g.f; });
+test("eval", function () { return g.eval("debugger; \'termination fail\';"); });
+test("global", function () { return g.evaluate("debugger; \'termination fail\';"); });
+throw 'TestComplete';
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-error-throw.js b/js/src/jit-test/tests/debug/Frame-onPop-error-throw.js
new file mode 100644
index 000000000000..568eded74864
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-error-throw.js
@@ -0,0 +1,42 @@
+// |jit-test| error: TestComplete
+// onPop can change a termination into a throw.
+
+load(libdir + "asserts.js");
+var g = newGlobal('new-compartment');
+var dbg = new Debugger(g);
+
+function test(type, provocation) {
+ var log;
+
+ // Help people figure out which 'test' call failed.
+ print("type: " + uneval(type));
+ print("provocation: " + uneval(provocation));
+
+ dbg.onDebuggerStatement = function handleDebuggerStatement(f) {
+ log += 'd';
+ return null;
+ };
+
+ dbg.onEnterFrame = function handleEnterFrame(f) {
+ log += '(';
+ assertEq(f.type, type);
+ f.onPop = function handlePop(c) {
+ log += ')';
+ assertEq(c, null);
+ return { throw: 'snow' };
+ };
+ };
+
+ log = '';
+ assertThrowsValue(provocation, 'snow');
+ assertEq(log, "(d)");
+
+ print();
+}
+
+g.eval("function f() { debugger; return 'termination fail'; }");
+test("call", g.f);
+test("call", function () { return new g.f; });
+test("eval", function () { return g.eval("debugger; \'termination fail\';"); });
+test("global", function () { return g.evaluate("debugger; \'termination fail\';"); });
+throw 'TestComplete';
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-error.js b/js/src/jit-test/tests/debug/Frame-onPop-error.js
new file mode 100644
index 000000000000..759543a33e8b
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-error.js
@@ -0,0 +1,59 @@
+// |jit-test| error: TestComplete
+// onPop fires when frames are terminated.
+
+var g = newGlobal('new-compartment');
+var dbg = new Debugger(g);
+
+// We use Debugger.Frame.prototype.eval and ignore the outer 'eval' frame so we
+// can catch the termination.
+
+function test(type, provocation) {
+ // Help people figure out which 'test' call failed.
+ print("type: " + uneval(type));
+ print("provocation: " + uneval(provocation));
+
+ var log;
+ dbg.onEnterFrame = function handleFirstFrame(f) {
+ log += 'f';
+ dbg.onDebuggerStatement = function handleDebugger(f) {
+ log += 'd';
+ return null;
+ };
+
+ dbg.onEnterFrame = function handleSecondFrame(f) {
+ log += 'e';
+ assertEq(f.type, 'eval');
+
+ dbg.onEnterFrame = function handleThirdFrame(f) {
+ log += '(';
+ assertEq(f.type, type);
+
+ dbg.onEnterFrame = function handleExtraFrames(f) {
+ // This should never be called.
+ assertEq(false, true);
+ };
+
+ f.onPop = function handlePop(c) {
+ log += ')';
+ assertEq(c, null);
+ };
+ };
+ };
+
+ assertEq(f.eval(provocation), null);
+ };
+
+ log = '';
+ // This causes handleFirstFrame to be called.
+ assertEq(typeof g.eval('eval'), 'function');
+ assertEq(log, 'fe(d)');
+
+ print();
+}
+
+g.eval('function f() { debugger; return \'termination fail\'; }');
+test('call', 'f();');
+test('call', 'new f;');
+test('eval', 'eval(\'debugger; \\\'termination fail\\\';\');');
+test('global', 'evaluate(\'debugger; \\\'termination fail\\\';\');');
+throw 'TestComplete';
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-multiple-01.js b/js/src/jit-test/tests/debug/Frame-onPop-multiple-01.js
new file mode 100644
index 000000000000..498af587dfe6
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-multiple-01.js
@@ -0,0 +1,127 @@
+// Multiple debuggers all get their onPop handlers called, and see each others' effects.
+
+function completionsEqual(c1, c2) {
+ if (c1 && c2) {
+ if (c1.throw)
+ return c1.throw === c2.throw;
+ else
+ return c1.return === c2.return;
+ }
+ return c1 === c2;
+}
+
+function completionString(c) {
+ if (c == null)
+ return 'x';
+ if (c.return)
+ return 'r' + c.return;
+ if (c.throw)
+ return 't' + c.throw;
+ return '?';
+}
+
+var g = newGlobal('new-compartment'); // poor thing
+g.eval('function f() { debugger; return "1"; }');
+
+// We create a bunch of debuggers, but they all consult this global variable
+// for expectations and responses, so the order in which events get
+// reported to the debuggers doesn't matter.
+//
+// This list includes every pair of transitions, and is of minimal length.
+// As if opportunity cost were just some theoretical concern.
+var sequence = [{ expect: { return: '1' }, resume: { return: '2'} },
+ { expect: { return: '2' }, resume: { throw: '3'} },
+ { expect: { throw: '3' }, resume: { return: '4'} },
+ { expect: { return: '4' }, resume: null },
+ { expect: null, resume: { throw: '5'} },
+ { expect: { throw: '5' }, resume: { throw: '6'} },
+ { expect: { throw: '6' }, resume: null },
+ { expect: null, resume: null },
+ { expect: null, resume: { return: '7'} }];
+
+// A list of the debuggers' Debugger.Frame instances. When it's all over,
+// we test that they are all marked as no longer live.
+var frames = [];
+
+// We start off the test via Debugger.Frame.prototype.eval, so if we end
+// with a termination, we still catch it, instead of aborting the whole
+// test. (Debugger.Object.prototype.evalInGlobal would simplify this...)
+var dbg0 = new Debugger(g);
+dbg0.onEnterFrame = function handleOriginalEnter(frame) {
+ dbg0.log += '(';
+ dbg0.onEnterFrame = undefined;
+
+ assertEq(frame.live, true);
+ frames.push(frame);
+
+ var dbgs = [];
+ var log;
+
+ // Create a separate debugger to carry out each item in sequence.
+ for (s in sequence) {
+ // Each debugger's handlers close over a distinct 'dbg', but
+ // that's the only distinction between them. Otherwise, they're
+ // driven entirely by global data, so the order in which events are
+ // dispatched to them shouldn't matter.
+ let dbg = new Debugger(g);
+ dbgs.push(dbg);
+
+ dbg.onDebuggerStatement = function handleDebuggerStatement(f) {
+ log += 'd';
+ assertEq(f.live, true);
+ frames.push(f);
+ };
+
+ // First expect the 'eval'...
+ dbg.onEnterFrame = function handleEnterEval(f) {
+ log += 'e';
+ assertEq(f.type, 'eval');
+ assertEq(f.live, true);
+ frames.push(f);
+
+ // Then expect the call.
+ dbg.onEnterFrame = function handleEnterCall(f) {
+ log += '(';
+ assertEq(f.type, 'call');
+ assertEq(f.live, true);
+ frames.push(f);
+
+ // Don't expect any further frames.
+ dbg.onEnterFrame = function handleExtraEnter(f) {
+ log += 'z';
+ };
+
+ f.onPop = function handlePop(c) {
+ log += ')' + completionString(c);
+ assertEq(this.live, true);
+ frames.push(this);
+
+ // Check that this debugger is in the list, and then remove it.
+ var i = dbgs.indexOf(dbg);
+ assertEq(i != -1, true);
+ dbgs.splice(i,1);
+
+ // Check the frame's completion value against 'sequence'.
+ assertEq(completionsEqual(c, sequence[0].expect), true);
+
+ // Provide the next resumption value from 'sequence'.
+ return sequence.shift().resume;
+ };
+ };
+ };
+ }
+
+ log = '';
+ assertEq(completionsEqual(frame.eval('f()'), { return: '7' }), true);
+ assertEq(log, "eeeeeeeee(((((((((ddddddddd)r1)r2)t3)r4)x)t5)t6)x)x");
+
+ dbg0.log += '.';
+};
+
+dbg0.log = '';
+g.eval('eval');
+assertEq(dbg0.log, '(.');
+
+// Check that all Debugger.Frame instances we ran into are now marked as dead.
+for (var i = 0; i < frames.length; i++)
+ assertEq(frames[i].live, false);
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-multiple-02.js b/js/src/jit-test/tests/debug/Frame-onPop-multiple-02.js
new file mode 100644
index 000000000000..17dd071d49f6
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-multiple-02.js
@@ -0,0 +1,36 @@
+// One Debugger's onPop handler can remove another Debugger's onPop handler.
+var g = newGlobal('new-compartment');
+var dbg1 = new Debugger(g);
+var dbg2 = new Debugger(g);
+
+var log;
+var frames = [];
+var firstPop = true;
+
+function handleEnter(frame) {
+ log += '(';
+ frames.push(frame);
+ frame.onPop = function handlePop(completion) {
+ log += ')';
+ assertEq(completion.return, 42);
+ if (firstPop) {
+ // We can't say which frame's onPop handler will get called first.
+ if (this == frames[0])
+ frames[1].onPop = undefined;
+ else
+ frames[0].onPop = undefined;
+ gc();
+ } else {
+ assertEq("second pop handler was called",
+ "second pop handler should not be called");
+ }
+ firstPop = false;
+ };
+};
+
+dbg1.onEnterFrame = handleEnter;
+dbg2.onEnterFrame = handleEnter;
+
+log = '';
+assertEq(g.eval('40 + 2'), 42);
+assertEq(log, '(()');
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-multiple-03.js b/js/src/jit-test/tests/debug/Frame-onPop-multiple-03.js
new file mode 100644
index 000000000000..1d7f4fee2a76
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-multiple-03.js
@@ -0,0 +1,36 @@
+// One Debugger's onPop handler can disable another Debugger.
+var g = newGlobal('new-compartment');
+var dbg1 = new Debugger(g);
+var dbg2 = new Debugger(g);
+
+var log;
+var frames = [];
+var firstPop = true;
+
+function handleEnter(frame) {
+ log += '(';
+ frames.push(frame);
+ frame.debugger = this;
+ frame.onPop = function handlePop(completion) {
+ log += ')';
+ assertEq(completion.return, 42);
+ if (firstPop) {
+ // We can't say which frame's onPop handler will get called first.
+ if (this == frames[0])
+ frames[1].debugger.enabled = false;
+ else
+ frames[0].debugger.enabled = false;
+ } else {
+ assertEq("second pop handler was called",
+ "second pop handler should not be called");
+ }
+ firstPop = false;
+ };
+};
+
+dbg1.onEnterFrame = handleEnter;
+dbg2.onEnterFrame = handleEnter;
+
+log = '';
+assertEq(g.eval('40 + 2'), 42);
+assertEq(log, '(()');
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-multiple-04.js b/js/src/jit-test/tests/debug/Frame-onPop-multiple-04.js
new file mode 100644
index 000000000000..342e465a2255
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-multiple-04.js
@@ -0,0 +1,27 @@
+// If one Debugger's onPop handler causes another Debugger to create a
+// Debugger.Frame instance referring to the same frame, that frame still
+// gets marked as not live after all the onPop handlers have run.
+var g = newGlobal('new-compartment');
+var dbg1 = new Debugger(g);
+var dbg2 = new Debugger(g);
+
+var log;
+var frame2;
+
+dbg1.onEnterFrame = function handleEnter(frame) {
+ log += '(';
+ frame.onPop = function handlerPop1(c) {
+ log += ')';
+ frame2 = dbg2.getNewestFrame();
+ assertEq(frame2.live, true);
+ frame2.onPop = function handlePop2(c) {
+ assertEq("late frame's onPop handler ran",
+ "late frame's onPop handler should not run");
+ };
+ };
+};
+
+log = '';
+assertEq(g.eval('40 + 2'), 42);
+assertEq(log, '()');
+assertEq(frame2.live, false);
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-return-error.js b/js/src/jit-test/tests/debug/Frame-onPop-return-error.js
new file mode 100644
index 000000000000..4b93c0868a48
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-return-error.js
@@ -0,0 +1,59 @@
+// |jit-test| error: TestComplete
+// onPop can change a normal return into a termination.
+
+var g = newGlobal('new-compartment');
+var dbg = new Debugger(g);
+
+// We use Debugger.Frame.prototype.eval and ignore the outer 'eval' frame so we
+// can catch the termination.
+
+function test(type, provocation) {
+ // Help people figure out which 'test' call failed.
+ print("type: " + uneval(type));
+ print("provocation: " + uneval(provocation));
+
+ var log;
+ dbg.onEnterFrame = function handleFirstFrame(f) {
+ log += 'f';
+ dbg.onDebuggerStatement = function handleDebugger(f) {
+ log += 'd';
+ };
+
+ dbg.onEnterFrame = function handleSecondFrame(f) {
+ log += 'e';
+ assertEq(f.type, 'eval');
+
+ dbg.onEnterFrame = function handleThirdFrame(f) {
+ log += '(';
+ assertEq(f.type, type);
+
+ dbg.onEnterFrame = function handleExtraFrames(f) {
+ // This should never be called.
+ assertEq(false, true);
+ };
+
+ f.onPop = function handlePop(c) {
+ log += ')';
+ assertEq(c.return, 'compliment');
+ return null;
+ };
+ };
+ };
+
+ assertEq(f.eval(provocation), null);
+ };
+
+ log = '';
+ // This causes handleFirstFrame to be called.
+ assertEq(typeof g.eval('eval'), 'function');
+ assertEq(log, 'fe(d)');
+
+ print();
+}
+
+g.eval('function f() { debugger; return \'compliment\'; }');
+test('call', 'f();');
+test('call', 'new f;');
+test('eval', 'eval(\'debugger; \\\'compliment\\\';\');');
+test('global', 'evaluate(\'debugger; \\\'compliment\\\';\');');
+throw 'TestComplete';
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-return-return.js b/js/src/jit-test/tests/debug/Frame-onPop-return-return.js
new file mode 100644
index 000000000000..d1fbfe88e7ef
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-return-return.js
@@ -0,0 +1,46 @@
+// |jit-test| error: TestComplete
+// onPop can change a normal return into a normal return of a different value.
+
+var g = newGlobal('new-compartment');
+var dbg = new Debugger(g);
+
+function test(type, provocation) {
+ var log;
+ var wasConstructing;
+
+ // Help people figure out which 'test' call failed.
+ print("type: " + uneval(type));
+ print("provocation: " + uneval(provocation));
+
+ dbg.onDebuggerStatement = function handleDebuggerStatement(f) {
+ log += 'd';
+ };
+
+ dbg.onEnterFrame = function handleEnterFrame(f) {
+ log += '(';
+ assertEq(f.type, type);
+ wasConstructing = f.constructing;
+ f.onPop = function handlePop(c) {
+ log += ')';
+ assertEq(c.return, 'compliment');
+ return { return: 'favor' };
+ };
+ };
+
+ log = '';
+ var result = provocation();
+ if (wasConstructing)
+ assertEq(typeof result, "object");
+ else
+ assertEq(result, 'favor');
+ assertEq(log, "(d)");
+
+ print();
+}
+
+g.eval("function f() { debugger; return 'compliment'; }");
+test("call", g.f);
+test("call", function () { return new g.f; });
+test("eval", function () { return g.eval("debugger; \'compliment\';"); });
+test("global", function () { return g.evaluate("debugger; \'compliment\';"); });
+throw 'TestComplete';
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-return-throw.js b/js/src/jit-test/tests/debug/Frame-onPop-return-throw.js
new file mode 100644
index 000000000000..57fbc945fd52
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-return-throw.js
@@ -0,0 +1,41 @@
+// |jit-test| error: TestComplete
+// onPop can change a normal return into a throw.
+
+load(libdir + "asserts.js");
+var g = newGlobal('new-compartment');
+var dbg = new Debugger(g);
+
+function test(type, provocation) {
+ var log;
+
+ // Help people figure out which 'test' call failed.
+ print("type: " + uneval(type));
+ print("provocation: " + uneval(provocation));
+
+ dbg.onDebuggerStatement = function handleDebuggerStatement(f) {
+ log += 'd';
+ };
+
+ dbg.onEnterFrame = function handleEnterFrame(f) {
+ log += '(';
+ assertEq(f.type, type);
+ f.onPop = function handlePop(c) {
+ log += ')';
+ assertEq(c.return, 'compliment');
+ return { throw: 'snow' };
+ };
+ };
+
+ log = '';
+ assertThrowsValue(provocation, 'snow');
+ assertEq(log, "(d)");
+
+ print();
+}
+
+g.eval("function f() { debugger; return 'compliment'; }");
+test("call", g.f);
+test("call", function () { return new g.f; });
+test("eval", function () { return g.eval("debugger; \'compliment\';"); });
+test("global", function () { return g.evaluate("debugger; \'compliment\';"); });
+throw 'TestComplete';
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-return.js b/js/src/jit-test/tests/debug/Frame-onPop-return.js
new file mode 100644
index 000000000000..d46c1a5f51a3
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-return.js
@@ -0,0 +1,45 @@
+// |jit-test| error: TestComplete
+// onPop fires when frames return normally.
+
+var g = newGlobal('new-compartment');
+var dbg = new Debugger(g);
+
+function test(type, provocation) {
+ var log;
+ var wasConstructing;
+
+ // Help people figure out which 'test' call failed.
+ print("type: " + uneval(type));
+ print("provocation: " + uneval(provocation));
+
+ dbg.onDebuggerStatement = function handleDebuggerStatement(f) {
+ log += 'd';
+ };
+
+ dbg.onEnterFrame = function handleEnterFrame(f) {
+ log += '(';
+ assertEq(f.type, type);
+ wasConstructing = f.constructing;
+ f.onPop = function handlePop(c) {
+ log += ')';
+ assertEq(c.return, 'compliment');
+ };
+ };
+
+ log = '';
+ var result = provocation();
+ if (wasConstructing)
+ assertEq(typeof result, "object");
+ else
+ assertEq(result, 'compliment');
+ assertEq(log, "(d)");
+
+ print();
+}
+
+g.eval("function f() { debugger; return 'compliment'; }");
+test("call", g.f);
+test("call", function () { return new g.f; });
+test("eval", function () { return g.eval("debugger; \'compliment\';"); });
+test("global", function () { return g.evaluate("debugger; \'compliment\';"); });
+throw 'TestComplete';
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-throw-error.js b/js/src/jit-test/tests/debug/Frame-onPop-throw-error.js
new file mode 100644
index 000000000000..6dd9caf0e999
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-throw-error.js
@@ -0,0 +1,59 @@
+// |jit-test| error: TestComplete
+// onPop can change a throw into a termination.
+
+var g = newGlobal('new-compartment');
+var dbg = new Debugger(g);
+
+// We use Debugger.Frame.prototype.eval and ignore the outer 'eval' frame so we
+// can catch the termination.
+
+function test(type, provocation) {
+ // Help people figure out which 'test' call failed.
+ print("type: " + uneval(type));
+ print("provocation: " + uneval(provocation));
+
+ var log;
+ dbg.onEnterFrame = function handleFirstFrame(f) {
+ log += 'f';
+ dbg.onDebuggerStatement = function handleDebugger(f) {
+ log += 'd';
+ };
+
+ dbg.onEnterFrame = function handleSecondFrame(f) {
+ log += 'e';
+ assertEq(f.type, 'eval');
+
+ dbg.onEnterFrame = function handleThirdFrame(f) {
+ log += '(';
+ assertEq(f.type, type);
+
+ dbg.onEnterFrame = function handleExtraFrames(f) {
+ // This should never be called.
+ assertEq(false, true);
+ };
+
+ f.onPop = function handlePop(c) {
+ log += ')';
+ assertEq(c.throw, 'mud');
+ return null;
+ };
+ };
+ };
+
+ assertEq(f.eval(provocation), null);
+ };
+
+ log = '';
+ // This causes handleFirstFrame to be called.
+ assertEq(typeof g.eval('eval'), 'function');
+ assertEq(log, 'fe(d)');
+
+ print();
+}
+
+g.eval('function f() { debugger; throw \'mud\'; }');
+test('call', 'f();');
+test('call', 'new f;');
+test('eval', 'eval(\'debugger; throw \\\'mud\\\';\');');
+test('global', 'evaluate(\'debugger; throw \\\'mud\\\';\');');
+throw 'TestComplete';
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-throw-return.js b/js/src/jit-test/tests/debug/Frame-onPop-throw-return.js
new file mode 100644
index 000000000000..bf0419b37510
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-throw-return.js
@@ -0,0 +1,46 @@
+// |jit-test| error: TestComplete
+// onPop can change a throw into a normal return.
+
+var g = newGlobal('new-compartment');
+var dbg = new Debugger(g);
+
+function test(type, provocation) {
+ var log;
+ var wasConstructing;
+
+ // Help people figure out which 'test' call failed.
+ print("type: " + uneval(type));
+ print("provocation: " + uneval(provocation));
+
+ dbg.onDebuggerStatement = function handleDebuggerStatement(f) {
+ log += 'd';
+ };
+
+ dbg.onEnterFrame = function handleEnterFrame(f) {
+ log += '(';
+ assertEq(f.type, type);
+ wasConstructing = f.constructing;
+ f.onPop = function handlePop(c) {
+ log += ')';
+ assertEq(c.throw, 'mud');
+ return { return: 'favor' };
+ };
+ };
+
+ log = '';
+ var result = provocation();
+ if (wasConstructing)
+ assertEq(typeof result, "object");
+ else
+ assertEq(result, 'favor');
+ assertEq(log, "(d)");
+
+ print();
+}
+
+g.eval("function f() { debugger; throw 'mud'; }");
+test("call", g.f);
+test("call", function () { return new g.f; });
+test("eval", function () { return g.eval("debugger; throw \'mud\';"); });
+test("global", function () { return g.evaluate("debugger; throw \'mud\';"); });
+throw 'TestComplete';
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-throw-throw.js b/js/src/jit-test/tests/debug/Frame-onPop-throw-throw.js
new file mode 100644
index 000000000000..cdf552cb91f4
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-throw-throw.js
@@ -0,0 +1,41 @@
+// |jit-test| error: TestComplete
+// onPop can change a throw into a throw of a different value.
+
+load(libdir + "asserts.js");
+var g = newGlobal('new-compartment');
+var dbg = new Debugger(g);
+
+function test(type, provocation) {
+ var log;
+
+ // Help people figure out which 'test' call failed.
+ print("type: " + uneval(type));
+ print("provocation: " + uneval(provocation));
+
+ dbg.onDebuggerStatement = function handleDebuggerStatement(f) {
+ log += 'd';
+ };
+
+ dbg.onEnterFrame = function handleEnterFrame(f) {
+ log += '(';
+ assertEq(f.type, type);
+ f.onPop = function handlePop(c) {
+ log += ')';
+ assertEq(c.throw, 'mud');
+ return { throw: 'snow' };
+ };
+ };
+
+ log = '';
+ assertThrowsValue(provocation, 'snow');
+ assertEq(log, "(d)");
+
+ print();
+}
+
+g.eval("function f() { debugger; throw 'mud'; }");
+test("call", g.f);
+test("call", function () { return new g.f; });
+test("eval", function () { return g.eval("debugger; throw \'mud\';"); });
+test("global", function () { return g.evaluate("debugger; throw \'mud\';"); });
+throw 'TestComplete';
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-throw.js b/js/src/jit-test/tests/debug/Frame-onPop-throw.js
new file mode 100644
index 000000000000..7f8490a005df
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-throw.js
@@ -0,0 +1,40 @@
+// |jit-test| error: TestComplete
+// onPop fires when frames throw an exception.
+
+load(libdir + "asserts.js");
+var g = newGlobal('new-compartment');
+var dbg = new Debugger(g);
+
+function test(type, provocation) {
+ var log;
+
+ // Help people figure out which 'test' call failed.
+ print("type: " + uneval(type));
+ print("provocation: " + uneval(provocation));
+
+ dbg.onDebuggerStatement = function handleDebuggerStatement(f) {
+ log += 'd';
+ };
+
+ dbg.onEnterFrame = function handleEnterFrame(f) {
+ log += '(';
+ assertEq(f.type, type);
+ f.onPop = function handlePop(c) {
+ log += ')';
+ assertEq(c.throw, 'mud');
+ };
+ };
+
+ log = '';
+ assertThrowsValue(provocation, 'mud');
+ assertEq(log, "(d)");
+
+ print();
+}
+
+g.eval("function f() { debugger; throw 'mud'; }");
+test("call", g.f);
+test("call", function () { return new g.f; });
+test("eval", function () { return g.eval("debugger; throw \'mud\';"); });
+test("global", function () { return g.evaluate("debugger; throw \'mud\';"); });
+throw 'TestComplete';
diff --git a/js/src/jsanalyze.cpp b/js/src/jsanalyze.cpp
index c46f50ee5e55..a7fc0bef599b 100644
--- a/js/src/jsanalyze.cpp
+++ b/js/src/jsanalyze.cpp
@@ -386,9 +386,9 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
isInlineable = false;
unsigned defaultOffset = offset + GET_JUMP_OFFSET(pc);
jsbytecode *pc2 = pc + JUMP_OFFSET_LEN;
- jsint low = GET_JUMP_OFFSET(pc2);
+ int32_t low = GET_JUMP_OFFSET(pc2);
pc2 += JUMP_OFFSET_LEN;
- jsint high = GET_JUMP_OFFSET(pc2);
+ int32_t high = GET_JUMP_OFFSET(pc2);
pc2 += JUMP_OFFSET_LEN;
if (!addJump(cx, defaultOffset, &nextOffset, &forwardJump, stackDepth))
@@ -396,7 +396,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
getCode(defaultOffset).switchTarget = true;
getCode(defaultOffset).safePoint = true;
- for (jsint i = low; i <= high; i++) {
+ for (int32_t i = low; i <= high; i++) {
unsigned targetOffset = offset + GET_JUMP_OFFSET(pc2);
if (targetOffset != offset) {
if (!addJump(cx, targetOffset, &nextOffset, &forwardJump, stackDepth))
@@ -1520,12 +1520,12 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
case JSOP_TABLESWITCH: {
unsigned defaultOffset = offset + GET_JUMP_OFFSET(pc);
jsbytecode *pc2 = pc + JUMP_OFFSET_LEN;
- jsint low = GET_JUMP_OFFSET(pc2);
+ int32_t low = GET_JUMP_OFFSET(pc2);
pc2 += JUMP_OFFSET_LEN;
- jsint high = GET_JUMP_OFFSET(pc2);
+ int32_t high = GET_JUMP_OFFSET(pc2);
pc2 += JUMP_OFFSET_LEN;
- for (jsint i = low; i <= high; i++) {
+ for (int32_t i = low; i <= high; i++) {
unsigned targetOffset = offset + GET_JUMP_OFFSET(pc2);
if (targetOffset != offset)
checkBranchTarget(cx, targetOffset, branchTargets, values, stackDepth);
diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
index 464fdacfecfe..b43249bb776a 100644
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -547,9 +547,9 @@ JS_ValueToNumber(JSContext *cx, jsval v, double *dp)
}
JS_PUBLIC_API(JSBool)
-JS_DoubleIsInt32(double d, jsint *ip)
+JS_DoubleIsInt32(double d, int32_t *ip)
{
- return JSDOUBLE_IS_INT32(d, (int32_t *)ip);
+ return JSDOUBLE_IS_INT32(d, ip);
}
JS_PUBLIC_API(int32_t)
@@ -2025,7 +2025,7 @@ JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
}
static JSIdArray *
-NewIdArray(JSContext *cx, jsint length)
+NewIdArray(JSContext *cx, int length)
{
JSIdArray *ida;
@@ -2040,7 +2040,7 @@ NewIdArray(JSContext *cx, jsint length)
* Unlike realloc(3), this function frees ida on failure.
*/
static JSIdArray *
-SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length)
+SetIdArrayLength(JSContext *cx, JSIdArray *ida, int length)
{
JSIdArray *rida;
@@ -2056,12 +2056,10 @@ SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length)
}
static JSIdArray *
-AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip)
+AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, int *ip)
{
- jsint i, length;
-
- i = *ip;
- length = ida->length;
+ int i = *ip;
+ int length = ida->length;
if (i >= length) {
ida = SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8));
if (!ida)
@@ -2075,7 +2073,7 @@ AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip)
static JSIdArray *
EnumerateIfResolved(JSContext *cx, JSObject *obj, JSAtom *atom, JSIdArray *ida,
- jsint *ip, JSBool *foundp)
+ int *ip, JSBool *foundp)
{
*foundp = obj->nativeContains(cx, ATOM_TO_JSID(atom));
if (*foundp)
@@ -2087,7 +2085,7 @@ JS_PUBLIC_API(JSIdArray *)
JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj, JSIdArray *ida)
{
JSRuntime *rt;
- jsint i, j, k;
+ int i, j, k;
JSAtom *atom;
JSBool found;
JSObjectOp init;
@@ -3001,14 +2999,14 @@ JS_SetNativeStackQuota(JSRuntime *rt, size_t stackSize)
/************************************************************************/
-JS_PUBLIC_API(jsint)
+JS_PUBLIC_API(int)
JS_IdArrayLength(JSContext *cx, JSIdArray *ida)
{
return ida->length;
}
JS_PUBLIC_API(jsid)
-JS_IdArrayGet(JSContext *cx, JSIdArray *ida, jsint index)
+JS_IdArrayGet(JSContext *cx, JSIdArray *ida, int index)
{
JS_ASSERT(index >= 0 && index < ida->length);
return ida->vector[index];
@@ -4297,7 +4295,7 @@ JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
{
JSObject *iterobj;
void *pdata;
- jsint index;
+ int index;
JSIdArray *ida;
AssertNoGC(cx);
@@ -4334,7 +4332,7 @@ JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
JS_PUBLIC_API(JSBool)
JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp)
{
- jsint i;
+ int32_t i;
const Shape *shape;
JSIdArray *ida;
@@ -4401,7 +4399,7 @@ JS_SetReservedSlot(JSObject *obj, uint32_t index, jsval v)
}
JS_PUBLIC_API(JSObject *)
-JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector)
+JS_NewArrayObject(JSContext *cx, int length, jsval *vector)
{
JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
AssertNoGC(cx);
diff --git a/js/src/jsapi.h b/js/src/jsapi.h
index aa6b992d230a..5a1a6aa84dc9 100644
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -65,8 +65,8 @@
/* JS::Value can store a full int32_t. */
#define JSVAL_INT_BITS 32
-#define JSVAL_INT_MIN ((jsint)0x80000000)
-#define JSVAL_INT_MAX ((jsint)0x7fffffff)
+#define JSVAL_INT_MIN ((int32_t)0x80000000)
+#define JSVAL_INT_MAX ((int32_t)0x7fffffff)
/************************************************************************/
@@ -1651,7 +1651,7 @@ JSVAL_IS_INT(jsval v)
return JSVAL_IS_INT32_IMPL(JSVAL_TO_IMPL(v));
}
-static JS_ALWAYS_INLINE jsint
+static JS_ALWAYS_INLINE int32_t
JSVAL_TO_INT(jsval v)
{
JS_ASSERT(JSVAL_IS_INT(v));
@@ -2062,7 +2062,7 @@ class AutoIdRooter : private AutoGCRooter
set of the same-named property in an
object that delegates to a prototype
containing this property */
-#define JSPROP_INDEX 0x80 /* name is actually (jsint) index */
+#define JSPROP_INDEX 0x80 /* name is actually (int) index */
#define JSPROP_SHORTID 0x100 /* set in JS_DefineProperty attrs
if getters/setters use a shortid */
#define JSPROP_NATIVE_ACCESSORS 0x08 /* set in JSPropertyDescriptor.flags
@@ -2244,7 +2244,7 @@ extern JS_PUBLIC_API(JSBool)
JS_ValueToNumber(JSContext *cx, jsval v, double *dp);
extern JS_PUBLIC_API(JSBool)
-JS_DoubleIsInt32(double d, jsint *ip);
+JS_DoubleIsInt32(double d, int32_t *ip);
extern JS_PUBLIC_API(int32_t)
JS_DoubleToInt32(double d);
@@ -3492,11 +3492,11 @@ struct JSClass {
#define JSCLASS_NO_INTERNAL_MEMBERS {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
#define JSCLASS_NO_OPTIONAL_MEMBERS 0,0,0,0,0,JSCLASS_NO_INTERNAL_MEMBERS
-extern JS_PUBLIC_API(jsint)
+extern JS_PUBLIC_API(int)
JS_IdArrayLength(JSContext *cx, JSIdArray *ida);
extern JS_PUBLIC_API(jsid)
-JS_IdArrayGet(JSContext *cx, JSIdArray *ida, jsint index);
+JS_IdArrayGet(JSContext *cx, JSIdArray *ida, int index);
extern JS_PUBLIC_API(void)
JS_DestroyIdArray(JSContext *cx, JSIdArray *ida);
@@ -3980,7 +3980,7 @@ JS_DeleteUCProperty2(JSContext *cx, JSObject *obj,
jsval *rval);
extern JS_PUBLIC_API(JSObject *)
-JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector);
+JS_NewArrayObject(JSContext *cx, int length, jsval *vector);
extern JS_PUBLIC_API(JSBool)
JS_IsArrayObject(JSContext *cx, JSObject *obj);
diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp
index 89cb4d253451..07bd71d1cb32 100644
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -167,7 +167,7 @@ js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
return false;
if (tvr.value().isInt32()) {
- *lengthp = jsuint(jsint(tvr.value().toInt32())); /* jsuint cast does ToUint32_t */
+ *lengthp = jsuint(tvr.value().toInt32()); /* jsuint cast does ToUint32_t */
return true;
}
@@ -3082,7 +3082,7 @@ array_indexOfHelper(JSContext *cx, IndexOfKind mode, CallArgs &args)
{
jsuint length, i, stop;
Value tosearch;
- jsint direction;
+ int direction;
JSBool hole;
JSObject *obj = ToObject(cx, &args.thisv());
diff --git a/js/src/jsarray.h b/js/src/jsarray.h
index 7ca7728340db..c9b541720c4c 100644
--- a/js/src/jsarray.h
+++ b/js/src/jsarray.h
@@ -60,8 +60,7 @@ inline JSBool
js_IdIsIndex(jsid id, jsuint *indexp)
{
if (JSID_IS_INT(id)) {
- jsint i;
- i = JSID_TO_INT(id);
+ int32_t i = JSID_TO_INT(id);
if (i < 0)
return JS_FALSE;
*indexp = (jsuint)i;
diff --git a/js/src/jsatom.cpp b/js/src/jsatom.cpp
index 84c3d35dc700..2666c53d6942 100644
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -736,13 +736,13 @@ js_CheckForStringIndex(jsid id)
if (oldIndex < -(JSID_INT_MIN / 10) ||
(oldIndex == -(JSID_INT_MIN / 10) && c <= (-JSID_INT_MIN % 10)))
{
- id = INT_TO_JSID(-jsint(index));
+ id = INT_TO_JSID(-int32_t(index));
}
} else {
if (oldIndex < JSID_INT_MAX / 10 ||
(oldIndex == JSID_INT_MAX / 10 && c <= (JSID_INT_MAX % 10)))
{
- id = INT_TO_JSID(jsint(index));
+ id = INT_TO_JSID(int32_t(index));
}
}
diff --git a/js/src/jsatom.h b/js/src/jsatom.h
index 93dc888bb20c..4564fbb641a1 100644
--- a/js/src/jsatom.h
+++ b/js/src/jsatom.h
@@ -53,7 +53,7 @@
#include "js/HashTable.h"
struct JSIdArray {
- jsint length;
+ int length;
js::HeapId vector[1]; /* actually, length jsid words */
};
diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h
index 4a9d260e1b9c..6c2637338e83 100644
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -214,7 +214,7 @@ class CompartmentChecker
void check(JSIdArray *ida) {
if (ida) {
- for (jsint i = 0; i < ida->length; i++) {
+ for (int i = 0; i < ida->length; i++) {
if (JSID_IS_OBJECT(ida->vector[i]))
check(ida->vector[i]);
}
diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp
index 45451bc7ec7c..013cae650602 100644
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -80,7 +80,6 @@ JSCompartment::JSCompartment(JSRuntime *rt)
typeLifoAlloc(TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
data(NULL),
active(false),
- hasDebugModeCodeToDrop(false),
#ifdef JS_METHODJIT
jaegerCompartment_(NULL),
#endif
@@ -397,7 +396,7 @@ bool
JSCompartment::wrap(JSContext *cx, AutoIdVector &props)
{
jsid *vector = props.begin();
- jsint length = props.length();
+ int length = props.length();
for (size_t n = 0; n < size_t(length); ++n) {
if (!wrapId(cx, &vector[n]))
return false;
@@ -676,12 +675,10 @@ JSCompartment::updateForDebugMode(JSContext *cx)
#ifdef JS_METHODJIT
bool enabled = debugMode();
- if (enabled) {
+ if (enabled)
JS_ASSERT(!hasScriptsOnStack());
- } else if (hasScriptsOnStack()) {
- hasDebugModeCodeToDrop = true;
+ else if (hasScriptsOnStack())
return;
- }
/*
* Discard JIT code and bytecode analyses for any scripts that change
@@ -695,7 +692,6 @@ JSCompartment::updateForDebugMode(JSContext *cx)
script->debugMode = enabled;
}
}
- hasDebugModeCodeToDrop = false;
#endif
}
diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h
index fc22037a23eb..27d72cd59350 100644
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -125,17 +125,17 @@ class MathCache;
*/
class DtoaCache {
double d;
- jsint base;
+ int base;
JSFixedString *s; // if s==NULL, d and base are not valid
public:
DtoaCache() : s(NULL) {}
void purge() { s = NULL; }
- JSFixedString *lookup(jsint base, double d) {
+ JSFixedString *lookup(int base, double d) {
return this->s && base == this->base && d == this->d ? this->s : NULL;
}
- void cache(jsint base, double d, JSFixedString *s) {
+ void cache(int base, double d, JSFixedString *s) {
this->base = base;
this->d = d;
this->s = s;
@@ -230,7 +230,6 @@ struct JSCompartment
void *data;
bool active; // GC flag, whether there are active frames
- bool hasDebugModeCodeToDrop;
js::WrapperMap crossCompartmentWrappers;
#ifdef JS_METHODJIT
diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp
index cdf8bf64999d..3ea86bc6f326 100644
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -200,19 +200,19 @@ TimeWithinDay(double t)
}
static inline bool
-IsLeapYear(jsint year)
+IsLeapYear(int year)
{
return year % 4 == 0 && (year % 100 || (year % 400 == 0));
}
-static inline jsint
-DaysInYear(jsint year)
+static inline int
+DaysInYear(int year)
{
return IsLeapYear(year) ? 366 : 365;
}
-static inline jsint
-DaysInFebruary(jsint year)
+static inline int
+DaysInFebruary(int year)
{
return IsLeapYear(year) ? 29 : 28;
}
@@ -224,10 +224,10 @@ DaysInFebruary(jsint year)
- floor(((y)-1901)/100.0) + floor(((y)-1601)/400.0))
#define TimeFromYear(y) (DayFromYear(y) * msPerDay)
-static jsint
+static int
YearFromTime(double t)
{
- jsint y = (jsint) floor(t /(msPerDay*365.2425)) + 1970;
+ int y = (int) floor(t /(msPerDay*365.2425)) + 1970;
double t2 = (double) TimeFromYear(y);
/*
@@ -258,7 +258,7 @@ static double firstDayOfMonth[2][13] = {
#define DayFromMonth(m, leap) firstDayOfMonth[leap][(int)m]
static int
-DaysInMonth(jsint year, jsint month)
+DaysInMonth(int year, int month)
{
JSBool leap = IsLeapYear(year);
int result = int(DayFromMonth(month, leap) - DayFromMonth(month-1, leap));
@@ -269,7 +269,7 @@ static int
MonthFromTime(double t)
{
int d, step;
- jsint year = YearFromTime(t);
+ int year = YearFromTime(t);
d = DayWithinYear(t, year);
if (d < (step = 31))
@@ -301,7 +301,7 @@ static int
DateFromTime(double t)
{
int d, step, next;
- jsint year = YearFromTime(t);
+ int year = YearFromTime(t);
d = DayWithinYear(t, year);
if (d <= (next = 30))
@@ -343,8 +343,8 @@ DateFromTime(double t)
static int
WeekDay(double t)
{
- jsint result;
- result = (jsint) Day(t) + 4;
+ int result;
+ result = (int) Day(t) + 4;
result = result % 7;
if (result < 0)
result += 7;
@@ -367,7 +367,7 @@ MakeDay(double year, double month, double date)
if (month < 0)
month += 12;
- leap = IsLeapYear((jsint) year);
+ leap = IsLeapYear((int) year);
yearday = floor(TimeFromYear(year) / msPerDay);
monthday = DayFromMonth(month, leap);
@@ -386,7 +386,7 @@ MakeDay(double year, double month, double date)
* yearStartingWith[1][i] is an example leap year where
* Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
*/
-static jsint yearStartingWith[2][7] = {
+static int yearStartingWith[2][7] = {
{1978, 1973, 1974, 1975, 1981, 1971, 1977},
{1984, 1996, 1980, 1992, 1976, 1988, 1972}
};
@@ -398,12 +398,12 @@ static jsint yearStartingWith[2][7] = {
* for determining DST; it hasn't been proven not to produce an
* incorrect year for times near year boundaries.
*/
-static jsint
-EquivalentYearForDST(jsint year)
+static int
+EquivalentYearForDST(int year)
{
- jsint day;
+ int day;
- day = (jsint) DayFromYear(year) + 4;
+ day = (int) DayFromYear(year) + 4;
day = day % 7;
if (day < 0)
day += 7;
@@ -426,7 +426,7 @@ DaylightSavingTA(double t, JSContext *cx)
* many OSes, map it to an equivalent year before asking.
*/
if (t < 0.0 || t > 2145916800000.0) {
- jsint year = EquivalentYearForDST(YearFromTime(t));
+ int year = EquivalentYearForDST(YearFromTime(t));
double day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
t = MakeDate(day, TimeWithinDay(t));
}
@@ -1273,11 +1273,11 @@ FillLocalTimes(JSContext *cx, JSObject *obj)
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_TIME, DoubleValue(localTime));
- jsint year = (jsint) floor(localTime /(msPerDay*365.2425)) + 1970;
+ int year = (int) floor(localTime /(msPerDay*365.2425)) + 1970;
double yearStartTime = (double) TimeFromYear(year);
/* Adjust the year in case the approximation was wrong, as in YearFromTime. */
- jsint yearDays;
+ int yearDays;
if (yearStartTime > localTime) {
year--;
yearStartTime -= (msPerDay * DaysInYear(year));
@@ -1295,12 +1295,12 @@ FillLocalTimes(JSContext *cx, JSObject *obj)
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR, Int32Value(year));
uint64_t yearTime = uint64_t(localTime - yearStartTime);
- jsint yearSeconds = uint32_t(yearTime / 1000);
+ int yearSeconds = uint32_t(yearTime / 1000);
- jsint day = yearSeconds / jsint(SecondsPerDay);
+ int day = yearSeconds / int(SecondsPerDay);
- jsint step = -1, next = 30;
- jsint month;
+ int step = -1, next = 30;
+ int month;
do {
if (day <= next) {
@@ -1365,19 +1365,19 @@ FillLocalTimes(JSContext *cx, JSObject *obj)
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH, Int32Value(month));
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_DATE, Int32Value(day - step));
- jsint weekday = WeekDay(localTime);
+ int weekday = WeekDay(localTime);
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_DAY, Int32Value(weekday));
- jsint seconds = yearSeconds % 60;
+ int seconds = yearSeconds % 60;
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS, Int32Value(seconds));
- jsint minutes = (yearSeconds / 60) % 60;
+ int minutes = (yearSeconds / 60) % 60;
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES, Int32Value(minutes));
- jsint hours = (yearSeconds / (60 * 60)) % 24;
+ int hours = (yearSeconds / (60 * 60)) % 24;
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS, Int32Value(hours));
@@ -1441,7 +1441,7 @@ date_getYear(JSContext *cx, unsigned argc, Value *vp)
Value yearVal = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR);
if (yearVal.isInt32()) {
/* Follow ECMA-262 to the letter, contrary to IE JScript. */
- jsint year = yearVal.toInt32() - 1900;
+ int year = yearVal.toInt32() - 1900;
args.rval().setInt32(year);
} else {
args.rval() = yearVal;
@@ -2162,7 +2162,7 @@ date_toJSON(JSContext *cx, unsigned argc, Value *vp)
static void
new_explode(double timeval, PRMJTime *split, JSContext *cx)
{
- jsint year = YearFromTime(timeval);
+ int year = YearFromTime(timeval);
split->tm_usec = int32_t(msFromTime(timeval)) * 1000;
split->tm_sec = int8_t(SecFromTime(timeval));
@@ -2201,7 +2201,7 @@ date_format(JSContext *cx, double date, formatspec format, CallReceiver call)
/* offset from GMT in minutes. The offset includes daylight savings,
if it applies. */
- jsint minutes = (jsint) floor(AdjustTime(date, cx) / msPerMinute);
+ int minutes = (int) floor(AdjustTime(date, cx) / msPerMinute);
/* map 510 minutes to 0830 hours */
int offset = (minutes / 60) * 100 + minutes % 60;
diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp
index 9c006b8d0e71..f7cfcfa78c35 100644
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -155,9 +155,8 @@ ScriptDebugEpilogue(JSContext *cx, StackFrame *fp, bool okArg)
hook(cx, Jsvalify(fp), false, &ok, hookData);
}
}
- Debugger::onLeaveFrame(cx);
- return ok;
+ return Debugger::onLeaveFrame(cx, ok);
}
} /* namespace js */
diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp
index 3cdbd8c898fa..f95754c5b523 100644
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -902,7 +902,7 @@ js::ValueToId(JSContext *cx, const Value &v, jsid *idp)
* of the with block with sp + stackIndex.
*/
static bool
-EnterWith(JSContext *cx, jsint stackIndex)
+EnterWith(JSContext *cx, int stackIndex)
{
StackFrame *fp = cx->fp();
Value *sp = cx->regs().sp;
@@ -1495,7 +1495,7 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
#endif
/* State communicated between non-local jumps: */
- JSBool interpReturnOK;
+ bool interpReturnOK;
/* Don't call the script prologue if executing between Method and Trace JIT. */
if (interpMode == JSINTERP_NORMAL) {
@@ -1509,7 +1509,7 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
case JSTRAP_CONTINUE:
break;
case JSTRAP_RETURN:
- interpReturnOK = JS_TRUE;
+ interpReturnOK = true;
goto forced_return;
case JSTRAP_THROW:
case JSTRAP_ERROR:
@@ -1535,7 +1535,7 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
* "op" correctly in all other cases.
*/
JSOp op;
- jsint len;
+ int32_t len;
len = 0;
/* Check for too deep of a native thread stack. */
@@ -1606,7 +1606,7 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
break;
case JSTRAP_RETURN:
regs.fp()->setReturnValue(rval);
- interpReturnOK = JS_TRUE;
+ interpReturnOK = true;
goto forced_return;
case JSTRAP_THROW:
cx->setPendingException(rval);
@@ -1627,7 +1627,7 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
goto error;
case JSTRAP_RETURN:
regs.fp()->setReturnValue(rval);
- interpReturnOK = JS_TRUE;
+ interpReturnOK = true;
goto forced_return;
case JSTRAP_THROW:
cx->setPendingException(rval);
@@ -2757,7 +2757,7 @@ BEGIN_CASE(JSOP_FUNAPPLY)
case JSTRAP_CONTINUE:
break;
case JSTRAP_RETURN:
- interpReturnOK = JS_TRUE;
+ interpReturnOK = true;
goto forced_return;
case JSTRAP_THROW:
case JSTRAP_ERROR:
@@ -2896,7 +2896,7 @@ BEGIN_CASE(JSOP_TABLESWITCH)
/*
* ECMAv2+ forbids conversion of discriminant, so we will skip to the
* default case if the discriminant isn't already an int jsval. (This
- * opcode is emitted only for dense jsint-domain switches.)
+ * opcode is emitted only for dense int-domain switches.)
*/
const Value &rref = *--regs.sp;
int32_t i;
@@ -2910,14 +2910,14 @@ BEGIN_CASE(JSOP_TABLESWITCH)
}
pc2 += JUMP_OFFSET_LEN;
- jsint low = GET_JUMP_OFFSET(pc2);
+ int32_t low = GET_JUMP_OFFSET(pc2);
pc2 += JUMP_OFFSET_LEN;
- jsint high = GET_JUMP_OFFSET(pc2);
+ int32_t high = GET_JUMP_OFFSET(pc2);
i -= low;
if ((jsuint)i < (jsuint)(high - low + 1)) {
pc2 += JUMP_OFFSET_LEN + JUMP_OFFSET_LEN * i;
- jsint off = (jsint) GET_JUMP_OFFSET(pc2);
+ int32_t off = (int32_t) GET_JUMP_OFFSET(pc2);
if (off)
len = off;
}
@@ -2928,7 +2928,7 @@ END_VARLEN_CASE
{
BEGIN_CASE(JSOP_LOOKUPSWITCH)
{
- jsint off;
+ int32_t off;
off = JUMP_OFFSET_LEN;
/*
@@ -2941,12 +2941,12 @@ BEGIN_CASE(JSOP_LOOKUPSWITCH)
Value lval = regs.sp[-1];
regs.sp--;
+ int npairs;
if (!lval.isPrimitive())
goto end_lookup_switch;
pc2 += off;
- jsint npairs;
- npairs = (jsint) GET_UINT16(pc2);
+ npairs = GET_UINT16(pc2);
pc2 += UINT16_LEN;
JS_ASSERT(npairs); /* empty switch uses JSOP_TABLESWITCH */
@@ -3354,7 +3354,7 @@ BEGIN_CASE(JSOP_SETTER)
JSOp op2 = JSOp(*++regs.pc);
jsid id;
Value rval;
- jsint i;
+ int i;
JSObject *obj;
switch (op2) {
case JSOP_SETNAME:
@@ -3583,7 +3583,7 @@ END_CASE(JSOP_INITELEM)
{
BEGIN_CASE(JSOP_GOSUB)
PUSH_BOOLEAN(false);
- jsint i = (regs.pc - script->code) + JSOP_GOSUB_LENGTH;
+ int32_t i = (regs.pc - script->code) + JSOP_GOSUB_LENGTH;
len = GET_JUMP_OFFSET(regs.pc);
PUSH_INT32(i);
END_VARLEN_CASE
@@ -3682,7 +3682,7 @@ BEGIN_CASE(JSOP_DEBUGGER)
break;
case JSTRAP_RETURN:
regs.fp()->setReturnValue(rval);
- interpReturnOK = JS_TRUE;
+ interpReturnOK = true;
goto forced_return;
case JSTRAP_THROW:
cx->setPendingException(rval);
@@ -4138,7 +4138,7 @@ BEGIN_CASE(JSOP_YIELD)
regs.fp()->setReturnValue(regs.sp[-1]);
regs.fp()->setYielding();
regs.pc += JSOP_YIELD_LENGTH;
- interpReturnOK = JS_TRUE;
+ interpReturnOK = true;
goto exit;
BEGIN_CASE(JSOP_ARRAYPUSH)
@@ -4221,7 +4221,7 @@ END_CASE(JSOP_ARRAYPUSH)
if (!cx->isExceptionPending()) {
/* This is an error, not a catchable exception, quit the frame ASAP. */
- interpReturnOK = JS_FALSE;
+ interpReturnOK = false;
} else {
JSThrowHook handler;
JSTryNote *tn, *tnlimit;
@@ -4247,7 +4247,7 @@ END_CASE(JSOP_ARRAYPUSH)
case JSTRAP_RETURN:
cx->clearPendingException();
regs.fp()->setReturnValue(rval);
- interpReturnOK = JS_TRUE;
+ interpReturnOK = true;
goto forced_return;
case JSTRAP_THROW:
cx->setPendingException(rval);
@@ -4347,12 +4347,12 @@ END_CASE(JSOP_ARRAYPUSH)
* Propagate the exception or error to the caller unless the exception
* is an asynchronous return from a generator.
*/
- interpReturnOK = JS_FALSE;
+ interpReturnOK = false;
#if JS_HAS_GENERATORS
if (JS_UNLIKELY(cx->isExceptionPending() &&
cx->getPendingException().isMagic(JS_GENERATOR_CLOSING))) {
cx->clearPendingException();
- interpReturnOK = JS_TRUE;
+ interpReturnOK = true;
regs.fp()->clearReturnValue();
}
#endif
diff --git a/js/src/jsinterp.h b/js/src/jsinterp.h
index fd0939ebda40..1f01b12d6146 100644
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -112,6 +112,21 @@ ScriptEpilogueOrGeneratorYield(JSContext *cx, StackFrame *fp, bool ok);
extern JSTrapStatus
ScriptDebugPrologue(JSContext *cx, StackFrame *fp);
+/*
+ * Announce to the debugger that the thread has exited a JavaScript frame, |fp|.
+ * If |ok| is true, the frame is returning normally; if |ok| is false, the frame
+ * is throwing an exception or terminating.
+ *
+ * Call whatever hooks have been registered to observe frame exits. Change cx's
+ * current exception and |fp|'s return value to reflect the changes in behavior
+ * the hooks request, if any. Return the new error/success value.
+ *
+ * This function may be called twice for the same outgoing frame; only the
+ * first call has any effect. (Permitting double calls simplifies some
+ * cases where an onPop handler's resumption value changes a return to a
+ * throw, or vice versa: we can redirect to a complete copy of the
+ * alternative path, containing its own call to ScriptDebugEpilogue.)
+ */
extern bool
ScriptDebugEpilogue(JSContext *cx, StackFrame *fp, bool ok);
diff --git a/js/src/jsinterpinlines.h b/js/src/jsinterpinlines.h
index c0b4bf990d9b..1f24a5d872b6 100644
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -805,7 +805,7 @@ SetObjectElementOperation(JSContext *cx, JSObject *obj, jsid id, const Value &va
do {
if (obj->isDenseArray() && JSID_IS_INT(id)) {
jsuint length = obj->getDenseArrayInitializedLength();
- jsint i = JSID_TO_INT(id);
+ int32_t i = JSID_TO_INT(id);
if ((jsuint)i < length) {
if (obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) {
if (js_PrototypeHasIndexedProperties(cx, obj))
diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp
index 34f26faf53cb..e8b9556c41fe 100644
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -426,9 +426,9 @@ js::VectorToIdArray(JSContext *cx, AutoIdVector &props, JSIdArray **idap)
if (!ida)
return false;
- ida->length = static_cast(len);
+ ida->length = static_cast(len);
jsid *v = props.begin();
- for (jsint i = 0; i < ida->length; i++)
+ for (int i = 0; i < ida->length; i++)
ida->vector[i].init(v[i]);
*idap = ida;
return true;
@@ -1274,7 +1274,7 @@ js_IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
return true;
JSString *str;
- jsint i;
+ int i;
if (rval->isInt32() && StaticStrings::hasInt(i = rval->toInt32())) {
str = cx->runtime->staticStrings.getInt(i);
} else {
diff --git a/js/src/jsmath.cpp b/js/src/jsmath.cpp
index d8b07ed777f1..17c25123d492 100644
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -433,7 +433,7 @@ js_math_min(JSContext *cx, unsigned argc, Value *vp)
}
static double
-powi(double x, jsint y)
+powi(double x, int y)
{
jsuint n = (y < 0) ? -y : y;
double m = x;
diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp
index e9d64733011f..3ae22a765821 100644
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -575,7 +575,7 @@ js_IntToString(JSContext *cx, int32_t si)
/* Returns a non-NULL pointer to inside cbuf. */
static char *
-IntToCString(ToCStringBuf *cbuf, jsint i, jsint base = 10)
+IntToCString(ToCStringBuf *cbuf, int i, int base = 10)
{
jsuint u = (i < 0) ? -i : i;
@@ -610,7 +610,7 @@ IntToCString(ToCStringBuf *cbuf, jsint i, jsint base = 10)
}
static JSString * JS_FASTCALL
-js_NumberToStringWithBase(JSContext *cx, double d, jsint base);
+js_NumberToStringWithBase(JSContext *cx, double d, int base);
static JS_ALWAYS_INLINE bool
num_toStringHelper(JSContext *cx, Native native, unsigned argc, Value *vp)
@@ -788,7 +788,7 @@ js_num_valueOf(JSContext *cx, unsigned argc, Value *vp)
static JSBool
num_to(JSContext *cx, Native native, JSDToStrMode zeroArgMode, JSDToStrMode oneArgMode,
- jsint precisionMin, jsint precisionMax, jsint precisionOffset,
+ int precisionMin, int precisionMax, int precisionOffset,
CallArgs args)
{
/* Use MAX_PRECISION+1 because precisionOffset can be 1. */
@@ -809,7 +809,7 @@ num_to(JSContext *cx, Native native, JSDToStrMode zeroArgMode, JSDToStrMode oneA
return false;
if (precision < precisionMin || precision > precisionMax) {
ToCStringBuf cbuf;
- numStr = IntToCString(&cbuf, jsint(precision));
+ numStr = IntToCString(&cbuf, int(precision));
JS_ASSERT(numStr);
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PRECISION_RANGE, numStr);
return JS_FALSE;
@@ -817,7 +817,7 @@ num_to(JSContext *cx, Native native, JSDToStrMode zeroArgMode, JSDToStrMode oneA
}
numStr = js_dtostr(cx->runtime->dtoaState, buf, sizeof buf,
- oneArgMode, (jsint)precision + precisionOffset, d);
+ oneArgMode, (int)precision + precisionOffset, d);
if (!numStr) {
JS_ReportOutOfMemory(cx);
return JS_FALSE;
@@ -1065,7 +1065,7 @@ extern char* DoubleToCString(double v, char* buffer, int buflen);
namespace js {
static char *
-FracNumberToCString(JSContext *cx, ToCStringBuf *cbuf, double d, jsint base = 10)
+FracNumberToCString(JSContext *cx, ToCStringBuf *cbuf, double d, int base = 10)
{
#ifdef DEBUG
{
@@ -1097,7 +1097,7 @@ FracNumberToCString(JSContext *cx, ToCStringBuf *cbuf, double d, jsint base = 10
}
char *
-NumberToCString(JSContext *cx, ToCStringBuf *cbuf, double d, jsint base/* = 10*/)
+NumberToCString(JSContext *cx, ToCStringBuf *cbuf, double d, int base/* = 10*/)
{
int32_t i;
return (JSDOUBLE_IS_INT32(d, &i))
@@ -1108,7 +1108,7 @@ NumberToCString(JSContext *cx, ToCStringBuf *cbuf, double d, jsint base/* = 10*/
}
static JSString * JS_FASTCALL
-js_NumberToStringWithBase(JSContext *cx, double d, jsint base)
+js_NumberToStringWithBase(JSContext *cx, double d, int base)
{
ToCStringBuf cbuf;
char *numStr;
diff --git a/js/src/jsnum.h b/js/src/jsnum.h
index 157ee4520c5f..1e7402644b99 100644
--- a/js/src/jsnum.h
+++ b/js/src/jsnum.h
@@ -160,7 +160,7 @@ class JSString;
class JSFixedString;
extern JSString * JS_FASTCALL
-js_IntToString(JSContext *cx, jsint i);
+js_IntToString(JSContext *cx, int i);
/*
* When base == 10, this function implements ToString() as specified by
@@ -213,7 +213,7 @@ struct ToCStringBuf
* js_NumberToCString().
*/
extern char *
-NumberToCString(JSContext *cx, ToCStringBuf *cbuf, double d, jsint base = 10);
+NumberToCString(JSContext *cx, ToCStringBuf *cbuf, double d, int base = 10);
/*
* The largest positive integer such that all positive integers less than it
diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp
index dd4ac258b536..e47b39ccaeea 100644
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -214,7 +214,7 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap, JSSharpInfo *va
return false;
bool ok = true;
- for (jsint i = 0, length = ida->length; i < length; i++) {
+ for (int i = 0, length = ida->length; i < length; i++) {
jsid id = ida->vector[i];
JSObject *obj2;
JSProperty *prop;
@@ -486,7 +486,7 @@ obj_toSource(JSContext *cx, unsigned argc, Value *vp)
*/
val = localroot + 2;
- for (jsint i = 0; i < ida->length; i++) {
+ for (int i = 0; i < ida->length; i++) {
/* Get strings for id and value and GC-root them via vp. */
jsid id = ida->vector[i];
JSLinearString *idstr;
diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp
index bfb99e60fa1a..8960317e2df2 100644
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -148,7 +148,7 @@ size_t
js_GetVariableBytecodeLength(jsbytecode *pc)
{
unsigned ncases;
- jsint low, high;
+ int32_t low, high;
JSOp op = JSOp(*pc);
JS_ASSERT(js_CodeSpec[op].length == -1);
@@ -586,7 +586,7 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc,
case JOF_TABLESWITCH:
{
- jsint i, low, high;
+ int32_t i, low, high;
ptrdiff_t off = GET_JUMP_OFFSET(pc);
jsbytecode *pc2 = pc + JUMP_OFFSET_LEN;
@@ -651,18 +651,18 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc,
int i;
case JOF_UINT16PAIR:
- i = (jsint)GET_UINT16(pc);
+ i = (int)GET_UINT16(pc);
Sprint(sp, " %d", i);
pc += UINT16_LEN;
/* FALL THROUGH */
case JOF_UINT16:
- i = (jsint)GET_UINT16(pc);
+ i = (int)GET_UINT16(pc);
goto print_int;
case JOF_UINT24:
JS_ASSERT(op == JSOP_UINT24 || op == JSOP_NEWARRAY);
- i = (jsint)GET_UINT24(pc);
+ i = (int)GET_UINT24(pc);
goto print_int;
case JOF_UINT8:
@@ -1558,7 +1558,7 @@ struct TableEntry {
jsval key;
ptrdiff_t offset;
JSAtom *label;
- jsint order; /* source order for stable tableswitch sort */
+ int order; /* source order for stable tableswitch sort */
};
inline bool
@@ -1766,7 +1766,7 @@ GetArgOrVarAtom(JSPrinter *jp, unsigned slot)
#define LOCAL_ASSERT(expr) LOCAL_ASSERT_RV(expr, "")
static const char *
-GetLocalInSlot(SprintStack *ss, jsint i, jsint slot, JSObject *obj)
+GetLocalInSlot(SprintStack *ss, int i, int slot, JSObject *obj)
{
for (Shape::Range r(obj->lastProperty()); !r.empty(); r.popFront()) {
const Shape &shape = r.front();
@@ -1790,7 +1790,7 @@ GetLocalInSlot(SprintStack *ss, jsint i, jsint slot, JSObject *obj)
}
const char *
-GetLocal(SprintStack *ss, jsint i)
+GetLocal(SprintStack *ss, int i)
{
ptrdiff_t off = ss->offsets[i];
if (off >= 0)
@@ -1826,7 +1826,7 @@ GetLocal(SprintStack *ss, jsint i)
uint32_t depth = obj->asBlock().stackDepth();
uint32_t count = obj->asBlock().slotCount();
if (jsuint(i - depth) < jsuint(count))
- return GetLocalInSlot(ss, i, jsint(i - depth), obj);
+ return GetLocalInSlot(ss, i, int(i - depth), obj);
}
}
}
@@ -1839,7 +1839,7 @@ GetLocal(SprintStack *ss, jsint i)
uint32_t depth = obj->asBlock().stackDepth();
uint32_t count = obj->asBlock().slotCount();
if (jsuint(i - depth) < jsuint(count))
- return GetLocalInSlot(ss, i, jsint(i - depth), obj);
+ return GetLocalInSlot(ss, i, int(i - depth), obj);
}
}
@@ -1849,7 +1849,7 @@ GetLocal(SprintStack *ss, jsint i)
#undef LOCAL_ASSERT
static JSBool
-IsVarSlot(JSPrinter *jp, jsbytecode *pc, jsint *indexp)
+IsVarSlot(JSPrinter *jp, jsbytecode *pc, int *indexp)
{
unsigned slot;
@@ -1900,7 +1900,7 @@ DecompileDestructuringLHS(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc, JS
JSOp op;
const JSCodeSpec *cs;
unsigned oplen;
- jsint i;
+ int i;
const char *lval, *xval;
JSAtom *atom;
@@ -2117,7 +2117,7 @@ DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc,
case JSOP_DOUBLE:
d = jp->script->getConst(GET_UINT32_INDEX(pc)).toDouble();
LOCAL_ASSERT(JSDOUBLE_IS_FINITE(d) && !JSDOUBLE_IS_NEGZERO(d));
- i = (jsint)d;
+ i = (int)d;
do_getelem:
{
@@ -2561,7 +2561,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, int nb)
jssrcnote *sn, *sn2;
const char *lval, *rval, *xval, *fmt, *token;
unsigned nuses;
- jsint i, argc;
+ int i, argc;
JSAtom *atom;
JSObject *obj;
JSFunction *fun = NULL; /* init to shut GCC up */
@@ -4681,11 +4681,11 @@ Decompile(SprintStack *ss, jsbytecode *pc, int nb)
break;
case JSOP_UINT16:
- i = (jsint) GET_UINT16(pc);
+ i = (int) GET_UINT16(pc);
goto do_sprint_int;
case JSOP_UINT24:
- i = (jsint) GET_UINT24(pc);
+ i = (int) GET_UINT24(pc);
goto do_sprint_int;
case JSOP_INT8:
@@ -4893,7 +4893,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, int nb)
case JSOP_TABLESWITCH:
{
ptrdiff_t off, off2;
- jsint j, n, low, high;
+ int32_t j, n, low, high;
TableEntry *table, *tmp;
sn = js_GetSrcNote(jp->script, pc);
@@ -4998,7 +4998,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, int nb)
case JSOP_CONDSWITCH:
{
ptrdiff_t off, off2, caseOff;
- jsint ncases;
+ int ncases;
TableEntry *table;
sn = js_GetSrcNote(jp->script, pc);
@@ -5040,7 +5040,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, int nb)
pc2 += off2;
LOCAL_ASSERT(*pc2 == JSOP_CASE || *pc2 == JSOP_DEFAULT);
caseOff = pc2 - pc;
- table[i].key = INT_TO_JSVAL((jsint) caseOff);
+ table[i].key = INT_TO_JSVAL((int32_t) caseOff);
table[i].offset = caseOff + GET_JUMP_OFFSET(pc2);
if (*pc2 == JSOP_CASE) {
sn = js_GetSrcNote(jp->script, pc2);
diff --git a/js/src/jsopcode.h b/js/src/jsopcode.h
index 313e4f7fb3d2..526d8d395b30 100644
--- a/js/src/jsopcode.h
+++ b/js/src/jsopcode.h
@@ -216,12 +216,12 @@ SET_UINT32_INDEX(jsbytecode *pc, uint32_t index)
(pc)[2] = UINT24_MID(i), \
(pc)[3] = UINT24_LO(i))
-#define GET_INT8(pc) ((jsint)int8_t((pc)[1]))
+#define GET_INT8(pc) (int8_t((pc)[1]))
-#define GET_INT32(pc) ((jsint)((uint32_t((pc)[1]) << 24) | \
- (uint32_t((pc)[2]) << 16) | \
- (uint32_t((pc)[3]) << 8) | \
- uint32_t((pc)[4])))
+#define GET_INT32(pc) (((uint32_t((pc)[1]) << 24) | \
+ (uint32_t((pc)[2]) << 16) | \
+ (uint32_t((pc)[3]) << 8) | \
+ uint32_t((pc)[4])))
#define SET_INT32(pc,i) ((pc)[1] = (jsbytecode)(uint32_t(i) >> 24), \
(pc)[2] = (jsbytecode)(uint32_t(i) >> 16), \
(pc)[3] = (jsbytecode)(uint32_t(i) >> 8), \
diff --git a/js/src/jspropertytree.cpp b/js/src/jspropertytree.cpp
index 7353ab13e5da..bab78a357290 100644
--- a/js/src/jspropertytree.cpp
+++ b/js/src/jspropertytree.cpp
@@ -277,7 +277,7 @@ Shape::dump(JSContext *cx, FILE *fp) const
if (attrs) {
int first = 1;
fputs("(", fp);
-#define DUMP_ATTR(name, display) if (attrs & JSPROP_##name) fputs(" " #display + first, fp), first = 0
+#define DUMP_ATTR(name, display) if (attrs & JSPROP_##name) fputs(&(" " #display)[first], fp), first = 0
DUMP_ATTR(ENUMERATE, enumerate);
DUMP_ATTR(READONLY, readonly);
DUMP_ATTR(PERMANENT, permanent);
@@ -292,7 +292,7 @@ Shape::dump(JSContext *cx, FILE *fp) const
if (flags) {
int first = 1;
fputs("(", fp);
-#define DUMP_FLAG(name, display) if (flags & name) fputs(" " #display + first, fp), first = 0
+#define DUMP_FLAG(name, display) if (flags & name) fputs(&(" " #display)[first], fp), first = 0
DUMP_FLAG(HAS_SHORTID, has_shortid);
DUMP_FLAG(METHOD, method);
DUMP_FLAG(IN_DICTIONARY, in_dictionary);
diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h
index d2d5d7ddc8de..e6ef4610a068 100644
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -94,7 +94,6 @@ typedef ptrdiff_t jsid;
JS_BEGIN_EXTERN_C
/* Scalar typedefs. */
-typedef int32_t jsint;
typedef uint32_t jsuint;
#ifdef WIN32
diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp
index 2e0878895aa5..995112384751 100644
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -424,7 +424,7 @@ str_resolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
JSString *str = obj->asString().unbox();
- jsint slot = JSID_TO_INT(id);
+ int32_t slot = JSID_TO_INT(id);
if ((size_t)slot < str->length()) {
JSString *str1 = cx->runtime->staticStrings.getUnitStringForElement(cx, str, size_t(slot));
if (!str1)
@@ -877,9 +877,9 @@ out_of_range:
*/
static const jsuint sBMHCharSetSize = 256; /* ISO-Latin-1 */
static const jsuint sBMHPatLenMax = 255; /* skip table element is uint8_t */
-static const jsint sBMHBadPattern = -2; /* return value if pat is not ISO-Latin-1 */
+static const int sBMHBadPattern = -2; /* return value if pat is not ISO-Latin-1 */
-jsint
+int
js_BoyerMooreHorspool(const jschar *text, jsuint textlen,
const jschar *pat, jsuint patlen)
{
@@ -903,7 +903,7 @@ js_BoyerMooreHorspool(const jschar *text, jsuint textlen,
if (text[i] != pat[j])
break;
if (j == 0)
- return static_cast(i); /* safe: max string size */
+ return static_cast(i); /* safe: max string size */
}
}
return -1;
@@ -934,7 +934,7 @@ struct ManualCmp {
};
template
-static jsint
+static int
UnrolledMatch(const jschar *text, jsuint textlen, const jschar *pat, jsuint patlen)
{
JS_ASSERT(patlen > 0 && textlen > 0);
@@ -979,7 +979,7 @@ UnrolledMatch(const jschar *text, jsuint textlen, const jschar *pat, jsuint patl
return -1;
}
-static JS_ALWAYS_INLINE jsint
+static JS_ALWAYS_INLINE int
StringMatch(const jschar *text, jsuint textlen,
const jschar *pat, jsuint patlen)
{
@@ -1017,7 +1017,7 @@ StringMatch(const jschar *text, jsuint textlen,
* empirically. See bug 526348.
*/
if (textlen >= 512 && patlen >= 11 && patlen <= sBMHPatLenMax) {
- jsint index = js_BoyerMooreHorspool(text, textlen, pat, patlen);
+ int index = js_BoyerMooreHorspool(text, textlen, pat, patlen);
if (index != sBMHBadPattern)
return index;
}
@@ -1044,7 +1044,7 @@ static const size_t sRopeMatchThresholdRatioLog2 = 5;
* the 'match' outparam (-1 for not found).
*/
static bool
-RopeMatch(JSContext *cx, JSString *textstr, const jschar *pat, jsuint patlen, jsint *match)
+RopeMatch(JSContext *cx, JSString *textstr, const jschar *pat, jsuint patlen, int *match)
{
JS_ASSERT(textstr->isRope());
@@ -1090,14 +1090,14 @@ RopeMatch(JSContext *cx, JSString *textstr, const jschar *pat, jsuint patlen, js
}
/* Absolute offset from the beginning of the logical string textstr. */
- jsint pos = 0;
+ int pos = 0;
for (JSLinearString **outerp = strs.begin(); outerp != strs.end(); ++outerp) {
/* Try to find a match within 'outer'. */
JSLinearString *outer = *outerp;
const jschar *chars = outer->chars();
size_t len = outer->length();
- jsint matchResult = StringMatch(chars, len, pat, patlen);
+ int matchResult = StringMatch(chars, len, pat, patlen);
if (matchResult != -1) {
/* Matched! */
*match = pos + matchResult;
@@ -1166,7 +1166,7 @@ str_indexOf(JSContext *cx, unsigned argc, Value *vp)
jsuint start;
if (args.length() > 1) {
if (args[1].isInt32()) {
- jsint i = args[1].toInt32();
+ int i = args[1].toInt32();
if (i <= 0) {
start = 0;
} else if (jsuint(i) > textlen) {
@@ -1187,7 +1187,7 @@ str_indexOf(JSContext *cx, unsigned argc, Value *vp)
start = textlen;
textlen = 0;
} else {
- start = (jsint)d;
+ start = (int)d;
text += start;
textlen -= start;
}
@@ -1196,7 +1196,7 @@ str_indexOf(JSContext *cx, unsigned argc, Value *vp)
start = 0;
}
- jsint match = StringMatch(text, textlen, pat, patlen);
+ int match = StringMatch(text, textlen, pat, patlen);
args.rval() = Int32Value((match == -1) ? -1 : start + match);
return true;
}
@@ -1221,7 +1221,7 @@ str_lastIndexOf(JSContext *cx, unsigned argc, Value *vp)
size_t patlen = patstr->length();
const jschar *pat = patstr->chars();
- jsint i = textlen - patlen; // Start searching here
+ int i = textlen - patlen; // Start searching here
if (i < 0) {
args.rval() = Int32Value(-1);
return true;
@@ -1229,7 +1229,7 @@ str_lastIndexOf(JSContext *cx, unsigned argc, Value *vp)
if (args.length() > 1) {
if (args[1].isInt32()) {
- jsint j = args[1].toInt32();
+ int j = args[1].toInt32();
if (j <= 0)
i = 0;
else if (j < i)
@@ -1243,7 +1243,7 @@ str_lastIndexOf(JSContext *cx, unsigned argc, Value *vp)
if (d <= 0)
i = 0;
else if (d < i)
- i = (jsint)d;
+ i = (int)d;
}
}
}
@@ -1717,7 +1717,7 @@ struct ReplaceData
JSLinearString *repstr; /* replacement string */
const jschar *dollar; /* null or pointer to first $ in repstr */
const jschar *dollarEnd; /* limit pointer for js_strchr_limit */
- jsint leftIndex; /* left context index in str->chars */
+ int leftIndex; /* left context index in str->chars */
JSSubString dollarStr; /* for "$$" InterpretDollar result */
bool calledBack; /* record whether callback has been called */
InvokeArgsGuard args; /* arguments for lambda call */
@@ -2528,7 +2528,7 @@ class SplitStringMatcher
{
JS_ASSERT(index == 0 || index < str->length());
const jschar *chars = str->chars();
- jsint match = StringMatch(chars + index, str->length() - index, sepChars, sepLength);
+ int match = StringMatch(chars + index, str->length() - index, sepChars, sepLength);
if (match == -1)
res->setFailure();
else
diff --git a/js/src/jsstrinlines.h b/js/src/jsstrinlines.h
index e7f082e526b8..576e90d9604b 100644
--- a/js/src/jsstrinlines.h
+++ b/js/src/jsstrinlines.h
@@ -117,7 +117,7 @@ class StringBuffer
const jschar *begin() const { return cb.begin(); }
const jschar *end() const { return cb.end(); }
bool empty() const { return cb.empty(); }
- inline jsint length() const;
+ inline int length() const;
/*
* Creates a string from the characters in this buffer, then (regardless
@@ -216,12 +216,12 @@ StringBuffer::appendInflated(const char *cstr, size_t cstrlen)
return true;
}
-inline jsint
+inline int
StringBuffer::length() const
{
- JS_STATIC_ASSERT(jsint(JSString::MAX_LENGTH) == JSString::MAX_LENGTH);
+ JS_STATIC_ASSERT(int(JSString::MAX_LENGTH) == JSString::MAX_LENGTH);
JS_ASSERT(cb.length() <= JSString::MAX_LENGTH);
- return jsint(cb.length());
+ return int(cb.length());
}
inline bool
diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp
index 8376f59b54a1..99e87fe9b041 100644
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -156,7 +156,7 @@ ArrayBuffer::prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp
vp->setInt32(0);
return true;
}
- vp->setInt32(jsint(arrayBuffer->arrayBufferByteLength()));
+ vp->setInt32(int32_t(arrayBuffer->arrayBufferByteLength()));
return true;
}
@@ -2542,7 +2542,7 @@ JS_NewArrayBuffer(JSContext *cx, jsuint nbytes)
}
static inline JSObject *
-TypedArrayConstruct(JSContext *cx, jsint atype, unsigned argc, Value *argv)
+TypedArrayConstruct(JSContext *cx, int atype, unsigned argc, Value *argv)
{
switch (atype) {
case TypedArray::TYPE_INT8:
@@ -2579,7 +2579,7 @@ TypedArrayConstruct(JSContext *cx, jsint atype, unsigned argc, Value *argv)
}
JS_FRIEND_API(JSObject *)
-js_CreateTypedArray(JSContext *cx, jsint atype, jsuint nelements)
+js_CreateTypedArray(JSContext *cx, int atype, jsuint nelements)
{
JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX);
@@ -2588,7 +2588,7 @@ js_CreateTypedArray(JSContext *cx, jsint atype, jsuint nelements)
}
JS_FRIEND_API(JSObject *)
-js_CreateTypedArrayWithArray(JSContext *cx, jsint atype, JSObject *arrayArg)
+js_CreateTypedArrayWithArray(JSContext *cx, int atype, JSObject *arrayArg)
{
JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX);
@@ -2597,8 +2597,8 @@ js_CreateTypedArrayWithArray(JSContext *cx, jsint atype, JSObject *arrayArg)
}
JS_FRIEND_API(JSObject *)
-js_CreateTypedArrayWithBuffer(JSContext *cx, jsint atype, JSObject *bufArg,
- jsint byteoffset, jsint length)
+js_CreateTypedArrayWithBuffer(JSContext *cx, int atype, JSObject *bufArg,
+ int byteoffset, int length)
{
JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX);
JS_ASSERT(bufArg && js_IsArrayBuffer(bufArg));
diff --git a/js/src/jstypedarray.h b/js/src/jstypedarray.h
index ef24ae934b9b..d19194f98844 100644
--- a/js/src/jstypedarray.h
+++ b/js/src/jstypedarray.h
@@ -307,7 +307,7 @@ js_CreateArrayBuffer(JSContext *cx, uint32_t nbytes);
* enumerant values above), with nelements elements.
*/
JS_FRIEND_API(JSObject *)
-js_CreateTypedArray(JSContext *cx, jsint atype, uint32_t nelements);
+js_CreateTypedArray(JSContext *cx, int atype, uint32_t nelements);
/*
* Create a new typed array of type atype (one of the TypedArray
@@ -315,7 +315,7 @@ js_CreateTypedArray(JSContext *cx, jsint atype, uint32_t nelements);
* which must either be a typed array or an array-like object.
*/
JS_FRIEND_API(JSObject *)
-js_CreateTypedArrayWithArray(JSContext *cx, jsint atype, JSObject *arrayArg);
+js_CreateTypedArrayWithArray(JSContext *cx, int atype, JSObject *arrayArg);
/*
* Create a new typed array of type atype (one of the TypedArray
@@ -325,8 +325,8 @@ js_CreateTypedArrayWithArray(JSContext *cx, jsint atype, JSObject *arrayArg);
* array are used as the default values.
*/
JS_FRIEND_API(JSObject *)
-js_CreateTypedArrayWithBuffer(JSContext *cx, jsint atype, JSObject *bufArg,
- jsint byteoffset, jsint length);
+js_CreateTypedArrayWithBuffer(JSContext *cx, int atype, JSObject *bufArg,
+ int byteoffset, int length);
extern int32_t JS_FASTCALL
js_TypedArray_uint8_clamp_double(const double x);
diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp
index 30555b064676..0c4e3fdee6aa 100644
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -4668,8 +4668,7 @@ static bool
IdValIsIndex(JSContext *cx, jsval id, jsuint *indexp, bool *isIndex)
{
if (JSVAL_IS_INT(id)) {
- jsint i;
- i = JSVAL_TO_INT(id);
+ int32_t i = JSVAL_TO_INT(id);
if (i < 0) {
*isIndex = false;
return true;
@@ -5602,7 +5601,7 @@ static JSBool
ValueToId(JSContext *cx, jsval v, AutoIdRooter *idr)
{
if (JSVAL_IS_INT(v)) {
- jsint i = JSVAL_TO_INT(v);
+ int32_t i = JSVAL_TO_INT(v);
if (INT_FITS_IN_JSID(i))
*idr->addr() = INT_TO_JSID(i);
else if (!js_ValueToStringId(cx, v, idr->addr()))
diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp
index 900dde1c6e48..6b050655d4d9 100644
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -734,9 +734,9 @@ MakeJITScript(JSContext *cx, JSScript *script, bool construct)
jsbytecode *pc2 = pc;
unsigned defaultOffset = offset + GET_JUMP_OFFSET(pc);
pc2 += JUMP_OFFSET_LEN;
- jsint low = GET_JUMP_OFFSET(pc2);
+ int32_t low = GET_JUMP_OFFSET(pc2);
pc2 += JUMP_OFFSET_LEN;
- jsint high = GET_JUMP_OFFSET(pc2);
+ int32_t high = GET_JUMP_OFFSET(pc2);
pc2 += JUMP_OFFSET_LEN;
CrossChunkEdge edge;
@@ -745,7 +745,7 @@ MakeJITScript(JSContext *cx, JSScript *script, bool construct)
if (!currentEdges.append(edge))
return NULL;
- for (jsint i = low; i <= high; i++) {
+ for (int32_t i = low; i <= high; i++) {
unsigned targetOffset = offset + GET_JUMP_OFFSET(pc2);
if (targetOffset != offset) {
/*
@@ -3781,6 +3781,21 @@ mjit::Compiler::emitReturn(FrameEntry *fe)
JS_ASSERT_IF(fe, fe == frame.peek(-1));
if (debugMode() || Probes::callTrackingActive(cx)) {
+ /* If the return value isn't in the frame's rval slot, move it there. */
+ if (fe) {
+ frame.storeTo(fe, Address(JSFrameReg, StackFrame::offsetOfReturnValue()), true);
+
+ /* Set the frame flag indicating it's there. */
+ RegisterID reg = frame.allocReg();
+ masm.load32(FrameFlagsAddress(), reg);
+ masm.or32(Imm32(StackFrame::HAS_RVAL), reg);
+ masm.store32(reg, FrameFlagsAddress());
+ frame.freeReg(reg);
+
+ /* Use the frame's return value when generating further code. */
+ fe = NULL;
+ }
+
prepareStubCall(Uses(0));
INLINE_STUBCALL(stubs::ScriptDebugEpilogue, REJOIN_RESUME);
}
@@ -7332,9 +7347,9 @@ mjit::Compiler::jsop_tableswitch(jsbytecode *pc)
uint32_t defaultTarget = GET_JUMP_OFFSET(pc);
pc += JUMP_OFFSET_LEN;
- jsint low = GET_JUMP_OFFSET(pc);
+ int32_t low = GET_JUMP_OFFSET(pc);
pc += JUMP_OFFSET_LEN;
- jsint high = GET_JUMP_OFFSET(pc);
+ int32_t high = GET_JUMP_OFFSET(pc);
pc += JUMP_OFFSET_LEN;
int numJumps = high + 1 - low;
JS_ASSERT(numJumps >= 0);
diff --git a/js/src/methodjit/InvokeHelpers.cpp b/js/src/methodjit/InvokeHelpers.cpp
index 5ac2418a8623..a66c8eb8b8c9 100644
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -566,17 +566,23 @@ js_InternalThrow(VMFrame &f)
if (pc)
break;
- // The JIT guarantees that ScriptEpilogue() has always been run
- // upon exiting to its caller. This is important for consistency,
- // where execution modes make similar guarantees about prologues
- // and epilogues. RunTracer(), Interpret(), and Invoke() all
- // rely on this property.
+ // The JIT guarantees that ScriptDebugEpilogue() and ScriptEpilogue()
+ // have always been run upon exiting to its caller. This is important
+ // for consistency, where execution modes make similar guarantees about
+ // prologues and epilogues. Interpret(), and Invoke() all rely on this
+ // property.
JS_ASSERT(!f.fp()->finishedInInterpreter());
UnwindScope(cx, 0);
f.regs.sp = f.fp()->base();
- if (cx->compartment->debugMode())
- js::ScriptDebugEpilogue(cx, f.fp(), false);
+ if (cx->compartment->debugMode()) {
+ // This can turn a throw or error into a healthy return. Note that
+ // we will run ScriptDebugEpilogue again (from AnyFrameEpilogue);
+ // ScriptDebugEpilogue is prepared for this eventuality.
+ if (js::ScriptDebugEpilogue(cx, f.fp(), false))
+ return cx->jaegerCompartment()->forceReturnFromExternC();
+ }
+
ScriptEpilogue(f.cx, f.fp(), false);
diff --git a/js/src/methodjit/StubCalls.cpp b/js/src/methodjit/StubCalls.cpp
index ba30084046bf..ea229603035c 100644
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -235,7 +235,7 @@ stubs::SetElem(VMFrame &f)
do {
if (obj->isDenseArray() && JSID_IS_INT(id)) {
jsuint length = obj->getDenseArrayInitializedLength();
- jsint i = JSID_TO_INT(id);
+ int32_t i = JSID_TO_INT(id);
if ((jsuint)i < length) {
if (obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) {
if (js_PrototypeHasIndexedProperties(cx, obj))
@@ -1578,9 +1578,9 @@ stubs::TableSwitch(VMFrame &f, jsbytecode *origPc)
}
{
- jsint low = GET_JUMP_OFFSET(pc);
+ int32_t low = GET_JUMP_OFFSET(pc);
pc += JUMP_OFFSET_LEN;
- jsint high = GET_JUMP_OFFSET(pc);
+ int32_t high = GET_JUMP_OFFSET(pc);
pc += JUMP_OFFSET_LEN;
tableIdx -= low;
@@ -1928,7 +1928,7 @@ stubs::ConvertToTypedInt(JSContext *cx, Value *vp)
#ifdef DEBUG
bool success =
#endif
- StringToNumberType(cx, vp->toString(), &i32);
+ StringToNumberType(cx, vp->toString(), &i32);
JS_ASSERT(success);
return i32;
diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp
index 1de2ec70ba52..655049804981 100644
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -866,8 +866,7 @@ Evaluate(JSContext *cx, unsigned argc, jsval *vp)
return false;
}
- JS_SET_RVAL(cx, vp, JSVAL_VOID);
- return JS_EvaluateUCScript(cx, thisobj, codeChars, codeLength, "@evaluate", 0, NULL);
+ return JS_EvaluateUCScript(cx, thisobj, codeChars, codeLength, "@evaluate", 0, vp);
}
static JSString *
@@ -1910,7 +1909,7 @@ UpdateSwitchTableBounds(JSContext *cx, JSScript *script, unsigned offset,
jsbytecode *pc;
JSOp op;
ptrdiff_t jmplen;
- jsint low, high, n;
+ int32_t low, high, n;
pc = script->code + offset;
op = JSOp(*pc);
diff --git a/js/src/tests/e4x/Regress/regress-308111.js b/js/src/tests/e4x/Regress/regress-308111.js
index 88a8ff6dc0f7..d1c01d3bcdab 100644
--- a/js/src/tests/e4x/Regress/regress-308111.js
+++ b/js/src/tests/e4x/Regress/regress-308111.js
@@ -757,7 +757,6 @@ var xml =
extensions.ignoreMTimeChanges
network.hosts.pop_server
privacy.item.history
-editor.quotesPreformatted
security.password_lifetime
security.ssl3.dhe_dss_aes_128_sha
font.name.monospace.x-tamil
diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp
index b4b682f3a375..70338819f2cf 100644
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -68,6 +68,7 @@ enum {
JSSLOT_DEBUGFRAME_OWNER,
JSSLOT_DEBUGFRAME_ARGUMENTS,
JSSLOT_DEBUGFRAME_ONSTEP_HANDLER,
+ JSSLOT_DEBUGFRAME_ONPOP_HANDLER,
JSSLOT_DEBUGFRAME_COUNT
};
@@ -143,6 +144,110 @@ ValueToIdentifier(JSContext *cx, const Value &v, jsid *idp)
return true;
}
+/*
+ * A range of all the Debugger.Frame objects for a particular StackFrame.
+ *
+ * FIXME This checks only current debuggers, so it relies on a hack in
+ * Debugger::removeDebuggeeGlobal to make sure only current debuggers have Frame
+ * objects with .live === true.
+ */
+class Debugger::FrameRange {
+ JSContext *cx;
+ StackFrame *fp;
+
+ /* The debuggers in |fp|'s compartment, or NULL if there are none. */
+ GlobalObject::DebuggerVector *debuggers;
+
+ /*
+ * The index of the front Debugger.Frame's debugger in debuggers.
+ * nextDebugger < debuggerCount if and only if the range is not empty.
+ */
+ size_t debuggerCount, nextDebugger;
+
+ /*
+ * If the range is not empty, this is front Debugger.Frame's entry in its
+ * debugger's frame table.
+ */
+ FrameMap::Ptr entry;
+
+ public:
+ /*
+ * Return a range containing all Debugger.Frame instances referring to |fp|.
+ * |global| is |fp|'s global object; if NULL or omitted, we compute it
+ * ourselves from |fp|.
+ *
+ * We keep an index into the compartment's debugger list, and a
+ * FrameMap::Ptr into the current debugger's frame map. Thus, if the set of
+ * debuggers in |fp|'s compartment changes, this range becomes invalid.
+ * Similarly, if stack frames are added to or removed from frontDebugger(),
+ * then the range's front is invalid until popFront is called.
+ */
+ FrameRange(JSContext *cx, StackFrame *fp, GlobalObject *global = NULL)
+ : cx(cx), fp(fp) {
+ nextDebugger = 0;
+
+ /* Find our global, if we were not given one. */
+ if (!global)
+ global = &fp->scopeChain().global();
+
+ /* The frame and global must match. */
+ JS_ASSERT(&fp->scopeChain().global() == global);
+
+ /* Find the list of debuggers we'll iterate over. There may be none. */
+ debuggers = global->getDebuggers();
+ if (debuggers) {
+ debuggerCount = debuggers->length();
+ findNext();
+ } else {
+ debuggerCount = 0;
+ }
+ }
+
+ bool empty() const {
+ return nextDebugger >= debuggerCount;
+ }
+
+ JSObject *frontFrame() const {
+ JS_ASSERT(!empty());
+ return entry->value;
+ }
+
+ Debugger *frontDebugger() const {
+ JS_ASSERT(!empty());
+ return (*debuggers)[nextDebugger];
+ }
+
+ /*
+ * Delete the front frame from its Debugger's frame map. After this call,
+ * the range's front is invalid until popFront is called.
+ */
+ void removeFrontFrame() const {
+ JS_ASSERT(!empty());
+ frontDebugger()->frames.remove(entry);
+ }
+
+ void popFront() {
+ JS_ASSERT(!empty());
+ nextDebugger++;
+ findNext();
+ }
+
+ private:
+ /*
+ * Either make this range refer to the first appropriate Debugger.Frame at
+ * or after nextDebugger, or make it empty.
+ */
+ void findNext() {
+ while (!empty()) {
+ Debugger *dbg = (*debuggers)[nextDebugger];
+ entry = dbg->frames.lookup(fp);
+ if (entry)
+ break;
+ nextDebugger++;
+ }
+ }
+};
+
/*** Breakpoints *********************************************************************************/
@@ -419,7 +524,9 @@ Debugger::hasAnyLiveHooks() const
}
for (FrameMap::Range r = frames.all(); !r.empty(); r.popFront()) {
- if (!r.front().value->getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER).isUndefined())
+ JSObject *frameObj = r.front().value;
+ if (!frameObj->getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER).isUndefined() ||
+ !frameObj->getReservedSlot(JSSLOT_DEBUGFRAME_ONPOP_HANDLER).isUndefined())
return true;
}
@@ -454,36 +561,98 @@ Debugger::slowPathOnEnterFrame(JSContext *cx, Value *vp)
return JSTRAP_CONTINUE;
}
-void
-Debugger::slowPathOnLeaveFrame(JSContext *cx)
+/*
+ * Handle leaving a frame with debuggers watching. |frameOk| indicates whether
+ * the frame is exiting normally or abruptly. Set |cx|'s exception and/or
+ * |cx->fp()|'s return value, and return a new success value.
+ */
+bool
+Debugger::slowPathOnLeaveFrame(JSContext *cx, bool frameOk)
{
StackFrame *fp = cx->fp();
GlobalObject *global = &fp->scopeChain().global();
- /*
- * FIXME This notifies only current debuggers, so it relies on a hack in
- * Debugger::removeDebuggeeGlobal to make sure only current debuggers have
- * Frame objects with .live === true.
- */
- if (GlobalObject::DebuggerVector *debuggers = global->getDebuggers()) {
- for (Debugger **p = debuggers->begin(); p != debuggers->end(); p++) {
- Debugger *dbg = *p;
- if (FrameMap::Ptr p = dbg->frames.lookup(fp)) {
- StackFrame *frame = p->key;
- JSObject *frameobj = p->value;
- frameobj->setPrivate(NULL);
+ /* Save the frame's completion value. */
+ JSTrapStatus status;
+ Value value;
+ Debugger::resultToCompletion(cx, frameOk, fp->returnValue(), &status, &value);
- /* If this frame had an onStep handler, adjust the script's count. */
- if (!frameobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER).isUndefined() &&
- frame->isScriptFrame()) {
- frame->script()->changeStepModeCount(cx, -1);
- }
+ /* Build a list of the recipients. */
+ AutoObjectVector frames(cx);
+ for (FrameRange r(cx, fp, global); !r.empty(); r.popFront()) {
+ if (!frames.append(r.frontFrame())) {
+ cx->clearPendingException();
+ return false;
+ }
+ }
- dbg->frames.remove(p);
+ /* For each Debugger.Frame, fire its onPop handler, if any. */
+ for (JSObject **p = frames.begin(); p != frames.end(); p++) {
+ JSObject *frameobj = *p;
+ Debugger *dbg = Debugger::fromChildJSObject(frameobj);
+
+ if (dbg->enabled &&
+ !frameobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONPOP_HANDLER).isUndefined()) {
+ const Value &handler = frameobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONPOP_HANDLER);
+
+ AutoCompartment ac(cx, dbg->object);
+
+ if (!ac.enter()) {
+ status = JSTRAP_ERROR;
+ break;
+ }
+
+ Value completion;
+ if (!dbg->newCompletionValue(cx, status, value, &completion)) {
+ status = dbg->handleUncaughtException(ac, NULL, false);
+ break;
+ }
+
+ /* Call the onPop handler. */
+ Value rval;
+ bool hookOk = Invoke(cx, ObjectValue(*frameobj), handler, 1, &completion, &rval);
+ Value nextValue;
+ JSTrapStatus nextStatus = dbg->parseResumptionValue(ac, hookOk, rval, &nextValue);
+
+ /*
+ * At this point, we are back in the debuggee compartment, and any error has
+ * been wrapped up as a completion value.
+ */
+ JS_ASSERT(cx->compartment == global->compartment());
+ JS_ASSERT(!cx->isExceptionPending());
+
+ /* JSTRAP_CONTINUE means "make no change". */
+ if (nextStatus != JSTRAP_CONTINUE) {
+ status = nextStatus;
+ value = nextValue;
}
}
}
+ /*
+ * Clean up all Debugger.Frame instances. Use a fresh FrameRange, as one
+ * debugger's onPop handler could have caused another debugger to create its
+ * own Debugger.Frame instance.
+ */
+ for (FrameRange r(cx, fp, global); !r.empty(); r.popFront()) {
+ JSObject *frameobj = r.frontFrame();
+ Debugger *dbg = r.frontDebugger();
+ JS_ASSERT(dbg == Debugger::fromChildJSObject(frameobj));
+
+ frameobj->setPrivate(NULL);
+
+ /* If this frame had an onStep handler, adjust the script's count. */
+ if (!frameobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER).isUndefined() &&
+ fp->isScriptFrame() &&
+ !fp->script()->changeStepModeCount(cx, -1))
+ {
+ status = JSTRAP_ERROR;
+ /* Don't exit the loop; we must mark all frames as dead. */
+ }
+
+ dbg->frames.remove(fp);
+ }
+
/*
* If this is an eval frame, then from the debugger's perspective the
* script is about to be destroyed. Remove any breakpoints in it.
@@ -492,6 +661,24 @@ Debugger::slowPathOnLeaveFrame(JSContext *cx)
JSScript *script = fp->script();
script->clearBreakpointsIn(cx, NULL, NULL);
}
+
+ /* Establish (status, value) as our resumption value. */
+ switch (status) {
+ case JSTRAP_RETURN:
+ fp->setReturnValue(value);
+ return true;
+
+ case JSTRAP_THROW:
+ cx->setPendingException(value);
+ return false;
+
+ case JSTRAP_ERROR:
+ JS_ASSERT(!cx->isExceptionPending());
+ return false;
+
+ default:
+ JS_NOT_REACHED("bad final trap status");
+ }
}
bool
@@ -606,39 +793,79 @@ Debugger::handleUncaughtException(AutoCompartment &ac, Value *vp, bool callHook)
return JSTRAP_ERROR;
}
-bool
-Debugger::newCompletionValue(AutoCompartment &ac, bool ok, Value val, Value *vp)
+void
+Debugger::resultToCompletion(JSContext *cx, bool ok, const Value &rv,
+ JSTrapStatus *status, Value *value)
{
- JS_ASSERT_IF(ok, !ac.context->isExceptionPending());
+ JS_ASSERT_IF(ok, !cx->isExceptionPending());
- JSContext *cx = ac.context;
- jsid key;
if (ok) {
- ac.leave();
- key = ATOM_TO_JSID(cx->runtime->atomState.returnAtom);
+ *status = JSTRAP_RETURN;
+ *value = rv;
} else if (cx->isExceptionPending()) {
- key = ATOM_TO_JSID(cx->runtime->atomState.throwAtom);
- val = cx->getPendingException();
+ *status = JSTRAP_THROW;
+ *value = cx->getPendingException();
cx->clearPendingException();
- ac.leave();
} else {
- ac.leave();
- vp->setNull();
+ *status = JSTRAP_ERROR;
+ value->setUndefined();
+ }
+}
+
+bool
+Debugger::newCompletionValue(JSContext *cx, JSTrapStatus status, Value value, Value *result)
+{
+ /*
+ * We must be in the debugger's compartment, since that's where we want
+ * to construct the completion value.
+ */
+ assertSameCompartment(cx, object.get());
+
+ jsid key;
+
+ switch (status) {
+ case JSTRAP_RETURN:
+ key = ATOM_TO_JSID(cx->runtime->atomState.returnAtom);
+ break;
+
+ case JSTRAP_THROW:
+ key = ATOM_TO_JSID(cx->runtime->atomState.throwAtom);
+ break;
+
+ case JSTRAP_ERROR:
+ result->setNull();
return true;
+
+ default:
+ JS_NOT_REACHED("bad status passed to Debugger::newCompletionValue");
}
+ /* Common tail for JSTRAP_RETURN and JSTRAP_THROW. */
JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass);
if (!obj ||
- !wrapDebuggeeValue(cx, &val) ||
- !DefineNativeProperty(cx, obj, key, val, JS_PropertyStub, JS_StrictPropertyStub,
+ !wrapDebuggeeValue(cx, &value) ||
+ !DefineNativeProperty(cx, obj, key, value, JS_PropertyStub, JS_StrictPropertyStub,
JSPROP_ENUMERATE, 0, 0))
{
return false;
}
- vp->setObject(*obj);
+
+ result->setObject(*obj);
return true;
}
+bool
+Debugger::receiveCompletionValue(AutoCompartment &ac, bool ok, Value val, Value *vp)
+{
+ JSContext *cx = ac.context;
+
+ JSTrapStatus status;
+ Value value;
+ resultToCompletion(cx, ok, val, &status, &value);
+ ac.leave();
+ return newCompletionValue(cx, status, value, vp);
+}
+
JSTrapStatus
Debugger::parseResumptionValue(AutoCompartment &ac, bool ok, const Value &rv, Value *vp,
bool callHook)
@@ -975,16 +1202,12 @@ Debugger::onSingleStep(JSContext *cx, Value *vp)
* onStep handlers.
*/
AutoObjectVector frames(cx);
- GlobalObject *global = &fp->scopeChain().global();
- if (GlobalObject::DebuggerVector *debuggers = global->getDebuggers()) {
- for (Debugger **d = debuggers->begin(); d != debuggers->end(); d++) {
- Debugger *dbg = *d;
- if (FrameMap::Ptr p = dbg->frames.lookup(fp)) {
- JSObject *frame = p->value;
- if (!frame->getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER).isUndefined() &&
- !frames.append(frame))
- return JSTRAP_ERROR;
- }
+ for (FrameRange r(cx, fp); !r.empty(); r.popFront()) {
+ JSObject *frame = r.frontFrame();
+ if (!frame->getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER).isUndefined() &&
+ !frames.append(frame))
+ {
+ return JSTRAP_ERROR;
}
}
@@ -1001,6 +1224,7 @@ Debugger::onSingleStep(JSContext *cx, Value *vp)
{
uint32_t stepperCount = 0;
JSScript *trappingScript = fp->script();
+ GlobalObject *global = &fp->scopeChain().global();
if (GlobalObject::DebuggerVector *debuggers = global->getDebuggers()) {
for (Debugger **p = debuggers->begin(); p != debuggers->end(); p++) {
Debugger *dbg = *p;
@@ -2146,19 +2370,19 @@ class FlowGraphSummary : public Vector {
pc += step;
addEdge(lineno, defaultOffset);
- jsint ncases;
+ int ncases;
if (op == JSOP_TABLESWITCH) {
- jsint low = GET_JUMP_OFFSET(pc);
+ int32_t low = GET_JUMP_OFFSET(pc);
pc += JUMP_OFFSET_LEN;
ncases = GET_JUMP_OFFSET(pc) - low + 1;
pc += JUMP_OFFSET_LEN;
} else {
- ncases = (jsint) GET_UINT16(pc);
+ ncases = GET_UINT16(pc);
pc += UINT16_LEN;
JS_ASSERT(ncases > 0);
}
- for (jsint i = 0; i < ncases; i++) {
+ for (int i = 0; i < ncases; i++) {
if (op == JSOP_LOOKUPSWITCH)
pc += UINT32_INDEX_LEN;
size_t target = offset + GET_JUMP_OFFSET(pc);
@@ -2784,6 +3008,36 @@ DebuggerFrame_setOnStep(JSContext *cx, unsigned argc, Value *vp)
return true;
}
+static JSBool
+DebuggerFrame_getOnPop(JSContext *cx, unsigned argc, Value *vp)
+{
+ THIS_FRAME(cx, argc, vp, "get onPop", args, thisobj, fp);
+ (void) fp; // Silence GCC warning
+ Value handler = thisobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONPOP_HANDLER);
+ JS_ASSERT(IsValidHook(handler));
+ args.rval() = handler;
+ return true;
+}
+
+static JSBool
+DebuggerFrame_setOnPop(JSContext *cx, unsigned argc, Value *vp)
+{
+ REQUIRE_ARGC("Debugger.Frame.set onPop", 1);
+ THIS_FRAME(cx, argc, vp, "set onPop", args, thisobj, fp);
+ if (!fp->isScriptFrame()) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEBUG_NOT_SCRIPT_FRAME);
+ return false;
+ }
+ if (!IsValidHook(args[0])) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_CALLABLE_OR_UNDEFINED);
+ return false;
+ }
+
+ thisobj->setReservedSlot(JSSLOT_DEBUGFRAME_ONPOP_HANDLER, args[0]);
+ args.rval().setUndefined();
+ return true;
+}
+
namespace js {
JSBool
@@ -2895,7 +3149,7 @@ DebuggerFrameEval(JSContext *cx, unsigned argc, Value *vp, EvalBindingsMode mode
JS::Anchor anchor(linearStr);
bool ok = EvaluateInEnv(cx, env, fp, linearStr->chars(), linearStr->length(),
"debugger eval code", 1, &rval);
- return dbg->newCompletionValue(ac, ok, rval, vp);
+ return dbg->receiveCompletionValue(ac, ok, rval, vp);
}
static JSBool
@@ -2930,6 +3184,7 @@ static JSPropertySpec DebuggerFrame_properties[] = {
JS_PSG("this", DebuggerFrame_getThis, 0),
JS_PSG("type", DebuggerFrame_getType, 0),
JS_PSGS("onStep", DebuggerFrame_getOnStep, DebuggerFrame_setOnStep, 0),
+ JS_PSGS("onPop", DebuggerFrame_getOnPop, DebuggerFrame_setOnPop, 0),
JS_PS_END
};
@@ -3533,12 +3788,12 @@ ApplyOrCall(JSContext *cx, unsigned argc, Value *vp, ApplyOrCallMode mode)
}
/*
- * Call the function. Use newCompletionValue to return to the debugger
+ * Call the function. Use receiveCompletionValue to return to the debugger
* compartment and populate args.rval().
*/
Value rval;
bool ok = Invoke(cx, thisv, calleev, callArgc, callArgv, &rval);
- return dbg->newCompletionValue(ac, ok, rval, &args.rval());
+ return dbg->receiveCompletionValue(ac, ok, rval, &args.rval());
}
static JSBool
diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h
index d74163622835..e130da46b561 100644
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -119,6 +119,8 @@ class Debugger {
/* The map from debuggee Envs to Debugger.Environment instances. */
ObjectWeakMap environments;
+ class FrameRange;
+
bool addDebuggeeGlobal(JSContext *cx, GlobalObject *obj);
void removeDebuggeeGlobal(JSContext *cx, GlobalObject *global,
GlobalObjectSet::Enum *compartmentEnum,
@@ -206,7 +208,7 @@ class Debugger {
bool hasAnyLiveHooks() const;
static JSTrapStatus slowPathOnEnterFrame(JSContext *cx, Value *vp);
- static void slowPathOnLeaveFrame(JSContext *cx);
+ static bool slowPathOnLeaveFrame(JSContext *cx, bool ok);
static void slowPathOnNewScript(JSContext *cx, JSScript *script,
GlobalObject *compileAndGoGlobal);
static JSTrapStatus dispatchHook(JSContext *cx, Value *vp, Hook which);
@@ -264,7 +266,7 @@ class Debugger {
GlobalObjectSet::Enum *compartmentEnum);
static inline JSTrapStatus onEnterFrame(JSContext *cx, Value *vp);
- static inline void onLeaveFrame(JSContext *cx);
+ static inline bool onLeaveFrame(JSContext *cx, bool ok);
static inline JSTrapStatus onDebuggerStatement(JSContext *cx, Value *vp);
static inline JSTrapStatus onExceptionUnwind(JSContext *cx, Value *vp);
static inline void onNewScript(JSContext *cx, JSScript *script,
@@ -329,6 +331,23 @@ class Debugger {
/* Store the Debugger.Frame object for the frame fp in *vp. */
bool getScriptFrame(JSContext *cx, StackFrame *fp, Value *vp);
+ /*
+ * Set |*status| and |*value| to a (JSTrapStatus, Value) pair reflecting a
+ * standard SpiderMonkey call state: a boolean success value |ok|, a return
+ * value |rv|, and a context |cx| that may or may not have an exception set.
+ * If an exception was pending on |cx|, it is cleared (and |ok| is asserted
+ * to be false).
+ */
+ static void resultToCompletion(JSContext *cx, bool ok, const Value &rv,
+ JSTrapStatus *status, Value *value);
+
+ /*
+ * Set |*result| to a JavaScript completion value corresponding to |status|
+ * and |value|. |value| should be the return value or exception value, not
+ * wrapped as a debuggee value. |cx| must be in the debugger compartment.
+ */
+ bool newCompletionValue(JSContext *cx, JSTrapStatus status, Value value, Value *result);
+
/*
* Precondition: we are in the debuggee compartment (ac is entered) and ok
* is true if the operation in the debuggee compartment succeeded, false on
@@ -341,7 +360,7 @@ class Debugger {
* pending exception. (This ordinarily returns true even if the ok argument
* is false.)
*/
- bool newCompletionValue(AutoCompartment &ac, bool ok, Value val, Value *vp);
+ bool receiveCompletionValue(AutoCompartment &ac, bool ok, Value val, Value *vp);
/*
* Return the Debugger.Script object for |script|, or create a new one if
@@ -503,14 +522,15 @@ Debugger::onEnterFrame(JSContext *cx, Value *vp)
return slowPathOnEnterFrame(cx, vp);
}
-void
-Debugger::onLeaveFrame(JSContext *cx)
+bool
+Debugger::onLeaveFrame(JSContext *cx, bool ok)
{
/* Traps must be cleared from eval frames, see slowPathOnLeaveFrame. */
bool evalTraps = cx->fp()->isEvalFrame() &&
cx->fp()->script()->hasAnyBreakpointsOrStepMode();
if (!cx->compartment->getDebuggees().empty() || evalTraps)
- slowPathOnLeaveFrame(cx);
+ ok = slowPathOnLeaveFrame(cx, ok);
+ return ok;
}
JSTrapStatus
diff --git a/js/src/vm/String-inl.h b/js/src/vm/String-inl.h
index aa2f92af1a2d..2fdea5081dd0 100644
--- a/js/src/vm/String-inl.h
+++ b/js/src/vm/String-inl.h
@@ -293,7 +293,7 @@ js::StaticStrings::hasInt(int32_t i)
}
inline JSAtom *
-js::StaticStrings::getInt(jsint i)
+js::StaticStrings::getInt(int32_t i)
{
JS_ASSERT(hasInt(i));
return getUint(uint32_t(i));
@@ -352,7 +352,7 @@ js::StaticStrings::lookup(const jschar *chars, size_t length)
if ('1' <= chars[0] && chars[0] <= '9' &&
'0' <= chars[1] && chars[1] <= '9' &&
'0' <= chars[2] && chars[2] <= '9') {
- jsint i = (chars[0] - '0') * 100 +
+ int i = (chars[0] - '0') * 100 +
(chars[1] - '0') * 10 +
(chars[2] - '0');
diff --git a/js/src/vm/String.cpp b/js/src/vm/String.cpp
index 963eb04cc4ae..3d60f495d1b0 100644
--- a/js/src/vm/String.cpp
+++ b/js/src/vm/String.cpp
@@ -529,7 +529,7 @@ StaticStrings::isStatic(JSAtom *atom)
if ('1' <= chars[0] && chars[0] <= '9' &&
'0' <= chars[1] && chars[1] <= '9' &&
'0' <= chars[2] && chars[2] <= '9') {
- jsint i = (chars[0] - '0') * 100 +
+ int i = (chars[0] - '0') * 100 +
(chars[1] - '0') * 10 +
(chars[2] - '0');
diff --git a/js/src/vm/String.h b/js/src/vm/String.h
index 65d913af2ac8..6480e16205b4 100644
--- a/js/src/vm/String.h
+++ b/js/src/vm/String.h
@@ -723,7 +723,7 @@ class StaticStrings
inline JSAtom *getUint(uint32_t u);
static inline bool hasInt(int32_t i);
- inline JSAtom *getInt(jsint i);
+ inline JSAtom *getInt(int32_t i);
static inline bool hasUnit(jschar c);
JSAtom *getUnit(jschar c);
diff --git a/js/xpconnect/src/dom_quickstubs.qsconf b/js/xpconnect/src/dom_quickstubs.qsconf
index 716647657742..3666343f8837 100644
--- a/js/xpconnect/src/dom_quickstubs.qsconf
+++ b/js/xpconnect/src/dom_quickstubs.qsconf
@@ -518,6 +518,7 @@ customIncludes = [
'nsINodeList.h',
'nsCSSPropertiesQS.h',
'nsDocument.h',
+ 'nsDOMTokenList.h',
'nsGenericDOMDataNode.h',
'nsGenericElement.h',
'nsGenericHTMLElement.h',
@@ -785,7 +786,7 @@ customMethodCalls = {
},
'nsIDOMElement_GetClassList': {
'thisType': 'nsGenericElement',
- 'code': ' nsIDOMDOMTokenList *result = self->GetClassList(&rv);'
+ 'code': ' nsDOMTokenList *result = self->GetClassList(&rv);'
},
'nsIDOMElement_SetCapture': {
'thisType': 'nsGenericElement',
diff --git a/js/xpconnect/src/dombindings.conf b/js/xpconnect/src/dombindings.conf
index b088dad64bd0..f4eba4c2476f 100644
--- a/js/xpconnect/src/dombindings.conf
+++ b/js/xpconnect/src/dombindings.conf
@@ -3,6 +3,10 @@ classes = {
'HTMLCollection': 'nsIHTMLCollection',
'HTMLOptionsCollection': 'nsHTMLOptionCollection',
}
+prefableClasses = {
+ 'DOMTokenList': 'nsDOMTokenList',
+ 'DOMSettableTokenList': 'nsDOMSettableTokenList',
+ }
irregularFilenames = {
'nsHTMLOptionCollection': 'nsHTMLSelectElement',
diff --git a/js/xpconnect/src/dombindings.cpp b/js/xpconnect/src/dombindings.cpp
index b65b42bbfa49..3c0b1e63b37c 100644
--- a/js/xpconnect/src/dombindings.cpp
+++ b/js/xpconnect/src/dombindings.cpp
@@ -431,20 +431,6 @@ interface_hasInstance(JSContext *cx, JSObject *obj, const JS::Value *vp, JSBool
return true;
}
-template
-JSObject *
-ListBase::getPrototype(JSContext *cx, XPCWrappedNativeScope *scope, bool *enabled)
-{
- if (!scope->NewDOMBindingsEnabled()) {
- *enabled = false;
- return NULL;
- }
-
- *enabled = true;
-
- return getPrototype(cx, scope);
-}
-
enum {
USE_CACHE = 0,
CHECK_CACHE = 1,
diff --git a/js/xpconnect/src/dombindings.h b/js/xpconnect/src/dombindings.h
index 0fe4d5c5e302..dbdedbffbc95 100644
--- a/js/xpconnect/src/dombindings.h
+++ b/js/xpconnect/src/dombindings.h
@@ -43,6 +43,7 @@
#include "jsapi.h"
#include "jsproxy.h"
#include "xpcpublic.h"
+#include "nsString.h"
namespace mozilla {
namespace dom {
@@ -212,7 +213,11 @@ public:
static JSObject *create(JSContext *cx, XPCWrappedNativeScope *scope, ListType *list,
nsWrapperCache* cache, bool *triedToWrap);
- static JSObject *getPrototype(JSContext *cx, XPCWrappedNativeScope *scope, bool *enabled);
+ static JSObject *getPrototype(JSContext *cx, XPCWrappedNativeScope *scope, bool *enabled)
+ {
+ *enabled = true;
+ return getPrototype(cx, scope);
+ }
bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
JSPropertyDescriptor *desc);
diff --git a/js/xpconnect/src/dombindingsgen.py b/js/xpconnect/src/dombindingsgen.py
index a283411d06b3..abc42e38a943 100644
--- a/js/xpconnect/src/dombindingsgen.py
+++ b/js/xpconnect/src/dombindingsgen.py
@@ -87,7 +87,7 @@ def firstCap(str):
return str[0].upper() + str[1:]
class DOMClass(UserDict.DictMixin):
- def __init__(self, name, nativeClass):
+ def __init__(self, name, nativeClass, prefable):
self.name = name
self.base = None
self.isBase = False
@@ -98,6 +98,7 @@ class DOMClass(UserDict.DictMixin):
self.nameSetter = None
self.stringifier = False
self.members = set()
+ self.prefable = prefable
@staticmethod
def getterNativeType(getter):
@@ -236,7 +237,10 @@ class Configuration:
raise UserError(filename + ": `%s` was not defined." % name)
self.classes = {}
for clazz in config['classes']:
- self.classes[clazz] = DOMClass(name=clazz, nativeClass=config['classes'][clazz])
+ self.classes[clazz] = DOMClass(name=clazz, nativeClass=config['classes'][clazz], prefable=False)
+ if 'prefableClasses' in config:
+ for clazz in config['prefableClasses']:
+ self.classes[clazz] = DOMClass(name=clazz, nativeClass=config['prefableClasses'][clazz], prefable=True)
# optional settings
self.customInheritance = config.get('customInheritance', {})
self.derivedClasses = {}
@@ -477,6 +481,21 @@ derivedClassTemplate = (
"}\n"
"\n")
+prefableClassTemplate = (
+"template<>\n"
+"JSObject *\n"
+"${name}Wrapper::getPrototype(JSContext *cx, XPCWrappedNativeScope *scope, bool *enabled)\n"
+"{\n"
+" if (!scope->NewDOMBindingsEnabled()) {\n"
+" *enabled = false;\n"
+" return NULL;\n"
+" }\n"
+"\n"
+" *enabled = true;\n"
+" return getPrototype(cx, scope);\n"
+"}\n"
+"\n")
+
toStringTemplate = (
"template<>\n"
"JSString *\n"
@@ -689,6 +708,8 @@ def writeStubFile(filename, config, interfaces):
checkproxyhandlers = "||\n".join(map(lambda d: " %sWrapper::proxyHandlerIsList(handler)" % d, derivedClasses))
castproxyhandlers = "\n".join(map(lambda d: " if (%sWrapper::proxyHandlerIsList(handler))\n return %sWrapper::getNative(obj);\n" % (d, d), derivedClasses))
f.write(string.Template(derivedClassTemplate).substitute(clazz, checkproxyhandlers=checkproxyhandlers, castproxyhandlers=castproxyhandlers))
+ if clazz.prefable:
+ f.write(string.Template(prefableClassTemplate).substitute(clazz))
methodsList = []
propertiesList = []
if clazz.stringifier:
diff --git a/layout/base/nsIPresShell.h b/layout/base/nsIPresShell.h
index 61b2f8c3250d..c1e83efee4b7 100644
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -144,8 +144,8 @@ typedef struct CapturingContentInfo {
} CapturingContentInfo;
#define NS_IPRESSHELL_IID \
- { 0x87719fd6, 0xe50c, 0x4d72, \
- { 0xbd, 0x55, 0x05, 0xf9, 0x5f, 0x33, 0x9e, 0xf2 } }
+ { 0x4dc4db09, 0x03d4, 0x4427, \
+ { 0xbe, 0xfb, 0xc9, 0x29, 0xac, 0x5c, 0x62, 0xab } }
// Constants for ScrollContentIntoView() function
#define NS_PRESSHELL_SCROLL_TOP 0
@@ -1176,6 +1176,11 @@ public:
virtual bool IsVisible() = 0;
virtual void DispatchSynthMouseMove(nsGUIEvent *aEvent, bool aFlushOnHoverChange) = 0;
+ virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
+ size_t *aArenasSize,
+ size_t *aStyleSetsSize,
+ size_t *aTextRunsSize) const = 0;
+
/**
* Refresh observer management.
*/
@@ -1283,10 +1288,6 @@ protected:
float mXResolution;
float mYResolution;
- // Live pres shells, for memory and other tracking
- typedef nsPtrHashKey PresShellPtrKey;
- static nsTHashtable *sLiveShells;
-
static nsIContent* gKeyDownTarget;
};
diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp
index 5b50bba3ecad..068b8c20aac8 100644
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -4734,9 +4734,13 @@ ShouldInflateFontsForContainer(const nsIFrame *aFrame)
// indicates whether the frame is inside something with a constrained
// height (propagating down the tree), but the propagation stops when
// we hit overflow-y: scroll or auto.
- return aFrame->GetStyleText()->mTextSizeAdjust !=
- NS_STYLE_TEXT_SIZE_ADJUST_NONE &&
- !(aFrame->GetStateBits() & NS_FRAME_IN_CONSTRAINED_HEIGHT);
+ const nsStyleText* styleText = aFrame->GetStyleText();
+
+ return styleText->mTextSizeAdjust != NS_STYLE_TEXT_SIZE_ADJUST_NONE &&
+ !(aFrame->GetStateBits() & NS_FRAME_IN_CONSTRAINED_HEIGHT) &&
+ // We also want to disable font inflation for containers that have
+ // preformatted text.
+ styleText->WhiteSpaceCanWrap();
}
nscoord
diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp
index c45502efd854..e5724c138942 100644
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -201,9 +201,6 @@
#include "imgIEncoder.h"
#include "gfxPlatform.h"
-/* for NS_MEMORY_REPORTER_IMPLEMENT */
-#include "nsIMemoryReporter.h"
-
#include "mozilla/FunctionTimer.h"
#include "mozilla/Preferences.h"
#include "mozilla/Telemetry.h"
@@ -608,113 +605,6 @@ struct nsCallbackEventRequest
GetPresContext()->RefreshDriver()-> \
IsLayoutFlushObserver(this), "Unexpected state")
-NS_IMPL_ISUPPORTS1(PresShell::MemoryReporter, nsIMemoryMultiReporter)
-
-namespace {
-
-struct MemoryReporterData
-{
- nsIMemoryMultiReporterCallback* callback;
- nsISupports* closure;
-};
-
-} // anonymous namespace
-
-NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(LayoutMallocSizeOf, "layout")
-
-/* static */ PLDHashOperator
-PresShell::MemoryReporter::SizeEnumerator(PresShellPtrKey *aEntry,
- void *userArg)
-{
- PresShell *aShell = static_cast(aEntry->GetKey());
- MemoryReporterData *data = (MemoryReporterData*)userArg;
-
- // Build the string "explicit/layout/shell()"
- nsCAutoString str("explicit/layout/shell(");
-
- nsIDocument* doc = aShell->GetDocument();
- if (doc) {
- nsIURI* docURI = doc->GetDocumentURI();
-
- if (docURI) {
- nsCString spec;
- docURI->GetSpec(spec);
-
- // A hack: replace forward slashes with '\\' so they aren't
- // treated as path separators. Users of the reporters
- // (such as about:memory) have to undo this change.
- spec.ReplaceChar('/', '\\');
-
- str += spec;
- }
- }
-
- str += NS_LITERAL_CSTRING(")");
-
- NS_NAMED_LITERAL_CSTRING(kArenaDesc, "Memory used by layout PresShell, PresContext, and other related areas.");
- NS_NAMED_LITERAL_CSTRING(kStyleDesc, "Memory used by the style system.");
- NS_NAMED_LITERAL_CSTRING(kTextRunsDesc, "Memory used for text-runs (glyph layout) in the PresShell's frame tree.");
-
- nsCAutoString arenaPath = str + NS_LITERAL_CSTRING("/arenas");
- nsCAutoString stylePath = str + NS_LITERAL_CSTRING("/styledata");
- nsCAutoString textRunsPath = str + NS_LITERAL_CSTRING("/textruns");
-
- PRInt64 arenasSize =
- aShell->SizeOfIncludingThis(LayoutMallocSizeOf) +
- aShell->mPresContext->SizeOfIncludingThis(LayoutMallocSizeOf);
-
- PRInt64 styleSize =
- aShell->StyleSet()->SizeOfIncludingThis(LayoutMallocSizeOf);
-
- PRInt64 textRunsSize = aShell->SizeOfTextRuns(LayoutMallocSizeOf);
-
- data->callback->
- Callback(EmptyCString(), arenaPath, nsIMemoryReporter::KIND_HEAP,
- nsIMemoryReporter::UNITS_BYTES, arenasSize, kArenaDesc,
- data->closure);
-
- data->callback->
- Callback(EmptyCString(), stylePath, nsIMemoryReporter::KIND_HEAP,
- nsIMemoryReporter::UNITS_BYTES, styleSize, kStyleDesc,
- data->closure);
-
- if (textRunsSize) {
- data->callback->
- Callback(EmptyCString(), textRunsPath, nsIMemoryReporter::KIND_HEAP,
- nsIMemoryReporter::UNITS_BYTES, textRunsSize, kTextRunsDesc,
- data->closure);
- }
-
- return PL_DHASH_NEXT;
-}
-
-NS_IMETHODIMP
-PresShell::MemoryReporter::GetName(nsACString &aName)
-{
- aName.AssignLiteral("layout");
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresShell::MemoryReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb,
- nsISupports* aClosure)
-{
- MemoryReporterData data;
- data.callback = aCb;
- data.closure = aClosure;
-
- sLiveShells->EnumerateEntries(SizeEnumerator, &data);
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresShell::MemoryReporter::GetExplicitNonHeap(PRInt64 *aAmount) {
- // This reporter doesn't do any KIND_NONHEAP measurements.
- *aAmount = 0;
- return NS_OK;
-}
-
class nsAutoCauseReflowNotifier
{
public:
@@ -915,7 +805,6 @@ NS_NewPresShell(nsIPresShell** aInstancePtrResult)
return NS_OK;
}
-nsTHashtable *nsIPresShell::sLiveShells = 0;
static bool sSynthMouseMove = true;
PresShell::PresShell()
@@ -943,15 +832,12 @@ PresShell::PresShell()
mYResolution = 1.0;
mViewportOverridden = false;
- static bool registeredReporter = false;
- if (!registeredReporter) {
- NS_RegisterMemoryMultiReporter(new MemoryReporter);
+ static bool addedSynthMouseMove = false;
+ if (!addedSynthMouseMove) {
Preferences::AddBoolVarCache(&sSynthMouseMove,
"layout.reflow.synthMouseMove", true);
- registeredReporter = true;
+ addedSynthMouseMove = true;
}
-
- sLiveShells->PutEntry(this);
}
NS_IMPL_ISUPPORTS7(PresShell, nsIPresShell, nsIDocumentObserver,
@@ -961,8 +847,6 @@ NS_IMPL_ISUPPORTS7(PresShell, nsIPresShell, nsIDocumentObserver,
PresShell::~PresShell()
{
- sLiveShells->RemoveEntry(this);
-
if (!mHaveShutDown) {
NS_NOTREACHED("Someone did not call nsIPresShell::destroy");
Destroy();
@@ -9085,19 +8969,18 @@ nsIPresShell::AccService()
}
#endif
+static bool inited = false;
+
void nsIPresShell::InitializeStatics()
{
- NS_ASSERTION(sLiveShells == nsnull, "InitializeStatics called multiple times!");
- sLiveShells = new nsTHashtable();
- sLiveShells->Init();
+ NS_ASSERTION(!inited, "InitializeStatics called multiple times!");
gCaptureTouchList.Init();
+ inited = true;
}
void nsIPresShell::ReleaseStatics()
{
- NS_ASSERTION(sLiveShells, "ReleaseStatics called without Initialize!");
- delete sLiveShells;
- sLiveShells = nsnull;
+ NS_ASSERTION(inited, "ReleaseStatics called without Initialize!");
}
// Asks our docshell whether we're active.
@@ -9203,8 +9086,23 @@ PresShell::GetRootPresShell()
return nsnull;
}
+void
+PresShell::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
+ size_t *aArenasSize,
+ size_t *aStyleSetsSize,
+ size_t *aTextRunsSize) const
+{
+ *aArenasSize = aMallocSizeOf(this);
+ *aArenasSize += mStackArena.SizeOfExcludingThis(aMallocSizeOf);
+ *aArenasSize += mFrameArena.SizeOfExcludingThis(aMallocSizeOf);
+
+ *aStyleSetsSize = StyleSet()->SizeOfIncludingThis(aMallocSizeOf);
+
+ *aTextRunsSize = SizeOfTextRuns(aMallocSizeOf);
+}
+
size_t
-PresShell::SizeOfTextRuns(nsMallocSizeOfFun aMallocSizeOf)
+PresShell::SizeOfTextRuns(nsMallocSizeOfFun aMallocSizeOf) const
{
nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
if (!rootFrame) {
diff --git a/layout/base/nsPresShell.h b/layout/base/nsPresShell.h
index cc271570da79..dd8e3c19a60f 100644
--- a/layout/base/nsPresShell.h
+++ b/layout/base/nsPresShell.h
@@ -901,26 +901,11 @@ private:
public:
- size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const {
- size_t n = 0;
-
- n += aMallocSizeOf(this);
- n += mStackArena.SizeOfExcludingThis(aMallocSizeOf);
- n += mFrameArena.SizeOfExcludingThis(aMallocSizeOf);
-
- return n;
- }
-
- size_t SizeOfTextRuns(nsMallocSizeOfFun aMallocSizeOf);
-
- class MemoryReporter : public nsIMemoryMultiReporter
- {
- public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIMEMORYMULTIREPORTER
- protected:
- static PLDHashOperator SizeEnumerator(PresShellPtrKey *aEntry, void *userArg);
- };
+ void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
+ size_t *aArenasSize,
+ size_t *aStyleSetsSize,
+ size_t *aTextRunsSize) const;
+ size_t SizeOfTextRuns(nsMallocSizeOfFun aMallocSizeOf) const;
protected:
void QueryIsActive();
diff --git a/layout/base/tests/font-inflation/preformatted-text-ref.html b/layout/base/tests/font-inflation/preformatted-text-ref.html
new file mode 100644
index 000000000000..0a847a806646
--- /dev/null
+++ b/layout/base/tests/font-inflation/preformatted-text-ref.html
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+ Firefox is quite neat
+ It browses the web fluidly
+ With no cares at all
+
+
+
+
+
diff --git a/layout/base/tests/font-inflation/preformatted-text.html b/layout/base/tests/font-inflation/preformatted-text.html
new file mode 100644
index 000000000000..0a847a806646
--- /dev/null
+++ b/layout/base/tests/font-inflation/preformatted-text.html
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+ Firefox is quite neat
+ It browses the web fluidly
+ With no cares at all
+
+
+
+
+
diff --git a/layout/base/tests/test_font_inflation_reftests.html b/layout/base/tests/test_font_inflation_reftests.html
index 1031c320847c..e1e3e0290187 100644
--- a/layout/base/tests/test_font_inflation_reftests.html
+++ b/layout/base/tests/test_font_inflation_reftests.html
@@ -65,6 +65,7 @@ var gTests = [
"== disable-fontinfl-on-mobile-2.html disable-fontinfl-on-mobile-ref.html",
"== disable-fontinfl-on-mobile-3.html disable-fontinfl-on-mobile-ref.html",
"== disable-fontinfl-on-mobile-4.html disable-fontinfl-on-mobile-ref.html",
+ "== preformatted-text.html preformatted-text-ref.html",
];
// Maintain a reference count of how many things we're waiting for until
diff --git a/layout/build/nsLayoutStatics.cpp b/layout/build/nsLayoutStatics.cpp
index 6dd77c043f16..bc779cb003d7 100644
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -123,7 +123,7 @@
#include "nsHyphenationManager.h"
#include "nsEditorSpellCheck.h"
-#include "nsDOMMemoryReporter.h"
+#include "nsWindowMemoryReporter.h"
extern void NS_ShutdownChainItemPool();
@@ -268,7 +268,7 @@ nsLayoutStatics::Initialize()
NS_SealStaticAtomTable();
- nsDOMMemoryMultiReporter::Init();
+ nsWindowMemoryReporter::Init();
return NS_OK;
}
@@ -276,8 +276,8 @@ nsLayoutStatics::Initialize()
void
nsLayoutStatics::Shutdown()
{
- // Don't need to shutdown nsDOMMemoryReporter, that will be done by the memory
- // reporter manager.
+ // Don't need to shutdown nsWindowMemoryReporter, that will be done by the
+ // memory reporter manager.
nsFrameScriptExecutor::Shutdown();
nsFocusManager::Shutdown();
diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp
index 072c7dee6deb..c6a384e6c1b3 100644
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -525,12 +525,12 @@ nsBlockFrame::InvalidateInternal(const nsRect& aDamageRect,
// be able to invalidate areas outside the 'clip'.
if (aForChild) {
const nsStyleDisplay* disp = GetStyleDisplay();
- nsRect absPosClipRect;
- if (GetAbsPosClipRect(disp, &absPosClipRect, GetSize())) {
+ nsRect clipRect;
+ if (GetClipPropClipRect(disp, &clipRect, GetSize())) {
// Restrict the invalidated area to abs-pos clip rect
// abs-pos clipping clips everything in the frame
nsRect r;
- if (r.IntersectRect(aDamageRect, absPosClipRect - nsPoint(aX, aY))) {
+ if (r.IntersectRect(aDamageRect, clipRect - nsPoint(aX, aY))) {
nsBlockFrameSuper::InvalidateInternal(r, aX, aY, this, aFlags);
}
return;
diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp
index 1de86c83f522..fc486698fc5c 100644
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -352,7 +352,7 @@ static bool ApplyOverflowClipping(nsDisplayListBuilder* aBuilder,
const nsStyleDisplay* aDisp,
nsRect* aRect);
-static bool ApplyAbsPosClipping(nsDisplayListBuilder* aBuilder,
+static bool ApplyClipPropClipping(nsDisplayListBuilder* aBuilder,
const nsStyleDisplay* aDisp,
const nsIFrame* aFrame,
nsRect* aRect);
@@ -962,7 +962,7 @@ nsIFrame::Preserves3DChildren() const
nsRect temp;
return (!ApplyOverflowClipping(nsnull, this, GetStyleDisplay(), &temp) &&
- !ApplyAbsPosClipping(nsnull, GetStyleDisplay(), this, &temp) &&
+ !ApplyClipPropClipping(nsnull, GetStyleDisplay(), this, &temp) &&
!nsSVGIntegrationUtils::UsingEffectsForFrame(this));
}
@@ -1448,8 +1448,8 @@ nsFrame::DisplayBorderBackgroundOutline(nsDisplayListBuilder* aBuilder,
}
bool
-nsIFrame::GetAbsPosClipRect(const nsStyleDisplay* aDisp, nsRect* aRect,
- const nsSize& aSize) const
+nsIFrame::GetClipPropClipRect(const nsStyleDisplay* aDisp, nsRect* aRect,
+ const nsSize& aSize) const
{
NS_PRECONDITION(aRect, "Must have aRect out parameter");
@@ -1467,10 +1467,10 @@ nsIFrame::GetAbsPosClipRect(const nsStyleDisplay* aDisp, nsRect* aRect,
return true;
}
-static bool ApplyAbsPosClipping(nsDisplayListBuilder* aBuilder,
+static bool ApplyClipPropClipping(nsDisplayListBuilder* aBuilder,
const nsStyleDisplay* aDisp, const nsIFrame* aFrame,
nsRect* aRect) {
- if (!aFrame->GetAbsPosClipRect(aDisp, aRect, aFrame->GetSize()))
+ if (!aFrame->GetClipPropClipRect(aDisp, aRect, aFrame->GetSize()))
return false;
if (aBuilder) {
@@ -1562,10 +1562,10 @@ protected:
bool mHaveRadius;
};
-class nsAbsPosClipWrapper : public nsDisplayWrapper
+class nsDisplayClipPropWrapper : public nsDisplayWrapper
{
public:
- nsAbsPosClipWrapper(const nsRect& aRect)
+ nsDisplayClipPropWrapper(const nsRect& aRect)
: mRect(aRect) {}
virtual nsDisplayItem* WrapList(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList) {
@@ -1734,15 +1734,15 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
if (IsFrameOfType(eReplaced) && !IsVisibleForPainting(aBuilder))
return NS_OK;
- nsRect absPosClip;
+ nsRect clipPropClip;
const nsStyleDisplay* disp = GetStyleDisplay();
// We can stop right away if this is a zero-opacity stacking context and
// we're painting.
if (disp->mOpacity == 0.0 && aBuilder->IsForPainting())
return NS_OK;
- bool applyAbsPosClipping =
- ApplyAbsPosClipping(aBuilder, disp, this, &absPosClip);
+ bool applyClipPropClipping =
+ ApplyClipPropClipping(aBuilder, disp, this, &clipPropClip);
nsRect dirtyRect = aDirtyRect;
bool inTransform = aBuilder->IsInTransform();
@@ -1770,9 +1770,9 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
inTransform = true;
}
- if (applyAbsPosClipping) {
+ if (applyClipPropClipping) {
dirtyRect.IntersectRect(dirtyRect,
- absPosClip - aBuilder->ToReferenceFrame(this));
+ clipPropClip - aBuilder->ToReferenceFrame(this));
}
bool usingSVGEffects = nsSVGIntegrationUtils::UsingEffectsForFrame(this);
@@ -1863,9 +1863,9 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
/* If we have absolute position clipping and we have, or will have, items to
* be clipped, wrap the list in a clip wrapper.
*/
- if (applyAbsPosClipping &&
+ if (applyClipPropClipping &&
(!resultList.IsEmpty() || usingSVGEffects)) {
- nsAbsPosClipWrapper wrapper(absPosClip);
+ nsDisplayClipPropWrapper wrapper(clipPropClip);
nsDisplayItem* item = wrapper.WrapList(aBuilder, this, &resultList);
if (!item)
return NS_ERROR_OUT_OF_MEMORY;
@@ -2088,15 +2088,15 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
}
} else {
nsRect clipRect;
- bool applyAbsPosClipping =
- ApplyAbsPosClipping(aBuilder, disp, child, &clipRect);
+ bool applyClipPropClipping =
+ ApplyClipPropClipping(aBuilder, disp, child, &clipRect);
// A pseudo-stacking context (e.g., a positioned element with z-index auto).
// We allow positioned descendants of the child to escape to our parent
// stacking context's positioned descendant list, because they might be
// z-index:non-auto
nsDisplayListCollection pseudoStack;
nsRect clippedDirtyRect = dirty;
- if (applyAbsPosClipping) {
+ if (applyClipPropClipping) {
// clipRect is in builder-reference-frame coordinates,
// dirty/clippedDirtyRect are in child coordinates
clippedDirtyRect.IntersectRect(clippedDirtyRect,
@@ -2115,8 +2115,8 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
}
if (NS_SUCCEEDED(rv)) {
- if (applyAbsPosClipping) {
- nsAbsPosClipWrapper wrapper(clipRect);
+ if (applyClipPropClipping) {
+ nsDisplayClipPropWrapper wrapper(clipRect);
rv = wrapper.WrapListsInPlace(aBuilder, child, pseudoStack);
}
}
@@ -6738,13 +6738,13 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
true);
// Absolute position clipping
- bool didHaveAbsPosClip = (GetStateBits() & NS_FRAME_HAS_CLIP) != 0;
- nsRect absPosClipRect;
- bool hasAbsPosClip = GetAbsPosClipRect(disp, &absPosClipRect, aNewSize);
- if (hasAbsPosClip) {
+ bool didHaveClipPropClip = (GetStateBits() & NS_FRAME_HAS_CLIP) != 0;
+ nsRect clipPropClipRect;
+ bool hasClipPropClip = GetClipPropClipRect(disp, &clipPropClipRect, aNewSize);
+ if (hasClipPropClip) {
NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
nsRect& o = aOverflowAreas.Overflow(otype);
- o.IntersectRect(o, absPosClipRect);
+ o.IntersectRect(o, clipPropClipRect);
}
AddStateBits(NS_FRAME_HAS_CLIP);
} else {
@@ -6799,7 +6799,7 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
// to do anything here since removing those styles can't require
// repainting of areas that weren't in the old overflow area.
Invalidate(aOverflowAreas.VisualOverflow());
- } else if (hasAbsPosClip || didHaveAbsPosClip) {
+ } else if (hasClipPropClip || didHaveClipPropClip) {
// If we are (or were) clipped by the 'clip' property, and our
// overflow area changes, it might be because the clipping changed.
// The nsChangeHint_RepaintFrame for the style change will only
diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h
index e2ebe88c4959..ab8112bc05e3 100644
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -2538,12 +2538,17 @@ NS_PTR_TO_INT32(frame->Properties().Get(nsIFrame::EmbeddingLevelProperty()))
virtual bool SupportsVisibilityHidden() { return true; }
/**
- * Returns true if the frame is absolutely positioned and has a clip
- * rect set via the 'clip' property. If true, then we also set aRect
- * to the computed clip rect coordinates relative to this frame's origin.
- * aRect must not be null!
+ * Returns true if the frame has a valid clip rect set via the 'clip'
+ * property, and the 'clip' property applies to this frame. The 'clip'
+ * property applies to HTML frames if they are absolutely positioned. The
+ * 'clip' property applies to SVG frames regardless of the value of the
+ * 'position' property.
+ *
+ * If this method returns true, then we also set aRect to the computed clip
+ * rect, with coordinates relative to this frame's origin. aRect must not be
+ * null!
*/
- bool GetAbsPosClipRect(const nsStyleDisplay* aDisp, nsRect* aRect,
+ bool GetClipPropClipRect(const nsStyleDisplay* aDisp, nsRect* aRect,
const nsSize& aSize) const;
/**
diff --git a/layout/media/symbols.def.in b/layout/media/symbols.def.in
index f76c639a972f..d070ff1443cf 100644
--- a/layout/media/symbols.def.in
+++ b/layout/media/symbols.def.in
@@ -105,3 +105,5 @@ ShGetInfoLog
ShCompile
ShGetInfo
ShConstructCompiler
+ShGetActiveAttrib
+ShGetActiveUniform
diff --git a/layout/reftests/svg/smil/sort/reftest.list b/layout/reftests/svg/smil/sort/reftest.list
index 3495c17e944c..28631268763f 100644
--- a/layout/reftests/svg/smil/sort/reftest.list
+++ b/layout/reftests/svg/smil/sort/reftest.list
@@ -9,4 +9,4 @@
== sort-startSame-1b.svg sort-startSame-1-ref.svg
== sort-startSame-2a.svg sort-startSame-2-ref.svg
== sort-startSame-2b.svg sort-startSame-2-ref.svg
-== sort-additive-1.svg sort-additive-1-ref.svg
+random-if(Android) == sort-additive-1.svg sort-additive-1-ref.svg # bug 547801
diff --git a/layout/svg/base/src/nsISVGChildFrame.h b/layout/svg/base/src/nsISVGChildFrame.h
index 0680804a0004..38c73eec57ed 100644
--- a/layout/svg/base/src/nsISVGChildFrame.h
+++ b/layout/svg/base/src/nsISVGChildFrame.h
@@ -47,7 +47,7 @@
#include "gfxMatrix.h"
class gfxContext;
-class nsSVGRenderState;
+class nsRenderingContext;
namespace mozilla {
class SVGAnimatedNumberList;
@@ -70,7 +70,7 @@ public:
// Paint this frame - aDirtyRect is the area being redrawn, in frame
// offset pixel coordinates
- NS_IMETHOD PaintSVG(nsSVGRenderState* aContext,
+ NS_IMETHOD PaintSVG(nsRenderingContext* aContext,
const nsIntRect *aDirtyRect)=0;
// Check if this frame or children contain the given point,
diff --git a/layout/svg/base/src/nsSVGClipPathFrame.cpp b/layout/svg/base/src/nsSVGClipPathFrame.cpp
index 79f86c20339e..881878e4a53d 100644
--- a/layout/svg/base/src/nsSVGClipPathFrame.cpp
+++ b/layout/svg/base/src/nsSVGClipPathFrame.cpp
@@ -56,7 +56,7 @@ NS_NewSVGClipPathFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
NS_IMPL_FRAMEARENA_HELPERS(nsSVGClipPathFrame)
nsresult
-nsSVGClipPathFrame::ClipPaint(nsSVGRenderState* aContext,
+nsSVGClipPathFrame::ClipPaint(nsRenderingContext* aContext,
nsIFrame* aParent,
const gfxMatrix &aMatrix)
{
@@ -78,12 +78,11 @@ nsSVGClipPathFrame::ClipPaint(nsSVGRenderState* aContext,
bool isTrivial = IsTrivial();
- nsAutoSVGRenderMode mode(aContext,
- isTrivial ? nsSVGRenderState::CLIP
- : nsSVGRenderState::CLIP_MASK);
+ SVGAutoRenderState mode(aContext,
+ isTrivial ? SVGAutoRenderState::CLIP
+ : SVGAutoRenderState::CLIP_MASK);
-
- gfxContext *gfx = aContext->GetGfxContext();
+ gfxContext *gfx = aContext->ThebesContext();
nsSVGClipPathFrame *clipPathFrame =
nsSVGEffects::GetEffectProperties(this).GetClipPathFrame(nsnull);
diff --git a/layout/svg/base/src/nsSVGClipPathFrame.h b/layout/svg/base/src/nsSVGClipPathFrame.h
index 88404e37ce1f..a569ad608350 100644
--- a/layout/svg/base/src/nsSVGClipPathFrame.h
+++ b/layout/svg/base/src/nsSVGClipPathFrame.h
@@ -40,6 +40,8 @@
#include "nsSVGContainerFrame.h"
#include "gfxMatrix.h"
+class nsRenderingContext;
+
typedef nsSVGContainerFrame nsSVGClipPathFrameBase;
class nsSVGClipPathFrame : public nsSVGClipPathFrameBase
@@ -55,7 +57,7 @@ public:
NS_DECL_FRAMEARENA_HELPERS
// nsSVGClipPathFrame methods:
- nsresult ClipPaint(nsSVGRenderState* aContext,
+ nsresult ClipPaint(nsRenderingContext* aContext,
nsIFrame* aParent,
const gfxMatrix &aMatrix);
diff --git a/layout/svg/base/src/nsSVGContainerFrame.cpp b/layout/svg/base/src/nsSVGContainerFrame.cpp
index 45930aa1ad49..fafc65e62f0e 100644
--- a/layout/svg/base/src/nsSVGContainerFrame.cpp
+++ b/layout/svg/base/src/nsSVGContainerFrame.cpp
@@ -164,7 +164,7 @@ nsSVGDisplayContainerFrame::RemoveFrame(ChildListID aListID,
// nsISVGChildFrame methods
NS_IMETHODIMP
-nsSVGDisplayContainerFrame::PaintSVG(nsSVGRenderState* aContext,
+nsSVGDisplayContainerFrame::PaintSVG(nsRenderingContext* aContext,
const nsIntRect *aDirtyRect)
{
const nsStyleDisplay *display = mStyleContext->GetStyleDisplay();
diff --git a/layout/svg/base/src/nsSVGContainerFrame.h b/layout/svg/base/src/nsSVGContainerFrame.h
index c035a62f60b2..60ac96faf528 100644
--- a/layout/svg/base/src/nsSVGContainerFrame.h
+++ b/layout/svg/base/src/nsSVGContainerFrame.h
@@ -43,6 +43,8 @@
#include "gfxRect.h"
#include "gfxMatrix.h"
+class nsRenderingContext;
+
typedef nsContainerFrame nsSVGContainerFrameBase;
class nsSVGContainerFrame : public nsSVGContainerFrameBase
@@ -103,7 +105,7 @@ public:
nsIFrame* aPrevInFlow);
// nsISVGChildFrame interface:
- NS_IMETHOD PaintSVG(nsSVGRenderState* aContext,
+ NS_IMETHOD PaintSVG(nsRenderingContext* aContext,
const nsIntRect *aDirtyRect);
NS_IMETHOD_(nsIFrame*) GetFrameForPoint(const nsPoint &aPoint);
NS_IMETHOD_(nsRect) GetCoveredRegion();
diff --git a/layout/svg/base/src/nsSVGFilterFrame.cpp b/layout/svg/base/src/nsSVGFilterFrame.cpp
index b29eb3fbe3b4..9df040b4f25a 100644
--- a/layout/svg/base/src/nsSVGFilterFrame.cpp
+++ b/layout/svg/base/src/nsSVGFilterFrame.cpp
@@ -250,7 +250,7 @@ nsSVGFilterFrame::AttributeChanged(PRInt32 aNameSpaceID,
}
nsresult
-nsSVGFilterFrame::FilterPaint(nsSVGRenderState *aContext,
+nsSVGFilterFrame::FilterPaint(nsRenderingContext *aContext,
nsIFrame *aTarget,
nsSVGFilterPaintCallback *aPaintCallback,
const nsIntRect *aDirtyRect)
@@ -263,7 +263,7 @@ nsSVGFilterFrame::FilterPaint(nsSVGRenderState *aContext,
nsRefPtr result;
nsresult rv = instance.get()->Render(getter_AddRefs(result));
if (NS_SUCCEEDED(rv) && result) {
- nsSVGUtils::CompositeSurfaceMatrix(aContext->GetGfxContext(),
+ nsSVGUtils::CompositeSurfaceMatrix(aContext->ThebesContext(),
result, instance.get()->GetFilterSpaceToDeviceSpaceTransform(), 1.0);
}
return rv;
diff --git a/layout/svg/base/src/nsSVGFilterFrame.h b/layout/svg/base/src/nsSVGFilterFrame.h
index bfc17a46e916..7f2659639b03 100644
--- a/layout/svg/base/src/nsSVGFilterFrame.h
+++ b/layout/svg/base/src/nsSVGFilterFrame.h
@@ -40,7 +40,7 @@
#include "nsRect.h"
#include "nsSVGContainerFrame.h"
-class nsSVGRenderState;
+class nsRenderingContext;
class nsSVGFilterPaintCallback;
typedef nsSVGContainerFrame nsSVGFilterFrameBase;
@@ -58,7 +58,7 @@ public:
nsIAtom* aAttribute,
PRInt32 aModType);
- nsresult FilterPaint(nsSVGRenderState *aContext,
+ nsresult FilterPaint(nsRenderingContext *aContext,
nsIFrame *aTarget, nsSVGFilterPaintCallback *aPaintCallback,
const nsIntRect* aDirtyRect);
diff --git a/layout/svg/base/src/nsSVGFilterInstance.cpp b/layout/svg/base/src/nsSVGFilterInstance.cpp
index 77e8c6c10018..4c694c37b1dd 100644
--- a/layout/svg/base/src/nsSVGFilterInstance.cpp
+++ b/layout/svg/base/src/nsSVGFilterInstance.cpp
@@ -364,8 +364,9 @@ nsSVGFilterInstance::BuildSourceImages()
if (!offscreen || offscreen->CairoStatus())
return NS_ERROR_OUT_OF_MEMORY;
offscreen->SetDeviceOffset(gfxPoint(-mSurfaceRect.x, -mSurfaceRect.y));
-
- nsSVGRenderState tmpState(offscreen);
+
+ nsRenderingContext tmpCtx;
+ tmpCtx.Init(mTargetFrame->PresContext()->DeviceContext(), offscreen);
gfxMatrix userSpaceToFilterSpace = GetUserSpaceToFilterSpaceTransform();
gfxRect r(neededRect.x, neededRect.y, neededRect.width, neededRect.height);
@@ -389,8 +390,8 @@ nsSVGFilterInstance::BuildSourceImages()
// code more complex while being hard to get right without introducing
// subtle bugs, and in practice it probably makes no real difference.)
gfxMatrix deviceToFilterSpace = GetFilterSpaceToDeviceSpaceTransform().Invert();
- tmpState.GetGfxContext()->Multiply(deviceToFilterSpace);
- mPaintCallback->Paint(&tmpState, mTargetFrame, &dirty);
+ tmpCtx.ThebesContext()->Multiply(deviceToFilterSpace);
+ mPaintCallback->Paint(&tmpCtx, mTargetFrame, &dirty);
gfxContext copyContext(sourceColorAlpha);
copyContext.SetSource(offscreen);
diff --git a/layout/svg/base/src/nsSVGFilterPaintCallback.h b/layout/svg/base/src/nsSVGFilterPaintCallback.h
index f71f2ecb3760..49c56afff326 100644
--- a/layout/svg/base/src/nsSVGFilterPaintCallback.h
+++ b/layout/svg/base/src/nsSVGFilterPaintCallback.h
@@ -40,7 +40,7 @@
#include "nsRect.h"
class nsIFrame;
-class nsSVGRenderState;
+class nsRenderingContext;
class nsSVGFilterPaintCallback {
public:
@@ -54,7 +54,7 @@ public:
* system.
* @param aDirtyRect the dirty rect *in user space pixels*
*/
- virtual void Paint(nsSVGRenderState *aContext, nsIFrame *aTarget,
+ virtual void Paint(nsRenderingContext *aContext, nsIFrame *aTarget,
const nsIntRect *aDirtyRect) = 0;
};
diff --git a/layout/svg/base/src/nsSVGForeignObjectFrame.cpp b/layout/svg/base/src/nsSVGForeignObjectFrame.cpp
index 289919a713d9..73474c6f03dd 100644
--- a/layout/svg/base/src/nsSVGForeignObjectFrame.cpp
+++ b/layout/svg/base/src/nsSVGForeignObjectFrame.cpp
@@ -209,7 +209,7 @@ ToCanvasBounds(const gfxRect &aUserspaceRect,
}
NS_IMETHODIMP
-nsSVGForeignObjectFrame::PaintSVG(nsSVGRenderState *aContext,
+nsSVGForeignObjectFrame::PaintSVG(nsRenderingContext *aContext,
const nsIntRect *aDirtyRect)
{
if (IsDisabled())
@@ -222,9 +222,7 @@ nsSVGForeignObjectFrame::PaintSVG(nsSVGRenderState *aContext,
gfxMatrix matrixForChildren = GetCanvasTMForChildren();
gfxMatrix matrix = GetCanvasTM();
- nsRenderingContext *ctx = aContext->GetRenderingContext(this);
-
- if (!ctx || matrixForChildren.IsSingular()) {
+ if (matrixForChildren.IsSingular()) {
NS_WARNING("Can't render foreignObject element!");
return NS_ERROR_FAILURE;
}
@@ -255,7 +253,7 @@ nsSVGForeignObjectFrame::PaintSVG(nsSVGRenderState *aContext,
return NS_OK;
}
- gfxContext *gfx = aContext->GetGfxContext();
+ gfxContext *gfx = aContext->ThebesContext();
gfx->Save();
@@ -272,10 +270,10 @@ nsSVGForeignObjectFrame::PaintSVG(nsSVGRenderState *aContext,
gfx->Multiply(matrixForChildren);
PRUint32 flags = nsLayoutUtils::PAINT_IN_TRANSFORM;
- if (aContext->IsPaintingToWindow()) {
+ if (SVGAutoRenderState::IsPaintingToWindow(aContext)) {
flags |= nsLayoutUtils::PAINT_TO_WINDOW;
}
- nsresult rv = nsLayoutUtils::PaintFrame(ctx, kid, nsRegion(kidDirtyRect),
+ nsresult rv = nsLayoutUtils::PaintFrame(aContext, kid, nsRegion(kidDirtyRect),
NS_RGBA(0,0,0,0), flags);
gfx->Restore();
diff --git a/layout/svg/base/src/nsSVGForeignObjectFrame.h b/layout/svg/base/src/nsSVGForeignObjectFrame.h
index f2d016c587fc..5085734eb041 100644
--- a/layout/svg/base/src/nsSVGForeignObjectFrame.h
+++ b/layout/svg/base/src/nsSVGForeignObjectFrame.h
@@ -46,6 +46,7 @@
#include "nsIPresShell.h"
#include "mozilla/Attributes.h"
+class nsRenderingContext;
class nsSVGOuterSVGFrame;
typedef nsContainerFrame nsSVGForeignObjectFrameBase;
@@ -121,7 +122,7 @@ public:
#endif
// nsISVGChildFrame interface:
- NS_IMETHOD PaintSVG(nsSVGRenderState *aContext,
+ NS_IMETHOD PaintSVG(nsRenderingContext *aContext,
const nsIntRect *aDirtyRect);
NS_IMETHOD_(nsIFrame*) GetFrameForPoint(const nsPoint &aPoint);
NS_IMETHOD_(nsRect) GetCoveredRegion();
diff --git a/layout/svg/base/src/nsSVGGlyphFrame.cpp b/layout/svg/base/src/nsSVGGlyphFrame.cpp
index aba3c98abd44..d5c639ba2c4c 100644
--- a/layout/svg/base/src/nsSVGGlyphFrame.cpp
+++ b/layout/svg/base/src/nsSVGGlyphFrame.cpp
@@ -323,14 +323,14 @@ nsSVGGlyphFrame::GetType() const
// nsISVGChildFrame methods
NS_IMETHODIMP
-nsSVGGlyphFrame::PaintSVG(nsSVGRenderState *aContext,
+nsSVGGlyphFrame::PaintSVG(nsRenderingContext *aContext,
const nsIntRect *aDirtyRect)
{
if (!GetStyleVisibility()->IsVisible())
return NS_OK;
- gfxContext *gfx = aContext->GetGfxContext();
- PRUint16 renderMode = aContext->GetRenderMode();
+ gfxContext *gfx = aContext->ThebesContext();
+ PRUint16 renderMode = SVGAutoRenderState::GetRenderMode(aContext);
switch (GetStyleSVG()->mTextRendering) {
case NS_STYLE_TEXT_RENDERING_OPTIMIZESPEED:
@@ -341,7 +341,7 @@ nsSVGGlyphFrame::PaintSVG(nsSVGRenderState *aContext,
break;
}
- if (renderMode != nsSVGRenderState::NORMAL) {
+ if (renderMode != SVGAutoRenderState::NORMAL) {
gfxMatrix matrix = gfx->CurrentMatrix();
SetupGlobalTransform(gfx);
@@ -354,7 +354,7 @@ nsSVGGlyphFrame::PaintSVG(nsSVGRenderState *aContext,
else
gfx->SetFillRule(gfxContext::FILL_RULE_WINDING);
- if (renderMode == nsSVGRenderState::CLIP_MASK) {
+ if (renderMode == SVGAutoRenderState::CLIP_MASK) {
gfx->SetColor(gfxRGBA(1.0f, 1.0f, 1.0f, 1.0f));
DrawCharacters(&iter, gfx, gfxFont::GLYPH_FILL);
} else {
diff --git a/layout/svg/base/src/nsSVGGlyphFrame.h b/layout/svg/base/src/nsSVGGlyphFrame.h
index e0523f7d6d23..fc1c99ee066f 100644
--- a/layout/svg/base/src/nsSVGGlyphFrame.h
+++ b/layout/svg/base/src/nsSVGGlyphFrame.h
@@ -47,6 +47,7 @@
#include "gfxFont.h"
#include "nsTextFragment.h"
+class nsRenderingContext;
class nsSVGTextFrame;
class nsSVGTextPathFrame;
class nsSVGGlyphFrame;
@@ -172,7 +173,7 @@ public:
// nsISVGChildFrame interface:
// These four always use the global transform, even if NS_STATE_NONDISPLAY_CHILD
- NS_IMETHOD PaintSVG(nsSVGRenderState *aContext,
+ NS_IMETHOD PaintSVG(nsRenderingContext *aContext,
const nsIntRect *aDirtyRect);
NS_IMETHOD_(nsIFrame*) GetFrameForPoint(const nsPoint &aPoint);
NS_IMETHOD UpdateCoveredRegion();
diff --git a/layout/svg/base/src/nsSVGImageFrame.cpp b/layout/svg/base/src/nsSVGImageFrame.cpp
index b0930b26ca4d..42e4ed2bc333 100644
--- a/layout/svg/base/src/nsSVGImageFrame.cpp
+++ b/layout/svg/base/src/nsSVGImageFrame.cpp
@@ -50,6 +50,7 @@
using namespace mozilla;
+class nsRenderingContext;
class nsSVGImageFrame;
class nsSVGImageListener MOZ_FINAL : public nsStubImageDecoderObserver
@@ -90,7 +91,7 @@ public:
NS_DECL_FRAMEARENA_HELPERS
// nsISVGChildFrame interface:
- NS_IMETHOD PaintSVG(nsSVGRenderState *aContext, const nsIntRect *aDirtyRect);
+ NS_IMETHOD PaintSVG(nsRenderingContext *aContext, const nsIntRect *aDirtyRect);
NS_IMETHOD_(nsIFrame*) GetFrameForPoint(const nsPoint &aPoint);
// nsSVGPathGeometryFrame methods:
@@ -309,7 +310,7 @@ nsSVGImageFrame::TransformContextForPainting(gfxContext* aGfxContext)
//----------------------------------------------------------------------
// nsISVGChildFrame methods:
NS_IMETHODIMP
-nsSVGImageFrame::PaintSVG(nsSVGRenderState *aContext,
+nsSVGImageFrame::PaintSVG(nsRenderingContext *aContext,
const nsIntRect *aDirtyRect)
{
nsresult rv = NS_OK;
@@ -335,7 +336,7 @@ nsSVGImageFrame::PaintSVG(nsSVGRenderState *aContext,
}
if (mImageContainer) {
- gfxContext* ctx = aContext->GetGfxContext();
+ gfxContext* ctx = aContext->ThebesContext();
gfxContextAutoSaveRestore autoRestorer(ctx);
if (GetStyleDisplay()->IsScrollableOverflow()) {
@@ -404,7 +405,7 @@ nsSVGImageFrame::PaintSVG(nsSVGRenderState *aContext,
// That method needs our image to have a fixed native width & height,
// and that's not always true for TYPE_VECTOR images.
nsLayoutUtils::DrawSingleImage(
- aContext->GetRenderingContext(this),
+ aContext,
mImageContainer,
nsLayoutUtils::GetGraphicsFilterForFrame(this),
destRect,
@@ -414,7 +415,7 @@ nsSVGImageFrame::PaintSVG(nsSVGRenderState *aContext,
rootSVGElem->ClearImageOverridePreserveAspectRatio();
} else { // mImageContainer->GetType() == TYPE_RASTER
nsLayoutUtils::DrawSingleUnscaledImage(
- aContext->GetRenderingContext(this),
+ aContext,
mImageContainer,
nsLayoutUtils::GetGraphicsFilterForFrame(this),
nsPoint(0, 0),
diff --git a/layout/svg/base/src/nsSVGInnerSVGFrame.cpp b/layout/svg/base/src/nsSVGInnerSVGFrame.cpp
index 6e3a98cd2fcb..7ce03e7b3b0f 100644
--- a/layout/svg/base/src/nsSVGInnerSVGFrame.cpp
+++ b/layout/svg/base/src/nsSVGInnerSVGFrame.cpp
@@ -83,7 +83,7 @@ nsSVGInnerSVGFrame::GetType() const
// nsISVGChildFrame methods
NS_IMETHODIMP
-nsSVGInnerSVGFrame::PaintSVG(nsSVGRenderState *aContext,
+nsSVGInnerSVGFrame::PaintSVG(nsRenderingContext *aContext,
const nsIntRect *aDirtyRect)
{
gfxContextAutoSaveRestore autoSR;
@@ -100,7 +100,7 @@ nsSVGInnerSVGFrame::PaintSVG(nsSVGRenderState *aContext,
nsSVGContainerFrame *parent = static_cast(mParent);
gfxMatrix clipTransform = parent->GetCanvasTM();
- gfxContext *gfx = aContext->GetGfxContext();
+ gfxContext *gfx = aContext->ThebesContext();
autoSR.SetContext(gfx);
gfxRect clipRect =
nsSVGUtils::GetClipRectForFrame(this, x, y, width, height);
diff --git a/layout/svg/base/src/nsSVGInnerSVGFrame.h b/layout/svg/base/src/nsSVGInnerSVGFrame.h
index 31db89169ce4..2b8990e696b7 100644
--- a/layout/svg/base/src/nsSVGInnerSVGFrame.h
+++ b/layout/svg/base/src/nsSVGInnerSVGFrame.h
@@ -40,6 +40,8 @@
#include "nsISVGSVGFrame.h"
#include "gfxMatrix.h"
+class nsRenderingContext;
+
typedef nsSVGDisplayContainerFrame nsSVGInnerSVGFrameBase;
class nsSVGInnerSVGFrame : public nsSVGInnerSVGFrameBase,
@@ -81,7 +83,7 @@ public:
PRInt32 aModType);
// nsISVGChildFrame interface:
- NS_IMETHOD PaintSVG(nsSVGRenderState *aContext, const nsIntRect *aDirtyRect);
+ NS_IMETHOD PaintSVG(nsRenderingContext *aContext, const nsIntRect *aDirtyRect);
virtual void NotifySVGChanged(PRUint32 aFlags);
NS_IMETHOD_(nsIFrame*) GetFrameForPoint(const nsPoint &aPoint);
diff --git a/layout/svg/base/src/nsSVGIntegrationUtils.cpp b/layout/svg/base/src/nsSVGIntegrationUtils.cpp
index 2d03db4e8e9a..5238807190d3 100644
--- a/layout/svg/base/src/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/base/src/nsSVGIntegrationUtils.cpp
@@ -217,12 +217,11 @@ public:
: mBuilder(aBuilder), mInnerList(aInnerList), mFrame(aFrame),
mOffset(aOffset) {}
- virtual void Paint(nsSVGRenderState *aContext, nsIFrame *aTarget,
+ virtual void Paint(nsRenderingContext *aContext, nsIFrame *aTarget,
const nsIntRect* aDirtyRect)
{
- nsRenderingContext* ctx = aContext->GetRenderingContext(aTarget);
- nsRenderingContext::AutoPushTranslation push(ctx, -mOffset);
- mInnerList->PaintForFrame(mBuilder, ctx, mFrame, nsDisplayList::PAINT_DEFAULT);
+ nsRenderingContext::AutoPushTranslation push(aContext, -mOffset);
+ mInnerList->PaintForFrame(mBuilder, aContext, mFrame, nsDisplayList::PAINT_DEFAULT);
}
private:
@@ -283,7 +282,8 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(nsRenderingContext* aCtx,
gfxContext* gfx = aCtx->ThebesContext();
gfxMatrix savedCTM = gfx->CurrentMatrix();
- nsSVGRenderState svgContext(aCtx);
+
+ //SVGAutoRenderState autoRenderState(aCtx, SVGAutoRenderState::NORMAL);
nsRect userSpaceRect = GetNonSVGUserSpace(firstFrame) + aBuilder->ToReferenceFrame(firstFrame);
PRInt32 appUnitsPerDevPixel = aEffectsFrame->PresContext()->AppUnitsPerDevPixel();
@@ -307,7 +307,7 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(nsRenderingContext* aCtx,
*/
if (clipPathFrame && isTrivialClip) {
gfx->Save();
- clipPathFrame->ClipPaint(&svgContext, aEffectsFrame, matrix);
+ clipPathFrame->ClipPaint(aCtx, aEffectsFrame, matrix);
}
/* Paint the child */
@@ -315,7 +315,7 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(nsRenderingContext* aCtx,
RegularFramePaintCallback paint(aBuilder, aInnerList, aEffectsFrame,
userSpaceRect.TopLeft());
nsIntRect r = (aDirtyRect - userSpaceRect.TopLeft()).ToOutsidePixels(appUnitsPerDevPixel);
- filterFrame->FilterPaint(&svgContext, aEffectsFrame, &paint, &r);
+ filterFrame->FilterPaint(aCtx, aEffectsFrame, &paint, &r);
} else {
gfx->SetMatrix(savedCTM);
aInnerList->PaintForFrame(aBuilder, aCtx, aEffectsFrame,
@@ -336,14 +336,14 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(nsRenderingContext* aCtx,
gfx->PopGroupToSource();
nsRefPtr maskSurface =
- maskFrame ? maskFrame->ComputeMaskAlpha(&svgContext, aEffectsFrame,
+ maskFrame ? maskFrame->ComputeMaskAlpha(aCtx, aEffectsFrame,
matrix, opacity) : nsnull;
nsRefPtr clipMaskSurface;
if (clipPathFrame && !isTrivialClip) {
gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
- nsresult rv = clipPathFrame->ClipPaint(&svgContext, aEffectsFrame, matrix);
+ nsresult rv = clipPathFrame->ClipPaint(aCtx, aEffectsFrame, matrix);
clipMaskSurface = gfx->PopGroup();
if (NS_SUCCEEDED(rv) && clipMaskSurface) {
@@ -443,7 +443,8 @@ PaintFrameCallback::operator()(gfxContext* aContext,
mFrame->AddStateBits(NS_FRAME_DRAWING_AS_PAINTSERVER);
- nsSVGRenderState renderState(aContext);
+ nsRenderingContext context;
+ context.Init(mFrame->PresContext()->DeviceContext(), aContext);
aContext->Save();
// Clip to aFillRect so that we don't paint outside.
@@ -475,7 +476,7 @@ PaintFrameCallback::operator()(gfxContext* aContext,
// Draw.
nsRect dirty(bbox.x, bbox.y, mPaintServerSize.width, mPaintServerSize.height);
- nsLayoutUtils::PaintFrame(renderState.GetRenderingContext(mTarget), mFrame,
+ nsLayoutUtils::PaintFrame(&context, mFrame,
dirty, NS_RGBA(0, 0, 0, 0),
nsLayoutUtils::PAINT_IN_TRANSFORM |
nsLayoutUtils::PAINT_ALL_CONTINUATIONS);
diff --git a/layout/svg/base/src/nsSVGMarkerFrame.cpp b/layout/svg/base/src/nsSVGMarkerFrame.cpp
index df9dd60db4f3..b45d94229979 100644
--- a/layout/svg/base/src/nsSVGMarkerFrame.cpp
+++ b/layout/svg/base/src/nsSVGMarkerFrame.cpp
@@ -122,7 +122,7 @@ nsSVGMarkerFrame::GetCanvasTM()
nsresult
-nsSVGMarkerFrame::PaintMark(nsSVGRenderState *aContext,
+nsSVGMarkerFrame::PaintMark(nsRenderingContext *aContext,
nsSVGPathGeometryFrame *aMarkedFrame,
nsSVGMark *aMark, float aStrokeWidth)
{
@@ -148,7 +148,7 @@ nsSVGMarkerFrame::PaintMark(nsSVGRenderState *aContext,
mY = aMark->y;
mAutoAngle = aMark->angle;
- gfxContext *gfx = aContext->GetGfxContext();
+ gfxContext *gfx = aContext->ThebesContext();
if (GetStyleDisplay()->IsScrollableOverflow()) {
gfx->Save();
diff --git a/layout/svg/base/src/nsSVGMarkerFrame.h b/layout/svg/base/src/nsSVGMarkerFrame.h
index 5cfbab47d98e..d7204ebe5653 100644
--- a/layout/svg/base/src/nsSVGMarkerFrame.h
+++ b/layout/svg/base/src/nsSVGMarkerFrame.h
@@ -41,6 +41,7 @@
#include "gfxMatrix.h"
class gfxContext;
+class nsRenderingContext;
class nsSVGPathGeometryFrame;
class nsIURI;
class nsIContent;
@@ -87,7 +88,7 @@ public:
#endif
// nsSVGMarkerFrame methods:
- nsresult PaintMark(nsSVGRenderState *aContext,
+ nsresult PaintMark(nsRenderingContext *aContext,
nsSVGPathGeometryFrame *aMarkedFrame,
nsSVGMark *aMark,
float aStrokeWidth);
diff --git a/layout/svg/base/src/nsSVGMaskFrame.cpp b/layout/svg/base/src/nsSVGMaskFrame.cpp
index c7589ffecffe..896086d87abb 100644
--- a/layout/svg/base/src/nsSVGMaskFrame.cpp
+++ b/layout/svg/base/src/nsSVGMaskFrame.cpp
@@ -54,7 +54,7 @@ NS_NewSVGMaskFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
NS_IMPL_FRAMEARENA_HELPERS(nsSVGMaskFrame)
already_AddRefed
-nsSVGMaskFrame::ComputeMaskAlpha(nsSVGRenderState *aContext,
+nsSVGMaskFrame::ComputeMaskAlpha(nsRenderingContext *aContext,
nsIFrame* aParent,
const gfxMatrix &aMatrix,
float aOpacity)
@@ -80,7 +80,7 @@ nsSVGMaskFrame::ComputeMaskAlpha(nsSVGRenderState *aContext,
gfxRect maskArea = nsSVGUtils::GetRelativeRect(units,
&mask->mLengthAttributes[nsSVGMaskElement::X], bbox, aParent);
- gfxContext *gfx = aContext->GetGfxContext();
+ gfxContext *gfx = aContext->ThebesContext();
gfx->Save();
nsSVGUtils::SetClipRect(gfx, aMatrix, maskArea);
@@ -113,7 +113,8 @@ nsSVGMaskFrame::ComputeMaskAlpha(nsSVGRenderState *aContext,
return nsnull;
image->SetDeviceOffset(-clipExtents.TopLeft());
- nsSVGRenderState tmpState(image);
+ nsRenderingContext tmpCtx;
+ tmpCtx.Init(this->PresContext()->DeviceContext(), image);
mMaskParent = aParent;
if (mMaskParentMatrix) {
@@ -130,7 +131,7 @@ nsSVGMaskFrame::ComputeMaskAlpha(nsSVGRenderState *aContext,
SVGFrame->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
nsISVGChildFrame::TRANSFORM_CHANGED);
}
- nsSVGUtils::PaintFrameWithEffects(&tmpState, nsnull, kid);
+ nsSVGUtils::PaintFrameWithEffects(&tmpCtx, nsnull, kid);
}
PRUint8 *data = image->Data();
diff --git a/layout/svg/base/src/nsSVGMaskFrame.h b/layout/svg/base/src/nsSVGMaskFrame.h
index 96f0db3c981d..d524bc102d16 100644
--- a/layout/svg/base/src/nsSVGMaskFrame.h
+++ b/layout/svg/base/src/nsSVGMaskFrame.h
@@ -42,6 +42,7 @@
#include "gfxMatrix.h"
class gfxContext;
+class nsRenderingContext;
typedef nsSVGContainerFrame nsSVGMaskFrameBase;
@@ -58,7 +59,7 @@ public:
NS_DECL_FRAMEARENA_HELPERS
// nsSVGMaskFrame method:
- already_AddRefed ComputeMaskAlpha(nsSVGRenderState *aContext,
+ already_AddRefed ComputeMaskAlpha(nsRenderingContext *aContext,
nsIFrame* aParent,
const gfxMatrix &aMatrix,
float aOpacity = 1.0f);
diff --git a/layout/svg/base/src/nsSVGOuterSVGFrame.cpp b/layout/svg/base/src/nsSVGOuterSVGFrame.cpp
index 6c80a8ddc849..070230743251 100644
--- a/layout/svg/base/src/nsSVGOuterSVGFrame.cpp
+++ b/layout/svg/base/src/nsSVGOuterSVGFrame.cpp
@@ -505,10 +505,70 @@ nsDisplaySVG::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
void
nsDisplaySVG::Paint(nsDisplayListBuilder* aBuilder,
- nsRenderingContext* aCtx)
+ nsRenderingContext* aContext)
{
- static_cast(mFrame)->
- Paint(aBuilder, *aCtx, mVisibleRect, ToReferenceFrame());
+ nsSVGOuterSVGFrame *frame = static_cast(mFrame);
+
+ if (frame->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)
+ return;
+
+#if defined(DEBUG) && defined(SVG_DEBUG_PAINT_TIMING)
+ PRTime start = PR_Now();
+#endif
+
+ aContext->PushState();
+
+#ifdef XP_MACOSX
+ if (frame->BitmapFallbackEnabled()) {
+ // nquartz fallback paths, which svg tends to trigger, need
+ // a non-window context target
+ aContext->ThebesContext()->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
+ }
+#endif
+
+ frame->Paint(aBuilder, aContext, mVisibleRect, ToReferenceFrame());
+
+#ifdef XP_MACOSX
+ if (frame->BitmapFallbackEnabled()) {
+ // show the surface we pushed earlier for fallbacks
+ aContext->ThebesContext()->PopGroupToSource();
+ aContext->ThebesContext()->Paint();
+ }
+
+ if (aContext->ThebesContext()->HasError() && !frame->BitmapFallbackEnabled()) {
+ frame->SetBitmapFallbackEnabled(true);
+ // It's not really clear what area to invalidate here. We might have
+ // stuffed up rendering for the entire window in this paint pass,
+ // so we can't just invalidate our own rect. Invalidate everything
+ // in sight.
+ // This won't work for printing, by the way, but failure to print the
+ // odd document is probably no worse than printing horribly for all
+ // documents. Better to fix things so we don't need fallback.
+ nsIFrame* ancestor = frame;
+ PRUint32 flags = 0;
+ while (true) {
+ nsIFrame* next = nsLayoutUtils::GetCrossDocParentFrame(ancestor);
+ if (!next)
+ break;
+ if (ancestor->GetParent() != next) {
+ // We're crossing a document boundary. Logically, the invalidation is
+ // being triggered by a subdocument of the root document. This will
+ // prevent an untrusted root document being told about invalidation
+ // that happened because a child was using SVG...
+ flags |= nsIFrame::INVALIDATE_CROSS_DOC;
+ }
+ ancestor = next;
+ }
+ ancestor->InvalidateWithFlags(nsRect(nsPoint(0, 0), ancestor->GetSize()), flags);
+ }
+#endif
+
+ aContext->PopState();
+
+#if defined(DEBUG) && defined(SVG_DEBUG_PAINT_TIMING)
+ PRTime end = PR_Now();
+ printf("SVG Paint Timing: %f ms\n", (end-start)/1000.0);
+#endif
}
// helper
@@ -585,88 +645,30 @@ nsSVGOuterSVGFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
void
nsSVGOuterSVGFrame::Paint(const nsDisplayListBuilder* aBuilder,
- nsRenderingContext& aRenderingContext,
+ nsRenderingContext* aContext,
const nsRect& aDirtyRect, nsPoint aPt)
{
- if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)
- return;
-
- // initialize Mozilla rendering context
- aRenderingContext.PushState();
-
nsRect viewportRect = GetContentRect();
nsPoint viewportOffset = aPt + viewportRect.TopLeft() - GetPosition();
viewportRect.MoveTo(viewportOffset);
nsRect clipRect;
clipRect.IntersectRect(aDirtyRect, viewportRect);
- aRenderingContext.IntersectClip(clipRect);
- aRenderingContext.Translate(viewportRect.TopLeft());
+ aContext->IntersectClip(clipRect);
+ aContext->Translate(viewportRect.TopLeft());
nsRect dirtyRect = clipRect - viewportOffset;
-#if defined(DEBUG) && defined(SVG_DEBUG_PAINT_TIMING)
- PRTime start = PR_Now();
-#endif
-
nsIntRect dirtyPxRect = dirtyRect.ToOutsidePixels(PresContext()->AppUnitsPerDevPixel());
- nsSVGRenderState ctx(&aRenderingContext);
+ // Create an SVGAutoRenderState so we can call SetPaintingToWindow on
+ // it, but don't change the render mode:
+ SVGAutoRenderState state(aContext, SVGAutoRenderState::GetRenderMode(aContext));
if (aBuilder->IsPaintingToWindow()) {
- ctx.SetPaintingToWindow(true);
+ state.SetPaintingToWindow(true);
}
-#ifdef XP_MACOSX
- if (mEnableBitmapFallback) {
- // nquartz fallback paths, which svg tends to trigger, need
- // a non-window context target
- ctx.GetGfxContext()->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
- }
-#endif
-
- nsSVGUtils::PaintFrameWithEffects(&ctx, &dirtyPxRect, this);
-
-#ifdef XP_MACOSX
- if (mEnableBitmapFallback) {
- // show the surface we pushed earlier for fallbacks
- ctx.GetGfxContext()->PopGroupToSource();
- ctx.GetGfxContext()->Paint();
- }
-
- if (ctx.GetGfxContext()->HasError() && !mEnableBitmapFallback) {
- mEnableBitmapFallback = true;
- // It's not really clear what area to invalidate here. We might have
- // stuffed up rendering for the entire window in this paint pass,
- // so we can't just invalidate our own rect. Invalidate everything
- // in sight.
- // This won't work for printing, by the way, but failure to print the
- // odd document is probably no worse than printing horribly for all
- // documents. Better to fix things so we don't need fallback.
- nsIFrame* frame = this;
- PRUint32 flags = 0;
- while (true) {
- nsIFrame* next = nsLayoutUtils::GetCrossDocParentFrame(frame);
- if (!next)
- break;
- if (frame->GetParent() != next) {
- // We're crossing a document boundary. Logically, the invalidation is
- // being triggered by a subdocument of the root document. This will
- // prevent an untrusted root document being told about invalidation
- // that happened because a child was using SVG...
- flags |= INVALIDATE_CROSS_DOC;
- }
- frame = next;
- }
- frame->InvalidateWithFlags(nsRect(nsPoint(0, 0), frame->GetSize()), flags);
- }
-#endif
-
-#if defined(DEBUG) && defined(SVG_DEBUG_PAINT_TIMING)
- PRTime end = PR_Now();
- printf("SVG Paint Timing: %f ms\n", (end-start)/1000.0);
-#endif
-
- aRenderingContext.PopState();
+ nsSVGUtils::PaintFrameWithEffects(aContext, &dirtyPxRect, this);
}
nsSplittableType
diff --git a/layout/svg/base/src/nsSVGOuterSVGFrame.h b/layout/svg/base/src/nsSVGOuterSVGFrame.h
index c5f6cf872086..2283705820e7 100644
--- a/layout/svg/base/src/nsSVGOuterSVGFrame.h
+++ b/layout/svg/base/src/nsSVGOuterSVGFrame.h
@@ -110,7 +110,7 @@ public:
virtual nsIAtom* GetType() const;
void Paint(const nsDisplayListBuilder* aBuilder,
- nsRenderingContext& aRenderingContext,
+ nsRenderingContext* aContext,
const nsRect& aDirtyRect, nsPoint aPt);
#ifdef DEBUG
@@ -140,6 +140,16 @@ public:
void RegisterForeignObject(nsSVGForeignObjectFrame* aFrame);
void UnregisterForeignObject(nsSVGForeignObjectFrame* aFrame);
+#ifdef XP_MACOSX
+ bool BitmapFallbackEnabled() const {
+ return mEnableBitmapFallback;
+ }
+ void SetBitmapFallbackEnabled(bool aVal) {
+ NS_NOTREACHED("don't think me need this any more"); // comment in bug 732429 if we do
+ mEnableBitmapFallback = aVal;
+ }
+#endif
+
protected:
/* Returns true if our content is the document element and our document is
diff --git a/layout/svg/base/src/nsSVGPathGeometryFrame.cpp b/layout/svg/base/src/nsSVGPathGeometryFrame.cpp
index e235a67a146e..110cba877db4 100644
--- a/layout/svg/base/src/nsSVGPathGeometryFrame.cpp
+++ b/layout/svg/base/src/nsSVGPathGeometryFrame.cpp
@@ -108,7 +108,7 @@ nsSVGPathGeometryFrame::GetType() const
// nsISVGChildFrame methods
NS_IMETHODIMP
-nsSVGPathGeometryFrame::PaintSVG(nsSVGRenderState *aContext,
+nsSVGPathGeometryFrame::PaintSVG(nsRenderingContext *aContext,
const nsIntRect *aDirtyRect)
{
if (!GetStyleVisibility()->IsVisible())
@@ -437,11 +437,11 @@ nsSVGPathGeometryFrame::MarkerProperties::GetMarkerEndFrame()
}
void
-nsSVGPathGeometryFrame::Render(nsSVGRenderState *aContext)
+nsSVGPathGeometryFrame::Render(nsRenderingContext *aContext)
{
- gfxContext *gfx = aContext->GetGfxContext();
+ gfxContext *gfx = aContext->ThebesContext();
- PRUint16 renderMode = aContext->GetRenderMode();
+ PRUint16 renderMode = SVGAutoRenderState::GetRenderMode(aContext);
switch (GetStyleSVG()->mShapeRendering) {
case NS_STYLE_SHAPE_RENDERING_OPTIMIZESPEED:
@@ -458,7 +458,7 @@ nsSVGPathGeometryFrame::Render(nsSVGRenderState *aContext)
GeneratePath(gfx);
- if (renderMode != nsSVGRenderState::NORMAL) {
+ if (renderMode != SVGAutoRenderState::NORMAL) {
gfx->Restore();
if (GetClipRule() == NS_STYLE_FILL_RULE_EVENODD)
@@ -466,7 +466,7 @@ nsSVGPathGeometryFrame::Render(nsSVGRenderState *aContext)
else
gfx->SetFillRule(gfxContext::FILL_RULE_WINDING);
- if (renderMode == nsSVGRenderState::CLIP_MASK) {
+ if (renderMode == SVGAutoRenderState::CLIP_MASK) {
gfx->SetColor(gfxRGBA(1.0f, 1.0f, 1.0f, 1.0f));
gfx->Fill();
gfx->NewPath();
diff --git a/layout/svg/base/src/nsSVGPathGeometryFrame.h b/layout/svg/base/src/nsSVGPathGeometryFrame.h
index 5a2114779a6d..2c8bd08ce718 100644
--- a/layout/svg/base/src/nsSVGPathGeometryFrame.h
+++ b/layout/svg/base/src/nsSVGPathGeometryFrame.h
@@ -45,6 +45,7 @@
#include "nsGkAtoms.h"
#include "nsSVGGeometryFrame.h"
+class nsRenderingContext;
class nsSVGMarkerFrame;
class nsSVGMarkerProperty;
@@ -89,7 +90,7 @@ public:
protected:
// nsISVGChildFrame interface:
- NS_IMETHOD PaintSVG(nsSVGRenderState *aContext,
+ NS_IMETHOD PaintSVG(nsRenderingContext *aContext,
const nsIntRect *aDirtyRect);
NS_IMETHOD_(nsIFrame*) GetFrameForPoint(const nsPoint &aPoint);
NS_IMETHOD_(nsRect) GetCoveredRegion();
@@ -110,7 +111,7 @@ protected:
const gfxMatrix *aOverrideTransform = nsnull);
private:
- void Render(nsSVGRenderState *aContext);
+ void Render(nsRenderingContext *aContext);
struct MarkerProperties {
nsSVGMarkerProperty* mMarkerStart;
diff --git a/layout/svg/base/src/nsSVGPatternFrame.cpp b/layout/svg/base/src/nsSVGPatternFrame.cpp
index 9a57343bbbb9..02028fd4eb76 100644
--- a/layout/svg/base/src/nsSVGPatternFrame.cpp
+++ b/layout/svg/base/src/nsSVGPatternFrame.cpp
@@ -295,17 +295,18 @@ nsSVGPatternFrame::PaintPattern(gfxASurface** surface,
if (!tmpSurface || tmpSurface->CairoStatus())
return NS_ERROR_FAILURE;
- nsSVGRenderState tmpState(tmpSurface);
- gfxContext* tmpContext = tmpState.GetGfxContext();
+ nsRenderingContext context;
+ context.Init(aSource->PresContext()->DeviceContext(), tmpSurface);
+ gfxContext* gfx = context.ThebesContext();
// Fill with transparent black
- tmpContext->SetOperator(gfxContext::OPERATOR_CLEAR);
- tmpContext->Paint();
- tmpContext->SetOperator(gfxContext::OPERATOR_OVER);
+ gfx->SetOperator(gfxContext::OPERATOR_CLEAR);
+ gfx->Paint();
+ gfx->SetOperator(gfxContext::OPERATOR_OVER);
if (aGraphicOpacity != 1.0f) {
- tmpContext->Save();
- tmpContext->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
+ gfx->Save();
+ gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
}
// OK, now render -- note that we use "firstKid", which
@@ -329,7 +330,7 @@ nsSVGPatternFrame::PaintPattern(gfxASurface** surface,
SVGFrame->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
nsISVGChildFrame::TRANSFORM_CHANGED);
}
- nsSVGUtils::PaintFrameWithEffects(&tmpState, nsnull, kid);
+ nsSVGUtils::PaintFrameWithEffects(&context, nsnull, kid);
}
patternFrame->RemoveStateBits(NS_FRAME_DRAWING_AS_PAINTSERVER);
}
@@ -337,9 +338,9 @@ nsSVGPatternFrame::PaintPattern(gfxASurface** surface,
patternFrame->mSource = nsnull;
if (aGraphicOpacity != 1.0f) {
- tmpContext->PopGroupToSource();
- tmpContext->Paint(aGraphicOpacity);
- tmpContext->Restore();
+ gfx->PopGroupToSource();
+ gfx->Paint(aGraphicOpacity);
+ gfx->Restore();
}
// caller now owns the surface
diff --git a/layout/svg/base/src/nsSVGSwitchFrame.cpp b/layout/svg/base/src/nsSVGSwitchFrame.cpp
index f57c5798a39f..d7445249191e 100644
--- a/layout/svg/base/src/nsSVGSwitchFrame.cpp
+++ b/layout/svg/base/src/nsSVGSwitchFrame.cpp
@@ -41,6 +41,8 @@
#include "gfxRect.h"
#include "gfxMatrix.h"
+class nsRenderingContext;
+
typedef nsSVGGFrame nsSVGSwitchFrameBase;
class nsSVGSwitchFrame : public nsSVGSwitchFrameBase
@@ -75,7 +77,7 @@ public:
#endif
// nsISVGChildFrame interface:
- NS_IMETHOD PaintSVG(nsSVGRenderState* aContext, const nsIntRect *aDirtyRect);
+ NS_IMETHOD PaintSVG(nsRenderingContext* aContext, const nsIntRect *aDirtyRect);
NS_IMETHODIMP_(nsIFrame*) GetFrameForPoint(const nsPoint &aPoint);
NS_IMETHODIMP_(nsRect) GetCoveredRegion();
NS_IMETHOD UpdateCoveredRegion();
@@ -119,7 +121,7 @@ nsSVGSwitchFrame::GetType() const
}
NS_IMETHODIMP
-nsSVGSwitchFrame::PaintSVG(nsSVGRenderState* aContext,
+nsSVGSwitchFrame::PaintSVG(nsRenderingContext* aContext,
const nsIntRect *aDirtyRect)
{
const nsStyleDisplay *display = mStyleContext->GetStyleDisplay();
diff --git a/layout/svg/base/src/nsSVGTextFrame.cpp b/layout/svg/base/src/nsSVGTextFrame.cpp
index 187f153e798c..cbdae2d8d3cd 100644
--- a/layout/svg/base/src/nsSVGTextFrame.cpp
+++ b/layout/svg/base/src/nsSVGTextFrame.cpp
@@ -219,7 +219,7 @@ nsSVGTextFrame::NotifyRedrawUnsuspended()
}
NS_IMETHODIMP
-nsSVGTextFrame::PaintSVG(nsSVGRenderState* aContext,
+nsSVGTextFrame::PaintSVG(nsRenderingContext* aContext,
const nsIntRect *aDirtyRect)
{
UpdateGlyphPositioning(true);
diff --git a/layout/svg/base/src/nsSVGTextFrame.h b/layout/svg/base/src/nsSVGTextFrame.h
index ba8b6f02e3a0..a2e08da4eeba 100644
--- a/layout/svg/base/src/nsSVGTextFrame.h
+++ b/layout/svg/base/src/nsSVGTextFrame.h
@@ -43,6 +43,8 @@
#include "gfxRect.h"
#include "gfxMatrix.h"
+class nsRenderingContext;
+
typedef nsSVGTextContainerFrame nsSVGTextFrameBase;
class nsSVGTextFrame : public nsSVGTextFrameBase
@@ -87,7 +89,7 @@ public:
virtual void NotifyRedrawUnsuspended();
// Override these four to ensure that UpdateGlyphPositioning is called
// to bring glyph positions up to date
- NS_IMETHOD PaintSVG(nsSVGRenderState* aContext,
+ NS_IMETHOD PaintSVG(nsRenderingContext* aContext,
const nsIntRect *aDirtyRect);
NS_IMETHOD_(nsIFrame*) GetFrameForPoint(const nsPoint & aPoint);
NS_IMETHOD UpdateCoveredRegion();
diff --git a/layout/svg/base/src/nsSVGUtils.cpp b/layout/svg/base/src/nsSVGUtils.cpp
index b2df85abe846..6358215f46fc 100644
--- a/layout/svg/base/src/nsSVGUtils.cpp
+++ b/layout/svg/base/src/nsSVGUtils.cpp
@@ -196,6 +196,56 @@ NS_SMILEnabled()
return gSMILEnabled;
}
+// we only take the address of this:
+static mozilla::gfx::UserDataKey sSVGAutoRenderStateKey;
+
+SVGAutoRenderState::SVGAutoRenderState(nsRenderingContext *aContext,
+ RenderMode aMode)
+ : mContext(aContext)
+ , mOriginalRenderState(nsnull)
+ , mMode(aMode)
+ , mPaintingToWindow(false)
+{
+ mOriginalRenderState = aContext->RemoveUserData(&sSVGAutoRenderStateKey);
+ // We always remove ourselves from aContext before it dies, so
+ // passing nsnull as the destroy function is okay.
+ aContext->AddUserData(&sSVGAutoRenderStateKey, this, nsnull);
+}
+
+SVGAutoRenderState::~SVGAutoRenderState()
+{
+ mContext->RemoveUserData(&sSVGAutoRenderStateKey);
+ if (mOriginalRenderState) {
+ mContext->AddUserData(&sSVGAutoRenderStateKey, mOriginalRenderState, nsnull);
+ }
+}
+
+void
+SVGAutoRenderState::SetPaintingToWindow(bool aPaintingToWindow)
+{
+ mPaintingToWindow = aPaintingToWindow;
+}
+
+/* static */ SVGAutoRenderState::RenderMode
+SVGAutoRenderState::GetRenderMode(nsRenderingContext *aContext)
+{
+ void *state = aContext->GetUserData(&sSVGAutoRenderStateKey);
+ if (state) {
+ return static_cast(state)->mMode;
+ }
+ return NORMAL;
+}
+
+/* static */ bool
+SVGAutoRenderState::IsPaintingToWindow(nsRenderingContext *aContext)
+{
+ void *state = aContext->GetUserData(&sSVGAutoRenderStateKey);
+ if (state) {
+ return static_cast(state)->mPaintingToWindow;
+ }
+ return false;
+}
+
nsSVGSVGElement*
nsSVGUtils::GetOuterSVGElement(nsSVGElement *aSVGElement)
{
@@ -960,7 +1010,7 @@ nsSVGUtils::NotifyRedrawUnsuspended(nsIFrame *aFrame)
class SVGPaintCallback : public nsSVGFilterPaintCallback
{
public:
- virtual void Paint(nsSVGRenderState *aContext, nsIFrame *aTarget,
+ virtual void Paint(nsRenderingContext *aContext, nsIFrame *aTarget,
const nsIntRect* aDirtyRect)
{
nsISVGChildFrame *svgChildFrame = do_QueryFrame(aTarget);
@@ -989,7 +1039,7 @@ public:
};
void
-nsSVGUtils::PaintFrameWithEffects(nsSVGRenderState *aContext,
+nsSVGUtils::PaintFrameWithEffects(nsRenderingContext *aContext,
const nsIntRect *aDirtyRect,
nsIFrame *aFrame)
{
@@ -1046,7 +1096,7 @@ nsSVGUtils::PaintFrameWithEffects(nsSVGRenderState *aContext,
if (opacity != 1.0f && CanOptimizeOpacity(aFrame))
opacity = 1.0f;
- gfxContext *gfx = aContext->GetGfxContext();
+ gfxContext *gfx = aContext->ThebesContext();
bool complexEffects = false;
nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
@@ -1579,34 +1629,6 @@ nsSVGUtils::PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents,
// ----------------------------------------------------------------------
-nsSVGRenderState::nsSVGRenderState(nsRenderingContext *aContext) :
- mRenderMode(NORMAL), mRenderingContext(aContext), mPaintingToWindow(false)
-{
- mGfxContext = aContext->ThebesContext();
-}
-
-nsSVGRenderState::nsSVGRenderState(gfxContext *aContext) :
- mRenderMode(NORMAL), mGfxContext(aContext), mPaintingToWindow(false)
-{
-}
-
-nsSVGRenderState::nsSVGRenderState(gfxASurface *aSurface) :
- mRenderMode(NORMAL), mPaintingToWindow(false)
-{
- mGfxContext = new gfxContext(aSurface);
-}
-
-nsRenderingContext*
-nsSVGRenderState::GetRenderingContext(nsIFrame *aFrame)
-{
- if (!mRenderingContext) {
- mRenderingContext = new nsRenderingContext();
- mRenderingContext->Init(aFrame->PresContext()->DeviceContext(),
- mGfxContext);
- }
- return mRenderingContext;
-}
-
/* static */ bool
nsSVGUtils::RootSVGElementHasViewbox(const nsIContent *aRootSVGElem)
{
diff --git a/layout/svg/base/src/nsSVGUtils.h b/layout/svg/base/src/nsSVGUtils.h
index e7fcb2ed3c6d..ada73571f51e 100644
--- a/layout/svg/base/src/nsSVGUtils.h
+++ b/layout/svg/base/src/nsSVGUtils.h
@@ -149,59 +149,30 @@ IsSVGWhitespace(PRUnichar aChar)
*/
bool NS_SMILEnabled();
+
// GRRR WINDOWS HATE HATE HATE
#undef CLIP_MASK
-class nsSVGRenderState
+class NS_STACK_CLASS SVGAutoRenderState
{
public:
enum RenderMode { NORMAL, CLIP, CLIP_MASK };
- /**
- * Render SVG to a legacy rendering context
- */
- nsSVGRenderState(nsRenderingContext *aContext);
- /**
- * Render SVG to a modern rendering context
- */
- nsSVGRenderState(gfxContext *aContext);
- /**
- * Render SVG to a temporary surface
- */
- nsSVGRenderState(gfxASurface *aSurface);
+ SVGAutoRenderState(nsRenderingContext *aContext, RenderMode aMode);
+ ~SVGAutoRenderState();
- nsRenderingContext *GetRenderingContext(nsIFrame *aFrame);
- gfxContext *GetGfxContext() { return mGfxContext; }
+ void SetPaintingToWindow(bool aPaintingToWindow);
- void SetRenderMode(RenderMode aMode) { mRenderMode = aMode; }
- RenderMode GetRenderMode() { return mRenderMode; }
-
- void SetPaintingToWindow(bool aPaintingToWindow) {
- mPaintingToWindow = aPaintingToWindow;
- }
- bool IsPaintingToWindow() { return mPaintingToWindow; }
+ static RenderMode GetRenderMode(nsRenderingContext *aContext);
+ static bool IsPaintingToWindow(nsRenderingContext *aContext);
private:
- RenderMode mRenderMode;
- nsRefPtr mRenderingContext;
- nsRefPtr mGfxContext;
- bool mPaintingToWindow;
+ nsRenderingContext *mContext;
+ void *mOriginalRenderState;
+ RenderMode mMode;
+ bool mPaintingToWindow;
};
-class nsAutoSVGRenderMode
-{
-public:
- nsAutoSVGRenderMode(nsSVGRenderState *aState,
- nsSVGRenderState::RenderMode aMode) : mState(aState) {
- mOriginalMode = aState->GetRenderMode();
- aState->SetRenderMode(aMode);
- }
- ~nsAutoSVGRenderMode() { mState->SetRenderMode(mOriginalMode); }
-
-private:
- nsSVGRenderState *mState;
- nsSVGRenderState::RenderMode mOriginalMode;
-};
#define NS_ISVGFILTERPROPERTY_IID \
{ 0x9744ee20, 0x1bcf, 0x4c62, \
@@ -401,7 +372,7 @@ public:
/* Paint SVG frame with SVG effects - aDirtyRect is the area being
* redrawn, in device pixel coordinates relative to the outer svg */
static void
- PaintFrameWithEffects(nsSVGRenderState *aContext,
+ PaintFrameWithEffects(nsRenderingContext *aContext,
const nsIntRect *aDirtyRect,
nsIFrame *aFrame);
diff --git a/layout/tools/reftest/remotereftest.py b/layout/tools/reftest/remotereftest.py
index bedee7300aba..cf10c6a3c23f 100644
--- a/layout/tools/reftest/remotereftest.py
+++ b/layout/tools/reftest/remotereftest.py
@@ -364,23 +364,6 @@ user_pref("capability.principal.codebase.p2.id", "http://%s:%s");
if (self._devicemanager.pushDir(profileDir, options.remoteProfile) == None):
raise devicemanager.FileError("Failed to copy extra files to device")
- def registerExtension(self, browserEnv, options, profileDir, extraArgs = ['-silent'] ):
- if options.bootstrap:
- return
-
- self.automation.log.info("REFTEST INFO | runreftest.py | Performing extension manager registration: start.\n")
- # Because our startProcess code doesn't return until fennec starts we just give it
- # a maxTime of 20 secs before timing it out and ensuring it is dead.
- # Besides registering the extension, this works around fennec bug 570027
- status = self.automation.runApp(None, browserEnv, options.app, profileDir,
- extraArgs,
- utilityPath = options.utilityPath,
- xrePath=options.xrePath,
- symbolsPath=options.symbolsPath,
- maxTime = 20)
- # We don't care to call |processLeakLog()| for this step.
- self.automation.log.info("\nREFTEST INFO | runreftest.py | Performing extension manager registration: end.")
-
def getManifestPath(self, path):
return path
diff --git a/layout/tools/reftest/runreftest.py b/layout/tools/reftest/runreftest.py
index a8f869fe9c8b..7b15887b0e1d 100644
--- a/layout/tools/reftest/runreftest.py
+++ b/layout/tools/reftest/runreftest.py
@@ -113,25 +113,6 @@ class RefTest(object):
profileDir,
"reftest@mozilla.org")
-
- def registerExtension(self, browserEnv, options, profileDir, extraArgs = ['-silent']):
- # run once with -silent to let the extension manager do its thing
- # and then exit the app
- self.automation.log.info("REFTEST INFO | runreftest.py | Performing extension manager registration: start.\n")
- # Don't care about this |status|: |runApp()| reporting it should be enough.
- status = self.automation.runApp(None, browserEnv, options.app, profileDir,
- extraArgs,
- utilityPath = options.utilityPath,
- xrePath=options.xrePath,
- symbolsPath=options.symbolsPath)
- # We don't care to call |processLeakLog()| for this step.
- self.automation.log.info("\nREFTEST INFO | runreftest.py | Performing extension manager registration: end.")
-
- # Remove the leak detection file so it can't "leak" to the tests run.
- # The file is not there if leak logging was not enabled in the application build.
- if os.path.exists(self.leakLogFile):
- os.remove(self.leakLogFile)
-
def buildBrowserEnv(self, options, profileDir):
browserEnv = self.automation.environment(xrePath = options.xrePath)
browserEnv["XPCOM_DEBUG_BREAK"] = "stack"
@@ -162,9 +143,6 @@ class RefTest(object):
# browser environment
browserEnv = self.buildBrowserEnv(options, profileDir)
- self.registerExtension(browserEnv, options, profileDir)
-
- # then again to actually run reftest
self.automation.log.info("REFTEST INFO | runreftest.py | Running tests: start.\n")
status = self.automation.runApp(None, browserEnv, options.app, profileDir,
cmdlineArgs,
diff --git a/mfbt/Attributes.h b/mfbt/Attributes.h
index d3bc3de9b7ec..4713b2c3f7a4 100644
--- a/mfbt/Attributes.h
+++ b/mfbt/Attributes.h
@@ -320,6 +320,25 @@
# define MOZ_FINAL /* no support */
#endif
+/**
+ * MOZ_WARN_UNUSED_RESULT tells the compiler to emit a warning if a function's
+ * return value is not used by the caller.
+ *
+ * Place this attribute at the very beginning of a function definition. For
+ * example, write
+ *
+ * MOZ_WARN_UNUSED_RESULT int foo();
+ *
+ * or
+ *
+ * MOZ_WARN_UNUSED_RESULT int foo() { return 42; }
+ */
+#if defined(__GNUC__) || defined(__clang__)
+# define MOZ_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
+#else
+# define MOZ_WARN_UNUSED_RESULT
+#endif
+
#endif /* __cplusplus */
#endif /* mozilla_Attributes_h_ */
diff --git a/mfbt/HashFunctions.h b/mfbt/HashFunctions.h
new file mode 100644
index 000000000000..9bc088a20bd8
--- /dev/null
+++ b/mfbt/HashFunctions.h
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sw=4 et tw=99 ft=cpp:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Utilities for hashing */
+
+#ifndef mozilla_HashFunctions_h_
+#define mozilla_HashFunctions_h_
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/StandardInteger.h"
+
+#ifdef __cplusplus
+namespace mozilla {
+
+/**
+ * The golden ratio as a 32-bit fixed-point value.
+ */
+static const uint32_t GoldenRatioU32 = 0x9E3779B9U;
+
+inline uint32_t
+RotateLeft32(uint32_t value, uint8_t bits)
+{
+ MOZ_ASSERT(bits < 32);
+ return (value << bits) | (value >> (32 - bits));
+}
+
+/**
+ * Add the given value(s) to the given hashcode and return the new hashcode.
+ *
+ * AddToHash(h, x, y) is equivalent to AddToHash(AddToHash(h, x), y).
+ */
+MOZ_WARN_UNUSED_RESULT
+inline uint32_t
+AddToHash(uint32_t hash, uint32_t value)
+{
+ /*
+ * This is not a sophisticated hash routine, but it seems to work well for our
+ * mostly plain-text inputs. Implementation notes follow.
+ *
+ * Our use of the golden ratio here is arbitrary; we could pick almost any
+ * number which:
+ *
+ * * is odd (because otherwise, all our hash values will be even)
+ *
+ * * has a reasonably-even mix of 1's and 0's (consider the extreme case
+ * where we multiply by 0x3 or 0xeffffff -- this will not produce good
+ * mixing across all bits of the hash).
+ *
+ * The rotation length of 5 is also arbitrary, although an odd number is again
+ * preferable so our hash explores the whole universe of possible rotations.
+ *
+ * Finally, we multiply by the golden ratio *after* xor'ing, not before.
+ * Otherwise, if |hash| is 0 (as it often is for the beginning of a message),
+ * the expression
+ *
+ * (GoldenRatioU32 * RotateLeft(hash, 5)) ^ value
+ *
+ * evaluates to |value|.
+ *
+ * (Number-theoretic aside: Because any odd number |m| is relatively prime to
+ * our modulus (2^32), the list
+ *
+ * [x * m (mod 2^32) for 0 <= x < 2^32]
+ *
+ * has no duplicate elements. This means that multiplying by |m| does not
+ * cause us to skip any possible hash values.
+ *
+ * It's also nice if |m| has larger order mod 2^32 -- that is, if the smallest
+ * k such that m^k == 1 (mod 2^32) is large -- so we can safely multiply our
+ * hash value by |m| a few times without negating the multiplicative effect.
+ * Our golden ratio constant has order 2^29, which is more than enough for our
+ * purposes.)
+ */
+ return GoldenRatioU32 * (RotateLeft32(hash, 5) ^ value);
+}
+
+MOZ_WARN_UNUSED_RESULT
+inline uint32_t
+AddToHash(uint32_t hash, uint32_t v1, uint32_t v2)
+{
+ return AddToHash(AddToHash(hash, v1), v2);
+}
+
+MOZ_WARN_UNUSED_RESULT
+inline uint32_t
+AddToHash(uint32_t hash, uint32_t v1, uint32_t v2, uint32_t v3)
+{
+ return AddToHash(AddToHash(hash, v1, v2), v3);
+}
+
+MOZ_WARN_UNUSED_RESULT
+inline uint32_t
+AddToHash(uint32_t hash, uint32_t v1, uint32_t v2, uint32_t v3, uint32_t v4)
+{
+ return AddToHash(AddToHash(hash, v1, v2, v3), v4);
+}
+
+MOZ_WARN_UNUSED_RESULT
+inline uint32_t
+AddToHash(uint32_t hash, uint32_t v1, uint32_t v2, uint32_t v3, uint32_t v4, uint32_t v5)
+{
+ return AddToHash(AddToHash(hash, v1, v2, v3, v4), v5);
+}
+
+} /* namespace mozilla */
+#endif /* __cplusplus */
+#endif /* mozilla_HashFunctions_h_ */
diff --git a/mfbt/Types.h b/mfbt/Types.h
index 4a540392bb48..6899719463ec 100644
--- a/mfbt/Types.h
+++ b/mfbt/Types.h
@@ -101,7 +101,7 @@
* depending upon the compilation mode.
*/
#ifdef _WIN32
-# if defined(__MWERKS__) || defined(__GNUC__)
+# if defined(__MWERKS__)
# define MOZ_IMPORT_API(x) x
# else
# define MOZ_IMPORT_API(x) __declspec(dllimport) x
diff --git a/mfbt/exported_headers.mk b/mfbt/exported_headers.mk
index 1ca535712295..12294fc024a4 100644
--- a/mfbt/exported_headers.mk
+++ b/mfbt/exported_headers.mk
@@ -46,6 +46,7 @@ EXPORTS_mozilla += \
Attributes.h \
BloomFilter.h \
GuardObjects.h \
+ HashFunctions.h \
Likely.h \
LinkedList.h \
MSStdInt.h \
diff --git a/mobile/android/base/sync/CryptoRecord.java b/mobile/android/base/sync/CryptoRecord.java
index 6c53b8961f36..4e3c0dc45e7a 100644
--- a/mobile/android/base/sync/CryptoRecord.java
+++ b/mobile/android/base/sync/CryptoRecord.java
@@ -236,12 +236,22 @@ public class CryptoRecord extends Record {
}
@Override
- public void initFromPayload(CryptoRecord payload) {
+ public void initFromEnvelope(CryptoRecord payload) {
throw new IllegalStateException("Can't do this with a CryptoRecord.");
}
@Override
- public CryptoRecord getPayload() {
+ public CryptoRecord getEnvelope() {
+ throw new IllegalStateException("Can't do this with a CryptoRecord.");
+ }
+
+ @Override
+ protected void populatePayload(ExtendedJSONObject payload) {
+ throw new IllegalStateException("Can't do this with a CryptoRecord.");
+ }
+
+ @Override
+ protected void initFromPayload(ExtendedJSONObject payload) {
throw new IllegalStateException("Can't do this with a CryptoRecord.");
}
diff --git a/mobile/android/base/sync/ExtendedJSONObject.java b/mobile/android/base/sync/ExtendedJSONObject.java
index 6b2ad31212a4..0e9f195fd5d0 100644
--- a/mobile/android/base/sync/ExtendedJSONObject.java
+++ b/mobile/android/base/sync/ExtendedJSONObject.java
@@ -127,6 +127,9 @@ public class ExtendedJSONObject {
public Long getLong(String key) {
return (Long) this.get(key);
}
+ public String getString(String key) {
+ return (String) this.get(key);
+ }
/**
* Return a server timestamp value as milliseconds since epoch.
diff --git a/mobile/android/base/sync/GlobalConstants.java.in b/mobile/android/base/sync/GlobalConstants.java.in
index 3c0b42aa1eed..464705d719dc 100644
--- a/mobile/android/base/sync/GlobalConstants.java.in
+++ b/mobile/android/base/sync/GlobalConstants.java.in
@@ -9,4 +9,9 @@ package org.mozilla.gecko.sync;
* Preprocessed class for storing preprocessed values.
*/
public class GlobalConstants {
+ public static final String PRODUCT_NAME = "@MOZ_APP_DISPLAYNAME@";
+ public static final String SYNC_VERSION_STRING = "0.6";
+
+ public static final String USER_AGENT = "Firefox AndroidSync " + SYNC_VERSION_STRING +
+ " (" + PRODUCT_NAME + ")";
}
diff --git a/mobile/android/base/sync/jpake/stage/ComputeKeyVerificationStage.java b/mobile/android/base/sync/jpake/stage/ComputeKeyVerificationStage.java
index ac4b82d67ee4..5b47bfab0c97 100644
--- a/mobile/android/base/sync/jpake/stage/ComputeKeyVerificationStage.java
+++ b/mobile/android/base/sync/jpake/stage/ComputeKeyVerificationStage.java
@@ -21,6 +21,7 @@ public class ComputeKeyVerificationStage extends JPakeStage {
if (jClient.myKeyBundle == null) {
Logger.error(LOG_TAG, "KeyBundle has not been set; aborting.");
jClient.abort(Constants.JPAKE_ERROR_INTERNAL);
+ return;
}
try {
jClient.jOutgoing = computeKeyVerification(jClient.myKeyBundle, jClient.mySignerId);
diff --git a/mobile/android/base/sync/jpake/stage/GetChannelStage.java b/mobile/android/base/sync/jpake/stage/GetChannelStage.java
index e51747b885ec..7efd92dd3700 100644
--- a/mobile/android/base/sync/jpake/stage/GetChannelStage.java
+++ b/mobile/android/base/sync/jpake/stage/GetChannelStage.java
@@ -52,13 +52,16 @@ public class GetChannelStage extends JPakeStage {
@Override
public void handleFailure(String error) {
+ Logger.error(LOG_TAG, "Got HTTP failure: " + error);
jClient.abort(error);
+ return;
}
@Override
public void handleError(Exception e) {
Logger.error(LOG_TAG, "Threw HTTP exception.", e);
jClient.abort(Constants.JPAKE_ERROR_CHANNEL);
+ return;
}
};
@@ -67,9 +70,11 @@ public class GetChannelStage extends JPakeStage {
} catch (URISyntaxException e) {
Logger.error(LOG_TAG, "Incorrect URI syntax.", e);
jClient.abort(Constants.JPAKE_ERROR_INVALID);
+ return;
} catch (Exception e) {
Logger.error(LOG_TAG, "Unexpected exception.", e);
jClient.abort(Constants.JPAKE_ERROR_INTERNAL);
+ return;
}
}
diff --git a/mobile/android/base/sync/jpake/stage/GetRequestStage.java b/mobile/android/base/sync/jpake/stage/GetRequestStage.java
index 4064f719ebad..d697e6e624b9 100644
--- a/mobile/android/base/sync/jpake/stage/GetRequestStage.java
+++ b/mobile/android/base/sync/jpake/stage/GetRequestStage.java
@@ -73,13 +73,16 @@ public class GetRequestStage extends JPakeStage {
@Override
public void handleFailure(String error) {
+ Logger.error(LOG_TAG, "Got HTTP failure: " + error);
jClient.abort(error);
+ return;
}
@Override
public void handleError(Exception e) {
Logger.error(LOG_TAG, "Threw HTTP exception.", e);
jClient.abort(Constants.JPAKE_ERROR_NETWORK);
+ return;
}
};
diff --git a/mobile/android/base/sync/jpake/stage/PutRequestStage.java b/mobile/android/base/sync/jpake/stage/PutRequestStage.java
index 3ca4335203e4..bdf0c2e7fa6e 100644
--- a/mobile/android/base/sync/jpake/stage/PutRequestStage.java
+++ b/mobile/android/base/sync/jpake/stage/PutRequestStage.java
@@ -58,13 +58,16 @@ public class PutRequestStage extends JPakeStage {
@Override
public void handleFailure(String error) {
+ Logger.error(LOG_TAG, "Got HTTP failure: " + error);
jClient.abort(error);
+ return;
}
@Override
public void handleError(Exception e) {
Logger.error(LOG_TAG, "HTTP exception.", e);
jClient.abort(Constants.JPAKE_ERROR_NETWORK);
+ return;
}
};
@@ -81,7 +84,9 @@ public class PutRequestStage extends JPakeStage {
try {
putRequest.put(JPakeClient.jsonEntity(jClient.jOutgoing.object));
} catch (UnsupportedEncodingException e) {
- e.printStackTrace();
+ Logger.error(LOG_TAG, "UnsupportedEncodingException", e);
+ jClient.abort(Constants.JPAKE_ERROR_INTERNAL);
+ return;
}
Logger.debug(LOG_TAG, "Outgoing message: " + jClient.jOutgoing.toJSONString());
}
diff --git a/mobile/android/base/sync/jpake/stage/VerifyPairingStage.java b/mobile/android/base/sync/jpake/stage/VerifyPairingStage.java
index 056b0f99ee9f..d2b5c76e2c83 100644
--- a/mobile/android/base/sync/jpake/stage/VerifyPairingStage.java
+++ b/mobile/android/base/sync/jpake/stage/VerifyPairingStage.java
@@ -54,6 +54,7 @@ public class VerifyPairingStage extends JPakeStage {
} else {
Logger.error(LOG_TAG, "Keys don't match.");
jClient.abort(Constants.JPAKE_ERROR_KEYMISMATCH);
+ return;
}
}
diff --git a/mobile/android/base/sync/middleware/Crypto5MiddlewareRepositorySession.java b/mobile/android/base/sync/middleware/Crypto5MiddlewareRepositorySession.java
index e17135ac598b..e2af12a8b7da 100644
--- a/mobile/android/base/sync/middleware/Crypto5MiddlewareRepositorySession.java
+++ b/mobile/android/base/sync/middleware/Crypto5MiddlewareRepositorySession.java
@@ -216,7 +216,7 @@ public class Crypto5MiddlewareRepositorySession extends RepositorySession {
if (delegate == null) {
throw new NoStoreDelegateException();
}
- CryptoRecord rec = record.getPayload();
+ CryptoRecord rec = record.getEnvelope();
rec.keyBundle = this.keyBundle;
try {
rec.encrypt();
diff --git a/mobile/android/base/sync/net/BaseResource.java b/mobile/android/base/sync/net/BaseResource.java
index 3d333b9ee230..999094df150e 100644
--- a/mobile/android/base/sync/net/BaseResource.java
+++ b/mobile/android/base/sync/net/BaseResource.java
@@ -177,7 +177,7 @@ public class BaseResource implements Resource {
}
}
- public static ClientConnectionManager enableTLSConnectionManager() throws KeyManagementException, NoSuchAlgorithmException {
+ private static ClientConnectionManager enableTLSConnectionManager() throws KeyManagementException, NoSuchAlgorithmException {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, null, new SecureRandom());
SSLSocketFactory sf = new TLSSocketFactory(sslContext);
diff --git a/mobile/android/base/sync/net/SyncStorageRequest.java b/mobile/android/base/sync/net/SyncStorageRequest.java
index a9258382bdf7..a65f8d6e32cb 100644
--- a/mobile/android/base/sync/net/SyncStorageRequest.java
+++ b/mobile/android/base/sync/net/SyncStorageRequest.java
@@ -1,39 +1,6 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Android Sync Client.
- *
- * The Initial Developer of the Original Code is
- * the Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2011
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Richard Newman
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.sync.net;
@@ -43,6 +10,8 @@ import java.net.URISyntaxException;
import java.security.GeneralSecurityException;
import java.util.HashMap;
+import org.mozilla.gecko.sync.GlobalConstants;
+
import android.util.Log;
import ch.boye.httpclientandroidlib.HttpEntity;
@@ -163,12 +132,12 @@ public class SyncStorageRequest implements Resource {
@Override
public void addHeaders(HttpRequestBase request, DefaultHttpClient client) {
- client.getParams().setParameter(CoreProtocolPNames.USER_AGENT, USER_AGENT);
+ client.getParams().setParameter(CoreProtocolPNames.USER_AGENT, GlobalConstants.USER_AGENT);
- // Clients can use their delegate interface to specify X-Weave-If-Unmodified-Since.
+ // Clients can use their delegate interface to specify X-If-Unmodified-Since.
String ifUnmodifiedSince = this.request.delegate.ifUnmodifiedSince();
if (ifUnmodifiedSince != null) {
- request.setHeader("x-weave-if-unmodified-since", ifUnmodifiedSince);
+ request.setHeader("x-if-unmodified-since", ifUnmodifiedSince);
}
if (request.getMethod().equalsIgnoreCase("DELETE")) {
request.addHeader("x-confirm-delete", "1");
@@ -176,7 +145,6 @@ public class SyncStorageRequest implements Resource {
}
}
- public static String USER_AGENT = "Firefox AndroidSync 0.5";
protected SyncResourceDelegate resourceDelegate;
public SyncStorageRequestDelegate delegate;
protected BaseResource resource;
diff --git a/mobile/android/base/sync/repositories/MultipleRecordsForGuidException.java b/mobile/android/base/sync/repositories/MultipleRecordsForGuidException.java
index f127e7f4ec97..a54bf0593d15 100644
--- a/mobile/android/base/sync/repositories/MultipleRecordsForGuidException.java
+++ b/mobile/android/base/sync/repositories/MultipleRecordsForGuidException.java
@@ -46,5 +46,4 @@ public class MultipleRecordsForGuidException extends SyncException {
public MultipleRecordsForGuidException(Exception ex) {
super(ex);
}
-
}
diff --git a/mobile/android/base/sync/repositories/android/AndroidBrowserHistoryDataExtender.java b/mobile/android/base/sync/repositories/android/AndroidBrowserHistoryDataExtender.java
index 027518daa008..415bcd7a4238 100644
--- a/mobile/android/base/sync/repositories/android/AndroidBrowserHistoryDataExtender.java
+++ b/mobile/android/base/sync/repositories/android/AndroidBrowserHistoryDataExtender.java
@@ -46,9 +46,8 @@ import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-public class AndroidBrowserHistoryDataExtender extends SQLiteOpenHelper {
+public class AndroidBrowserHistoryDataExtender extends CachedSQLiteOpenHelper {
public static final String LOG_TAG = "SyncHistoryVisits";
@@ -77,44 +76,6 @@ public class AndroidBrowserHistoryDataExtender extends SQLiteOpenHelper {
db.execSQL(createTableSql);
}
- // Cache these so we don't have to track them across cursors. Call `close`
- // when you're done.
- private static SQLiteDatabase readableDatabase;
- private static SQLiteDatabase writableDatabase;
-
- protected SQLiteDatabase getCachedReadableDatabase() {
- if (AndroidBrowserHistoryDataExtender.readableDatabase == null) {
- if (AndroidBrowserHistoryDataExtender.writableDatabase == null) {
- AndroidBrowserHistoryDataExtender.readableDatabase = this.getReadableDatabase();
- return AndroidBrowserHistoryDataExtender.readableDatabase;
- } else {
- return AndroidBrowserHistoryDataExtender.writableDatabase;
- }
- } else {
- return AndroidBrowserHistoryDataExtender.readableDatabase;
- }
- }
-
- protected SQLiteDatabase getCachedWritableDatabase() {
- if (AndroidBrowserHistoryDataExtender.writableDatabase == null) {
- AndroidBrowserHistoryDataExtender.writableDatabase = this.getWritableDatabase();
- }
- return AndroidBrowserHistoryDataExtender.writableDatabase;
- }
-
- @Override
- public void close() {
- if (AndroidBrowserHistoryDataExtender.readableDatabase != null) {
- AndroidBrowserHistoryDataExtender.readableDatabase.close();
- AndroidBrowserHistoryDataExtender.readableDatabase = null;
- }
- if (AndroidBrowserHistoryDataExtender.writableDatabase != null) {
- AndroidBrowserHistoryDataExtender.writableDatabase.close();
- AndroidBrowserHistoryDataExtender.writableDatabase = null;
- }
- super.close();
- }
-
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// For now we'll just drop and recreate the tables.
diff --git a/mobile/android/base/sync/repositories/android/CachedSQLiteOpenHelper.java b/mobile/android/base/sync/repositories/android/CachedSQLiteOpenHelper.java
new file mode 100644
index 000000000000..69f66ee98ea8
--- /dev/null
+++ b/mobile/android/base/sync/repositories/android/CachedSQLiteOpenHelper.java
@@ -0,0 +1,55 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.sync.repositories.android;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteDatabase.CursorFactory;
+import android.database.sqlite.SQLiteOpenHelper;
+
+public abstract class CachedSQLiteOpenHelper extends SQLiteOpenHelper {
+
+ public CachedSQLiteOpenHelper(Context context, String name, CursorFactory factory,
+ int version) {
+ super(context, name, factory, version);
+ }
+
+ // Cache these so we don't have to track them across cursors. Call `close`
+ // when you're done.
+ private static SQLiteDatabase readableDatabase;
+ private static SQLiteDatabase writableDatabase;
+
+ synchronized protected SQLiteDatabase getCachedReadableDatabase() {
+ if (readableDatabase == null) {
+ if (writableDatabase == null) {
+ readableDatabase = this.getReadableDatabase();
+ return readableDatabase;
+ } else {
+ return writableDatabase;
+ }
+ } else {
+ return readableDatabase;
+ }
+ }
+
+ synchronized protected SQLiteDatabase getCachedWritableDatabase() {
+ if (writableDatabase == null) {
+ writableDatabase = this.getWritableDatabase();
+ }
+ return writableDatabase;
+ }
+
+ synchronized public void close() {
+ if (readableDatabase != null) {
+ readableDatabase.close();
+ readableDatabase = null;
+ }
+ if (writableDatabase != null) {
+ writableDatabase.close();
+ writableDatabase = null;
+ }
+ super.close();
+ }
+}
diff --git a/mobile/android/base/sync/repositories/domain/BookmarkRecord.java b/mobile/android/base/sync/repositories/domain/BookmarkRecord.java
index 6c50446cad52..bc0e0b01fcc2 100644
--- a/mobile/android/base/sync/repositories/domain/BookmarkRecord.java
+++ b/mobile/android/base/sync/repositories/domain/BookmarkRecord.java
@@ -39,7 +39,6 @@
package org.mozilla.gecko.sync.repositories.domain;
import org.json.simple.JSONArray;
-import org.mozilla.gecko.sync.CryptoRecord;
import org.mozilla.gecko.sync.ExtendedJSONObject;
import org.mozilla.gecko.sync.Logger;
import org.mozilla.gecko.sync.NonArrayJSONException;
@@ -143,33 +142,19 @@ public class BookmarkRecord extends Record {
}
@Override
- public void initFromPayload(CryptoRecord payload) {
- ExtendedJSONObject p = payload.payload;
-
- // All.
- this.guid = payload.guid;
- checkGUIDs(p);
-
- final Object del = p.get("deleted");
- if (del instanceof Boolean) {
- this.deleted = (Boolean) del;
- }
-
- this.collection = payload.collection;
- this.lastModified = payload.lastModified;
-
- this.type = (String) p.get("type");
- this.title = (String) p.get("title");
- this.description = (String) p.get("description");
- this.parentID = (String) p.get("parentid");
- this.parentName = (String) p.get("parentName");
+ protected void initFromPayload(ExtendedJSONObject payload) {
+ this.type = (String) payload.get("type");
+ this.title = (String) payload.get("title");
+ this.description = (String) payload.get("description");
+ this.parentID = (String) payload.get("parentid");
+ this.parentName = (String) payload.get("parentName");
// Bookmark.
if (isBookmark()) {
- this.bookmarkURI = (String) p.get("bmkUri");
- this.keyword = (String) p.get("keyword");
+ this.bookmarkURI = (String) payload.get("bmkUri");
+ this.keyword = (String) payload.get("keyword");
try {
- this.tags = p.getArray("tags");
+ this.tags = payload.getArray("tags");
} catch (NonArrayJSONException e) {
Log.e(LOG_TAG, "Got non-array tags in bookmark record " + this.guid, e);
this.tags = new JSONArray();
@@ -179,7 +164,7 @@ public class BookmarkRecord extends Record {
// Folder.
if (isFolder()) {
try {
- this.children = p.getArray("children");
+ this.children = payload.getArray("children");
} catch (NonArrayJSONException e) {
Log.e(LOG_TAG, "Got non-array children in bookmark record " + this.guid, e);
// Let's see if we can recover later by using the parentid pointers.
@@ -200,6 +185,23 @@ public class BookmarkRecord extends Record {
*/
}
+ @Override
+ protected void populatePayload(ExtendedJSONObject payload) {
+ putPayload(payload, "type", this.type);
+ putPayload(payload, "title", this.title);
+ putPayload(payload, "description", this.description);
+ putPayload(payload, "parentid", this.parentID);
+ putPayload(payload, "parentName", this.parentName);
+
+ if (isBookmark()) {
+ payload.put("bmkUri", bookmarkURI);
+ payload.put("keyword", keyword);
+ payload.put("tags", this.tags);
+ } else if (isFolder()) {
+ payload.put("children", this.children);
+ }
+ }
+
public boolean isBookmark() {
return AndroidBrowserBookmarksDataAccessor.TYPE_BOOKMARK.equalsIgnoreCase(this.type);
}
@@ -208,32 +210,6 @@ public class BookmarkRecord extends Record {
return AndroidBrowserBookmarksDataAccessor.TYPE_FOLDER.equalsIgnoreCase(this.type);
}
- @Override
- public CryptoRecord getPayload() {
- CryptoRecord rec = new CryptoRecord(this);
- rec.payload = new ExtendedJSONObject();
- rec.payload.put("id", this.guid);
-
- if (this.deleted) {
- rec.payload.put("deleted", true);
- } else {
- putPayload(rec, "type", this.type);
- putPayload(rec, "title", this.title);
- putPayload(rec, "description", this.description);
- putPayload(rec, "parentid", this.parentID);
- putPayload(rec, "parentName", this.parentName);
-
- if (isBookmark()) {
- rec.payload.put("bmkUri", bookmarkURI);
- rec.payload.put("keyword", keyword);
- rec.payload.put("tags", this.tags);
- } else if (isFolder()) {
- rec.payload.put("children", this.children);
- }
- }
- return rec;
- }
-
private void trace(String s) {
Logger.trace(LOG_TAG, s);
}
diff --git a/mobile/android/base/sync/repositories/domain/BookmarkRecordFactory.java b/mobile/android/base/sync/repositories/domain/BookmarkRecordFactory.java
index 8362a87aee67..593fcce8011a 100644
--- a/mobile/android/base/sync/repositories/domain/BookmarkRecordFactory.java
+++ b/mobile/android/base/sync/repositories/domain/BookmarkRecordFactory.java
@@ -51,7 +51,7 @@ public class BookmarkRecordFactory extends RecordFactory {
@Override
public Record createRecord(Record record) {
BookmarkRecord r = new BookmarkRecord();
- r.initFromPayload((CryptoRecord) record);
+ r.initFromEnvelope((CryptoRecord) record);
return r;
}
diff --git a/mobile/android/base/sync/repositories/domain/HistoryRecord.java b/mobile/android/base/sync/repositories/domain/HistoryRecord.java
index 6531b8090add..37b7f344c69f 100644
--- a/mobile/android/base/sync/repositories/domain/HistoryRecord.java
+++ b/mobile/android/base/sync/repositories/domain/HistoryRecord.java
@@ -41,7 +41,6 @@ import java.util.HashMap;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
-import org.mozilla.gecko.sync.CryptoRecord;
import org.mozilla.gecko.sync.ExtendedJSONObject;
import org.mozilla.gecko.sync.Logger;
import org.mozilla.gecko.sync.NonArrayJSONException;
@@ -109,46 +108,25 @@ public class HistoryRecord extends Record {
}
@Override
- public void initFromPayload(CryptoRecord payload) {
- ExtendedJSONObject p = payload.payload;
+ protected void populatePayload(ExtendedJSONObject payload) {
+ putPayload(payload, "id", this.guid);
+ putPayload(payload, "title", this.title);
+ putPayload(payload, "histUri", this.histURI); // TODO: encoding?
+ payload.put("visits", this.visits);
+ }
- this.guid = payload.guid;
- this.checkGUIDs(p);
-
- this.lastModified = payload.lastModified;
- final Object del = p.get("deleted");
- if (del instanceof Boolean) {
- this.deleted = (Boolean) del;
- }
-
- this.histURI = (String) p.get("histUri");
- this.title = (String) p.get("title");
+ @Override
+ protected void initFromPayload(ExtendedJSONObject payload) {
+ this.histURI = (String) payload.get("histUri");
+ this.title = (String) payload.get("title");
try {
- this.visits = p.getArray("visits");
+ this.visits = payload.getArray("visits");
} catch (NonArrayJSONException e) {
Logger.error(LOG_TAG, "Got non-array visits in history record " + this.guid, e);
this.visits = new JSONArray();
}
}
- @Override
- public CryptoRecord getPayload() {
- CryptoRecord rec = new CryptoRecord(this);
- rec.payload = new ExtendedJSONObject();
- Logger.debug(LOG_TAG, "Getting payload for history record " + this.guid + " (" + this.guid.length() + ").");
-
- if (this.deleted) {
- rec.payload.put("deleted", true);
- } else {
- putPayload(rec, "id", this.guid);
- putPayload(rec, "title", this.title);
- putPayload(rec, "histUri", this.histURI); // TODO: encoding?
- rec.payload.put("visits", this.visits);
- }
- return rec;
- }
-
-
/**
* We consider two history records to be congruent if they represent the
* same history record regardless of visits.
diff --git a/mobile/android/base/sync/repositories/domain/HistoryRecordFactory.java b/mobile/android/base/sync/repositories/domain/HistoryRecordFactory.java
index 9f7c259280c9..40b4d90c1b74 100644
--- a/mobile/android/base/sync/repositories/domain/HistoryRecordFactory.java
+++ b/mobile/android/base/sync/repositories/domain/HistoryRecordFactory.java
@@ -51,7 +51,7 @@ public class HistoryRecordFactory extends RecordFactory {
@Override
public Record createRecord(Record record) {
HistoryRecord r = new HistoryRecord();
- r.initFromPayload((CryptoRecord) record);
+ r.initFromEnvelope((CryptoRecord) record);
return r;
}
diff --git a/mobile/android/base/sync/repositories/domain/PasswordRecord.java b/mobile/android/base/sync/repositories/domain/PasswordRecord.java
index aa978f572df0..3452f6fc45cc 100644
--- a/mobile/android/base/sync/repositories/domain/PasswordRecord.java
+++ b/mobile/android/base/sync/repositories/domain/PasswordRecord.java
@@ -37,7 +37,7 @@
package org.mozilla.gecko.sync.repositories.domain;
-import org.mozilla.gecko.sync.CryptoRecord;
+import org.mozilla.gecko.sync.ExtendedJSONObject;
import org.mozilla.gecko.sync.Utils;
import org.mozilla.gecko.sync.repositories.android.RepoUtils;
@@ -98,15 +98,13 @@ public class PasswordRecord extends Record {
}
@Override
- public void initFromPayload(CryptoRecord payload) {
- // TODO Auto-generated method stub
-
+ public void initFromPayload(ExtendedJSONObject payload) {
+ // TODO: implement.
}
+
@Override
- public CryptoRecord getPayload() {
- // TODO Auto-generated method stub
- // TODO: don't forget to set "id" to our GUID.
- return null;
+ public void populatePayload(ExtendedJSONObject payload) {
+ // TODO: implement.
}
@Override
diff --git a/mobile/android/base/sync/repositories/domain/Record.java b/mobile/android/base/sync/repositories/domain/Record.java
index 26d221e78904..29ab7904234b 100644
--- a/mobile/android/base/sync/repositories/domain/Record.java
+++ b/mobile/android/base/sync/repositories/domain/Record.java
@@ -224,8 +224,39 @@ public abstract class Record {
return ((Record) o).lastModified == this.lastModified;
}
- public abstract void initFromPayload(CryptoRecord payload);
- public abstract CryptoRecord getPayload();
+ protected abstract void populatePayload(ExtendedJSONObject payload);
+ protected abstract void initFromPayload(ExtendedJSONObject payload);
+
+ public void initFromEnvelope(CryptoRecord envelope) {
+ ExtendedJSONObject p = envelope.payload;
+ this.guid = envelope.guid;
+ checkGUIDs(p);
+
+ this.collection = envelope.collection;
+ this.lastModified = envelope.lastModified;
+
+ final Object del = p.get("deleted");
+ if (del instanceof Boolean) {
+ this.deleted = (Boolean) del;
+ } else {
+ this.initFromPayload(p);
+ }
+
+ }
+
+ public CryptoRecord getEnvelope() {
+ CryptoRecord rec = new CryptoRecord(this);
+ ExtendedJSONObject payload = new ExtendedJSONObject();
+ payload.put("id", this.guid);
+
+ if (this.deleted) {
+ payload.put("deleted", true);
+ } else {
+ populatePayload(payload);
+ }
+ rec.payload = payload;
+ return rec;
+ }
public String toJSONString() {
throw new RuntimeException("Cannot JSONify non-CryptoRecord Records.");
@@ -254,6 +285,13 @@ public abstract class Record {
rec.payload.put(key, value);
}
+ protected void putPayload(ExtendedJSONObject payload, String key, String value) {
+ if (value == null) {
+ return;
+ }
+ payload.put(key, value);
+ }
+
protected void checkGUIDs(ExtendedJSONObject payload) {
String payloadGUID = (String) payload.get("id");
if (this.guid == null ||
diff --git a/mobile/android/base/sync/repositories/domain/TabsRecord.java b/mobile/android/base/sync/repositories/domain/TabsRecord.java
new file mode 100644
index 000000000000..4b9b7c47410a
--- /dev/null
+++ b/mobile/android/base/sync/repositories/domain/TabsRecord.java
@@ -0,0 +1,134 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.sync.repositories.domain;
+
+import java.util.ArrayList;
+
+import org.json.simple.JSONObject;
+import org.json.simple.JSONArray;
+import org.mozilla.gecko.sync.ExtendedJSONObject;
+import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.sync.NonArrayJSONException;
+import org.mozilla.gecko.sync.Utils;
+import org.mozilla.gecko.sync.repositories.domain.Record;
+
+/**
+ * Represents a client's collection of tabs.
+ *
+ * @author rnewman
+ *
+ */
+public class TabsRecord extends Record {
+
+ // Immutable.
+ public static class Tab {
+ public final String title;
+ public final String icon;
+ public final JSONArray history;
+ public final long lastUsed;
+
+ public Tab(String title, String icon, JSONArray history, long lastUsed) {
+ this.title = title;
+ this.icon = icon;
+ this.history = history;
+ this.lastUsed = lastUsed;
+ }
+
+ public static Tab fromJSONObject(JSONObject o) throws NonArrayJSONException {
+ ExtendedJSONObject obj = new ExtendedJSONObject(o);
+ String title = obj.getString("title");
+ String icon = obj.getString("icon");
+ JSONArray history = obj.getArray("urlHistory");
+ long lastUsed = obj.getLong("lastUsed");
+ return new Tab(title, icon, history, lastUsed);
+ }
+
+ @SuppressWarnings("unchecked")
+ public JSONObject toJSONObject() {
+ JSONObject o = new JSONObject();
+ o.put("title", title);
+ o.put("icon", icon);
+ o.put("urlHistory", history);
+ o.put("lastUsed", lastUsed);
+ return o;
+ }
+ }
+
+ private static final String LOG_TAG = "TabsRecord";
+
+ public static final String COLLECTION_NAME = "tabs";
+
+ public TabsRecord(String guid, String collection, long lastModified, boolean deleted) {
+ super(guid, collection, lastModified, deleted);
+ }
+ public TabsRecord(String guid, String collection, long lastModified) {
+ super(guid, collection, lastModified, false);
+ }
+ public TabsRecord(String guid, String collection) {
+ super(guid, collection, 0, false);
+ }
+ public TabsRecord(String guid) {
+ super(guid, COLLECTION_NAME, 0, false);
+ }
+ public TabsRecord() {
+ super(Utils.generateGuid(), COLLECTION_NAME, 0, false);
+ }
+
+ public String clientName;
+ public ArrayList tabs;
+
+ @Override
+ public void initFromPayload(ExtendedJSONObject payload) {
+ clientName = (String) payload.get("clientName");
+ try {
+ tabs = tabsFrom(payload.getArray("tabs"));
+ } catch (NonArrayJSONException e) {
+ // Oh well.
+ tabs = new ArrayList();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ protected static JSONArray tabsToJSON(ArrayList tabs) {
+ JSONArray out = new JSONArray();
+ for (Tab tab : tabs) {
+ out.add(tab.toJSONObject());
+ }
+ return out;
+ }
+
+ protected static ArrayList tabsFrom(JSONArray in) {
+ ArrayList tabs = new ArrayList(in.size());
+ for (Object o : in) {
+ if (o instanceof JSONObject) {
+ try {
+ tabs.add(Tab.fromJSONObject((JSONObject) o));
+ } catch (NonArrayJSONException e) {
+ Logger.warn(LOG_TAG, "urlHistory is not an array for this tab.", e);
+ }
+ }
+ }
+ return tabs;
+ }
+
+ @Override
+ public void populatePayload(ExtendedJSONObject payload) {
+ putPayload(payload, "id", this.guid);
+ putPayload(payload, "clientName", this.clientName);
+ payload.put("tabs", tabsToJSON(this.tabs));
+ }
+
+ @Override
+ public Record copyWithIDs(String guid, long androidID) {
+ TabsRecord out = new TabsRecord(guid, this.collection, this.lastModified, this.deleted);
+ out.androidID = androidID;
+ out.sortIndex = this.sortIndex;
+
+ out.clientName = this.clientName;
+ out.tabs = new ArrayList(this.tabs);
+
+ return out;
+ }
+}
diff --git a/mobile/android/base/sync/setup/SyncAuthenticatorService.java b/mobile/android/base/sync/setup/SyncAuthenticatorService.java
index 6a47e279a631..6728af8297fb 100644
--- a/mobile/android/base/sync/setup/SyncAuthenticatorService.java
+++ b/mobile/android/base/sync/setup/SyncAuthenticatorService.java
@@ -154,7 +154,7 @@ public class SyncAuthenticatorService extends Service {
try {
String username = KeyBundle.usernameFromAccount(account.name);
Logger.pii(LOG_TAG, "Account " + account.name + " hashes to " + username);
- Logger.info(LOG_TAG, "Setting username. Null?" + (username == null));
+ Logger.info(LOG_TAG, "Setting username. Null? " + (username == null));
result.putString(Constants.OPTION_USERNAME, username);
} catch (NoSuchAlgorithmException e) {
// Do nothing. Calling code must check for missing value.
diff --git a/mobile/android/base/sync/synchronizer/SerialRecordConsumer.java b/mobile/android/base/sync/synchronizer/SerialRecordConsumer.java
index 18b7fbcd7128..f2b634d13bbb 100644
--- a/mobile/android/base/sync/synchronizer/SerialRecordConsumer.java
+++ b/mobile/android/base/sync/synchronizer/SerialRecordConsumer.java
@@ -49,7 +49,7 @@ import android.util.Log;
class SerialRecordConsumer extends RecordConsumer {
private static final String LOG_TAG = "SerialRecordConsumer";
protected boolean stopEventually = false;
- private long counter = 0;
+ private volatile long counter = 0;
public SerialRecordConsumer(RecordsConsumerDelegate delegate) {
this.delegate = delegate;
@@ -130,7 +130,8 @@ class SerialRecordConsumer extends RecordConsumer {
}
private void consumerIsDone() {
- info("Consumer is done. Processed " + counter + ((counter == 1) ? " record." : " records."));
+ long counterNow = this.counter;
+ info("Consumer is done. Processed " + counterNow + ((counterNow == 1) ? " record." : " records."));
delegate.consumerIsDone(stopImmediately);
}
diff --git a/mobile/android/config/mozconfigs/android/l10n-nightly b/mobile/android/config/mozconfigs/android/l10n-nightly
new file mode 100644
index 000000000000..cfcceb1a9d04
--- /dev/null
+++ b/mobile/android/config/mozconfigs/android/l10n-nightly
@@ -0,0 +1,29 @@
+# L10n
+ac_add_options --with-l10n-base=../../l10n-central
+
+# Global options
+mk_add_options MOZ_MAKE_FLAGS="-j4"
+ac_add_options --disable-tests
+
+# Mozilla-Central nightlies only since this has a cost in performance
+ac_add_options --enable-js-diagnostics
+
+# Build Fennec
+ac_add_options --enable-application=mobile/android
+
+# Android
+ac_add_options --target=arm-linux-androideabi
+ac_add_options --with-endian=little
+ac_add_options --with-android-ndk="/tools/android-ndk-r5c"
+ac_add_options --with-android-sdk="/tools/android-sdk-r15/platforms/android-14"
+ac_add_options --with-android-tools="/tools/android-sdk-r15/tools"
+ac_add_options --with-android-toolchain=/tools/android-ndk-r5c/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86
+ac_add_options --with-android-platform=/tools/android-ndk-r5c/platforms/android-5/arch-arm
+ac_add_options --with-system-zlib
+ac_add_options --enable-updater
+ac_add_options --enable-update-channel=nightly
+
+export JAVA_HOME=/tools/jdk6
+export MOZILLA_OFFICIAL=1
+
+ac_add_options --with-branding=mobile/android/branding/nightly
diff --git a/mobile/android/config/mozconfigs/android/nightly b/mobile/android/config/mozconfigs/android/nightly
index e7e128c38b5d..0c66db2b2a06 100644
--- a/mobile/android/config/mozconfigs/android/nightly
+++ b/mobile/android/config/mozconfigs/android/nightly
@@ -1,5 +1,5 @@
# Global options
-mk_add_options MOZ_MAKE_FLAGS=-j4
+mk_add_options MOZ_MAKE_FLAGS="-j4"
# Build Fennec
ac_add_options --enable-application=mobile/android
diff --git a/mobile/android/config/mozconfigs/linux-desktop/l10n-mozconfig b/mobile/android/config/mozconfigs/linux-desktop/l10n-mozconfig
deleted file mode 100644
index ae620448594e..000000000000
--- a/mobile/android/config/mozconfigs/linux-desktop/l10n-mozconfig
+++ /dev/null
@@ -1,5 +0,0 @@
-mk_add_options MOZ_PKG_FORMAT=BZ2
-
-ac_add_options --with-l10n-base=../../l10n-central
-ac_add_options --enable-application=mobile/android
-ac_add_options --disable-compile-environment
diff --git a/mobile/android/config/mozconfigs/linux-desktop/nightly b/mobile/android/config/mozconfigs/linux-desktop/nightly
deleted file mode 100644
index ef68f21ae1c2..000000000000
--- a/mobile/android/config/mozconfigs/linux-desktop/nightly
+++ /dev/null
@@ -1,12 +0,0 @@
-mk_add_options MOZ_PKG_FORMAT=BZ2
-ac_add_options --enable-application=mobile/android
-
-# Nightlies only since this has a cost in performance
-ac_add_options --enable-js-diagnostics
-
-CC=/tools/gcc-4.5/bin/gcc
-CXX=/tools/gcc-4.5/bin/g++
-# Avoid dependency on libstdc++ 4.5
-ac_add_options --enable-stdcxx-compat
-
-export MOZILLA_OFFICIAL=1
diff --git a/mobile/android/config/mozconfigs/macosx-desktop/l10n-mozconfig b/mobile/android/config/mozconfigs/macosx-desktop/l10n-mozconfig
deleted file mode 100644
index b8eb22b07fc1..000000000000
--- a/mobile/android/config/mozconfigs/macosx-desktop/l10n-mozconfig
+++ /dev/null
@@ -1,3 +0,0 @@
-ac_add_options --with-l10n-base=../../l10n-central
-ac_add_options --enable-application=mobile/android
-ac_add_options --disable-compile-environment
diff --git a/mobile/android/config/mozconfigs/macosx-desktop/nightly b/mobile/android/config/mozconfigs/macosx-desktop/nightly
deleted file mode 100644
index e93d3c86f24d..000000000000
--- a/mobile/android/config/mozconfigs/macosx-desktop/nightly
+++ /dev/null
@@ -1,15 +0,0 @@
-# Options for client.mk.
-mk_add_options AUTOCONF=autoconf213
-
-# Global options
-. $topsrcdir/build/macosx/mozconfig.leopard
-ac_cv_visibility_pragma=no
-
-ac_add_options --disable-install-strip
-
-ac_add_options --enable-application=mobile/android
-
-# Nightlies only since this has a cost in performance
-ac_add_options --enable-js-diagnostics
-
-export MOZILLA_OFFICIAL=1
diff --git a/mobile/android/config/mozconfigs/win32-desktop/l10n-mozconfig b/mobile/android/config/mozconfigs/win32-desktop/l10n-mozconfig
deleted file mode 100644
index 905c633852a2..000000000000
--- a/mobile/android/config/mozconfigs/win32-desktop/l10n-mozconfig
+++ /dev/null
@@ -1,6 +0,0 @@
-mk_add_options MOZ_PKG_FORMAT=ZIP
-
-ac_add_options --with-l10n-base=../../l10n-central
-ac_add_options --enable-application=mobile/android
-ac_add_options --disable-compile-environment
-ac_add_options --disable-angle
diff --git a/mobile/android/config/mozconfigs/win32-desktop/nightly b/mobile/android/config/mozconfigs/win32-desktop/nightly
deleted file mode 100644
index f37480434cca..000000000000
--- a/mobile/android/config/mozconfigs/win32-desktop/nightly
+++ /dev/null
@@ -1,13 +0,0 @@
-# Options for client.mk.
-mk_add_options MOZ_PKG_FORMAT=ZIP
-
-export WIN32_REDIST_DIR=/d/msvs8/VC/redist/x86/Microsoft.VC80.CRT
-
-ac_add_options --enable-jemalloc
-ac_add_options --enable-application=mobile/android
-ac_add_options --disable-webm
-
-# Nightlies only since this has a cost in performance
-ac_add_options --enable-js-diagnostics
-
-export MOZILLA_OFFICIAL=1
diff --git a/mobile/android/sync/java-sources.mn b/mobile/android/sync/java-sources.mn
index 78007ea8bc0b..ad12b40ea5e0 100644
--- a/mobile/android/sync/java-sources.mn
+++ b/mobile/android/sync/java-sources.mn
@@ -1 +1 @@
-sync/AlreadySyncingException.java sync/CollectionKeys.java sync/CredentialsSource.java sync/crypto/CryptoException.java sync/crypto/CryptoInfo.java sync/crypto/HKDF.java sync/crypto/HMACVerificationException.java sync/crypto/KeyBundle.java sync/crypto/MissingCryptoInputException.java sync/crypto/NoKeyBundleException.java sync/CryptoRecord.java sync/DelayedWorkTracker.java sync/delegates/FreshStartDelegate.java sync/delegates/GlobalSessionCallback.java sync/delegates/InfoCollectionsDelegate.java sync/delegates/KeyUploadDelegate.java sync/delegates/MetaGlobalDelegate.java sync/delegates/WipeServerDelegate.java sync/ExtendedJSONObject.java sync/GlobalSession.java sync/HTTPFailureException.java sync/InfoCollections.java sync/jpake/BigIntegerHelper.java sync/jpake/Gx3OrGx4IsZeroOrOneException.java sync/jpake/IncorrectZkpException.java sync/jpake/JPakeClient.java sync/jpake/JPakeCrypto.java sync/jpake/JPakeJson.java sync/jpake/JPakeNoActivePairingException.java sync/jpake/JPakeNumGenerator.java sync/jpake/JPakeNumGeneratorRandom.java sync/jpake/JPakeParty.java sync/jpake/JPakeRequest.java sync/jpake/JPakeRequestDelegate.java sync/jpake/JPakeResponse.java sync/jpake/stage/CompleteStage.java sync/jpake/stage/ComputeFinalStage.java sync/jpake/stage/ComputeKeyVerificationStage.java sync/jpake/stage/ComputeStepOneStage.java sync/jpake/stage/ComputeStepTwoStage.java sync/jpake/stage/DecryptDataStage.java sync/jpake/stage/GetChannelStage.java sync/jpake/stage/GetRequestStage.java sync/jpake/stage/JPakeStage.java sync/jpake/stage/PutRequestStage.java sync/jpake/stage/VerifyPairingStage.java sync/jpake/Zkp.java sync/Logger.java sync/MetaGlobal.java sync/MetaGlobalException.java sync/MetaGlobalMissingEnginesException.java sync/MetaGlobalNotSetException.java sync/middleware/Crypto5MiddlewareRepository.java sync/middleware/Crypto5MiddlewareRepositorySession.java sync/middleware/MiddlewareRepository.java sync/net/BaseResource.java sync/net/CompletedEntity.java sync/net/HandleProgressException.java sync/net/Resource.java sync/net/ResourceDelegate.java sync/net/SyncResourceDelegate.java sync/net/SyncResponse.java sync/net/SyncStorageCollectionRequest.java sync/net/SyncStorageCollectionRequestDelegate.java sync/net/SyncStorageRecordRequest.java sync/net/SyncStorageRequest.java sync/net/SyncStorageRequestDelegate.java sync/net/SyncStorageRequestIncrementalDelegate.java sync/net/SyncStorageResponse.java sync/net/TLSSocketFactory.java sync/net/WBOCollectionRequestDelegate.java sync/NoCollectionKeysSetException.java sync/NonArrayJSONException.java sync/NonObjectJSONException.java sync/PrefsSource.java sync/repositories/android/AndroidBrowserBookmarksDataAccessor.java sync/repositories/android/AndroidBrowserBookmarksRepository.java sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java sync/repositories/android/AndroidBrowserHistoryDataAccessor.java sync/repositories/android/AndroidBrowserHistoryDataExtender.java sync/repositories/android/AndroidBrowserHistoryRepository.java sync/repositories/android/AndroidBrowserHistoryRepositorySession.java sync/repositories/android/AndroidBrowserPasswordsDataAccessor.java sync/repositories/android/AndroidBrowserPasswordsRepository.java sync/repositories/android/AndroidBrowserPasswordsRepositorySession.java sync/repositories/android/AndroidBrowserRepository.java sync/repositories/android/AndroidBrowserRepositoryDataAccessor.java sync/repositories/android/AndroidBrowserRepositorySession.java sync/repositories/android/BrowserContractHelpers.java sync/repositories/android/PasswordColumns.java sync/repositories/android/RepoUtils.java sync/repositories/BookmarkNeedsReparentingException.java sync/repositories/BookmarksRepository.java sync/repositories/ConstrainedServer11Repository.java sync/repositories/delegates/DeferrableRepositorySessionCreationDelegate.java sync/repositories/delegates/DeferredRepositorySessionBeginDelegate.java sync/repositories/delegates/DeferredRepositorySessionFetchRecordsDelegate.java sync/repositories/delegates/DeferredRepositorySessionFinishDelegate.java sync/repositories/delegates/DeferredRepositorySessionStoreDelegate.java sync/repositories/delegates/RepositorySessionBeginDelegate.java sync/repositories/delegates/RepositorySessionCleanDelegate.java sync/repositories/delegates/RepositorySessionCreationDelegate.java sync/repositories/delegates/RepositorySessionFetchRecordsDelegate.java sync/repositories/delegates/RepositorySessionFinishDelegate.java sync/repositories/delegates/RepositorySessionGuidsSinceDelegate.java sync/repositories/delegates/RepositorySessionStoreDelegate.java sync/repositories/delegates/RepositorySessionWipeDelegate.java sync/repositories/domain/BookmarkRecord.java sync/repositories/domain/BookmarkRecordFactory.java sync/repositories/domain/HistoryRecord.java sync/repositories/domain/HistoryRecordFactory.java sync/repositories/domain/PasswordRecord.java sync/repositories/domain/Record.java sync/repositories/HashSetStoreTracker.java sync/repositories/HistoryRepository.java sync/repositories/IdentityRecordFactory.java sync/repositories/InactiveSessionException.java sync/repositories/InvalidBookmarkTypeException.java sync/repositories/InvalidRequestException.java sync/repositories/InvalidSessionTransitionException.java sync/repositories/MultipleRecordsForGuidException.java sync/repositories/NoGuidForIdException.java sync/repositories/NoStoreDelegateException.java sync/repositories/NullCursorException.java sync/repositories/ParentNotFoundException.java sync/repositories/ProfileDatabaseException.java sync/repositories/RecordFactory.java sync/repositories/RecordFilter.java sync/repositories/Repository.java sync/repositories/RepositorySession.java sync/repositories/RepositorySessionBundle.java sync/repositories/Server11Repository.java sync/repositories/Server11RepositorySession.java sync/repositories/StoreTracker.java sync/repositories/StoreTrackingRepositorySession.java sync/setup/activities/AccountActivity.java sync/setup/activities/SetupFailureActivity.java sync/setup/activities/SetupSuccessActivity.java sync/setup/activities/SetupSyncActivity.java sync/setup/Constants.java sync/setup/SyncAuthenticatorService.java sync/stage/AndroidBrowserBookmarksServerSyncStage.java sync/stage/AndroidBrowserHistoryServerSyncStage.java sync/stage/CheckPreconditionsStage.java sync/stage/CompletedStage.java sync/stage/EnsureClusterURLStage.java sync/stage/EnsureKeysStage.java sync/stage/FetchInfoCollectionsStage.java sync/stage/FetchMetaGlobalStage.java sync/stage/GlobalSyncStage.java sync/stage/NoSuchStageException.java sync/stage/NoSyncIDException.java sync/stage/ServerSyncStage.java sync/StubActivity.java sync/syncadapter/SyncAdapter.java sync/syncadapter/SyncService.java sync/SyncConfiguration.java sync/SyncConfigurationException.java sync/SyncException.java sync/synchronizer/ConcurrentRecordConsumer.java sync/synchronizer/RecordConsumer.java sync/synchronizer/RecordsChannel.java sync/synchronizer/RecordsChannelDelegate.java sync/synchronizer/RecordsConsumerDelegate.java sync/synchronizer/SerialRecordConsumer.java sync/synchronizer/SessionNotBegunException.java sync/synchronizer/Synchronizer.java sync/synchronizer/SynchronizerDelegate.java sync/synchronizer/SynchronizerSession.java sync/synchronizer/SynchronizerSessionDelegate.java sync/synchronizer/UnbundleError.java sync/synchronizer/UnexpectedSessionException.java sync/SynchronizerConfiguration.java sync/SynchronizerConfigurations.java sync/ThreadPool.java sync/UnexpectedJSONException.java sync/UnknownSynchronizerConfigurationVersionException.java sync/Utils.java
+sync/AlreadySyncingException.java sync/CollectionKeys.java sync/CredentialsSource.java sync/crypto/CryptoException.java sync/crypto/CryptoInfo.java sync/crypto/HKDF.java sync/crypto/HMACVerificationException.java sync/crypto/KeyBundle.java sync/crypto/MissingCryptoInputException.java sync/crypto/NoKeyBundleException.java sync/CryptoRecord.java sync/DelayedWorkTracker.java sync/delegates/FreshStartDelegate.java sync/delegates/GlobalSessionCallback.java sync/delegates/InfoCollectionsDelegate.java sync/delegates/KeyUploadDelegate.java sync/delegates/MetaGlobalDelegate.java sync/delegates/WipeServerDelegate.java sync/ExtendedJSONObject.java sync/GlobalSession.java sync/HTTPFailureException.java sync/InfoCollections.java sync/jpake/BigIntegerHelper.java sync/jpake/Gx3OrGx4IsZeroOrOneException.java sync/jpake/IncorrectZkpException.java sync/jpake/JPakeClient.java sync/jpake/JPakeCrypto.java sync/jpake/JPakeJson.java sync/jpake/JPakeNoActivePairingException.java sync/jpake/JPakeNumGenerator.java sync/jpake/JPakeNumGeneratorRandom.java sync/jpake/JPakeParty.java sync/jpake/JPakeRequest.java sync/jpake/JPakeRequestDelegate.java sync/jpake/JPakeResponse.java sync/jpake/stage/CompleteStage.java sync/jpake/stage/ComputeFinalStage.java sync/jpake/stage/ComputeKeyVerificationStage.java sync/jpake/stage/ComputeStepOneStage.java sync/jpake/stage/ComputeStepTwoStage.java sync/jpake/stage/DecryptDataStage.java sync/jpake/stage/GetChannelStage.java sync/jpake/stage/GetRequestStage.java sync/jpake/stage/JPakeStage.java sync/jpake/stage/PutRequestStage.java sync/jpake/stage/VerifyPairingStage.java sync/jpake/Zkp.java sync/Logger.java sync/MetaGlobal.java sync/MetaGlobalException.java sync/MetaGlobalMissingEnginesException.java sync/MetaGlobalNotSetException.java sync/middleware/Crypto5MiddlewareRepository.java sync/middleware/Crypto5MiddlewareRepositorySession.java sync/middleware/MiddlewareRepository.java sync/net/BaseResource.java sync/net/CompletedEntity.java sync/net/HandleProgressException.java sync/net/Resource.java sync/net/ResourceDelegate.java sync/net/SyncResourceDelegate.java sync/net/SyncResponse.java sync/net/SyncStorageCollectionRequest.java sync/net/SyncStorageCollectionRequestDelegate.java sync/net/SyncStorageRecordRequest.java sync/net/SyncStorageRequest.java sync/net/SyncStorageRequestDelegate.java sync/net/SyncStorageRequestIncrementalDelegate.java sync/net/SyncStorageResponse.java sync/net/TLSSocketFactory.java sync/net/WBOCollectionRequestDelegate.java sync/NoCollectionKeysSetException.java sync/NonArrayJSONException.java sync/NonObjectJSONException.java sync/PrefsSource.java sync/repositories/android/AndroidBrowserBookmarksDataAccessor.java sync/repositories/android/AndroidBrowserBookmarksRepository.java sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java sync/repositories/android/AndroidBrowserHistoryDataAccessor.java sync/repositories/android/AndroidBrowserHistoryDataExtender.java sync/repositories/android/AndroidBrowserHistoryRepository.java sync/repositories/android/AndroidBrowserHistoryRepositorySession.java sync/repositories/android/AndroidBrowserPasswordsDataAccessor.java sync/repositories/android/AndroidBrowserPasswordsRepository.java sync/repositories/android/AndroidBrowserPasswordsRepositorySession.java sync/repositories/android/AndroidBrowserRepository.java sync/repositories/android/AndroidBrowserRepositoryDataAccessor.java sync/repositories/android/AndroidBrowserRepositorySession.java sync/repositories/android/BrowserContractHelpers.java sync/repositories/android/CachedSQLiteOpenHelper.java sync/repositories/android/PasswordColumns.java sync/repositories/android/RepoUtils.java sync/repositories/BookmarkNeedsReparentingException.java sync/repositories/BookmarksRepository.java sync/repositories/ConstrainedServer11Repository.java sync/repositories/delegates/DeferrableRepositorySessionCreationDelegate.java sync/repositories/delegates/DeferredRepositorySessionBeginDelegate.java sync/repositories/delegates/DeferredRepositorySessionFetchRecordsDelegate.java sync/repositories/delegates/DeferredRepositorySessionFinishDelegate.java sync/repositories/delegates/DeferredRepositorySessionStoreDelegate.java sync/repositories/delegates/RepositorySessionBeginDelegate.java sync/repositories/delegates/RepositorySessionCleanDelegate.java sync/repositories/delegates/RepositorySessionCreationDelegate.java sync/repositories/delegates/RepositorySessionFetchRecordsDelegate.java sync/repositories/delegates/RepositorySessionFinishDelegate.java sync/repositories/delegates/RepositorySessionGuidsSinceDelegate.java sync/repositories/delegates/RepositorySessionStoreDelegate.java sync/repositories/delegates/RepositorySessionWipeDelegate.java sync/repositories/domain/BookmarkRecord.java sync/repositories/domain/BookmarkRecordFactory.java sync/repositories/domain/HistoryRecord.java sync/repositories/domain/HistoryRecordFactory.java sync/repositories/domain/PasswordRecord.java sync/repositories/domain/Record.java sync/repositories/domain/TabsRecord.java sync/repositories/HashSetStoreTracker.java sync/repositories/HistoryRepository.java sync/repositories/IdentityRecordFactory.java sync/repositories/InactiveSessionException.java sync/repositories/InvalidBookmarkTypeException.java sync/repositories/InvalidRequestException.java sync/repositories/InvalidSessionTransitionException.java sync/repositories/MultipleRecordsForGuidException.java sync/repositories/NoGuidForIdException.java sync/repositories/NoStoreDelegateException.java sync/repositories/NullCursorException.java sync/repositories/ParentNotFoundException.java sync/repositories/ProfileDatabaseException.java sync/repositories/RecordFactory.java sync/repositories/RecordFilter.java sync/repositories/Repository.java sync/repositories/RepositorySession.java sync/repositories/RepositorySessionBundle.java sync/repositories/Server11Repository.java sync/repositories/Server11RepositorySession.java sync/repositories/StoreTracker.java sync/repositories/StoreTrackingRepositorySession.java sync/setup/activities/AccountActivity.java sync/setup/activities/SetupFailureActivity.java sync/setup/activities/SetupSuccessActivity.java sync/setup/activities/SetupSyncActivity.java sync/setup/Constants.java sync/setup/SyncAuthenticatorService.java sync/stage/AndroidBrowserBookmarksServerSyncStage.java sync/stage/AndroidBrowserHistoryServerSyncStage.java sync/stage/CheckPreconditionsStage.java sync/stage/CompletedStage.java sync/stage/EnsureClusterURLStage.java sync/stage/EnsureKeysStage.java sync/stage/FetchInfoCollectionsStage.java sync/stage/FetchMetaGlobalStage.java sync/stage/GlobalSyncStage.java sync/stage/NoSuchStageException.java sync/stage/NoSyncIDException.java sync/stage/ServerSyncStage.java sync/StubActivity.java sync/syncadapter/SyncAdapter.java sync/syncadapter/SyncService.java sync/SyncConfiguration.java sync/SyncConfigurationException.java sync/SyncException.java sync/synchronizer/ConcurrentRecordConsumer.java sync/synchronizer/RecordConsumer.java sync/synchronizer/RecordsChannel.java sync/synchronizer/RecordsChannelDelegate.java sync/synchronizer/RecordsConsumerDelegate.java sync/synchronizer/SerialRecordConsumer.java sync/synchronizer/SessionNotBegunException.java sync/synchronizer/Synchronizer.java sync/synchronizer/SynchronizerDelegate.java sync/synchronizer/SynchronizerSession.java sync/synchronizer/SynchronizerSessionDelegate.java sync/synchronizer/UnbundleError.java sync/synchronizer/UnexpectedSessionException.java sync/SynchronizerConfiguration.java sync/SynchronizerConfigurations.java sync/ThreadPool.java sync/UnexpectedJSONException.java sync/UnknownSynchronizerConfigurationVersionException.java sync/Utils.java
diff --git a/mobile/xul/config/mozconfigs/android/nightly b/mobile/xul/config/mozconfigs/android/nightly
index 01fbe1470e69..4964d339869c 100644
--- a/mobile/xul/config/mozconfigs/android/nightly
+++ b/mobile/xul/config/mozconfigs/android/nightly
@@ -1,5 +1,5 @@
# Global options
-mk_add_options MOZ_MAKE_FLAGS=-j4
+mk_add_options MOZ_MAKE_FLAGS="-j4"
# Nightlies only since this has a cost in performance
ac_add_options --enable-js-diagnostics
diff --git a/mobile/xul/config/mozconfigs/linux-desktop/l10n-mozconfig b/mobile/xul/config/mozconfigs/linux-desktop/l10n-mozconfig
deleted file mode 100644
index 05c34224143b..000000000000
--- a/mobile/xul/config/mozconfigs/linux-desktop/l10n-mozconfig
+++ /dev/null
@@ -1,5 +0,0 @@
-mk_add_options MOZ_PKG_FORMAT=BZ2
-
-ac_add_options --with-l10n-base=../../l10n-central
-ac_add_options --enable-application=mobile
-ac_add_options --disable-compile-environment
diff --git a/mobile/xul/config/mozconfigs/linux-desktop/nightly b/mobile/xul/config/mozconfigs/linux-desktop/nightly
deleted file mode 100644
index 1454a383a28e..000000000000
--- a/mobile/xul/config/mozconfigs/linux-desktop/nightly
+++ /dev/null
@@ -1,12 +0,0 @@
-mk_add_options MOZ_PKG_FORMAT=BZ2
-ac_add_options --enable-application=mobile
-
-# Nightlies only since this has a cost in performance
-ac_add_options --enable-js-diagnostics
-
-. $topsrcdir/build/unix/mozconfig.linux
-
-# Avoid dependency on libstdc++ 4.5
-ac_add_options --enable-stdcxx-compat
-
-export MOZILLA_OFFICIAL=1
diff --git a/mobile/xul/config/mozconfigs/macosx-desktop/l10n-mozconfig b/mobile/xul/config/mozconfigs/macosx-desktop/l10n-mozconfig
deleted file mode 100644
index 30a2e0a47b7b..000000000000
--- a/mobile/xul/config/mozconfigs/macosx-desktop/l10n-mozconfig
+++ /dev/null
@@ -1,3 +0,0 @@
-ac_add_options --with-l10n-base=../../l10n-central
-ac_add_options --enable-application=mobile
-ac_add_options --disable-compile-environment
diff --git a/mobile/xul/config/mozconfigs/macosx-desktop/nightly b/mobile/xul/config/mozconfigs/macosx-desktop/nightly
deleted file mode 100644
index 03f616db948a..000000000000
--- a/mobile/xul/config/mozconfigs/macosx-desktop/nightly
+++ /dev/null
@@ -1,15 +0,0 @@
-# Options for client.mk.
-mk_add_options AUTOCONF=autoconf213
-
-# Global options
-. $topsrcdir/build/macosx/mozconfig.leopard
-ac_cv_visibility_pragma=no
-
-ac_add_options --disable-install-strip
-
-ac_add_options --enable-application=mobile
-
-# Nightlies only since this has a cost in performance
-ac_add_options --enable-js-diagnostics
-
-export MOZILLA_OFFICIAL=1
diff --git a/mobile/xul/config/mozconfigs/win32-desktop/l10n-mozconfig b/mobile/xul/config/mozconfigs/win32-desktop/l10n-mozconfig
deleted file mode 100644
index 9f2f7770ee4e..000000000000
--- a/mobile/xul/config/mozconfigs/win32-desktop/l10n-mozconfig
+++ /dev/null
@@ -1,6 +0,0 @@
-mk_add_options MOZ_PKG_FORMAT=ZIP
-
-ac_add_options --with-l10n-base=../../l10n-central
-ac_add_options --enable-application=mobile
-ac_add_options --disable-compile-environment
-ac_add_options --disable-angle
diff --git a/mobile/xul/config/mozconfigs/win32-desktop/nightly b/mobile/xul/config/mozconfigs/win32-desktop/nightly
deleted file mode 100644
index 0671833c1df0..000000000000
--- a/mobile/xul/config/mozconfigs/win32-desktop/nightly
+++ /dev/null
@@ -1,13 +0,0 @@
-# Options for client.mk.
-mk_add_options MOZ_PKG_FORMAT=ZIP
-
-export WIN32_REDIST_DIR=/d/msvs8/VC/redist/x86/Microsoft.VC80.CRT
-
-ac_add_options --enable-jemalloc
-ac_add_options --enable-application=mobile
-ac_add_options --disable-webm
-
-# Nightlies only since this has a cost in performance
-ac_add_options --enable-js-diagnostics
-
-export MOZILLA_OFFICIAL=1
diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js
index 970a63a99469..32ab27737b2b 100644
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -407,7 +407,6 @@ pref("extensions.spellcheck.inline.max-misspellings", 500);
pref("editor.use_custom_colors", false);
pref("editor.singleLine.pasteNewlines", 2);
-pref("editor.quotesPreformatted", false);
pref("editor.use_css", true);
pref("editor.css.default_length_unit", "px");
pref("editor.resizing.preserve_ratio", true);
diff --git a/src/test/java/org/mozilla/android/sync/repositories/domain/TabsRecord.java b/src/test/java/org/mozilla/android/sync/repositories/domain/TabsRecord.java
new file mode 100644
index 000000000000..91a1b79d5855
--- /dev/null
+++ b/src/test/java/org/mozilla/android/sync/repositories/domain/TabsRecord.java
@@ -0,0 +1,134 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.android.sync.repositories.domain;
+
+import java.util.ArrayList;
+
+import org.json.simple.JSONObject;
+import org.json.simple.JSONArray;
+import org.mozilla.gecko.sync.ExtendedJSONObject;
+import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.sync.NonArrayJSONException;
+import org.mozilla.gecko.sync.Utils;
+import org.mozilla.gecko.sync.repositories.domain.Record;
+
+/**
+ * Represents a client's collection of tabs.
+ *
+ * @author rnewman
+ *
+ */
+public class TabsRecord extends Record {
+
+ // Immutable.
+ public static class Tab {
+ public final String title;
+ public final String icon;
+ public final JSONArray history;
+ public final long lastUsed;
+
+ public Tab(String title, String icon, JSONArray history, long lastUsed) {
+ this.title = title;
+ this.icon = icon;
+ this.history = history;
+ this.lastUsed = lastUsed;
+ }
+
+ public static Tab fromJSONObject(JSONObject o) throws NonArrayJSONException {
+ ExtendedJSONObject obj = new ExtendedJSONObject((JSONObject) o);
+ String title = obj.getString("title");
+ String icon = obj.getString("icon");
+ JSONArray history = obj.getArray("urlHistory");
+ long lastUsed = obj.getLong("lastUsed");
+ return new Tab(title, icon, history, lastUsed);
+ }
+
+ @SuppressWarnings("unchecked")
+ public JSONObject toJSONObject() {
+ JSONObject o = new JSONObject();
+ o.put("title", title);
+ o.put("icon", icon);
+ o.put("urlHistory", history);
+ o.put("lastUsed", lastUsed);
+ return o;
+ }
+ }
+
+ private static final String LOG_TAG = "TabsRecord";
+
+ public static final String COLLECTION_NAME = "tabs";
+
+ public TabsRecord(String guid, String collection, long lastModified, boolean deleted) {
+ super(guid, collection, lastModified, deleted);
+ }
+ public TabsRecord(String guid, String collection, long lastModified) {
+ super(guid, collection, lastModified, false);
+ }
+ public TabsRecord(String guid, String collection) {
+ super(guid, collection, 0, false);
+ }
+ public TabsRecord(String guid) {
+ super(guid, COLLECTION_NAME, 0, false);
+ }
+ public TabsRecord() {
+ super(Utils.generateGuid(), COLLECTION_NAME, 0, false);
+ }
+
+ public String clientName;
+ public ArrayList tabs;
+
+ @Override
+ public void initFromPayload(ExtendedJSONObject payload) {
+ clientName = (String) payload.get("clientName");
+ try {
+ tabs = tabsFrom(payload.getArray("tabs"));
+ } catch (NonArrayJSONException e) {
+ // Oh well.
+ tabs = new ArrayList();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ protected static JSONArray tabsToJSON(ArrayList tabs) {
+ JSONArray out = new JSONArray();
+ for (Tab tab : tabs) {
+ out.add(tab.toJSONObject());
+ }
+ return out;
+ }
+
+ protected static ArrayList tabsFrom(JSONArray in) {
+ ArrayList tabs = new ArrayList(in.size());
+ for (Object o : in) {
+ if (o instanceof JSONObject) {
+ try {
+ tabs.add(Tab.fromJSONObject((JSONObject) o));
+ } catch (NonArrayJSONException e) {
+ Logger.warn(LOG_TAG, "urlHistory is not an array for this tab.", e);
+ }
+ }
+ }
+ return tabs;
+ }
+
+ @Override
+ public void populatePayload(ExtendedJSONObject payload) {
+ putPayload(payload, "id", this.guid);
+ putPayload(payload, "clientName", this.clientName);
+ payload.put("tabs", tabsToJSON(this.tabs));
+ }
+
+ @Override
+ public Record copyWithIDs(String guid, long androidID) {
+ TabsRecord out = new TabsRecord(guid, this.collection, this.lastModified, this.deleted);
+ out.androidID = androidID;
+ out.sortIndex = this.sortIndex;
+
+ out.clientName = this.clientName;
+ out.tabs = new ArrayList(this.tabs);
+
+ return out;
+ }
+}
diff --git a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul
index 7302a4857d97..27774929ce35 100644
--- a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul
+++ b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul
@@ -44,8 +44,7 @@
let areJsCompartmentsPresent = false;
let isSandboxLocationShown = false;
- let areLayoutShellsPresent = false;
- let areDomInnerWindowsPresent = false;
+ let areInnerWindowsPresent = false;
let isPlacesPresent = false;
let isImagesPresent = false;
let isXptiWorkingSetPresent = false;
@@ -73,10 +72,8 @@
// Check the presence of some other notable reporters.
} else if (aPath.search(/^explicit\/js\/compartment\(/) >= 0) {
areJsCompartmentsPresent = true;
- } else if (aPath.search(/^explicit\/layout\/shell\(/) >= 0) {
- areLayoutShellsPresent = true;
- } else if (aPath.search(/^explicit\/dom\+style\/window-objects\/.*inner-window\(/) >= 0) {
- areDomInnerWindowsPresent = true;
+ } else if (aPath.search(/^explicit\/window-objects\/.*inner-window\(/) >= 0) {
+ areInnerWindowsPresent = true;
} else if (aPath.search(/^explicit\/storage\/sqlite\/places.sqlite/) >= 0) {
isPlacesPresent = true;
} else if (aPath.search(/^explicit\/images/) >= 0) {
@@ -134,8 +131,7 @@
ok(areJsCompartmentsPresent, "js compartments are present");
ok(isSandboxLocationShown, "sandbox locations are present");
- ok(areLayoutShellsPresent, "layout shells are present");
- ok(areDomInnerWindowsPresent, "dom inner-windows are present");
+ ok(areInnerWindowsPresent, "inner-windows are present");
ok(isPlacesPresent, "places is present");
ok(isImagesPresent, "images is present");
ok(isXptiWorkingSetPresent, "xpti-working-set is present");
diff --git a/toolkit/components/places/nsLivemarkService.js b/toolkit/components/places/nsLivemarkService.js
index 1f527906b280..f6f258f03788 100644
--- a/toolkit/components/places/nsLivemarkService.js
+++ b/toolkit/components/places/nsLivemarkService.js
@@ -124,9 +124,9 @@ LivemarkService.prototype = {
stmt.finalize();
},
- _onCacheReady: function LS__onCacheReady(aCallback)
+ _onCacheReady: function LS__onCacheReady(aCallback, aWaitForAsyncWrites)
{
- if (this._pendingStmt) {
+ if (this._pendingStmt || aWaitForAsyncWrites) {
// The cache is still being populated, so enqueue the job to the Storage
// async thread. Ideally this should just dispatch a runnable to it,
// that would call back on the main thread, but bug 608142 made that
@@ -421,7 +421,7 @@ LivemarkService.prototype = {
try {
aLivemarkCallback.onCompletion(result, livemark);
} catch(ex2) {}
- });
+ }, true);
}
}
},
@@ -1003,7 +1003,9 @@ Livemark.prototype = {
*/
terminate: function LM_terminate()
{
- delete this._resultObserversList;
+ // Clear the list before aborting, since abort() would try to set the
+ // status and notify about it, but that's not really useful at this point.
+ this._resultObserversList = [];
this.abort();
},
diff --git a/toolkit/components/telemetry/Telemetry.cpp b/toolkit/components/telemetry/Telemetry.cpp
index f4b132963bbe..46f97c143876 100644
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -318,26 +318,41 @@ ReflectHistogramAndSamples(JSContext *cx, JSObject *obj, Histogram *h,
return REFLECT_CORRUPT;
}
- JSObject *counts_array;
- JSObject *rarray;
- const size_t count = h->bucket_count();
if (!(JS_DefineProperty(cx, obj, "min", INT_TO_JSVAL(h->declared_min()), NULL, NULL, JSPROP_ENUMERATE)
&& JS_DefineProperty(cx, obj, "max", INT_TO_JSVAL(h->declared_max()), NULL, NULL, JSPROP_ENUMERATE)
&& JS_DefineProperty(cx, obj, "histogram_type", INT_TO_JSVAL(h->histogram_type()), NULL, NULL, JSPROP_ENUMERATE)
- && JS_DefineProperty(cx, obj, "sum", DOUBLE_TO_JSVAL(ss.sum()), NULL, NULL, JSPROP_ENUMERATE)
- && (rarray = JS_NewArrayObject(cx, count, NULL))
- && JS_DefineProperty(cx, obj, "ranges", OBJECT_TO_JSVAL(rarray), NULL, NULL, JSPROP_ENUMERATE)
- && FillRanges(cx, rarray, h)
- && (counts_array = JS_NewArrayObject(cx, count, NULL))
- && JS_DefineProperty(cx, obj, "counts", OBJECT_TO_JSVAL(counts_array), NULL, NULL, JSPROP_ENUMERATE)
- )) {
+ && JS_DefineProperty(cx, obj, "sum", DOUBLE_TO_JSVAL(ss.sum()), NULL, NULL, JSPROP_ENUMERATE))) {
+ return REFLECT_FAILURE;
+ }
+
+ const size_t count = h->bucket_count();
+ JSObject *rarray = JS_NewArrayObject(cx, count, nsnull);
+ if (!rarray) {
+ return REFLECT_FAILURE;
+ }
+ JS::AutoObjectRooter aroot(cx, rarray);
+ if (!(FillRanges(cx, rarray, h)
+ && JS_DefineProperty(cx, obj, "ranges", OBJECT_TO_JSVAL(rarray),
+ NULL, NULL, JSPROP_ENUMERATE))) {
+ return REFLECT_FAILURE;
+ }
+
+ JSObject *counts_array = JS_NewArrayObject(cx, count, NULL);
+ if (!counts_array) {
+ return REFLECT_FAILURE;
+ }
+ JS::AutoObjectRooter croot(cx, counts_array);
+ if (!JS_DefineProperty(cx, obj, "counts", OBJECT_TO_JSVAL(counts_array),
+ NULL, NULL, JSPROP_ENUMERATE)) {
return REFLECT_FAILURE;
}
for (size_t i = 0; i < count; i++) {
- if (!JS_DefineElement(cx, counts_array, i, INT_TO_JSVAL(ss.counts(i)), NULL, NULL, JSPROP_ENUMERATE)) {
+ if (!JS_DefineElement(cx, counts_array, i, INT_TO_JSVAL(ss.counts(i)),
+ NULL, NULL, JSPROP_ENUMERATE)) {
return REFLECT_FAILURE;
}
}
+
return REFLECT_OK;
}
@@ -393,9 +408,10 @@ JSHistogram_Snapshot(JSContext *cx, unsigned argc, jsval *vp)
}
Histogram *h = static_cast(JS_GetPrivate(obj));
- JSObject *snapshot = JS_NewObject(cx, NULL, NULL, NULL);
+ JSObject *snapshot = JS_NewObject(cx, nsnull, nsnull, nsnull);
if (!snapshot)
return JS_FALSE;
+ JS::AutoObjectRooter sroot(cx, snapshot);
switch (ReflectHistogramSnapshot(cx, snapshot, h)) {
case REFLECT_FAILURE:
@@ -426,10 +442,14 @@ WrapAndReturnHistogram(Histogram *h, JSContext *cx, jsval *ret)
JSObject *obj = JS_NewObject(cx, &JSHistogram_class, NULL, NULL);
if (!obj)
return NS_ERROR_FAILURE;
+ JS::AutoObjectRooter root(cx, obj);
+ if (!(JS_DefineFunction (cx, obj, "add", JSHistogram_Add, 1, 0)
+ && JS_DefineFunction (cx, obj, "snapshot", JSHistogram_Snapshot, 1, 0))) {
+ return NS_ERROR_FAILURE;
+ }
*ret = OBJECT_TO_JSVAL(obj);
JS_SetPrivate(obj, h);
- return (JS_DefineFunction (cx, obj, "add", JSHistogram_Add, 1, 0)
- && JS_DefineFunction (cx, obj, "snapshot", JSHistogram_Snapshot, 1, 0)) ? NS_OK : NS_ERROR_FAILURE;
+ return NS_OK;
}
TelemetryImpl::TelemetryImpl():
@@ -479,8 +499,11 @@ TelemetryImpl::StatementReflector(SlowSQLEntryType *entry, JSContext *cx,
jsval totalTime = UINT_TO_JSVAL(entry->mData.totalTime);
JSObject *arrayObj = JS_NewArrayObject(cx, 2, nsnull);
- return (arrayObj
- && JS_SetElement(cx, arrayObj, 0, &hitCount)
+ if (!arrayObj) {
+ return false;
+ }
+ JS::AutoObjectRooter root(cx, arrayObj);
+ return (JS_SetElement(cx, arrayObj, 0, &hitCount)
&& JS_SetElement(cx, arrayObj, 1, &totalTime)
&& JS_DefineProperty(cx, obj,
sql.BeginReading(),
@@ -494,18 +517,19 @@ TelemetryImpl::AddSQLInfo(JSContext *cx, JSObject *rootObj, bool mainThread)
JSObject *statsObj = JS_NewObject(cx, NULL, NULL, NULL);
if (!statsObj)
return false;
-
- JSBool ok = JS_DefineProperty(cx, rootObj,
- mainThread ? "mainThread" : "otherThreads",
- OBJECT_TO_JSVAL(statsObj),
- NULL, NULL, JSPROP_ENUMERATE);
- if (!ok)
- return false;
+ JS::AutoObjectRooter root(cx, statsObj);
AutoHashtable &sqlMap = (mainThread
? mSlowSQLOnMainThread
: mSlowSQLOnOtherThread);
- return sqlMap.ReflectHashtable(StatementReflector, cx, statsObj);
+ if (!sqlMap.ReflectHashtable(StatementReflector, cx, statsObj)) {
+ return false;
+ }
+
+ return JS_DefineProperty(cx, rootObj,
+ mainThread ? "mainThread" : "otherThreads",
+ OBJECT_TO_JSVAL(statsObj),
+ NULL, NULL, JSPROP_ENUMERATE);
}
nsresult
@@ -778,6 +802,7 @@ TelemetryImpl::GetHistogramSnapshots(JSContext *cx, jsval *ret)
if (!hobj) {
return NS_ERROR_FAILURE;
}
+ JS::AutoObjectRooter root(cx, hobj);
switch (ReflectHistogramSnapshot(cx, hobj, h)) {
case REFLECT_CORRUPT:
// We can still hit this case even if ShouldReflectHistograms
@@ -806,7 +831,11 @@ TelemetryImpl::AddonHistogramReflector(AddonHistogramEntryType *entry,
}
JSObject *snapshot = JS_NewObject(cx, NULL, NULL, NULL);
- js::AutoObjectRooter r(cx, snapshot);
+ if (!snapshot) {
+ // Just consider this to be skippable.
+ return true;
+ }
+ JS::AutoObjectRooter r(cx, snapshot);
switch (ReflectHistogramSnapshot(cx, snapshot, entry->mData.h)) {
case REFLECT_FAILURE:
case REFLECT_CORRUPT:
@@ -833,7 +862,7 @@ TelemetryImpl::AddonReflector(AddonEntryType *entry,
if (!subobj) {
return false;
}
- js::AutoObjectRooter r(cx, subobj);
+ JS::AutoObjectRooter r(cx, subobj);
AddonHistogramMapType *map = entry->mData;
if (!(map->ReflectHashtable(AddonHistogramReflector, cx, subobj)
@@ -854,7 +883,7 @@ TelemetryImpl::GetAddonHistogramSnapshots(JSContext *cx, jsval *ret)
if (!obj) {
return NS_ERROR_FAILURE;
}
- js::AutoObjectRooter r(cx, obj);
+ JS::AutoObjectRooter r(cx, obj);
if (!mAddonMap.ReflectHashtable(AddonReflector, cx, obj)) {
return NS_ERROR_FAILURE;
@@ -889,6 +918,7 @@ TelemetryImpl::GetRegisteredHistograms(JSContext *cx, jsval *ret)
JSObject *info = JS_NewObject(cx, NULL, NULL, NULL);
if (!info)
return NS_ERROR_FAILURE;
+ JS::AutoObjectRooter root(cx, info);
for (size_t i = 0; i < count; ++i) {
JSString *comment = JS_InternString(cx, gHistograms[i].comment);
@@ -983,7 +1013,7 @@ TelemetrySessionData::SampleReflector(EntryType *entry, JSContext *cx,
if (!snapshot) {
return false;
}
- js::AutoObjectRooter root(cx, snapshot);
+ JS::AutoObjectRooter root(cx, snapshot);
return (ReflectHistogramAndSamples(cx, snapshot, h, entry->mData)
&& JS_DefineProperty(cx, snapshots,
h->histogram_name().c_str(),
@@ -998,7 +1028,7 @@ TelemetrySessionData::GetSnapshots(JSContext *cx, jsval *ret)
if (!snapshots) {
return NS_ERROR_FAILURE;
}
- js::AutoObjectRooter root(cx, snapshots);
+ JS::AutoObjectRooter root(cx, snapshots);
if (!mSampleSetMap.ReflectHashtable(SampleReflector, cx, snapshots)) {
return NS_ERROR_FAILURE;
diff --git a/toolkit/components/viewsource/test/browser/Makefile.in b/toolkit/components/viewsource/test/browser/Makefile.in
index fce201d69b7d..a5368fc69251 100644
--- a/toolkit/components/viewsource/test/browser/Makefile.in
+++ b/toolkit/components/viewsource/test/browser/Makefile.in
@@ -48,6 +48,7 @@ _BROWSER_CHROME_FILES = \
browser_bug699356.js \
browser_bug713810.js \
browser_contextmenu.js \
+ browser_gotoline.js \
browser_viewsourceprefs.js \
browser_viewsourceprefs_nonhtml.js \
head.js \
diff --git a/toolkit/components/viewsource/test/browser/browser_gotoline.js b/toolkit/components/viewsource/test/browser/browser_gotoline.js
new file mode 100644
index 000000000000..1afa57162db3
--- /dev/null
+++ b/toolkit/components/viewsource/test/browser/browser_gotoline.js
@@ -0,0 +1,27 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+let content = "line 1\nline 2\nline 3";
+let runningPlainText = false;
+
+function test() {
+ waitForExplicitFinish();
+
+ testViewSourceWindow("data:text/html," + encodeURIComponent(content), checkViewSource, function() {
+ testViewSourceWindow("data:text/plain," + encodeURIComponent(content), checkViewSource, finish);
+ });
+}
+
+function checkViewSource(aWindow) {
+ is(aWindow.gBrowser.contentDocument.body.textContent, content, "Correct content loaded");
+
+ let selection = aWindow.gBrowser.contentWindow.getSelection();
+ let statusPanel = aWindow.document.getElementById("statusbar-line-col");
+ is(statusPanel.getAttribute("label"), "", "Correct status bar text");
+ for (let i = 1; i <= 3; i++) {
+ aWindow.goToLine(i);
+ is(selection.toString(), "line " + i, "Correct text selected");
+ is(statusPanel.getAttribute("label"), "Line " + i + ", Col 1", "Correct status bar text");
+ }
+}
diff --git a/toolkit/components/viewsource/test/browser/head.js b/toolkit/components/viewsource/test/browser/head.js
index e0ed3b3c6cad..2b6c494e616d 100644
--- a/toolkit/components/viewsource/test/browser/head.js
+++ b/toolkit/components/viewsource/test/browser/head.js
@@ -18,12 +18,19 @@ function closeViewSourceWindow(aWindow, aCallback) {
Services.wm.addListener({
onCloseWindow: function() {
Services.wm.removeListener(this);
- aCallback();
+ executeSoon(aCallback);
}
});
aWindow.close();
}
+function testViewSourceWindow(aURI, aTestCallback, aCloseCallback) {
+ openViewSourceWindow(aURI, function(aWindow) {
+ aTestCallback(aWindow);
+ closeViewSourceWindow(aWindow, aCloseCallback);
+ });
+}
+
function openViewPartialSourceWindow(aReference, aCallback) {
let viewSourceWindow = openDialog("chrome://global/content/viewPartialSource.xul",
null, null, null, null, aReference, "selection");
diff --git a/widget/windows/nsDataObj.h b/widget/windows/nsDataObj.h
index 6ca4cd1061f0..f5a7e6780cc9 100644
--- a/widget/windows/nsDataObj.h
+++ b/widget/windows/nsDataObj.h
@@ -38,11 +38,6 @@
#ifndef _NSDATAOBJ_H_
#define _NSDATAOBJ_H_
-#ifdef __MINGW32__
-#include
-#include
-#include
-#endif
#include
#include
@@ -111,35 +106,6 @@ IAsyncOperation : public IUnknown
# define CFSTR_FILEDESCRIPTORW L"FileGroupDescriptorW"
#endif
-#ifdef __MINGW32__
-# include
-# if __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION == 0)
-# ifndef FILEGROUPDESCRIPTORA
-# define FILEGROUPDESCRIPTORA FILEGROUPDESCRIPTOR
-# endif
-# ifndef LPFILEGROUPDESCRIPTORA
-# define LPFILEGROUPDESCRIPTORA LPFILEGROUPDESCRIPTOR
-# endif
-typedef struct _FILEDESCRIPTORW {
- DWORD dwFlags;
- CLSID clsid;
- SIZEL sizel;
- POINTL pointl;
- DWORD dwFileAttributes;
- FILETIME ftCreationTime;
- FILETIME ftLastAccessTime;
- FILETIME ftLastWriteTime;
- DWORD nFileSizeHigh;
- DWORD nFileSizeLow;
- WCHAR cFileName[MAX_PATH];
-} FILEDESCRIPTORW,*LPFILEDESCRIPTORW;
-typedef struct _FILEGROUPDESCRIPTORW {
- UINT cItems;
- FILEDESCRIPTORW fgd[1];
-} FILEGROUPDESCRIPTORW,*LPFILEGROUPDESCRIPTORW;
-# endif /*__W32API_MAJOR_VERSION*/
-#endif /*__MINGW32__*/
-
class CEnumFormatEtc;
class nsITransferable;
diff --git a/widget/windows/nsDataObjCollection.h b/widget/windows/nsDataObjCollection.h
index c85e3afac3fa..957ee7539496 100644
--- a/widget/windows/nsDataObjCollection.h
+++ b/widget/windows/nsDataObjCollection.h
@@ -39,11 +39,6 @@
#ifndef _NSDATAOBJCOLLECTION_H_
#define _NSDATAOBJCOLLECTION_H_
-#ifdef __MINGW32__
-#include
-#include
-#include
-#endif
#include
#include "nsString.h"
diff --git a/widget/windows/nsNativeDragTarget.h b/widget/windows/nsNativeDragTarget.h
index c57169e75de4..16e5e1ed35ec 100644
--- a/widget/windows/nsNativeDragTarget.h
+++ b/widget/windows/nsNativeDragTarget.h
@@ -43,9 +43,7 @@
#include
#ifndef IDropTargetHelper
-#ifndef __MINGW32__ // MingW does not provide shobjidl.h.
#include // Vista drag image interfaces
-#endif // MingW
#endif
class nsIDragService;
diff --git a/xpcom/ds/nsCRT.cpp b/xpcom/ds/nsCRT.cpp
index dd6a44c08ca2..9de1ea93d946 100644
--- a/xpcom/ds/nsCRT.cpp
+++ b/xpcom/ds/nsCRT.cpp
@@ -54,11 +54,10 @@
#include "nsCRT.h"
#include "nsIServiceManager.h"
#include "nsCharTraits.h"
-#include "prbit.h"
#include "nsUTF8Utils.h"
+#include "mozilla/HashFunctions.h"
-#define ADD_TO_HASHVAL(hashval, c) \
- hashval = PR_ROTATE_LEFT32(hashval, 4) ^ (c);
+using namespace mozilla;
//----------------------------------------------------------------------
@@ -221,11 +220,13 @@ PRUint32 nsCRT::HashCode(const char* str, PRUint32* resultingStrLen)
if (!str) return h;
unsigned char c;
- while ( (c = *s++) )
- ADD_TO_HASHVAL(h, c);
+ while ( (c = *s++) ) {
+ h = AddToHash(h, c);
+ }
if ( resultingStrLen )
*resultingStrLen = (s-str)-1;
+
return h;
}
@@ -238,7 +239,7 @@ PRUint32 nsCRT::HashCode(const char* start, PRUint32 length)
unsigned char c;
while ( s < end ) {
c = *s++;
- ADD_TO_HASHVAL(h, c);
+ h = AddToHash(h, c);
}
return h;
@@ -253,10 +254,11 @@ PRUint32 nsCRT::HashCode(const PRUnichar* str, PRUint32* resultingStrLen)
PRUnichar c;
while ( (c = *s++) )
- ADD_TO_HASHVAL(h, c);
+ h = AddToHash(h, c);
if ( resultingStrLen )
*resultingStrLen = (s-str)-1;
+
return h;
}
@@ -269,7 +271,7 @@ PRUint32 nsCRT::HashCode(const PRUnichar* start, PRUint32 length)
PRUnichar c;
while ( s < end ) {
c = *s++;
- ADD_TO_HASHVAL(h, c);
+ h = AddToHash(h, c);
}
return h;
@@ -292,11 +294,10 @@ PRUint32 nsCRT::HashCodeAsUTF16(const char* start, PRUint32 length,
}
if (ucs4 < PLANE1_BASE) {
- ADD_TO_HASHVAL(h, ucs4);
+ h = AddToHash(h, ucs4);
}
else {
- ADD_TO_HASHVAL(h, H_SURROGATE(ucs4));
- ADD_TO_HASHVAL(h, L_SURROGATE(ucs4));
+ h = AddToHash(h, H_SURROGATE(ucs4), L_SURROGATE(ucs4));
}
}
diff --git a/xpcom/glue/nsTHashtable.cpp b/xpcom/glue/nsTHashtable.cpp
index bf6e6dc63945..f762d8e70970 100644
--- a/xpcom/glue/nsTHashtable.cpp
+++ b/xpcom/glue/nsTHashtable.cpp
@@ -38,6 +38,9 @@
#include "nsTHashtable.h"
#include "nsHashKeys.h"
#include "prbit.h"
+#include "mozilla/HashFunctions.h"
+
+using namespace mozilla;
PRUint32
HashString( const nsAString& aStr )
@@ -55,7 +58,7 @@ HashString( const nsAString& aStr )
#endif
while (begin != end) {
- code = PR_ROTATE_LEFT32(code, 4) ^ PRUint32(*begin);
+ code = AddToHash(code, *begin);
++begin;
}
@@ -78,7 +81,7 @@ HashString( const nsACString& aStr )
#endif
while (begin != end) {
- code = PR_ROTATE_LEFT32(code, 4) ^ PRUint32(*begin);
+ code = AddToHash(code, *begin);
++begin;
}
@@ -89,9 +92,10 @@ PRUint32
HashString(const char *str)
{
PRUint32 code = 0;
+ const char *origStr = str;
while (*str) {
- code = PR_ROTATE_LEFT32(code, 4) ^ PRUint32(*str);
+ code = AddToHash(code, *str);
++str;
}
@@ -102,9 +106,10 @@ PRUint32
HashString(const PRUnichar *str)
{
PRUint32 code = 0;
+ const PRUnichar *origStr = str;
while (*str) {
- code = PR_ROTATE_LEFT32(code, 4) ^ PRUint32(*str);
+ code = AddToHash(code, *str);
++str;
}
diff --git a/xpcom/glue/pldhash.cpp b/xpcom/glue/pldhash.cpp
index 867c29e3dd08..f10f696541b6 100644
--- a/xpcom/glue/pldhash.cpp
+++ b/xpcom/glue/pldhash.cpp
@@ -48,6 +48,7 @@
#include
#include "prbit.h"
#include "pldhash.h"
+#include "mozilla/HashFunctions.h"
#include "nsDebug.h" /* for PR_ASSERT */
#ifdef PL_DHASHMETER
@@ -108,6 +109,8 @@
#endif /* defined(DEBUG) */
+using namespace mozilla;
+
void *
PL_DHashAllocTable(PLDHashTable *table, PRUint32 nbytes)
{
@@ -128,7 +131,7 @@ PL_DHashStringKey(PLDHashTable *table, const void *key)
h = 0;
for (s = (const unsigned char *) key; *s != '\0'; s++)
- h = PR_ROTATE_LEFT32(h, 4) ^ *s;
+ h = AddToHash(h, *s);
return h;
}
diff --git a/xpcom/typelib/xpt/src/Makefile.in b/xpcom/typelib/xpt/src/Makefile.in
index 518768f649cf..2fc1c645c142 100644
--- a/xpcom/typelib/xpt/src/Makefile.in
+++ b/xpcom/typelib/xpt/src/Makefile.in
@@ -75,3 +75,8 @@ endif
ifdef _MSC_VER
OS_COMPILE_CFLAGS += -Zl
endif
+
+LOCAL_INCLUDES += \
+ -I../../../ \
+ -I$(topsrcdir)/xpcom/base \
+ $(NULL)
diff --git a/xpcom/typelib/xpt/src/xpt_xdr.c b/xpcom/typelib/xpt/src/xpt_xdr.c
index a69c9d793655..405a9c002567 100644
--- a/xpcom/typelib/xpt/src/xpt_xdr.c
+++ b/xpcom/typelib/xpt/src/xpt_xdr.c
@@ -39,6 +39,7 @@
#include "xpt_xdr.h"
#include "nspr.h"
+#include "nscore.h"
#include /* strchr */
static PRBool
@@ -143,7 +144,7 @@ XPT_HashTableDestroy(XPTHashTable *table) {
static void *
XPT_HashTableAdd(XPTHashTable *table, void *key, void *value) {
XPTHashRecord **bucketloc = table->buckets +
- (((PRUint32)key) % XPT_HASHSIZE);
+ (NS_PTR_TO_UINT32(key) % XPT_HASHSIZE);
XPTHashRecord *bucket;
while (*bucketloc != NULL)
@@ -159,7 +160,7 @@ XPT_HashTableAdd(XPTHashTable *table, void *key, void *value) {
static void *
XPT_HashTableLookup(XPTHashTable *table, void *key) {
- XPTHashRecord *bucket = table->buckets[(PRUint32)key % XPT_HASHSIZE];
+ XPTHashRecord *bucket = table->buckets[NS_PTR_TO_UINT32(key) % XPT_HASHSIZE];
while (bucket != NULL) {
if (bucket->key == key)
return bucket->value;
@@ -483,27 +484,29 @@ XPT_DoCString(XPTArena *arena, XPTCursor *cursor, char **identp)
XPT_PUBLIC_API(PRUint32)
XPT_GetOffsetForAddr(XPTCursor *cursor, void *addr)
{
- return (PRUint32)XPT_HashTableLookup(cursor->state->pool->offset_map, addr);
+ XPTHashTable *table = cursor->state->pool->offset_map;
+ return NS_PTR_TO_UINT32(XPT_HashTableLookup(table, addr));
}
XPT_PUBLIC_API(PRBool)
XPT_SetOffsetForAddr(XPTCursor *cursor, void *addr, PRUint32 offset)
{
return XPT_HashTableAdd(cursor->state->pool->offset_map,
- addr, (void *)offset) != NULL;
+ addr, NS_INT32_TO_PTR(offset)) != NULL;
}
XPT_PUBLIC_API(PRBool)
XPT_SetAddrForOffset(XPTCursor *cursor, PRUint32 offset, void *addr)
{
return XPT_HashTableAdd(cursor->state->pool->offset_map,
- (void *)offset, addr) != NULL;
+ NS_INT32_TO_PTR(offset), addr) != NULL;
}
XPT_PUBLIC_API(void *)
XPT_GetAddrForOffset(XPTCursor *cursor, PRUint32 offset)
{
- return XPT_HashTableLookup(cursor->state->pool->offset_map, (void *)offset);
+ return XPT_HashTableLookup(cursor->state->pool->offset_map,
+ NS_INT32_TO_PTR(offset));
}
/* Used by XPT_PREAMBLE_NO_ALLOC. */