Merge last PGO-green changeset of mozilla-inbound to mozilla-central
authorEd Morley <bmo@edmorley.co.uk>
Mon, 20 Feb 2012 12:08:28 +0000
changeset 88710 b8e7474374d533d84d5dbac3e9afa426b93ac945
parent 88673 561771f018817fe409df25af244a45cb5e81a32d (current diff)
parent 88709 766fdf473acd96b76ca7c7669a0672df9cf1633b (diff)
child 88711 64d8bba7047f004dc6acbf4a7025fd04e6b71b88
child 88740 81c166bac966d0b225b78220264cbef5256266c5
push id975
push userffxbld
push dateTue, 13 Mar 2012 21:39:16 +0000
treeherdermozilla-aurora@99faebf9dc36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone13.0a1
Merge last PGO-green changeset of mozilla-inbound to mozilla-central
--- a/accessible/src/base/TextUpdater.cpp
+++ b/accessible/src/base/TextUpdater.cpp
@@ -89,18 +89,18 @@ TextUpdater::DoUpdate(const nsAString& a
 
   // Trim coinciding substrings from the end.
   PRUint32 skipEnd = 0;
   while (minLen - skipEnd > aSkipStart &&
          aNewText[newLen - skipEnd - 1] == aOldText[oldLen - skipEnd - 1]) {
     skipEnd++;
   }
 
-  PRInt32 strLen1 = oldLen - aSkipStart - skipEnd;
-  PRInt32 strLen2 = newLen - aSkipStart - skipEnd;
+  PRUint32 strLen1 = oldLen - aSkipStart - skipEnd;
+  PRUint32 strLen2 = newLen - aSkipStart - skipEnd;
 
   const nsAString& str1 = Substring(aOldText, aSkipStart, strLen1);
   const nsAString& str2 = Substring(aNewText, aSkipStart, strLen2);
 
   // Increase offset of the text leaf on skipped characters amount.
   mTextOffset += aSkipStart;
 
   // It could be single insertion or removal or the case of long strings. Do not
@@ -182,17 +182,17 @@ TextUpdater::ComputeTextChangeEvents(con
   PRInt32 colIdx = aStr1.Length(), rowIdx = aStr2.Length();
 
   // Point at which strings last matched.
   PRInt32 colEnd = colIdx;
   PRInt32 rowEnd = rowIdx;
 
   PRInt32 colLen = colEnd + 1;
   PRUint32* row = aEntries + rowIdx * colLen;
-  PRInt32 dist = row[colIdx]; // current Levenshtein distance
+  PRUint32 dist = row[colIdx]; // current Levenshtein distance
   while (rowIdx && colIdx) { // stop when we can't move diagonally
     if (aStr1[colIdx - 1] == aStr2[rowIdx - 1]) { // match
       if (rowIdx < rowEnd) { // deal with any pending insertion
         FireInsertEvent(Substring(aStr2, rowIdx, rowEnd - rowIdx),
                         rowIdx, aEvents);
       }
       if (colIdx < colEnd) { // deal with any pending deletion
         FireDeleteEvent(Substring(aStr1, colIdx, colEnd - colIdx),
--- a/accessible/src/html/nsHTMLTableAccessible.cpp
+++ b/accessible/src/html/nsHTMLTableAccessible.cpp
@@ -1516,40 +1516,27 @@ nsHTMLTableAccessible::IsProbablyForLayo
   }
 
   // Check for many rows
   const PRInt32 kMaxLayoutRows = 20;
   if (rows > kMaxLayoutRows) { // A ton of rows, this is probably for data
     RETURN_LAYOUT_ANSWER(false, ">= kMaxLayoutRows (20) and non-bordered");
   }
 
-  // Check for very wide table
-  nsAutoString styledWidth;
-  GetComputedStyleValue(EmptyString(), NS_LITERAL_STRING("width"), styledWidth);
-  if (styledWidth.EqualsLiteral("100%")) {
-    RETURN_LAYOUT_ANSWER(true, "<=4 columns and 100% width");
-  }
-  if (styledWidth.Find(NS_LITERAL_STRING("px"))) { // Hardcoded in pixels
-    nsIFrame *tableFrame = GetFrame();
-    NS_ENSURE_TRUE(tableFrame , NS_ERROR_FAILURE);
-    nsSize tableSize  = tableFrame->GetSize();
-
-    nsDocAccessible* docAccessible = Document();
-    NS_ENSURE_TRUE(docAccessible, NS_ERROR_FAILURE);
-    nsIFrame *docFrame = docAccessible->GetFrame();
-    NS_ENSURE_TRUE(docFrame , NS_ERROR_FAILURE);
-
-    nsSize docSize = docFrame->GetSize();
-    if (docSize.width > 0) {
-      PRInt32 percentageOfDocWidth = (100 * tableSize.width) / docSize.width;
-      if (percentageOfDocWidth > 95) {
-        // 3-4 columns, no borders, not a lot of rows, and 95% of the doc's width
-        // Probably for layout
-        RETURN_LAYOUT_ANSWER(true, "<=4 columns, width hardcoded in pixels and 95% of document width");
-      }
+  // Check for very wide table.
+  nsIFrame* documentFrame = Document()->GetFrame();
+  nsSize documentSize = documentFrame->GetSize();
+  if (documentSize.width > 0) {
+    nsSize tableSize = GetFrame()->GetSize();
+    PRInt32 percentageOfDocWidth = (100 * tableSize.width) / documentSize.width;
+    if (percentageOfDocWidth > 95) {
+      // 3-4 columns, no borders, not a lot of rows, and 95% of the doc's width
+      // Probably for layout
+      RETURN_LAYOUT_ANSWER(true,
+                           "<= 4 columns, table width is 95% of document width");
     }
   }
 
   // Two column rules
   if (rows * columns <= 10) {
     RETURN_LAYOUT_ANSWER(true, "2-4 columns, 10 cells or less, non-bordered");
   }
 
--- a/browser/base/content/test/browser_homeDrop.js
+++ b/browser/base/content/test/browser_homeDrop.js
@@ -21,16 +21,17 @@ function test() {
 
   let dialogListener = new WindowListener("chrome://global/content/commonDialog.xul", function (domwindow) {
     ok(true, "dialog appeared in response to home button drop");
     domwindow.document.documentElement.cancelDialog();
     Services.wm.removeListener(dialogListener);
 
     // Now trigger the invalid URI test
     executeSoon(function () {
+      info("Dialog closed? " + domwindow.closed + "\n");
       let consoleListener = {
         observe: function (m) {
           info("m: " + m + "\n");
           info("m.message: " + m.message + "\n");
           if (m.message.indexOf("NS_ERROR_DOM_BAD_URI") > -1) {
             ok(true, "drop was blocked");
             executeSoon(finish);
           }
@@ -39,16 +40,24 @@ function test() {
       Services.console.registerListener(consoleListener);
       registerCleanupFunction(function () {
         Services.console.unregisterListener(consoleListener);
       });
 
       // The drop handler throws an exception when dragging URIs that inherit
       // principal, e.g. javascript:
       expectUncaughtException();
+      let originalHandler = homeButtonObserver.onDrop;
+      homeButtonObserver.onDrop = function (aEvent) {
+        info("homeButtonObserver.onDrop called");
+        originalHandler(aEvent);
+      };
+      registerCleanupFunction(function () {
+        homeButtonObserver.onDrop = originalHandler;
+      });
       chromeUtils.synthesizeDrop(homeButton, homeButton, [[{type: "text/plain", data: "javascript:8888"}]], "copy", window, EventUtils);
     })
   });
 
   Services.wm.addListener(dialogListener);
 
   chromeUtils.synthesizeDrop(homeButton, homeButton, [[{type: "text/plain", data: "http://mochi.test:8888/"}]], "copy", window, EventUtils);
 }
--- a/browser/themes/winstripe/browser-aero.css
+++ b/browser/themes/winstripe/browser-aero.css
@@ -176,19 +176,19 @@
   #main-window[sizemode=normal][tabsontop=false] #PersonalToolbar:not(:-moz-lwtheme) {
     border-top-left-radius: 3.5px;
     border-top-right-radius: 3.5px;
   }
 
   /* Toolbar shadow behind tabs */
   /* This code is only needed for restored windows (i.e. sizemode=normal)
      because of the border radius on the toolbar below the tab bar. */
-  #main-window[sizemode=normal][tabsontop=true] #nav-bar:not(:-moz-lwtheme),
-  #main-window[sizemode=normal][tabsontop=true] > #nav-bar[collapsed=true]:not([customizing]) + toolbar:not(:-moz-lwtheme),
-  #main-window[sizemode=normal][tabsontop=true] > #nav-bar[collapsed=true]:not([customizing]) + #customToolbars + #PersonalToolbar:not(:-moz-lwtheme),
+  #main-window[sizemode=normal] #navigator-toolbox[tabsontop=true] > #nav-bar:not(:-moz-lwtheme),
+  #main-window[sizemode=normal] #navigator-toolbox[tabsontop=true] > #nav-bar[collapsed=true]:not([customizing]) + toolbar:not(:-moz-lwtheme),
+  #main-window[sizemode=normal] #navigator-toolbox[tabsontop=true] > #nav-bar[collapsed=true]:not([customizing]) + #customToolbars + #PersonalToolbar:not(:-moz-lwtheme),
   #main-window[sizemode=normal][tabsontop=true][disablechrome] #navigator-toolbox:not(:-moz-lwtheme)::after {
     border-top: 1px solid @toolbarShadowColor@;
     border-top-left-radius: 3.5px;
     border-top-right-radius: 3.5px;
     background-clip: padding-box;
   }
   #main-window[sizemode=normal] #TabsToolbar[tabsontop=true]:not(:-moz-lwtheme) {
     margin-bottom: -1px;
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -2478,21 +2478,20 @@ nsScriptSecurityManager::doGetObjectPrin
 
         jsClass = js::GetObjectClass(aObj);
     } while (1);
 
 #ifdef DEBUG
     if (aAllowShortCircuit) {
         nsIPrincipal *principal = doGetObjectPrincipal(origObj, false);
 
-        // Location is always wrapped (even for same-compartment), so we can
-        // loosen the check to same-origin instead of same-principal.
-        NS_ASSERTION(strcmp(jsClass->name, "Location") == 0 ?
-                     NS_SUCCEEDED(CheckSameOriginPrincipal(result, principal)) :
-                     result == principal,
+        // Because of inner window reuse, we can have objects with one principal
+        // living in a scope with a different (but same-origin) principal. So
+        // just check same-origin here.
+        NS_ASSERTION(NS_SUCCEEDED(CheckSameOriginPrincipal(result, principal)),
                      "Principal mismatch.  Not good");
     }
 #endif
 
     return result;
 }
 
 nsresult
--- a/client.py
+++ b/client.py
@@ -1,15 +1,16 @@
 #!/usr/bin/python
 
 NSPR_DIRS = (('nsprpub', 'mozilla/nsprpub'),)
 NSS_DIRS  = (('dbm', 'mozilla/dbm'),
              ('security/nss', 'mozilla/security/nss'),
              ('security/coreconf', 'mozilla/security/coreconf'),
              ('security/dbm', 'mozilla/security/dbm'))
+NSSCKBI_DIRS = (('security/nss/lib/ckfw/builtins', 'mozilla/security/nss/lib/ckfw/builtins'),)
 LIBFFI_DIRS = (('js/ctypes/libffi', 'libffi'),)
 
 CVSROOT_MOZILLA = ':pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot'
 CVSROOT_LIBFFI = ':pserver:anoncvs@sources.redhat.com:/cvs/libffi'
 
 import os
 import sys
 import datetime
@@ -86,16 +87,23 @@ elif action in ('update_nspr'):
     do_cvs_export(NSPR_DIRS, tag, options.cvsroot, options.cvs)
     print >>file("nsprpub/TAG-INFO", "w"), tag
 elif action in ('update_nss'):
     tag, = args[1:]
     if not options.cvsroot:
         options.cvsroot = os.environ.get('CVSROOT', CVSROOT_MOZILLA)
     do_cvs_export(NSS_DIRS, tag, options.cvsroot, options.cvs)
     print >>file("security/nss/TAG-INFO", "w"), tag
+    print >>file("security/nss/TAG-INFO-CKBI", "w"), tag
+elif action in ('update_nssckbi'):
+    tag, = args[1:]
+    if not options.cvsroot:
+        options.cvsroot = os.environ.get('CVSROOT', CVSROOT_MOZILLA)
+    do_cvs_export(NSSCKBI_DIRS, tag, options.cvsroot, options.cvs)
+    print >>file("security/nss/TAG-INFO-CKBI", "w"), tag
 elif action in ('update_libffi'):
     tag, = args[1:]
     if not options.cvsroot:
         options.cvsroot = CVSROOT_LIBFFI
     do_cvs_export(LIBFFI_DIRS, tag, options.cvsroot, options.cvs)
 else:
     o.print_help()
     sys.exit(2)
--- a/content/base/public/nsIContent.h
+++ b/content/base/public/nsIContent.h
@@ -915,27 +915,27 @@ public:
    * If the content is a part of HTML editor, this returns editing
    * host content.  When the content is in designMode, this returns its body
    * element.  Also, when the content isn't editable, this returns null.
    */
   nsIContent* GetEditingHost();
 
   /**
    * Determing language. Look at the nearest ancestor element that has a lang
-   * attribute in the XML namespace or is an HTML element and has a lang in
+   * attribute in the XML namespace or is an HTML/SVG element and has a lang in
    * no namespace attribute.
    */
   void GetLang(nsAString& aResult) const {
     for (const nsIContent* content = this; content; content = content->GetParent()) {
       if (content->GetAttrCount() > 0) {
         // xml:lang has precedence over lang on HTML elements (see
         // XHTML1 section C.7).
         bool hasAttr = content->GetAttr(kNameSpaceID_XML, nsGkAtoms::lang,
                                           aResult);
-        if (!hasAttr && content->IsHTML()) {
+        if (!hasAttr && (content->IsHTML() || content->IsSVG())) {
           hasAttr = content->GetAttr(kNameSpaceID_None, nsGkAtoms::lang,
                                      aResult);
         }
         NS_ASSERTION(hasAttr || aResult.IsEmpty(),
                      "GetAttr that returns false should not make string non-empty");
         if (hasAttr) {
           return;
         }
--- a/content/base/public/nsIFrameLoader.idl
+++ b/content/base/public/nsIFrameLoader.idl
@@ -62,17 +62,17 @@ typedef unsigned long long nsContentView
  * the content document does not (yet) define.
  *
  * The view scroll values are in units of chrome-document CSS
  * pixels.
  *
  * These APIs are designed to be used with nsIDOMWindowUtils
  * setDisplayPort() and setResolution().
  */
-[scriptable, uuid(fbd25468-d2cf-487b-bc58-a0e105398b47)]
+[scriptable, uuid(c04c5c40-fa2a-4e9c-94f5-b362a10a86cb)]
 interface nsIContentView : nsISupports
 {
   /**
    * Scroll view to or by the given chrome-document CSS pixels.
    * Fails if the view is no longer valid.
    */
   void scrollTo(in float xPx, in float yPx);
   void scrollBy(in float dxPx, in float dyPx);
@@ -260,16 +260,23 @@ interface nsIFrameLoader : nsISupports
   attribute unsigned long eventMode;
 
   /**
    * If false, then the subdocument is not clipped to its CSS viewport, and the
    * subdocument's viewport scrollbar(s) are not rendered.
    * Defaults to true.
    */
   attribute boolean clipSubdocument;
+
+  /**
+   * If false, then the subdocument's scroll coordinates will not be clamped
+   * to their scroll boundaries.
+   * Defaults to true.
+   */
+  attribute boolean clampScrollPosition;
 };
 
 native alreadyAddRefed_nsFrameLoader(already_AddRefed<nsFrameLoader>);
 
 [scriptable, uuid(5879040e-83e9-40e3-b2bb-5ddf43b76e47)]
 interface nsIFrameLoaderOwner : nsISupports
 {
   /**
--- a/content/base/src/mozSanitizingSerializer.cpp
+++ b/content/base/src/mozSanitizingSerializer.cpp
@@ -549,20 +549,19 @@ mozSanitizingHTMLSerializer::IsAllowedAt
 #endif
   nsresult rv;
 
   nsPRUint32Key tag_key(aTag);
   nsIProperties* attr_bag = (nsIProperties*)mAllowedTags.Get(&tag_key);
   NS_ENSURE_TRUE(attr_bag, false);
 
   bool allowed;
-  nsAutoString attr(anAttributeName);
-  ToLowerCase(attr);
-  rv = attr_bag->Has(NS_LossyConvertUTF16toASCII(attr).get(),
-                     &allowed);
+  nsCAutoString attr;
+  ToLowerCase(NS_ConvertUTF16toUTF8(anAttributeName), attr);
+  rv = attr_bag->Has(attr.get(), &allowed);
   if (NS_FAILED(rv))
     return false;
 
 #ifdef DEBUG_BenB
   printf(" Allowed: %s\n", allowed?"yes":"no");
 #endif
   return allowed;
 }
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -854,17 +854,17 @@ TransferZoomLevels(nsIDocument* aFromDoc
   if (!toShell)
     return;
 
   nsPresContext* toCtxt = toShell->GetPresContext();
   if (!toCtxt)
     return;
 
   toCtxt->SetFullZoom(fromCtxt->GetFullZoom());
-  toCtxt->SetMinFontSize(fromCtxt->MinFontSize());
+  toCtxt->SetMinFontSize(fromCtxt->MinFontSize(nsnull));
   toCtxt->SetTextZoom(fromCtxt->TextZoom());
 }
 
 void
 TransferShowingState(nsIDocument* aFromDoc, nsIDocument* aToDoc)
 {
   NS_ABORT_IF_FALSE(aFromDoc && aToDoc,
                     "transferring showing state from/to null doc");
@@ -2114,17 +2114,16 @@ nsDocument::ResetToURI(nsIURI *aURI, nsI
 #ifdef PR_LOGGING
   if (gDocumentLeakPRLog && PR_LOG_TEST(gDocumentLeakPRLog, PR_LOG_DEBUG)) {
     nsCAutoString spec;
     aURI->GetSpec(spec);
     PR_LogPrint("DOCUMENT %p ResetToURI %s", this, spec.get());
   }
 #endif
 
-  SetPrincipal(nsnull);
   mSecurityInfo = nsnull;
 
   mDocumentLoadGroup = nsnull;
 
   // Delete references to sub-documents and kill the subdocument map,
   // if any. It holds strong references
   if (mSubDocuments) {
     PL_DHashTableDestroy(mSubDocuments);
@@ -2164,16 +2163,22 @@ nsDocument::ResetToURI(nsIURI *aURI, nsI
   if (mListenerManager) {
     mListenerManager->Disconnect();
     mListenerManager = nsnull;
   }
 
   // Release the stylesheets list.
   mDOMStyleSheets = nsnull;
 
+  // Release our principal after tearing down the document, rather than before.
+  // This ensures that, during teardown, the document and the dying window (which
+  // already nulled out its document pointer and cached the principal) have
+  // matching principals.
+  SetPrincipal(nsnull);
+
   // Clear the original URI so SetDocumentURI sets it.
   mOriginalURI = nsnull;
 
   SetDocumentURI(aURI);
   // If mDocumentBaseURI is null, nsIDocument::GetBaseURI() returns
   // mDocumentURI.
   mDocumentBaseURI = nsnull;
 
@@ -8522,17 +8527,17 @@ nsDocument::MozCancelFullScreen()
 class nsSetWindowFullScreen : public nsRunnable {
 public:
   nsSetWindowFullScreen(nsIDocument* aDoc, bool aValue)
     : mDoc(aDoc), mValue(aValue) {}
 
   NS_IMETHOD Run()
   {
     if (mDoc->GetWindow()) {
-      mDoc->GetWindow()->SetFullScreen(mValue);
+      mDoc->GetWindow()->SetFullScreenInternal(mValue, false);
     }
     return NS_OK;
   }
 
 private:
   nsCOMPtr<nsIDocument> mDoc;
   bool mValue;
 };
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -71,16 +71,17 @@
 #include "nsIJSContextStack.h"
 #include "nsUnicharUtils.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIScrollable.h"
 #include "nsFrameLoader.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIFrame.h"
+#include "nsIScrollableFrame.h"
 #include "nsSubDocumentFrame.h"
 #include "nsDOMError.h"
 #include "nsGUIEvent.h"
 #include "nsEventDispatcher.h"
 #include "nsISHistory.h"
 #include "nsISHistoryInternal.h"
 #include "nsIDocShellHistory.h"
 #include "nsIDOMHTMLDocument.h"
@@ -325,16 +326,17 @@ nsFrameLoader::nsFrameLoader(Element* aO
   , mInSwap(false)
   , mInShow(false)
   , mHideCalled(false)
   , mNetworkCreated(aNetworkCreated)
   , mDelayRemoteDialogs(false)
   , mRemoteBrowserShown(false)
   , mRemoteFrame(false)
   , mClipSubdocument(true)
+  , mClampScrollPosition(true)
   , mCurrentRemoteFrame(nsnull)
   , mRemoteBrowser(nsnull)
   , mRenderMode(RENDER_MODE_DEFAULT)
   , mEventMode(EVENT_MODE_NORMAL_DISPATCH)
 {
 }
 
 nsFrameLoader*
@@ -1750,16 +1752,48 @@ nsFrameLoader::SetClipSubdocument(bool a
             FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
         }
       }
     }
   }
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsFrameLoader::GetClampScrollPosition(bool* aResult)
+{
+  *aResult = mClampScrollPosition;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFrameLoader::SetClampScrollPosition(bool aClamp)
+{
+  mClampScrollPosition = aClamp;
+
+  // When turning clamping on, make sure the current position is clamped.
+  if (aClamp) {
+    nsIFrame* frame = GetPrimaryFrameOfOwningContent();
+    if (frame) {
+      nsSubDocumentFrame* subdocFrame = do_QueryFrame(frame);
+      if (subdocFrame) {
+        nsIFrame* subdocRootFrame = subdocFrame->GetSubdocumentRootFrame();
+        if (subdocRootFrame) {
+          nsIScrollableFrame* subdocRootScrollFrame = subdocRootFrame->PresContext()->PresShell()->
+            GetRootScrollFrameAsScrollable();
+          if (subdocRootScrollFrame) {
+            subdocRootScrollFrame->ScrollTo(subdocRootScrollFrame->GetScrollPosition(), nsIScrollableFrame::INSTANT);
+          }
+        }
+      }
+    }
+  }
+  return NS_OK;
+}
+
 nsIntSize
 nsFrameLoader::GetSubDocumentSize(const nsIFrame *aIFrame)
 {
   nsSize docSizeAppUnits;
   nsPresContext* presContext = aIFrame->PresContext();
   nsCOMPtr<nsIDOMHTMLFrameElement> frameElem = 
     do_QueryInterface(aIFrame->GetContent());
   if (frameElem) {
--- a/content/base/src/nsFrameLoader.h
+++ b/content/base/src/nsFrameLoader.h
@@ -284,16 +284,18 @@ public:
   }
   nsFrameMessageManager* GetFrameMessageManager() { return mMessageManager; }
 
   mozilla::dom::Element* GetOwnerContent() { return mOwnerContent; }
   void SetOwnerContent(mozilla::dom::Element* aContent);
 
   bool ShouldClipSubdocument() { return mClipSubdocument; }
 
+  bool ShouldClampScrollPosition() { return mClampScrollPosition; }
+
 private:
 
   bool ShouldUseRemoteProcess();
 
   /**
    * If we are an IPC frame, set mRemoteFrame. Otherwise, create and
    * initialize mDocShell.
    */
@@ -337,16 +339,17 @@ private:
   // created using NS_FROM_PARSER_NETWORK flag. If the element is modified,
   // it may lose the flag.
   bool mNetworkCreated : 1;
 
   bool mDelayRemoteDialogs : 1;
   bool mRemoteBrowserShown : 1;
   bool mRemoteFrame : 1;
   bool mClipSubdocument : 1;
+  bool mClampScrollPosition : 1;
 
   // XXX leaking
   nsCOMPtr<nsIObserver> mChildHost;
   RenderFrameParent* mCurrentRemoteFrame;
   TabParent* mRemoteBrowser;
 
   // See nsIFrameLoader.idl.  Short story, if !(mRenderMode &
   // RENDER_MODE_ASYNC_SCROLL), all the fields below are ignored in
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -1095,16 +1095,17 @@ GK_ATOM(window, "window")
 GK_ATOM(headerWindowTarget, "window-target")
 GK_ATOM(withParam, "with-param")
 GK_ATOM(wizard, "wizard")
 GK_ATOM(wrap, "wrap")
 GK_ATOM(headerDNSPrefetchControl,"x-dns-prefetch-control")
 GK_ATOM(headerCSP, "x-content-security-policy")
 GK_ATOM(headerCSPReportOnly, "x-content-security-policy-report-only")
 GK_ATOM(headerXFO, "x-frame-options")
+GK_ATOM(x_western, "x-western")
 GK_ATOM(xml, "xml")
 GK_ATOM(xml_stylesheet, "xml-stylesheet")
 GK_ATOM(xmlns, "xmlns")
 GK_ATOM(xmp, "xmp")
 GK_ATOM(xulcontentsgenerated, "xulcontentsgenerated")
 GK_ATOM(yes, "yes")
 GK_ATOM(z_index, "z-index")
 GK_ATOM(zeroDigit, "zero-digit")
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -1319,30 +1319,53 @@ nsXMLHttpRequest::Abort()
 
 /* string getAllResponseHeaders (); */
 NS_IMETHODIMP
 nsXMLHttpRequest::GetAllResponseHeaders(char **_retval)
 {
   NS_ENSURE_ARG_POINTER(_retval);
   *_retval = nsnull;
 
+  // If the state is UNSENT or OPENED,
+  // return the empty string and terminate these steps.
+  if (mState & (XML_HTTP_REQUEST_UNSENT |
+                XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT)) {
+    *_retval = ToNewCString(EmptyString());
+    return NS_OK;
+  }
+
   if (mState & XML_HTTP_REQUEST_USE_XSITE_AC) {
     *_retval = ToNewCString(EmptyString());
     return NS_OK;
   }
 
   nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
 
   if (httpChannel) {
     nsRefPtr<nsHeaderVisitor> visitor = new nsHeaderVisitor();
     nsresult rv = httpChannel->VisitResponseHeaders(visitor);
     if (NS_SUCCEEDED(rv))
       *_retval = ToNewCString(visitor->Headers());
+  } else if (mChannel) {
+    // Even non-http channels supply content type.
+    nsCString value;
+    if (NS_SUCCEEDED(mChannel->GetContentType(value))) {
+      nsCString headers;
+      headers.Append("Content-Type: ");
+      headers.Append(value);
+      if (NS_SUCCEEDED(mChannel->GetContentCharset(value)) &&
+          !value.IsEmpty()) {
+        headers.Append(";charset=");
+        headers.Append(value);
+      }
+      headers.Append('\n');
+      *_retval = ToNewCString(headers);
+    }
   }
- 
+
   if (!*_retval) {
     *_retval = ToNewCString(EmptyString());
   }
 
   return NS_OK;
 }
 
 /* ACString getResponseHeader (in AUTF8String header); */
@@ -1351,16 +1374,47 @@ nsXMLHttpRequest::GetResponseHeader(cons
                                     nsACString& _retval)
 {
   nsresult rv = NS_OK;
   _retval.SetIsVoid(true);
 
   nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
 
   if (!httpChannel) {
+    // If the state is UNSENT or OPENED,
+    // return null and terminate these steps.
+    if (mState & (XML_HTTP_REQUEST_UNSENT |
+                  XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT)) {
+      return NS_OK;
+    }
+
+    // Even non-http channels supply content type.
+    // Remember we don't leak header information from denied cross-site
+    // requests.
+    nsresult status;
+    if (!mChannel ||
+        NS_FAILED(mChannel->GetStatus(&status)) ||
+        NS_FAILED(status) ||
+        !header.LowerCaseEqualsASCII("content-type")) {
+      return NS_OK;
+    }
+
+    if (NS_FAILED(mChannel->GetContentType(_retval))) {
+      // Means no content type
+      _retval.SetIsVoid(true);
+      return NS_OK;
+    }
+
+    nsCString value;
+    if (NS_SUCCEEDED(mChannel->GetContentCharset(value)) &&
+        !value.IsEmpty()) {
+      _retval.Append(";charset=");
+      _retval.Append(value);
+    }
+
     return NS_OK;
   }
 
   // See bug #380418. Hide "Set-Cookie" headers from non-chrome scripts.
   bool chrome = false; // default to false in case IsCapabilityEnabled fails
   IsCapabilityEnabled("UniversalXPConnect", &chrome);
   if (!chrome &&
        (header.LowerCaseEqualsASCII("set-cookie") ||
--- a/content/base/test/test_XHR.html
+++ b/content/base/test/test_XHR.html
@@ -17,43 +17,52 @@ SimpleTest.waitForExplicitFinish();
 
 var gen = runTests();
 function continueTest() { gen.next(); }
 
 function runTests() {
 
 var path = "/tests/content/base/test/";
 
-var passFiles = [['file_XHR_pass1.xml', 'GET', 200],
-                 ['file_XHR_pass2.txt', 'GET', 200],
-                 ['file_XHR_pass3.txt', 'GET', 200],
-                 ['data:text/xml,%3Cres%3Ehello%3C/res%3E%0A', 'GET', 0],
-                 ['data:text/plain,hello%20pass%0A', 'GET', 0],
+var passFiles = [['file_XHR_pass1.xml', 'GET', 200, 'text/xml'],
+                 ['file_XHR_pass2.txt', 'GET', 200, 'text/plain'],
+                 ['file_XHR_pass3.txt', 'GET', 200, 'text/plain'],
+                 ['data:text/xml,%3Cres%3Ehello%3C/res%3E%0A', 'GET', 0, 'text/xml'],
+                 ['data:text/plain,hello%20pass%0A', 'GET', 0, 'text/plain'],
+                 ['data:,foo', 'GET', 0, 'text/plain;charset=US-ASCII', 'foo'],
+                 ['data:text/plain;base64,Zm9v', 'GET', 0, 'text/plain', 'foo'],
+                 ['data:text/plain,foo#bar', 'GET', 0, 'text/plain', 'foo'],
+                 ['data:text/plain,foo%23bar', 'GET', 0, 'text/plain', 'foo#bar'],
                  ];
 
 var failFiles = [['//example.com' + path + 'file_XHR_pass1.xml', 'GET'],
                  ['ftp://localhost' + path + 'file_XHR_pass1.xml', 'GET'],
                  ['file_XHR_fail1.txt', 'GET'],
                  ];
 
 for (i = 0; i < passFiles.length; ++i) {
   xhr = new XMLHttpRequest();
+  is(xhr.getResponseHeader("Content-Type"), null, "should be null");
+  is(xhr.getAllResponseHeaders(), "", "should be empty string");
   is(xhr.responseType, "", "wrong initial responseType");
   xhr.open(passFiles[i][1], passFiles[i][0], false); 
   xhr.send(null);
   is(xhr.status, passFiles[i][2], "wrong status");
+  is(xhr.getResponseHeader("Content-Type"), passFiles[i][3], "wrong content type");
+  var headers = xhr.getAllResponseHeaders();
+  ok(/(?:^|\n)Content-Type:\s*([^\n]*)\n/i.test(headers) &&
+     RegExp.$1 === passFiles[i][3], "wrong response headers");
   if (xhr.responseXML) {
     is((new XMLSerializer()).serializeToString(xhr.responseXML.documentElement),
-       "<res>hello</res>",
-       "wrong responseXML");
-    is(xhr.response, "<res>hello</res>\n", "wrong response");
+       passFiles[i][4] || "<res>hello</res>", "wrong responseXML");
+    is(xhr.response, passFiles[i][4] || "<res>hello</res>\n", "wrong response");
   }
   else {
-    is(xhr.responseText, "hello pass\n", "wrong responseText");
-    is(xhr.response, "hello pass\n", "wrong response");
+    is(xhr.responseText, passFiles[i][4] || "hello pass\n", "wrong responseText");
+    is(xhr.response, passFiles[i][4] || "hello pass\n", "wrong response");
   }
 }
 
 for (i = 0; i < failFiles.length; ++i) {
   xhr = new XMLHttpRequest();
   var didthrow = false;
   try {
     xhr.open(failFiles[i][1], failFiles[i][0], false); 
--- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
@@ -1287,54 +1287,53 @@ nsCanvasRenderingContext2DAzure::Initial
   Reset();
 
   NS_ASSERTION(mCanvasElement, "Must have a canvas element!");
   mDocShell = nsnull;
 
   mWidth = width;
   mHeight = height;
 
-  mTarget = target;
+  // This first time this is called on this object is via
+  // nsHTMLCanvasElement::GetContext. If target was non-null then mTarget is
+  // non-null, otherwise we'll return an error here and GetContext won't
+  // return this context object and we'll never enter this code again.
+  // All other times this method is called, if target is null then
+  // mTarget won't be changed, i.e. it will remain non-null, or else it
+  // will be set to non-null.
+  // In all cases, any usable canvas context will have non-null mTarget.
+
+  if (target) {
+    mValid = true;
+    mTarget = target;
+  } else {
+    mValid = false;
+  }
 
   mResetLayer = true;
 
-  /* Create dummy surfaces here - target can be null when a canvas was created
-   * that is too large to support.
-   */
-  if (!target)
-  {
-    mTarget = gfxPlatform::GetPlatform()->CreateOffscreenDrawTarget(IntSize(1, 1), FORMAT_B8G8R8A8);
-    if (!mTarget) {
-      // SupportsAzure() is controlled by the "gfx.canvas.azure.prefer-skia"
-      // pref so that may be the reason rather than an OOM.
-      mValid = false;
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-  } else {
-    mValid = true;
-  }
-
   // set up the initial canvas defaults
   mStyleStack.Clear();
   mPathBuilder = nsnull;
   mPath = nsnull;
   mDSPathBuilder = nsnull;
 
   ContextState *state = mStyleStack.AppendElement();
   state->globalAlpha = 1.0;
 
   state->colorStyles[STYLE_FILL] = NS_RGB(0,0,0);
   state->colorStyles[STYLE_STROKE] = NS_RGB(0,0,0);
   state->shadowColor = NS_RGBA(0,0,0,0);
 
-  mTarget->ClearRect(mgfx::Rect(Point(0, 0), Size(mWidth, mHeight)));
-    
-  // always force a redraw, because if the surface dimensions were reset
-  // then the surface became cleared, and we need to redraw everything.
-  Redraw();
+  if (mTarget) {
+    mTarget->ClearRect(mgfx::Rect(Point(0, 0), Size(mWidth, mHeight)));
+    // always force a redraw, because if the surface dimensions were reset
+    // then the surface became cleared, and we need to redraw everything.
+    Redraw();
+  }
 
   return mValid ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2DAzure::SetIsOpaque(bool isOpaque)
 {
   if (isOpaque == mOpaque)
--- a/content/html/content/public/nsHTMLMediaElement.h
+++ b/content/html/content/public/nsHTMLMediaElement.h
@@ -452,16 +452,22 @@ protected:
   void QueueLoadFromSourceTask();
 
   /**
    * Runs the media resource selection algorithm.
    */
   void SelectResource();
 
   /**
+   * A wrapper function that allows us to cleanly reset flags after a call
+   * to SelectResource()
+   */
+  void SelectResourceWrapper();
+
+  /**
    * Asynchronously awaits a stable state, and then causes SelectResource()
    * to be run on the main thread's event loop.
    */
   void QueueSelectResourceTask();
 
   /**
    * The resource-fetch algorithm step of the load algorithm.
    */
@@ -734,16 +740,19 @@ protected:
   // True if we're delaying the "load" event. They are delayed until either
   // an error occurs, or the first frame is loaded.
   bool mDelayingLoadEvent;
 
   // True when we've got a task queued to call SelectResource(),
   // or while we're running SelectResource().
   bool mIsRunningSelectResource;
 
+  // True when we already have select resource call queued
+  bool mHaveQueuedSelectResource;
+
   // True if we suspended the decoder because we were paused,
   // preloading metadata is enabled, autoplay was not enabled, and we loaded
   // the first frame.
   bool mSuspendedAfterFirstFrame;
 
   // True if we are allowed to suspend the decoder because we were paused,
   // preloading metdata was enabled, autoplay was not enabled, and we loaded
   // the first frame.
--- a/content/html/content/src/nsHTMLMediaElement.cpp
+++ b/content/html/content/src/nsHTMLMediaElement.cpp
@@ -533,16 +533,17 @@ void nsHTMLMediaElement::AbortExistingLo
   }
 
   mError = nsnull;
   mLoadedFirstFrame = false;
   mAutoplaying = true;
   mIsLoadingFromSourceChildren = false;
   mSuspendedAfterFirstFrame = false;
   mAllowSuspendAfterFirstFrame = true;
+  mHaveQueuedSelectResource = false;
   mLoadIsSuspended = false;
   mSourcePointer = nsnull;
 
   // TODO: The playback rate must be set to the default playback rate.
 
   if (mNetworkState != nsIDOMHTMLMediaElement::NETWORK_EMPTY) {
     mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY;
     ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING);
@@ -620,21 +621,21 @@ void nsHTMLMediaElement::QueueLoadFromSo
   ChangeDelayLoadStatus(true);
   mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
   AsyncAwaitStableState(this, &nsHTMLMediaElement::LoadFromSourceChildren);
 }
 
 void nsHTMLMediaElement::QueueSelectResourceTask()
 {
   // Don't allow multiple async select resource calls to be queued.
-  if (mIsRunningSelectResource)
+  if (mHaveQueuedSelectResource)
     return;
-  mIsRunningSelectResource = true;
+  mHaveQueuedSelectResource = true;
   mNetworkState = nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE;
-  AsyncAwaitStableState(this, &nsHTMLMediaElement::SelectResource);
+  AsyncAwaitStableState(this, &nsHTMLMediaElement::SelectResourceWrapper);
 }
 
 /* void load (); */
 NS_IMETHODIMP nsHTMLMediaElement::Load()
 {
   if (mIsRunningLoadMethod)
     return NS_OK;
   SetPlayedOrSeeked(false);
@@ -653,69 +654,78 @@ static bool HasSourceChildren(nsIContent
     if (child->IsHTML(nsGkAtoms::source))
     {
       return true;
     }
   }
   return false;
 }
 
+void nsHTMLMediaElement::SelectResourceWrapper()
+{
+  SelectResource();
+  mIsRunningSelectResource = false;
+  mHaveQueuedSelectResource = false;
+}
+
 void nsHTMLMediaElement::SelectResource()
 {
   if (!HasAttr(kNameSpaceID_None, nsGkAtoms::src) && !HasSourceChildren(this)) {
     // The media element has neither a src attribute nor any source
     // element children, abort the load.
     mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY;
     // This clears mDelayingLoadEvent, so AddRemoveSelfReference will be called
     ChangeDelayLoadStatus(false);
-    mIsRunningSelectResource = false;
     return;
   }
 
   ChangeDelayLoadStatus(true);
 
   mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
   // Load event was delayed, and still is, so no need to call
   // AddRemoveSelfReference, since it must still be held
   DispatchAsyncEvent(NS_LITERAL_STRING("loadstart"));
 
+  // Delay setting mIsRunningSeletResource until after UpdatePreloadAction
+  // so that we don't lose our state change by bailing out of the preload
+  // state update
+  UpdatePreloadAction();
+  mIsRunningSelectResource = true;
+
   // If we have a 'src' attribute, use that exclusively.
   nsAutoString src;
   if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
     nsCOMPtr<nsIURI> uri;
     nsresult rv = NewURIFromString(src, getter_AddRefs(uri));
     if (NS_SUCCEEDED(rv)) {
       LOG(PR_LOG_DEBUG, ("%p Trying load from src=%s", this, NS_ConvertUTF16toUTF8(src).get()));
       NS_ASSERTION(!mIsLoadingFromSourceChildren,
         "Should think we're not loading from source children by default");
       mLoadingSrc = uri;
       if (mPreloadAction == nsHTMLMediaElement::PRELOAD_NONE) {
         // preload:none media, suspend the load here before we make any
         // network requests.
         SuspendLoad();
-        mIsRunningSelectResource = false;
         return;
       }
 
       rv = LoadResource();
       if (NS_SUCCEEDED(rv)) {
-        mIsRunningSelectResource = false;
         return;
       }
     } else {
       const PRUnichar* params[] = { src.get() };
       ReportLoadError("MediaLoadInvalidURI", params, ArrayLength(params));
     }
     NoSupportedMediaSourceError();
   } else {
     // Otherwise, the source elements will be used.
     mIsLoadingFromSourceChildren = true;
     LoadFromSourceChildren();
   }
-  mIsRunningSelectResource = false;
 }
 
 void nsHTMLMediaElement::NotifyLoadError()
 {
   if (!mIsLoadingFromSourceChildren) {
     LOG(PR_LOG_DEBUG, ("NotifyLoadError(), no supported media error"));
     NoSupportedMediaSourceError();
   } else if (mSourceLoadCandidate) {
@@ -1436,16 +1446,17 @@ nsHTMLMediaElement::nsHTMLMediaElement(a
     mMuted(false),
     mPlayingBeforeSeek(false),
     mPausedForInactiveDocument(false),
     mWaitingFired(false),
     mIsRunningLoadMethod(false),
     mIsLoadingFromSourceChildren(false),
     mDelayingLoadEvent(false),
     mIsRunningSelectResource(false),
+    mHaveQueuedSelectResource(false),
     mSuspendedAfterFirstFrame(false),
     mAllowSuspendAfterFirstFrame(true),
     mHasPlayedOrSeeked(false),
     mHasSelfReference(false),
     mShuttingDown(false),
     mLoadIsSuspended(false),
     mMediaSecurityVerified(false),
     mCORSMode(CORS_NONE)
--- a/content/html/content/test/test_fullscreen-api.html
+++ b/content/html/content/test/test_fullscreen-api.html
@@ -65,15 +65,21 @@ function nextTest() {
     gTestIndex++;
   } else {
     SpecialPowers.setBoolPref("full-screen-api.enabled", prevEnabled);
     SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", prevTrusted);	
     SimpleTest.finish();
   }
 }
 
+try {
+  window.fullScreen = true;
+} catch (e) {
+}
+is(window.fullScreen, false, "Shouldn't be able to set window fullscreen from content");
+
 addLoadEvent(nextTest);
 SimpleTest.waitForExplicitFinish();
 
 </script>
 </pre>
 </body>
 </html>
--- a/content/media/test/test_preload_actions.html
+++ b/content/media/test/test_preload_actions.html
@@ -380,42 +380,42 @@ var tests = [
       v.addEventListener("loadstart", function(e){v._gotLoadStart = true;}, false);
       v.addEventListener("loadedmetadata", function(e){v._gotLoadedMetaData = true;}, false);
       v.addEventListener("canplaythrough", this.canplaythrough, false);
       v.src = test.name; // Causes implicit load.
       document.body.appendChild(v);
       v.preload = "metadata";
     },
   },
-  
   {
-    // 13. Change preload value from metadata to none after load started,
-    // should still load up to metadata, should not halt immediately.
-    loadeddata:
+    // 13. Change preload value from auto to none after specifying a src
+    // should load according to preload none, no buffering should have taken place
+    suspend:
     function(e) {
       var v = e.target;
       is(v._gotLoadStart, true, "(13) Must get loadstart.");
-      is(v._gotLoadedMetaData, true, "(13) Must get loadedmetadata.");
-      ok(v.readyState >= v.HAVE_CURRENT_DATA, "(13) ReadyState must be >= HAVE_CURRENT_DATA.");
-      is(v.networkState, v.NETWORK_IDLE, "(13) NetworkState must be NETWORK_IDLE.");
+      is(v._gotLoadedMetaData, false, "(13) Must not get loadedmetadata.");
+      is(v.readyState, v.HAVE_NOTHING, "(13) ReadyState must be HAVE_NOTHING");
+      is(v.networkState, v.NETWORK_IDLE, "(13) NetworkState must be NETWORK_IDLE");
       maybeFinish(v, 13);
     },
 
     setup:
     function(v) {
       v._gotLoadStart = false;
       v._gotLoadedMetaData = false;
-      v.preload = "metadata";
-      v.addEventListener("loadstart", function(e){v._gotLoadStart = true;}, false);
+      v.preload = "auto";
+      v.src = test.name;
+      v.preload = "none";
       v.addEventListener("loadedmetadata", function(e){v._gotLoadedMetaData = true;}, false);
-      v.addEventListener("loadeddata", this.loadeddata, false);
-      v.src = test.name; // Causes implicit load.
-      document.body.appendChild(v);
-      v.preload = "none";
-    },
+      v.addEventListener("loadstart", function(e){v._gotLoadStart = true;}, false);
+      v.addEventListener("suspend", this.suspend, false);
+      document.body.appendChild(v); // Causes implicit load, should load according to preload none
+      var s = document.createElement("source");
+    }
   },
   {
     // 14. Add preload:metadata video with src to document. Play(), should play through.
     loadeddata:
     function(e) {
       var v = e.target;
       is(v._gotLoadStart, true, "(14) Must get loadstart.");
       is(v._gotLoadedMetaData, true, "(14) Must get loadedmetadata.");
@@ -516,17 +516,45 @@ var tests = [
     setup:
     function(v) {
       v.addEventListener("ended", this.ended, false);
       v.preload = "none";
       v.src = test.name; // Schedules async section to continue load algorithm.
       document.body.appendChild(v);
       v.play(); // Should cause preload:none to be overridden.
     },  
+  },
+  {
+    // 19. Set preload='auto' on first video source then switching preload='none' and swapping the video source to another.
+    // The second video should not start playing as it's preload state has been changed to 'none' from 'auto'
+    loadedmetadata: function(e) {
+      var v = e.target;
+      is(v.preload === "auto", true, "(19) preload is initially auto");
+      setTimeout(function() {
+        // set preload state to none and switch video sources
+        v.preload="none";
+        v.src = test.name + "?asdf";
+        setTimeout(function() {
+          is(v.readyState === 0, true, "(19) no buffering has taken place");
+          maybeFinish(v, 19);
+        }, 2000);
+      }, 2000);
+
+    },
+
+    setup:
+    function(v) {
+      var that = this;
+      v.preload = "auto";
+      v.src = test.name;
+      // add a listener for when the video has loaded, so we know preload auto has worked
+      v.addEventListener( "loadedmetadata", this.loadedmetadata, false);
+      document.body.appendChild(v);
     }
+  }
 ];
 
 var iterationCount = 0;
 function startTest(test, token) {
   if (test == tests[0]) {
     ++iterationCount;
   }
   if (iterationCount == 2) {
--- a/content/svg/content/src/SVGPathData.cpp
+++ b/content/svg/content/src/SVGPathData.cpp
@@ -530,36 +530,32 @@ SVGPathData::ToFlattenedPath(const gfxMa
 
   ctx->SetMatrix(aMatrix);
   ConstructPath(ctx);
   ctx->IdentityMatrix();
 
   return ctx->GetFlattenedPath();
 }
 
-static float AngleOfVector(gfxPoint v)
+static double
+AngleOfVector(const gfxPoint& aVector)
 {
   // C99 says about atan2 "A domain error may occur if both arguments are
   // zero" and "On a domain error, the function returns an implementation-
   // defined value". In the case of atan2 the implementation-defined value
   // seems to commonly be zero, but it could just as easily be a NaN value.
   // We specifically want zero in this case, hence the check:
 
-  return (v != gfxPoint(0.0f, 0.0f)) ? atan2(v.y, v.x) : 0.0f;
+  return (aVector != gfxPoint(0.0, 0.0)) ? atan2(aVector.y, aVector.x) : 0.0;
 }
 
-// TODO replace callers with calls to AngleOfVector
-static double
-CalcVectorAngle(double ux, double uy, double vx, double vy)
+static float
+AngleOfVectorF(const gfxPoint& aVector)
 {
-  double ta = atan2(uy, ux);
-  double tb = atan2(vy, vx);
-  if (tb >= ta)
-    return tb-ta;
-  return 2 * M_PI - (ta-tb);
+  return static_cast<float>(AngleOfVector(aVector));
 }
 
 void
 SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const
 {
   // This code should assume that ANY type of segment can appear at ANY index.
   // It should also assume that segments such as M and Z can appear in weird
   // places, and repeat multiple times consecutively.
@@ -583,41 +579,41 @@ SVGPathData::GetMarkerPositioningData(ns
     gfxPoint &segStart = prevSegEnd;
     gfxPoint segEnd;
     float segStartAngle, segEndAngle;
 
     switch (segType) // to find segStartAngle, segEnd and segEndAngle
     {
     case nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH:
       segEnd = pathStart;
-      segStartAngle = segEndAngle = AngleOfVector(segEnd - segStart);
+      segStartAngle = segEndAngle = AngleOfVectorF(segEnd - segStart);
       break;
 
     case nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS:
     case nsIDOMSVGPathSeg::PATHSEG_MOVETO_REL:
       if (segType == nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS) {
         segEnd = gfxPoint(mData[i], mData[i+1]);
       } else {
         segEnd = segStart + gfxPoint(mData[i], mData[i+1]);
       }
       pathStart = segEnd;
       // If authors are going to specify multiple consecutive moveto commands
       // with markers, me might as well make the angle do something useful:
-      segStartAngle = segEndAngle = AngleOfVector(segEnd - segStart);
+      segStartAngle = segEndAngle = AngleOfVectorF(segEnd - segStart);
       i += 2;
       break;
 
     case nsIDOMSVGPathSeg::PATHSEG_LINETO_ABS:
     case nsIDOMSVGPathSeg::PATHSEG_LINETO_REL:
       if (segType == nsIDOMSVGPathSeg::PATHSEG_LINETO_ABS) {
         segEnd = gfxPoint(mData[i], mData[i+1]);
       } else {
         segEnd = segStart + gfxPoint(mData[i], mData[i+1]);
       }
-      segStartAngle = segEndAngle = AngleOfVector(segEnd - segStart);
+      segStartAngle = segEndAngle = AngleOfVectorF(segEnd - segStart);
       i += 2;
       break;
 
     case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS:
     case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL:
     {
       gfxPoint cp1, cp2; // control points
       if (segType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS) {
@@ -631,36 +627,36 @@ SVGPathData::GetMarkerPositioningData(ns
       }
       prevCP = cp2;
       if (cp1 == segStart) {
         cp1 = cp2;
       }
       if (cp2 == segEnd) {
         cp2 = cp1;
       }
-      segStartAngle = AngleOfVector(cp1 - segStart);
-      segEndAngle = AngleOfVector(segEnd - cp2);
+      segStartAngle = AngleOfVectorF(cp1 - segStart);
+      segEndAngle = AngleOfVectorF(segEnd - cp2);
       i += 6;
       break;
     }
 
     case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS:
     case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL:
     {
       gfxPoint cp1, cp2; // control points
       if (segType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS) {
         cp1 = gfxPoint(mData[i],   mData[i+1]);
         segEnd = gfxPoint(mData[i+2], mData[i+3]);
       } else {
         cp1 = segStart + gfxPoint(mData[i],   mData[i+1]);
         segEnd = segStart + gfxPoint(mData[i+2], mData[i+3]);
       }
       prevCP = cp1;
-      segStartAngle = AngleOfVector(cp1 - segStart);
-      segEndAngle = AngleOfVector(segEnd - cp1);
+      segStartAngle = AngleOfVectorF(cp1 - segStart);
+      segEndAngle = AngleOfVectorF(segEnd - cp1);
       i += 4;
       break;
     }
 
     case nsIDOMSVGPathSeg::PATHSEG_ARC_ABS:
     case nsIDOMSVGPathSeg::PATHSEG_ARC_REL:
     {
       double rx = mData[i];
@@ -690,17 +686,17 @@ SVGPathData::GetMarkerPositioningData(ns
       }
 
       // Below we have funny interleaving of F.6.6 (Correction of out-of-range
       // radii) and F.6.5 (Conversion from endpoint to center parameterization)
       // which is designed to avoid some unnecessary calculations.
 
       if (rx == 0.0 || ry == 0.0) {
         // F.6.6 step 1 - straight line or coincidental points
-        segStartAngle = segEndAngle = AngleOfVector(segEnd - segStart);
+        segStartAngle = segEndAngle = AngleOfVectorF(segEnd - segStart);
         i += 7;
         break;
       }
       rx = fabs(rx); // F.6.6.1
       ry = fabs(ry);
 
       // F.6.5.1:
       angle = angle * M_PI/180.0;
@@ -731,19 +727,20 @@ SVGPathData::GetMarkerPositioningData(ns
         ry *= s;
         root = 0.0;
       }
 
       double cxp =  root * rx * y1p / ry;  // F.6.5.2
       double cyp = -root * ry * x1p / rx;
 
       double theta, delta;
-      theta = CalcVectorAngle(1.0, 0.0, (x1p-cxp)/rx, (y1p-cyp)/ry); // F.6.5.5
-      delta = CalcVectorAngle((x1p-cxp)/rx, (y1p-cyp)/ry,
-                              (-x1p-cxp)/rx, (-y1p-cyp)/ry);         // F.6.5.6
+      theta = AngleOfVector(gfxPoint((x1p-cxp)/rx, (y1p-cyp)/ry) -   // F.6.5.5
+                            gfxPoint(1.0, 0.0));
+      delta = AngleOfVector(gfxPoint((-x1p-cxp)/rx, (-y1p-cyp)/ry) - // F.6.5.6
+                            gfxPoint((x1p-cxp)/rx, (y1p-cyp)/ry));
       if (!sweepFlag && delta > 0)
         delta -= 2.0 * M_PI;
       else if (sweepFlag && delta < 0)
         delta += 2.0 * M_PI;
 
       double tx1, ty1, tx2, ty2;
       tx1 = -cos(angle)*rx*sin(theta) - sin(angle)*ry*cos(theta);
       ty1 = -sin(angle)*rx*sin(theta) + cos(angle)*ry*cos(theta);
@@ -752,40 +749,40 @@ SVGPathData::GetMarkerPositioningData(ns
 
       if (delta < 0.0f) {
         tx1 = -tx1;
         ty1 = -ty1;
         tx2 = -tx2;
         ty2 = -ty2;
       }
 
-      segStartAngle = atan2(ty1, tx1);
-      segEndAngle = atan2(ty2, tx2);
+      segStartAngle = static_cast<float>(atan2(ty1, tx1));
+      segEndAngle = static_cast<float>(atan2(ty2, tx2));
       i += 7;
       break;
     }
 
     case nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_ABS:
     case nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_REL:
       if (segType == nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_ABS) {
         segEnd = gfxPoint(mData[i++], segStart.y);
       } else {
         segEnd = segStart + gfxPoint(mData[i++], 0.0f);
       }
-      segStartAngle = segEndAngle = AngleOfVector(segEnd - segStart);
+      segStartAngle = segEndAngle = AngleOfVectorF(segEnd - segStart);
       break;
 
     case nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_ABS:
     case nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_REL:
       if (segType == nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_ABS) {
         segEnd = gfxPoint(segStart.x, mData[i++]);
       } else {
         segEnd = segStart + gfxPoint(0.0f, mData[i++]);
       }
-      segStartAngle = segEndAngle = AngleOfVector(segEnd - segStart);
+      segStartAngle = segEndAngle = AngleOfVectorF(segEnd - segStart);
       break;
 
     case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
     case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
     {
       gfxPoint cp1 = SVGPathSegUtils::IsCubicType(prevSegType) ?
                        segStart * 2 - prevCP : segStart;
       gfxPoint cp2;
@@ -798,36 +795,36 @@ SVGPathData::GetMarkerPositioningData(ns
       }
       prevCP = cp2;
       if (cp1 == segStart) {
         cp1 = cp2;
       }
       if (cp2 == segEnd) {
         cp2 = cp1;
       }
-      segStartAngle = AngleOfVector(cp1 - segStart);
-      segEndAngle = AngleOfVector(segEnd - cp2);
+      segStartAngle = AngleOfVectorF(cp1 - segStart);
+      segEndAngle = AngleOfVectorF(segEnd - cp2);
       i += 4;
       break;
     }
 
     case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
     case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
     {
       gfxPoint cp1 = SVGPathSegUtils::IsQuadraticType(prevSegType) ?
                        segStart * 2 - prevCP : segStart;
       gfxPoint cp2;
       if (segType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS) {
         segEnd = gfxPoint(mData[i], mData[i+1]);
       } else {
         segEnd = segStart + gfxPoint(mData[i], mData[i+1]);
       }
       prevCP = cp1;
-      segStartAngle = AngleOfVector(cp1 - segStart);
-      segEndAngle = AngleOfVector(segEnd - cp1);
+      segStartAngle = AngleOfVectorF(cp1 - segStart);
+      segEndAngle = AngleOfVectorF(segEnd - cp1);
       i += 2;
       break;
     }
 
     default:
       // Leave any existing marks in aMarks so we have a visual indication of
       // when things went wrong.
       NS_ABORT_IF_FALSE(false, "Unknown segment type - path corruption?");
@@ -847,17 +844,18 @@ SVGPathData::GetMarkerPositioningData(ns
       } else {
         if (!(segType == nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH &&
               prevSegType == nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH))
           mark.angle = nsSVGUtils::AngleBisect(prevSegEndAngle, segStartAngle);
       }
     }
 
     // Add the mark at the end of this segment, and set its position:
-    if (!aMarks->AppendElement(nsSVGMark(segEnd.x, segEnd.y, 0))) {
+    if (!aMarks->AppendElement(nsSVGMark(static_cast<float>(segEnd.x),
+                                         static_cast<float>(segEnd.y), 0))) {
       aMarks->Clear(); // OOM, so try to free some
       return;
     }
 
     if (segType == nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH &&
         prevSegType != nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH) {
       aMarks->ElementAt(aMarks->Length() - 1).angle =
         //aMarks->ElementAt(pathStartIndex).angle =
--- a/content/svg/content/src/nsSVGElement.cpp
+++ b/content/svg/content/src/nsSVGElement.cpp
@@ -903,16 +903,25 @@ nsSVGElement::WalkContentStyleRules(nsRu
       animContentStyleRule->RuleMatched();
       aRuleWalker->Forward(animContentStyleRule);
     }
   }
 
   return NS_OK;
 }
 
+NS_IMETHODIMP_(bool)
+nsSVGElement::IsAttributeMapped(const nsIAtom* name) const
+{
+  if (name == nsGkAtoms::lang) {
+    return true;
+  }
+  return nsSVGElementBase::IsAttributeMapped(name);
+}
+
 // PresentationAttributes-FillStroke
 /* static */ const nsGenericElement::MappedAttributeEntry
 nsSVGElement::sFillStrokeMap[] = {
   { &nsGkAtoms::fill },
   { &nsGkAtoms::fill_opacity },
   { &nsGkAtoms::fill_rule },
   { &nsGkAtoms::stroke },
   { &nsGkAtoms::stroke_dasharray },
@@ -1150,19 +1159,34 @@ MappedAttrParser::ParseMappedAttrValue(n
   if (!mDecl) {
     mDecl = new css::Declaration();
     mDecl->InitializeEmpty();
   }
 
   // Get the nsCSSProperty ID for our mapped attribute.
   nsCSSProperty propertyID =
     nsCSSProps::LookupProperty(nsDependentAtomString(aMappedAttrName));
-  bool changed; // outparam for ParseProperty. (ignored)
-  mParser.ParseProperty(propertyID, aMappedAttrValue, mDocURI, mBaseURI,
-                        mNodePrincipal, mDecl, &changed, false);
+  if (propertyID != eCSSProperty_UNKNOWN) {
+    bool changed; // outparam for ParseProperty. (ignored)
+    mParser.ParseProperty(propertyID, aMappedAttrValue, mDocURI, mBaseURI,
+                          mNodePrincipal, mDecl, &changed, false);
+    return;
+  }
+  NS_ABORT_IF_FALSE(aMappedAttrName == nsGkAtoms::lang,
+                    "Only 'lang' should be unrecognized!");
+  // nsCSSParser doesn't know about 'lang', so we need to handle it specially.
+  if (aMappedAttrName == nsGkAtoms::lang) {
+    propertyID = eCSSProperty__x_lang;
+    nsCSSExpandedDataBlock block;
+    mDecl->ExpandTo(&block);
+    nsCSSValue cssValue(PromiseFlatString(aMappedAttrValue), eCSSUnit_Ident);
+    block.AddLonghandProperty(propertyID, cssValue);
+    mDecl->ValueAppended(propertyID);
+    mDecl->CompressFrom(&block);
+  }
 }
 
 already_AddRefed<css::StyleRule>
 MappedAttrParser::CreateStyleRule()
 {
   if (!mDecl) {
     return nsnull; // No mapped attributes were parsed
   }
@@ -1198,16 +1222,26 @@ nsSVGElement::UpdateContentStyleRule()
   MappedAttrParser mappedAttrParser(doc->CSSLoader(), doc->GetDocumentURI(),
                                     GetBaseURI(), NodePrincipal());
 
   for (PRUint32 i = 0; i < attrCount; ++i) {
     const nsAttrName* attrName = mAttrsAndChildren.AttrNameAt(i);
     if (!attrName->IsAtom() || !IsAttributeMapped(attrName->Atom()))
       continue;
 
+    if (attrName->NamespaceID() != kNameSpaceID_None &&
+        !attrName->Equals(nsGkAtoms::lang, kNameSpaceID_XML)) {
+      continue;
+    }
+
+    if (attrName->Equals(nsGkAtoms::lang, kNameSpaceID_None) &&
+        HasAttr(kNameSpaceID_XML, nsGkAtoms::lang)) {
+      continue; // xml:lang has precedence
+    }
+
     if (Tag() == nsGkAtoms::svg) {
       // Special case: we don't want <svg> 'width'/'height' mapped into style
       // if the attribute value isn't a valid <length> according to SVG (which
       // only supports a subset of the CSS <length> values). We don't enforce
       // this by checking the attribute value in nsSVGSVGElement::
       // IsAttributeMapped since we don't want that method to depend on the
       // value of the attribute that is being checked. Rather we just prevent
       // the actual mapping here, as necessary.
--- a/content/svg/content/src/nsSVGElement.h
+++ b/content/svg/content/src/nsSVGElement.h
@@ -119,16 +119,18 @@ public:
 
   virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
                                               PRInt32 aModType) const;
 
   virtual bool IsNodeOfType(PRUint32 aFlags) const;
 
   NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker);
 
+  NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const;
+
   static const MappedAttributeEntry sFillStrokeMap[];
   static const MappedAttributeEntry sGraphicsMap[];
   static const MappedAttributeEntry sTextContentElementsMap[];
   static const MappedAttributeEntry sFontSpecificationMap[];
   static const MappedAttributeEntry sGradientStopMap[];
   static const MappedAttributeEntry sViewportsMap[];
   static const MappedAttributeEntry sMarkersMap[];
   static const MappedAttributeEntry sColorMap[];
@@ -228,32 +230,32 @@ public:
   void DidChangePointList(const nsAttrValue& aEmptyOrOldValue);
   void DidChangePathSegList(const nsAttrValue& aEmptyOrOldValue);
   void DidChangeTransformList(const nsAttrValue& aEmptyOrOldValue);
   void DidChangeString(PRUint8 aAttrEnum) {}
   void DidChangeStringList(bool aIsConditionalProcessingAttribute,
                            PRUint8 aAttrEnum,
                            const nsAttrValue& aEmptyOrOldValue);
 
-  virtual void DidAnimateLength(PRUint8 aAttrEnum);
-  virtual void DidAnimateNumber(PRUint8 aAttrEnum);
-  virtual void DidAnimateNumberPair(PRUint8 aAttrEnum);
-  virtual void DidAnimateInteger(PRUint8 aAttrEnum);
-  virtual void DidAnimateIntegerPair(PRUint8 aAttrEnum);
-  virtual void DidAnimateAngle(PRUint8 aAttrEnum);
-  virtual void DidAnimateBoolean(PRUint8 aAttrEnum);
-  virtual void DidAnimateEnum(PRUint8 aAttrEnum);
-  virtual void DidAnimateViewBox();
-  virtual void DidAnimatePreserveAspectRatio();
-  virtual void DidAnimateNumberList(PRUint8 aAttrEnum);
-  virtual void DidAnimateLengthList(PRUint8 aAttrEnum);
-  virtual void DidAnimatePointList();
-  virtual void DidAnimatePathSegList();
-  virtual void DidAnimateTransformList();
-  virtual void DidAnimateString(PRUint8 aAttrEnum);
+  void DidAnimateLength(PRUint8 aAttrEnum);
+  void DidAnimateNumber(PRUint8 aAttrEnum);
+  void DidAnimateNumberPair(PRUint8 aAttrEnum);
+  void DidAnimateInteger(PRUint8 aAttrEnum);
+  void DidAnimateIntegerPair(PRUint8 aAttrEnum);
+  void DidAnimateAngle(PRUint8 aAttrEnum);
+  void DidAnimateBoolean(PRUint8 aAttrEnum);
+  void DidAnimateEnum(PRUint8 aAttrEnum);
+  void DidAnimateViewBox();
+  void DidAnimatePreserveAspectRatio();
+  void DidAnimateNumberList(PRUint8 aAttrEnum);
+  void DidAnimateLengthList(PRUint8 aAttrEnum);
+  void DidAnimatePointList();
+  void DidAnimatePathSegList();
+  void DidAnimateTransformList();
+  void DidAnimateString(PRUint8 aAttrEnum);
 
   nsSVGLength2* GetAnimatedLength(const nsIAtom *aAttrName);
   void GetAnimatedLengthValues(float *aFirst, ...);
   void GetAnimatedNumberValues(float *aFirst, ...);
   void GetAnimatedIntegerValues(PRInt32 *aFirst, ...);
   SVGAnimatedNumberList* GetAnimatedNumberList(PRUint8 aAttrEnum);
   SVGAnimatedNumberList* GetAnimatedNumberList(nsIAtom *aAttrName);
   void GetAnimatedLengthListValues(SVGUserUnitList *aFirst, ...);
--- a/content/svg/content/src/nsSVGSVGElement.cpp
+++ b/content/svg/content/src/nsSVGSVGElement.cpp
@@ -996,16 +996,20 @@ nsSVGSVGElement::GetViewBoxTransform() c
     nsSVGSVGElement *ctx = GetCtx();
     viewportWidth = mLengthAttributes[WIDTH].GetAnimValue(ctx);
     viewportHeight = mLengthAttributes[HEIGHT].GetAnimValue(ctx);
   } else {
     viewportWidth = mViewportWidth;
     viewportHeight = mViewportHeight;
   }
 
+  if (viewportWidth <= 0.0f || viewportHeight <= 0.0f) {
+    return gfxMatrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
+  }
+
   nsSVGViewBoxRect viewBox;
   if (mViewBox.IsValid()) {
     viewBox = mViewBox.GetAnimValue();
   } else {
     viewBox.x = viewBox.y = 0.0f;
     if (ShouldSynthesizeViewBox()) {
       // Special case -- fake a viewBox, using height & width attrs.
       // (Use |this| as context, since if we get here, we're outermost <svg>.)
--- a/content/svg/content/test/Makefile.in
+++ b/content/svg/content/test/Makefile.in
@@ -69,16 +69,17 @@ include $(topsrcdir)/config/rules.mk
 		test_dataTypesModEvents.html \
 		dataTypes-helper.svg \
 		getCTM-helper.svg \
 		test_getCTM.html \
 		test_getElementById.xhtml \
 		test_getSubStringLength.xhtml \
 		getSubStringLength-helper.svg \
 		test_isSupported.xhtml \
+		test_lang.xhtml \
 		test_nonAnimStrings.xhtml \
 		test_pathAnimInterpolation.xhtml \
 		test_pathSeg.xhtml \
 		test_pointAtLength.xhtml \
 		test_pointer-events.xhtml \
 		test_pointer-events-2.xhtml \
 		test_scientific.html \
 		scientific-helper.svg \
--- a/content/svg/content/test/getCTM-helper.svg
+++ b/content/svg/content/test/getCTM-helper.svg
@@ -12,16 +12,19 @@
       <symbol id="sym" width="100" height="100">
         <rect id="symbolRect" width="0" height="0"
               transform="translate(70, 80)"/>
       </symbol>
     </defs>
     <svg id="inner" x="30" y="40" width="100" height="100">
       <g id="g1"/>
     </svg>
+    <svg id="inner-2" viewBox="0 0 10 10" width="-10" height="10">
+      <g id="g5"/>
+    </svg>
     <foreignObject id="fO" x="30" y="40" width="100" height="100" transform="translate(1, 1)">
       <!-- current layout implementation ignores x="50" and y="60".
            thus, I made getCTM and getScreenCTM do the same. -->
       <svg id="outer" x="50" y="60" width="100" height="100">
         <g id="g2" transform="translate(600, 700)"/>
       </svg>
     </foreignObject>
     <!-- something invalid -->
--- a/content/svg/content/test/test_getCTM.html
+++ b/content/svg/content/test/test_getCTM.html
@@ -30,16 +30,17 @@ function runTest()
 
   var root = doc.documentElement;
   var inner = doc.getElementById("inner");
   var g1 = doc.getElementById("g1");
   var outer = doc.getElementById("outer");
   var g2 = doc.getElementById("g2");
   var g3 = doc.getElementById("g3");
   var g4 = doc.getElementById("g4");
+  var g5 = doc.getElementById("g5");
   var sym = doc.getElementById("sym");
   var symbolRect = doc.getElementById("symbolRect");
   var fO = doc.getElementById("fO");
   /* Tests the consistency with nearestViewportElement
      (code is from test_viewport.html) */
   // root.nearestViewportElement == null
   is((function(){try{return root.getCTM()}catch(e){return e}})(), null, "root.getCTM()");
   // inner.nearestViewportElement == root
@@ -56,19 +57,21 @@ function runTest()
   // g3.nearestViewportElement == null
   is((function(){try{return g3.getCTM()}catch(e){return e}})(), null, "g3.getCTM()");
   // g4.nearestViewportElement == null
   is((function(){try{return g4.getCTM().e}catch(e){return e}})(), 1, "g4.getCTM().e");
   is((function(){try{return g4.getCTM().f}catch(e){return e}})(), 2, "g4.getCTM().f");
   // symbolRect.nearestViewportElement == sym
   is((function(){try{return symbolRect.getCTM().e}catch(e){return e}})(), 70, "symbolRect.getCTM().e");
   is((function(){try{return symbolRect.getCTM().f}catch(e){return e}})(), 80, "symbolRect.getCTM().f");
-  // fO.nearestViewportElement = <svg> with no 'id'
+  // fO.nearestViewportElement == <svg> with no 'id'
   is((function(){try{return fO.getCTM().e}catch(e){return e}})(), 2, "fO.getCTM().e");
   is((function(){try{return fO.getCTM().f}catch(e){return e}})(), 3, "fO.getCTM().f");
+  // g5.nearestViewportElement == inner-2 
+  is((function(){try{return g5.getCTM()}catch(e){return e}})(), null, "g5.getCTM()");
 
   /* Tests the consistency with farthestViewportElement
      (code is from test_viewport.html) */
   // root.farthestViewportElement == null (but actually == root)
   is((function(){try{return root.getScreenCTM().e}catch(e){return e}})(), 11, "root.getScreenCTM().e");
   is((function(){try{return root.getScreenCTM().f}catch(e){return e}})(), 22, "root.getScreenCTM().f");
   // inner.farthestViewportElement == root
   is((function(){try{return inner.getScreenCTM().e}catch(e){return e}})(), 45, "inner.getScreenCTM().e");
@@ -85,16 +88,18 @@ function runTest()
   // g3.farthestViewportElement == null (but actually == null)
   is((function(){try{return g3.getScreenCTM()}catch(e){return e}})(), null, "g3.getScreenCTM()");
   // symbolRect.farthestViewportElement == root
   is((function(){try{return symbolRect.getScreenCTM().e}catch(e){return e}})(), 85, "symbolRect.getScreenCTM().e");
   is((function(){try{return symbolRect.getScreenCTM().f}catch(e){return e}})(), 108, "symbolRect.getScreenCTM().f");
   // fO.farthestViewportElement == root
   is((function(){try{return fO.getScreenCTM().e}catch(e){return e}})(), 16, "symbolRect.getScreenCTM().e");
   is((function(){try{return fO.getScreenCTM().f}catch(e){return e}})(), 29, "symbolRect.getScreenCTM().f");
+  // g5.farthestViewportElement == root
+  is((function(){try{return g5.getScreenCTM()}catch(e){return e}})(), null, "g5.getScreenCTM()");
 
   SimpleTest.finish();
 }
 
 window.addEventListener("load", runTest, false);
 </script>
 </pre>
 </body>
new file mode 100644
--- /dev/null
+++ b/content/svg/content/test/test_lang.xhtml
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=721920
+-->
+<head>
+  <title>Test for Bug 721920</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+  <style type="text/css">
+
+svg text { word-spacing: 1em; }
+
+  </style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=721920">Mozilla Bug 721920</a>
+<p id="display">
+  <svg xmlns="http://www.w3.org/2000/svg" width="400" height="300">
+    <g lang="zh-Hans">
+      <text id="s0" y="40" style="font-size: 0">汉字</text>
+      <text id="s4" y="80" style="font-size: 4px">汉字</text>
+      <text id="s12" y="120" style="font-size: 12px">汉字</text>
+      <text id="s28" y="160" style="font-size: 28px">汉字</text>
+    </g>
+  </svg>
+</p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+//<![CDATA[
+
+/** Test for Bug 721920 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var elts = [
+  document.getElementById("s0"),
+  document.getElementById("s4"),
+  document.getElementById("s12"),
+  document.getElementById("s28")
+];
+
+function fs(idx) {
+  // The computed font size actually *doesn't* currently reflect the
+  // minimum font size preference, but things in em units do.  Hence
+  // why we use word-spacing here.
+  // test_bug401046.html uses margin-bottom instead, but there's an
+  // SVG bug that prevents that working in SVG (bug 728723).
+  return getComputedStyle(elts[idx], "").wordSpacing;
+}
+
+SpecialPowers.pushPrefEnv({'clear': [['font.minimum-size.zh-CN']]}, step1);
+
+function step1() {
+    is(fs(0), "0px", "at min font size 0, 0px should compute to 0px");
+    is(fs(1), "4px", "at min font size 0, 4px should compute to 4px");
+    is(fs(2), "12px", "at min font size 0, 12px should compute to 12px");
+    is(fs(3), "28px", "at min font size 0, 28px should compute to 28px");
+
+    SpecialPowers.pushPrefEnv({'set': [['font.minimum-size.zh-CN', 7]]}, step2);
+}
+
+function step2() {
+    is(fs(0), "0px", "at min font size 7, 0px should compute to 0px");
+    is(fs(1), "7px", "at min font size 7, 4px should compute to 7px");
+    is(fs(2), "12px", "at min font size 7, 12px should compute to 12px");
+    is(fs(3), "28px", "at min font size 7, 28px should compute to 28px");
+
+    SpecialPowers.pushPrefEnv({'set': [['font.minimum-size.zh-CN', 18]]}, step3);
+}
+
+function step3() {
+    is(fs(0), "0px", "at min font size 18, 0px should compute to 0px");
+    is(fs(1), "18px", "at min font size 18, 4px should compute to 18px");
+    is(fs(2), "18px", "at min font size 18, 12px should compute to 18px");
+    is(fs(3), "28px", "at min font size 18, 28px should compute to 28px");
+
+    SpecialPowers.pushPrefEnv({'clear': [['font.minimum-size.zh-CN']]}, SimpleTest.finish);
+}
+
+//]]>
+</script>
+</pre>
+</body>
+</html>
+
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -4453,41 +4453,46 @@ nsGlobalWindow::GetNearestWidget()
   nsIFrame* rootFrame = presShell->GetRootFrame();
   NS_ENSURE_TRUE(rootFrame, nsnull);
   return rootFrame->GetView()->GetNearestWidget(nsnull);
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::SetFullScreen(bool aFullScreen)
 {
+  return SetFullScreenInternal(aFullScreen, true);
+}
+
+nsresult
+nsGlobalWindow::SetFullScreenInternal(bool aFullScreen, bool aRequireTrust)
+{
   FORWARD_TO_OUTER(SetFullScreen, (aFullScreen), NS_ERROR_NOT_INITIALIZED);
 
   NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
 
   bool rootWinFullScreen;
   GetFullScreen(&rootWinFullScreen);
-  // Only chrome can change our fullScreen mode, unless the DOM full-screen
-  // API is enabled.
-  if ((aFullScreen == rootWinFullScreen || 
-      !nsContentUtils::IsCallerTrustedForWrite()) &&
-      !nsContentUtils::IsFullScreenApiEnabled()) {
+  // Only chrome can change our fullScreen mode, unless we're running in
+  // untrusted mode.
+  if (aFullScreen == rootWinFullScreen || 
+      (aRequireTrust && !nsContentUtils::IsCallerTrustedForWrite())) {
     return NS_OK;
   }
 
   // SetFullScreen needs to be called on the root window, so get that
   // via the DocShell tree, and if we are not already the root,
   // call SetFullScreen on that window instead.
   nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
   nsCOMPtr<nsIDocShellTreeItem> rootItem;
   treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
-  nsCOMPtr<nsIDOMWindow> window = do_GetInterface(rootItem);
+  nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(rootItem);
   if (!window)
     return NS_ERROR_FAILURE;
   if (rootItem != treeItem)
-    return window->SetFullScreen(aFullScreen);
+    return window->SetFullScreenInternal(aFullScreen, aRequireTrust);
 
   // make sure we don't try to set full screen on a non-chrome window,
   // which might happen in embedding world
   PRInt32 itemType;
   treeItem->GetItemType(&itemType);
   if (itemType != nsIDocShellTreeItem::typeChrome)
     return NS_ERROR_FAILURE;
 
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -393,16 +393,17 @@ public:
   virtual NS_HIDDEN_(bool) CanClose();
   virtual NS_HIDDEN_(nsresult) ForceClose();
 
   virtual NS_HIDDEN_(void) SetHasOrientationEventListener();
   virtual NS_HIDDEN_(void) RemoveOrientationEventListener();
   virtual NS_HIDDEN_(void) MaybeUpdateTouchState();
   virtual NS_HIDDEN_(void) UpdateTouchState();
   virtual NS_HIDDEN_(bool) DispatchCustomEvent(const char *aEventName);
+  virtual NS_HIDDEN_(nsresult) SetFullScreenInternal(bool aIsFullScreen, bool aRequireTrust);
 
   // nsIDOMStorageIndexedDB
   NS_DECL_NSIDOMSTORAGEINDEXEDDB
 
   // nsIInterfaceRequestor
   NS_DECL_NSIINTERFACEREQUESTOR
 
   // Object Management
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -75,18 +75,18 @@ class nsIDocument;
 class nsIScriptTimeoutHandler;
 struct nsTimeout;
 template <class> class nsScriptObjectHolder;
 class nsXBLPrototypeHandler;
 class nsIArray;
 class nsPIWindowRoot;
 
 #define NS_PIDOMWINDOW_IID \
-{ 0x1352de12, 0x7a07, 0x4610, \
-  { 0x93, 0xd5, 0xb8, 0x76, 0xfe, 0x93, 0x09, 0x50 } }
+{ 0x9aef58e9, 0x5225, 0x4e58, \
+  { 0x9a, 0xfb, 0xe6, 0x63, 0x97, 0x1d, 0x86, 0x88 } }
 
 class nsPIDOMWindow : public nsIDOMWindowInternal
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_PIDOMWINDOW_IID)
 
   virtual nsPIDOMWindow* GetPrivateRoot() = 0;
 
@@ -453,16 +453,23 @@ public:
   }
 
   bool HasTouchEventListeners()
   {
     return mMayHaveTouchEventListener;
   }
 
   /**
+   * Moves the top-level window into fullscreen mode if aIsFullScreen is true,
+   * otherwise exits fullscreen. If aRequireTrust is true, this method only
+   * changes window state in a context trusted for write.
+   */
+  virtual nsresult SetFullScreenInternal(bool aIsFullScreen, bool aRequireTrust) = 0;
+
+  /**
    * Call this to indicate that some node (this window, its document,
    * or content in that document) has a "MozAudioAvailable" event listener.
    */
   virtual void SetHasAudioAvailableEventListeners() = 0;
 
   /**
    * Call this to check whether some node (this window, its document,
    * or content in that document) has a mouseenter/leave event listener.
--- a/dom/sms/interfaces/Makefile.in
+++ b/dom/sms/interfaces/Makefile.in
@@ -43,18 +43,19 @@ include $(DEPTH)/config/autoconf.mk
 
 XPIDL_MODULE = dom_sms
 
 include $(topsrcdir)/dom/dom-config.mk
 
 XPIDLSRCS = \
   nsIDOMNavigatorSms.idl \
   nsIDOMSmsManager.idl \
-  nsISmsService.idl \
   nsIDOMSmsMessage.idl \
   nsIDOMSmsEvent.idl \
-  nsISmsDatabaseService.idl \
   nsIDOMSmsRequest.idl \
   nsIDOMSmsFilter.idl \
   nsIDOMSmsCursor.idl \
+  nsISmsDatabaseService.idl \
+  nsISmsRequestManager.idl \
+  nsISmsService.idl \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/sms/interfaces/nsISmsRequestManager.idl
@@ -0,0 +1,80 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+interface nsIDOMMozSmsMessage;
+interface nsIDOMMozSmsRequest;
+interface nsPIDOMWindow;
+interface nsIScriptContext;
+
+%{C++
+#define SMS_REQUEST_MANAGER_CID \
+{ 0xa97a3129, 0x1e0b, 0x45da,    \
+{ 0xa3, 0x85, 0xcf, 0xe5, 0xb0, 0xb1, 0xc4, 0x8f } }
+#define SMS_REQUEST_MANAGER_CONTRACTID "@mozilla.org/sms/smsrequestmanager;1"
+%}
+
+[scriptable, uuid(1638b963-3a45-4937-b6a9-280c1bfb166c)]
+interface nsISmsRequestManager : nsISupports
+{
+
+  /**
+   * All SMS related errors that could apply to SmsRequest objects.
+   * Make sure to keep this list in sync with the list in:
+   * embedding/android/GeckoSmsManager.java
+   */
+  const unsigned short SUCCESS_NO_ERROR = 0;
+  const unsigned short NO_SIGNAL_ERROR  = 1;
+  const unsigned short NOT_FOUND_ERROR  = 2;
+  const unsigned short UNKNOWN_ERROR    = 3;
+  const unsigned short INTERNAL_ERROR   = 4;
+
+  /**
+   * Create a new request object.
+   *
+   * @return the request ID.
+   */
+  long createRequest(in nsPIDOMWindow aWindow,
+                     in nsIScriptContext aScriptContext,
+                     out nsIDOMMozSmsRequest aRequest);
+
+  /**
+   * Track an already existing request object.
+   *
+   * @return the request ID.
+   */
+  long addRequest(in nsIDOMMozSmsRequest aRequest);
+
+  void notifySmsSent(in long aRequestId,
+                     in nsIDOMMozSmsMessage aMessage);
+
+  void notifySmsSendFailed(in long aRequestId,
+                           in long aError);
+
+  void notifyGotSms(in long aRequestId,
+                    in nsIDOMMozSmsMessage aMessage);
+
+  void notifyGetSmsFailed(in long aRequestId,
+                          in long aError);
+
+  void notifySmsDeleted(in long aRequestId,
+                        in bool aDeleted);
+
+  void notifySmsDeleteFailed(in long aRequestId,
+                             in long aError);
+
+  void notifyNoMessageInList(in long aRequestId);
+
+  void notifyCreateMessageList(in long aRequestId,
+                               in long aListId,
+                               in nsIDOMMozSmsMessage aMessage);
+
+  void notifyGotNextMessage(in long aRequestId,
+                            in nsIDOMMozSmsMessage aMessage);
+
+  void notifyReadMessageListFailed(in long aRequestId,
+                                   in long aError);
+
+};
--- a/dom/sms/src/SmsCursor.cpp
+++ b/dom/sms/src/SmsCursor.cpp
@@ -110,17 +110,21 @@ SmsCursor::Continue()
   // No message means we are waiting for a message or we got the last one.
   if (!mMessage) {
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
   mMessage = nsnull;
   static_cast<SmsRequest*>(mRequest.get())->Reset();
 
-  PRInt32 requestId = SmsRequestManager::GetInstance()->AddRequest(mRequest);
+  nsCOMPtr<nsISmsRequestManager> requestManager = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+
+  PRInt32 requestId;
+  nsresult rv = requestManager->AddRequest(mRequest, &requestId);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsISmsDatabaseService> smsDBService =
     do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(smsDBService, NS_ERROR_FAILURE);
 
   smsDBService->GetNextMessageInList(mListId, requestId, 0);
 
   return NS_OK;
--- a/dom/sms/src/SmsManager.cpp
+++ b/dom/sms/src/SmsManager.cpp
@@ -141,27 +141,33 @@ SmsManager::Send(JSContext* aCx, JSObjec
   nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
   if (!smsService) {
     NS_ERROR("No SMS Service!");
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIDOMMozSmsRequest> request;
 
-  int requestId =
-    SmsRequestManager::GetInstance()->CreateRequest(mOwner, mScriptContext,
-                                                    getter_AddRefs(request));
-  NS_ASSERTION(request, "The request object must have been created!");
+  nsCOMPtr<nsISmsRequestManager> requestManager = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+
+  PRInt32 requestId;
+  nsresult rv = requestManager->CreateRequest(mOwner, mScriptContext,
+                                              getter_AddRefs(request),
+                                              &requestId);
+  if (NS_FAILED(rv)) {
+    NS_ERROR("Failed to create the request!");
+    return rv;
+  }
 
   nsDependentJSString number;
   number.init(aCx, aNumber);
 
   smsService->Send(number, aMessage, requestId, 0);
 
-  nsresult rv = nsContentUtils::WrapNative(aCx, aGlobal, request, aRequest);
+  rv = nsContentUtils::WrapNative(aCx, aGlobal, request, aRequest);
   if (NS_FAILED(rv)) {
     NS_ERROR("Failed to create the js value!");
     return rv;
   }
 
   return NS_OK;
 }
 
@@ -212,35 +218,47 @@ SmsManager::Send(const jsval& aNumber, c
   NS_ENSURE_TRUE(aReturn->isObject(), NS_ERROR_FAILURE);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SmsManager::GetMessageMoz(PRInt32 aId, nsIDOMMozSmsRequest** aRequest)
 {
-  int requestId =
-    SmsRequestManager::GetInstance()->CreateRequest(mOwner, mScriptContext, aRequest);
-  NS_ASSERTION(*aRequest, "The request object must have been created!");
+  nsCOMPtr<nsISmsRequestManager> requestManager = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+
+  PRInt32 requestId;
+  nsresult rv = requestManager->CreateRequest(mOwner, mScriptContext, aRequest,
+                                              &requestId);
+  if (NS_FAILED(rv)) {
+    NS_ERROR("Failed to create the request!");
+    return rv;
+  }
 
   nsCOMPtr<nsISmsDatabaseService> smsDBService =
     do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(smsDBService, NS_ERROR_FAILURE);
 
   smsDBService->GetMessageMoz(aId, requestId, 0);
 
   return NS_OK;
 }
 
 nsresult
 SmsManager::Delete(PRInt32 aId, nsIDOMMozSmsRequest** aRequest)
 {
-  int requestId =
-    SmsRequestManager::GetInstance()->CreateRequest(mOwner, mScriptContext, aRequest);
-  NS_ASSERTION(*aRequest, "The request object must have been created!");
+  nsCOMPtr<nsISmsRequestManager> requestManager = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+
+  PRInt32 requestId;
+  nsresult rv = requestManager->CreateRequest(mOwner, mScriptContext, aRequest,
+                                              &requestId);
+  if (NS_FAILED(rv)) {
+    NS_ERROR("Failed to create the request!");
+    return rv;
+  }
 
   nsCOMPtr<nsISmsDatabaseService> smsDBService =
     do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(smsDBService, NS_ERROR_FAILURE);
 
   smsDBService->DeleteMessage(aId, requestId, 0);
 
   return NS_OK;
@@ -273,19 +291,25 @@ SmsManager::GetMessages(nsIDOMMozSmsFilt
                         nsIDOMMozSmsRequest** aRequest)
 {
   nsCOMPtr<nsIDOMMozSmsFilter> filter = aFilter;
 
   if (!filter) {
     filter = new SmsFilter();
   }
 
-  int requestId =
-    SmsRequestManager::GetInstance()->CreateRequest(mOwner, mScriptContext, aRequest);
-  NS_ASSERTION(*aRequest, "The request object must have been created!");
+  nsCOMPtr<nsISmsRequestManager> requestManager = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+
+  PRInt32 requestId;
+  nsresult rv = requestManager->CreateRequest(mOwner, mScriptContext, aRequest,
+                                              &requestId);
+  if (NS_FAILED(rv)) {
+    NS_ERROR("Failed to create the request!");
+    return rv;
+  }
 
   nsCOMPtr<nsISmsDatabaseService> smsDBService =
     do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(smsDBService, NS_ERROR_FAILURE);
 
   smsDBService->CreateMessageList(filter, aReverse, requestId, 0);
 
   return NS_OK;
--- a/dom/sms/src/SmsRequest.cpp
+++ b/dom/sms/src/SmsRequest.cpp
@@ -36,16 +36,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "SmsRequest.h"
 #include "nsIDOMClassInfo.h"
 #include "nsDOMString.h"
 #include "nsContentUtils.h"
 #include "nsIDOMSmsMessage.h"
 #include "nsIDOMSmsCursor.h"
+#include "nsISmsRequestManager.h"
 
 DOMCI_DATA(MozSmsRequest, mozilla::dom::sms::SmsRequest)
 
 namespace mozilla {
 namespace dom {
 namespace sms {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(SmsRequest)
@@ -87,17 +88,17 @@ NS_IMPL_ADDREF_INHERITED(SmsRequest, nsD
 NS_IMPL_RELEASE_INHERITED(SmsRequest, nsDOMEventTargetHelper)
 
 NS_IMPL_EVENT_HANDLER(SmsRequest, success)
 NS_IMPL_EVENT_HANDLER(SmsRequest, error)
 
 SmsRequest::SmsRequest(nsPIDOMWindow* aWindow, nsIScriptContext* aScriptContext)
   : mResult(JSVAL_VOID)
   , mResultRooted(false)
-  , mError(eNoError)
+  , mError(nsISmsRequestManager::SUCCESS_NO_ERROR)
   , mDone(false)
 {
   // Those vars come from nsDOMEventTargetHelper.
   mOwner = aWindow;
   mScriptContext = aScriptContext;
 }
 
 SmsRequest::~SmsRequest()
@@ -107,17 +108,18 @@ SmsRequest::~SmsRequest()
   }
 }
 
 void
 SmsRequest::Reset()
 {
   NS_ASSERTION(mDone, "mDone should be true if we try to reset!");
   NS_ASSERTION(mResult != JSVAL_VOID, "mResult should be set if we try to reset!");
-  NS_ASSERTION(mError == eNoError, "There should be no error if we try to reset!");
+  NS_ASSERTION(mError == nsISmsRequestManager::SUCCESS_NO_ERROR,
+               "There should be no error if we try to reset!");
 
   if (mResultRooted) {
     UnrootResult();
   }
 
   mResult = JSVAL_VOID;
   mDone = false;
 }
@@ -143,17 +145,18 @@ SmsRequest::SetSuccess(nsIDOMMozSmsMessa
 {
   SetSuccessInternal(aMessage);
 }
 
 void
 SmsRequest::SetSuccess(bool aResult)
 {
   NS_PRECONDITION(!mDone, "mDone shouldn't have been set to true already!");
-  NS_PRECONDITION(mError == eNoError, "mError shouldn't have been set!");
+  NS_PRECONDITION(mError == nsISmsRequestManager::SUCCESS_NO_ERROR,
+                  "mError shouldn't have been set!");
   NS_PRECONDITION(mResult == JSVAL_NULL, "mResult shouldn't have been set!");
 
   mResult.setBoolean(aResult);
   mDone = true;
 }
 
 void
 SmsRequest::SetSuccess(nsIDOMMozSmsCursor* aCursor)
@@ -169,50 +172,52 @@ SmsRequest::SetSuccess(nsIDOMMozSmsCurso
     mCursor = aCursor;
   }
 }
 
 bool
 SmsRequest::SetSuccessInternal(nsISupports* aObject)
 {
   NS_PRECONDITION(!mDone, "mDone shouldn't have been set to true already!");
-  NS_PRECONDITION(mError == eNoError, "mError shouldn't have been set!");
+  NS_PRECONDITION(mError == nsISmsRequestManager::SUCCESS_NO_ERROR,
+                  "mError shouldn't have been set!");
   NS_PRECONDITION(mResult == JSVAL_VOID, "mResult shouldn't have been set!");
 
   JSContext* cx = mScriptContext->GetNativeContext();
   NS_ASSERTION(cx, "Failed to get a context!");
 
   JSObject* global = mScriptContext->GetNativeGlobal();
   NS_ASSERTION(global, "Failed to get global object!");
 
   JSAutoRequest ar(cx);
   JSAutoEnterCompartment ac;
   if (!ac.enter(cx, global)) {
-    SetError(eInternalError);
+    SetError(nsISmsRequestManager::INTERNAL_ERROR);
     return false;
   }
 
   RootResult();
 
   if (NS_FAILED(nsContentUtils::WrapNative(cx, global, aObject, &mResult))) {
     UnrootResult();
     mResult = JSVAL_VOID;
-    SetError(eInternalError);
+    SetError(nsISmsRequestManager::INTERNAL_ERROR);
     return false;
   }
 
   mDone = true;
   return true;
 }
 
 void
-SmsRequest::SetError(ErrorType aError)
+SmsRequest::SetError(PRInt32 aError)
 {
   NS_PRECONDITION(!mDone, "mDone shouldn't have been set to true already!");
-  NS_PRECONDITION(mError == eNoError, "mError shouldn't have been set!");
+  NS_PRECONDITION(mError == nsISmsRequestManager::SUCCESS_NO_ERROR,
+                  "mError shouldn't have been set!");
   NS_PRECONDITION(mResult == JSVAL_VOID, "mResult shouldn't have been set!");
 
   mDone = true;
   mError = aError;
   mCursor = nsnull;
 }
 
 NS_IMETHODIMP
@@ -226,42 +231,45 @@ SmsRequest::GetReadyState(nsAString& aRe
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SmsRequest::GetError(nsAString& aError)
 {
   if (!mDone) {
-    NS_ASSERTION(mError == eNoError,
+    NS_ASSERTION(mError == nsISmsRequestManager::SUCCESS_NO_ERROR,
                  "There should be no error if the request is still processing!");
 
     SetDOMStringToNull(aError);
     return NS_OK;
   }
 
-  NS_ASSERTION(mError == eNoError || mResult == JSVAL_VOID,
+  NS_ASSERTION(mError == nsISmsRequestManager::SUCCESS_NO_ERROR ||
+               mResult == JSVAL_VOID,
                "mResult should be void when there is an error!");
 
   switch (mError) {
-    case eNoError:
+    case nsISmsRequestManager::SUCCESS_NO_ERROR:
       SetDOMStringToNull(aError);
       break;
-    case eNoSignalError:
+    case nsISmsRequestManager::NO_SIGNAL_ERROR:
       aError.AssignLiteral("NoSignalError");
       break;
-    case eNotFoundError:
+    case nsISmsRequestManager::NOT_FOUND_ERROR:
       aError.AssignLiteral("NotFoundError");
       break;
-    case eUnknownError:
+    case nsISmsRequestManager::UNKNOWN_ERROR:
       aError.AssignLiteral("UnknownError");
       break;
-    case eInternalError:
+    case nsISmsRequestManager::INTERNAL_ERROR:
       aError.AssignLiteral("InternalError");
       break;
+    default:
+      MOZ_ASSERT(false, "Unknown error value.");
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SmsRequest::GetResult(jsval* aResult)
 {
--- a/dom/sms/src/SmsRequest.h
+++ b/dom/sms/src/SmsRequest.h
@@ -49,29 +49,16 @@ namespace dom {
 namespace sms {
 
 class SmsRequest : public nsIDOMMozSmsRequest
                  , public nsDOMEventTargetHelper
 {
 public:
   friend class SmsRequestManager;
 
-  /**
-   * All SMS related errors that could apply to SmsRequest objects.
-   * Make sure to keep this list in sync with the list in:
-   * embedding/android/GeckoSmsManager.java
-   */
-  enum ErrorType {
-    eNoError = 0,
-    eNoSignalError,
-    eNotFoundError,
-    eUnknownError,
-    eInternalError,
-  };
-
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMMOZSMSREQUEST
 
   NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(SmsRequest,
                                                          nsDOMEventTargetHelper)
 
@@ -106,17 +93,17 @@ private:
   /**
    * Set the object in a success state with the result being a SmsCursor.
    */
   void SetSuccess(nsIDOMMozSmsCursor* aCursor);
 
   /**
    * Set the object in an error state with the error type being aError.
    */
-  void SetError(ErrorType aError);
+  void SetError(PRInt32 aError);
 
   /**
    * Set the object in a success state with the result being the nsISupports
    * object in parameter.
    * @return whether setting the object was a success
    */
   bool SetSuccessInternal(nsISupports* aObject);
 
@@ -124,17 +111,17 @@ private:
    * Return the internal cursor that is saved when
    * SetSuccess(nsIDOMMozSmsCursor*) is used.
    * Returns null if this request isn't associated to an cursor.
    */
   nsIDOMMozSmsCursor* GetCursor();
 
   jsval     mResult;
   bool      mResultRooted;
-  ErrorType mError;
+  PRInt32   mError;
   bool      mDone;
   nsCOMPtr<nsIDOMMozSmsCursor> mCursor;
 
   NS_DECL_EVENT_HANDLER(success)
   NS_DECL_EVENT_HANDLER(error)
 };
 
 inline nsIDOMMozSmsCursor*
--- a/dom/sms/src/SmsRequestManager.cpp
+++ b/dom/sms/src/SmsRequestManager.cpp
@@ -46,85 +46,69 @@
  */
 #define SUCCESS_EVENT_NAME NS_LITERAL_STRING("success")
 #define ERROR_EVENT_NAME   NS_LITERAL_STRING("error")
 
 namespace mozilla {
 namespace dom {
 namespace sms {
 
-SmsRequestManager* SmsRequestManager::sInstance = nsnull;
-
-void
-SmsRequestManager::Init()
-{
-  NS_PRECONDITION(!sInstance,
-                  "sInstance shouldn't be set. Did you call Init() twice?");
-  sInstance = new SmsRequestManager();
-}
+NS_IMPL_ISUPPORTS1(SmsRequestManager, nsISmsRequestManager)
 
-void
-SmsRequestManager::Shutdown()
-{
-  NS_PRECONDITION(sInstance, "sInstance should be set. Did you call Init()?");
-
-  delete sInstance;
-  sInstance = nsnull;
-}
-
-/* static */ SmsRequestManager*
-SmsRequestManager::GetInstance()
-{
-  return sInstance;
-}
-
-PRInt32
-SmsRequestManager::AddRequest(nsIDOMMozSmsRequest* aRequest)
+NS_IMETHODIMP
+SmsRequestManager::AddRequest(nsIDOMMozSmsRequest* aRequest,
+                              PRInt32* aRequestId)
 {
   // TODO: merge with CreateRequest
   PRInt32 size = mRequests.Count();
 
   // Look for empty slots.
   for (PRInt32 i=0; i<size; ++i) {
     if (mRequests[i]) {
       continue;
     }
 
     mRequests.ReplaceObjectAt(aRequest, i);
-    return i;
+    *aRequestId = i;
+    return NS_OK;
   }
 
   mRequests.AppendObject(aRequest);
-  return size;
+  *aRequestId = size;
+  return NS_OK;
 }
 
-PRInt32
+
+NS_IMETHODIMP
 SmsRequestManager::CreateRequest(nsPIDOMWindow* aWindow,
                                  nsIScriptContext* aScriptContext,
-                                 nsIDOMMozSmsRequest** aRequest)
+                                 nsIDOMMozSmsRequest** aRequest,
+                                 PRInt32* aRequestId)
 {
   nsCOMPtr<nsIDOMMozSmsRequest> request =
     new SmsRequest(aWindow, aScriptContext);
 
   PRInt32 size = mRequests.Count();
 
   // Look for empty slots.
   for (PRInt32 i=0; i<size; ++i) {
     if (mRequests[i]) {
       continue;
     }
 
     mRequests.ReplaceObjectAt(request, i);
     NS_ADDREF(*aRequest = request);
-    return i;
+    *aRequestId = i;
+    return NS_OK;
   }
 
   mRequests.AppendObject(request);
   NS_ADDREF(*aRequest = request);
-  return size;
+  *aRequestId = size;
+  return NS_OK;
 }
 
 nsresult
 SmsRequestManager::DispatchTrustedEventToRequest(const nsAString& aEventName,
                                                  nsIDOMMozSmsRequest* aRequest)
 {
   nsRefPtr<nsDOMEvent> event = new nsDOMEvent(nsnull, nsnull);
   nsresult rv = event->InitEvent(aEventName, false, false);
@@ -144,123 +128,123 @@ SmsRequestManager::GetRequest(PRInt32 aR
                "Got an invalid request id or it has been already deleted!");
 
   // It's safe to use the static_cast here given that we did call
   // |new SmsRequest()|.
   return static_cast<SmsRequest*>(mRequests[aRequestId]);
 }
 
 template <class T>
-void
+nsresult
 SmsRequestManager::NotifySuccess(PRInt32 aRequestId, T aParam)
 {
   SmsRequest* request = GetRequest(aRequestId);
   request->SetSuccess(aParam);
 
-  DispatchTrustedEventToRequest(SUCCESS_EVENT_NAME, request);
+  nsresult rv = DispatchTrustedEventToRequest(SUCCESS_EVENT_NAME, request);
 
   mRequests.ReplaceObjectAt(nsnull, aRequestId);
+  return rv;
 }
 
-void
-SmsRequestManager::NotifyError(PRInt32 aRequestId, SmsRequest::ErrorType aError)
+nsresult
+SmsRequestManager::NotifyError(PRInt32 aRequestId, PRInt32 aError)
 {
   SmsRequest* request = GetRequest(aRequestId);
   request->SetError(aError);
 
-  DispatchTrustedEventToRequest(ERROR_EVENT_NAME, request);
+  nsresult rv = DispatchTrustedEventToRequest(ERROR_EVENT_NAME, request);
 
   mRequests.ReplaceObjectAt(nsnull, aRequestId);
+  return rv;
 }
 
-void
+NS_IMETHODIMP
 SmsRequestManager::NotifySmsSent(PRInt32 aRequestId, nsIDOMMozSmsMessage* aMessage)
 {
-  NotifySuccess<nsIDOMMozSmsMessage*>(aRequestId, aMessage);
+  return NotifySuccess<nsIDOMMozSmsMessage*>(aRequestId, aMessage);
 }
 
-void
-SmsRequestManager::NotifySmsSendFailed(PRInt32 aRequestId, SmsRequest::ErrorType aError)
+NS_IMETHODIMP
+SmsRequestManager::NotifySmsSendFailed(PRInt32 aRequestId, PRInt32 aError)
 {
-  NotifyError(aRequestId, aError);
+  return NotifyError(aRequestId, aError);
 }
 
-void
+NS_IMETHODIMP
 SmsRequestManager::NotifyGotSms(PRInt32 aRequestId, nsIDOMMozSmsMessage* aMessage)
 {
-  NotifySuccess<nsIDOMMozSmsMessage*>(aRequestId, aMessage);
+  return NotifySuccess<nsIDOMMozSmsMessage*>(aRequestId, aMessage);
 }
 
-void
-SmsRequestManager::NotifyGetSmsFailed(PRInt32 aRequestId,
-                                      SmsRequest::ErrorType aError)
+NS_IMETHODIMP
+SmsRequestManager::NotifyGetSmsFailed(PRInt32 aRequestId, PRInt32 aError)
 {
-  NotifyError(aRequestId, aError);
+  return NotifyError(aRequestId, aError);
 }
 
-void
+NS_IMETHODIMP
 SmsRequestManager::NotifySmsDeleted(PRInt32 aRequestId, bool aDeleted)
 {
-  NotifySuccess<bool>(aRequestId, aDeleted);
+  return NotifySuccess<bool>(aRequestId, aDeleted);
 }
 
-void
-SmsRequestManager::NotifySmsDeleteFailed(PRInt32 aRequestId, SmsRequest::ErrorType aError)
+NS_IMETHODIMP
+SmsRequestManager::NotifySmsDeleteFailed(PRInt32 aRequestId, PRInt32 aError)
 {
-  NotifyError(aRequestId, aError);
+  return NotifyError(aRequestId, aError);
 }
 
-void
+NS_IMETHODIMP
 SmsRequestManager::NotifyNoMessageInList(PRInt32 aRequestId)
 {
   SmsRequest* request = GetRequest(aRequestId);
 
   nsCOMPtr<nsIDOMMozSmsCursor> cursor = request->GetCursor();
   if (!cursor) {
     cursor = new SmsCursor();
   } else {
     static_cast<SmsCursor*>(cursor.get())->Disconnect();
   }
 
-  NotifySuccess<nsIDOMMozSmsCursor*>(aRequestId, cursor);
+  return NotifySuccess<nsIDOMMozSmsCursor*>(aRequestId, cursor);
 }
 
-void
+NS_IMETHODIMP
 SmsRequestManager::NotifyCreateMessageList(PRInt32 aRequestId, PRInt32 aListId,
                                            nsIDOMMozSmsMessage* aMessage)
 {
   SmsRequest* request = GetRequest(aRequestId);
 
   nsCOMPtr<SmsCursor> cursor = new SmsCursor(aListId, request);
   cursor->SetMessage(aMessage);
 
-  NotifySuccess<nsIDOMMozSmsCursor*>(aRequestId, cursor);
+  return NotifySuccess<nsIDOMMozSmsCursor*>(aRequestId, cursor);
 }
 
-void
+NS_IMETHODIMP
 SmsRequestManager::NotifyGotNextMessage(PRInt32 aRequestId, nsIDOMMozSmsMessage* aMessage)
 {
   SmsRequest* request = GetRequest(aRequestId);
 
   nsCOMPtr<SmsCursor> cursor = static_cast<SmsCursor*>(request->GetCursor());
   NS_ASSERTION(cursor, "Request should have an cursor in that case!");
   cursor->SetMessage(aMessage);
 
-  NotifySuccess<nsIDOMMozSmsCursor*>(aRequestId, cursor);
+  return NotifySuccess<nsIDOMMozSmsCursor*>(aRequestId, cursor);
 }
 
-void
-SmsRequestManager::NotifyReadMessageListFailed(PRInt32 aRequestId,
-                                               SmsRequest::ErrorType aError)
+NS_IMETHODIMP
+SmsRequestManager::NotifyReadMessageListFailed(PRInt32 aRequestId, PRInt32 aError)
 {
   SmsRequest* request = GetRequest(aRequestId);
 
   nsCOMPtr<nsIDOMMozSmsCursor> cursor = request->GetCursor();
   if (cursor) {
     static_cast<SmsCursor*>(cursor.get())->Disconnect();
   }
 
-  NotifyError(aRequestId, aError);
+  return NotifyError(aRequestId, aError);
 }
 
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
--- a/dom/sms/src/SmsRequestManager.h
+++ b/dom/sms/src/SmsRequestManager.h
@@ -36,60 +36,36 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_dom_sms_SmsRequestManager_h
 #define mozilla_dom_sms_SmsRequestManager_h
 
 #include "nsCOMArray.h"
 #include "SmsRequest.h"
-
-class nsIDOMMozSmsRequest;
-class nsPIDOMWindow;
-class nsIScriptContext;
-class nsIDOMMozSmsMessage;
+#include "nsISmsRequestManager.h"
 
 namespace mozilla {
 namespace dom {
 namespace sms {
 
-class SmsRequestManager
+class SmsRequestManager : nsISmsRequestManager
 {
 public:
-  static void Init();
-  static void Shutdown();
-  static SmsRequestManager* GetInstance();
-
-  PRInt32 CreateRequest(nsPIDOMWindow* aWindow,
-                        nsIScriptContext* aScriptContext,
-                        nsIDOMMozSmsRequest** aRequest);
-
-  PRInt32 AddRequest(nsIDOMMozSmsRequest* aRequest);
-
-  void NotifySmsSent(PRInt32 aRequestId, nsIDOMMozSmsMessage* aMessage);
-  void NotifySmsSendFailed(PRInt32 aRequestId, SmsRequest::ErrorType aError);
-  void NotifyGotSms(PRInt32 aRequestId, nsIDOMMozSmsMessage* aMessage);
-  void NotifyGetSmsFailed(PRInt32 aRequestId, SmsRequest::ErrorType aError);
-  void NotifySmsDeleted(PRInt32 aRequestId, bool aDeleted);
-  void NotifySmsDeleteFailed(PRInt32 aRequestId, SmsRequest::ErrorType aError);
-  void NotifyNoMessageInList(PRInt32 aRequestId);
-  void NotifyCreateMessageList(PRInt32 aRequestId, PRInt32 aListId, nsIDOMMozSmsMessage* aMessage);
-  void NotifyGotNextMessage(PRInt32 aRequestId, nsIDOMMozSmsMessage* aMessage);
-  void NotifyReadMessageListFailed(PRInt32 aRequestId, SmsRequest::ErrorType aError);
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSISMSREQUESTMANAGER
 
 private:
-  static SmsRequestManager* sInstance;
-
   nsresult DispatchTrustedEventToRequest(const nsAString& aEventName,
                                          nsIDOMMozSmsRequest* aRequest);
   SmsRequest* GetRequest(PRInt32 aRequestId);
 
   template <class T>
-  void NotifySuccess(PRInt32 aRequestId, T aParam);
-  void NotifyError(PRInt32 aRequestId, SmsRequest::ErrorType aError);
+  nsresult NotifySuccess(PRInt32 aRequestId, T aParam);
+  nsresult NotifyError(PRInt32 aRequestId, PRInt32 aError);
 
   nsCOMArray<nsIDOMMozSmsRequest> mRequests;
 };
 
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/sms/src/ipc/SmsChild.cpp
+++ b/dom/sms/src/ipc/SmsChild.cpp
@@ -95,145 +95,151 @@ SmsChild::RecvNotifyRequestSmsSent(const
                                    const PRInt32& aRequestId,
                                    const PRUint64& aProcessId)
 {
   if (ContentChild::GetSingleton()->GetID() != aProcessId) {
     return true;
   }
 
   nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(aMessage);
-  SmsRequestManager::GetInstance()->NotifySmsSent(aRequestId, message);
+  nsCOMPtr<nsISmsRequestManager> requestManager = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+  requestManager->NotifySmsSent(aRequestId, message);
 
   return true;
 }
 
 bool
 SmsChild::RecvNotifyRequestSmsSendFailed(const PRInt32& aError,
                                          const PRInt32& aRequestId,
                                          const PRUint64& aProcessId)
 {
   if (ContentChild::GetSingleton()->GetID() != aProcessId) {
     return true;
   }
 
-  SmsRequestManager::GetInstance()->NotifySmsSendFailed(aRequestId,
-                                                        SmsRequest::ErrorType(aError));
+  nsCOMPtr<nsISmsRequestManager> requestManager = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+  requestManager->NotifySmsSendFailed(aRequestId, aError);
 
   return true;
 }
 
 bool
 SmsChild::RecvNotifyRequestGotSms(const SmsMessageData& aMessage,
                                   const PRInt32& aRequestId,
                                   const PRUint64& aProcessId)
 {
   if (ContentChild::GetSingleton()->GetID() != aProcessId) {
     return true;
   }
 
   nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(aMessage);
-  SmsRequestManager::GetInstance()->NotifyGotSms(aRequestId, message);
+  nsCOMPtr<nsISmsRequestManager> requestManager = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+  requestManager->NotifyGotSms(aRequestId, message);
 
   return true;
 }
 
 bool
 SmsChild::RecvNotifyRequestGetSmsFailed(const PRInt32& aError,
                                         const PRInt32& aRequestId,
                                         const PRUint64& aProcessId)
 {
   if (ContentChild::GetSingleton()->GetID() != aProcessId) {
     return true;
   }
 
-  SmsRequestManager::GetInstance()->NotifyGetSmsFailed(aRequestId,
-                                                       SmsRequest::ErrorType(aError));
+  nsCOMPtr<nsISmsRequestManager> requestManager = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+  requestManager->NotifyGetSmsFailed(aRequestId, aError);
 
   return true;
 }
 
 bool
 SmsChild::RecvNotifyRequestSmsDeleted(const bool& aDeleted,
                                       const PRInt32& aRequestId,
                                       const PRUint64& aProcessId)
 {
   if (ContentChild::GetSingleton()->GetID() != aProcessId) {
     return true;
   }
 
-  SmsRequestManager::GetInstance()->NotifySmsDeleted(aRequestId, aDeleted);
+  nsCOMPtr<nsISmsRequestManager> requestManager = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+  requestManager->NotifySmsDeleted(aRequestId, aDeleted);
 
   return true;
 }
 
 bool
 SmsChild::RecvNotifyRequestSmsDeleteFailed(const PRInt32& aError,
                                            const PRInt32& aRequestId,
                                            const PRUint64& aProcessId)
 {
   if (ContentChild::GetSingleton()->GetID() != aProcessId) {
     return true;
   }
 
-  SmsRequestManager::GetInstance()->NotifySmsDeleteFailed(aRequestId,
-                                                          SmsRequest::ErrorType(aError));
+  nsCOMPtr<nsISmsRequestManager> requestManager = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+  requestManager->NotifySmsDeleteFailed(aRequestId, aError);
 
   return true;
 }
 
 bool
 SmsChild::RecvNotifyRequestNoMessageInList(const PRInt32& aRequestId,
                                            const PRUint64& aProcessId)
 {
   if (ContentChild::GetSingleton()->GetID() != aProcessId) {
     return true;
   }
 
-  SmsRequestManager::GetInstance()->NotifyNoMessageInList(aRequestId);
+  nsCOMPtr<nsISmsRequestManager> requestManager = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+  requestManager->NotifyNoMessageInList(aRequestId);
   return true;
 }
 
 bool
 SmsChild::RecvNotifyRequestCreateMessageList(const PRInt32& aListId,
                                              const SmsMessageData& aMessageData,
                                              const PRInt32& aRequestId,
                                              const PRUint64& aProcessId)
 {
   if (ContentChild::GetSingleton()->GetID() != aProcessId) {
     return true;
   }
 
   nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(aMessageData);
-  SmsRequestManager::GetInstance()->NotifyCreateMessageList(aRequestId, aListId, message);
+  nsCOMPtr<nsISmsRequestManager> requestManager = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+  requestManager->NotifyCreateMessageList(aRequestId, aListId, message);
   return true;
 }
 
 bool
 SmsChild::RecvNotifyRequestGotNextMessage(const SmsMessageData& aMessageData,
                                           const PRInt32& aRequestId,
                                           const PRUint64& aProcessId)
 {
   if (ContentChild::GetSingleton()->GetID() != aProcessId) {
     return true;
   }
 
   nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(aMessageData);
-  SmsRequestManager::GetInstance()->NotifyGotNextMessage(aRequestId, message);
+  nsCOMPtr<nsISmsRequestManager> requestManager = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+  requestManager->NotifyGotNextMessage(aRequestId, message);
   return true;
 }
 
 bool
 SmsChild::RecvNotifyRequestReadListFailed(const PRInt32& aError,
                                           const PRInt32& aRequestId,
                                           const PRUint64& aProcessId)
 {
   if (ContentChild::GetSingleton()->GetID() != aProcessId) {
     return true;
   }
 
-  SmsRequestManager::GetInstance()->NotifyReadMessageListFailed(aRequestId,
-                                                                SmsRequest::ErrorType(aError));
+  nsCOMPtr<nsISmsRequestManager> requestManager = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+  requestManager->NotifyReadMessageListFailed(aRequestId, aError);
   return true;
 }
 
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
--- a/dom/sms/src/ril/SmsService.cpp
+++ b/dom/sms/src/ril/SmsService.cpp
@@ -84,17 +84,17 @@ SmsService::Send(const nsAString& aNumbe
                  const nsAString& aMessage,
                  PRInt32 aRequestId,
                  PRUint64 aProcessId)
 {
   if (!mRIL) {
     return NS_OK;
   }
 
-  mRIL->SendSMS(aNumber, aMessage);
+  mRIL->SendSMS(aNumber, aMessage, aRequestId, aProcessId);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SmsService::CreateSmsMessage(PRInt32 aId,
                              const nsAString& aDelivery,
                              const nsAString& aSender,
                              const nsAString& aReceiver,
--- a/dom/system/b2g/RadioInterfaceLayer.js
+++ b/dom/system/b2g/RadioInterfaceLayer.js
@@ -54,21 +54,26 @@ const RADIOINTERFACELAYER_CID =
 const DATACALLINFO_CID =
   Components.ID("{ef474cd9-94f7-4c05-a31b-29b9de8a10d2}");
 
 const nsIAudioManager = Ci.nsIAudioManager;
 const nsIRadioInterfaceLayer = Ci.nsIRadioInterfaceLayer;
 
 const kSmsReceivedObserverTopic          = "sms-received";
 const DOM_SMS_DELIVERY_RECEIVED          = "received";
+const DOM_SMS_DELIVERY_SENT              = "sent";
 
 XPCOMUtils.defineLazyServiceGetter(this, "gSmsService",
                                    "@mozilla.org/sms/smsservice;1",
                                    "nsISmsService");
 
+XPCOMUtils.defineLazyServiceGetter(this, "gSmsRequestManager",
+                                   "@mozilla.org/sms/smsrequestmanager;1",
+                                   "nsISmsRequestManager");
+
 function convertRILCallState(state) {
   switch (state) {
     case RIL.CALL_STATE_ACTIVE:
       return nsIRadioInterfaceLayer.CALL_STATE_CONNECTED;
     case RIL.CALL_STATE_HOLDING:
       return nsIRadioInterfaceLayer.CALL_STATE_HELD;
     case RIL.CALL_STATE_DIALING:
       return nsIRadioInterfaceLayer.CALL_STATE_DIALING;
@@ -196,16 +201,19 @@ RadioInterfaceLayer.prototype = {
         this.currentState.radioState = message.radioState;
         break;
       case "cardstatechange":
         this.currentState.cardState = message.cardState;
         break;
       case "sms-received":
         this.handleSmsReceived(message);
         return;
+      case "sms-sent":
+        this.handleSmsSent(message);
+        return;
       case "datacallstatechange":
         this.handleDataCallState(message.datacall);
         break;
       case "datacalllist":
         this.handleDataCallList(message);
         break;
       default:
         throw new Error("Don't know about this message type: " + message.type);
@@ -305,16 +313,28 @@ RadioInterfaceLayer.prototype = {
                                            DOM_SMS_DELIVERY_RECEIVED,
                                            message.sender || null,
                                            message.receiver || null,
                                            message.body || null,
                                            message.timestamp);
     Services.obs.notifyObservers(sms, kSmsReceivedObserverTopic, null);
   },
 
+  handleSmsSent: function handleSmsSent(message) {
+    let message = gSmsService.createSmsMessage(-1,
+                                               DOM_SMS_DELIVERY_SENT,
+                                               message.SMSC,
+                                               message.number,
+                                               message.body,
+                                               Date.now());
+    //TODO At this point we should save the sms into the DB (bug 712809)
+    //TODO handle errors (bug XXX)
+    gSmsRequestManager.notifySmsSent(message.requestId, message);
+  },
+
   /**
    * Handle data call state changes.
    */
   handleDataCallState: function handleDataCallState(datacall) {
     this._deliverDataCallCallback("dataCallStateChanged",
                                   [datacall.cid, datacall.ifname, datacall.state]);
   },
 
@@ -397,20 +417,22 @@ RadioInterfaceLayer.prototype = {
 
   getNumberOfMessagesForText: function getNumberOfMessagesForText(text) {
     //TODO: this assumes 7bit encoding, which is incorrect. Need to look
     // for characters not supported by 7bit alphabets and then calculate
     // length in UCS2 encoding.
     return Math.ceil(text.length / 160);
   },
 
-  sendSMS: function sendSMS(number, message) {
+  sendSMS: function sendSMS(number, message, requestId, processId) {
     this.worker.postMessage({type: "sendSMS",
                              number: number,
-                             body: message});
+                             body: message,
+                             requestId: requestId,
+                             processId: processId});
   },
 
   _callbacks: null,
   _enumerationCallbacks: null,
 
   registerCallback: function registerCallback(callback) {
     if (this._callbacks) {
       if (this._callbacks.indexOf(callback) != -1) {
--- a/dom/system/b2g/nsIRadioInterfaceLayer.idl
+++ b/dom/system/b2g/nsIRadioInterfaceLayer.idl
@@ -111,17 +111,17 @@ interface nsIRILDataCallback : nsISuppor
    *        Array of nsIRILDataCallInfo objects.
    * @param length
    *        Lenght of the aforementioned array.
    */
   void receiveDataCallList([array,size_is(length)] in nsIRILDataCallInfo dataCalls,
                            in unsigned long length);
 };
 
-[scriptable, uuid(9b7e3a01-9c45-4af3-81bb-1bf08a842226)]
+[scriptable, uuid(aeb7ffe7-7d3a-4b7d-9b59-b6d3ae1c72ed)]
 interface nsIRadioInterfaceLayer : nsISupports
 {
   const unsigned short CALL_STATE_UNKNOWN = 0;
   const unsigned short CALL_STATE_DIALING = 1;
   const unsigned short CALL_STATE_RINGING = 2;
   const unsigned short CALL_STATE_BUSY = 3;
   const unsigned short CALL_STATE_CONNECTING = 4;
   const unsigned short CALL_STATE_CONNECTED = 5;
@@ -172,18 +172,21 @@ interface nsIRadioInterfaceLayer : nsISu
                      in DOMString apn,
                      in DOMString user,
                      in DOMString passwd,
                      in long chappap,
                      in DOMString pdptype);
   void deactivateDataCall(in DOMString cid,
                           in DOMString reason);
   void getDataCallList();
-  
+
   void registerDataCallCallback(in nsIRILDataCallback callback);
   void unregisterDataCallCallback(in nsIRILDataCallback callback);
 
   /**
    * SMS-related functionality.
    */
   unsigned short getNumberOfMessagesForText(in DOMString text);
-  void sendSMS(in DOMString number, in DOMString message);
+  void sendSMS(in DOMString number,
+               in DOMString message,
+               in long requestId,
+               in unsigned long long processId);
 };
--- a/dom/system/b2g/ril_worker.js
+++ b/dom/system/b2g/ril_worker.js
@@ -433,22 +433,24 @@ let Buf = {
 
   /**
    * Process one parcel.
    */
   processParcel: function processParcel() {
     let response_type = this.readUint32();
     let length = this.readIncoming - UINT32_SIZE;
 
-    let request_type;
+    let request_type, options;
     if (response_type == RESPONSE_TYPE_SOLICITED) {
       let token = this.readUint32();
       let error = this.readUint32();
       length -= 2 * UINT32_SIZE;
-      request_type = this.tokenRequestMap[token];
+
+      options = this.tokenRequestMap[token];
+      request_type = options.rilRequestType;
       if (error) {
         //TODO
         if (DEBUG) {
           debug("Received error " + error + " for solicited parcel type " +
                 request_type);
         }
         return;
       }
@@ -462,33 +464,41 @@ let Buf = {
       request_type = this.readUint32();
       length -= UINT32_SIZE;
       if (DEBUG) debug("Unsolicited response for request type " + request_type);
     } else {
       if (DEBUG) debug("Unknown response type: " + response_type);
       return;
     }
 
-    RIL.handleParcel(request_type, length);
+    RIL.handleParcel(request_type, length, options);
   },
 
   /**
    * Start a new outgoing parcel.
    *
    * @param type
    *        Integer specifying the request type.
+   * @param options [optional]
+   *        Object containing information about the request, e.g. the
+   *        original main thread message object that led to the RIL request. 
    */
-  newParcel: function newParcel(type) {
+  newParcel: function newParcel(type, options) {
     if (DEBUG) debug("New outgoing parcel of type " + type);
     // We're going to leave room for the parcel size at the beginning.
     this.outgoingIndex = PARCEL_SIZE_SIZE;
     this.writeUint32(type);
     let token = this.token;
     this.writeUint32(token);
-    this.tokenRequestMap[token] = type;
+
+    if (!options) {
+      options = {};
+    }
+    options.rilRequestType = type;
+    this.tokenRequestMap[token] = options;
     this.token++;
     return token;
   },
 
   /**
    * Communicate with the RIL IPC thread.
    */
   sendParcel: function sendParcel() {
@@ -748,37 +758,42 @@ let RIL = {
    */
   rejectCall: function rejectCall() {
     Buf.simpleRequest(REQUEST_UDUB);
   },
 
   /**
    * Send an SMS.
    *
-   * @param smscPDU
+   * The `options` parameter object should contain the following attributes:
+   *
+   * @param SMSC
    *        String containing the SMSC PDU in hex format.
-   * @param address
+   * @param number
    *        String containing the recipients address.
    * @param body
    *        String containing the message body.
    * @param dcs
    *        Data coding scheme. One of the PDU_DCS_MSG_CODING_*BITS_ALPHABET
    *        constants.
    * @param bodyLengthInOctets
    *        Byte length of the message body when encoded with the given DCS.
    */
-  sendSMS: function sendSMS(smscPDU, address, body, dcs, bodyLengthInOctets) {
-    let token = Buf.newParcel(REQUEST_SEND_SMS);
+  sendSMS: function sendSMS(options) {
+    let token = Buf.newParcel(REQUEST_SEND_SMS, options);
     //TODO we want to map token to the input values so that on the
     // response from the RIL device we know which SMS request was successful
     // or not. Maybe we should build that functionality into newParcel() and
     // handle it within tokenRequestMap[].
     Buf.writeUint32(2);
-    Buf.writeString(smscPDU);
-    GsmPDUHelper.writeMessage(address, body, dcs, bodyLengthInOctets);
+    Buf.writeString(options.SMSC);
+    GsmPDUHelper.writeMessage(options.number,
+                              options.body,
+                              options.dcs,
+                              options.bodyLengthInOctets);
     Buf.sendParcel();
   },
 
   /**
    * Acknowledge the receipt and handling of an SMS.
    *
    * @param success
    *        Boolean indicating whether the message was successfuly handled.
@@ -902,21 +917,21 @@ let RIL = {
   },
 
   /**
    * Handle incoming requests from the RIL. We find the method that
    * corresponds to the request type. Incidentally, the request type
    * _is_ the method name, so that's easy.
    */
 
-  handleParcel: function handleParcel(request_type, length) {
+  handleParcel: function handleParcel(request_type, length, options) {
     let method = this[request_type];
     if (typeof method == "function") {
       if (DEBUG) debug("Handling parcel as " + method.name);
-      method.call(this, length);
+      method.call(this, length, options);
     }
   }
 };
 
 RIL[REQUEST_GET_SIM_STATUS] = function REQUEST_GET_SIM_STATUS() {
   let iccStatus = {
     cardState:                   Buf.readUint32(), // CARD_STATE_*
     universalPINState:           Buf.readUint32(), // PINSTATE_*
@@ -1059,21 +1074,21 @@ RIL[REQUEST_GPRS_REGISTRATION_STATE] = f
 RIL[REQUEST_OPERATOR] = function REQUEST_OPERATOR(length) {
   let operator = Buf.readStringList();
   Phone.onOperator(operator);
 };
 RIL[REQUEST_RADIO_POWER] = null;
 RIL[REQUEST_DTMF] = function REQUEST_DTMF() {
   Phone.onSendTone();
 };
-RIL[REQUEST_SEND_SMS] = function REQUEST_SEND_SMS() {
-  let messageRef = Buf.readUint32();
-  let ackPDU = Buf.readString();
-  let errorCode = Buf.readUint32();
-  Phone.onSendSMS(messageRef, ackPDU, errorCode);
+RIL[REQUEST_SEND_SMS] = function REQUEST_SEND_SMS(length, options) {
+  options.messageRef = Buf.readUint32();
+  options.ackPDU = Buf.readString();
+  options.errorCode = Buf.readUint32();
+  Phone.onSendSMS(options);
 };
 RIL[REQUEST_SEND_SMS_EXPECT_MORE] = null;
 RIL[REQUEST_SETUP_DATA_CALL] = function REQUEST_SETUP_DATA_CALL() {
   let [cid, ifname, ipaddr, dns, gw] = Buf.readStringList();
   Phone.onSetupDataCall(Buf.lastSolicitedToken, cid, ifname, ipaddr, dns, gw);
 };
 RIL[REQUEST_SIM_IO] = null;
 RIL[REQUEST_SEND_USSD] = null;
@@ -1748,18 +1763,19 @@ let Phone = {
 
   onGetSMSCAddress: function onGetSMSCAddress(smsc) {
     this.SMSC = smsc;
   },
 
   onSetSMSCAddress: function onSetSMSCAddress() {
   },
 
-  onSendSMS: function onSendSMS(messageRef, ackPDU, errorCode) {
-    //TODO
+  onSendSMS: function onSendSMS(options) {
+    options.type = "sms-sent";
+    this.sendDOMMessage(options);
   },
 
   onNewSMS: function onNewSMS(payloadLength) {
     if (!payloadLength) {
       if (DEBUG) debug("Received empty SMS!");
       //TODO: should we acknowledge the SMS here? maybe only after multiple
       //failures.
       return;
@@ -2008,34 +2024,43 @@ let Phone = {
 
   /**
    * Send an SMS.
    *
    * @param number
    *        String containing the recipient number.
    * @param body
    *        String containing the message text.
+   * @param requestId
+   *        String identifying the sms request used by the SmsRequestManager.
+   * @param processId
+   *        String containing the processId for the SmsRequestManager.
    */
   sendSMS: function sendSMS(options) {
     // Get the SMS Center address
     if (!this.SMSC) {
       //TODO: we shouldn't get here, but if we do, we might want to hold on
       // to the message and retry once we know the SMSC... or just notify an
       // error to the mainthread and let them deal with retrying?
       if (DEBUG) {
         debug("Cannot send the SMS. Need to get the SMSC address first.");
       }
       return;
     }
+    // We explicitly save this information on the options object so that we
+    // can refer to it later, in particular on the main thread (where this
+    // object may get sent eventually.)
+    options.SMSC = this.SMSC;
+
     //TODO: verify values on 'options'
     //TODO: the data encoding and length in octets should eventually be
     // computed on the mainthread and passed down to us.
-    RIL.sendSMS(this.SMSC, options.number, options.body,
-                PDU_DCS_MSG_CODING_7BITS_ALPHABET, //TODO: hard-coded for now,
-                Math.ceil(options.body.length * 7 / 8)); //TODO: ditto
+    options.dcs = PDU_DCS_MSG_CODING_7BITS_ALPHABET;
+    options.bodyLengthInOctets = Math.ceil(options.body.length * 7 / 8);
+    RIL.sendSMS(options);
   },
 
   /**
    * Setup a data call (PDP).
    */
   setupDataCall: function setupDataCall(options) {
     if (DEBUG) debug("setupDataCall: " + JSON.stringify(options));
 
--- a/embedding/android/GeckoSmsManager.java
+++ b/embedding/android/GeckoSmsManager.java
@@ -322,19 +322,19 @@ public class GeckoSmsManager
   extends BroadcastReceiver
   implements ISmsManager
 {
   public final static String ACTION_SMS_RECEIVED  = "android.provider.Telephony.SMS_RECEIVED";
   public final static String ACTION_SMS_SENT      = "org.mozilla.gecko.SMS_SENT";
   public final static String ACTION_SMS_DELIVERED = "org.mozilla.gecko.SMS_DELIVERED";
 
   /*
-   * Make sure that the following error codes are in sync with |ErrorType| in:
-   * dom/sms/src/Types.h
-   * The error code are owned by the DOM.
+   * Make sure that the following error codes are in sync with the ones
+   * defined in dom/sms/interfaces/nsISmsRequestManager.idl. They are owned
+   * owned by the interface.
    */
   public final static int kNoError       = 0;
   public final static int kNoSignalError = 1;
   public final static int kNotFoundError = 2;
   public final static int kUnknownError  = 3;
   public final static int kInternalError = 4;
 
   private final static int kMaxMessageSize    = 160;
--- a/ipc/chromium/src/base/histogram.cc
+++ b/ipc/chromium/src/base/histogram.cc
@@ -770,18 +770,18 @@ bool Histogram::SampleSet::Deserialize(v
   int count = 0;
   for (size_t index = 0; index < counts_size; ++index) {
     int i;
     if (!pickle.ReadInt(iter, &i))
       return false;
     counts_.push_back(i);
     count += i;
   }
-  DCHECK_EQ(count, redundant_count_);
-  return count == redundant_count_;
+
+  return true;
 }
 
 //------------------------------------------------------------------------------
 // LinearHistogram: This histogram uses a traditional set of evenly spaced
 // buckets.
 //------------------------------------------------------------------------------
 
 LinearHistogram::~LinearHistogram() {
--- a/js/src/methodjit/BaseCompiler.h
+++ b/js/src/methodjit/BaseCompiler.h
@@ -95,16 +95,30 @@ class BaseCompiler : public MacroAssembl
   public:
     BaseCompiler() : cx(NULL)
     { }
 
     BaseCompiler(JSContext *cx) : cx(cx)
     { }
 };
 
+#ifdef JS_CPU_X64
+inline bool
+VerifyRange(void *start1, size_t size1, void *start2, size_t size2)
+{
+    uintptr_t end1 = uintptr_t(start1) + size1;
+    uintptr_t end2 = uintptr_t(start2) + size2;
+
+    uintptr_t lowest = JS_MIN(uintptr_t(start1), uintptr_t(start2));
+    uintptr_t highest = JS_MAX(end1, end2);
+
+    return (highest - lowest < INT_MAX);
+}
+#endif
+
 // This class wraps JSC::LinkBuffer for Mozilla-specific memory handling.
 // Every return |false| guarantees an OOM that has been correctly propagated,
 // and should continue to propagate.
 class LinkerHelper : public JSC::LinkBuffer
 {
   protected:
     Assembler &masm;
 #ifdef DEBUG
@@ -123,23 +137,17 @@ class LinkerHelper : public JSC::LinkBuf
         JS_ASSERT(verifiedRange);
     }
 
     bool verifyRange(const JSC::JITCode &other) {
 #ifdef DEBUG
         verifiedRange = true;
 #endif
 #ifdef JS_CPU_X64
-        uintptr_t lowest = JS_MIN(uintptr_t(m_code), uintptr_t(other.start()));
-
-        uintptr_t myEnd = uintptr_t(m_code) + m_size;
-        uintptr_t otherEnd = uintptr_t(other.start()) + other.size();
-        uintptr_t highest = JS_MAX(myEnd, otherEnd);
-
-        return (highest - lowest < INT_MAX);
+        return VerifyRange(m_code, m_size, other.start(), other.size());
 #else
         return true;
 #endif
     }
 
     bool verifyRange(JITChunk *chunk) {
         return verifyRange(JSC::JITCode(chunk->code.m_code.executableAddress(),
                                         chunk->code.m_size));
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -661,29 +661,22 @@ MakeJITScript(JSContext *cx, JSScript *s
 
     ScriptAnalysis *analysis = script->analysis();
 
     JITScript *&location = construct ? script->jitCtor : script->jitNormal;
 
     Vector<ChunkDescriptor> chunks(cx);
     Vector<CrossChunkEdge> edges(cx);
 
-    /*
-     * Chunk compilation is not supported on x64, since there is no guarantee
-     * that cross chunk jumps will be patchable even to go to the default shim.
-     */
-#ifndef JS_CPU_X64
     if (script->length < CHUNK_LIMIT || !cx->typeInferenceEnabled()) {
-#endif
         ChunkDescriptor desc;
         desc.begin = 0;
         desc.end = script->length;
         if (!chunks.append(desc))
             return NULL;
-#ifndef JS_CPU_X64
     } else {
         if (!script->ensureRanInference(cx))
             return NULL;
 
         /* Outgoing edges within the current chunk. */
         Vector<CrossChunkEdge> currentEdges(cx);
         uint32_t chunkStart = 0;
 
@@ -866,17 +859,16 @@ MakeJITScript(JSContext *cx, JSScript *s
         if (chunkStart != script->length) {
             ChunkDescriptor desc;
             desc.begin = chunkStart;
             desc.end = script->length;
             if (!chunks.append(desc))
                 return NULL;
         }
     }
-#endif /* !JS_CPU_X64 */
 
     size_t dataSize = sizeof(JITScript)
         + (chunks.length() * sizeof(ChunkDescriptor))
         + (edges.length() * sizeof(CrossChunkEdge));
     uint8_t *cursor = (uint8_t *) OffTheBooks::calloc_(dataSize);
     if (!cursor)
         return NULL;
 
@@ -1254,16 +1246,25 @@ CompileStatus
 mjit::Compiler::generateEpilogue()
 {
     return Compile_Okay;
 }
 
 CompileStatus
 mjit::Compiler::finishThisUp()
 {
+#ifdef JS_CPU_X64
+    /* Generate trampolines to ensure that cross chunk edges are patchable. */
+    for (unsigned i = 0; i < chunkEdges.length(); i++) {
+        chunkEdges[i].sourceTrampoline = stubcc.masm.label();
+        stubcc.masm.move(ImmPtr(NULL), Registers::ScratchReg);
+        stubcc.masm.jump(Registers::ScratchReg);
+    }
+#endif
+
     RETURN_IF_OOM(Compile_Error);
 
     /*
      * Watch for reallocation of the global slots while we were in the middle
      * of compiling due to, e.g. standard class initialization.
      */
     if (globalSlots && globalObj->getRawSlots() != globalSlots)
         return Compile_Retry;
@@ -1784,18 +1785,16 @@ mjit::Compiler::finishThisUp()
     Probes::registerMJITCode(cx, jit,
                              a,
                              (JSActiveFrame**) inlineFrames.begin(),
                              result, masm.size(),
                              result + masm.size(), stubcc.size());
 
     outerChunk.chunk = chunk;
 
-    Repatcher repatch(chunk);
-
     /* Patch all incoming and outgoing cross-chunk jumps. */
     CrossChunkEdge *crossEdges = jit->edges();
     for (unsigned i = 0; i < jit->nedges; i++) {
         CrossChunkEdge &edge = crossEdges[i];
         if (bytecodeInChunk(outerScript->code + edge.source)) {
             JS_ASSERT(!edge.sourceJump1 && !edge.sourceJump2);
             void *label = edge.targetLabel ? edge.targetLabel : edge.shimLabel;
             CodeLocationLabel targetLabel(label);
@@ -1832,22 +1831,25 @@ mjit::Compiler::finishThisUp()
                     /*
                      * Only a single edge needs to be patched; we ensured while
                      * generating chunks that no two cross chunk edges can have
                      * the same source and target. Note that there may not be
                      * an edge to patch, if constant folding determined the
                      * jump is never taken.
                      */
                     edge.sourceJump1 = fullCode.locationOf(oedge.fastJump).executableAddress();
-                    repatch.relink(CodeLocationJump(edge.sourceJump1), targetLabel);
                     if (oedge.slowJump.isSet()) {
                         edge.sourceJump2 =
                             stubCode.locationOf(oedge.slowJump.get()).executableAddress();
-                        repatch.relink(CodeLocationJump(edge.sourceJump2), targetLabel);
                     }
+#ifdef JS_CPU_X64
+                    edge.sourceTrampoline =
+                        stubCode.locationOf(oedge.sourceTrampoline).executableAddress();
+#endif
+                    jit->patchEdge(edge, label);
                     break;
                 }
             }
         } else if (bytecodeInChunk(outerScript->code + edge.target)) {
             JS_ASSERT(!edge.targetLabel);
             JS_ASSERT(jumpMap[edge.target].isSet());
             edge.targetLabel = fullCode.locationOf(jumpMap[edge.target]).executableAddress();
             jit->patchEdge(edge, edge.targetLabel);
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -375,16 +375,20 @@ class Compiler : public BaseCompiler
             return type;
         }
     };
 
     struct OutgoingChunkEdge {
         uint32_t source;
         uint32_t target;
 
+#ifdef JS_CPU_X64
+        Label sourceTrampoline;
+#endif
+
         Jump fastJump;
         MaybeJump slowJump;
     };
 
     struct SlotType
     {
         uint32_t slot;
         VarType vt;
--- a/js/src/methodjit/MethodJIT.cpp
+++ b/js/src/methodjit/MethodJIT.cpp
@@ -1225,23 +1225,44 @@ JITChunk::polyICSectionsLimit() const
 }
 #endif  // JS_POLYIC
 
 void
 JITScript::patchEdge(const CrossChunkEdge &edge, void *label)
 {
     if (edge.sourceJump1 || edge.sourceJump2) {
         JITChunk *sourceChunk = chunk(script->code + edge.source);
-        JSC::CodeLocationLabel targetLabel(label);
         ic::Repatcher repatch(sourceChunk);
 
+#ifdef JS_CPU_X64
+        JS_ASSERT(edge.sourceTrampoline);
+
+        static const uint32_t JUMP_LENGTH = 10;
+
+        if (edge.sourceJump1) {
+            JSC::CodeLocationLabel targetLabel(VerifyRange(edge.sourceJump1, JUMP_LENGTH, label, 0)
+                                               ? label
+                                               : edge.sourceTrampoline);
+            repatch.relink(JSC::CodeLocationJump(edge.sourceJump1), targetLabel);
+        }
+        if (edge.sourceJump2) {
+            JSC::CodeLocationLabel targetLabel(VerifyRange(edge.sourceJump2, JUMP_LENGTH, label, 0)
+                                               ? label
+                                               : edge.sourceTrampoline);
+            repatch.relink(JSC::CodeLocationJump(edge.sourceJump2), targetLabel);
+        }
+        JSC::CodeLocationDataLabelPtr sourcePatch((char*)edge.sourceTrampoline + JUMP_LENGTH);
+        repatch.repatch(sourcePatch, label);
+#else
+        JSC::CodeLocationLabel targetLabel(label);
         if (edge.sourceJump1)
             repatch.relink(JSC::CodeLocationJump(edge.sourceJump1), targetLabel);
         if (edge.sourceJump2)
             repatch.relink(JSC::CodeLocationJump(edge.sourceJump2), targetLabel);
+#endif
     }
     if (edge.jumpTableEntries) {
         for (unsigned i = 0; i < edge.jumpTableEntries->length(); i++)
             *(*edge.jumpTableEntries)[i] = label;
     }
 }
 
 template <typename T>
@@ -1312,16 +1333,19 @@ JITScript::destroyChunk(JSContext *cx, u
         cx->delete_(desc.chunk);
         desc.chunk = NULL;
 
         CrossChunkEdge *edges = this->edges();
         for (unsigned i = 0; i < nedges; i++) {
             CrossChunkEdge &edge = edges[i];
             if (edge.source >= desc.begin && edge.source < desc.end) {
                 edge.sourceJump1 = edge.sourceJump2 = NULL;
+#ifdef JS_CPU_X64
+                edge.sourceTrampoline = NULL;
+#endif
                 if (edge.jumpTableEntries) {
                     cx->delete_(edge.jumpTableEntries);
                     edge.jumpTableEntries = NULL;
                 }
             } else if (edge.target >= desc.begin && edge.target < desc.end) {
                 edge.targetLabel = NULL;
                 patchEdge(edge, edge.shimLabel);
             }
--- a/js/src/methodjit/MethodJIT.h
+++ b/js/src/methodjit/MethodJIT.h
@@ -756,16 +756,24 @@ struct CrossChunkEdge
     /* Bytecode offsets of the source and target of the edge. */
     uint32_t source;
     uint32_t target;
 
     /* Locations of the jump(s) for the source, NULL if not compiled. */
     void *sourceJump1;
     void *sourceJump2;
 
+#ifdef JS_CPU_X64
+    /*
+     * Location of a trampoline for the edge to perform an indirect jump if
+     * out of range, NULL if the source is not compiled.
+     */
+    void *sourceTrampoline;
+#endif
+
     /* Any jump table entries along this edge. */
     typedef Vector<void**,4,SystemAllocPolicy> JumpTableEntryVector;
     JumpTableEntryVector *jumpTableEntries;
 
     /* Location of the label for the target, NULL if not compiled. */
     void *targetLabel;
 
     /*
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -2912,19 +2912,28 @@ NS_IMETHODIMP XPCWrappedNative::GetJSObj
     return NS_OK;
 }
 
 nsIPrincipal*
 XPCWrappedNative::GetObjectPrincipal() const
 {
     nsIPrincipal* principal = GetScope()->GetPrincipal();
 #ifdef DEBUG
+    // Because of inner window reuse, we can have objects with one principal
+    // living in a scope with a different (but same-origin) principal. So
+    // just check same-origin here.
     nsCOMPtr<nsIScriptObjectPrincipal> objPrin(do_QueryInterface(mIdentity));
-    NS_ASSERTION(!objPrin || objPrin->GetPrincipal() == principal,
-                 "Principal mismatch.  Expect bad things to happen");
+    if (objPrin) {
+        bool equal;
+        if (!principal)
+            equal = !objPrin->GetPrincipal();
+        else
+            principal->Equals(objPrin->GetPrincipal(), &equal);
+        NS_ASSERTION(equal, "Principal mismatch.  Expect bad things to happen");
+    }
 #endif
     return principal;
 }
 
 /* readonly attribute nsIXPConnect XPConnect; */
 NS_IMETHODIMP XPCWrappedNative::GetXPConnect(nsIXPConnect * *aXPConnect)
 {
     if (IsValid()) {
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -2868,33 +2868,33 @@ DocumentViewerImpl::SetMinFontSize(PRInt
   // Set the min font on all children of mContainer (even if our min font didn't
   // change, our children's min font may be different, though it would be unusual).
   // Do this first, in case kids are auto-sizing and post reflow commands on
   // our presshell (which should be subsumed into our own style change reflow).
   CallChildren(SetChildMinFontSize, NS_INT32_TO_PTR(aMinFontSize));
 
   // Now change our own min font
   nsPresContext* pc = GetPresContext();
-  if (pc && aMinFontSize != mPresContext->MinFontSize()) {
+  if (pc && aMinFontSize != mPresContext->MinFontSize(nsnull)) {
     pc->SetMinFontSize(aMinFontSize);
   }
 
   // And do the external resources
   mDocument->EnumerateExternalResources(SetExtResourceMinFontSize,
                                         NS_INT32_TO_PTR(aMinFontSize));
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 DocumentViewerImpl::GetMinFontSize(PRInt32* aMinFontSize)
 {
   NS_ENSURE_ARG_POINTER(aMinFontSize);
   nsPresContext* pc = GetPresContext();
-  *aMinFontSize = pc ? pc->MinFontSize() : 0;
+  *aMinFontSize = pc ? pc->MinFontSize(nsnull) : 0;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 DocumentViewerImpl::SetFullZoom(float aFullZoom)
 {
 #ifdef NS_PRINT_PREVIEW
   if (GetIsPrintPreview()) {
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -207,37 +207,17 @@ destroy_loads(const void * aKey, nsRefPt
 
   // NOTE! nsPresContext::operator new() zeroes out all members, so don't
   // bother initializing members to 0.
 
 nsPresContext::nsPresContext(nsIDocument* aDocument, nsPresContextType aType)
   : mType(aType), mDocument(aDocument), mMinFontSize(0),
     mTextZoom(1.0), mFullZoom(1.0), mPageSize(-1, -1), mPPScale(1.0f),
     mViewportStyleOverflow(NS_STYLE_OVERFLOW_AUTO, NS_STYLE_OVERFLOW_AUTO),
-    mImageAnimationModePref(imgIContainer::kNormalAnimMode),
-    // Font sizes default to zero; they will be set in GetFontPreferences
-    mDefaultVariableFont("serif", NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL,
-                         NS_FONT_WEIGHT_NORMAL, NS_FONT_STRETCH_NORMAL, 0, 0),
-    mDefaultFixedFont("monospace", NS_FONT_STYLE_NORMAL,
-                      NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL,
-                      NS_FONT_STRETCH_NORMAL, 0, 0),
-    mDefaultSerifFont("serif", NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL,
-                      NS_FONT_WEIGHT_NORMAL, NS_FONT_STRETCH_NORMAL, 0, 0),
-    mDefaultSansSerifFont("sans-serif", NS_FONT_STYLE_NORMAL,
-                          NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL,
-                          NS_FONT_STRETCH_NORMAL, 0, 0),
-    mDefaultMonospaceFont("monospace", NS_FONT_STYLE_NORMAL,
-                          NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL,
-                          NS_FONT_STRETCH_NORMAL, 0, 0),
-    mDefaultCursiveFont("cursive", NS_FONT_STYLE_NORMAL,
-                        NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL,
-                        NS_FONT_STRETCH_NORMAL, 0, 0),
-    mDefaultFantasyFont("fantasy", NS_FONT_STYLE_NORMAL,
-                        NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL,
-                        NS_FONT_STRETCH_NORMAL, 0, 0)
+    mImageAnimationModePref(imgIContainer::kNormalAnimMode)
 {
   // NOTE! nsPresContext::operator new() zeroes out all members, so don't
   // bother initializing members to 0.
 
   mDoScaledTwips = true;
 
   SetBackgroundImageDraw(true);		// always draw the background
   SetBackgroundColorDraw(true);
@@ -438,53 +418,82 @@ static bool sNoTheme = false;
 // more than one prescontext.
 static bool sLookAndFeelChanged;
 
 // Set to true when ThemeChanged needs to be called on mTheme.  This is used
 // because mTheme is a service, so there's no need to notify it from more than
 // one prescontext.
 static bool sThemeChanged;
 
-void
-nsPresContext::GetFontPreferences()
+const nsPresContext::LangGroupFontPrefs*
+nsPresContext::GetFontPrefsForLang(nsIAtom *aLanguage) const
 {
+  // Get language group for aLanguage:
+
+  nsresult rv;
+  nsIAtom *langGroupAtom = nsnull;
+  if (!aLanguage) {
+    aLanguage = mLanguage;
+  }
+  if (aLanguage && mLangService) {
+    langGroupAtom = mLangService->GetLanguageGroup(aLanguage, &rv);
+  }
+  if (NS_FAILED(rv) || !langGroupAtom) {
+    langGroupAtom = nsGkAtoms::x_western; // Assume x-western is safe...
+  }
+
+  // Look for cached prefs for this lang group.
+  // Most documents will only use one (or very few) language groups. Rather
+  // than have the overhead of a hash lookup, we simply look along what will
+  // typically be a very short (usually of length 1) linked list. There are 31
+  // language groups, so in the worst case scenario we'll need to traverse 31
+  // link items.
+
+  LangGroupFontPrefs *prefs =
+    const_cast<LangGroupFontPrefs*>(&mLangGroupFontPrefs);
+  if (prefs->mLangGroup) { // if initialized
+    DebugOnly<PRUint32> count = 0;
+    for (;;) {
+      NS_ASSERTION(++count < 35, "Lang group count exceeded!!!");
+      if (prefs->mLangGroup == langGroupAtom) {
+        return prefs;
+      }
+      if (!prefs->mNext) {
+        break;
+      }
+      prefs = prefs->mNext;
+    }
+
+    // nothing cached, so go on and fetch the prefs for this lang group:
+    prefs = prefs->mNext = new LangGroupFontPrefs;
+  }
+
+  prefs->mLangGroup = langGroupAtom;
+
   /* Fetch the font prefs to be used -- see bug 61883 for details.
      Not all prefs are needed upfront. Some are fallback prefs intended
      for the GFX font sub-system...
 
   1) unit : assumed to be the same for all language groups -------------
   font.size.unit = px | pt    XXX could be folded in the size... bug 90440
 
   2) attributes for generic fonts --------------------------------------
-  font.default = serif | sans-serif - fallback generic font
+  font.default.[langGroup] = serif | sans-serif - fallback generic font
   font.name.[generic].[langGroup] = current user' selected font on the pref dialog
   font.name-list.[generic].[langGroup] = fontname1, fontname2, ... [factory pre-built list]
   font.size.[generic].[langGroup] = integer - settable by the user
   font.size-adjust.[generic].[langGroup] = "float" - settable by the user
   font.minimum-size.[langGroup] = integer - settable by the user
   */
 
-  mDefaultVariableFont.size = CSSPixelsToAppUnits(16);
-  mDefaultFixedFont.size = CSSPixelsToAppUnits(13);
+  nsCAutoString langGroup;
+  langGroupAtom->ToUTF8String(langGroup);
 
-  // the font prefs are based on langGroup, not actual language
-  nsCAutoString langGroup;
-  if (mLanguage && mLangService) {
-    nsresult rv;
-    nsIAtom *group = mLangService->GetLanguageGroup(mLanguage, &rv);
-    if (NS_SUCCEEDED(rv) && group) {
-      group->ToUTF8String(langGroup);
-    }
-    else {
-      langGroup.AssignLiteral("x-western"); // Assume x-western is safe...
-    }
-  }
-  else {
-    langGroup.AssignLiteral("x-western"); // Assume x-western is safe...
-  }
+  prefs->mDefaultVariableFont.size = CSSPixelsToAppUnits(16);
+  prefs->mDefaultFixedFont.size = CSSPixelsToAppUnits(13);
 
   nsCAutoString pref;
 
   // get the current applicable font-size unit
   enum {eUnit_unknown = -1, eUnit_px, eUnit_pt};
   PRInt32 unit = eUnit_px;
 
   nsAdoptingCString cvalue =
@@ -493,82 +502,87 @@ nsPresContext::GetFontPreferences()
   if (!cvalue.IsEmpty()) {
     if (cvalue.Equals("px")) {
       unit = eUnit_px;
     }
     else if (cvalue.Equals("pt")) {
       unit = eUnit_pt;
     }
     else {
+      // XXX should really send this warning to the user (Error Console?).
+      // And just default to unit = eUnit_px?
       NS_WARNING("unexpected font-size unit -- expected: 'px' or 'pt'");
       unit = eUnit_unknown;
     }
   }
 
   // get font.minimum-size.[langGroup]
 
-  pref.Assign("font.minimum-size.");
-  pref.Append(langGroup);
+  MAKE_FONT_PREF_KEY(pref, "font.minimum-size.", langGroup);
 
   PRInt32 size = Preferences::GetInt(pref.get());
   if (unit == eUnit_px) {
-    mMinimumFontSizePref = CSSPixelsToAppUnits(size);
+    prefs->mMinimumFontSize = CSSPixelsToAppUnits(size);
   }
   else if (unit == eUnit_pt) {
-    mMinimumFontSizePref = CSSPointsToAppUnits(size);
+    prefs->mMinimumFontSize = CSSPointsToAppUnits(size);
   }
 
   nsFont* fontTypes[] = {
-    &mDefaultVariableFont,
-    &mDefaultFixedFont,
-    &mDefaultSerifFont,
-    &mDefaultSansSerifFont,
-    &mDefaultMonospaceFont,
-    &mDefaultCursiveFont,
-    &mDefaultFantasyFont
+    &prefs->mDefaultVariableFont,
+    &prefs->mDefaultFixedFont,
+    &prefs->mDefaultSerifFont,
+    &prefs->mDefaultSansSerifFont,
+    &prefs->mDefaultMonospaceFont,
+    &prefs->mDefaultCursiveFont,
+    &prefs->mDefaultFantasyFont
   };
   PR_STATIC_ASSERT(NS_ARRAY_LENGTH(fontTypes) == eDefaultFont_COUNT);
 
-  // get attributes specific to each generic font
+  // Get attributes specific to each generic font. We do not get the user's
+  // generic-font-name-to-specific-family-name preferences because its the
+  // generic name that should be fed into the cascade. It is up to the GFX
+  // code to look up the font prefs to convert generic names to specific
+  // family names as necessary.
   nsCAutoString generic_dot_langGroup;
   for (PRUint32 eType = 0; eType < ArrayLength(fontTypes); ++eType) {
     generic_dot_langGroup.Assign(kGenericFont[eType]);
     generic_dot_langGroup.Append(langGroup);
 
     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);
+      MAKE_FONT_PREF_KEY(pref, "font.name.variable.", langGroup);
 
       nsAdoptingString value = Preferences::GetString(pref.get());
       if (!value.IsEmpty()) {
-        font->name.Assign(value);
+        prefs->mDefaultVariableFont.name.Assign(value);
       }
       else {
         MAKE_FONT_PREF_KEY(pref, "font.default.", langGroup);
         value = Preferences::GetString(pref.get());
         if (!value.IsEmpty()) {
-          mDefaultVariableFont.name.Assign(value);
+          prefs->mDefaultVariableFont.name.Assign(value);
         }
       } 
     }
     else {
       if (eType == eDefaultFont_Monospace) {
         // This takes care of the confusion whereby people often expect "monospace" 
         // to have the same default font-size as "-moz-fixed" (this tentative
         // size may be overwritten with the specific value for "monospace" when
         // "font.size.monospace.[langGroup]" is read -- see below)
-        font->size = mDefaultFixedFont.size;
+        prefs->mDefaultMonospaceFont.size = prefs->mDefaultFixedFont.size;
       }
       else if (eType != eDefaultFont_Fixed) {
         // all the other generic fonts are initialized with the size of the
         // variable font, but their specific size can supersede later -- see below
-        font->size = mDefaultVariableFont.size;
+        font->size = prefs->mDefaultVariableFont.size;
       }
     }
 
     // Bug 84398: for spec purists, a different font-size only applies to the
     // .variable. and .fixed. fonts and the other fonts should get |font-size-adjust|.
     // The problem is that only GfxWin has the support for |font-size-adjust|. So for
     // parity, we enable the ability to set a different font-size on all platforms.
 
@@ -595,16 +609,18 @@ nsPresContext::GetFontPreferences()
 
 #ifdef DEBUG_rbs
     printf("%s Family-list:%s size:%d sizeAdjust:%.2f\n",
            generic_dot_langGroup.get(),
            NS_ConvertUTF16toUTF8(font->name).get(), font->size,
            font->sizeAdjust);
 #endif
   }
+
+  return prefs;
 }
 
 void
 nsPresContext::GetDocumentColorPreferences()
 {
   PRInt32 useAccessibilityTheme = 0;
   bool usePrefColors = true;
   nsCOMPtr<nsIDocShellTreeItem> docShell(do_QueryReferent(mContainer));
@@ -735,17 +751,17 @@ nsPresContext::GetUserPreferences()
     Preferences::GetInt("browser.display.use_document_fonts") != 0;
 
   // * replace backslashes with Yen signs? (bug 245770)
   mEnableJapaneseTransform =
     Preferences::GetBool("layout.enable_japanese_specific_transform");
 
   mPrefScrollbarSide = Preferences::GetInt("layout.scrollbar.side");
 
-  GetFontPreferences();
+  ResetCachedFontPrefs();
 
   // * image animation
   const nsAdoptingCString& animatePref =
     Preferences::GetCString("image.animation_mode");
   if (animatePref.Equals("normal"))
     mImageAnimationModePref = imgIContainer::kNormalAnimMode;
   else if (animatePref.Equals("none"))
     mImageAnimationModePref = imgIContainer::kDontAnimMode;
@@ -1118,17 +1134,17 @@ nsPresContext::UpdateCharSet(const nsCSt
     mLanguage = mLangService->LookupCharSet(aCharSet.get()).get();  // addrefs
     // this will be a language group (or script) code rather than a true language code
 
     // bug 39570: moved from nsLanguageAtomService::LookupCharSet()
     if (mLanguage == nsGkAtoms::Unicode) {
       NS_RELEASE(mLanguage);
       NS_IF_ADDREF(mLanguage = mLangService->GetLocaleLanguage()); 
     }
-    GetFontPreferences();
+    ResetCachedFontPrefs();
   }
 #ifdef IBMBIDI
   //ahmed
 
   switch (GET_BIDI_OPTION_TEXTTYPE(GetBidi())) {
 
     case IBMBIDI_TEXTTYPE_LOGICAL:
       SetVisualMode(false);
@@ -1300,42 +1316,44 @@ nsPresContext::SetImageAnimationModeInte
 
 void
 nsPresContext::SetImageAnimationModeExternal(PRUint16 aMode)
 {
   SetImageAnimationModeInternal(aMode);
 }
 
 const nsFont*
-nsPresContext::GetDefaultFont(PRUint8 aFontID) const
+nsPresContext::GetDefaultFont(PRUint8 aFontID, nsIAtom *aLanguage) const
 {
+  const LangGroupFontPrefs *prefs = GetFontPrefsForLang(aLanguage);
+
   const nsFont *font;
   switch (aFontID) {
     // Special (our default variable width font and fixed width font)
     case kPresContext_DefaultVariableFont_ID:
-      font = &mDefaultVariableFont;
+      font = &prefs->mDefaultVariableFont;
       break;
     case kPresContext_DefaultFixedFont_ID:
-      font = &mDefaultFixedFont;
+      font = &prefs->mDefaultFixedFont;
       break;
     // CSS
     case kGenericFont_serif:
-      font = &mDefaultSerifFont;
+      font = &prefs->mDefaultSerifFont;
       break;
     case kGenericFont_sans_serif:
-      font = &mDefaultSansSerifFont;
+      font = &prefs->mDefaultSansSerifFont;
       break;
     case kGenericFont_monospace:
-      font = &mDefaultMonospaceFont;
+      font = &prefs->mDefaultMonospaceFont;
       break;
     case kGenericFont_cursive:
-      font = &mDefaultCursiveFont;
+      font = &prefs->mDefaultCursiveFont;
       break;
     case kGenericFont_fantasy: 
-      font = &mDefaultFantasyFont;
+      font = &prefs->mDefaultFantasyFont;
       break;
     default:
       font = nsnull;
       NS_ERROR("invalid arg");
       break;
   }
   return font;
 }
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -114,18 +114,17 @@ class nsRenderingContext;
 enum nsPresContext_CachedBoolPrefType {
   kPresContext_UseDocumentColors = 1,
   kPresContext_UseDocumentFonts,
   kPresContext_UnderlineLinks
 };
 
 // supported values for cached integer pref types
 enum nsPresContext_CachedIntPrefType {
-  kPresContext_MinimumFontSize = 1,
-  kPresContext_ScrollbarSide,
+  kPresContext_ScrollbarSide = 1,
   kPresContext_BidiDirection
 };
 
 // IDs for the default variable and fixed fonts (not to be changed, see nsFont.h)
 // To be used for Get/SetDefaultFont(). The other IDs in nsFont.h are also supported.
 const PRUint8 kPresContext_DefaultVariableFont_ID = 0x00; // kGenericFont_moz_variable
 const PRUint8 kPresContext_DefaultFixedFont_ID    = 0x01; // kGenericFont_moz_fixed
 
@@ -299,33 +298,36 @@ public:
   void FreeToShell(size_t aSize, void* aFreeChunk)
   {
     NS_ASSERTION(mShell, "freeing after shutdown");
     if (mShell)
       mShell->FreeMisc(aSize, aFreeChunk);
   }
 
   /**
-   * Get the default font corresponding to the given ID.  This object is
-   * read-only, you must copy the font to modify it.
+   * Get the default font for the given language and generic font ID.
+   * If aLanguage is nsnull, the document's language is used.
+   *
+   * This object is read-only, you must copy the font to modify it.
    * 
    * When aFontID is kPresContext_DefaultVariableFontID or
    * kPresContext_DefaultFixedFontID (which equals
    * kGenericFont_moz_fixed, which is used for the -moz-fixed generic),
    * the nsFont returned has its name as a CSS generic family (serif or
    * sans-serif for the former, monospace for the latter), and its size
-   * as the default font size for variable or fixed fonts for the pres
-   * context's language group.
+   * as the default font size for variable or fixed fonts for the
+   * language group.
    *
-   * For aFontID corresponds to a CSS Generic, the nsFont returned has
-   * its name as the name or names of the fonts in the user's
-   * preferences for the given generic and the pres context's language
-   * group, and its size set to the default variable font size.
+   * For aFontID corresponding to a CSS Generic, the nsFont returned has
+   * its name set to that generic font's name, and its size set to
+   * the user's preference for font size for that generic and the
+   * given language.
    */
-  NS_HIDDEN_(const nsFont*) GetDefaultFont(PRUint8 aFontID) const;
+  NS_HIDDEN_(const nsFont*) GetDefaultFont(PRUint8 aFontID,
+                                           nsIAtom *aLanguage) const;
 
   /** Get a cached boolean pref, by its type */
   // *  - initially created for bugs 31816, 20760, 22963
   bool GetCachedBoolPref(nsPresContext_CachedBoolPrefType aPrefType) const
   {
     // If called with a constant parameter, the compiler should optimize
     // this switch statement away.
     switch (aPrefType) {
@@ -344,18 +346,16 @@ public:
 
   /** Get a cached integer pref, by its type */
   // *  - initially created for bugs 30910, 61883, 74186, 84398
   PRInt32 GetCachedIntPref(nsPresContext_CachedIntPrefType aPrefType) const
   {
     // If called with a constant parameter, the compiler should optimize
     // this switch statement away.
     switch (aPrefType) {
-    case kPresContext_MinimumFontSize:
-      return mMinimumFontSizePref;
     case kPresContext_ScrollbarSide:
       return mPrefScrollbarSide;
     case kPresContext_BidiDirection:
       return mPrefBidiDirection;
     default:
       NS_ERROR("invalid arg passed to GetCachedIntPref");
     }
 
@@ -523,34 +523,39 @@ public:
 
   float TextZoom() { return mTextZoom; }
   void SetTextZoom(float aZoom) {
     if (aZoom == mTextZoom)
       return;
 
     mTextZoom = aZoom;
     if (HasCachedStyleData()) {
-      // Media queries could have changed since we changed the meaning
+      // Media queries could have changed, since we changed the meaning
       // of 'em' units in them.
       MediaFeatureValuesChanged(true);
       RebuildAllStyleData(NS_STYLE_HINT_REFLOW);
     }
   }
 
-  PRInt32 MinFontSize() const {
-    return NS_MAX(mMinFontSize, mMinimumFontSizePref);
+  /**
+   * Get the minimum font size for the specified language. If aLanguage
+   * is nsnull, then the document's language is used.
+   */
+  PRInt32 MinFontSize(nsIAtom *aLanguage) const {
+    const LangGroupFontPrefs *prefs = GetFontPrefsForLang(aLanguage);
+    return NS_MAX(mMinFontSize, prefs->mMinimumFontSize);
   }
 
   void SetMinFontSize(PRInt32 aMinFontSize) {
     if (aMinFontSize == mMinFontSize)
       return;
 
     mMinFontSize = aMinFontSize;
     if (HasCachedStyleData()) {
-      // Media queries could have changed since we changed the meaning
+      // Media queries could have changed, since we changed the meaning
       // of 'em' units in them.
       MediaFeatureValuesChanged(true);
       RebuildAllStyleData(NS_STYLE_HINT_REFLOW);
     }
   }
 
   float GetFullZoom() { return mFullZoom; }
   void SetFullZoom(float aZoom);
@@ -960,17 +965,24 @@ public:
     mContainsUpdatePluginGeometryFrame = aValue;
   }
 
   bool MayHaveFixedBackgroundFrames() { return mMayHaveFixedBackgroundFrames; }
   void SetHasFixedBackgroundFrame() { mMayHaveFixedBackgroundFrames = true; }
 
   virtual NS_MUST_OVERRIDE size_t
         SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const {
-    return 0;
+    size_t n = 0;
+    LangGroupFontPrefs *langGroupfontPrefs = mLangGroupFontPrefs.mNext;
+    while (langGroupfontPrefs) {
+      // XXX this doesn't include allocations made by the nsFont members
+      n += sizeof(LangGroupFontPrefs);
+      langGroupfontPrefs = langGroupfontPrefs->mNext;
+    }
+    return n;
 
     // Measurement of other members may be added later if DMD finds it is
     // worthwhile.
   }
   virtual NS_MUST_OVERRIDE size_t
         SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const {
     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   }
@@ -989,17 +1001,72 @@ protected:
 
   NS_HIDDEN_(void) PreferenceChanged(const char* aPrefName);
   static NS_HIDDEN_(int) PrefChangedCallback(const char*, void*);
 
   NS_HIDDEN_(void) UpdateAfterPreferencesChanged();
   static NS_HIDDEN_(void) PrefChangedUpdateTimerCallback(nsITimer *aTimer, void *aClosure);
 
   NS_HIDDEN_(void) GetUserPreferences();
-  NS_HIDDEN_(void) GetFontPreferences();
+
+  // Allow nsAutoPtr<LangGroupFontPrefs> dtor to access this protected struct's
+  // dtor:
+  struct LangGroupFontPrefs;
+  friend class nsAutoPtr<LangGroupFontPrefs>;
+  struct LangGroupFontPrefs {
+    // Font sizes default to zero; they will be set in GetFontPreferences
+    LangGroupFontPrefs()
+      : mLangGroup(nsnull)
+      , mMinimumFontSize(0)
+      , mDefaultVariableFont("serif", NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL,
+                             NS_FONT_WEIGHT_NORMAL, NS_FONT_STRETCH_NORMAL, 0, 0)
+      , mDefaultFixedFont("monospace", NS_FONT_STYLE_NORMAL,
+                          NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL,
+                          NS_FONT_STRETCH_NORMAL, 0, 0)
+      , mDefaultSerifFont("serif", NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL,
+                        NS_FONT_WEIGHT_NORMAL, NS_FONT_STRETCH_NORMAL, 0, 0)
+      , mDefaultSansSerifFont("sans-serif", NS_FONT_STYLE_NORMAL,
+                              NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL,
+                              NS_FONT_STRETCH_NORMAL, 0, 0)
+      , mDefaultMonospaceFont("monospace", NS_FONT_STYLE_NORMAL,
+                              NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL,
+                              NS_FONT_STRETCH_NORMAL, 0, 0)
+      , mDefaultCursiveFont("cursive", NS_FONT_STYLE_NORMAL,
+                            NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL,
+                            NS_FONT_STRETCH_NORMAL, 0, 0)
+      , mDefaultFantasyFont("fantasy", NS_FONT_STYLE_NORMAL,
+                            NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL,
+                            NS_FONT_STRETCH_NORMAL, 0, 0)
+    {}
+
+    nsCOMPtr<nsIAtom> mLangGroup;
+    nscoord mMinimumFontSize;
+    nsFont mDefaultVariableFont;
+    nsFont mDefaultFixedFont;
+    nsFont mDefaultSerifFont;
+    nsFont mDefaultSansSerifFont;
+    nsFont mDefaultMonospaceFont;
+    nsFont mDefaultCursiveFont;
+    nsFont mDefaultFantasyFont;
+    nsAutoPtr<LangGroupFontPrefs> mNext;
+  };
+
+  /**
+   * Fetch the user's font preferences for the given aLanguage's
+   * langugage group.
+   */
+  const LangGroupFontPrefs* GetFontPrefsForLang(nsIAtom *aLanguage) const;
+
+  void ResetCachedFontPrefs() {
+    // Throw away any other LangGroupFontPrefs objects:
+    mLangGroupFontPrefs.mNext = nsnull;
+
+    // Make GetFontPreferences reinitialize mLangGroupFontPrefs:
+    mLangGroupFontPrefs.mLangGroup = nsnull;
+  }
 
   NS_HIDDEN_(void) UpdateCharSet(const nsCString& aCharSet);
 
 public:
   void DoChangeCharSet(const nsCString& aCharSet);
 
 protected:
   void InvalidateThebesLayers();
@@ -1084,19 +1151,16 @@ protected:
 
   FramePropertyTable    mPropertyTable;
 
   nsInvalidateRequestList mInvalidateRequests;
 
   // container for per-context fonts (downloadable, SVG, etc.)
   nsUserFontSet*        mUserFontSet;
   
-  PRInt32               mFontScaler;
-  nscoord               mMinimumFontSizePref;
-
   nsRect                mVisibleArea;
   nsSize                mPageSize;
   float                 mPageScale;
   float                 mPPScale;
 
   nscolor               mDefaultColor;
   nscolor               mBackgroundColor;
 
@@ -1110,23 +1174,17 @@ protected:
   nscolor               mBodyTextColor;
 
   ScrollbarStyles       mViewportStyleOverflow;
   PRUint8               mFocusRingWidth;
 
   PRUint16              mImageAnimationMode;
   PRUint16              mImageAnimationModePref;
 
-  nsFont                mDefaultVariableFont;
-  nsFont                mDefaultFixedFont;
-  nsFont                mDefaultSerifFont;
-  nsFont                mDefaultSansSerifFont;
-  nsFont                mDefaultMonospaceFont;
-  nsFont                mDefaultCursiveFont;
-  nsFont                mDefaultFantasyFont;
+  LangGroupFontPrefs    mLangGroupFontPrefs;
 
   nscoord               mBorderWidthTable[3];
 
   PRUint32              mInterruptChecksToSkip;
 
   mozilla::TimeStamp    mReflowStartTime;
 
   unsigned              mHasPendingInterrupt : 1;
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -683,18 +683,16 @@ PresShell::MemoryReporter::SizeEnumerato
       Callback(EmptyCString(), textRunsPath, nsIMemoryReporter::KIND_HEAP,
                nsIMemoryReporter::UNITS_BYTES, textRunsSize, kTextRunsDesc,
                data->closure);
   }
 
   return PL_DHASH_NEXT;
 }
 
-NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(GfxTextrunWordCacheMallocSizeOf, "gfx/textrun-word-cache")
-
 NS_IMETHODIMP
 PresShell::MemoryReporter::GetName(nsACString &aName)
 {
   aName.AssignLiteral("layout");
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -972,18 +970,18 @@ PresShell::~PresShell()
 
   NS_ASSERTION(mCurrentEventContentStack.Count() == 0,
                "Huh, event content left on the stack in pres shell dtor!");
   NS_ASSERTION(mFirstCallbackEventRequest == nsnull &&
                mLastCallbackEventRequest == nsnull,
                "post-reflow queues not empty.  This means we're leaking");
 
 #ifdef DEBUG
-  NS_ASSERTION(mPresArenaAllocCount == 0,
-               "Some pres arena objects were not freed");
+  MOZ_ASSERT(mPresArenaAllocCount == 0,
+             "Some pres arena objects were not freed");
 #endif
 
   delete mStyleSet;
   delete mFrameConstructor;
 
   mCurrentEventContent = nsnull;
 
   NS_IF_RELEASE(mPresContext);
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -247,16 +247,17 @@ static void Shutdown();
     defined(machintosh) || \
     defined(android)
 #include "nsDeviceMotionSystem.h"
 #endif
 #endif
 #include "nsCSPService.h"
 #include "nsISmsService.h"
 #include "nsISmsDatabaseService.h"
+#include "mozilla/dom/sms/SmsRequestManager.h"
 #include "mozilla/dom/sms/SmsServicesFactory.h"
 #include "nsIPowerManagerService.h"
 
 using namespace mozilla::dom::sms;
 
 #include "mozilla/dom/power/PowerManagerService.h"
 
 using mozilla::dom::power::PowerManagerService;
@@ -304,16 +305,17 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsDeviceM
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsHapticFeedback)
 #endif
 #endif
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ThirdPartyUtil, Init)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsISmsService, SmsServicesFactory::CreateSmsService)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsISmsDatabaseService, SmsServicesFactory::CreateSmsDatabaseService)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIPowerManagerService,
                                          PowerManagerService::GetInstance)
+NS_GENERIC_FACTORY_CONSTRUCTOR(SmsRequestManager)
 
 //-----------------------------------------------------------------------------
 
 // Per bug 209804, it is necessary to observe the "xpcom-shutdown" event and
 // perform shutdown of the layout modules at that time instead of waiting for
 // our module destructor to run.  If we do not do this, then we risk holding
 // references to objects in other component libraries that have already been
 // shutdown (and possibly unloaded if 60709 is ever fixed).
@@ -795,16 +797,17 @@ NS_DEFINE_NAMED_CID(NS_STRUCTUREDCLONECO
 NS_DEFINE_NAMED_CID(NS_DEVICE_MOTION_CID);
 #endif
 #if defined(ANDROID) || defined(MOZ_PLATFORM_MAEMO)
 NS_DEFINE_NAMED_CID(NS_HAPTICFEEDBACK_CID);
 #endif
 #endif
 NS_DEFINE_NAMED_CID(SMS_SERVICE_CID);
 NS_DEFINE_NAMED_CID(SMS_DATABASE_SERVICE_CID);
+NS_DEFINE_NAMED_CID(SMS_REQUEST_MANAGER_CID);
 NS_DEFINE_NAMED_CID(NS_POWERMANAGERSERVICE_CID);
 
 static nsresult
 CreateWindowCommandTableConstructor(nsISupports *aOuter,
                                     REFNSIID aIID, void **aResult)
 {
   nsresult rv;
   nsCOMPtr<nsIControllerCommandTable> commandTable =
@@ -1066,16 +1069,17 @@ static const mozilla::Module::CIDEntry k
 #if defined(ANDROID) || defined(MOZ_PLATFORM_MAEMO)
   { &kNS_HAPTICFEEDBACK_CID, false, NULL, nsHapticFeedbackConstructor },
 #endif
 #endif
   { &kTHIRDPARTYUTIL_CID, false, NULL, ThirdPartyUtilConstructor },
   { &kNS_STRUCTUREDCLONECONTAINER_CID, false, NULL, nsStructuredCloneContainerConstructor },
   { &kSMS_SERVICE_CID, false, NULL, nsISmsServiceConstructor },
   { &kSMS_DATABASE_SERVICE_CID, false, NULL, nsISmsDatabaseServiceConstructor },
+  { &kSMS_REQUEST_MANAGER_CID, false, NULL, SmsRequestManagerConstructor },
   { &kNS_POWERMANAGERSERVICE_CID, false, NULL, nsIPowerManagerServiceConstructor },
   { NULL }
 };
 
 static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
   XPCONNECT_CONTRACTS
   { "@mozilla.org/layout/xul-boxobject;1", &kNS_BOXOBJECT_CID },
 #ifdef MOZ_XUL
@@ -1202,16 +1206,17 @@ static const mozilla::Module::ContractID
 #if defined(ANDROID) || defined(MOZ_PLATFORM_MAEMO)
   { "@mozilla.org/widget/hapticfeedback;1", &kNS_HAPTICFEEDBACK_CID },
 #endif
 #endif
   { THIRDPARTYUTIL_CONTRACTID, &kTHIRDPARTYUTIL_CID },
   { NS_STRUCTUREDCLONECONTAINER_CONTRACTID, &kNS_STRUCTUREDCLONECONTAINER_CID },
   { SMS_SERVICE_CONTRACTID, &kSMS_SERVICE_CID },
   { SMS_DATABASE_SERVICE_CONTRACTID, &kSMS_DATABASE_SERVICE_CID },
+  { SMS_REQUEST_MANAGER_CONTRACTID, &kSMS_REQUEST_MANAGER_CID },
   { POWERMANAGERSERVICE_CONTRACTID, &kNS_POWERMANAGERSERVICE_CID },
   { NULL }
 };
 
 static const mozilla::Module::CategoryEntry kLayoutCategories[] = {
   XPCONNECT_CATEGORIES
   { JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY, "Image", NS_HTMLIMGELEMENT_CONTRACTID },
   { JAVASCRIPT_GLOBAL_CONSTRUCTOR_PROTO_ALIAS_CATEGORY, "Image", "HTMLImageElement" },
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -120,17 +120,16 @@
 #include "nsJSEnvironment.h"
 #include "nsContentSink.h"
 #include "nsFrameMessageManager.h"
 #include "nsRefreshDriver.h"
 
 #include "nsHyphenationManager.h"
 #include "nsEditorSpellCheck.h"
 #include "nsDOMMemoryReporter.h"
-#include "mozilla/dom/sms/SmsRequestManager.h"
 
 extern void NS_ShutdownChainItemPool();
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsrefcnt nsLayoutStatics::sLayoutStaticRefcnt = 0;
 
@@ -267,26 +266,22 @@ nsLayoutStatics::Initialize()
   nsCORSListenerProxy::Startup();
 
   nsFrameList::Init();
 
   NS_SealStaticAtomTable();
 
   nsDOMMemoryMultiReporter::Init();
 
-  sms::SmsRequestManager::Init();
-
   return NS_OK;
 }
 
 void
 nsLayoutStatics::Shutdown()
 {
-  sms::SmsRequestManager::Shutdown();
-
   // Don't need to shutdown nsDOMMemoryReporter, that will be done by the memory
   // reporter manager.
 
   nsFrameScriptExecutor::Shutdown();
   nsFocusManager::Shutdown();
 #ifdef MOZ_XUL
   nsXULPopupManager::Shutdown();
 #endif
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1545,17 +1545,21 @@ nsGfxScrollFrameInner::AsyncScrollCallba
 /*
  * this method wraps calls to ScrollToImpl(), either in one shot or incrementally,
  *  based on the setting of the smooth scroll pref
  */
 void
 nsGfxScrollFrameInner::ScrollTo(nsPoint aScrollPosition,
                                 nsIScrollableFrame::ScrollMode aMode)
 {
-  mDestination = ClampScrollPosition(aScrollPosition);
+  if (ShouldClampScrollPosition()) {
+    mDestination = ClampScrollPosition(aScrollPosition);
+  } else {
+    mDestination = aScrollPosition;
+  }
 
   if (aMode == nsIScrollableFrame::INSTANT) {
     // Asynchronous scrolling is not allowed, so we'll kill any existing
     // async-scrolling process and do an instant scroll
     delete mAsyncScroll;
     mAsyncScroll = nsnull;
     ScrollToImpl(mDestination);
     return;
@@ -1708,16 +1712,25 @@ bool nsGfxScrollFrameInner::IsIgnoringVi
 {
   if (!mIsRoot)
     return false;
   nsSubDocumentFrame* subdocFrame = static_cast<nsSubDocumentFrame*>
     (nsLayoutUtils::GetCrossDocParentFrame(mOuter->PresContext()->PresShell()->GetRootFrame()));
   return subdocFrame && !subdocFrame->ShouldClipSubdocument();
 }
 
+bool nsGfxScrollFrameInner::ShouldClampScrollPosition() const
+{
+  if (!mIsRoot)
+    return true;
+  nsSubDocumentFrame* subdocFrame = static_cast<nsSubDocumentFrame*>
+    (nsLayoutUtils::GetCrossDocParentFrame(mOuter->PresContext()->PresShell()->GetRootFrame()));
+  return !subdocFrame || subdocFrame->ShouldClampScrollPosition();
+}
+
 bool nsGfxScrollFrameInner::IsAlwaysActive() const
 {
   // The root scrollframe for a non-chrome document which is the direct
   // child of a chrome document is always treated as "active".
   // XXX maybe we should extend this so that IFRAMEs which are fill the
   // entire viewport (like GMail!) are always active
   return mIsRoot && mOuter->PresContext()->IsRootContentDocument();
 }
@@ -1807,27 +1820,33 @@ ClampInt(nscoord aLower, nscoord aVal, n
   if (v < low)
     return low;
   if (v > high)
     return high;
   return v;
 }
 
 nsPoint
-nsGfxScrollFrameInner::ClampAndRestrictToDevPixels(const nsPoint& aPt,
-                                                   nsIntPoint* aPtDevPx) const
+nsGfxScrollFrameInner::RestrictToDevPixels(const nsPoint& aPt,
+                                           nsIntPoint* aPtDevPx,
+                                           bool aShouldClamp) const
 {
   nsPresContext* presContext = mOuter->PresContext();
   nscoord appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
   // Convert to device pixels so we scroll to an integer offset of device
   // pixels. But we also need to make sure that our position remains
   // inside the allowed region.
-  nsRect scrollRange = GetScrollRange();
-  *aPtDevPx = nsIntPoint(ClampInt(scrollRange.x, aPt.x, scrollRange.XMost(), appUnitsPerDevPixel),
-                         ClampInt(scrollRange.y, aPt.y, scrollRange.YMost(), appUnitsPerDevPixel));
+  if (aShouldClamp) {
+    nsRect scrollRange = GetScrollRange();
+    *aPtDevPx = nsIntPoint(ClampInt(scrollRange.x, aPt.x, scrollRange.XMost(), appUnitsPerDevPixel),
+                           ClampInt(scrollRange.y, aPt.y, scrollRange.YMost(), appUnitsPerDevPixel));
+  } else {
+    *aPtDevPx = nsIntPoint(NSAppUnitsToIntPixels(aPt.x, appUnitsPerDevPixel),
+                           NSAppUnitsToIntPixels(aPt.y, appUnitsPerDevPixel));
+  }
   return nsPoint(NSIntPixelsToAppUnits(aPtDevPx->x, appUnitsPerDevPixel),
                  NSIntPixelsToAppUnits(aPtDevPx->y, appUnitsPerDevPixel));
 }
 
 /* static */ void
 nsGfxScrollFrameInner::ScrollActivityCallback(nsITimer *aTimer, void* anInstance)
 {
   nsGfxScrollFrameInner* self = static_cast<nsGfxScrollFrameInner*>(anInstance);
@@ -1853,17 +1872,18 @@ nsGfxScrollFrameInner::ScheduleSynthetic
 }
 
 void
 nsGfxScrollFrameInner::ScrollToImpl(nsPoint aPt)
 {
   nsPresContext* presContext = mOuter->PresContext();
   nscoord appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
   nsIntPoint ptDevPx;
-  nsPoint pt = ClampAndRestrictToDevPixels(aPt, &ptDevPx);
+
+  nsPoint pt = RestrictToDevPixels(aPt, &ptDevPx, ShouldClampScrollPosition());
 
   nsPoint curPos = GetScrollPosition();
   if (pt == curPos) {
     return;
   }
   nsIntPoint curPosDevPx(NSAppUnitsToIntPixels(curPos.x, appUnitsPerDevPixel),
                          NSAppUnitsToIntPixels(curPos.y, appUnitsPerDevPixel));
   // We maintain the invariant that the scroll position is a multiple of device
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -172,17 +172,17 @@ public:
     pt.x = IsLTR() ?
       mScrollPort.x - mScrolledFrame->GetPosition().x :
       mScrollPort.XMost() - mScrolledFrame->GetRect().XMost();
     pt.y = mScrollPort.y - mScrolledFrame->GetPosition().y;
     return pt;
   }
   nsRect GetScrollRange() const;
 
-  nsPoint ClampAndRestrictToDevPixels(const nsPoint& aPt, nsIntPoint* aPtDevPx) const;
+  nsPoint RestrictToDevPixels(const nsPoint& aPt, nsIntPoint* aPtDevPx, bool aShouldClamp) const;
   nsPoint ClampScrollPosition(const nsPoint& aPt) const;
   static void AsyncScrollCallback(nsITimer *aTimer, void* anInstance);
   void ScrollTo(nsPoint aScrollPosition, nsIScrollableFrame::ScrollMode aMode);
   void ScrollToImpl(nsPoint aScrollPosition);
   void ScrollVisual(nsPoint aOldScrolledFramePosition);
   void ScrollBy(nsIntPoint aDelta, nsIScrollableFrame::ScrollUnit aUnit,
                 nsIScrollableFrame::ScrollMode aMode, nsIntPoint* aOverflow);
   void ScrollToRestoredPosition();
@@ -256,16 +256,18 @@ public:
   // returns true if a resizer should be visible
   bool HasResizer() { return mResizerBox && !mCollapsedResizer; }
   void LayoutScrollbars(nsBoxLayoutState& aState,
                         const nsRect& aContentArea,
                         const nsRect& aOldScrollArea);
 
   bool IsIgnoringViewportClipping() const;
 
+  bool ShouldClampScrollPosition() const;
+
   bool IsAlwaysActive() const;
   void MarkActive();
   void MarkInactive();
   nsExpirationState* GetExpirationState() { return &mActivityExpirationState; }
 
   void ScheduleSyntheticMouseMove();
   static void ScrollActivityCallback(nsITimer *aTimer, void* anInstance);
 
--- a/layout/generic/nsSimplePageSequence.cpp
+++ b/layout/generic/nsSimplePageSequence.cpp
@@ -118,17 +118,19 @@ nsSimplePageSequenceFrame::nsSimplePageS
   mSelectionHeight(-1),
   mYSelOffset(0)
 {
   nscoord halfInch = PresContext()->CSSTwipsToAppUnits(NS_INCHES_TO_TWIPS(0.5));
   mMargin.SizeTo(halfInch, halfInch, halfInch, halfInch);
 
   // XXX Unsafe to assume successful allocation
   mPageData = new nsSharedPageData();
-  mPageData->mHeadFootFont = new nsFont(*PresContext()->GetDefaultFont(kGenericFont_serif));
+  mPageData->mHeadFootFont =
+    new nsFont(*PresContext()->GetDefaultFont(kGenericFont_serif,
+                                              aContext->GetStyleFont()->mLanguage));
   mPageData->mHeadFootFont->size = nsPresContext::CSSPointsToAppUnits(10);
 
   nsresult rv;
   mPageData->mPrintOptions = do_GetService(sPrintOptionsContractID, &rv);
 
   // Doing this here so we only have to go get these formats once
   SetPageNumberFormat("pagenumber",  "%1$d", true);
   SetPageNumberFormat("pageofpages", "%1$d of %2$d", false);
--- a/layout/generic/nsSubDocumentFrame.h
+++ b/layout/generic/nsSubDocumentFrame.h
@@ -125,16 +125,22 @@ public:
   virtual void ReflowCallbackCanceled();
 
   bool ShouldClipSubdocument()
   {
     nsFrameLoader* frameLoader = FrameLoader();
     return !frameLoader || frameLoader->ShouldClipSubdocument();
   }
 
+  bool ShouldClampScrollPosition()
+  {
+    nsFrameLoader* frameLoader = FrameLoader();
+    return !frameLoader || frameLoader->ShouldClampScrollPosition();
+  }
+
 protected:
   friend class AsyncFrameInit;
 
   // Helper method to look up the HTML marginwidth & marginheight attributes
   nsIntSize GetMarginAttributes();
 
   nsFrameLoader* FrameLoader();
 
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/fallback-color-04.svg
@@ -0,0 +1,38 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<svg xmlns="http://www.w3.org/2000/svg" >
+
+  <title>Testcase for fallback colours</title>
+
+  <defs>
+    <filter id="erode">
+      <feMorphology operator="dilate" radius="3"/>
+    </filter>
+  </defs>
+
+  <rect x="0%" y="0%" width="100%" height="100%" fill="lime"/>
+  <text x="10" y="50" font-size="50"
+        stroke-width="8" stroke="red" fill="none">
+    A B
+  </text>
+  <text x="10" y="50" font-size="50"
+        stroke-width="8" stroke="url(#null) lime" fill="none" filter="url(#erode)">
+    A B
+  </text>
+  <text x="200" y="50" font-size="50" fill="red">
+    A B
+  </text>
+  <text x="200" y="50" font-size="50" fill="url(#null) lime" filter="url(#erode)">
+    A B
+  </text>
+  <text x="10" y="200" font-size="50" fill="red"
+        stroke-width="1" stroke="red">
+    A B
+  </text>
+  <text x="10" y="200" font-size="50" fill="url(#null) lime"
+        stroke-width="1" stroke="url(#null) lime" filter="url(#erode)">
+    A B
+  </text>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/lang-attribute-01.svg
@@ -0,0 +1,16 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<svg xmlns="http://www.w3.org/2000/svg" lang="foo">
+  <title>Test the 'lang' attribute in SVG</title>
+  <!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=368840 -->
+  <style type="text/css">
+
+rect:lang(foo) {
+  fill: lime;
+}
+
+  </style>
+  <rect width="100%" height="100%" fill="red"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/lang-attribute-02.svg
@@ -0,0 +1,16 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<svg xmlns="http://www.w3.org/2000/svg" xml:lang="foo">
+  <title>Test the 'xml:lang' attribute in SVG</title>
+  <!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=368840 -->
+  <style type="text/css">
+
+rect:lang(foo) {
+  fill: lime;
+}
+
+  </style>
+  <rect width="100%" height="100%" fill="red"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/lang-attribute-03.svg
@@ -0,0 +1,16 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<svg xmlns="http://www.w3.org/2000/svg" xml:lang="foo" lang="bar">
+  <title>Test the 'xml:lang' attribute in SVG</title>
+  <!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=368840 -->
+  <style type="text/css">
+
+rect:lang(foo) {
+  fill: lime;
+}
+
+  </style>
+  <rect width="100%" height="100%" fill="red"/>
+</svg>
--- a/layout/reftests/svg/reftest.list
+++ b/layout/reftests/svg/reftest.list
@@ -116,16 +116,17 @@ random == dynamic-use-nested-01.svg dyna
 == use-02-extref.svg use-02-extref-ref.svg
 == use-extref-dataURI-01.svg pass.svg
 == use-children.svg pass.svg
 == fallback-color-01a.svg pass.svg
 == fallback-color-01b.svg pass.svg
 == fallback-color-02a.svg fallback-color-02-ref.svg
 == fallback-color-02b.svg fallback-color-02-ref.svg
 == fallback-color-03.svg pass.svg
+== fallback-color-04.svg pass.svg
 == filter-basic-01.svg pass.svg
 == filter-basic-02.svg pass.svg
 == filter-basic-03.svg pass.svg
 == filter-bounds-01.svg pass.svg
 == filter-bounds-02.svg pass.svg
 fails-if(Android) == filter-extref-differentOrigin-01.svg pass.svg # Bug 695385
 == filter-foreignObject-01.svg pass.svg
 == filter-in-mask-01.svg pass.svg
@@ -147,16 +148,19 @@ fails-if(Android) == filter-extref-diffe
 == foreignObject-style-change-01.svg pass.svg
 == getElementById-a-element-01.svg pass.svg
 fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated) == gradient-live-01a.svg gradient-live-01-ref.svg # bug 696674
 fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated) == gradient-live-01b.svg gradient-live-01-ref.svg # bug 696674
 fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated) == gradient-live-01c.svg gradient-live-01-ref.svg # bug 696674
 fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated) == gradient-live-01d.svg gradient-live-01-ref.svg # bug 696674
 fails == inline-in-xul-basic-01.xul pass.svg
 == invalid-text-01.svg pass.svg
+== lang-attribute-01.svg pass.svg
+== lang-attribute-02.svg pass.svg
+== lang-attribute-03.svg pass.svg
 == linearGradient-basic-01.svg pass.svg
 == linearGradient-basic-02.svg pass.svg
 == markers-and-group-opacity-01.svg markers-and-group-opacity-01-ref.svg
 == marker-attribute-01.svg pass.svg
 == marker-viewBox-01.svg marker-viewBox-01-ref.svg
 == mask-basic-01.svg pass.svg
 == mask-basic-02.svg mask-basic-02-ref.svg
 == mask-extref-dataURI-01.svg pass.svg
--- a/layout/style/Declaration.h
+++ b/layout/style/Declaration.h
@@ -113,16 +113,17 @@ public:
   /**
    * Initialize this declaration as holding no data.  Cannot fail.
    */
   void InitializeEmpty();
 
   /**
    * Transfer all of the state from |aExpandedData| into this declaration.
    * After calling, |aExpandedData| should be in its initial state.
+   * Callers must make sure mOrder is updated as necessary.
    */
   void CompressFrom(nsCSSExpandedDataBlock *aExpandedData) {
     NS_ABORT_IF_FALSE(!mData, "oops");
     NS_ABORT_IF_FALSE(!mImportantData, "oops");
     aExpandedData->Compress(getter_Transfers(mData),
                             getter_Transfers(mImportantData));
     aExpandedData->AssertInitialState();
   }
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -1217,17 +1217,18 @@ nsComputedDOMStyle::DoGetFontFamily()
   nsIPresShell* presShell = doc->GetShell();
   NS_ASSERTION(presShell, "pres shell is required");
   nsPresContext *presContext = presShell->GetPresContext();
   NS_ASSERTION(presContext, "pres context is required");
 
   const nsString& fontName = font->mFont.name;
   if (font->mGenericID == kGenericFont_NONE && !font->mFont.systemFont) {
     const nsFont* defaultFont =
-      presContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID);
+      presContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID,
+                                  font->mLanguage);
 
     PRInt32 lendiff = fontName.Length() - defaultFont->name.Length();
     if (lendiff > 0) {
       val->SetString(Substring(fontName, 0, lendiff-1)); // -1 removes comma
     } else {
       val->SetString(fontName);
     }
   } else {
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -1977,17 +1977,17 @@ nsRuleNode::WalkRuleTree(const nsStyleSt
 const void*
 nsRuleNode::SetDefaultOnRoot(const nsStyleStructID aSID, nsStyleContext* aContext)
 {
   switch (aSID) {
     case eStyleStruct_Font:
     {
       nsStyleFont* fontData = new (mPresContext) nsStyleFont(mPresContext);
       if (NS_LIKELY(fontData != nsnull)) {
-        nscoord minimumFontSize = mPresContext->MinFontSize();
+        nscoord minimumFontSize = mPresContext->MinFontSize(fontData->mLanguage);
 
         if (minimumFontSize > 0 && !mPresContext->IsChrome()) {
           fontData->mFont.size = NS_MAX(fontData->mSize, minimumFontSize);
         }
         else {
           fontData->mFont.size = fontData->mSize;
         }
         aContext->SetStyle(eStyleStruct_Font, fontData);
@@ -2538,17 +2538,17 @@ nsRuleNode::SetFontSize(nsPresContext* a
                         nscoord aParentSize,
                         nscoord aScriptLevelAdjustedParentSize,
                         bool aUsedStartStruct,
                         bool aAtRoot,
                         bool& aCanStoreInRuleTree)
 {
   bool zoom = false;
   PRInt32 baseSize = (PRInt32) aPresContext->
-    GetDefaultFont(aFont->mGenericID)->size;
+    GetDefaultFont(aFont->mGenericID, aFont->mLanguage)->size;
   const nsCSSValue* sizeValue = aRuleData->ValueForFontSize();
   if (eCSSUnit_Enumerated == sizeValue->GetUnit()) {
     PRInt32 value = sizeValue->GetIntValue();
 
     zoom = true;
     if ((NS_STYLE_FONT_SIZE_XXSMALL <= value) &&
         (value <= NS_STYLE_FONT_SIZE_XXLARGE)) {
       *aSize = nsStyleUtil::CalcFontPointSize(value, baseSize,
@@ -2649,41 +2649,41 @@ static PRInt8 ClampTo8Bit(PRInt32 aValue
     return -128;
   if (aValue > 127)
     return 127;
   return PRInt8(aValue);
 }
 
 /* static */ void
 nsRuleNode::SetFont(nsPresContext* aPresContext, nsStyleContext* aContext,
-                    nscoord aMinFontSize,
                     PRUint8 aGenericFontID, const nsRuleData* aRuleData,
                     const nsStyleFont* aParentFont,
                     nsStyleFont* aFont, bool aUsedStartStruct,
                     bool& aCanStoreInRuleTree)
 {
   bool atRoot = !aContext->GetParent();
 
-  // mLanguage must be set before before any of the CalcLengthWith (direct
-  // calls or calls via SetFontSize) for the cases where |aParentFont| is the
-  // same as |aFont|.
+  // mLanguage must be set before before any of the CalcLengthWith calls
+  // (direct calls or calls via SetFontSize) for the cases where |aParentFont|
+  // is the same as |aFont|.
   //
   // -x-lang: string, inherit
-  // this is not a real CSS property, it is a html attribute mapped to CSS
+  // This is not a real CSS property, it is an HTML attribute mapped to CSS.
   const nsCSSValue* langValue = aRuleData->ValueForLang();
   if (eCSSUnit_Ident == langValue->GetUnit()) {
     nsAutoString lang;
     langValue->GetStringValue(lang);
 
     nsContentUtils::ASCIIToLower(lang);
     aFont->mLanguage = do_GetAtom(lang);
   }
 
   const nsFont* defaultVariableFont =
-    aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID);
+    aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID,
+                                 aFont->mLanguage);
 
   // -moz-system-font: enum (never inherit!)
   nsFont systemFont;
   const nsCSSValue* systemFontValue = aRuleData->ValueForSystemFont();
   if (eCSSUnit_Enumerated == systemFontValue->GetUnit()) {
     nsSystemFontID sysID;
     switch (systemFontValue->GetIntValue()) {
       case NS_STYLE_FONT_CAPTION:       sysID = eSystemFont_Caption;      break;    // css2
@@ -2953,41 +2953,52 @@ nsRuleNode::SetFont(nsPresContext* aPres
                 &aFont->mScriptUnconstrainedSize,
                 systemFont, aParentFont->mScriptUnconstrainedSize,
                 scriptLevelAdjustedUnconstrainedParentSize,
                 aUsedStartStruct, atRoot, aCanStoreInRuleTree);
   }
   NS_ASSERTION(aFont->mScriptUnconstrainedSize <= aFont->mSize,
                "scriptminsize should never be making things bigger");
 
+  nscoord fontSize = aFont->mSize;
+
   // enforce the user' specified minimum font-size on the value that we expose
-  // (but don't change font-size:0)
-  if (0 < aFont->mSize && aFont->mSize < aMinFontSize)
-    aFont->mFont.size = aMinFontSize;
-  else
-    aFont->mFont.size = aFont->mSize;
+  // (but don't change font-size:0, since that would unhide hidden text)
+  if (fontSize > 0) {
+    nscoord minFontSize = aPresContext->MinFontSize(aFont->mLanguage);
+    if (minFontSize < 0) {
+      minFontSize = 0;
+    }
+    if (fontSize < minFontSize && !aPresContext->IsChrome()) {
+      // override the minimum font-size constraint
+      fontSize = minFontSize;
+    }
+  }
+  aFont->mFont.size = fontSize;
 
   // font-size-adjust: number, none, inherit, initial, -moz-system-font
   const nsCSSValue* sizeAdjustValue = aRuleData->ValueForFontSizeAdjust();
   if (eCSSUnit_System_Font == sizeAdjustValue->GetUnit()) {
     aFont->mFont.sizeAdjust = systemFont.sizeAdjust;
   } else
     SetFactor(*sizeAdjustValue, aFont->mFont.sizeAdjust,
               aCanStoreInRuleTree, aParentFont->mFont.sizeAdjust, 0.0f,
               SETFCT_NONE);
 }
 
+// This should die (bug 380915).
+//
 // SetGenericFont:
 //  - backtrack to an ancestor with the same generic font name (possibly
 //    up to the root where default values come from the presentation context)
 //  - re-apply cascading rules from there without caching intermediate values
 /* static */ void
 nsRuleNode::SetGenericFont(nsPresContext* aPresContext,
                            nsStyleContext* aContext,
-                           PRUint8 aGenericFontID, nscoord aMinFontSize,
+                           PRUint8 aGenericFontID,
                            nsStyleFont* aFont)
 {
   // walk up the contexts until a context with the desired generic font
   nsAutoTArray<nsStyleContext*, 8> contextPath;
   contextPath.AppendElement(aContext);
   nsStyleContext* higherContext = aContext->GetParent();
   while (higherContext) {
     if (higherContext->GetStyleFont()->mGenericID == aGenericFontID) {
@@ -2998,17 +3009,18 @@ nsRuleNode::SetGenericFont(nsPresContext
     higherContext = higherContext->GetParent();
   }
 
   // re-apply the cascading rules, starting from the higher context
 
   // If we stopped earlier because we reached the root of the style tree,
   // we will start with the default generic font from the presentation
   // context. Otherwise we start with the higher context.
-  const nsFont* defaultFont = aPresContext->GetDefaultFont(aGenericFontID);
+  const nsFont* defaultFont =
+    aPresContext->GetDefaultFont(aGenericFontID, aFont->mLanguage);
   nsStyleFont parentFont(*defaultFont, aPresContext);
   if (higherContext) {
     const nsStyleFont* tmpFont = higherContext->GetStyleFont();
     parentFont = *tmpFont;
   }
   *aFont = parentFont;
 
   bool dummy;
@@ -3048,17 +3060,17 @@ nsRuleNode::SetGenericFont(nsPresContext
 
     // Compute the delta from the information that the rules specified
 
     // Avoid unnecessary operations in SetFont().  But we care if it's
     // the final value that we're computing.
     if (i != 0)
       ruleData.ValueForFontFamily()->Reset();
 
-    nsRuleNode::SetFont(aPresContext, context, aMinFontSize,
+    nsRuleNode::SetFont(aPresContext, context,
                         aGenericFontID, &ruleData, &parentFont, aFont,
                         false, dummy);
 
     // XXX Not sure if we need to do this here
     // If we have a post-resolve callback, handle that now.
     if (ruleData.mPostResolveCallback)
       (ruleData.mPostResolveCallback)(aFont, &ruleData);
 
@@ -3094,34 +3106,26 @@ nsRuleNode::ComputeFontData(void* aStart
   // we do need to consider it in WalkRuleTree when deciding whether to
   // walk further up the tree.  So this means that when the font struct
   // is fully specified using *longhand* properties (excluding
   // -moz-system-font), we won't cache in the rule tree even though we
   // could.  However, it's pretty unlikely authors will do that
   // (although there is a pretty good chance they'll fully specify it
   // using the 'font' shorthand).
 
-  // See if there is a minimum font-size constraint to honor
-  nscoord minimumFontSize = mPresContext->MinFontSize();
-
-  if (minimumFontSize < 0)
-    minimumFontSize = 0;
-
   bool useDocumentFonts =
     mPresContext->GetCachedBoolPref(kPresContext_UseDocumentFonts);
 
   // See if we are in the chrome
   // We only need to know this to determine if we have to use the
-  // document fonts (overriding the useDocumentFonts flag), or to
-  // determine if we have to override the minimum font-size constraint.
-  if ((!useDocumentFonts || minimumFontSize > 0) && mPresContext->IsChrome()) {
+  // document fonts (overriding the useDocumentFonts flag).
+  if (!useDocumentFonts && mPresContext->IsChrome()) {
     // if we are not using document fonts, but this is a XUL document,
     // then we use the document fonts anyway
     useDocumentFonts = true;
-    minimumFontSize = 0;
   }
 
   // Figure out if we are a generic font
   PRUint8 generic = kGenericFont_NONE;
   // XXXldb What if we would have had a string if we hadn't been doing
   // the optimization with a non-null aStartStruct?
   const nsCSSValue* familyValue = aRuleData->ValueForFontFamily();
   if (eCSSUnit_Families == familyValue->GetUnit()) {
@@ -3152,25 +3156,25 @@ nsRuleNode::ComputeFontData(void* aStart
         generic = kGenericFont_NONE;
       }
     }
   }
 
   // Now compute our font struct
   if (generic == kGenericFont_NONE) {
     // continue the normal processing
-    nsRuleNode::SetFont(mPresContext, aContext, minimumFontSize, generic,
+    nsRuleNode::SetFont(mPresContext, aContext, generic,
                         aRuleData, parentFont, font,
                         aStartStruct != nsnull, canStoreInRuleTree);
   }
   else {
     // re-calculate the font as a generic font
     canStoreInRuleTree = false;
     nsRuleNode::SetGenericFont(mPresContext, aContext, generic,
-                               minimumFontSize, font);
+                               font);
   }
 
   COMPUTE_END_INHERITED(Font, font)
 }
 
 template <typename T>
 inline PRUint32 ListLength(const T* aList)
 {
@@ -3321,24 +3325,22 @@ nsRuleNode::ComputeTextData(void* aStart
   else {
     SetCoord(*lineHeightValue, text->mLineHeight, parentText->mLineHeight,
              SETCOORD_LEH | SETCOORD_FACTOR | SETCOORD_NORMAL,
              aContext, mPresContext, canStoreInRuleTree);
     if (lineHeightValue->IsLengthUnit() &&
         !lineHeightValue->IsRelativeLengthUnit()) {
       nscoord lh = nsStyleFont::ZoomText(mPresContext,
                                          text->mLineHeight.GetCoordValue());
-      nscoord minimumFontSize = mPresContext->MinFontSize();
+
+      canStoreInRuleTree = false;
+      const nsStyleFont *font = aContext->GetStyleFont();
+      nscoord minimumFontSize = mPresContext->MinFontSize(font->mLanguage);
 
       if (minimumFontSize > 0 && !mPresContext->IsChrome()) {
-        // If we applied a minimum font size, scale the line height by
-        // the same ratio.  (If we *might* have applied a minimum font
-        // size, we can't cache in the rule tree.)
-        canStoreInRuleTree = false;
-        const nsStyleFont *font = aContext->GetStyleFont();
         if (font->mSize != 0) {
           lh = nscoord(float(lh) * float(font->mFont.size) / float(font->mSize));
         } else {
           lh = minimumFontSize;
         }
       }
       text->mLineHeight.SetCoordValue(lh);
     }
--- a/layout/style/nsRuleNode.h
+++ b/layout/style/nsRuleNode.h
@@ -605,28 +605,26 @@ protected:
                           nscoord aParentSize,
                           nscoord aScriptLevelAdjustedParentSize,
                           bool aUsedStartStruct,
                           bool aAtRoot,
                           bool& aCanStoreInRuleTree);
 
   static void SetFont(nsPresContext* aPresContext,
                       nsStyleContext* aContext,
-                      nscoord aMinFontSize,
                       PRUint8 aGenericFontID,
                       const nsRuleData* aRuleData,
                       const nsStyleFont* aParentFont,
                       nsStyleFont* aFont,
                       bool aStartStruct,
                       bool& aCanStoreInRuleTree);
 
   static void SetGenericFont(nsPresContext* aPresContext,
                              nsStyleContext* aContext,
                              PRUint8 aGenericFontID,
-                             nscoord aMinFontSize,
                              nsStyleFont* aFont);
 
   void AdjustLogicalBoxProp(nsStyleContext* aContext,
                             const nsCSSValue& aLTRSource,
                             const nsCSSValue& aRTLSource,
                             const nsCSSValue& aLTRLogicalValue,
                             const nsCSSValue& aRTLLogicalValue,
                             mozilla::css::Side aSide,
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -142,17 +142,18 @@ nsStyleFont::nsStyleFont(const nsStyleFo
   , mScriptMinSize(aSrc.mScriptMinSize)
   , mScriptSizeMultiplier(aSrc.mScriptSizeMultiplier)
   , mLanguage(aSrc.mLanguage)
 {
   MOZ_COUNT_CTOR(nsStyleFont);
 }
 
 nsStyleFont::nsStyleFont(nsPresContext* aPresContext)
-  : mFont(*(aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID))),
+  // passing nsnull to GetDefaultFont make it use the doc language
+  : mFont(*(aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID, nsnull))),
     mGenericID(kGenericFont_NONE)
 {
   MOZ_COUNT_CTOR(nsStyleFont);
   Init(aPresContext);
 }
 
 void
 nsStyleFont::Init(nsPresContext* aPresContext)
--- a/layout/style/test/test_bug401046.html
+++ b/layout/style/test/test_bug401046.html
@@ -11,32 +11,22 @@ https://bugzilla.mozilla.org/show_bug.cg
   <style type="text/css">
 
   #display span { margin-bottom: 1em; }
 
   </style>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=401046">Mozilla Bug 401046</a>
-<!-- FIXME tried changing the zh-CN pref instead of x-western, but the language
-     is based only on the document *charset* -->
-<!--
 <p id="display" lang="zh-Hans">
   <span id="s0" style="font-size: 0">汉字</span>
   <span id="s4" style="font-size: 4px">汉字</span>
   <span id="s12" style="font-size: 12px">汉字</span>
   <span id="s28" style="font-size: 28px">汉字</span>
 </p>
--->
-<p id="display">
-  <span id="s0" style="font-size: 0">Ép</span>
-  <span id="s4" style="font-size: 4px">Ép</span>
-  <span id="s12" style="font-size: 12px">Ép</span>
-  <span id="s28" style="font-size: 28px">Ép</span>
-</p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 401046 **/
 
@@ -51,42 +41,42 @@ var elts = [
 
 function fs(idx) {
   // The computed font size actually *doesn't* currently reflect the
   // minimum font size preference, but things in em units do.  Not sure
   // if this is how it ought to be...
   return getComputedStyle(elts[idx], "").marginBottom;
 }
 
-SpecialPowers.pushPrefEnv({'clear': [['font.minimum-size.x-western']]}, step1);
+SpecialPowers.pushPrefEnv({'clear': [['font.minimum-size.zh-CN']]}, step1);
 
 function step1() {
     is(fs(0), "0px", "at min font size 0, 0px should compute to 0px");
     is(fs(1), "4px", "at min font size 0, 4px should compute to 4px");
     is(fs(2), "12px", "at min font size 0, 12px should compute to 12px");
     is(fs(3), "28px", "at min font size 0, 28px should compute to 28px");
 
-    SpecialPowers.pushPrefEnv({'set': [['font.minimum-size.x-western', 7]]}, step2);
+    SpecialPowers.pushPrefEnv({'set': [['font.minimum-size.zh-CN', 7]]}, step2);
 }
 
 function step2() {
     is(fs(0), "0px", "at min font size 7, 0px should compute to 0px");
     is(fs(1), "7px", "at min font size 7, 4px should compute to 7px");
     is(fs(2), "12px", "at min font size 7, 12px should compute to 12px");
     is(fs(3), "28px", "at min font size 7, 28px should compute to 28px");
 
-    SpecialPowers.pushPrefEnv({'set': [['font.minimum-size.x-western', 18]]}, step3);
+    SpecialPowers.pushPrefEnv({'set': [['font.minimum-size.zh-CN', 18]]}, step3);
 }
 
 function step3() {
     is(fs(0), "0px", "at min font size 18, 0px should compute to 0px");
     is(fs(1), "18px", "at min font size 18, 4px should compute to 18px");
     is(fs(2), "18px", "at min font size 18, 12px should compute to 18px");
     is(fs(3), "28px", "at min font size 18, 28px should compute to 28px");
 
-    SpecialPowers.pushPrefEnv({'clear': [['font.minimum-size.x-western']]}, SimpleTest.finish);
+    SpecialPowers.pushPrefEnv({'clear': [['font.minimum-size.zh-CN']]}, SimpleTest.finish);
 }
 
 </script>
 </pre>
 </body>
 </html>
 
--- a/netwerk/protocol/http/SpdySession.cpp
+++ b/netwerk/protocol/http/SpdySession.cpp
@@ -716,25 +716,27 @@ SpdySession::GenerateGoAway()
   
   // last-good-stream-id are bytes 8-11, when we accept server push this will
   // need to be set non zero
 
   FlushOutputQueue();
 }
 
 void
-SpdySession::CleanupStream(SpdyStream *aStream, nsresult aResult)
+SpdySession::CleanupStream(SpdyStream *aStream, nsresult aResult,
+                           rstReason aResetCode)
 {
   NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
   LOG3(("SpdySession::CleanupStream %p %p 0x%x %X\n",
         this, aStream, aStream->StreamID(), aResult));
 
   if (!aStream->RecvdFin() && aStream->StreamID()) {
-    LOG3(("Stream had not processed recv FIN, sending RST"));
-    GenerateRstStream(RST_CANCEL, aStream->StreamID());
+    LOG3(("Stream had not processed recv FIN, sending RST code %X\n",
+          aResetCode));
+    GenerateRstStream(aResetCode, aStream->StreamID());
     --mConcurrent;
     ProcessPending();
   }
   
   // Check if partial frame reader
   if (aStream == mInputFrameDataStream) {
     LOG3(("Stream had active partial read frame on close"));
     ChangeDownstreamState(DISCARDING_DATA_FRAME);
@@ -837,103 +839,115 @@ nsresult
 SpdySession::HandleSynReply(SpdySession *self)
 {
   NS_ABORT_IF_FALSE(self->mFrameControlType == CONTROL_TYPE_SYN_REPLY,
                     "wrong control type");
 
   if (self->mInputFrameDataSize < 8) {
     LOG3(("SpdySession::HandleSynReply %p SYN REPLY too short data=%d",
           self, self->mInputFrameDataSize));
+    // A framing error is a session wide error that cannot be recovered
     return NS_ERROR_ILLEGAL_VALUE;
   }
   
+  // Uncompress the headers into mDecompressBuffer, leaving them in
+  // spdy format for the time being. Make certain to do this
+  // step before any error handling that might abort the stream but not
+  // the session becuase the session compression context will become
+  // inconsistent if all of the compressed data is not processed.
+  if (NS_FAILED(self->DownstreamUncompress(self->mInputFrameBuffer + 14,
+                                           self->mInputFrameDataSize - 6))) {
+    LOG(("SpdySession::HandleSynReply uncompress failed\n"));
+    return NS_ERROR_FAILURE;
+  }
+
   PRUint32 streamID =
     PR_ntohl(reinterpret_cast<PRUint32 *>(self->mInputFrameBuffer.get())[2]);
   self->mInputFrameDataStream = self->mStreamIDHash.Get(streamID);
   if (!self->mInputFrameDataStream) {
     LOG3(("SpdySession::HandleSynReply %p lookup streamID in syn_reply "
           "0x%X failed. NextStreamID = 0x%x", self, streamID,
           self->mNextStreamID));
     if (streamID >= self->mNextStreamID)
       self->GenerateRstStream(RST_INVALID_STREAM, streamID);
-    
-    // It is likely that this is a reply to a stream ID that has been canceled.
-    // For the most part we would like to ignore it, but the header needs to be
-    // be parsed to keep the compression context synchronized
-    self->DownstreamUncompress(self->mInputFrameBuffer + 14,
-                               self->mInputFrameDataSize - 6);
+
     self->ResetDownstreamState();
     return NS_OK;
   }
 
-  self->mInputFrameDataStream->UpdateTransportReadEvents(
-    self->mInputFrameDataSize);
+  nsresult rv = self->HandleSynReplyForValidStream();
+  if (rv == NS_ERROR_ILLEGAL_VALUE) {
+    LOG3(("SpdySession::HandleSynReply %p PROTOCOL_ERROR detected 0x%X\n",
+          self, streamID));
+    self->CleanupStream(self->mInputFrameDataStream, rv, RST_PROTOCOL_ERROR);
+    self->ResetDownstreamState();
+    rv = NS_OK;
+  }
 
-  if (self->mInputFrameDataStream->GetFullyOpen()) {
+  return rv;
+}
+
+// HandleSynReplyForValidStream() returns NS_ERROR_ILLEGAL_VALUE when the stream
+// should be reset with a PROTOCOL_ERROR, NS_OK when the SYN_REPLY was
+// fine, and any other error is fatal to the session.
+nsresult
+SpdySession::HandleSynReplyForValidStream()
+{
+  if (mInputFrameDataStream->GetFullyOpen()) {
     // "If an endpoint receives multiple SYN_REPLY frames for the same active
     // stream ID, it must drop the stream, and send a RST_STREAM for the
     // stream with the error PROTOCOL_ERROR."
     //
-    // In addition to that we abort the session - this is a serious protocol
-    // violation.
-
-    self->GenerateRstStream(RST_PROTOCOL_ERROR, streamID);
-    return NS_ERROR_ILLEGAL_VALUE;
+    // If the stream is open then just RST_STREAM and move on, otherwise
+    // abort the session
+    return mInputFrameDataStream->RecvdFin() ?
+      NS_ERROR_ALREADY_OPENED : NS_ERROR_ILLEGAL_VALUE;
   }
-  self->mInputFrameDataStream->SetFullyOpen();
+  mInputFrameDataStream->SetFullyOpen();
 
-  self->mInputFrameDataLast = self->mInputFrameBuffer[4] & kFlag_Data_FIN;
+  mInputFrameDataLast = mInputFrameBuffer[4] & kFlag_Data_FIN;
 
-  if (self->mInputFrameBuffer[4] & kFlag_Data_UNI) {
+  if (mInputFrameBuffer[4] & kFlag_Data_UNI) {
     LOG3(("SynReply had unidirectional flag set on it - nonsensical"));
     return NS_ERROR_ILLEGAL_VALUE;
   }
 
-  LOG3(("SpdySession::HandleSynReply %p SYN_REPLY for 0x%X fin=%d",
-        self, streamID, self->mInputFrameDataLast));
-  
-  // The spdystream needs to see flattened http headers
-  // The Frame Buffer currently holds the complete SYN_REPLY
-  // frame. The interesting data is at offset 14, where the
-  // compressed name/value header block lives.
-  // We unpack that into the mDecompressBuffer - we can't do
-  // it streamed because the version and status information
-  // is not guaranteed to be first. This is then finally
-  // converted to HTTP format in mFlatHTTPResponseHeaders
-
-  nsresult rv = self->DownstreamUncompress(self->mInputFrameBuffer + 14,
-                                           self->mInputFrameDataSize - 6);
-  if (NS_FAILED(rv)) {
-    LOG(("SpdySession::HandleSynReply uncompress failed\n"));
-    return rv;
-  }
+  LOG3(("SpdySession::HandleSynReplyForValidStream %p SYN_REPLY for 0x%X "
+        "fin=%d",
+        this, mInputFrameDataStream->StreamID(), mInputFrameDataLast));
   
   Telemetry::Accumulate(Telemetry::SPDY_SYN_REPLY_SIZE,
-                        self->mInputFrameDataSize - 6);
-  if (self->mDecompressBufferUsed) {
+                        mInputFrameDataSize - 6);
+  if (mDecompressBufferUsed) {
     PRUint32 ratio =
-      (self->mInputFrameDataSize - 6) * 100 / self->mDecompressBufferUsed;
+      (mInputFrameDataSize - 6) * 100 / mDecompressBufferUsed;
     Telemetry::Accumulate(Telemetry::SPDY_SYN_REPLY_RATIO, ratio);
   }
 
   // status and version are required.
   nsDependentCSubstring status, version;
-  rv = self->FindHeader(NS_LITERAL_CSTRING("status"), status);
+  nsresult rv = FindHeader(NS_LITERAL_CSTRING("status"), status);
+  if (NS_FAILED(rv))
+    return (rv == NS_ERROR_NOT_AVAILABLE) ? NS_ERROR_ILLEGAL_VALUE : rv;
+
+  rv = FindHeader(NS_LITERAL_CSTRING("version"), version);
+  if (NS_FAILED(rv))
+    return (rv == NS_ERROR_NOT_AVAILABLE) ? NS_ERROR_ILLEGAL_VALUE : rv;
+
+  // The spdystream needs to see flattened http headers
+  // Uncompressed spdy format headers currently live in
+  // mDeccompressBuffer - convert that to HTTP format in
+  // mFlatHTTPResponseHeaders in ConvertHeaders()
+
+  rv = ConvertHeaders(status, version);
   if (NS_FAILED(rv))
     return rv;
 
-  rv = self->FindHeader(NS_LITERAL_CSTRING("version"), version);
-  if (NS_FAILED(rv))
-    return rv;
-
-  rv = self->ConvertHeaders(status, version);
-  if (NS_FAILED(rv))
-    return rv;
-
-  self->ChangeDownstreamState(PROCESSING_CONTROL_SYN_REPLY);
+  mInputFrameDataStream->UpdateTransportReadEvents(mInputFrameDataSize);
+  ChangeDownstreamState(PROCESSING_CONTROL_SYN_REPLY);
   return NS_OK;
 }
 
 nsresult
 SpdySession::HandleRstStream(SpdySession *self)
 {
   NS_ABORT_IF_FALSE(self->mFrameControlType == CONTROL_TYPE_RST_STREAM,
                     "wrong control type");
@@ -1469,40 +1483,40 @@ SpdySession::WriteSegments(nsAHttpSegmen
 
     if (mDownstreamRstReason != RST_REFUSED_STREAM &&
         mDownstreamRstReason != RST_CANCEL)
       mShouldGoAway = true;
 
     // mInputFrameDataStream is reset by ChangeDownstreamState
     SpdyStream *stream = mInputFrameDataStream;
     ResetDownstreamState();
-    CleanupStream(stream, rv);
+    CleanupStream(stream, rv, RST_CANCEL);
     return NS_OK;
   }
 
   if (mDownstreamState == PROCESSING_DATA_FRAME ||
       mDownstreamState == PROCESSING_CONTROL_SYN_REPLY) {
 
     mSegmentWriter = writer;
     rv = mInputFrameDataStream->WriteSegments(this, count, countWritten);
     mSegmentWriter = nsnull;
 
     if (rv == NS_BASE_STREAM_CLOSED) {
       // This will happen when the transaction figures out it is EOF, generally
       // due to a content-length match being made
       SpdyStream *stream = mInputFrameDataStream;
       if (mInputFrameDataRead == mInputFrameDataSize)
         ResetDownstreamState();
-      CleanupStream(stream, NS_OK);
+      CleanupStream(stream, NS_OK, RST_CANCEL);
       NS_ABORT_IF_FALSE(!mNeedsCleanup, "double cleanup out of data frame");
       return NS_OK;
     }
     
     if (mNeedsCleanup) {
-      CleanupStream(mNeedsCleanup, NS_OK);
+      CleanupStream(mNeedsCleanup, NS_OK, RST_CANCEL);
       mNeedsCleanup = nsnull;
     }
 
     // In v3 this is where we would generate a window update
 
     return rv;
   }
 
@@ -1617,17 +1631,17 @@ SpdySession::CloseTransaction(nsAHttpTra
   if (!stream) {
     LOG3(("SpdySession::CloseTransaction %p %p %x - not found.",
           this, aTransaction, aResult));
     return;
   }
   LOG3(("SpdySession::CloseTranscation probably a cancel. "
         "this=%p, trans=%p, result=%x, streamID=0x%X stream=%p",
         this, aTransaction, aResult, stream->StreamID(), stream));
-  CleanupStream(stream, aResult);
+  CleanupStream(stream, aResult, RST_CANCEL);
   ResumeRecv();
 }
 
 
 //-----------------------------------------------------------------------------
 // nsAHttpSegmentReader
 //-----------------------------------------------------------------------------
 
--- a/netwerk/protocol/http/SpdySession.h
+++ b/netwerk/protocol/http/SpdySession.h
@@ -100,17 +100,17 @@ public:
     CONTROL_TYPE_NOOP = 5,
     CONTROL_TYPE_PING = 6,
     CONTROL_TYPE_GOAWAY = 7,
     CONTROL_TYPE_HEADERS = 8,
     CONTROL_TYPE_WINDOW_UPDATE = 9,               /* no longer in v2 */
     CONTROL_TYPE_LAST = 10
   };
 
-  enum
+  enum rstReason
   {
     RST_PROTOCOL_ERROR = 1,
     RST_INVALID_STREAM = 2,
     RST_REFUSED_STREAM = 3,
     RST_UNSUPPORTED_VERSION = 4,
     RST_CANCEL = 5,
     RST_INTERNAL_ERROR = 6,
     RST_FLOW_CONTROL_ERROR = 7,
@@ -176,28 +176,29 @@ private:
     BUFFERING_FRAME_HEADER,
     BUFFERING_CONTROL_FRAME,
     PROCESSING_DATA_FRAME,
     DISCARDING_DATA_FRAME,
     PROCESSING_CONTROL_SYN_REPLY,
     PROCESSING_CONTROL_RST_STREAM
   };
 
+  nsresult    HandleSynReplyForValidStream();
   PRUint32    GetWriteQueueSize();
   void        ChangeDownstreamState(enum stateType);
   void        ResetDownstreamState();
   nsresult    DownstreamUncompress(char *, PRUint32);
   void        zlibInit();
   nsresult    FindHeader(nsCString, nsDependentCSubstring &);
   nsresult    ConvertHeaders(nsDependentCSubstring &,
                              nsDependentCSubstring &);
   void        GeneratePing(PRUint32);
   void        GenerateRstStream(PRUint32, PRUint32);
   void        GenerateGoAway();
-  void        CleanupStream(SpdyStream *, nsresult);
+  void        CleanupStream(SpdyStream *, nsresult, rstReason);
 
   void        SetWriteCallbacks();
   void        FlushOutputQueue();
 
   bool        RoomForMoreConcurrent();
   void        ActivateStream(SpdyStream *);
   void        ProcessPending();
 
--- a/netwerk/protocol/http/SpdyStream.cpp
+++ b/netwerk/protocol/http/SpdyStream.cpp
@@ -447,26 +447,41 @@ SpdyStream::ParseHttpRequestHeaders(cons
   
   // 4 to 7 are length and flags, which we can now fill in
   (reinterpret_cast<PRUint32 *>(mTxInlineFrame.get()))[1] =
     PR_htonl(mTxInlineFrameUsed - 8);
 
   NS_ABORT_IF_FALSE(!mTxInlineFrame[4],
                     "Size greater than 24 bits");
   
-  // For methods other than POST and PUT, we will set the fin bit
-  // right on the syn stream packet.
+  // Determine whether to put the fin bit on the syn stream frame or whether
+  // to wait for a data packet to put it on.
 
-  if (mTransaction->RequestHead()->Method() != nsHttp::Post &&
-      mTransaction->RequestHead()->Method() != nsHttp::Put &&
-      mTransaction->RequestHead()->Method() != nsHttp::Options) {
+  if (mTransaction->RequestHead()->Method() == nsHttp::Get ||
+      mTransaction->RequestHead()->Method() == nsHttp::Connect ||
+      mTransaction->RequestHead()->Method() == nsHttp::Head) {
+    // for GET, CONNECT, and HEAD place the fin bit right on the
+    // syn stream packet
+
     mSentFinOnData = 1;
     mTxInlineFrame[4] = SpdySession::kFlag_Data_FIN;
   }
-
+  else if (mTransaction->RequestHead()->Method() == nsHttp::Post ||
+           mTransaction->RequestHead()->Method() == nsHttp::Put ||
+           mTransaction->RequestHead()->Method() == nsHttp::Options) {
+    // place fin in a data frame even for 0 length messages, I've seen
+    // the google gateway be unhappy with fin-on-syn for 0 length POST
+  }
+  else if (!mRequestBodyLenRemaining) {
+    // for other HTTP extension methods, rely on the content-length
+    // to determine whether or not to put fin on syn
+    mSentFinOnData = 1;
+    mTxInlineFrame[4] = SpdySession::kFlag_Data_FIN;
+  }
+  
   Telemetry::Accumulate(Telemetry::SPDY_SYN_SIZE, mTxInlineFrameUsed - 18);
 
   // The size of the input headers is approximate
   PRUint32 ratio =
     (mTxInlineFrameUsed - 18) * 100 /
     (11 + mTransaction->RequestHead()->RequestURI().Length() +
      mFlatHttpRequestHeaders.Length());
   
--- a/services/sync/tests/unit/test_jpakeclient.js
+++ b/services/sync/tests/unit/test_jpakeclient.js
@@ -61,16 +61,21 @@ function server_report(request, response
     if (channel) {
       channel.clear();
     }
   }
 
   response.setStatusLine(request.httpVersion, 200, "OK");
 }
 
+// Hook for test code.
+let hooks = {
+  onGET: function onGET(request) {}
+}
+
 function ServerChannel() {
   this.data = "";
   this.etag = "";
   this.getCount = 0;
 }
 ServerChannel.prototype = {
 
   GET: function GET(request, response) {
@@ -78,28 +83,30 @@ ServerChannel.prototype = {
       response.setStatusLine(request.httpVersion, 404, "Not Found");
       return;
     }
 
     if (request.hasHeader("If-None-Match")) {
       let etag = request.getHeader("If-None-Match");
       if (etag == this.etag) {
         response.setStatusLine(request.httpVersion, 304, "Not Modified");
+        hooks.onGET(request);
         return;
       }
     }
     response.setHeader("ETag", this.etag);
     response.setStatusLine(request.httpVersion, 200, "OK");
     response.bodyOutputStream.write(this.data, this.data.length);
 
     // Automatically clear the channel after 6 successful GETs.
     this.getCount += 1;
     if (this.getCount == SERVER_MAX_GETS) {
       this.clear();
     }
+    hooks.onGET(request);
   },
 
   PUT: function PUT(request, response) {
     if (this.data) {
       do_check_true(request.hasHeader("If-Match"));
       let etag = request.getHeader("If-Match");
       if (etag != this.etag) {
         response.setHeader("ETag", this.etag);
@@ -289,19 +296,25 @@ add_test(function test_lastMsgMaxTries()
  let snd = new JPAKEClient({
     __proto__: BaseController,
     onPaired: function onPaired() {
       // For the purpose of the tests, the poll interval is 50ms and
       // we're polling up to 5 times for the last exchange (as opposed
       // to 2 times for other exchanges). So let's pretend it took
       // 150ms to come up with the final payload, which should require
       // 3 polls.
-      _("Pairing successful, waiting 150ms to send final payload.");
-      Utils.namedTimer(function() { snd.sendAndComplete(DATA); },
-                       150, this, "_sendTimer");
+      // Rather than using an imprecise timer, we hook into the channel's
+      // GET handler to know how long to wait.
+      let count = 0;
+      hooks.onGET = function onGET(request) {
+        if (++count == 3) {
+          _("Third GET. Triggering send.");
+          Utils.nextTick(function() { snd.sendAndComplete(DATA); });
+        }
+      };
     },
     onComplete: function onComplete() {}
   });
 
   let rec = new JPAKEClient({
     __proto__: BaseController,
     displayPIN: function displayPIN(pin) {
       _("Received PIN " + pin + ". Entering it in the other computer...");
@@ -309,16 +322,19 @@ add_test(function test_lastMsgMaxTries()
       Utils.nextTick(function() { snd.pairWithPIN(pin, false); });
     },
     onPairingStart: function onPairingStart(pin) {},
     onComplete: function onComplete(data) {
       do_check_true(Utils.deepEquals(DATA, data));
       // Ensure channel was cleared, no error report.
       do_check_eq(channels[this.cid].data, undefined);
       do_check_eq(error_report, undefined);
+
+      // Clean up.
+      hooks.onGET = function onGET(request) {};
       run_next_test();
     }
   });
 
   rec.receiveNoPIN();
 });
 
 
--- a/testing/mochitest/tests/SimpleTest/specialpowersAPI.js
+++ b/testing/mochitest/tests/SimpleTest/specialpowersAPI.js
@@ -151,30 +151,38 @@ function isXrayWrapper(x) {
 }
 
 // We can't call apply() directy on Xray-wrapped functions, so we have to be
 // clever.
 function doApply(fun, invocant, args) {
   return Function.prototype.apply.call(fun, invocant, args);
 }
 
+// Use a weak map to cache wrappers. This allows the wrappers to preserve identity.
+var wrapperCache = WeakMap();
+
 function wrapPrivileged(obj) {
 
   // Primitives pass straight through.
   if (!isWrappable(obj))
     return obj;
 
   // No double wrapping.
   if (isWrapper(obj))
     throw "Trying to double-wrap object!";
 
+  // Try the cache.
+  if (wrapperCache.has(obj))
+    return wrapperCache.get(obj);
+
   // Make our core wrapper object.
   var handler = new SpecialPowersHandler(obj);
 
   // If the object is callable, make a function proxy.
+  var wrapper;
   if (typeof obj === "function") {
     var callTrap = function() {
       // The invocant and arguments may or may not be wrappers. Unwrap them if necessary.
       var invocant = unwrapIfWrapped(this);
       var unwrappedArgs = Array.prototype.slice.call(arguments).map(unwrapIfWrapped);
 
       return wrapPrivileged(doApply(obj, invocant, unwrappedArgs));
     };
@@ -188,21 +196,26 @@ function wrapPrivileged(obj) {
       var FakeConstructor = function() {
         doApply(obj, this, unwrappedArgs);
       };
       FakeConstructor.prototype = obj.prototype;
 
       return wrapPrivileged(new FakeConstructor());
     };
 
-    return Proxy.createFunction(handler, callTrap, constructTrap);
+    wrapper = Proxy.createFunction(handler, callTrap, constructTrap);
+  }
+  // Otherwise, just make a regular object proxy.
+  else {
+    wrapper = Proxy.create(handler);
   }
 
-  // Otherwise, just make a regular object proxy.
-  return Proxy.create(handler);
+  // Cache the wrapper and return it.
+  wrapperCache.set(obj, wrapper);
+  return wrapper;
 };
 
 function unwrapPrivileged(x) {
 
   // We don't wrap primitives, so sometimes we have a primitive where we'd
   // expect to have a wrapper. The proxy pretends to be the type that it's
   // emulating, so we can just as easily check isWrappable() on a proxy as
   // we can on an unwrapped object.
@@ -403,19 +416,16 @@ SpecialPowersAPI.prototype = {
    * object containing a reference to the underlying object, where all method
    * calls and property accesses are transparently performed with the System
    * Principal. Moreover, objects obtained from the wrapper (including properties
    * and method return values) are wrapped automatically. Thus, after a single
    * call to SpecialPowers.wrap(), the wrapper layer is transitively maintained.
    *
    * Known Issues:
    *
-   *  - The wrapping function does not preserve identity, so
-   *    SpecialPowers.wrap(foo) !== SpecialPowers.wrap(foo). See bug 718543.
-   *
    *  - The wrapper cannot see expando properties on unprivileged DOM objects.
    *    That is to say, the wrapper uses Xray delegation.
    *
    *  - The wrapper sometimes guesses certain ES5 attributes for returned
    *    properties. This is explained in a comment in the wrapper code above,
    *    and shouldn't be a problem.
    */
   wrap: wrapPrivileged,
--- a/testing/mochitest/tests/test_SpecialPowersExtension.html
+++ b/testing/mochitest/tests/test_SpecialPowersExtension.html
@@ -129,16 +129,23 @@ function starttest(){
   noxray.__proto__ = noxray_proto;
   var noxray_wrapper = SpecialPowers.wrap(noxray);
   is(noxray_wrapper.c, 32, "Regular properties should work.");
   is(noxray_wrapper.a, 5, "Shadow properties should work.");
   is(noxray_wrapper.b, 12, "Proto properties should work.");
   noxray.b = 122;
   is(noxray_wrapper.b, 122, "Should be able to shadow.");
 
+  // Check that the wrapper preserves identity.
+  var someIdentityObject = {a: 2};
+  ok(SpecialPowers.wrap(someIdentityObject) === SpecialPowers.wrap(someIdentityObject),
+     "SpecialPowers wrapping should preserve identity!");
+  ok(webnav === SpecialPowers.wrap(SpecialPowers.unwrap(webnav)),
+     "SpecialPowers wrapping should preserve identity!");
+
   info("\nProfile::SpecialPowersRunTime: " + (new Date() - startTime) + "\n");
   SimpleTest.finish();
 }
 </script>
 </pre>
 </body>
 </html>
 
--- a/widget/android/AndroidJNI.cpp
+++ b/widget/android/AndroidJNI.cpp
@@ -60,19 +60,18 @@
 #endif
 
 #include "mozilla/unused.h"
 
 #include "mozilla/dom/sms/SmsMessage.h"
 #include "mozilla/dom/sms/Constants.h"
 #include "mozilla/dom/sms/Types.h"
 #include "mozilla/dom/sms/PSms.h"
-#include "mozilla/dom/sms/SmsRequestManager.h"
-#include "mozilla/dom/sms/SmsRequest.h"
 #include "mozilla/dom/sms/SmsParent.h"
+#include "nsISmsRequestManager.h"
 #include "nsISmsDatabaseService.h"
 
 using namespace mozilla;
 using namespace mozilla::dom::sms;
 
 /* Forward declare all the JNI methods as extern "C" */
 
 extern "C" {
@@ -340,17 +339,21 @@ Java_org_mozilla_gecko_GeckoAppShell_not
         if (!obs) {
           return NS_OK;
         }
 
         nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(mMessageData);
         obs->NotifyObservers(message, kSmsSentObserverTopic, nsnull);
 
         if (mProcessId == 0) { // Parent process.
-          SmsRequestManager::GetInstance()->NotifySmsSent(mRequestId, message);
+          nsCOMPtr<nsISmsRequestManager> requestManager
+            = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+          if (requestManager) {
+            requestManager->NotifySmsSent(mRequestId, message);
+          }
         } else { // Content process.
           nsTArray<SmsParent*> spList;
           SmsParent::GetAll(spList);
 
           for (PRUint32 i=0; i<spList.Length(); ++i) {
             unused << spList[i]->SendNotifyRequestSmsSent(mMessageData,
                                                           mRequestId,
                                                           mProcessId);
@@ -414,49 +417,54 @@ Java_org_mozilla_gecko_GeckoAppShell_not
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_notifySmsSendFailed(JNIEnv* jenv, jclass,
                                                          jint aError,
                                                          jint aRequestId,
                                                          jlong aProcessId)
 {
     class NotifySmsSendFailedRunnable : public nsRunnable {
     public:
-      NotifySmsSendFailedRunnable(SmsRequest::ErrorType aError,
-                                  PRInt32 aRequestId, PRUint64 aProcessId)
+      NotifySmsSendFailedRunnable(PRInt32 aError,
+                                  PRInt32 aRequestId,
+                                  PRUint64 aProcessId)
         : mError(aError)
         , mRequestId(aRequestId)
         , mProcessId(aProcessId)
       {}
 
       NS_IMETHODIMP Run() {
         if (mProcessId == 0) { // Parent process.
-          SmsRequestManager::GetInstance()->NotifySmsSendFailed(mRequestId, mError);
+          nsCOMPtr<nsISmsRequestManager> requestManager
+            = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+          if (requestManager) {
+            requestManager->NotifySmsSendFailed(mRequestId, mError);
+          }
         } else { // Content process.
           nsTArray<SmsParent*> spList;
           SmsParent::GetAll(spList);
 
           for (PRUint32 i=0; i<spList.Length(); ++i) {
             unused << spList[i]->SendNotifyRequestSmsSendFailed(mError,
                                                                 mRequestId,
                                                                 mProcessId);
           }
         }
 
         return NS_OK;
       }
 
     private:
-      SmsRequest::ErrorType mError;
-      PRInt32               mRequestId;
-      PRUint64              mProcessId;
+      PRInt32  mError;
+      PRInt32  mRequestId;
+      PRUint64 mProcessId;
     };
 
 
     nsCOMPtr<nsIRunnable> runnable =
-      new NotifySmsSendFailedRunnable(SmsRequest::ErrorType(aError), aRequestId, aProcessId);
+      new NotifySmsSendFailedRunnable(aError, aRequestId, aProcessId);
     NS_DispatchToMainThread(runnable);
 }
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_notifyGetSms(JNIEnv* jenv, jclass,
                                                   jint aId,
                                                   jstring aReceiver,
                                                   jstring aSender,
@@ -472,17 +480,21 @@ Java_org_mozilla_gecko_GeckoAppShell_not
         : mMessageData(aMessageData)
         , mRequestId(aRequestId)
         , mProcessId(aProcessId)
       {}
 
       NS_IMETHODIMP Run() {
         if (mProcessId == 0) { // Parent process.
           nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(mMessageData);
-          SmsRequestManager::GetInstance()->NotifyGotSms(mRequestId, message);
+          nsCOMPtr<nsISmsRequestManager> requestManager
+            = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+          if (requestManager) {
+            requestManager->NotifyGotSms(mRequestId, message);
+          }
         } else { // Content process.
           nsTArray<SmsParent*> spList;
           SmsParent::GetAll(spList);
 
           for (PRUint32 i=0; i<spList.Length(); ++i) {
             unused << spList[i]->SendNotifyRequestGotSms(mMessageData,
                                                          mRequestId,
                                                          mProcessId);
@@ -512,49 +524,54 @@ Java_org_mozilla_gecko_GeckoAppShell_not
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_notifyGetSmsFailed(JNIEnv* jenv, jclass,
                                                         jint aError,
                                                         jint aRequestId,
                                                         jlong aProcessId)
 {
     class NotifyGetSmsFailedRunnable : public nsRunnable {
     public:
-      NotifyGetSmsFailedRunnable(SmsRequest::ErrorType aError,
-                                  PRInt32 aRequestId, PRUint64 aProcessId)
+      NotifyGetSmsFailedRunnable(PRInt32 aError,
+                                 PRInt32 aRequestId,
+                                 PRUint64 aProcessId)
         : mError(aError)
         , mRequestId(aRequestId)
         , mProcessId(aProcessId)
       {}
 
       NS_IMETHODIMP Run() {
         if (mProcessId == 0) { // Parent process.
-          SmsRequestManager::GetInstance()->NotifyGetSmsFailed(mRequestId, mError);
+          nsCOMPtr<nsISmsRequestManager> requestManager
+            = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+          if (requestManager) {
+            requestManager->NotifyGetSmsFailed(mRequestId, mError);
+          }
         } else { // Content process.
           nsTArray<SmsParent*> spList;
           SmsParent::GetAll(spList);
 
           for (PRUint32 i=0; i<spList.Length(); ++i) {
             unused << spList[i]->SendNotifyRequestGetSmsFailed(mError,
                                                                mRequestId,
                                                                mProcessId);
           }
         }
 
         return NS_OK;
       }
 
     private:
-      SmsRequest::ErrorType mError;
-      PRInt32               mRequestId;
-      PRUint64              mProcessId;
+      PRInt32  mError;
+      PRInt32  mRequestId;
+      PRUint64 mProcessId;
     };
 
 
     nsCOMPtr<nsIRunnable> runnable =
-      new NotifyGetSmsFailedRunnable(SmsRequest::ErrorType(aError), aRequestId, aProcessId);
+      new NotifyGetSmsFailedRunnable(aError, aRequestId, aProcessId);
     NS_DispatchToMainThread(runnable);
 }
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_notifySmsDeleted(JNIEnv* jenv, jclass,
                                                       jboolean aDeleted,
                                                       jint aRequestId,
                                                       jlong aProcessId)
@@ -565,17 +582,21 @@ Java_org_mozilla_gecko_GeckoAppShell_not
                                PRUint64 aProcessId)
         : mDeleted(aDeleted)
         , mRequestId(aRequestId)
         , mProcessId(aProcessId)
       {}
 
       NS_IMETHODIMP Run() {
         if (mProcessId == 0) { // Parent process.
-          SmsRequestManager::GetInstance()->NotifySmsDeleted(mRequestId, mDeleted);
+          nsCOMPtr<nsISmsRequestManager> requestManager
+            = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+          if (requestManager) {
+            requestManager->NotifySmsDeleted(mRequestId, mDeleted);
+          }
         } else { // Content process.
           nsTArray<SmsParent*> spList;
           SmsParent::GetAll(spList);
 
           for (PRUint32 i=0; i<spList.Length(); ++i) {
             unused << spList[i]->SendNotifyRequestSmsDeleted(mDeleted,
                                                              mRequestId,
                                                              mProcessId);
@@ -600,49 +621,54 @@ Java_org_mozilla_gecko_GeckoAppShell_not
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_notifySmsDeleteFailed(JNIEnv* jenv, jclass,
                                                            jint aError,
                                                            jint aRequestId,
                                                            jlong aProcessId)
 {
     class NotifySmsDeleteFailedRunnable : public nsRunnable {
     public:
-      NotifySmsDeleteFailedRunnable(SmsRequest::ErrorType aError,
-                                    PRInt32 aRequestId, PRUint64 aProcessId)
+      NotifySmsDeleteFailedRunnable(PRInt32 aError,
+                                    PRInt32 aRequestId,
+                                    PRUint64 aProcessId)
         : mError(aError)
         , mRequestId(aRequestId)
         , mProcessId(aProcessId)
       {}
 
       NS_IMETHODIMP Run() {
         if (mProcessId == 0) { // Parent process.
-          SmsRequestManager::GetInstance()->NotifySmsDeleteFailed(mRequestId, mError);
+          nsCOMPtr<nsISmsRequestManager> requestManager
+            = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+          if (requestManager) {
+            requestManager->NotifySmsDeleteFailed(mRequestId, mError);
+          }
         } else { // Content process.
           nsTArray<SmsParent*> spList;
           SmsParent::GetAll(spList);
 
           for (PRUint32 i=0; i<spList.Length(); ++i) {
             unused << spList[i]->SendNotifyRequestSmsDeleteFailed(mError,
                                                                   mRequestId,
                                                                   mProcessId);
           }
         }
 
         return NS_OK;
       }
 
     private:
-      SmsRequest::ErrorType mError;
-      PRInt32               mRequestId;
-      PRUint64              mProcessId;
+      PRInt32  mError;
+      PRInt32  mRequestId;
+      PRUint64 mProcessId;
     };
 
 
     nsCOMPtr<nsIRunnable> runnable =
-      new NotifySmsDeleteFailedRunnable(SmsRequest::ErrorType(aError), aRequestId, aProcessId);
+      new NotifySmsDeleteFailedRunnable(aError, aRequestId, aProcessId);
     NS_DispatchToMainThread(runnable);
 }
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_notifyNoMessageInList(JNIEnv* jenv, jclass,
                                                            jint aRequestId,
                                                            jlong aProcessId)
 {
@@ -650,17 +676,21 @@ Java_org_mozilla_gecko_GeckoAppShell_not
     public:
       NotifyNoMessageInListRunnable(PRInt32 aRequestId, PRUint64 aProcessId)
         : mRequestId(aRequestId)
         , mProcessId(aProcessId)
       {}
 
       NS_IMETHODIMP Run() {
         if (mProcessId == 0) { // Parent process.
-          SmsRequestManager::GetInstance()->NotifyNoMessageInList(mRequestId);
+          nsCOMPtr<nsISmsRequestManager> requestManager
+            = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+          if (requestManager) {
+            requestManager->NotifyNoMessageInList(mRequestId);
+          }
         } else { // Content process.
           nsTArray<SmsParent*> spList;
           SmsParent::GetAll(spList);
 
           for (PRUint32 i=0; i<spList.Length(); ++i) {
             unused << spList[i]->SendNotifyRequestNoMessageInList(mRequestId,
                                                                   mProcessId);
           }
@@ -700,19 +730,23 @@ Java_org_mozilla_gecko_GeckoAppShell_not
         , mMessage(aMessage)
         , mRequestId(aRequestId)
         , mProcessId(aProcessId)
       {}
 
       NS_IMETHODIMP Run() {
         if (mProcessId == 0) { // Parent process.
           nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(mMessage);
-          SmsRequestManager::GetInstance()->NotifyCreateMessageList(mRequestId,
-                                                                    mListId,
-                                                                    message);
+          nsCOMPtr<nsISmsRequestManager> requestManager
+            = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+          if (requestManager) {
+            requestManager->NotifyCreateMessageList(mRequestId,
+                                                    mListId,
+                                                    message);
+          }
         } else { // Content process.
           nsTArray<SmsParent*> spList;
           SmsParent::GetAll(spList);
 
           for (PRUint32 i=0; i<spList.Length(); ++i) {
             unused << spList[i]->SendNotifyRequestCreateMessageList(mListId,
                                                                     mMessage,
                                                                     mRequestId,
@@ -760,18 +794,21 @@ Java_org_mozilla_gecko_GeckoAppShell_not
         : mMessage(aMessage)
         , mRequestId(aRequestId)
         , mProcessId(aProcessId)
       {}
 
       NS_IMETHODIMP Run() {
         if (mProcessId == 0) { // Parent process.
           nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(mMessage);
-          SmsRequestManager::GetInstance()->NotifyGotNextMessage(mRequestId,
-                                                                 message);
+          nsCOMPtr<nsISmsRequestManager> requestManager
+            = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+          if (requestManager) {
+            requestManager->NotifyGotNextMessage(mRequestId, message);
+          }
         } else { // Content process.
           nsTArray<SmsParent*> spList;
           SmsParent::GetAll(spList);
 
           for (PRUint32 i=0; i<spList.Length(); ++i) {
             unused << spList[i]->SendNotifyRequestGotNextMessage(mMessage,
                                                                  mRequestId,
                                                                  mProcessId);
@@ -803,49 +840,54 @@ Java_org_mozilla_gecko_GeckoAppShell_not
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_notifyReadingMessageListFailed(JNIEnv* jenv, jclass,
                                                                     jint aError,
                                                                     jint aRequestId,
                                                                     jlong aProcessId)
 {
     class NotifyReadListFailedRunnable : public nsRunnable {
     public:
-      NotifyReadListFailedRunnable(SmsRequest::ErrorType aError,
-                                    PRInt32 aRequestId, PRUint64 aProcessId)
+      NotifyReadListFailedRunnable(PRInt32 aError,
+                                   PRInt32 aRequestId,
+                                   PRUint64 aProcessId)
         : mError(aError)
         , mRequestId(aRequestId)
         , mProcessId(aProcessId)
       {}
 
       NS_IMETHODIMP Run() {
         if (mProcessId == 0) { // Parent process.
-          SmsRequestManager::GetInstance()->NotifyReadMessageListFailed(mRequestId, mError);
+          nsCOMPtr<nsISmsRequestManager> requestManager
+            = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
+          if (requestManager) {
+            requestManager->NotifyReadMessageListFailed(mRequestId, mError);
+          }
         } else { // Content process.
           nsTArray<SmsParent*> spList;
           SmsParent::GetAll(spList);
 
           for (PRUint32 i=0; i<spList.Length(); ++i) {
             unused << spList[i]->SendNotifyRequestReadListFailed(mError,
                                                                  mRequestId,
                                                                  mProcessId);
           }
         }
 
         return NS_OK;
       }
 
     private:
-      SmsRequest::ErrorType mError;
-      PRInt32               mRequestId;
-      PRUint64              mProcessId;
+      PRInt32  mError;
+      PRInt32  mRequestId;
+      PRUint64 mProcessId;
     };
 
 
     nsCOMPtr<nsIRunnable> runnable =
-      new NotifyReadListFailedRunnable(SmsRequest::ErrorType(aError), aRequestId, aProcessId);
+      new NotifyReadListFailedRunnable(aError, aRequestId, aProcessId);
     NS_DispatchToMainThread(runnable);
 }
 
 #ifdef MOZ_JAVA_COMPOSITOR
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_bindWidgetTexture(JNIEnv* jenv, jclass)
 {
--- a/xpcom/ds/TimeStamp.h
+++ b/xpcom/ds/TimeStamp.h
@@ -88,16 +88,19 @@ public:
   // durations up to over 280,000 years exactly.  If the units of
   // mValue do not allow us to represent durations of that length,
   // long durations are clamped to the max/min representable value
   // instead of overflowing.
   static inline TimeDuration FromSeconds(double aSeconds) {
     return FromMilliseconds(aSeconds * 1000.0);
   }
   static TimeDuration FromMilliseconds(double aMilliseconds);
+  static inline TimeDuration FromMicroseconds(double aMicroseconds) {
+    return FromMilliseconds(aMicroseconds / 1000.0);
+  }
 
   TimeDuration operator+(const TimeDuration& aOther) const {
     return TimeDuration::FromTicks(mValue + aOther.mValue);
   }
   TimeDuration operator-(const TimeDuration& aOther) const {
     return TimeDuration::FromTicks(mValue - aOther.mValue);
   }
   TimeDuration& operator+=(const TimeDuration& aOther) {
--- a/xulrunner/stub/nsXULStub.cpp
+++ b/xulrunner/stub/nsXULStub.cpp
@@ -390,17 +390,17 @@ main(int argc, char **argv)
     if (fwurl) {
       absfwurl = CFURLCopyAbsoluteURL(fwurl);
       CFRelease(fwurl);
     }
 
     if (absfwurl) {
       CFURLRef xulurl =
         CFURLCreateCopyAppendingPathComponent(NULL, absfwurl,
-                                              CFSTR("XUL.Framework"),
+                                              CFSTR("XUL.framework"),
                                               true);
 
       if (xulurl) {
         CFURLRef xpcomurl =
           CFURLCreateCopyAppendingPathComponent(NULL, xulurl,
                                                 CFSTR("libxpcom.dylib"),
                                                 false);