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 @@ + + + + + @hidden attribute testing + + + + + + + + + + + + + + + +

+ +
+  
+ +
+ +
+ + + + 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 aNodeInfo) diff --git a/content/base/src/nsGenericElement.h b/content/base/src/nsGenericElement.h index 5fde0c9dec3c..9553c667bbcc 100644 --- a/content/base/src/nsGenericElement.h +++ b/content/base/src/nsGenericElement.h @@ -597,7 +597,7 @@ public: nsIContent* GetLastElementChild(); nsIContent* GetPreviousElementSibling(); nsIContent* GetNextElementSibling(); - nsIDOMDOMTokenList* GetClassList(nsresult *aResult); + nsDOMTokenList* GetClassList(nsresult *aResult); bool MozMatchesSelector(const nsAString& aSelector, nsresult* aResult); /** diff --git a/content/base/src/nsMappedAttributeElement.h b/content/base/src/nsMappedAttributeElement.h index fd63907ede70..2c2950bc6c72 100644 --- a/content/base/src/nsMappedAttributeElement.h +++ b/content/base/src/nsMappedAttributeElement.h @@ -46,7 +46,6 @@ #define NS_MAPPEDATTRIBUTEELEMENT_H_ #include "nsStyledElement.h" -#include "nsDOMMemoryReporter.h" class nsMappedAttributes; struct nsRuleData; diff --git a/content/base/src/nsObjectLoadingContent.cpp b/content/base/src/nsObjectLoadingContent.cpp index 77ee34e91c95..b70dd2aa17bb 100644 --- a/content/base/src/nsObjectLoadingContent.cpp +++ b/content/base/src/nsObjectLoadingContent.cpp @@ -1871,9 +1871,18 @@ nsObjectLoadingContent::GetObjectBaseURI(const nsACString & aMimeType, nsIURI** codebase.AssignLiteral("/"); } - nsContentUtils::NewURIWithDocumentCharset(aURI, codebase, - thisContent->OwnerDoc(), - baseURI); + if (!codebase.IsEmpty()) { + nsresult rv = nsContentUtils::NewURIWithDocumentCharset(aURI, codebase, + thisContent->OwnerDoc(), + baseURI); + if (NS_SUCCEEDED(rv)) + return rv; + NS_WARNING("GetObjectBaseURI: Could not resolve plugin's codebase to a URI, using baseURI instead"); + } + + // Codebase empty or build URI failed, just use baseURI + *aURI = NULL; + baseURI.swap(*aURI); return NS_OK; } diff --git a/content/base/src/nsPlainTextSerializer.cpp b/content/base/src/nsPlainTextSerializer.cpp index dfdf4b5270c8..c6799f730329 100644 --- a/content/base/src/nsPlainTextSerializer.cpp +++ b/content/base/src/nsPlainTextSerializer.cpp @@ -108,7 +108,6 @@ nsPlainTextSerializer::nsPlainTextSerializer() mCiteQuoteLevel = 0; mStructs = true; // will be read from prefs later mHeaderStrategy = 1 /*indent increasingly*/; // ditto - mQuotesPreformatted = false; // ditto mDontWrapAnyQuotes = false; // ditto mHasWrittenCiteBlockquote = false; mSpanLevel = 0; @@ -210,10 +209,6 @@ nsPlainTextSerializer::Init(PRUint32 aFlags, PRUint32 aWrapColumn, mHeaderStrategy = Preferences::GetInt(PREF_HEADER_STRATEGY, mHeaderStrategy); - // The quotesPreformatted pref is a temporary measure. See bug 69638. - mQuotesPreformatted = - Preferences::GetBool("editor.quotesPreformatted", mQuotesPreformatted); - // DontWrapAnyQuotes is set according to whether plaintext mail // is wrapping to window width -- see bug 134439. // We'll only want this if we're wrapping and formatted. @@ -1636,7 +1631,7 @@ nsPlainTextSerializer::Write(const nsAString& aStr) // that does normal formatted text. The one for preformatted text calls // Output directly while the other code path goes through AddToLine. if ((mPreFormatted && !mWrapColumn) || IsInPre() - || ((((!mQuotesPreformatted && mSpanLevel > 0) || mDontWrapAnyQuotes)) + || ((mSpanLevel > 0 || mDontWrapAnyQuotes) && mEmptyLines >= 0 && str.First() == PRUnichar('>'))) { // No intelligent wrapping. diff --git a/content/base/src/nsPlainTextSerializer.h b/content/base/src/nsPlainTextSerializer.h index e43941ecc5e0..9edf91ba7c5d 100644 --- a/content/base/src/nsPlainTextSerializer.h +++ b/content/base/src/nsPlainTextSerializer.h @@ -176,11 +176,9 @@ protected: // Quotes need to be wrapped differently from non-quoted text, // because quoted text has a few extra characters (e.g. ">> ") // which makes the line length longer. - // Mail can represent quotes in different ways: it can wrap - // quotes in a
 (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. */