Merge last PGO-green changeset from mozilla-inbound to mozilla-central
authorEd Morley <bmo@edmorley.co.uk>
Wed, 21 Dec 2011 12:11:14 +0000
changeset 83173 d6b976e83811207066453e1de9b9d6f2abae0228
parent 83141 cd921d073b226cfa86ce6cb7c91307929ebf45c0 (current diff)
parent 83172 6cff9824c2c118561c888441562b34db8fb1b748 (diff)
child 83174 81d34a32e03170a69afa002b3de671e1950e451d
child 83188 ed488640454a476dd50ae85497fa436d44d012a2
child 83731 cc4d4c230ec1ce93654306060f7b5db87cba1238
push id21738
push userbmo@edmorley.co.uk
push dateWed, 21 Dec 2011 12:12:10 +0000
treeherdermozilla-central@d6b976e83811 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone12.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge last PGO-green changeset from mozilla-inbound to mozilla-central
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -214,16 +214,17 @@
 @BINPATH@/components/necko.xpt
 @BINPATH@/components/loginmgr.xpt
 @BINPATH@/components/parentalcontrols.xpt
 @BINPATH@/components/places.xpt
 @BINPATH@/components/plugin.xpt
 @BINPATH@/components/pref.xpt
 @BINPATH@/components/prefetch.xpt
 @BINPATH@/components/profile.xpt
+@BINPATH@/components/profiler.xpt
 @BINPATH@/components/proxyObject.xpt
 @BINPATH@/components/rdf.xpt
 @BINPATH@/components/satchel.xpt
 @BINPATH@/components/saxparser.xpt
 @BINPATH@/components/sessionstore.xpt
 @BINPATH@/components/services-crypto-component.xpt
 @BINPATH@/components/shellservice.xpt
 @BINPATH@/components/shistory.xpt
--- a/configure.in
+++ b/configure.in
@@ -308,17 +308,17 @@ if test -n "$gonkdir" ; then
     LD="$gonk_toolchain"/bin/"$android_tool_prefix"-ld
     AR="$gonk_toolchain"/bin/"$android_tool_prefix"-ar
     RANLIB="$gonk_toolchain"/bin/"$android_tool_prefix"-ranlib
     STRIP="$gonk_toolchain"/bin/"$android_tool_prefix"-strip
 
     STLPORT_CPPFLAGS="-I$gonkdir/ndk/sources/cxx-stl/stlport/stlport/"
     STLPORT_LIBS="-lstlport"
 
-    CPPFLAGS="-DANDROID -I$gonkdir/bionic/libc/include/ -I$gonkdir/bionic/libc/kernel/common -I$gonkdir/bionic/libc/arch-arm/include -I$gonkdir/bionic/libc/kernel/arch-arm -I$gonkdir/bionic/libm/include -I$gonkdir/frameworks/base/opengl/include -I$gonkdir/frameworks/base/native/include -I$gonkdir/hardware/libhardware/include -I$gonkdir/system/core/include -I$gonkdir/bionic -I$gonkdir/frameworks/base/include $STLPORT_CPPFLAGS $CPPFLAGS"
+    CPPFLAGS="-DANDROID -I$gonkdir/bionic/libc/include/ -I$gonkdir/bionic/libc/kernel/common -I$gonkdir/bionic/libc/arch-arm/include -I$gonkdir/bionic/libc/kernel/arch-arm -I$gonkdir/bionic/libm/include -I$gonkdir/frameworks/base/opengl/include -I$gonkdir/frameworks/base/native/include -I$gonkdir/hardware/libhardware/include -I$gonkdir/hardware/libhardware_legacy/include -I$gonkdir/system/core/include -I$gonkdir/bionic -I$gonkdir/frameworks/base/include $STLPORT_CPPFLAGS $CPPFLAGS"
     CFLAGS="-mandroid -fno-short-enums -fno-exceptions $CFLAGS"
     CXXFLAGS="-mandroid -fno-short-enums -fno-exceptions $CXXFLAGS"
     LIBS="$LIBS $STLPORT_LIBS"
 
     dnl Add -llog by default, since we use it all over the place.
     LDFLAGS="-mandroid -L$gonkdir/out/target/product/$GONK_PRODUCT/obj/lib -Wl,-rpath-link=$gonkdir/out/target/product/$GONK_PRODUCT/obj/lib --sysroot=$gonkdir/out/target/product/$GONK_PRODUCT/obj/ -llog $LDFLAGS"
 
     dnl prevent cross compile section from using these flags as host flags
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -115,17 +115,17 @@ public:
   }
 
   nsCOMPtr<nsIScriptElement> mElement;
   bool mLoading;             // Are we still waiting for a load to complete?
   bool mIsInline;            // Is the script inline or loaded?
   nsString mScriptText;              // Holds script for loaded scripts
   PRUint32 mJSVersion;
   nsCOMPtr<nsIURI> mURI;
-  nsCOMPtr<nsIURI> mFinalURI;
+  nsCOMPtr<nsIPrincipal> mOriginPrincipal;
   PRInt32 mLineNo;
 };
 
 // The nsScriptLoadRequest is passed as the context to necko, and thus
 // it needs to be threadsafe. Necko won't do anything with this
 // context, but it will AddRef and Release it on other threads.
 NS_IMPL_THREADSAFE_ISUPPORTS0(nsScriptLoadRequest)
 
@@ -877,33 +877,34 @@ nsScriptLoader::EvaluateScript(nsScriptL
   // Make sure context is a strong reference since we access it after
   // we've executed a script, which may cause all other references to
   // the context to go away.
   nsCOMPtr<nsIScriptContext> context = globalObject->GetScriptContext(stid);
   if (!context) {
     return NS_ERROR_FAILURE;
   }
 
-  nsIURI* uri = aRequest->mFinalURI ? aRequest->mFinalURI : aRequest->mURI;
-
   bool oldProcessingScriptTag = context->GetProcessingScriptTag();
   context->SetProcessingScriptTag(true);
 
   // Update our current script.
   nsCOMPtr<nsIScriptElement> oldCurrent = mCurrentScript;
   mCurrentScript = aRequest->mElement;
 
+  // It's very important to use aRequest->mURI, not the final URI of the channel
+  // aRequest ended up getting script data from, as the script filename.
   nsCAutoString url;
-  nsContentUtils::GetWrapperSafeScriptFilename(mDocument, uri, url);
+  nsContentUtils::GetWrapperSafeScriptFilename(mDocument, aRequest->mURI, url);
 
   bool isUndefined;
   rv = context->EvaluateString(aScript, globalObject->GetGlobalJSObject(),
-                          mDocument->NodePrincipal(), url.get(),
-                          aRequest->mLineNo, aRequest->mJSVersion, nsnull,
-                          &isUndefined);
+                               mDocument->NodePrincipal(),
+                               aRequest->mOriginPrincipal,
+                               url.get(), aRequest->mLineNo,
+                               aRequest->mJSVersion, nsnull, &isUndefined);
 
   // Put the old script back in case it wants to do anything else.
   mCurrentScript = oldCurrent;
 
   JSContext *cx = nsnull; // Initialize this to keep GCC happy.
   if (stid == nsIProgrammingLanguage::JAVASCRIPT) {
     cx = context->GetNativeContext();
     ::JS_BeginRequest(cx);
@@ -1208,17 +1209,20 @@ nsScriptLoader::PrepareLoadedRequest(nsS
     bool requestSucceeded;
     rv = httpChannel->GetRequestSucceeded(&requestSucceeded);
     if (NS_SUCCEEDED(rv) && !requestSucceeded) {
       return NS_ERROR_NOT_AVAILABLE;
     }
   }
 
   nsCOMPtr<nsIChannel> channel = do_QueryInterface(req);
-  NS_GetFinalChannelURI(channel, getter_AddRefs(aRequest->mFinalURI));
+  rv = nsContentUtils::GetSecurityManager()->
+    GetChannelPrincipal(channel, getter_AddRefs(aRequest->mOriginPrincipal));
+  NS_ENSURE_SUCCESS(rv, rv);
+
   if (aStringLen) {
     // Check the charset attribute to determine script charset.
     nsAutoString hintCharset;
     if (!aRequest->IsPreload()) {
       aRequest->mElement->GetScriptCharset(hintCharset);
     } else {
       nsTArray<PreloadInfo>::index_type i =
         mPreloads.IndexOf(aRequest, 0, PreloadRequestComparator());
--- a/content/base/test/test_bug461735.html
+++ b/content/base/test/test_bug461735.html
@@ -14,30 +14,34 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script type="application/javascript">
 var errorFired = false;
 window.onerror = function(message, uri, line) {
   is(message, "Script error.", "Should have empty error message");
-  is(uri, "", "Should have empty error location URI");
+  is(uri,
+     "http://mochi.test:8888/tests/content/base/test/bug461735-redirect1.sjs",
+     "Should have pre-redirect error location URI");
   is(line, 0, "Shouldn't have a line here");
   errorFired = true;
 }
 </script>
 <script src="bug461735-redirect1.sjs"></script>
 <script>
   is(errorFired, true, "Should have error in redirected different origin script");
   errorFired = false;
 </script>
 <script type="application/javascript">
 window.onerror = function(message, uri, line) {
   is(message, "c is not defined", "Should have correct error message");
-  is(uri, "http://mochi.test:8888/tests/content/base/test/bug461735-post-redirect.js", "Unexpected error location URI");
+  is(uri,
+     "http://mochi.test:8888/tests/content/base/test/bug461735-redirect2.sjs",
+     "Unexpected error location URI");
   is(line, 3, "Should have a line here");
   errorFired = true;
 }
 </script>
 <script src="bug461735-redirect2.sjs"></script>
 <script>
   is(errorFired, true, "Should have error in same origin script");
 </script>
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -9256,17 +9256,18 @@ nsGlobalWindow::RunTimeout(nsTimeout *aT
       const char *filename = nsnull;
       PRUint32 lineNo = 0;
       handler->GetLocation(&filename, &lineNo);
 
       NS_TIME_FUNCTION_MARK("(file: %s, line: %d)", filename, lineNo);
 
       bool is_undefined;
       scx->EvaluateString(nsDependentString(script), FastGetGlobalJSObject(),
-                          timeout->mPrincipal, filename, lineNo,
+                          timeout->mPrincipal, timeout->mPrincipal,
+                          filename, lineNo,
                           handler->GetScriptVersion(), nsnull,
                           &is_undefined);
     } else {
       // Let the script handler know about the "secret" final argument that
       // indicates timeout lateness in milliseconds
       TimeDuration lateness = now - timeout->mWhen;
 
       handler->SetLateness(lateness.ToMilliseconds());
--- a/dom/base/nsIScriptContext.h
+++ b/dom/base/nsIScriptContext.h
@@ -69,18 +69,18 @@ public:
 
   virtual nsIScriptObjectPrincipal* GetObjectPrincipal() = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptContextPrincipal,
                               NS_ISCRIPTCONTEXTPRINCIPAL_IID)
 
 #define NS_ISCRIPTCONTEXT_IID \
-{ 0xb36103bd, 0x304e, 0x4ef2, \
-  { 0x81, 0x12, 0x83, 0x42, 0xe5, 0xbd, 0xf3, 0xd4 } }
+{ 0xf3840057, 0x4fe5, 0x4f92, \
+ { 0xa3, 0xb8, 0x27, 0xd7, 0x44, 0x6f, 0x72, 0x4d } }
 
 /* This MUST match JSVERSION_DEFAULT.  This version stuff if we don't
    know what language we have is a little silly... */
 #define SCRIPTVERSION_DEFAULT JSVERSION_DEFAULT
 
 /**
  * It is used by the application to initialize a runtime and run scripts.
  * A script runtime would implement this interface.
@@ -94,32 +94,35 @@ public:
   virtual PRUint32 GetScriptTypeID() = 0;
 
   /**
    * Compile and execute a script.
    *
    * @param aScript a string representing the script to be executed
    * @param aScopeObject a script object for the scope to execute in, or
    *                     nsnull to use a default scope
-   * @param aPrincipal the principal that produced the script
+   * @param aPrincipal the principal the script should be evaluated with
+   * @param aOriginPrincipal the principal the script originates from.  If null,
+   *                         aPrincipal is used.
    * @param aURL the URL or filename for error messages
    * @param aLineNo the starting line number of the script for error messages
    * @param aVersion the script language version to use when executing
    * @param aRetValue the result of executing the script, or null for no result.
    *        If this is a JS context, it's the caller's responsibility to
    *        preserve aRetValue from GC across this call
    * @param aIsUndefined true if the result of executing the script is the
    *                     undefined value
    *
    * @return NS_OK if the script was valid and got executed
    *
    **/
   virtual nsresult EvaluateString(const nsAString& aScript,
                                   JSObject* aScopeObject,
                                   nsIPrincipal *aPrincipal,
+                                  nsIPrincipal *aOriginPrincipal,
                                   const char *aURL,
                                   PRUint32 aLineNo,
                                   PRUint32 aVersion,
                                   nsAString *aRetValue,
                                   bool* aIsUndefined) = 0;
 
   virtual nsresult EvaluateStringWithValue(const nsAString& aScript,
                                            JSObject* aScopeObject,
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -84,16 +84,18 @@
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 #include "nsDOMScriptObjectHolder.h"
 #include "prmem.h"
 #include "WrapperFactory.h"
 #include "nsGlobalWindow.h"
 #include "nsScriptNameSpaceManager.h"
 
+#include "nsJSPrincipals.h"
+
 #ifdef XP_MACOSX
 // AssertMacros.h defines 'check' and conflicts with AccessCheck.h
 #undef check
 #endif
 #include "AccessCheck.h"
 
 #ifdef MOZ_JSDEBUGGER
 #include "jsdIDebuggerService.h"
@@ -278,23 +280,25 @@ NS_HandleScriptError(nsIScriptGlobalObje
   }
   return called;
 }
 
 class ScriptErrorEvent : public nsRunnable
 {
 public:
   ScriptErrorEvent(nsIScriptGlobalObject* aScriptGlobal,
+                   nsIPrincipal* aScriptOriginPrincipal,
                    PRUint32 aLineNr, PRUint32 aColumn, PRUint32 aFlags,
                    const nsAString& aErrorMsg,
                    const nsAString& aFileName,
                    const nsAString& aSourceLine,
                    bool aDispatchEvent,
                    PRUint64 aInnerWindowID)
-  : mScriptGlobal(aScriptGlobal), mLineNr(aLineNr), mColumn(aColumn),
+    : mScriptGlobal(aScriptGlobal), mOriginPrincipal(aScriptOriginPrincipal),
+      mLineNr(aLineNr), mColumn(aColumn),
     mFlags(aFlags), mErrorMsg(aErrorMsg), mFileName(aFileName),
     mSourceLine(aSourceLine), mDispatchEvent(aDispatchEvent),
     mInnerWindowID(aInnerWindowID)
   {}
 
   NS_IMETHOD Run()
   {
     nsEventStatus status = nsEventStatus_eIgnore;
@@ -315,45 +319,32 @@ public:
 
           errorevent.fileName = mFileName.get();
 
           nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(win));
           NS_ENSURE_STATE(sop);
           nsIPrincipal* p = sop->GetPrincipal();
           NS_ENSURE_STATE(p);
 
-          bool sameOrigin = mFileName.IsVoid();
+          bool sameOrigin = !mOriginPrincipal;
 
           if (p && !sameOrigin) {
-            nsCOMPtr<nsIURI> errorURI;
-            NS_NewURI(getter_AddRefs(errorURI), mFileName);
-            if (errorURI) {
-              // FIXME: Once error reports contain the origin of the
-              // error (principals) we should change this to do the
-              // security check based on the principals and not
-              // URIs. See bug 387476.
-              sameOrigin = NS_SUCCEEDED(p->CheckMayLoad(errorURI, false));
+            if (NS_FAILED(p->Subsumes(mOriginPrincipal, &sameOrigin))) {
+              sameOrigin = false;
             }
           }
 
           NS_NAMED_LITERAL_STRING(xoriginMsg, "Script error.");
           if (sameOrigin) {
             errorevent.errorMsg = mErrorMsg.get();
             errorevent.lineNr = mLineNr;
           } else {
             NS_WARNING("Not same origin error!");
             errorevent.errorMsg = xoriginMsg.get();
             errorevent.lineNr = 0;
-            // FIXME: once the principal of the script is not tied to
-            // the filename, we can stop using the post-redirect
-            // filename if we want and remove this line.  Note that
-            // apparently we can't handle null filenames in the error
-            // event dispatching code.
-            static PRUnichar nullFilename[] = { PRUnichar(0) };
-            errorevent.fileName = nullFilename;
           }
 
           nsEventDispatcher::Dispatch(win, presContext, &errorevent, nsnull,
                                       &status);
         }
 
         sHandlingScriptError = false;
       }
@@ -402,16 +393,17 @@ public:
         }
       }
     }
     return NS_OK;
   }
 
 
   nsCOMPtr<nsIScriptGlobalObject> mScriptGlobal;
+  nsCOMPtr<nsIPrincipal>          mOriginPrincipal;
   PRUint32                        mLineNr;
   PRUint32                        mColumn;
   PRUint32                        mFlags;
   nsString                        mErrorMsg;
   nsString                        mFileName;
   nsString                        mSourceLine;
   bool                            mDispatchEvent;
   PRUint64                        mInnerWindowID;
@@ -497,18 +489,21 @@ NS_ScriptErrorReporter(JSContext *cx,
       nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(globalObject);
       PRUint64 innerWindowID = 0;
       if (win) {
         nsCOMPtr<nsPIDOMWindow> innerWin = win->GetCurrentInnerWindow();
         if (innerWin) {
           innerWindowID = innerWin->WindowID();
         }
       }
+      JSPrincipals *prin = report->originPrincipals;
+      nsIPrincipal *principal =
+        prin ? static_cast<nsJSPrincipals*>(prin)->nsIPrincipalPtr : nsnull;
       nsContentUtils::AddScriptRunner(
-        new ScriptErrorEvent(globalObject, report->lineno,
+        new ScriptErrorEvent(globalObject, principal, report->lineno,
                              report->uctokenptr - report->uclinebuf,
                              report->flags, msg, fileName, sourceLine,
                              report->errorNumber != JSMSG_OUT_OF_MEMORY,
                              innerWindowID));
     }
   }
 
 #ifdef DEBUG
@@ -1384,16 +1379,17 @@ nsJSContext::GetObjectPrincipal()
   nsCOMPtr<nsIScriptObjectPrincipal> prin = do_QueryInterface(GetGlobalObject());
   return prin;
 }
 
 nsresult
 nsJSContext::EvaluateString(const nsAString& aScript,
                             JSObject* aScopeObject,
                             nsIPrincipal *aPrincipal,
+                            nsIPrincipal *aOriginPrincipal,
                             const char *aURL,
                             PRUint32 aLineNo,
                             PRUint32 aVersion,
                             nsAString *aRetValue,
                             bool* aIsUndefined)
 {
   NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (url: %s, line: %d)", MOZ_FUNCTION_NAME,
                            __LINE__, aURL, aLineNo);
@@ -1431,34 +1427,47 @@ nsJSContext::EvaluateString(const nsAStr
     if (!objPrincipal)
       return NS_ERROR_FAILURE;
     principal = objPrincipal->GetPrincipal();
     if (!principal)
       return NS_ERROR_FAILURE;
     principal->GetJSPrincipals(mContext, &jsprin);
   }
 
+  JSPrincipals *originJSprin;
+  if (aOriginPrincipal) {
+    aOriginPrincipal->GetJSPrincipals(mContext, &originJSprin);
+  } else {
+    originJSprin = nsnull;
+  }
+
   // From here on, we must JSPRINCIPALS_DROP(jsprin) before returning...
 
   bool ok = false;
 
   nsresult rv = sSecurityManager->CanExecuteScripts(mContext, principal, &ok);
   if (NS_FAILED(rv)) {
     JSPRINCIPALS_DROP(mContext, jsprin);
+    if (originJSprin) {
+      JSPRINCIPALS_DROP(mContext, originJSprin);
+    }
     return NS_ERROR_FAILURE;
   }
 
   // Push our JSContext on the current thread's context stack so JS called
   // from native code via XPConnect uses the right context.  Do this whether
   // or not the SecurityManager said "ok", in order to simplify control flow
   // below where we pop before returning.
   nsCOMPtr<nsIJSContextStack> stack =
            do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
   if (NS_FAILED(rv) || NS_FAILED(stack->Push(mContext))) {
     JSPRINCIPALS_DROP(mContext, jsprin);
+    if (originJSprin) {
+      JSPRINCIPALS_DROP(mContext, originJSprin);
+    }
     return NS_ERROR_FAILURE;
   }
 
   // The result of evaluation, used only if there were no errors.  This need
   // not be a GC root currently, provided we run the GC only from the
   // operation callback or from ScriptEvaluated.
   jsval val = JSVAL_VOID;
   jsval* vp = aRetValue ? &val : NULL;
@@ -1474,35 +1483,41 @@ nsJSContext::EvaluateString(const nsAStr
   // Since the caller is responsible for parsing the version strings, we just
   // check it isn't JSVERSION_UNKNOWN.
   if (ok && JSVersion(aVersion) != JSVERSION_UNKNOWN) {
     JSAutoRequest ar(mContext);
     JSAutoEnterCompartment ac;
     if (!ac.enter(mContext, aScopeObject)) {
       stack->Pop(nsnull);
       JSPRINCIPALS_DROP(mContext, jsprin);
+      if (originJSprin) {
+        JSPRINCIPALS_DROP(mContext, originJSprin);
+      }
       return NS_ERROR_FAILURE;
     }
 
-    ok = JS_EvaluateUCScriptForPrincipalsVersion(
-      mContext, aScopeObject, jsprin,
+    ok = JS_EvaluateUCScriptForPrincipalsVersionOrigin(
+      mContext, aScopeObject, jsprin, originJSprin,
       static_cast<const jschar*>(PromiseFlatString(aScript).get()),
       aScript.Length(), aURL, aLineNo, vp, JSVersion(aVersion));
 
     if (!ok) {
       // Tell XPConnect about any pending exceptions. This is needed
       // to avoid dropping JS exceptions in case we got here through
       // nested calls through XPConnect.
 
       ReportPendingException();
     }
   }
 
   // Whew!  Finally done with these manually ref-counted things.
   JSPRINCIPALS_DROP(mContext, jsprin);
+  if (originJSprin) {
+    JSPRINCIPALS_DROP(mContext, originJSprin);
+  }
 
   // If all went well, convert val to a string if one is wanted.
   if (ok) {
     JSAutoRequest ar(mContext);
     JSAutoEnterCompartment ac;
     if (!ac.enter(mContext, aScopeObject)) {
       stack->Pop(nsnull);
     }
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -70,16 +70,17 @@ public:
   virtual nsIScriptObjectPrincipal* GetObjectPrincipal();
 
   virtual PRUint32 GetScriptTypeID()
     { return nsIProgrammingLanguage::JAVASCRIPT; }
 
   virtual nsresult EvaluateString(const nsAString& aScript,
                                   JSObject* aScopeObject,
                                   nsIPrincipal *principal,
+                                  nsIPrincipal *originPrincipal,
                                   const char *aURL,
                                   PRUint32 aLineNo,
                                   PRUint32 aVersion,
                                   nsAString *aRetValue,
                                   bool* aIsUndefined);
   virtual nsresult EvaluateStringWithValue(const nsAString& aScript,
                                            JSObject* aScopeObject,
                                            nsIPrincipal* aPrincipal,
--- a/dom/src/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/src/jsurl/nsJSProtocolHandler.cpp
@@ -355,16 +355,17 @@ nsresult nsJSThunk::EvaluateScript(nsICh
 
         stack->Pop(nsnull);
     } else {
         // No need to use the sandbox, evaluate the script directly in
         // the given scope.
         rv = scriptContext->EvaluateString(NS_ConvertUTF8toUTF16(script),
                                            globalJSObject, // obj
                                            principal,
+                                           principal,
                                            mURL.get(),     // url
                                            1,              // line no
                                            nsnull,
                                            &result,
                                            &isUndefined);
 
         // If there's an error on cx as a result of that call, report
         // it now -- either we're just running under the event loop,
--- a/hal/Makefile.in
+++ b/hal/Makefile.in
@@ -36,16 +36,17 @@
 # ***** END LICENSE BLOCK *****
 
 DEPTH       = ..
 topsrcdir   = @top_srcdir@
 srcdir      = @srcdir@
 VPATH       = \
   $(srcdir) \
   $(srcdir)/android \
+  $(srcdir)/gonk \
   $(srcdir)/fallback \
   $(srcdir)/sandbox \
   $(srcdir)/linux \
   $(srcdir)/windows \
   $(NULL)
 
 include $(DEPTH)/config/autoconf.mk
 
@@ -65,16 +66,18 @@ EXPORTS_mozilla = \
 CPPSRCS = \
   Hal.cpp \
   SandboxHal.cpp \
   WindowIdentifier.cpp \
   $(NULL)
 
 ifeq (android,$(MOZ_WIDGET_TOOLKIT))
 CPPSRCS += AndroidHal.cpp
+else ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
+CPPSRCS += GonkHal.cpp
 else ifeq (Linux,$(OS_TARGET))
 CPPSRCS += LinuxHal.cpp
 ifdef MOZ_ENABLE_DBUS
 CPPSRCS += UPowerClient.cpp
 endif
 else ifeq (WINNT,$(OS_TARGET))
 CPPSRCS += WindowsHal.cpp WindowsBattery.cpp
 else
new file mode 100644
--- /dev/null
+++ b/hal/gonk/GonkHal.cpp
@@ -0,0 +1,273 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et ft=cpp : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Code.
+ *
+ * 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):
+ *   Chris Jones <jones.chris.g@gmail.com>
+ *   Michael Wu <mwu@mozilla.com>
+ *   Justin Lebar <justin.lebar@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "hardware_legacy/uevent.h"
+#include "Hal.h"
+#include "mozilla/dom/battery/Constants.h"
+#include "mozilla/FileUtils.h"
+#include "nsAlgorithm.h"
+#include "nsThreadUtils.h"
+#include <stdio.h>
+#include <math.h>
+#include <fcntl.h>
+#include <errno.h>
+
+using mozilla::hal::WindowIdentifier;
+
+namespace mozilla {
+namespace hal_impl {
+
+void
+Vibrate(const nsTArray<uint32>& pattern, const WindowIdentifier &)
+{}
+
+void
+CancelVibrate(const WindowIdentifier &)
+{}
+
+namespace {
+
+class BatteryUpdater : public nsRunnable {
+public:
+  NS_IMETHOD Run()
+  {
+    hal::BatteryInformation info;
+    hal_impl::GetCurrentBatteryInformation(&info);
+    hal::NotifyBatteryChange(info);
+    return NS_OK;
+  }
+};
+
+class UEventWatcher : public nsRunnable {
+public:
+  UEventWatcher()
+    : mUpdater(new BatteryUpdater())
+    , mRunning(false)
+  {
+  }
+
+  NS_IMETHOD Run()
+  {
+    while (mRunning) {
+      char buf[1024];
+      int count = uevent_next_event(buf, sizeof(buf) - 1);
+      if (!count) {
+        NS_WARNING("uevent_next_event() returned 0!");
+        continue;
+      }
+
+      buf[sizeof(buf) - 1] = 0;
+      if (strstr(buf, "battery"))
+        NS_DispatchToMainThread(mUpdater);
+    }
+    return NS_OK;
+  }
+
+  bool mRunning;
+
+private:
+  nsRefPtr<BatteryUpdater> mUpdater;
+};
+
+} // anonymous namespace
+
+static bool sUEventInitialized = false;
+static UEventWatcher *sWatcher = NULL;
+static nsIThread *sWatcherThread = NULL;
+
+void
+EnableBatteryNotifications()
+{
+  if (!sUEventInitialized)
+    sUEventInitialized = uevent_init();
+  if (!sUEventInitialized) {
+    NS_WARNING("uevent_init() failed!");
+    return;
+  }
+
+  if (!sWatcher)
+    sWatcher = new UEventWatcher();
+  NS_ADDREF(sWatcher);
+
+  sWatcher->mRunning = true;
+  nsresult rv = NS_NewThread(&sWatcherThread, sWatcher);
+  if (NS_FAILED(rv))
+    NS_WARNING("Failed to get new thread for uevent watching");
+}
+
+void
+DisableBatteryNotifications()
+{
+  sWatcher->mRunning = false;
+  sWatcherThread->Shutdown();
+  NS_IF_RELEASE(sWatcherThread);
+  delete sWatcher;
+}
+
+void
+GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
+{
+  FILE *capacityFile = fopen("/sys/class/power_supply/battery/capacity", "r");
+  double capacity = dom::battery::kDefaultLevel * 100;
+  if (capacityFile)
+    fscanf(capacityFile, "%lf", &capacity);
+  fclose(capacityFile);
+
+  FILE *chargingFile = fopen("/sys/class/power_supply/battery/charging_source", "r");
+  int chargingSrc = 1;
+  if (chargingFile)
+    fscanf(chargingFile, "%d", &chargingSrc);
+  fclose(chargingFile);
+
+  aBatteryInfo->level() = capacity / 100;
+  aBatteryInfo->charging() = chargingSrc == 1;
+  aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime;
+}
+
+namespace {
+
+/**
+ * RAII class to help us remember to close file descriptors.
+ */
+const char *screenEnabledFilename = "/sys/power/state";
+const char *screenBrightnessFilename = "/sys/class/backlight/pwm-backlight/brightness";
+
+template<ssize_t n>
+bool ReadFromFile(const char *filename, char (&buf)[n])
+{
+  int fd = open(filename, O_RDONLY);
+  ScopedClose autoClose(fd);
+  if (fd < 0) {
+    HAL_LOG(("Unable to open file %s.", filename));
+    return false;
+  }
+
+  ssize_t numRead = read(fd, buf, n);
+  if (numRead < 0) {
+    HAL_LOG(("Error reading from file %s.", filename));
+    return false;
+  }
+
+  buf[PR_MIN(numRead, n - 1)] = '\0';
+  return true;
+}
+
+void WriteToFile(const char *filename, const char *toWrite)
+{
+  int fd = open(filename, O_WRONLY);
+  ScopedClose autoClose(fd);
+  if (fd < 0) {
+    HAL_LOG(("Unable to open file %s.", filename));
+    return;
+  }
+
+  if (write(fd, toWrite, strlen(toWrite)) < 0) {
+    HAL_LOG(("Unable to write to file %s.", filename));
+    return;
+  }
+}
+
+// We can write to screenEnabledFilename to enable/disable the screen, but when
+// we read, we always get "mem"!  So we have to keep track ourselves whether
+// the screen is on or not.
+bool sScreenEnabled = true;
+
+} // anonymous namespace
+
+bool
+GetScreenEnabled()
+{
+  return sScreenEnabled;
+}
+
+void
+SetScreenEnabled(bool enabled)
+{
+  WriteToFile(screenEnabledFilename, enabled ? "on" : "mem");
+  sScreenEnabled = enabled;
+}
+
+double
+GetScreenBrightness()
+{
+  char buf[32];
+  ReadFromFile(screenBrightnessFilename, buf);
+
+  errno = 0;
+  unsigned long val = strtoul(buf, NULL, 10);
+  if (errno) {
+    HAL_LOG(("Cannot parse contents of %s; expected an unsigned "
+             "int, but contains \"%s\".",
+             screenBrightnessFilename, buf));
+    return 1;
+  }
+
+  if (val > 255) {
+    HAL_LOG(("Got out-of-range brightness %d, truncating to 1.0", val));
+    val = 255;
+  }
+
+  return val / 255.0;
+}
+
+void
+SetScreenBrightness(double brightness)
+{
+  // Don't use De Morgan's law to push the ! into this expression; we want to
+  // catch NaN too.
+  if (!(0 <= brightness && brightness <= 1)) {
+    HAL_LOG(("SetScreenBrightness: Dropping illegal brightness %f.",
+             brightness));
+    return;
+  }
+
+  // Convert the value in [0, 1] to an int between 0 and 255, then write to a
+  // string.
+  int val = static_cast<int>(round(brightness * 255));
+  char str[4];
+  DebugOnly<int> numChars = snprintf(str, sizeof(str), "%d", val);
+  MOZ_ASSERT(numChars < static_cast<int>(sizeof(str)));
+
+  WriteToFile(screenBrightnessFilename, str);
+}
+
+} // hal_impl
+} // mozilla
--- a/intl/uconv/util/ubase.h
+++ b/intl/uconv/util/ubase.h
@@ -32,26 +32,14 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 #ifndef ubase_h__
 #define ubase_h__
 
-#ifdef _WIN32
-#ifndef NS_WIN32 
-#define NS_WIN32 1
-#endif
-#endif
-
-#if defined(__unix)
-#ifndef NS_UNIX 
-#define NS_UNIX 1
-#endif
-#endif
-
 #include "prtypes.h"
 
 #define PRIVATE 
 #define MODULE_PRIVATE
 
 #endif
--- a/js/src/ds/LifoAlloc.cpp
+++ b/js/src/ds/LifoAlloc.cpp
@@ -92,17 +92,20 @@ BumpChunk::canAllocUnaligned(size_t n)
 void *
 BumpChunk::tryAllocUnaligned(size_t n)
 {
     char *oldBump = bump;
     char *newBump = bump + n;
     if (newBump > limit)
         return NULL;
 
-    JS_ASSERT(canAllocUnaligned(n));
+    if (JS_UNLIKELY(newBump < oldBump))
+        return NULL;
+
+    JS_ASSERT(canAllocUnaligned(n)); /* Ensure consistency between "can" and "try". */
     setBump(newBump);
     return oldBump;
 }
 
 } /* namespace detail */
 } /* namespace js */
 
 void
--- a/js/src/jsxdrapi.cpp
+++ b/js/src/jsxdrapi.cpp
@@ -690,16 +690,19 @@ JS_XDRFunctionObject(JSXDRState *xdr, JS
 {
     XDRScriptState fstate(xdr);
 
     if (xdr->mode == JSXDR_ENCODE) {
         JSFunction* fun = (*objp)->toFunction();
         fstate.filename = fun->script()->filename;
     }
 
+    if (!JS_XDRCStringOrNull(xdr, (char **) &fstate.filename))
+        return false;
+
     return js_XDRFunctionObject(xdr, objp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_XDRScript(JSXDRState *xdr, JSScript **scriptp)
 {
     JS_ASSERT(!xdr->state);
 
--- a/js/src/tests/ecma_5/RegExp/jstests.list
+++ b/js/src/tests/ecma_5/RegExp/jstests.list
@@ -4,11 +4,12 @@ script 15.10.5-01.js
 script 15.10.7.5-01.js
 script empty-lookahead.js
 script exec.js
 script exec-lastIndex-ToInteger.js
 script regress-576828.js
 script regress-613820-1.js
 script regress-613820-2.js
 script regress-613820-3.js
+script regress-429241.js
 silentfail skip-if(!xulRuntime.shell&&(Android||xulRuntime.OS=="WINNT")) script regress-617935.js
 script instance-property-storage-introspection.js
 script regexp-space-character-class.js
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_5/RegExp/regress-429241.js
@@ -0,0 +1,233 @@
+/* ***** 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 JavaScript Engine testing utilities.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   <x00000000@freenet.de>
+ *
+ * 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 ***** */
+
+var gTestfile = 'regress-429241.js';
+var BUGNUMBER = 429241;
+var summary = '\\x or \\u followed by too few hex digits';
+var r;
+
+reportCompare(
+  "x",
+  (r = /[\x]+/.exec("\\x\0")) && r[0],
+  "Section 1"
+);
+
+reportCompare(
+  "xy",
+  (r = /[\xy]+/.exec("\\xy\0")) && r[0],
+  "Section 2"
+);
+
+reportCompare(
+  "x0",
+  (r = /[\x0]+/.exec("\\x0\0")) && r[0],
+  "Section 3"
+);
+
+reportCompare(
+  "x0y",
+  (r = /[\x0y]+/.exec("\\x0y\0")) && r[0],
+  "Section 4"
+);
+
+reportCompare(
+  "\0",
+  (r = /[\x00]+/.exec("\\x\0")) && r[0],
+  "Section 5"
+);
+
+reportCompare(
+  "0\0",
+  (r = /[\x000]+/.exec("0\0")) && r[0],
+  "Section 6"
+);
+
+reportCompare(
+  "x",
+  (r = /^\x$/.exec("x")) && r[0],
+  "Section 7"
+);
+
+reportCompare(
+  "xy",
+  (r = /^\xy$/.exec("xy")) && r[0],
+  "Section 8"
+);
+
+reportCompare(
+  "x0",
+  (r = /^\x0$/.exec("x0")) && r[0],
+  "Section 9"
+);
+
+reportCompare(
+  "x0y",
+  (r = /^\x0y$/.exec("x0y")) && r[0],
+  "Section 10"
+);
+
+reportCompare(
+  null,
+  /^\x00$/.exec("\0" + "0"),
+  "Section 11"
+);
+
+reportCompare(
+  "\0" + "0",
+  (r = /^\x000$/.exec("\0" + "0")) && r[0],
+  "Section 12"
+);
+
+reportCompare(
+  "u",
+  (r = /[\u]+/.exec("\\u\0")) && r[0],
+  "Section 13"
+);
+
+reportCompare(
+  "uy",
+  (r = /[\uy]+/.exec("\\uy\0")) && r[0],
+  "Section 14"
+);
+
+reportCompare(
+  "u0",
+  (r = /[\u0]+/.exec("\\u0\0")) && r[0],
+  "Section 15"
+);
+
+reportCompare(
+  "u0",
+  (r = /[\u00]+/.exec("\\u0\0")) && r[0],
+  "Section 16"
+);
+
+reportCompare(
+  "u0",
+  (r = /[\u000]+/.exec("\\u0\0")) && r[0],
+  "Section 17"
+);
+
+reportCompare(
+  "u0y",
+  (r = /[\u0y]+/.exec("\\u0y\0")) && r[0],
+  "Section 18"
+);
+
+reportCompare(
+  "u0y",
+  (r = /[\u00y]+/.exec("\\u0y\0")) && r[0],
+  "Section 19"
+);
+
+reportCompare(
+  "u0y",
+  (r = /[\u000y]+/.exec("\\u0y\0")) && r[0],
+  "Section 20"
+);
+
+reportCompare(
+  "\0",
+  (r = /[\u0000]+/.exec("\\u\0")) && r[0],
+  "Section 21"
+);
+
+reportCompare(
+  "0\0",
+  (r = /[\u00000]+/.exec("0\0")) && r[0],
+  "Section 22"
+);
+
+reportCompare(
+  "u",
+  (r = /^\u$/.exec("u")) && r[0],
+  "Section 23"
+);
+
+reportCompare(
+  "uy",
+  (r = /^\uy$/.exec("uy")) && r[0],
+  "Section 24"
+);
+
+reportCompare(
+  "u0",
+  (r = /^\u0$/.exec("u0")) && r[0],
+  "Section 25"
+);
+
+reportCompare(
+  "u00",
+  (r = /^\u00$/.exec("u00")) && r[0],
+  "Section 26"
+);
+
+reportCompare(
+  "u000",
+  (r = /^\u000$/.exec("u000")) && r[0],
+  "Section 27"
+);
+
+reportCompare(
+  "u0y",
+  (r = /^\u0y$/.exec("u0y")) && r[0],
+  "Section 28"
+);
+
+reportCompare(
+  "u00y",
+  (r = /^\u00y$/.exec("u00y")) && r[0],
+  "Section 29"
+);
+
+reportCompare(
+  "u000y",
+  (r = /^\u000y$/.exec("u000y")) && r[0],
+  "Section 30"
+);
+
+reportCompare(
+  null,
+  /^\u0000$/.exec("\0" + "0"),
+  "Section 31"
+);
+
+reportCompare(
+  "\0" + "0",
+  (r = /^\u00000$/.exec("\0" + "0")) && r[0],
+  "Section 32"
+);
--- a/js/src/tests/js1_5/Regress/jstests.list
+++ b/js/src/tests/js1_5/Regress/jstests.list
@@ -144,17 +144,17 @@ script regress-321874.js
 script regress-321971.js
 script regress-322430.js
 script regress-323314-1.js
 script regress-325925.js
 script regress-326453.js
 script regress-326467.js
 script regress-328012.js
 script regress-328664.js
-script regress-328897.js
+fails-if(browserIsRemote) script regress-328897.js
 script regress-329383.js
 skip-if(Android) script regress-329530.js
 skip-if(Android) script regress-330352.js
 script regress-330951.js
 script regress-334807-01.js
 script regress-334807-02.js
 script regress-334807-03.js
 script regress-334807-04.js
--- a/js/src/tests/js1_5/Regress/regress-328897.js
+++ b/js/src/tests/js1_5/Regress/regress-328897.js
@@ -46,17 +46,17 @@ printBugNumber(BUGNUMBER);
 printStatus (summary);
  
 if (typeof window == 'undefined')
 {
   reportCompare(expect, actual, summary);
 }
 else
 {
-  expect = /(Script error.|uncaught exception: Permission denied to get property UnnamedClass.classes)/;
+  expect = /(Script error.|Permission denied for <file:\/\/> to get property XPCComponents.classes)/;
 
   window._onerror = window.onerror;
   window.onerror = (function (msg, page, line) { 
       actual = msg; 
       gDelayTestDriverEnd = false;
       jsTestDriverEnd();
       reportMatch(expect, actual, summary);
     });
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -623,17 +623,22 @@ XPC_WN_NoHelper_Finalize(JSContext *cx, 
 
     if (IS_SLIM_WRAPPER_OBJECT(obj)) {
         SLIM_LOG(("----- %i finalized slim wrapper (%p, %p)\n",
                   ++sFinalizedSlimWrappers, obj, p));
 
         nsWrapperCache* cache;
         CallQueryInterface(p, &cache);
         cache->ClearWrapper();
-        NS_RELEASE(p);
+
+        XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance();
+        if(rt)
+            rt->DeferredRelease(p);
+        else
+            NS_RELEASE(p);
         return;
     }
 
     static_cast<XPCWrappedNative*>(p)->FlatJSObjectFinalized(cx);
 }
 
 static void
 TraceScopeJSObjects(JSTracer *trc, XPCWrappedNativeScope* scope)
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -3766,23 +3766,19 @@ DocumentViewerImpl::PrintPreviewNavigate
   // If it is "End" then just do a "goto" to the last page
   if (aType == nsIWebBrowserPrint::PRINTPREVIEW_END) {
     aType    = nsIWebBrowserPrint::PRINTPREVIEW_GOTO_PAGENUM;
     aPageNum = pageCount;
   }
 
   // Now, locate the current page we are on and
   // and the page of the page number
-  nscoord gap = 0;
   nsIFrame* pageFrame = seqFrame->GetFirstPrincipalChild();
   while (pageFrame != nsnull) {
     nsRect pageRect = pageFrame->GetRect();
-    if (pageNum == 1) {
-      gap = pageRect.y;
-    }
     if (pageRect.Contains(pageRect.x, pt.y)) {
       currentPage = pageFrame;
     }
     if (pageNum == aPageNum) {
       fndPageFrame = pageFrame;
       break;
     }
     pageNum++;
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -4222,17 +4222,17 @@ nsLayoutUtils::GetFontFacesForFrames(nsI
   if (aFrame->GetType() == nsGkAtoms::textFrame) {
     return GetFontFacesForText(aFrame, 0, PR_INT32_MAX, false,
                                aFontFaceList);
   }
 
   while (aFrame) {
     nsIFrame::ChildListID childLists[] = { nsIFrame::kPrincipalList,
                                            nsIFrame::kPopupList };
-    for (int i = 0; i < ArrayLength(childLists); ++i) {
+    for (size_t i = 0; i < ArrayLength(childLists); ++i) {
       nsFrameList children(aFrame->GetChildList(childLists[i]));
       for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) {
         nsIFrame* child = e.get();
         if (child->GetPrevContinuation()) {
           continue;
         }
         child = nsPlaceholderFrame::GetRealFrameFor(child);
         nsresult rv = GetFontFacesForFrames(child, aFontFaceList);
@@ -4501,29 +4501,34 @@ nsReflowFrameRunnable::Run()
  * width of the device**, the fonts satisfy our minima.
  */
 static nscoord
 MinimumFontSizeFor(nsPresContext* aPresContext, nscoord aContainerWidth)
 {
   if (sFontSizeInflationEmPerLine == 0 && sFontSizeInflationMinTwips == 0) {
     return 0;
   }
+
+  // Clamp the container width to the device dimensions
+  nscoord iFrameWidth = aPresContext->GetVisibleArea().width;
+  nscoord effectiveContainerWidth = NS_MIN(iFrameWidth, aContainerWidth);
+
   nscoord byLine = 0, byInch = 0;
   if (sFontSizeInflationEmPerLine != 0) {
-    byLine = aContainerWidth / sFontSizeInflationEmPerLine;
+    byLine = effectiveContainerWidth / sFontSizeInflationEmPerLine;
   }
   if (sFontSizeInflationMinTwips != 0) {
     // REVIEW: Is this giving us app units and sizes *not* counting
     // viewport scaling?
     nsDeviceContext *dx = aPresContext->DeviceContext();
     nsRect clientRect;
     dx->GetClientRect(clientRect); // FIXME: GetClientRect looks expensive
     float deviceWidthInches =
       float(clientRect.width) / float(dx->AppUnitsPerPhysicalInch());
-    byInch = NSToCoordRound(aContainerWidth /
+    byInch = NSToCoordRound(effectiveContainerWidth /
                             (deviceWidthInches * 1440 /
                              sFontSizeInflationMinTwips ));
   }
   return NS_MAX(byLine, byInch);
 }
 
 /* static */ float
 nsLayoutUtils::FontSizeInflationInner(const nsIFrame *aFrame,
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -486,32 +486,34 @@ nsPresContext::GetFontPreferences()
   PRInt32 size = Preferences::GetInt(pref.get());
   if (unit == eUnit_px) {
     mMinimumFontSizePref = CSSPixelsToAppUnits(size);
   }
   else if (unit == eUnit_pt) {
     mMinimumFontSizePref = CSSPointsToAppUnits(size);
   }
 
+  nsFont* fontTypes[] = {
+    &mDefaultVariableFont,
+    &mDefaultFixedFont,
+    &mDefaultSerifFont,
+    &mDefaultSansSerifFont,
+    &mDefaultMonospaceFont,
+    &mDefaultCursiveFont,
+    &mDefaultFantasyFont
+  };
+  PR_STATIC_ASSERT(NS_ARRAY_LENGTH(fontTypes) == eDefaultFont_COUNT);
+
   // get attributes specific to each generic font
   nsCAutoString generic_dot_langGroup;
-  for (PRInt32 eType = eDefaultFont_Variable; eType < eDefaultFont_COUNT; ++eType) {
+  for (PRUint32 eType = 0; eType < ArrayLength(fontTypes); ++eType) {
     generic_dot_langGroup.Assign(kGenericFont[eType]);
     generic_dot_langGroup.Append(langGroup);
 
-    nsFont* font;
-    switch (eType) {
-      case eDefaultFont_Variable:  font = &mDefaultVariableFont;  break;
-      case eDefaultFont_Fixed:     font = &mDefaultFixedFont;     break;
-      case eDefaultFont_Serif:     font = &mDefaultSerifFont;     break;
-      case eDefaultFont_SansSerif: font = &mDefaultSansSerifFont; break;
-      case eDefaultFont_Monospace: font = &mDefaultMonospaceFont; break;
-      case eDefaultFont_Cursive:   font = &mDefaultCursiveFont;   break;
-      case eDefaultFont_Fantasy:   font = &mDefaultFantasyFont;   break;
-    }
+    nsFont* font = fontTypes[eType];
 
     // set the default variable font (the other fonts are seen as 'generic' fonts
     // in GFX and will be queried there when hunting for alternative fonts)
     if (eType == eDefaultFont_Variable) {
       MAKE_FONT_PREF_KEY(pref, "font.name", generic_dot_langGroup);
 
       nsAdoptingString value = Preferences::GetString(pref.get());
       if (!value.IsEmpty()) {
--- a/layout/base/tests/TestPoisonArea.cpp
+++ b/layout/base/tests/TestPoisonArea.cpp
@@ -614,16 +614,17 @@ TestPage(const char *pagelabel, uintptr_
     } else if (pid == 0) {
       volatile unsigned char scratch;
       switch (test) {
       case 0: scratch = *(volatile unsigned char *)opaddr; break;
       case 1: JumpTo(opaddr); break;
       case 2: *(volatile unsigned char *)opaddr = 0; break;
       default: abort();
       }
+      (void)scratch;
       _exit(0);
     } else {
       int status;
       if (waitpid(pid, &status, 0) != pid) {
         printf("ERROR | %s %s | wait=%s\n", oplabel, pagelabel,
                LastErrMsg());
         exit(2);
       }
new file mode 100644
new file mode 100644
new file mode 100644
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/font-inflation/container-with-clamping-innerFrame-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<style>
+	div { background: yellow }
+	div { font-size: 20px; line-height: 1.0; width: 450px }
+</style>
+<!--
+Without the patch for bug 707855, we have a 450px container, and the minimum font size
+at 15em per line is 30px. This means we map 0px-45px into 30px-45px, so 12px gets mapped
+to 34px.
+
+With the patch, then we have a 240px container, so the minimum font size
+at 15 em per line is 16px. So, we map 0px-24px into 16px-24px, so 12px gets
+mapped to 20px.
+-->
+<div>Test to see if too large of a container causes a giant escalation of the font size when font inflation is enabled.</div>
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/font-inflation/container-with-clamping-innerFrame.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<style>
+	div { background: yellow }
+	div { font-size: 12px; line-height: 1.0; width: 450px }
+</style>
+<!--
+Without the patch for bug 707855, we have a 450px container, and the minimum font size
+at 15em per line is 30px. This means we map 0px-45px into 30px-45px, so 12px gets mapped
+to 34px.
+
+With the patch, then we have a 240px container, so the minimum font size
+at 15 em per line is 16px. So, we map 0px-24px into 16px-24px, so 12px gets
+mapped to 20px.
+-->
+<div>Test to see if too large of a container causes a giant escalation of the font size when font inflation is enabled.</div>
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/font-inflation/container-with-clamping-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<style>
+div { background: yellow }
+div { font-size: 12px; line-height: 1.0; width: 1200px }
+</style>
+<!--
+Without the patch for bug 707855, we have a 450px container, and the minimum font size
+at 15em per line is 30px. This means we map 0px-45px into 30px-45px, so 12px gets mapped
+to 34px.
+
+With the patch, then we have a 240px container, so the minimum font size
+at 15 em per line is 16px. So, we map 0px-24px into 16px-24px, so 12px gets
+mapped to 20px.
+-->
+<iframe src="container-with-clamping-innerFrame-ref.html" width="240" height="400">
+</iframe>
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/font-inflation/container-with-clamping.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<!--
+Without the patch for bug 707855, we have a 450px container, and the minimum font size
+at 15em per line is 30px. This means we map 0px-45px into 30px-45px, so 12px gets mapped
+to 34px.
+
+With the patch, then we have a 240px container, so the minimum font size
+at 15 em per line is 16px. So, we map 0px-24px into 16px-24px, so 12px gets
+mapped to 20px.
+-->
+<iframe src="container-with-clamping-innerFrame.html" width="240" height="400">
+</iframe>
--- a/layout/base/tests/test_font_inflation_reftests.html
+++ b/layout/base/tests/test_font_inflation_reftests.html
@@ -40,16 +40,17 @@ var gTests = [
   "== input-text-1.html input-text-1-ref.html",
   "== input-text-2.html input-text-2-ref.html",
   "== input-text-3.html input-text-3-ref.html",
   "== textarea-1.html textarea-1-ref.html",
   "== textarea-2.html textarea-2-ref.html",
   "== textarea-3.html textarea-3-ref.html",
   "== css-transform-1.html css-transform-1-ref.html",
   "== css-transform-2.html css-transform-2-ref.html",
+  "== container-with-clamping.html container-with-clamping-ref.html",
 ];
 
 // Maintain a reference count of how many things we're waiting for until
 // we can say the tests are done.
 var gDelayCount = 0;
 function AddFinishDependency()
   { ++gDelayCount; }
 function RemoveFinishDependency()
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -405,17 +405,17 @@ nsBlockFrame::List(FILE* out, PRInt32 aI
 
   if (nsnull != mContent) {
     fprintf(out, " [content=%p]", static_cast<void*>(mContent));
   }
 
   // Output the rect and state
   fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
   if (0 != mState) {
-    fprintf(out, " [state=%016llx]", mState);
+    fprintf(out, " [state=%016llx]", (unsigned long long)mState);
   }
   nsBlockFrame* f = const_cast<nsBlockFrame*>(this);
   if (f->HasOverflowAreas()) {
     nsRect overflowArea = f->GetVisualOverflowRect();
     fprintf(out, " [vis-overflow=%d,%d,%d,%d]", overflowArea.x, overflowArea.y,
             overflowArea.width, overflowArea.height);
     overflowArea = f->GetScrollableOverflowRect();
     fprintf(out, " [scr-overflow=%d,%d,%d,%d]", overflowArea.x, overflowArea.y,
@@ -7072,27 +7072,23 @@ nsBlockFrame::VerifyLines(bool aFinalChe
   }
   if (mLines.empty()) {
     return;
   }
 
   // Add up the counts on each line. Also validate that IsFirstLine is
   // set properly.
   PRInt32 count = 0;
-  bool seenBlock = false;
   line_iterator line, line_end;
   for (line = begin_lines(), line_end = end_lines();
        line != line_end;
        ++line) {
     if (aFinalCheckOK) {
       NS_ABORT_IF_FALSE(line->GetChildCount(), "empty line");
       if (line->IsBlock()) {
-        seenBlock = true;
-      }
-      if (line->IsBlock()) {
         NS_ASSERTION(1 == line->GetChildCount(), "bad first line");
       }
     }
     count += line->GetChildCount();
   }
 
   // Then count the frames
   PRInt32 frameCount = 0;
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -1738,17 +1738,17 @@ nsContainerFrame::List(FILE* out, PRInt3
     fprintf(out, " IBSplitSpecialSibling=%p", IBsibling);
   }
   void* IBprevsibling = Properties().Get(IBSplitSpecialPrevSibling());
   if (IBprevsibling) {
     fprintf(out, " IBSplitSpecialPrevSibling=%p", IBprevsibling);
   }
   fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
   if (0 != mState) {
-    fprintf(out, " [state=%016llx]", mState);
+    fprintf(out, " [state=%016llx]", (unsigned long long)mState);
   }
   fprintf(out, " [content=%p]", static_cast<void*>(mContent));
   nsContainerFrame* f = const_cast<nsContainerFrame*>(this);
   if (f->HasOverflowAreas()) {
     nsRect overflowArea = f->GetVisualOverflowRect();
     fprintf(out, " [vis-overflow=%d,%d,%d,%d]", overflowArea.x, overflowArea.y,
             overflowArea.width, overflowArea.height);
     overflowArea = f->GetScrollableOverflowRect();
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -5049,17 +5049,17 @@ nsFrame::List(FILE* out, PRInt32 aIndent
 #ifdef DEBUG_waterson
   fprintf(out, " [parent=%p]", static_cast<void*>(mParent));
 #endif
   if (HasView()) {
     fprintf(out, " [view=%p]", static_cast<void*>(GetView()));
   }
   fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
   if (0 != mState) {
-    fprintf(out, " [state=%016llx]", mState);
+    fprintf(out, " [state=%016llx]", (unsigned long long)mState);
   }
   nsIFrame* prevInFlow = GetPrevInFlow();
   nsIFrame* nextInFlow = GetNextInFlow();
   if (nsnull != prevInFlow) {
     fprintf(out, " prev-in-flow=%p", static_cast<void*>(prevInFlow));
   }
   if (nsnull != nextInFlow) {
     fprintf(out, " next-in-flow=%p", static_cast<void*>(nextInFlow));
@@ -5271,17 +5271,17 @@ nsFrame::DumpRegressionData(nsPresContex
 {
   IndentBy(out, aIndent);
   fprintf(out, "<frame va=\"%ld\" type=\"", PRUptrdiff(this));
   nsAutoString name;
   GetFrameName(name);
   XMLQuote(name);
   fputs(NS_LossyConvertUTF16toASCII(name).get(), out);
   fprintf(out, "\" state=\"%016llx\" parent=\"%ld\">\n",
-          GetDebugStateBits(), PRUptrdiff(mParent));
+          (unsigned long long)GetDebugStateBits(), PRUptrdiff(mParent));
 
   aIndent++;
   DumpBaseRegressionData(aPresContext, out, aIndent);
   aIndent--;
 
   IndentBy(out, aIndent);
   fprintf(out, "</frame>\n");
 
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -839,25 +839,23 @@ nsHTMLScrollFrame::Reflow(nsPresContext*
   // sanity check: ensure that if we have no scrollbar, we treat it
   // as hidden.
   if (!mInner.mVScrollbarBox || mInner.mNeverHasVerticalScrollbar)
     state.mStyles.mVertical = NS_STYLE_OVERFLOW_HIDDEN;
   if (!mInner.mHScrollbarBox || mInner.mNeverHasHorizontalScrollbar)
     state.mStyles.mHorizontal = NS_STYLE_OVERFLOW_HIDDEN;
 
   //------------ Handle Incremental Reflow -----------------
-  bool reflowContents = true; // XXX Ignored
   bool reflowHScrollbar = true;
   bool reflowVScrollbar = true;
   bool reflowScrollCorner = true;
   if (!aReflowState.ShouldReflowAllKids()) {
     #define NEEDS_REFLOW(frame_) \
       ((frame_) && NS_SUBTREE_DIRTY(frame_))
 
-    reflowContents = NEEDS_REFLOW(mInner.mScrolledFrame);
     reflowHScrollbar = NEEDS_REFLOW(mInner.mHScrollbarBox);
     reflowVScrollbar = NEEDS_REFLOW(mInner.mVScrollbarBox);
     reflowScrollCorner = NEEDS_REFLOW(mInner.mScrollCornerBox) ||
                          NEEDS_REFLOW(mInner.mResizerBox);
 
     #undef NEEDS_REFLOW
   }
 
@@ -1633,17 +1631,18 @@ CanScrollWithBlitting(nsIFrame* aFrame)
 
   for (nsIFrame* f = aFrame; f;
        f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
     if (nsSVGIntegrationUtils::UsingEffectsForFrame(f) ||
         f->IsFrameOfType(nsIFrame::eSVG)) {
       return false;
     }
     nsIScrollableFrame* sf = do_QueryFrame(f);
-    if (sf && nsLayoutUtils::HasNonZeroCorner(f->GetStyleBorder()->mBorderRadius))
+    if ((sf || f->IsFrameOfType(nsIFrame::eReplaced)) &&
+        nsLayoutUtils::HasNonZeroCorner(f->GetStyleBorder()->mBorderRadius))
       return false;
     if (nsLayoutUtils::IsPopup(f))
       break;
   }
   return true;
 }
 
 static void
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -1679,17 +1679,17 @@ nsImageFrame::List(FILE* out, PRInt32 aI
 #ifdef DEBUG_waterson
   fprintf(out, " [parent=%p]", mParent);
 #endif
   if (HasView()) {
     fprintf(out, " [view=%p]", (void*)GetView());
   }
   fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
   if (0 != mState) {
-    fprintf(out, " [state=%016llx]", mState);
+    fprintf(out, " [state=%016llx]", (unsigned long long)mState);
   }
   fprintf(out, " [content=%p]", (void*)mContent);
   fprintf(out, " [sc=%p]", static_cast<void*>(mStyleContext));
 
   // output the img src url
   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
   if (imageLoader) {
     nsCOMPtr<imgIRequest> currentRequest;
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -1796,30 +1796,27 @@ nsLineLayout::VerticalAlignFrames(PerSpa
     // sanity check (see bug 105168, non-reproducible crashes from null frame)
     NS_ASSERTION(frame, "null frame in PerFrameData - something is very very bad");
     if (!frame) {
       return;
     }
 
     // Compute the logical height of the frame
     nscoord logicalHeight;
-    nscoord topLeading;
     PerSpanData* frameSpan = pfd->mSpan;
     if (frameSpan) {
       // For span frames the logical-height and top-leading was
       // pre-computed when the span was reflowed.
       logicalHeight = frameSpan->mLogicalHeight;
-      topLeading = frameSpan->mTopLeading;
     }
     else {
       // For other elements the logical height is the same as the
       // frames height plus its margins.
       logicalHeight = pfd->mBounds.height + pfd->mMargin.top +
         pfd->mMargin.bottom;
-      topLeading = 0;
     }
 
     // Get vertical-align property
     const nsStyleCoord& verticalAlign =
       frame->GetStyleTextReset()->mVerticalAlign;
 #ifdef NOISY_VERTICAL_ALIGN
     printf("  [frame]");
     nsFrame::ListTag(stdout, frame);
@@ -2037,17 +2034,17 @@ nsLineLayout::VerticalAlignFrames(PerSpa
         }
         if (yTop < minY) minY = yTop;
         if (yBottom > maxY) maxY = yBottom;
 #ifdef NOISY_VERTICAL_ALIGN
         printf("     [frame]raw: a=%d h=%d bp=%d,%d logical: h=%d leading=%d y=%d minY=%d maxY=%d\n",
                pfd->mAscent, pfd->mBounds.height,
                pfd->mBorderPadding.top, pfd->mBorderPadding.bottom,
                logicalHeight,
-               pfd->mSpan ? topLeading : 0,
+               frameSpan ? frameSpan->mTopLeading : 0,
                pfd->mBounds.y, minY, maxY);
 #endif
       }
       if (psd != mRootSpan) {
         frame->SetRect(pfd->mBounds);
       }
     }
     pfd = pfd->mNext;
--- a/layout/generic/nsObjectFrame.cpp
+++ b/layout/generic/nsObjectFrame.cpp
@@ -1415,16 +1415,18 @@ nsObjectFrame::PrintPlugin(nsRenderingCo
   ::DisposeGWorld(gWorld);
 
   nativeDraw.EndNativeDrawing();
 #elif defined(XP_UNIX)
 
   /* XXX this just flat-out doesn't work in a thebes world --
    * RenderEPS is a no-op.  So don't bother to do any work here.
    */
+  (void)window;
+  (void)npprint;
 
 #elif defined(XP_OS2)
   void *hps = GetPSFromRC(aRenderingContext);
   if (!hps)
     return;
 
   npprint.print.embedPrint.platformPrint = hps;
   npprint.print.embedPrint.window = window;
--- a/layout/generic/nsPlaceholderFrame.cpp
+++ b/layout/generic/nsPlaceholderFrame.cpp
@@ -255,17 +255,17 @@ nsPlaceholderFrame::List(FILE* out, PRIn
 #ifdef DEBUG_waterson
   fprintf(out, " [parent=%p]", static_cast<void*>(mParent));
 #endif
   if (HasView()) {
     fprintf(out, " [view=%p]", (void*)GetView());
   }
   fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
   if (0 != mState) {
-    fprintf(out, " [state=%016llx]", mState);
+    fprintf(out, " [state=%016llx]", (unsigned long long)mState);
   }
   nsIFrame* prevInFlow = GetPrevInFlow();
   nsIFrame* nextInFlow = GetNextInFlow();
   if (nsnull != prevInFlow) {
     fprintf(out, " prev-in-flow=%p", static_cast<void*>(prevInFlow));
   }
   if (nsnull != nextInFlow) {
     fprintf(out, " next-in-flow=%p", static_cast<void*>(nextInFlow));
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -4686,20 +4686,18 @@ nsTypedSelection::StopAutoScrollTimer()
   return NS_OK; 
 }
 
 nsresult
 nsTypedSelection::DoAutoScroll(nsIFrame *aFrame, nsPoint& aPoint)
 {
   NS_PRECONDITION(aFrame, "Need a frame");
 
-  nsresult result = NS_OK;
-
   if (mAutoScrollTimer)
-    result = mAutoScrollTimer->Stop();
+    (void)mAutoScrollTimer->Stop();
 
   nsPresContext* presContext = aFrame->PresContext();
   nsRootPresContext* rootPC = presContext->GetRootPresContext();
   if (!rootPC)
     return NS_OK;
   nsIFrame* rootmostFrame = rootPC->PresShell()->FrameManager()->GetRootFrame();
   // Get the point relative to the root most frame because the scroll we are
   // about to do will change the coordinates of aFrame.
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -1750,17 +1750,16 @@ static const nsTextFrameUtils::Compressi
 gfxTextRun*
 BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
 {
   gfxSkipCharsBuilder builder;
 
   const void* textPtr = aTextBuffer;
   bool anySmallcapsStyle = false;
   bool anyTextTransformStyle = false;
-  PRInt32 endOfLastContent = 0;
   PRUint32 textFlags = nsTextFrameUtils::TEXT_NO_BREAKS;
 
   if (mCurrentRunContextInfo & nsTextFrameUtils::INCOMING_WHITESPACE) {
     textFlags |= nsTextFrameUtils::TEXT_INCOMING_WHITESPACE;
   }
   if (mCurrentRunContextInfo & nsTextFrameUtils::INCOMING_ARABICCHAR) {
     textFlags |= gfxTextRunWordCache::TEXT_INCOMING_ARABICCHAR;
   }
@@ -1869,18 +1868,16 @@ BuildTextRunsScanner::BuildTextRunForFra
             bufStart, compression, &mNextRunContextInfo, &builder, &analysisFlags);
         aTextBuffer = end;
       }
     }
     textFlags |= analysisFlags;
 
     currentTransformedTextOffset =
       (static_cast<const PRUint8*>(aTextBuffer) - static_cast<const PRUint8*>(textPtr)) >> mDoubleByteText;
-
-    endOfLastContent = contentEnd;
   }
 
   // Check for out-of-memory in gfxSkipCharsBuilder
   if (!builder.IsOK()) {
     DestroyUserData(userDataToDestroy);
     return nsnull;
   }
 
@@ -7048,17 +7045,17 @@ nsTextFrame::Reflow(nsPresContext*      
 #ifdef ACCESSIBILITY
 /**
  * Notifies accessibility about text reflow. Used by nsTextFrame::ReflowText.
  */
 class NS_STACK_CLASS ReflowTextA11yNotifier
 {
 public:
   ReflowTextA11yNotifier(nsPresContext* aPresContext, nsIContent* aContent) :
-    mPresContext(aPresContext), mContent(aContent)
+    mContent(aContent), mPresContext(aPresContext)
   {
   }
   ~ReflowTextA11yNotifier()
   {
     nsAccessibilityService* accService = nsIPresShell::AccService();
     if (accService) {
       accService->UpdateText(mPresContext->PresShell(), mContent);
     }
@@ -7942,17 +7939,17 @@ nsTextFrame::List(FILE* out, PRInt32 aIn
     fprintf(out, " prev-continuation=%p", static_cast<void*>(prevContinuation));
   }
   if (nsnull != mNextContinuation) {
     fprintf(out, " next-continuation=%p", static_cast<void*>(mNextContinuation));
   }
 
   // Output the rect and state
   fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
-  fprintf(out, " [state=%016llx]", mState);
+  fprintf(out, " [state=%016llx]", (unsigned long long)mState);
   if (IsSelected()) {
     fprintf(out, " SELECTED");
   }
   fprintf(out, " [content=%p]", static_cast<void*>(mContent));
   if (HasOverflowAreas()) {
     nsRect overflowArea = GetVisualOverflowRect();
     fprintf(out, " [vis-overflow=%d,%d,%d,%d]",
             overflowArea.x, overflowArea.y,
new file mode 100644
--- /dev/null
+++ b/layout/reftests/scrolling/iframe-border-radius-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<body onload="doTest()">
+<iframe src="data:text/html,<body style='font-size:100px; overflow:hidden'><p>Hello<p>Kitty<p>Hello<p>Kitty<p>Hello<p>Kitty<p>Hello<p>Kitty<p>Hello<p>Kitty<p>Hello<p>Kitty"
+        id="f" style="width:500px; height:500px; border-radius:100px; border:none;"></iframe>
+<script>
+var f = document.getElementById("f");
+function doTest() {
+  f.contentWindow.scrollTo(0, 80);
+}
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/scrolling/iframe-border-radius.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<body>
+<iframe src="data:text/html,<body style='font-size:100px; overflow:hidden'><p>Hello<p>Kitty<p>Hello<p>Kitty<p>Hello<p>Kitty<p>Hello<p>Kitty<p>Hello<p>Kitty<p>Hello<p>Kitty"
+        id="f" style="width:500px; height:500px; border-radius:100px; border:none;"></iframe>
+<script>
+var f = document.getElementById("f");
+var count = 0;
+function doTest() {
+  ++count;
+  f.contentWindow.scrollTo(0, count*20);
+  if (count == 4) {
+    document.documentElement.removeAttribute("class");
+  } else {
+    setTimeout(doTest, 20);
+  }
+}
+document.addEventListener("MozReftestInvalidate", doTest, false);
+</script>
+</body>
+</html>
--- a/layout/reftests/scrolling/reftest.list
+++ b/layout/reftests/scrolling/reftest.list
@@ -1,13 +1,14 @@
 HTTP == fixed-1.html fixed-1.html?ref
 HTTP == fixed-opacity-1.html fixed-opacity-1.html?ref
 HTTP == fixed-opacity-2.html fixed-opacity-2.html?ref
 HTTP == fixed-text-1.html fixed-text-1.html?ref
 HTTP == fixed-text-2.html fixed-text-2.html?ref
+== iframe-border-radius.html iframe-border-radius-ref.html
 HTTP == opacity-mixed-scrolling-1.html opacity-mixed-scrolling-1.html?ref
 random-if(cocoaWidget) HTTP == opacity-mixed-scrolling-2.html opacity-mixed-scrolling-2.html?ref # see bug 625357
 HTTP == simple-1.html simple-1.html?ref
 HTTP == text-1.html text-1.html?ref
 HTTP == transformed-1.html transformed-1.html?ref
 HTTP == transformed-1.html?up transformed-1.html?ref
 == uncovering-1.html uncovering-1-ref.html
 == uncovering-2.html uncovering-2-ref.html
--- a/layout/style/nsStyleAnimation.cpp
+++ b/layout/style/nsStyleAnimation.cpp
@@ -458,16 +458,17 @@ nsStyleAnimation::ComputeDistance(nsCSSP
             CalcValue v1 = ExtractCalcValue(triplet1->*member);
             CalcValue v2 = ExtractCalcValue(triplet2->*member);
             float difflen = v2.mLength - v1.mLength;
             float diffpct = v2.mPercent - v1.mPercent;
             diffsquared = difflen * difflen + diffpct * diffpct;
             break;
           }
           case eCSSUnit_Null:
+            diffsquared = 0;
             break;
           default:
             NS_ABORT_IF_FALSE(false, "unexpected unit");
             return false;
         }
         squareDistance += diffsquared;
       }
 
--- a/layout/tables/nsCellMap.cpp
+++ b/layout/tables/nsCellMap.cpp
@@ -2581,23 +2581,20 @@ void nsCellMap::Dump(bool aIsBorderColla
     printf("  row %d : ", rowIndex);
     PRUint32 colCount = row.Length();
     for (colIndex = 0; colIndex < colCount; colIndex++) {
       CellData* cd = row[colIndex];
       if (cd) {
         if (cd->IsOrig()) {
           printf("C%d,%d  ", rowIndex, colIndex);
         } else {
-          nsTableCellFrame* cell = nsnull;
           if (cd->IsRowSpan()) {
-            cell = GetCellFrame(rowIndex, colIndex, *cd, true);
             printf("R ");
           }
           if (cd->IsColSpan()) {
-            cell = GetCellFrame(rowIndex, colIndex, *cd, false);
             printf("C ");
           }
           if (!(cd->IsRowSpan() && cd->IsColSpan())) {
             printf("  ");
           }
           printf("  ");
         }
       } else {
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -5539,34 +5539,32 @@ nsTableFrame::CalcBCBorders()
   BCCellBorder currentBorder, adjacentBorder;
   BCCorners topCorners(damageArea.width + 1, damageArea.x);
   if (!topCorners.corners) ABORT0();
   BCCorners bottomCorners(damageArea.width + 1, damageArea.x);
   if (!bottomCorners.corners) ABORT0();
 
   BCMapCellIterator iter(this, damageArea);
   for (iter.First(info); !iter.mAtEnd; iter.Next(info)) {
-    bool bottomRowSpan = false;
     // see if lastTopBorder, lastBottomBorder need to be reset
     if (iter.IsNewRow()) {
       gotRowBorder = false;
       lastTopBorder.Reset(info.mRowIndex, info.mRowSpan);
       lastBottomBorder.Reset(info.GetCellEndRowIndex() + 1, info.mRowSpan);
     }
     else if (info.mColIndex > damageArea.x) {
       lastBottomBorder = lastBottomBorders[info.mColIndex - 1];
       if (info.mRowIndex >
           (lastBottomBorder.rowIndex - lastBottomBorder.rowSpan)) {
         // the top border's left edge butts against the middle of a rowspan
         lastTopBorder.Reset(info.mRowIndex, info.mRowSpan);
       }
       if (lastBottomBorder.rowIndex > (info.GetCellEndRowIndex() + 1)) {
         // the bottom border's left edge butts against the middle of a rowspan
         lastBottomBorder.Reset(info.GetCellEndRowIndex() + 1, info.mRowSpan);
-        bottomRowSpan = true;
       }
     }
 
     // find the dominant border considering the cell's top border and the table,
     // row group, row if the border is at the top of the table, otherwise it was
     // processed in a previous row
     if (0 == info.mRowIndex) {
       if (!tableBorderReset[NS_SIDE_TOP]) {
@@ -7053,18 +7051,19 @@ BCPaintBorderIterator::StoreColumnWidth(
 /**
  * Determine if a vertical segment owns the corder
  */
 bool
 BCPaintBorderIterator::VerticalSegmentOwnsCorner()
 {
   mozilla::css::Side cornerOwnerSide = NS_SIDE_TOP;
   bool bevel = false;
-  nscoord cornerSubWidth;
-  cornerSubWidth = (mBCData) ? mBCData->GetCorner(cornerOwnerSide, bevel) : 0;
+  if (mBCData) {
+    mBCData->GetCorner(cornerOwnerSide, bevel);
+  }
   // unitialized ownerside, bevel
   return  (NS_SIDE_TOP == cornerOwnerSide) ||
           (NS_SIDE_BOTTOM == cornerOwnerSide);
 }
 
 /**
  * Paint if necessary a horizontal segment, otherwise accumulate it
  * @param aRenderingContext - the rendering context
--- a/layout/tools/reftest/Makefile.in
+++ b/layout/tools/reftest/Makefile.in
@@ -47,16 +47,21 @@ MODULE		= reftest
 EXTRA_COMPONENTS= \
 		reftest-cmdline.js \
 		$(NULL)
 
 ifdef XPI_NAME
 NO_JS_MANIFEST = 1
 DIST_FILES = install.rdf
 
+ifeq ($(MOZ_BUILD_APP),mobile/android)
+DEFINES += -DBOOTSTRAP
+DIST_FILES += bootstrap.js
+endif
+
 # Used in install.rdf
 USE_EXTENSION_MANIFEST=1
 else
 EXTRA_COMPONENTS += reftest-cmdline.manifest
 endif
 
 include $(topsrcdir)/config/rules.mk
 
new file mode 100644
--- /dev/null
+++ b/layout/tools/reftest/bootstrap.js
@@ -0,0 +1,80 @@
+Components.utils.import("resource://gre/modules/FileUtils.jsm");        
+
+function loadIntoWindow(window) {}
+function unloadFromWindow(window) {}
+
+function setDefaultPrefs() {
+    // This code sets the preferences for extension-based reftest; for
+    // command-line based reftest they are set in function handler_handle in
+    // reftest-cmdline.js.  These two locations should stay in sync.
+    //
+    // FIXME: These should be in only one place.
+    var prefs = Components.classes["@mozilla.org/preferences-service;1"].
+                getService(Components.interfaces.nsIPrefService);
+    var branch = prefs.getDefaultBranch("");
+    branch.setBoolPref("gfx.color_management.force_srgb", true);
+    branch.setBoolPref("browser.dom.window.dump.enabled", true);
+    branch.setIntPref("ui.caretBlinkTime", -1);
+    branch.setBoolPref("dom.send_after_paint_to_content", true);
+    // no slow script dialogs
+    branch.setIntPref("dom.max_script_run_time", 0);
+    branch.setIntPref("dom.max_chrome_script_run_time", 0);
+    branch.setIntPref("hangmonitor.timeout", 0);
+}
+
+var windowListener = {
+    onOpenWindow: function(aWindow) {
+        let domWindow = aWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindowInternal || Components.interfaces.nsIDOMWindow);
+        domWindow.addEventListener("load", function() {
+            domWindow.removeEventListener("load", arguments.callee, false);
+
+            let wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService(Components.interfaces.nsIWindowMediator);
+
+            // Load into any existing windows
+            let enumerator = wm.getEnumerator("navigator:browser");
+            while (enumerator.hasMoreElements()) {
+                let win = enumerator.getNext().QueryInterface(Components.interfaces.nsIDOMWindow);
+                setDefaultPrefs();
+                Components.utils.import("chrome://reftest/content/reftest.jsm");
+                win.addEventListener("UIReady", function() {OnRefTestLoad(win);});
+                break;
+            }
+
+        }, false);
+   },
+   onCloseWindow: function(aWindow){ },
+   onWindowTitleChange: function(){ },
+};
+
+function startup(aData, aReason) {
+    let wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].
+             getService (Components.interfaces.nsIWindowMediator);
+
+    Components.manager.addBootstrappedManifestLocation(aData.installPath);
+
+    // Load into any new windows
+    wm.addListener(windowListener);
+}
+
+function shutdown(aData, aReason) {
+    // When the application is shutting down we normally don't have to clean up any UI changes
+    if (aReason == APP_SHUTDOWN)
+        return;
+
+    let wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].
+             getService(Components.interfaces.nsIWindowMediator);
+
+    // Stop watching for new windows
+    wm.removeListener(windowListener);
+
+    // Unload from any existing windows
+    let enumerator = wm.getEnumerator("navigator:browser");
+    while (enumerator.hasMoreElements()) {
+        let win = enumerator.getNext().QueryInterface(Components.interfaces.nsIDOMWindow);
+        unloadFromWindow(win);
+    }
+}
+
+function install(aData, aReason) { }
+function uninstall(aData, aReason) { }
+
--- a/layout/tools/reftest/install.rdf
+++ b/layout/tools/reftest/install.rdf
@@ -1,14 +1,18 @@
 <?xml version="1.0"?>
 
 <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
      xmlns:em="http://www.mozilla.org/2004/em-rdf#">
   <Description about="urn:mozilla:install-manifest">
     <em:id>reftest@mozilla.org</em:id>
+#ifdef BOOTSTRAP
+    <em:type>2</em:type>
+    <em:bootstrap>true</em:bootstrap>
+#endif
     <em:version>1.0</em:version>
     <em:targetApplication>
       <Description>
         <em:id>toolkit@mozilla.org</em:id>
 #expand        <em:minVersion>__MOZILLA_VERSION_U__</em:minVersion>
 #expand        <em:maxVersion>__MOZILLA_VERSION_U__</em:maxVersion>
       </Description>
     </em:targetApplication>
--- a/layout/tools/reftest/jar.mn
+++ b/layout/tools/reftest/jar.mn
@@ -1,10 +1,14 @@
 reftest.jar:
 % content reftest %content/
+  content/reftest-content.js (reftest-content.js)
+#ifdef BOOTSTRAP
+*  content/reftest.jsm (reftest.js)
+#else
 *  content/reftest.js (reftest.js)
-  content/reftest-content.js (reftest-content.js)
   content/reftest.xul (reftest.xul)
 #ifdef XPI_NAME
 %  component {32530271-8c1b-4b7d-a812-218e42c6bb23} components/reftest-cmdline.js
 %  contract @mozilla.org/commandlinehandler/general-startup;1?type=reftest {32530271-8c1b-4b7d-a812-218e42c6bb23}
 %  category command-line-handler m-reftest @mozilla.org/commandlinehandler/general-startup;1?type=reftest
 #endif
+#endif
--- a/layout/tools/reftest/reftest-cmdline.js
+++ b/layout/tools/reftest/reftest-cmdline.js
@@ -95,16 +95,22 @@ RefTestCmdLineHandler.prototype =
     /**
      * Manipulate preferences by adding to the *default* branch.  Adding
      * to the default branch means the changes we make won't get written
      * back to user preferences.
      *
      * We want to do this here rather than in reftest.js because it's
      * important to force sRGB as an output profile for color management
      * before we load a window.
+     *
+     * If you change these, please adjust them in the bootstrap.js function 
+     * setDefaultPrefs().  These are duplicated there so we can have a 
+     * restartless addon for reftest on native Android.
+     *
+     * FIXME: These should be in only one place. 
      */
     var prefs = Components.classes["@mozilla.org/preferences-service;1"].
                 getService(Components.interfaces.nsIPrefService);
     var branch = prefs.getDefaultBranch("");
     branch.setBoolPref("gfx.color_management.force_srgb", true);
     branch.setBoolPref("browser.dom.window.dump.enabled", true);
     branch.setIntPref("ui.caretBlinkTime", -1);
     branch.setBoolPref("dom.send_after_paint_to_content", true);
--- a/layout/tools/reftest/reftest.js
+++ b/layout/tools/reftest/reftest.js
@@ -31,16 +31,21 @@
  * 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 ***** */
 
+#if BOOTSTRAP
+var EXPORTED_SYMBOLS = ["OnRefTestLoad"];
+#endif
+
+
 const CC = Components.classes;
 const CI = Components.interfaces;
 const CR = Components.results;
 
 const XHTML_NS = "http://www.w3.org/1999/xhtml";
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 const NS_LOCAL_FILE_CONTRACTID = "@mozilla.org/file/local;1";
@@ -214,17 +219,17 @@ function IDForEventTarget(event)
 {
     try {
         return "'" + event.target.getAttribute('id') + "'";
     } catch (ex) {
         return "<unknown>";
     }
 }
 
-function OnRefTestLoad()
+function OnRefTestLoad(win)
 {
     gCrashDumpDir = CC[NS_DIRECTORY_SERVICE_CONTRACTID]
                     .getService(CI.nsIProperties)
                     .get("ProfD", CI.nsIFile);
     gCrashDumpDir.append("minidumps");
     
     var env = CC["@mozilla.org/process/environment;1"].
               getService(CI.nsIEnvironment);
@@ -233,29 +238,40 @@ function OnRefTestLoad()
     var prefs = Components.classes["@mozilla.org/preferences-service;1"].
                 getService(Components.interfaces.nsIPrefBranch2);
     try {
         gBrowserIsRemote = prefs.getBoolPref("browser.tabs.remote");
     } catch (e) {
         gBrowserIsRemote = false;
     }
     
-    if (gContainingWindow == null && window != null) {
-      gContainingWindow = window;
+    if (win === undefined || win == null) {
+      win = window;
+    }
+    if (gContainingWindow == null && win != null) {
+      gContainingWindow = win;
     }
 
     gBrowser = gContainingWindow.document.createElementNS(XUL_NS, "xul:browser");
     gBrowser.setAttribute("id", "browser");
     gBrowser.setAttribute("type", "content-primary");
     gBrowser.setAttribute("remote", gBrowserIsRemote ? "true" : "false");
     // Make sure the browser element is exactly 800x1000, no matter
     // what size our window is
     gBrowser.setAttribute("style", "min-width: 800px; min-height: 1000px; max-width: 800px; max-height: 1000px");
 
+#if BOOTSTRAP
+    var doc = gContainingWindow.document.getElementById('main-window');
+    while (doc.hasChildNodes()) {
+      doc.removeChild(doc.firstChild);
+    }
+    doc.appendChild(gBrowser);
+#else
     document.getElementById("reftest-window").appendChild(gBrowser);
+#endif
 
     gBrowserMessageManager = gBrowser.QueryInterface(CI.nsIFrameLoaderOwner)
                              .frameLoader.messageManager;
     // The content script waits for the initial onload, then notifies
     // us.
     RegisterMessageListenersAndLoadContentScript();
 }
 
@@ -280,17 +296,21 @@ function InitAndStartRefTests()
     try {
         logFile = prefs.getCharPref("reftest.logFile");
         if (logFile) {
             try {
                 var f = FileUtils.File(logFile);
                 var mfl = FileUtils.openFileOutputStream(f, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE);  
                 // Set to mirror to stdout as well as the file
                 gDumpLog = function (msg) {
+#if BOOTSTRAP
+                    //NOTE: on android-xul, we have a libc crash if we do a dump with %7s in the string
+#else
                     dump(msg); 
+#endif
                     mfl.write(msg, msg.length);
                 };
             }
             catch(e) {
                 // If there is a problem, just use stdout
                 gDumpLog = dump;
             }
         }
@@ -368,36 +388,77 @@ function StartHTTPServer()
             if (--tries == 0)
                 throw ex;
         }
     } while (true);
 }
 
 function StartTests()
 {
+#if BOOTSTRAP
+    /* These prefs are optional, so we don't need to spit an error to the log */
+    try {
+        var prefs = Components.classes["@mozilla.org/preferences-service;1"].
+                    getService(Components.interfaces.nsIPrefBranch2);
+    } catch(e) {
+        gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + e + "\n");
+    }
+    
+    try {
+        gNoCanvasCache = prefs.getIntPref("reftest.nocache");
+    } catch(e) { 
+        gNoCanvasCache = false;
+    }
+
+    try {
+        gRunSlowTests = prefs.getIntPref("reftest.skipslowtests");
+    } catch(e) { 
+        gRunSlowTests = false;
+    }
+
+    try {
+        uri = prefs.getCharPref("reftest.uri");
+    } catch(e) { 
+        uri = "";
+    }
+
+    if (uri == "") {
+        gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | Unable to find reftest.uri pref.  Please ensure your profile is setup properly\n");
+        DoneTests();
+    }
+#else
     try {
         // Need to read the manifest once we have the final HTTP_SERVER_PORT.
         var args = window.arguments[0].wrappedJSObject;
 
         if ("nocache" in args && args["nocache"])
             gNoCanvasCache = true;
 
         if ("skipslowtests" in args && args.skipslowtests)
             gRunSlowTests = false;
 
-        ReadTopManifest(args.uri);
+        uri = args.uri;
+    } catch (e) {
+        ++gTestResults.Exception;
+        gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + ex + "\n");
+        DoneTests();
+    }
+#endif
+
+    try {
+        ReadTopManifest(uri);
         BuildUseCounts();
 
         if (gTotalChunks > 0 && gThisChunk > 0) {
-          var testsPerChunk = gURLs.length / gTotalChunks;
-          var start = Math.round((gThisChunk-1) * testsPerChunk);
-          var end = Math.round(gThisChunk * testsPerChunk);
-          gURLs = gURLs.slice(start, end);
-          gDumpLog("REFTEST INFO | Running chunk " + gThisChunk + " out of " + gTotalChunks + " chunks.  ")
-          gDumpLog("tests " + (start+1) + "-" + end + "/" + gURLs.length + "\n");
+            var testsPerChunk = gURLs.length / gTotalChunks;
+            var start = Math.round((gThisChunk-1) * testsPerChunk);
+            var end = Math.round(gThisChunk * testsPerChunk);
+            gURLs = gURLs.slice(start, end);
+            gDumpLog("REFTEST INFO | Running chunk " + gThisChunk + " out of " + gTotalChunks + " chunks.  ")
+            gDumpLog("tests " + (start+1) + "-" + end + "/" + gURLs.length + "\n");
         }
         gTotalTests = gURLs.length;
 
         if (!gTotalTests)
             throw "No tests to run";
 
         gURICanvases = {};
         StartCurrentTest();
@@ -412,49 +473,49 @@ function StartTests()
 function OnRefTestUnload()
 {
 }
 
 // Read all available data from an input stream and return it
 // as a string.
 function getStreamContent(inputStream)
 {
-  var streamBuf = "";
-  var sis = CC["@mozilla.org/scriptableinputstream;1"].
-                createInstance(CI.nsIScriptableInputStream);
-  sis.init(inputStream);
+    var streamBuf = "";
+    var sis = CC["@mozilla.org/scriptableinputstream;1"].
+                  createInstance(CI.nsIScriptableInputStream);
+    sis.init(inputStream);
 
-  var available;
-  while ((available = sis.available()) != 0) {
-    streamBuf += sis.read(available);
-  }
-  
-  return streamBuf;
+    var available;
+    while ((available = sis.available()) != 0) {
+        streamBuf += sis.read(available);
+    }
+
+    return streamBuf;
 }
 
 // Build the sandbox for fails-if(), etc., condition evaluation.
 function BuildConditionSandbox(aURL) {
     var sandbox = new Components.utils.Sandbox(aURL.spec);
     var xr = CC[NS_XREAPPINFO_CONTRACTID].getService(CI.nsIXULRuntime);
     sandbox.isDebugBuild = gDebug.isDebugBuild;
     sandbox.xulRuntime = {widgetToolkit: xr.widgetToolkit, OS: xr.OS, __exposedProps__: { widgetToolkit: "r", OS: "r", XPCOMABI: "r", shell: "r" } };
 
     // xr.XPCOMABI throws exception for configurations without full ABI
     // support (mobile builds on ARM)
     try {
-      sandbox.xulRuntime.XPCOMABI = xr.XPCOMABI;
+        sandbox.xulRuntime.XPCOMABI = xr.XPCOMABI;
     } catch(e) {
-      sandbox.xulRuntime.XPCOMABI = "";
+        sandbox.xulRuntime.XPCOMABI = "";
     }
   
     try {
-      // nsIGfxInfo is currently only implemented on Windows
-      sandbox.d2d = (NS_GFXINFO_CONTRACTID in CC) && CC[NS_GFXINFO_CONTRACTID].getService(CI.nsIGfxInfo).D2DEnabled;
+        // nsIGfxInfo is currently only implemented on Windows
+        sandbox.d2d = (NS_GFXINFO_CONTRACTID in CC) && CC[NS_GFXINFO_CONTRACTID].getService(CI.nsIGfxInfo).D2DEnabled;
     } catch(e) {
-      sandbox.d2d = false;
+        sandbox.d2d = false;
     }
 
     sandbox.layersGPUAccelerated =
       gWindowUtils && gWindowUtils.layerManagerType != "Basic";
     sandbox.layersOpenGL =
       gWindowUtils && gWindowUtils.layerManagerType == "OpenGL";
 
     // Shortcuts for widget toolkits.
@@ -510,17 +571,17 @@ function BuildConditionSandbox(aURL) {
         },
         _prefs:      prefs,
         getBoolPref: function(p) { return this._prefs.getBoolPref(p); },
         getIntPref:  function(p) { return this._prefs.getIntPref(p); }
     }
 
     sandbox.testPluginIsOOP = function () {
         try {
-          netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+            netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
         } catch (ex) {}
 
         var prefservice = Components.classes["@mozilla.org/preferences-service;1"]
                                     .getService(CI.nsIPrefBranch);
 
         var testPluginIsOOP = false;
         if (navigator.platform.indexOf("Mac") == 0) {
             var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"]
@@ -561,17 +622,17 @@ function BuildConditionSandbox(aURL) {
     return sandbox;
 }
 
 function ReadTopManifest(aFileURL)
 {
     gURLs = new Array();
     var url = gIOService.newURI(aFileURL, null, null);
     if (!url)
-      throw "Expected a file or http URL for the manifest.";
+        throw "Expected a file or http URL for the manifest.";
     ReadManifest(url, EXPECTED_PASS);
 }
 
 // Note: If you materially change the reftest manifest parsing,
 // please keep the parser in print-manifest-dirs.py in sync.
 function ReadManifest(aURL, inherited_status)
 {
     var secMan = CC[NS_SCRIPTSECURITYMANAGER_CONTRACTID]
--- a/layout/tools/reftest/remotereftest.py
+++ b/layout/tools/reftest/remotereftest.py
@@ -106,16 +106,20 @@ class RemoteOptions(ReftestOptions):
                     help = "add webserver and port to the user.js file for remote script access and universalXPConnect")
         defaults["enablePrivilege"] = False
 
         self.add_option("--pidfile", action = "store",
                     type = "string", dest = "pidFile",
                     help = "name of the pidfile to generate")
         defaults["pidFile"] = ""
 
+        self.add_option("--bootstrap", action="store_true", dest = "bootstrap",
+                    help = "test with a bootstrap addon required for native Fennec")
+        defaults["bootstrap"] = False
+
         self.add_option("--dm_trans", action="store",
                     type = "string", dest = "dm_trans",
                     help = "the transport to use to communicate with device: [adb|sut]; default=sut")
         defaults["dm_trans"] = "sut"
 
         defaults["localLogName"] = None
 
         self.set_defaults(**defaults)
@@ -285,23 +289,23 @@ class RemoteReftest(RefTest):
         remoteUtilityPath = options.utilityPath
         localAutomation = Automation()
         localAutomation.IS_WIN32 = False
         localAutomation.IS_LINUX = False
         localAutomation.IS_MAC = False
         localAutomation.UNIXISH = False
         hostos = sys.platform
         if (hostos == 'mac' or  hostos == 'darwin'):
-          localAutomation.IS_MAC = True
+            localAutomation.IS_MAC = True
         elif (hostos == 'linux' or hostos == 'linux2'):
-          localAutomation.IS_LINUX = True
-          localAutomation.UNIXISH = True
+            localAutomation.IS_LINUX = True
+            localAutomation.UNIXISH = True
         elif (hostos == 'win32' or hostos == 'win64'):
-          localAutomation.BIN_SUFFIX = ".exe"
-          localAutomation.IS_WIN32 = True
+            localAutomation.BIN_SUFFIX = ".exe"
+            localAutomation.IS_WIN32 = True
 
         paths = [options.xrePath, localAutomation.DIST_BIN, self.automation._product, os.path.join('..', self.automation._product)]
         options.xrePath = self.findPath(paths)
         if options.xrePath == None:
             print "ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % (os.name)
             sys.exit(1)
         paths.append("bin")
         paths.append(os.path.join("..", "bin"))
@@ -323,47 +327,52 @@ class RemoteReftest(RefTest):
 
         self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT)
         options.xrePath = remoteXrePath
         options.utilityPath = remoteUtilityPath
          
     def stopWebServer(self, options):
         self.server.stop()
 
-    def createReftestProfile(self, options, profileDir):
-        RefTest.createReftestProfile(self, options, profileDir, server=options.remoteWebServer)
+    def createReftestProfile(self, options, profileDir, reftestlist):
+        RefTest.createReftestProfile(self, options, profileDir, reftestlist, server=options.remoteWebServer)
 
         # Turn off the locale picker screen
         fhandle = open(os.path.join(profileDir, "user.js"), 'a')
         fhandle.write("""
 user_pref("browser.firstrun.show.localepicker", false);
 user_pref("font.size.inflation.emPerLine", 0);
 user_pref("font.size.inflation.minTwips", 0);
-""")
+user_pref("reftest.remote", true);
+user_pref("toolkit.telemetry.prompted", true);
+user_pref("reftest.uri", "%s");
+""" % reftestlist)
 
         #workaround for jsreftests.
         if options.enablePrivilege:
-          fhandle.write("""
+            fhandle.write("""
 user_pref("capability.principal.codebase.p2.granted", "UniversalPreferencesWrite UniversalXPConnect UniversalBrowserWrite UniversalPreferencesRead UniversalBrowserRead");
 user_pref("capability.principal.codebase.p2.id", "http://%s:%s");
 """ % (options.remoteWebServer, options.httpPort))
 
         # Close the file
         fhandle.close()
 
-
         if (self._devicemanager.pushDir(profileDir, options.remoteProfile) == None):
             raise devicemanager.FileError("Failed to copy profiledir to device")
 
     def copyExtraFilesToProfile(self, options, profileDir):
         RefTest.copyExtraFilesToProfile(self, options, profileDir)
         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,
@@ -444,23 +453,27 @@ def main():
         print "ERROR: Could not find test manifest '%s'" % manifest
         sys.exit(1)
 
     # Start the webserver
     reftest.startWebServer(options)
 
     procName = options.app.split('/')[-1]
     if (dm.processExist(procName)):
-      dm.killProcess(procName)
+        dm.killProcess(procName)
 
 #an example manifest name to use on the cli
 #    manifest = "http://" + options.remoteWebServer + "/reftests/layout/reftests/reftest-sanity/reftest.list"
     try:
-      reftest.runTests(manifest, options)
+        cmdlineArgs = ["-reftest", manifest]
+        if options.bootstrap:
+            cmdlineArgs = []
+        reftest.runTests(manifest, options, cmdlineArgs)
     except:
-      print "TEST-UNEXPECTED-FAIL | | exception while running reftests"
-      reftest.stopWebServer(options)
-      sys.exit(1)
+        print "TEST-UNEXPECTED-FAIL | | exception while running reftests"
+        reftest.stopWebServer(options)
+        sys.exit(1)
 
     reftest.stopWebServer(options)
 
 if __name__ == "__main__":
     main()
+    
--- a/layout/tools/reftest/runreftest.py
+++ b/layout/tools/reftest/runreftest.py
@@ -1,9 +1,8 @@
-#
 # ***** 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/
 #
@@ -69,18 +68,23 @@ class RefTest(object):
       if os.path.exists(defaultManifestPath):
         path = defaultManifestPath
       else:
         defaultManifestPath = os.path.join(path, 'crashtests.list')
         if os.path.exists(defaultManifestPath):
           path = defaultManifestPath
     return path
 
-  def createReftestProfile(self, options, profileDir, server='localhost'):
-    "Sets up a profile for reftest."
+  def createReftestProfile(self, options, profileDir, manifest, server='localhost'):
+    """
+      Sets up a profile for reftest.
+      'manifest' is the path to the reftest.list file we want to test with.  This is used in
+      the remote subclass in remotereftest.py so we can write it to a preference for the 
+      bootstrap extension.
+    """
 
     self.automation.setupPermissionsDatabase(profileDir,
       {'allowXULXBL': [(server, True), ('<file>', True)]})
 
     # Set preferences for communication between our command line arguments
     # and the reftest harness.  Preferences that are required for reftest
     # to work should instead be set in reftest-cmdline.js .
     prefsFile = open(os.path.join(profileDir, "user.js"), "a")
@@ -136,37 +140,39 @@ class RefTest(object):
     self.leakLogFile = os.path.join(profileDir, "runreftest_leaks.log")
     browserEnv["XPCOM_MEM_BLOAT_LOG"] = self.leakLogFile
     return browserEnv
 
   def cleanup(self, profileDir):
     if profileDir:
       shutil.rmtree(profileDir, True)
 
-  def runTests(self, testPath, options):
+  def runTests(self, testPath, options, cmdlineArgs = None):
     debuggerInfo = getDebuggerInfo(self.oldcwd, options.debugger, options.debuggerArgs,
         options.debuggerInteractive);
 
     profileDir = None
     try:
+      reftestlist = self.getManifestPath(testPath)
+      if cmdlineArgs == None:
+        cmdlineArgs = ['-reftest', reftestlist]
       profileDir = mkdtemp()
       self.copyExtraFilesToProfile(options, profileDir)
-      self.createReftestProfile(options, profileDir)
+      self.createReftestProfile(options, profileDir, reftestlist)
       self.installExtensionsToProfile(options, profileDir)
 
       # 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")
-      reftestlist = self.getManifestPath(testPath)
       status = self.automation.runApp(None, browserEnv, options.app, profileDir,
-                                 ["-reftest", reftestlist],
+                                 cmdlineArgs,
                                  utilityPath = options.utilityPath,
                                  xrePath=options.xrePath,
                                  debuggerInfo=debuggerInfo,
                                  symbolsPath=options.symbolsPath,
                                  # give the JS harness 30 seconds to deal
                                  # with its own timeouts
                                  timeout=options.timeout + 30.0)
       processLeakLog(self.leakLogFile, options.leakThreshold)
--- a/layout/xul/base/src/grid/nsGridRowLeafLayout.cpp
+++ b/layout/xul/base/src/grid/nsGridRowLeafLayout.cpp
@@ -257,17 +257,17 @@ nsGridRowLeafLayout::ComputeChildSizes(n
   // see if we are in a scrollable frame. If we are then there could be scrollbars present
   // if so we need to subtract them out to make sure our columns line up.
   if (aBox) {
     bool isHorizontal = aBox->IsHorizontal();
 
     // go up the parent chain looking for scrollframes
     nscoord diff = 0;
     nsIBox* parentBox;
-    nsIGridPart* parent = GetParentGridPart(aBox, &parentBox);
+    (void)GetParentGridPart(aBox, &parentBox);
     while (parentBox) {
       nsIBox* scrollbox = nsGrid::GetScrollBox(parentBox);
       nsIScrollableFrame *scrollable = do_QueryFrame(scrollbox);
       if (scrollable) {
         // Don't call GetActualScrollbarSizes here because it's not safe
         // to call that while we're reflowing the contents of the scrollframe,
         // which we are here.
         nsMargin scrollbarSizes = scrollable->GetDesiredScrollbarSizes(&aState);
@@ -275,17 +275,17 @@ nsGridRowLeafLayout::ComputeChildSizes(n
 
         if (isHorizontal && (visible & nsIScrollableFrame::VERTICAL)) {
           diff += scrollbarSizes.left + scrollbarSizes.right;
         } else if (!isHorizontal && (visible & nsIScrollableFrame::HORIZONTAL)) {
           diff += scrollbarSizes.top + scrollbarSizes.bottom;
         }
       }
 
-      parent = GetParentGridPart(parentBox, &parentBox);
+      (void)GetParentGridPart(parentBox, &parentBox);
     }
 
     if (diff > 0) {
       aGivenSize += diff;
 
       nsSprocketLayout::ComputeChildSizes(aBox, aState, aGivenSize, aBoxSizes, aComputedBoxSizes);
 
       aGivenSize -= diff;
--- a/layout/xul/base/src/nsPopupSetFrame.cpp
+++ b/layout/xul/base/src/nsPopupSetFrame.cpp
@@ -202,17 +202,17 @@ nsPopupSetFrame::List(FILE* out, PRInt32
   if (nsnull != GetPrevContinuation()) {
     fprintf(out, " prev-continuation=%p", static_cast<void*>(GetPrevContinuation()));
   }
   if (nsnull != GetNextContinuation()) {
     fprintf(out, " next-continuation=%p", static_cast<void*>(GetNextContinuation()));
   }
   fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
   if (0 != mState) {
-    fprintf(out, " [state=%016llx]", mState);
+    fprintf(out, " [state=%016llx]", (unsigned long long)mState);
   }
   fprintf(out, " [content=%p]", static_cast<void*>(mContent));
   nsPopupSetFrame* f = const_cast<nsPopupSetFrame*>(this);
   if (f->HasOverflowAreas()) {
     nsRect overflowArea = f->GetVisualOverflowRect();
     fprintf(out, " [vis-overflow=%d,%d,%d,%d]",
             overflowArea.x, overflowArea.y,
             overflowArea.width, overflowArea.height);
--- a/layout/xul/base/src/nsXULTooltipListener.h
+++ b/layout/xul/base/src/nsXULTooltipListener.h
@@ -107,17 +107,17 @@ protected:
   static void sTooltipCallback (nsITimer* aTimer, void* aListener);
 
   // screen coordinates of the last mousemove event, stored so that the
   // tooltip can be opened at this location.
   PRInt32 mMouseScreenX, mMouseScreenY;
 
   // various constants for tooltips
   enum {
-    kTooltipMouseMoveTolerance = 7,    // 7 pixel tolerance for mousemove event
+    kTooltipMouseMoveTolerance = 7     // 7 pixel tolerance for mousemove event
   };
 
   // flag specifying if the tooltip has already been displayed by a MouseMove
   // event. The flag is reset on MouseOut so that the tooltip will display
   // the next time the mouse enters the node (bug #395668).
   bool mTooltipShownOnce;
 
 #ifdef MOZ_XUL
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -65,16 +65,19 @@ pref("browser.tabs.remote", true);
 
 pref("toolkit.screen.lock", false);
 
 // From libpref/src/init/all.js, extended to allow a slightly wider zoom range.
 pref("zoom.minPercent", 20);
 pref("zoom.maxPercent", 400);
 pref("toolkit.zoomManager.zoomValues", ".2,.3,.5,.67,.8,.9,1,1.1,1.2,1.33,1.5,1.7,2,2.4,3,4");
 
+// Mobile will use faster, less durable mode.
+pref("toolkit.storage.synchronous", 0);
+
 // Device pixel to CSS px ratio, in percent. Set to -1 to calculate based on display density.
 pref("browser.viewport.scaleRatio", -1);
 pref("browser.viewport.desktopWidth", 980);
 
 #ifndef ANDROID
 #ifndef MOZ_PLATFORM_MAEMO
 // On desktop builds, simulate an MDPI tablet by default.
 pref("layout.css.dpi", 160);
--- a/mobile/android/base/AboutHomeContent.java
+++ b/mobile/android/base/AboutHomeContent.java
@@ -216,74 +216,69 @@ public class AboutHomeContent extends Sc
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         mTopSitesGrid.setNumColumns(getNumberOfColumns());
         mTopSitesAdapter.notifyDataSetChanged();
 
         super.onConfigurationChanged(newConfig);
     }
 
-    InputStream getProfileRecommendedAddonsStream() {
-        try {
-            File profileDir = GeckoApp.mAppContext.getProfileDir();
-            if (profileDir == null)
-                return null;
-            File recommendedAddonsFile = new File(profileDir, "recommended-addons.json");
-            if (!recommendedAddonsFile.exists())
-                return null;
-            return new FileInputStream(recommendedAddonsFile);
-        } catch (FileNotFoundException fnfe) {
-            // ignore
-        }
-        return null;
-    }
-
-    InputStream getRecommendedAddonsStream(Activity activity) throws Exception{
-        InputStream is = getProfileRecommendedAddonsStream();
-        if (is != null)
-            return is;
-        File applicationPackage = new File(activity.getApplication().getPackageResourcePath());
-        ZipFile zip = null;
-        try {
-            zip = new ZipFile(applicationPackage);
-            if (zip == null)
-                return null;
-            ZipEntry fileEntry = zip.getEntry("recommended-addons.json");
-            if (fileEntry == null)
-                return null;
-            return zip.getInputStream(fileEntry);
-        } finally {
-            if (zip != null)
-                zip.close();
-        }
-    }
-
     void readRecommendedAddons(final Activity activity) {
         GeckoAppShell.getHandler().post(new Runnable() {
             public void run() {
+                byte[] buf = new byte[32768];
+                InputStream fileStream = null;
+                ZipFile zip = null;
+                StringBuffer jsonString = null;
+                File profileDir = GeckoApp.mAppContext.getProfileDir();
                 try {
-                    byte[] buf = new byte[32768];
-                    InputStream fileStream = getRecommendedAddonsStream(activity);
+                    if (profileDir != null) {
+                        try {
+                            File recommendedAddonsFile = new File(profileDir, "recommended-addons.json");
+                            if (recommendedAddonsFile.exists()) {
+                                fileStream = new FileInputStream(recommendedAddonsFile);
+                            }
+                        } catch (FileNotFoundException fnfe) {}
+                    }
+                    if (fileStream == null) {
+                        Log.i("Addons", "filestream is null");
+                        File applicationPackage = new File(activity.getApplication().getPackageResourcePath());
+                        zip = new ZipFile(applicationPackage);
+                        if (zip == null)
+                            return;
+                        ZipEntry fileEntry = zip.getEntry("recommended-addons.json");
+                        if (fileEntry == null)
+                            return;
+                        fileStream = zip.getInputStream(fileEntry);
+                    }
+
                     if (fileStream == null)
                         return;
-                    StringBuffer jsonString = new StringBuffer();
+                    jsonString = new StringBuffer();
+                    int read = 0;
+                    while ((read = fileStream.read(buf, 0, 32768)) != -1) {
+                        jsonString.append(new String(buf, 0, read));
+                    }
+                } catch (IOException ioe) {
+                    Log.i(LOGTAG, "error reading recommended addons file", ioe);
+                } finally {
                     try {
-                        int read = 0;
-                        while ((read = fileStream.read(buf, 0, 32768)) != -1) {
-                            jsonString.append(new String(buf, 0, read));
-                        }
-                    } finally {
-                        try {
+                        if (fileStream != null)
                             fileStream.close();
-                        } catch (IOException ioe) {
-                            // catch this here because we can continue even if the
-                            // close failed
-                            Log.i(LOGTAG, "error closing json file", ioe);
-                        }
+                        if (zip != null)
+                            zip.close();
+                    } catch (IOException ioe) {
+                        // catch this here because we can continue even if the
+                        // close failed
+                        Log.i(LOGTAG, "error closing json file", ioe);
                     }
+                } 
+                if (jsonString == null)
+                    return;
+                try {
                     final JSONArray array = new JSONObject(jsonString.toString()).getJSONArray("addons");
                     GeckoApp.mAppContext.mMainHandler.post(new Runnable() {
                         public void run() {
                             try {
                                 for (int i = 0; i < array.length(); i++) {
                                     JSONObject jsonobj = array.getJSONObject(i);
                                     mAddonsAdapter.add(jsonobj.getString("name"));
                                     Log.i(LOGTAG, "addon #" + i +": " + jsonobj.getString("name"));
--- a/mobile/android/base/AwesomeBar.java
+++ b/mobile/android/base/AwesomeBar.java
@@ -158,16 +158,21 @@ public class AwesomeBar extends Activity
             mText.selectAll();
         }
 
         mText.setOnKeyPreImeListener(new AwesomeBarEditText.OnKeyPreImeListener() {
             public boolean onKeyPreIme(View v, int keyCode, KeyEvent event) {
                 InputMethodManager imm =
                         (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
 
+                if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_DOWN) {
+                    submitAndFinish(mText.getText().toString());
+                    return true;
+                }
+
                 // If input method is in fullscreen mode, we want to dismiss
                 // it instead of closing awesomebar straight away.
                 if (!imm.isFullscreenMode() && keyCode == KeyEvent.KEYCODE_BACK) {
                     cancelAndFinish();
                     return true;
                 }
 
                 return false;
--- a/mobile/android/base/GeckoInputConnection.java
+++ b/mobile/android/base/GeckoInputConnection.java
@@ -372,21 +372,27 @@ public class GeckoInputConnection
         GeckoAppShell.sendEventToGecko(
             new GeckoEvent(GeckoEvent.IME_SET_SELECTION, start, before));
 
         if (count == 0) {
             GeckoAppShell.sendEventToGecko(
                 new GeckoEvent(GeckoEvent.IME_DELETE_TEXT, 0, 0));
         } else {
             GeckoAppShell.sendEventToGecko(
+                new GeckoEvent(GeckoEvent.IME_COMPOSITION_BEGIN, 0, 0));
+
+            GeckoAppShell.sendEventToGecko(
                 new GeckoEvent(0, count,
                                GeckoEvent.IME_RANGE_RAWINPUT, 0, 0, 0,
                                s.subSequence(start, start + count).toString()));
 
             GeckoAppShell.sendEventToGecko(
+                new GeckoEvent(GeckoEvent.IME_COMPOSITION_END, 0, 0));
+
+            GeckoAppShell.sendEventToGecko(
                 new GeckoEvent(GeckoEvent.IME_SET_SELECTION, start + count, 0));
         }
 
         // Block this thread until all pending events are processed
         GeckoAppShell.geckoEventSync();
     }
 
     public void afterTextChanged(Editable s)
--- a/mobile/android/base/Tab.java
+++ b/mobile/android/base/Tab.java
@@ -87,25 +87,25 @@ public class Tab {
 
         public HistoryEntry(String uri, String title) {
             mUri = uri;
             mTitle = title;
         }
     }
 
     public Tab() {
-        this(-1, "", false, -1);
+        this(-1, "", false, -1, "");
     }
 
-    public Tab(int id, String url, boolean external, int parentId) {
+    public Tab(int id, String url, boolean external, int parentId, String title) {
         mId = id;
         mUrl = url;
         mExternal = external;
         mParentId = parentId;
-        mTitle = "";
+        mTitle = title;
         mFavicon = null;
         mFaviconUrl = null;
         mSecurityMode = "unknown";
         mThumbnail = null;
         mHistory = new ArrayList<HistoryEntry>();
         mHistoryIndex = -1;
         mBookmark = false;
         mDoorHangers = new HashMap<String, DoorHanger>();
--- a/mobile/android/base/Tabs.java
+++ b/mobile/android/base/Tabs.java
@@ -71,18 +71,19 @@ public class Tabs implements GeckoEventL
     public Tab addTab(JSONObject params) throws JSONException {
         int id = params.getInt("tabID");
         if (tabs.containsKey(id))
            return tabs.get(id);
 
         String url = params.getString("uri");
         Boolean external = params.getBoolean("external");
         int parentId = params.getInt("parentId");
+        String title = params.getString("title");
 
-        Tab tab = new Tab(id, url, external, parentId);
+        Tab tab = new Tab(id, url, external, parentId, title);
         tabs.put(id, tab);
         order.add(tab);
         Log.i(LOGTAG, "Added a tab with id: " + id + ", url: " + url);
         return tab;
     }
 
     public void removeTab(int id) {
         if (tabs.containsKey(id)) {
--- a/mobile/android/base/gfx/GeckoSoftwareLayerClient.java
+++ b/mobile/android/base/gfx/GeckoSoftwareLayerClient.java
@@ -128,17 +128,16 @@ public class GeckoSoftwareLayerClient ex
     /** Attaches the root layer to the layer controller so that Gecko appears. */
     @Override
     public void setLayerController(LayerController layerController) {
         super.setLayerController(layerController);
 
         layerController.setRoot(mTileLayer);
         if (mGeckoViewport != null) {
             layerController.setViewportMetrics(mGeckoViewport);
-            layerController.notifyPanZoomControllerOfGeometryChange(false);
         }
 
         GeckoAppShell.registerGeckoEventListener("Viewport:Update", this);
         GeckoAppShell.registerGeckoEventListener("Viewport:UpdateLater", this);
     }
 
     public void beginDrawing() {
         beginTransaction(mTileLayer);
@@ -166,17 +165,17 @@ public class GeckoSoftwareLayerClient ex
                     // Don't adjust page size when zooming unless zoom levels are
                     // approximately equal.
                     if (FloatUtils.fuzzyEquals(controller.getZoomFactor(),
                             mGeckoViewport.getZoomFactor()))
                         controller.setPageSize(mGeckoViewport.getPageSize());
                 } else {
                     Log.d(LOGTAG, "Received viewport update from gecko");
                     controller.setViewportMetrics(mGeckoViewport);
-                    controller.notifyPanZoomControllerOfGeometryChange(true);
+                    controller.abortPanZoomAnimation();
                 }
             }
         } catch (JSONException e) {
             Log.e(LOGTAG, "Bad viewport description: " + viewportDescription);
             throw new RuntimeException(e);
         }
     }
 
@@ -198,16 +197,18 @@ public class GeckoSoftwareLayerClient ex
     public ViewportMetrics getGeckoViewportMetrics() {
         // Return a copy, as we modify this inside the Gecko thread
         if (mGeckoViewport != null)
             return new ViewportMetrics(mGeckoViewport);
         return null;
     }
 
     public Bitmap getBitmap() {
+        if (mBufferSize.width <= 0 || mBufferSize.height <= 0)
+            return null;
         try {
             Bitmap b = Bitmap.createBitmap(mBufferSize.width, mBufferSize.height,
                                            CairoUtils.cairoFormatTobitmapConfig(mFormat));
             b.copyPixelsFromBuffer(mBuffer.asIntBuffer());
             return b;
         } catch (OutOfMemoryError oom) {
             Log.w(LOGTAG, "Unable to create bitmap", oom);
             return null;
--- a/mobile/android/base/gfx/LayerController.java
+++ b/mobile/android/base/gfx/LayerController.java
@@ -169,64 +169,60 @@ public class LayerController {
         mViewportMetrics.setSize(size);
         Log.d(LOGTAG, "setViewportSize: " + mViewportMetrics);
         setForceRedraw();
 
         if (mLayerClient != null)
             mLayerClient.viewportSizeChanged();
 
         notifyLayerClientOfGeometryChange();
-        mPanZoomController.geometryChanged(true);
+        mPanZoomController.abortAnimation();
         mView.requestRender();
     }
 
     /** Scrolls the viewport to the given point. You must hold the monitor while calling this. */
     public void scrollTo(PointF point) {
         mViewportMetrics.setOrigin(point);
         Log.d(LOGTAG, "scrollTo: " + mViewportMetrics);
         notifyLayerClientOfGeometryChange();
-        mPanZoomController.geometryChanged(false);
         GeckoApp.mAppContext.repositionPluginViews(false);
         mView.requestRender();
     }
 
     /** Scrolls the viewport by the given offset. You must hold the monitor while calling this. */
     public void scrollBy(PointF point) {
         PointF origin = mViewportMetrics.getOrigin();
         origin.offset(point.x, point.y);
         mViewportMetrics.setOrigin(origin);
         Log.d(LOGTAG, "scrollBy: " + mViewportMetrics);
 
         notifyLayerClientOfGeometryChange();
-        mPanZoomController.geometryChanged(false);
         GeckoApp.mAppContext.repositionPluginViews(false);
         mView.requestRender();
     }
 
     /** Sets the current viewport. You must hold the monitor while calling this. */
     public void setViewport(RectF viewport) {
         mViewportMetrics.setViewport(viewport);
         Log.d(LOGTAG, "setViewport: " + mViewportMetrics);
         notifyLayerClientOfGeometryChange();
-        mPanZoomController.geometryChanged(false);
         GeckoApp.mAppContext.repositionPluginViews(false);
         mView.requestRender();
     }
 
     /** Sets the current page size. You must hold the monitor while calling this. */
     public void setPageSize(FloatSize size) {
         if (mViewportMetrics.getPageSize().fuzzyEquals(size))
             return;
 
         mViewportMetrics.setPageSize(size);
         Log.d(LOGTAG, "setPageSize: " + mViewportMetrics);
 
         // Page size is owned by the LayerClient, so no need to notify it of
         // this change.
-        mPanZoomController.geometryChanged(false);
         mView.requestRender();
     }
 
     /**
      * Sets the entire viewport metrics at once. This function does not notify the layer client or
      * the pan/zoom controller, so you will need to call notifyLayerClientOfGeometryChange() or
      * notifyPanZoomControllerOfGeometryChange() after calling this. You must hold the monitor
      * while calling this.
@@ -278,20 +274,25 @@ public class LayerController {
      * The view as well as the controller itself use this method to notify the layer client that
      * the geometry changed.
      */
     public void notifyLayerClientOfGeometryChange() {
         if (mLayerClient != null)
             mLayerClient.geometryChanged();
     }
 
-    /** Informs the pan/zoom controller that the viewport metrics changed. */
-    public void notifyPanZoomControllerOfGeometryChange(boolean abortAnimation) {
-        if (mPanZoomController != null)
-            mPanZoomController.geometryChanged(abortAnimation);
+    /** Aborts any pan/zoom animation that is currently in progress. */
+    public void abortPanZoomAnimation() {
+        if (mPanZoomController != null) {
+            mView.post(new Runnable() {
+                public void run() {
+                    mPanZoomController.abortAnimation();
+                }
+            });
+        }
     }
 
     /**
      * Returns true if this controller is fine with performing a redraw operation or false if it
      * would prefer that the action didn't take place.
      */
     public boolean getRedrawHint() {
         if (mForceRedraw) {
--- a/mobile/android/base/gfx/PlaceholderLayerClient.java
+++ b/mobile/android/base/gfx/PlaceholderLayerClient.java
@@ -148,17 +148,16 @@ public class PlaceholderLayerClient exte
 
     @Override
     public void setLayerController(LayerController layerController) {
         super.setLayerController(layerController);
 
         if (mViewportUnknown)
             mViewport.setViewport(layerController.getViewport());
         layerController.setViewportMetrics(mViewport);
-        layerController.notifyPanZoomControllerOfGeometryChange(false);
 
         BufferedCairoImage image = new BufferedCairoImage(mBuffer, mWidth, mHeight, mFormat);
         SingleTileLayer tileLayer = new SingleTileLayer(image);
 
         beginTransaction(tileLayer);
         tileLayer.setOrigin(PointUtils.round(mViewport.getDisplayportOrigin()));
         endTransaction(tileLayer);
 
--- a/mobile/android/base/ui/PanZoomController.java
+++ b/mobile/android/base/ui/PanZoomController.java
@@ -243,35 +243,34 @@ public class PanZoomController
         case MotionEvent.ACTION_DOWN:   return onTouchStart(event);
         case MotionEvent.ACTION_MOVE:   return onTouchMove(event);
         case MotionEvent.ACTION_UP:     return onTouchEnd(event);
         case MotionEvent.ACTION_CANCEL: return onTouchCancel(event);
         default:                        return false;
         }
     }
 
-    public void geometryChanged(boolean abortAnimation) {
-        if (abortAnimation) {
-            // this happens when gecko changes the viewport on us or if the device is rotated.
-            // if that's the case, abort any animation in progress and re-zoom so that the page
-            // snaps to edges. for other cases (where the user's finger(s) are down) don't do
-            // anything special.
-            switch (mState) {
-            case FLING:
-                mX.velocity = mY.velocity = 0.0f;
-                mState = PanZoomState.NOTHING;
-                // fall through
-            case ANIMATED_ZOOM:
-                // the zoom that's in progress likely makes no sense any more (such as if
-                // the screen orientation changed) so abort it and start a new one to
-                // ensure the viewport doesn't contain out-of-bounds areas
-            case NOTHING:
-                bounce();
-                break;
-            }
+    /** This function must be called from the UI thread. */
+    public void abortAnimation() {
+        // this happens when gecko changes the viewport on us or if the device is rotated.
+        // if that's the case, abort any animation in progress and re-zoom so that the page
+        // snaps to edges. for other cases (where the user's finger(s) are down) don't do
+        // anything special.
+        switch (mState) {
+        case FLING:
+            mX.velocity = mY.velocity = 0.0f;
+            mState = PanZoomState.NOTHING;
+            // fall through
+        case ANIMATED_ZOOM:
+            // the zoom that's in progress likely makes no sense any more (such as if
+            // the screen orientation changed) so abort it and start a new one to
+            // ensure the viewport doesn't contain out-of-bounds areas
+        case NOTHING:
+            bounce();
+            break;
         }
     }
 
     /*
      * Panning/scrolling
      */
 
     private boolean onTouchStart(MotionEvent event) {
@@ -613,16 +612,17 @@ public class PanZoomController
             if (mBounceFrame < EASE_OUT_ANIMATION_FRAMES.length) {
                 advanceBounce();
                 return;
             }
 
             /* Finally, if there's nothing else to do, complete the animation and go to sleep. */
             finishBounce();
             finishAnimation();
+            mState = PanZoomState.NOTHING;
         }
 
         /* Performs one frame of a bounce animation. */
         private void advanceBounce() {
             synchronized (mController) {
                 float t = EASE_OUT_ANIMATION_FRAMES[mBounceFrame];
                 ViewportMetrics newMetrics = mBounceStartMetrics.interpolate(mBounceEndMetrics, t);
                 mController.setViewportMetrics(newMetrics);
@@ -680,26 +680,27 @@ public class PanZoomController
                 return;
 
             /*
              * Perform a bounce-back animation if overscrolled, unless panning is being overridden
              * (which happens e.g. when the user is panning an iframe).
              */
             boolean overscrolledX = mX.getOverscroll() != Axis.Overscroll.NONE;
             boolean overscrolledY = mY.getOverscroll() != Axis.Overscroll.NONE;
-            if (!mOverridePanning && (overscrolledX || overscrolledY))
+            if (!mOverridePanning && (overscrolledX || overscrolledY)) {
                 bounce();
-            else
+            } else {
                 finishAnimation();
+                mState = PanZoomState.NOTHING;
+            }
         }
     }
 
     private void finishAnimation() {
         Log.d(LOGTAG, "Finishing animation at " + mController.getViewportMetrics());
-        mState = PanZoomState.NOTHING;
         stopAnimationTimer();
 
         // Force a viewport synchronisation
         mController.setForceRedraw();
         mController.notifyLayerClientOfGeometryChange();
     }
 
     private float computeElasticity(float excess, float viewportLength) {
@@ -911,17 +912,23 @@ public class PanZoomController
      */
     @Override
     public boolean onScale(ScaleGestureDetector detector) {
         Log.d(LOGTAG, "onScale in state " + mState);
 
         if (mState == PanZoomState.ANIMATED_ZOOM)
             return false;
 
-        float spanRatio = detector.getCurrentSpan() / detector.getPreviousSpan();
+        float prevSpan = detector.getPreviousSpan();
+        if (FloatUtils.fuzzyEquals(prevSpan, 0.0f)) {
+            // let's eat this one to avoid setting the new zoom to infinity (bug 711453)
+            return true;
+        }
+
+        float spanRatio = detector.getCurrentSpan() / prevSpan;
 
         /*
          * Apply edge resistance if we're zoomed out smaller than the page size by scaling the zoom
          * factor toward 1.0.
          */
         float resistance = Math.min(mX.getEdgeResistance(), mY.getEdgeResistance());
         if (spanRatio > 1.0f)
             spanRatio = 1.0f + (spanRatio - 1.0f) * resistance;
@@ -1061,17 +1068,17 @@ public class PanZoomController
             throw new RuntimeException(ex);
         }
 
         GeckoEvent e = new GeckoEvent("Gesture:DoubleTap", ret.toString());
         GeckoAppShell.sendEventToGecko(e);
         return true;
     }
 
-    public boolean animatedZoomTo(RectF zoomToRect) {
+    private boolean animatedZoomTo(RectF zoomToRect) {
         GeckoApp.mAppContext.hidePluginViews();
 
         mState = PanZoomState.ANIMATED_ZOOM;
         final float startZoom = mController.getZoomFactor();
         final PointF startPoint = mController.getOrigin();
 
         RectF viewport = mController.getViewport();
 
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -221,23 +221,29 @@ var BrowserApp = {
     Cc["@mozilla.org/satchel/form-history;1"].getService(Ci.nsIFormHistory2);
 
     let uri = "about:home";
     if ("arguments" in window && window.arguments[0])
       uri = window.arguments[0];
 
     // XXX maybe we don't do this if the launch was kicked off from external
     Services.io.offline = false;
-    let newTab = this.addTab(uri);
 
     // Broadcast a UIReady message so add-ons know we are finished with startup
     let event = document.createEvent("Events");
     event.initEvent("UIReady", true, false);
     window.dispatchEvent(event);
 
+    // restore the previous session
+    let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
+    if (ss.shouldRestore())
+      ss.restoreLastSession(true);
+    else
+      this.addTab(uri);
+
     // notify java that gecko has loaded
     sendMessageToJava({
       gecko: {
         type: "Gecko:Ready"
       }
     });
 
     let telemetryPrompted = false;
@@ -372,38 +378,50 @@ var BrowserApp = {
 
   addTab: function addTab(aURI, aParams) {
     aParams = aParams || { selected: true, flags: Ci.nsIWebNavigation.LOAD_FLAGS_NONE };
     let newTab = new Tab(aURI, aParams);
     this._tabs.push(newTab);
     if ("selected" in aParams && aParams.selected)
       newTab.active = true;
 
+    let evt = document.createEvent("UIEvents");
+    evt.initUIEvent("TabOpen", true, false, window, null);
+    newTab.browser.dispatchEvent(evt);
+
     return newTab;
   },
 
   closeTab: function closeTab(aTab) {
     if (aTab == this.selectedTab)
       this.selectedTab = null;
 
+    let evt = document.createEvent("UIEvents");
+    evt.initUIEvent("TabClose", true, false, window, null);
+    aTab.browser.dispatchEvent(evt);
+
     aTab.destroy();
     this._tabs.splice(this._tabs.indexOf(aTab), 1);
   },
 
   selectTab: function selectTab(aTab) {
     if (aTab != null) {
       this.selectedTab = aTab;
       aTab.active = true;
       let message = {
         gecko: {
           type: "Tab:Selected",
           tabID: aTab.id
         }
       };
 
+      let evt = document.createEvent("UIEvents");
+      evt.initUIEvent("TabSelect", true, false, window, null);
+      aTab.browser.dispatchEvent(evt);
+
       sendMessageToJava(message);
     }
   },
 
   quit: function quit() {
       Cu.reportError("got quit quit message");
       window.QueryInterface(Ci.nsIDOMChromeWindow).minimize();
       window.close();
@@ -1122,17 +1140,18 @@ Tab.prototype = {
 
     let message = {
       gecko: {
         type: "Tab:Added",
         tabID: this.id,
         uri: aURL,
         parentId: ("parentId" in aParams) ? aParams.parentId : -1,
         external: ("external" in aParams) ? aParams.external : false,
-        selected: ("selected" in aParams) ? aParams.selected : true
+        selected: ("selected" in aParams) ? aParams.selected : true,
+        title: aParams.title || ""
       }
     };
     sendMessageToJava(message);
 
     let flags = Ci.nsIWebProgress.NOTIFY_STATE_ALL |
                 Ci.nsIWebProgress.NOTIFY_LOCATION |
                 Ci.nsIWebProgress.NOTIFY_SECURITY;
     this.browser.addProgressListener(this, flags);
@@ -1142,34 +1161,36 @@ Tab.prototype = {
     this.browser.addEventListener("DOMLinkAdded", this, true);
     this.browser.addEventListener("DOMTitleChanged", this, true);
     this.browser.addEventListener("scroll", this, true);
     this.browser.addEventListener("PluginClickToPlay", this, true);
     this.browser.addEventListener("pagehide", this, true);
 
     Services.obs.addObserver(this, "http-on-modify-request", false);
 
-    let flags = "flags" in aParams ? aParams.flags : Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
-    let postData = ("postData" in aParams && aParams.postData) ? aParams.postData.value : null;
-    let referrerURI = "referrerURI" in aParams ? aParams.referrerURI : null;
-    let charset = "charset" in aParams ? aParams.charset : null;
-
-    try {
-      this.browser.loadURIWithFlags(aURL, flags, referrerURI, charset, postData);
-    } catch(e) {
-      let message = {
-        gecko: {
-          type: "Content:LoadError",
-          tabID: this.id,
-          uri: this.browser.currentURI.spec,
-          title: this.browser.contentTitle
-        }
-      };
-      sendMessageToJava(message);
-      dump("Handled load error: " + e)
+    if (!aParams.delayLoad) {
+      let flags = "flags" in aParams ? aParams.flags : Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
+      let postData = ("postData" in aParams && aParams.postData) ? aParams.postData.value : null;
+      let referrerURI = "referrerURI" in aParams ? aParams.referrerURI : null;
+      let charset = "charset" in aParams ? aParams.charset : null;
+
+      try {
+        this.browser.loadURIWithFlags(aURL, flags, referrerURI, charset, postData);
+      } catch(e) {
+        let message = {
+          gecko: {
+            type: "Content:LoadError",
+            tabID: this.id,
+            uri: this.browser.currentURI.spec,
+            title: this.browser.contentTitle
+          }
+        };
+        sendMessageToJava(message);
+        dump("Handled load error: " + e)
+      }
     }
   },
 
   setAgentMode: function(aMode) {
     if (this.agentMode != aMode) {
       this.agentMode = aMode;
       sendMessageToJava({
         gecko: {
@@ -1197,17 +1218,23 @@ Tab.prototype = {
 
     this.browser.removeProgressListener(this);
     this.browser.removeEventListener("DOMContentLoaded", this, true);
     this.browser.removeEventListener("DOMLinkAdded", this, true);
     this.browser.removeEventListener("DOMTitleChanged", this, true);
     this.browser.removeEventListener("scroll", this, true);
     this.browser.removeEventListener("PluginClickToPlay", this, true);
     this.browser.removeEventListener("pagehide", this, true);
+
+    // Make sure the previously selected panel remains selected. The selected panel of a deck is
+    // not stable when panels are removed.
+    let selectedPanel = BrowserApp.deck.selectedPanel;
     BrowserApp.deck.removeChild(this.vbox);
+    BrowserApp.deck.selectedPanel = selectedPanel;
+
     Services.obs.removeObserver(this, "http-on-modify-request", false);
     this.browser = null;
     this.vbox = null;
     let message = {
       gecko: {
         type: "Tab:Closed",
         tabID: this.id
       }
@@ -1452,17 +1479,17 @@ Tab.prototype = {
         }
         break;
       }
 
       case "PluginClickToPlay": {
         let plugin = aEvent.target;
         // Keep track of all the plugins on the current page
         this._pluginsToPlay.push(plugin);
-        
+
         let overlay = plugin.ownerDocument.getAnonymousElementByAttribute(plugin, "class", "mainBox");        
         if (!overlay)
           return;
 
         // If the overlay is too small, hide the overlay and act like this
         // is a hidden plugin object
         if (PluginHelper.isTooSmall(plugin, overlay)) {
           overlay.style.visibility = "hidden";
@@ -1471,19 +1498,22 @@ Tab.prototype = {
 
         // Play all the plugin objects when the user clicks on one
         PluginHelper.addPluginClickCallback(plugin, "playAllPlugins", this);
         this._pluginOverlayShowing = true;
         break;
       }
 
       case "pagehide": {
-        // Reset plugin state when we leave the page
-        this._pluginsToPlay = [];
-        this._pluginOverlayShowing = false;
+        // Check to make sure it's top-level pagehide
+        if (aEvent.target.defaultView == this.browser.contentWindow) {
+          // Reset plugin state when we leave the page
+          this._pluginsToPlay = [];
+          this._pluginOverlayShowing = false;
+        }
         break;
       }
     }
   },
 
   onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
     if (aStateFlags & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT) {
       // Filter optimization: Only really send DOCUMENT state changes to Java listener
@@ -1743,17 +1773,16 @@ Tab.prototype = {
   QueryInterface: XPCOMUtils.generateQI([
     Ci.nsIWebProgressListener,
     Ci.nsISHistoryListener,
     Ci.nsIObserver,
     Ci.nsISupportsWeakReference
   ])
 };
 
-
 var BrowserEventHandler = {
   init: function init() {
     Services.obs.addObserver(this, "Gesture:SingleTap", false);
     Services.obs.addObserver(this, "Gesture:ShowPress", false);
     Services.obs.addObserver(this, "Gesture:CancelTouch", false);
     Services.obs.addObserver(this, "Gesture:DoubleTap", false);
     Services.obs.addObserver(this, "Gesture:Scroll", false);
 
@@ -3259,17 +3288,17 @@ var PluginHelper = {
     }
   },
 
   // Mostly copied from /browser/base/content/browser.js
   addPluginClickCallback: function (plugin, callbackName /*callbackArgs...*/) {
     // XXX just doing (callback)(arg) was giving a same-origin error. bug?
     let self = this;
     let callbackArgs = Array.prototype.slice.call(arguments).slice(2);
-      plugin.addEventListener("click", function(evt) {
+    plugin.addEventListener("click", function(evt) {
       if (!evt.isTrusted)
         return;
       evt.preventDefault();
       if (callbackArgs.length == 0)
         callbackArgs = [ evt ];
       (self[callbackName]).apply(self, callbackArgs);
     }, true);
 
--- a/mobile/android/components/Makefile.in
+++ b/mobile/android/components/Makefile.in
@@ -41,29 +41,28 @@ topsrcdir  = @top_srcdir@
 srcdir     = @srcdir@
 VPATH      = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE = MobileComponents
 XPIDL_MODULE = MobileComponents
 
-# disabled (bug 696203)
-#XPIDLSRCS = \
-#        SessionStore.idl \
-#        $(NULL)
+XPIDLSRCS = \
+        SessionStore.idl \
+        $(NULL)
 
 EXTRA_PP_COMPONENTS = \
         MobileComponents.manifest \
         AboutRedirector.js \
         BrowserCLH.js \
         DirectoryProvider.js\
         HelperAppDialog.js \
         Sidebar.js \
-        $(NULL SessionStore.js is disabled - bug 696203) \
+        SessionStore.js \
         $(NULL)
 
 EXTRA_COMPONENTS = \
         AlertsService.js \
         ContentPermissionPrompt.js \
         XPIDialogService.js \
         DownloadManagerUI.js \
         PromptService.js \
--- a/mobile/android/components/MobileComponents.manifest
+++ b/mobile/android/components/MobileComponents.manifest
@@ -18,20 +18,20 @@ category xpcom-directory-providers brows
 
 # Sidebar.js
 component {22117140-9c6e-11d3-aaf1-00805f8a4905} Sidebar.js
 contract @mozilla.org/sidebar;1 {22117140-9c6e-11d3-aaf1-00805f8a4905}
 category JavaScript-global-property sidebar @mozilla.org/sidebar;1
 category JavaScript-global-property external @mozilla.org/sidebar;1
 category wakeup-request Sidebar @mozilla.org/sidebar;1,nsISidebarExternal,getService,Sidebar:AddSearchProvider
 
-# SessionStore.js - temporarily disabled (bug 696203)
-# component {8c1f07d6-cba3-4226-a315-8bd43d67d032} SessionStore.js
-# contract @mozilla.org/browser/sessionstore;1 {8c1f07d6-cba3-4226-a315-8bd43d67d032}
-# category app-startup SessionStore service,@mozilla.org/browser/sessionstore;1
+# SessionStore.js
+component {8c1f07d6-cba3-4226-a315-8bd43d67d032} SessionStore.js
+contract @mozilla.org/browser/sessionstore;1 {8c1f07d6-cba3-4226-a315-8bd43d67d032}
+category app-startup SessionStore service,@mozilla.org/browser/sessionstore;1
 
 # stylesheets
 category agent-style-sheets browser-content-stylesheet chrome://browser/skin/content.css
 category agent-style-sheets browser-cursor-stylesheet chrome://browser/content/cursor.css
 
 # ContentPermissionPrompt.js
 component {C6E8C44D-9F39-4AF7-BCC0-76E38A8310F5} ContentPermissionPrompt.js
 contract @mozilla.org/content-permission/prompt;1 {C6E8C44D-9F39-4AF7-BCC0-76E38A8310F5}
--- a/mobile/android/components/SessionStore.js
+++ b/mobile/android/components/SessionStore.js
@@ -47,16 +47,20 @@ XPCOMUtils.defineLazyServiceGetter(this,
   "@mozilla.org/xre/app-info;1", "nsICrashReporter");
 #endif
 
 XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
   Cu.import("resource://gre/modules/NetUtil.jsm");
   return NetUtil;
 });
 
+function dump(a) {
+  Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService).logStringMessage(a);
+}
+
 // -----------------------------------------------------------------------
 // Session Store
 // -----------------------------------------------------------------------
 
 const STATE_STOPPED = 0;
 const STATE_RUNNING = 1;
 const STATE_QUITTING = -1;
 
@@ -139,17 +143,17 @@ SessionStore.prototype = {
 
     this._clearCache();
   },
 
   _clearCache: function ss_clearCache() {
     // First, let's get a list of files we think should be active
     let activeFiles = [];
     this._forEachBrowserWindow(function(aWindow) {
-      let tabs = aWindow.Browser.tabs;
+      let tabs = aWindow.BrowserApp.tabs;
       for (let i = 0; i < tabs.length; i++) {
         let browser = tabs[i].browser;
         if (browser.__SS_extdata && "thumbnail" in browser.__SS_extdata)
           activeFiles.push(browser.__SS_extdata.thumbnail);
       }
     });
 
     // Now, let's find the stale files in the cache folder
@@ -277,41 +281,40 @@ SessionStore.prototype = {
         this.saveState();
         break;
     }
   },
 
   handleEvent: function ss_handleEvent(aEvent) {
     let window = aEvent.currentTarget.ownerDocument.defaultView;
     switch (aEvent.type) {
-      case "TabOpen":
+      case "TabOpen": {
+        let browser = aEvent.target;
+        this.onTabAdd(window, browser);
+        break;
+      }
       case "TabClose": {
-        let browser = aEvent.originalTarget.linkedBrowser;
-        if (aEvent.type == "TabOpen") {
-          this.onTabAdd(window, browser);
-        }
-        else {
-          this.onTabClose(window, browser);
-          this.onTabRemove(window, browser);
-        }
+        let browser = aEvent.target;
+        this.onTabClose(window, browser);
+        this.onTabRemove(window, browser);
         break;
-    }
+      }
       case "TabSelect": {
-        let browser = aEvent.originalTarget.linkedBrowser;
+        let browser = aEvent.target;
         this.onTabSelect(window, browser);
         break;
       }
+      case "pageshow": {
+        let browser = aEvent.currentTarget;
+        this.onTabLoad(window, browser, aEvent.persisted);
+        break;
+      }
     }
   },
 
-  receiveMessage: function ss_receiveMessage(aMessage) {
-    let window = aMessage.target.ownerDocument.defaultView;
-    this.onTabLoad(window, aMessage.target, aMessage);
-  },
-
   onWindowOpen: function ss_onWindowOpen(aWindow) {
     // Return if window has already been initialized
     if (aWindow && aWindow.__SSID && this._windows[aWindow.__SSID])
       return;
 
     // Ignore non-browser windows and windows opened while shutting down
     if (aWindow.document.documentElement.getAttribute("windowtype") != "navigator:browser" || this._loadState == STATE_QUITTING)
       return;
@@ -328,139 +331,143 @@ SessionStore.prototype = {
       // Nothing to restore, notify observers things are complete
       if (!this._shouldRestore) {
         this._clearCache();
         Services.obs.notifyObservers(null, "sessionstore-windows-restored", "");
       }
     }
 
     // Add tab change listeners to all already existing tabs
-    let tabs = aWindow.Browser.tabs;
+    let tabs = aWindow.BrowserApp.tabs;
     for (let i = 0; i < tabs.length; i++)
       this.onTabAdd(aWindow, tabs[i].browser, true);
 
     // Notification of tab add/remove/selection
-    let tabContainer = aWindow.document.getElementById("tabs");
-    tabContainer.addEventListener("TabOpen", this, true);
-    tabContainer.addEventListener("TabClose", this, true);
-    tabContainer.addEventListener("TabSelect", this, true);
+    let browsers = aWindow.document.getElementById("browsers");
+    browsers.addEventListener("TabOpen", this, true);
+    browsers.addEventListener("TabClose", this, true);
+    browsers.addEventListener("TabSelect", this, true);
   },
 
   onWindowClose: function ss_onWindowClose(aWindow) {
     // Ignore windows not tracked by SessionStore
     if (!aWindow.__SSID || !this._windows[aWindow.__SSID])
       return;
 
-    let tabContainer = aWindow.document.getElementById("tabs");
-    tabContainer.removeEventListener("TabOpen", this, true);
-    tabContainer.removeEventListener("TabClose", this, true);
-    tabContainer.removeEventListener("TabSelect", this, true);
+    let browsers = aWindow.document.getElementById("browsers");
+    browsers.removeEventListener("TabOpen", this, true);
+    browsers.removeEventListener("TabClose", this, true);
+    browsers.removeEventListener("TabSelect", this, true);
 
     if (this._loadState == STATE_RUNNING) {
       // Update all window data for a last time
       this._collectWindowData(aWindow);
 
       // Clear this window from the list
       delete this._windows[aWindow.__SSID];
 
       // Save the state without this window to disk
       this.saveStateDelayed();
     }
 
-    let tabs = aWindow.Browser.tabs;
+    let tabs = aWindow.BrowserApp.tabs;
     for (let i = 0; i < tabs.length; i++)
       this.onTabRemove(aWindow, tabs[i].browser, true);
 
     delete aWindow.__SSID;
   },
 
   onTabAdd: function ss_onTabAdd(aWindow, aBrowser, aNoNotification) {
-    aBrowser.messageManager.addMessageListener("pageshow", this);
-    aBrowser.messageManager.addMessageListener("Content:SessionHistory", this);
-
+    aBrowser.addEventListener("pageshow", this, true);
     if (!aNoNotification)
       this.saveStateDelayed();
     this._updateCrashReportURL(aWindow);
   },
 
   onTabRemove: function ss_onTabRemove(aWindow, aBrowser, aNoNotification) {
-    aBrowser.messageManager.removeMessageListener("pageshow", this);
-    aBrowser.messageManager.removeMessageListener("Content:SessionHistory", this);
+    aBrowser.removeEventListener("pageshow", this, true);
 
     // If this browser is being restored, skip any session save activity
     if (aBrowser.__SS_restore)
       return;
 
     delete aBrowser.__SS_data;
 
     if (!aNoNotification)
       this.saveStateDelayed();
   },
 
   onTabClose: function ss_onTabClose(aWindow, aBrowser) {
     if (this._maxTabsUndo == 0)
       return;
 
-    if (aWindow.Browser.tabs.length > 0) {
+    if (aWindow.BrowserApp.tabs.length > 0) {
       // Bundle this browser's data and extra data and save in the closedTabs
       // window property
       let data = aBrowser.__SS_data;
       data.extData = aBrowser.__SS_extdata;
 
       this._windows[aWindow.__SSID].closedTabs.unshift(data);
       let length = this._windows[aWindow.__SSID].closedTabs.length;
       if (length > this._maxTabsUndo)
         this._windows[aWindow.__SSID].closedTabs.splice(this._maxTabsUndo, length - this._maxTabsUndo);
     }
   },
 
-  onTabLoad: function ss_onTabLoad(aWindow, aBrowser, aMessage) {
+  onTabLoad: function ss_onTabLoad(aWindow, aBrowser, aPersisted) {
     // If this browser is being restored, skip any session save activity
     if (aBrowser.__SS_restore)
       return;
 
     // Ignore a transient "about:blank"
     if (!aBrowser.canGoBack && aBrowser.currentURI.spec == "about:blank")
       return;
 
-    if (aMessage.name == "Content:SessionHistory") {
+    let history = aBrowser.sessionHistory;
+
+    if (aPersisted && aBrowser.__SS_data) {
+      // Loading from the cache; just update the index
+      aBrowser.__SS_data.index = history.index + 1;
+      this.saveStateDelayed();
+    } else {
+      // Serialize the tab data
+      let entries = [];
+      for (let i = 0; i < history.count; i++) {
+        let entry = this._serializeHistoryEntry(history.getEntryAtIndex(i, false));
+        entries.push(entry);
+      }
+      let index = history.index + 1;
+      let data = { entries: entries, index: index };
+
       delete aBrowser.__SS_data;
-      this._collectTabData(aBrowser, aMessage.json);
+      this._collectTabData(aBrowser, data);
+      this.saveStateNow();
     }
 
-    // Save out the state as quickly as possible
-    if (aMessage.name == "pageshow")
-      this.saveStateNow();
-
     this._updateCrashReportURL(aWindow);
   },
 
   onTabSelect: function ss_onTabSelect(aWindow, aBrowser) {
     if (this._loadState != STATE_RUNNING)
       return;
 
-    let index = aWindow.Elements.browsers.selectedIndex;
+    let browsers = aWindow.document.getElementById("browsers");
+    let index = browsers.selectedIndex;
     this._windows[aWindow.__SSID].selected = parseInt(index) + 1; // 1-based
 
     // Restore the resurrected browser
     if (aBrowser.__SS_restore) {
       let data = aBrowser.__SS_data;
-      if (data.entries.length > 0) {
-        let json = {
-          uri: data.entries[data.index - 1].url,
-          flags: null,
-          entries: data.entries,
-          index: data.index
-        };
-        aBrowser.messageManager.sendAsyncMessage("WebNavigation:LoadURI", json);
-      }
+      if (data.entries.length > 0)
+        aBrowser.loadURI(data.entries[data.index - 1].url);
 
       delete aBrowser.__SS_restore;
     }
 
+    this.saveStateDelayed();
     this._updateCrashReportURL(aWindow);
   },
 
   saveStateDelayed: function ss_saveStateDelayed() {
     if (!this._saveTimer) {
       // Interval until the next disk operation is allowed
       let minimalDelay = this._lastSaveTime + this._interval - Date.now();
 
@@ -522,20 +529,21 @@ SessionStore.prototype = {
   _collectWindowData: function ss__collectWindowData(aWindow) {
     // Ignore windows not tracked by SessionStore
     if (!aWindow.__SSID || !this._windows[aWindow.__SSID])
       return;
 
     let winData = this._windows[aWindow.__SSID];
     winData.tabs = [];
 
-    let index = aWindow.Elements.browsers.selectedIndex;
+    let browsers = aWindow.document.getElementById("browsers");
+    let index = browsers.selectedIndex;
     winData.selected = parseInt(index) + 1; // 1-based
 
-    let tabs = aWindow.Browser.tabs;
+    let tabs = aWindow.BrowserApp.tabs;
     for (let i = 0; i < tabs.length; i++) {
       let browser = tabs[i].browser;
       if (browser.__SS_data) {
         let tabData = browser.__SS_data;
         if (browser.__SS_extdata)
           tabData.extData = browser.__SS_extdata;
         winData.tabs.push(tabData);
       }
@@ -574,41 +582,246 @@ SessionStore.prototype = {
       if (Components.isSuccessCode(rc)) {
         Services.obs.notifyObservers(null, "sessionstore-state-write-complete", "");
       }
     });
   },
 
   _updateCrashReportURL: function ss_updateCrashReportURL(aWindow) {
 #ifdef MOZ_CRASHREPORTER
+    if (!aWindow.BrowserApp.selectedBrowser)
+      return;
+
     try {
-      let currentURI = aWindow.Browser.selectedBrowser.currentURI.clone();
+      let currentURI = aWindow.BrowserApp.selectedBrowser.currentURI.clone();
       // if the current URI contains a username/password, remove it
       try {
         currentURI.userPass = "";
       }
       catch (ex) { } // ignore failures on about: URIs
 
       CrashReporter.annotateCrashReport("URL", currentURI.spec);
     }
     catch (ex) {
       // don't make noise when crashreporter is built but not enabled
       if (ex.result != Components.results.NS_ERROR_NOT_INITIALIZED)
         Components.utils.reportError("SessionStore:" + ex);
     }
 #endif
   },
 
+  _serializeHistoryEntry: function _serializeHistoryEntry(aEntry) {
+    let entry = { url: aEntry.URI.spec };
+
+    if (aEntry.title && aEntry.title != entry.url)
+      entry.title = aEntry.title;
+
+    if (!(aEntry instanceof Ci.nsISHEntry))
+      return entry;
+
+    let cacheKey = aEntry.cacheKey;
+    if (cacheKey && cacheKey instanceof Ci.nsISupportsPRUint32 && cacheKey.data != 0)
+      entry.cacheKey = cacheKey.data;
+
+    entry.ID = aEntry.ID;
+    entry.docshellID = aEntry.docshellID;
+
+    if (aEntry.referrerURI)
+      entry.referrer = aEntry.referrerURI.spec;
+
+    if (aEntry.contentType)
+      entry.contentType = aEntry.contentType;
+
+    let x = {}, y = {};
+    aEntry.getScrollPosition(x, y);
+    if (x.value != 0 || y.value != 0)
+      entry.scroll = x.value + "," + y.value;
+
+    if (aEntry.owner) {
+      try {
+        let binaryStream = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIObjectOutputStream);
+        let pipe = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
+        pipe.init(false, false, 0, 0xffffffff, null);
+        binaryStream.setOutputStream(pipe.outputStream);
+        binaryStream.writeCompoundObject(aEntry.owner, Ci.nsISupports, true);
+        binaryStream.close();
+
+        // Now we want to read the data from the pipe's input end and encode it.
+        let scriptableStream = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream);
+        scriptableStream.setInputStream(pipe.inputStream);
+        let ownerBytes = scriptableStream.readByteArray(scriptableStream.available());
+        // We can stop doing base64 encoding once our serialization into JSON
+        // is guaranteed to handle all chars in strings, including embedded
+        // nulls.
+        entry.owner_b64 = btoa(String.fromCharCode.apply(null, ownerBytes));
+      } catch (e) { dump(e); }
+    }
+
+    entry.docIdentifier = aEntry.BFCacheEntry.ID;
+
+    if (aEntry.stateData != null) {
+      entry.structuredCloneState = aEntry.stateData.getDataAsBase64();
+      entry.structuredCloneVersion = aEntry.stateData.formatVersion;
+    }
+
+    if (!(aEntry instanceof Ci.nsISHContainer))
+      return entry;
+
+    if (aEntry.childCount > 0) {
+      entry.children = [];
+      for (let i = 0; i < aEntry.childCount; i++) {
+        let child = aEntry.GetChildAt(i);
+        if (child)
+          entry.children.push(this._serializeHistoryEntry(child));
+        else // to maintain the correct frame order, insert a dummy entry
+          entry.children.push({ url: "about:blank" });
+
+        // don't try to restore framesets containing wyciwyg URLs (cf. bug 424689 and bug 450595)
+        if (/^wyciwyg:\/\//.test(entry.children[i].url)) {
+          delete entry.children;
+          break;
+        }
+      }
+    }
+
+    return entry;
+  },
+
+  _deserializeHistoryEntry: function _deserializeHistoryEntry(aEntry, aIdMap, aDocIdentMap) {
+    let shEntry = Cc["@mozilla.org/browser/session-history-entry;1"].createInstance(Ci.nsISHEntry);
+
+    shEntry.setURI(Services.io.newURI(aEntry.url, null, null));
+    shEntry.setTitle(aEntry.title || aEntry.url);
+    if (aEntry.subframe)
+      shEntry.setIsSubFrame(aEntry.subframe || false);
+    shEntry.loadType = Ci.nsIDocShellLoadInfo.loadHistory;
+    if (aEntry.contentType)
+      shEntry.contentType = aEntry.contentType;
+    if (aEntry.referrer)
+      shEntry.referrerURI = Services.io.newURI(aEntry.referrer, null, null);
+
+    if (aEntry.cacheKey) {
+      let cacheKey = Cc["@mozilla.org/supports-PRUint32;1"].createInstance(Ci.nsISupportsPRUint32);
+      cacheKey.data = aEntry.cacheKey;
+      shEntry.cacheKey = cacheKey;
+    }
+
+    if (aEntry.ID) {
+      // get a new unique ID for this frame (since the one from the last
+      // start might already be in use)
+      let id = aIdMap[aEntry.ID] || 0;
+      if (!id) {
+        for (id = Date.now(); id in aIdMap.used; id++);
+        aIdMap[aEntry.ID] = id;
+        aIdMap.used[id] = true;
+      }
+      shEntry.ID = id;
+    }
+
+    if (aEntry.docshellID)
+      shEntry.docshellID = aEntry.docshellID;
+
+    if (aEntry.structuredCloneState && aEntry.structuredCloneVersion) {
+      shEntry.stateData =
+        Cc["@mozilla.org/docshell/structured-clone-container;1"].
+        createInstance(Ci.nsIStructuredCloneContainer);
+
+      shEntry.stateData.initFromBase64(aEntry.structuredCloneState, aEntry.structuredCloneVersion);
+    }
+
+    if (aEntry.scroll) {
+      let scrollPos = aEntry.scroll.split(",");
+      scrollPos = [parseInt(scrollPos[0]) || 0, parseInt(scrollPos[1]) || 0];
+      shEntry.setScrollPosition(scrollPos[0], scrollPos[1]);
+    }
+
+    let childDocIdents = {};
+    if (aEntry.docIdentifier) {
+      // If we have a serialized document identifier, try to find an SHEntry
+      // which matches that doc identifier and adopt that SHEntry's
+      // BFCacheEntry.  If we don't find a match, insert shEntry as the match
+      // for the document identifier.
+      let matchingEntry = aDocIdentMap[aEntry.docIdentifier];
+      if (!matchingEntry) {
+        matchingEntry = {shEntry: shEntry, childDocIdents: childDocIdents};
+        aDocIdentMap[aEntry.docIdentifier] = matchingEntry;
+      } else {
+        shEntry.adoptBFCacheEntry(matchingEntry);
+        childDocIdents = matchingEntry.childDocIdents;
+      }
+    }
+
+    if (aEntry.owner_b64) {
+      let ownerInput = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
+      let binaryData = atob(aEntry.owner_b64);
+      ownerInput.setData(binaryData, binaryData.length);
+      let binaryStream = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIObjectInputStream);
+      binaryStream.setInputStream(ownerInput);
+      try { // Catch possible deserialization exceptions
+        shEntry.owner = binaryStream.readObject(true);
+      } catch (ex) { dump(ex); }
+    }
+
+    if (aEntry.children && shEntry instanceof Ci.nsISHContainer) {
+      for (let i = 0; i < aEntry.children.length; i++) {
+        if (!aEntry.children[i].url)
+          continue;
+
+        // We're getting sessionrestore.js files with a cycle in the
+        // doc-identifier graph, likely due to bug 698656.  (That is, we have
+        // an entry where doc identifier A is an ancestor of doc identifier B,
+        // and another entry where doc identifier B is an ancestor of A.)
+        //
+        // If we were to respect these doc identifiers, we'd create a cycle in
+        // the SHEntries themselves, which causes the docshell to loop forever
+        // when it looks for the root SHEntry.
+        //
+        // So as a hack to fix this, we restrict the scope of a doc identifier
+        // to be a node's siblings and cousins, and pass childDocIdents, not
+        // aDocIdents, to _deserializeHistoryEntry.  That is, we say that two
+        // SHEntries with the same doc identifier have the same document iff
+        // they have the same parent or their parents have the same document.
+
+        shEntry.AddChild(this._deserializeHistoryEntry(aEntry.children[i], aIdMap, childDocIdents), i);
+      }
+    }
+
+    return shEntry;
+  },
+
+  _restoreHistory: function _restoreHistory(aTabData, aHistory) {
+    if (aHistory.count > 0)
+      aHistory.PurgeHistory(aHistory.count);
+    aHistory.QueryInterface(Ci.nsISHistoryInternal);
+
+    // helper hashes for ensuring unique frame IDs and unique document
+    // identifiers.
+    let idMap = { used: {} };
+    let docIdentMap = {};
+
+    for (let i = 0; i < aTabData.entries.length; i++) {
+      if (!aTabData.entries[i].url)
+        continue;
+      aHistory.addEntry(this._deserializeHistoryEntry(aTabData.entries[i], idMap, docIdentMap), true);
+    }
+
+    // We need to force set the active history item and cause it to reload since
+    // we stop the load above
+    let activeIndex = (aTabData.index || aTabData.entries.length) - 1;
+    aHistory.getEntryAtIndex(activeIndex, true);
+    aHistory.QueryInterface(Ci.nsISHistory).reloadCurrentEntry();
+  },
+
   getBrowserState: function ss_getBrowserState() {
     let data = this._getCurrentState();
     return JSON.stringify(data);
   },
 
   getClosedTabCount: function ss_getClosedTabCount(aWindow) {
-    if (!aWindow || !aWindow.__SSID)
+    if (!aWindow || !aWindow.__SSID || !this._windows[aWindow.__SSID])
       return 0; // not a browser window, or not otherwise tracked by SS.
 
     return this._windows[aWindow.__SSID].closedTabs.length;
   },
 
   getClosedTabData: function ss_getClosedTabData(aWindow) {
     if (!aWindow.__SSID)
       throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
@@ -628,29 +841,24 @@ SessionStore.prototype = {
     aIndex = aIndex || 0;
     if (!(aIndex in closedTabs))
       throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
 
     // fetch the data of closed tab, while removing it from the array
     let closedTab = closedTabs.splice(aIndex, 1).shift();
 
     // create a new tab and bring to front
-    let tab = aWindow.Browser.addTab(closedTab.entries[closedTab.index - 1].url, true);
-
-    tab.browser.messageManager.sendAsyncMessage("WebNavigation:LoadURI", {
-      uri: closedTab.entries[closedTab.index - 1].url,
-      flags: null,
-      entries: closedTab.entries,
-      index: closedTab.index
-    });
+    let params = { selected: true };
+    let tab = aWindow.BrowserApp.addTab(closedTab.entries[closedTab.index - 1].url, params);
+    this._restoreHistory(closedTab, tab.browser.sessionHistory);
 
     // Put back the extra data
     tab.browser.__SS_extdata = closedTab.extData;
 
-    return tab.chromeTab;
+    return tab.browser;
   },
 
   forgetClosedTab: function ss_forgetClosedTab(aWindow, aIndex) {
     if (!aWindow.__SSID)
       throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
 
     let closedTabs = this._windows[aWindow.__SSID].closedTabs;
 
@@ -752,60 +960,33 @@ SessionStore.prototype = {
 
         let tabs = data.windows[0].tabs;
         let selected = data.windows[0].selected;
         if (selected > tabs.length) // Clamp the selected index if it's bogus
           selected = 1;
 
         for (let i=0; i<tabs.length; i++) {
           let tabData = tabs[i];
+          let isSelected = i + 1 == selected;
+          let entry = tabData.entries[tabData.index - 1];
 
           // Add a tab, but don't load the URL until we need to
-          let params = { getAttention: false, delayLoad: true };
-
-          // We must have selected tabs as soon as possible, so we let all tabs be selected
-          // until we get the real selected tab. Then we stop selecting tabs. The end result
-          // is that the right tab is selected, but we also don't get a bunch of errors
-          let bringToFront = (i + 1 <= selected) && aBringToFront;
-          let tab = window.Browser.addTab(tabData.entries[tabData.index - 1].url, bringToFront, null, params);
+          let params = { selected: isSelected, delayLoad: !isSelected, title: entry.title };
+          let tab = window.BrowserApp.addTab(entry.url, params);
 
-          // Start a real load for the selected tab
-          if (i + 1 == selected) {
-            let json = {
-              uri: tabData.entries[tabData.index - 1].url,
-              flags: null,
-              entries: tabData.entries,
-              index: tabData.index
-            };
-            tab.browser.messageManager.sendAsyncMessage("WebNavigation:LoadURI", json);
-          } else {
+          if (!isSelected) {
             // Make sure the browser has its session data for the delay reload
             tab.browser.__SS_data = tabData;
             tab.browser.__SS_restore = true;
-
-            // Restore current title
-            tab.chromeTab.updateTitle(tabData.entries[tabData.index - 1].title);
-
-            // Recreate the thumbnail if we are delay loading the tab
-            let canvas = tab.chromeTab.thumbnail;
-            canvas.setAttribute("restored", "true");
-            canvas.removeAttribute("empty");
-  
-            let image = new window.Image();
-            image.onload = function() {
-              if (canvas) {
-                canvas.getContext("2d").drawImage(image, 0, 0);
-              }
-            };
-            image.src = tabData.extData.thumbnail;
           }
 
           tab.browser.__SS_extdata = tabData.extData;
+          self._restoreHistory(tabData, tab.browser.sessionHistory);
         }
-    
+
         notifyObservers();
       });
     } catch (ex) {
       Cu.reportError("SessionStore: Could not read from sessionstore.bak file: " + ex);
       notifyObservers("fail");
     }
   }
 };
--- a/mobile/android/installer/package-manifest.in
+++ b/mobile/android/installer/package-manifest.in
@@ -603,17 +603,17 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DL
 @BINPATH@/components/DirectoryProvider.js
 @BINPATH@/components/DownloadManagerUI.js
 @BINPATH@/components/FormAutoComplete.js
 @BINPATH@/components/HelperAppDialog.js
 @BINPATH@/components/LoginManagerPrompter.js
 @BINPATH@/components/MobileComponents.manifest
 @BINPATH@/components/MobileComponents.xpt
 @BINPATH@/components/PromptService.js
-; disabled (bug 696203) @BINPATH@/components/SessionStore.js
+@BINPATH@/components/SessionStore.js
 @BINPATH@/components/Sidebar.js
 @BINPATH@/components/OpenWebapps.js
 #ifdef MOZ_SAFE_BROWSING
 @BINPATH@/components/SafeBrowsing.js
 #endif
 #ifdef MOZ_UPDATER
 @BINPATH@/components/UpdatePrompt.js
 #endif
--- a/mobile/xul/themes/core/gingerbread/browser.css
+++ b/mobile/xul/themes/core/gingerbread/browser.css
@@ -139,52 +139,54 @@ toolbarbutton.urlbar-button {
   margin: 0 !important;
   padding: 0 !important;
   border: 0 solid transparent;
   min-width: @touch_button_large@ !important;
   max-width: @touch_button_large@ !important;
   -moz-box-flex: 1;
   -moz-box-align: center;
   -moz-box-pack: center;
-  background: @color_background_inverse@ url("chrome://browser/skin/images/endcap-default-bg.png") bottom center;
+  background: @color_background_inverse@ url("chrome://browser/skin/images/endcap-default-bg.png") bottom center repeat-x;
 }
 
 .urlbar-cap-button[open="true"],
 .urlbar-cap-button:not([disabled="true"]):hover:active {
-  background: #a5aab2 url("chrome://browser/skin/images/endcap-active-bg.png") bottom center;
+  background: #ddd url("chrome://browser/skin/images/endcap-active-bg.png") top center repeat-x;
 }
 
 /* left cap button --------------------------------------------------------- */
 #identity-box {
   -moz-border-end: @border_width_tiny@ solid rgba(118,121,126,0.5) !important;
 }
 
 #identity-box[open="true"],
 #identity-box:hover:active {
   -moz-border-end: @border_width_tiny@ solid rgba(0, 0, 0, 0.2);
 }
 
 /* add special color */
 #identity-box[mode="verifiedIdentity"] {
-  background-color: #89d715;
+  background-color: #c9ea80;
   background-image: url("chrome://browser/skin/images/endcap-ev-default-bg.png");
 }
 
 #identity-box[mode="verifiedIdentity"][open="true"],
 #identity-box[mode="verifiedIdentity"]:hover:active {
+  background-color: #b9d880;
   background-image: url("chrome://browser/skin/images/endcap-ev-active-bg.png");
 }
 
 #identity-box[mode="verifiedDomain"] {
-  background-color: #6579e3;
+  background-color: #b2bcf1;
   background-image: url("chrome://browser/skin/images/endcap-ssl-default-bg.png");
 }
 
 #identity-box[mode="verifiedDomain"][open="true"],
 #identity-box[mode="verifiedDomain"]:hover:active {
+  background-color: #a7b2ef;
   background-image: url("chrome://browser/skin/images/endcap-ssl-active-bg.png");
 }
 
 #urlbar-throbber[loading] {
   list-style-image: url("chrome://browser/skin/images/throbber.png");
 }
 
 #urlbar-favicon {
--- a/netwerk/base/src/nsSocketTransport2.cpp
+++ b/netwerk/base/src/nsSocketTransport2.cpp
@@ -299,16 +299,26 @@ nsSocketInputStream::Available(PRUint32 
             return NS_OK;
     }
 
     // cannot hold lock while calling NSPR.  (worried about the fact that PSM
     // synchronously proxies notifications over to the UI thread, which could
     // mistakenly try to re-enter this code.)
     PRInt32 n = PR_Available(fd);
 
+    // PSM does not implement PR_Available() so do a best approximation of it
+    // with MSG_PEEK
+    if ((n == -1) && (PR_GetError() == PR_NOT_IMPLEMENTED_ERROR)) {
+        char c;
+
+        n = PR_Recv(fd, &c, 1, PR_MSG_PEEK, 0);
+        SOCKET_LOG(("nsSocketInputStream::Available [this=%x] "
+                    "using PEEK backup n=%d]\n", this, n));
+    }
+
     nsresult rv;
     {
         MutexAutoLock lock(mTransport->mLock);
 
         mTransport->ReleaseFD_Locked(fd);
 
         if (n >= 0)
             *avail = n;
--- a/netwerk/protocol/http/nsHttpConnection.cpp
+++ b/netwerk/protocol/http/nsHttpConnection.cpp
@@ -453,21 +453,20 @@ nsHttpConnection::CanReuse()
     
     canReuse = canReuse &&
         (NowInSeconds() - mLastReadTime < mIdleTimeout) &&
         IsAlive();
 
     // An idle persistent connection should not have data waiting to be read
     // before a request is sent. Data here is likely a 408 timeout response
     // which we would deal with later on through the restart logic, but that
-    // path is more expensive than just closing the socket now. SSL check can
-    // be removed with fixing of 631801
+    // path is more expensive than just closing the socket now.
 
     PRUint32 dataSize;
-    if (canReuse && mSocketIn && !mConnInfo->UsingSSL() && !mUsingSpdy &&
+    if (canReuse && mSocketIn && !mUsingSpdy &&
         NS_SUCCEEDED(mSocketIn->Available(&dataSize)) && dataSize) {
         LOG(("nsHttpConnection::CanReuse %p %s"
              "Socket not reusable because read data pending (%d) on it.\n",
              this, mConnInfo->Host(), dataSize));
         canReuse = false;
     }
     return canReuse;
 }
--- a/security/manager/ssl/src/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/src/nsNSSIOLayer.cpp
@@ -2244,25 +2244,39 @@ static PRStatus PR_CALLBACK PSMConnectco
   nsNSSShutDownPreventionLock locker;
   if (!getSocketInfoIfRunning(fd, locker)) {
     return PR_FAILURE;
   }
 
   return fd->lower->methods->connectcontinue(fd, out_flags);
 }
 
+static PRIntn PSMAvailable(void)
+{
+  // This is called through PR_Available(), but is not implemented in PSM
+  PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+  return -1;
+}
+
+static PRInt64 PSMAvailable64(void)
+{
+  // This is called through PR_Available(), but is not implemented in PSM
+  PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+  return -1;
+}
+
 nsresult nsSSLIOLayerHelpers::Init()
 {
   if (!nsSSLIOLayerInitialized) {
     nsSSLIOLayerInitialized = true;
     nsSSLIOLayerIdentity = PR_GetUniqueIdentity("NSS layer");
     nsSSLIOLayerMethods  = *PR_GetDefaultIOMethods();
 
-    nsSSLIOLayerMethods.available = (PRAvailableFN)_PSM_InvalidInt;
-    nsSSLIOLayerMethods.available64 = (PRAvailable64FN)_PSM_InvalidInt64;
+    nsSSLIOLayerMethods.available = (PRAvailableFN)PSMAvailable;
+    nsSSLIOLayerMethods.available64 = (PRAvailable64FN)PSMAvailable64;
     nsSSLIOLayerMethods.fsync = (PRFsyncFN)_PSM_InvalidStatus;
     nsSSLIOLayerMethods.seek = (PRSeekFN)_PSM_InvalidInt;
     nsSSLIOLayerMethods.seek64 = (PRSeek64FN)_PSM_InvalidInt64;
     nsSSLIOLayerMethods.fileInfo = (PRFileInfoFN)_PSM_InvalidStatus;
     nsSSLIOLayerMethods.fileInfo64 = (PRFileInfo64FN)_PSM_InvalidStatus;
     nsSSLIOLayerMethods.writev = (PRWritevFN)_PSM_InvalidInt;
     nsSSLIOLayerMethods.accept = (PRAcceptFN)_PSM_InvalidDesc;
     nsSSLIOLayerMethods.bind = (PRBindFN)_PSM_InvalidStatus;
--- a/toolkit/components/passwordmgr/storage-mozStorage.js
+++ b/toolkit/components/passwordmgr/storage-mozStorage.js
@@ -218,17 +218,17 @@ LoginManagerStorage_mozStorage.prototype
 
     /*
      * init
      *
      * Initialize this storage component; import from legacy files, if
      * necessary. Most of the work is done in _deferredInit.
      */
     init : function () {
-        this._dbStmts = [];
+        this._dbStmts = {};
 
         // Connect to the correct preferences branch.
         this._prefBranch = Services.prefs.getBranch("signon.");
         this._debug = this._prefBranch.getBoolPref("debug");
 
         let isFirstRun;
         try {
             // If initWithFile is calling us, _signonsFile may already be set.
@@ -1294,19 +1294,29 @@ LoginManagerStorage_mozStorage.prototype
                 this._dbMigrate(version);
             }
         } catch (e if e.result == Cr.NS_ERROR_FILE_CORRUPTED) {
             // Database is corrupted, so we backup the database, then throw
             // causing initialization to fail and a new db to be created next use
             this._dbCleanup(true);
             throw e;
         }
+
+        Services.obs.addObserver(this, "profile-before-change", false);
         return isFirstRun;
     },
 
+    observe: function (subject, topic, data) {
+        switch (topic) {
+            case "profile-before-change":
+                Services.obs.removeObserver(this, "profile-before-change");
+                this._dbClose();
+            break;
+        }
+    },
 
     _dbCreate: function () {
         this.log("Creating Database");
         this._dbCreateSchema();
         this._dbConnection.schemaVersion = DB_VERSION;
     },
 
 
@@ -1612,39 +1622,49 @@ LoginManagerStorage_mozStorage.prototype
             // (no need to execute statement, if it compiled we're good)
             stmt.finalize();
             return true;
         } catch (e) {
             return false;
         }
     },
 
+    _dbClose : function () {
+        this.log("Closing the DB connection.");
+        // Finalize all statements to free memory, avoid errors later
+        for each (let stmt in this._dbStmts) {
+            stmt.finalize();
+        }
+        this._dbStmts = {};
+
+        if (this._dbConnection !== null) {
+            try {
+                this._dbConnection.close();
+            } catch (e) {
+                Components.utils.reportError(e);
+            }
+        }
+        this._dbConnection = null;
+    },
 
     /*
      * _dbCleanup
      *
      * Called when database creation fails. Finalizes database statements,
      * closes the database connection, deletes the database file.
      */
     _dbCleanup : function (backup) {
         this.log("Cleaning up DB file - close & remove & backup=" + backup)
 
         // Create backup file
         if (backup) {
             let backupFile = this._signonsFile.leafName + ".corrupt";
             this._storageService.backupDatabaseFile(this._signonsFile, backupFile);
         }
 
-        // Finalize all statements to free memory, avoid errors later
-        for each (let stmt in this._dbStmts)
-            stmt.finalize();
-        this._dbStmts = [];
-
-        // Close the connection, ignore 'already closed' error
-        try { this._dbConnection.close() } catch(e) {}
-        this._dbConnection = null;
+        this._dbClose();
         this._signonsFile.remove(false);
     }
 
 }; // end of nsLoginManagerStorage_mozStorage implementation
 
 let component = [LoginManagerStorage_mozStorage];
 var NSGetFactory = XPCOMUtils.generateNSGetFactory(component);
--- a/toolkit/library/Makefile.in
+++ b/toolkit/library/Makefile.in
@@ -419,16 +419,17 @@ endif
 ifeq (android,$(MOZ_WIDGET_TOOLKIT))
 OS_LIBS += -lGLESv2
 endif
 
 ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
 OS_LIBS += \
   -lui \
   -lmedia \
+  -lhardware_legacy \
   $(NULL)
 endif
 
 EXTRA_DEPS += \
   $(topsrcdir)/intl/unicharutil/util/objs.mk \
   $(topsrcdir)/rdf/util/src/objs.mk \
   $(NULL)
 
--- a/xpcom/base/nscore.h
+++ b/xpcom/base/nscore.h
@@ -61,28 +61,16 @@
  * This is for functions that are like malloc_usable_size but also take a
  * computed size as a fallback.  Such functions are used for measuring the size
  * of data structures.
  */
 typedef size_t(*nsMallocSizeOfFun)(const void *p, size_t computedSize);
 
 /* Core XPCOM declarations. */
 
-/**
- * Macros defining the target platform...
- */
-#ifdef _WIN32
-#define NS_WIN32 1
-
-#elif defined(__unix)
-#define NS_UNIX 1
-
-#elif defined(XP_OS2)
-#define NS_OS2 1
-#endif
 /*----------------------------------------------------------------------*/
 /* Import/export defines */
 
 /**
  * Using the visibility("hidden") attribute allows the compiler to use
  * PC-relative addressing to call this function.  If a function does not
  * access any global data, and does not call any methods which are not either
  * file-local or hidden, then on ELF systems we avoid loading the address of
@@ -166,17 +154,17 @@ typedef size_t(*nsMallocSizeOfFun)(const
 #elif defined(XP_WIN) && !defined(_WIN64)
 #define NS_FASTCALL __fastcall
 #define NS_CONSTRUCTOR_FASTCALL
 #else
 #define NS_FASTCALL
 #define NS_CONSTRUCTOR_FASTCALL
 #endif
 
-#ifdef NS_WIN32
+#ifdef XP_WIN
 
 #define NS_IMPORT __declspec(dllimport)
 #define NS_IMPORT_(type) __declspec(dllimport) type __stdcall
 #define NS_EXPORT __declspec(dllexport)
 #define NS_EXPORT_(type) __declspec(dllexport) type __stdcall
 #define NS_IMETHOD_(type) virtual type __stdcall
 #define NS_IMETHODIMP_(type) type __stdcall
 #define NS_METHOD_(type) type __stdcall
@@ -390,17 +378,17 @@ typedef PRUint32 nsrefcnt;
 #endif
 
 #ifndef __PRUNICHAR__
 #define __PRUNICHAR__
   /* For now, don't use wchar_t on Unix because it breaks the Netscape
    * commercial build.  When this is fixed there will be no need for the
    * |reinterpret_cast| in nsLiteralString.h either.
    */
-  #if defined(HAVE_CPP_2BYTE_WCHAR_T) && defined(NS_WIN32)
+  #if defined(HAVE_CPP_2BYTE_WCHAR_T) && defined(XP_WIN)
     typedef wchar_t PRUnichar;
   #else
     typedef PRUint16 PRUnichar;
   #endif
 #endif
 
 /*
  * Use these macros to do 64bit safe pointer conversions.
--- a/xpcom/io/nsUnicharInputStream.cpp
+++ b/xpcom/io/nsUnicharInputStream.cpp
@@ -40,17 +40,17 @@
 #include "nsIByteBuffer.h"
 #include "nsIUnicharBuffer.h"
 #include "nsIServiceManager.h"
 #include "nsString.h"
 #include "nsAutoPtr.h"
 #include "nsCRT.h"
 #include "nsUTF8Utils.h"
 #include <fcntl.h>
-#if defined(NS_WIN32)
+#if defined(XP_WIN)
 #include <io.h>
 #else
 #include <unistd.h>
 #endif
 
 #define STRING_BUFFER_SIZE 8192
 
 class StringUnicharInputStream : public nsIUnicharInputStream {