Merge central to inbound
authorJustin Wood <Callek@gmail.com>
Sat, 02 Mar 2013 13:33:21 -0500
changeset 123594 18c3ffc28f4a80eeaa1cb9c9fd020f800de060f6
parent 123512 edf9c64f821e437865b3cfa9eb32036198e59567 (current diff)
parent 123593 b6fe70978ee5011e6b0d3db3daf0e97af76a246c (diff)
child 123595 3bdcde3b122c2a1a938565c80fb5dd65ca9d9682
push id1395
push userryanvm@gmail.com
push dateSun, 03 Mar 2013 04:46:03 +0000
treeherderfx-team@78a7a63eec08 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone22.0a1
Merge central to inbound
accessible/src/msaa/ARIAGridAccessibleWrap.cpp
accessible/src/msaa/ARIAGridAccessibleWrap.h
accessible/src/msaa/AccessibleWrap.cpp
accessible/src/msaa/AccessibleWrap.h
accessible/src/msaa/ApplicationAccessibleWrap.cpp
accessible/src/msaa/ApplicationAccessibleWrap.h
accessible/src/msaa/Compatibility.cpp
accessible/src/msaa/Compatibility.h
accessible/src/msaa/DocAccessibleWrap.cpp
accessible/src/msaa/DocAccessibleWrap.h
accessible/src/msaa/EnumVariant.cpp
accessible/src/msaa/EnumVariant.h
accessible/src/msaa/HTMLTableAccessibleWrap.cpp
accessible/src/msaa/HTMLTableAccessibleWrap.h
accessible/src/msaa/HTMLWin32ObjectAccessible.cpp
accessible/src/msaa/HTMLWin32ObjectAccessible.h
accessible/src/msaa/HyperTextAccessibleWrap.cpp
accessible/src/msaa/HyperTextAccessibleWrap.h
accessible/src/msaa/ImageAccessibleWrap.cpp
accessible/src/msaa/ImageAccessibleWrap.h
accessible/src/msaa/Makefile.in
accessible/src/msaa/Platform.cpp
accessible/src/msaa/RootAccessibleWrap.cpp
accessible/src/msaa/RootAccessibleWrap.h
accessible/src/msaa/ServiceProvider.cpp
accessible/src/msaa/ServiceProvider.h
accessible/src/msaa/TextLeafAccessibleWrap.cpp
accessible/src/msaa/TextLeafAccessibleWrap.h
accessible/src/msaa/XULListboxAccessibleWrap.cpp
accessible/src/msaa/XULListboxAccessibleWrap.h
accessible/src/msaa/XULMenuAccessibleWrap.cpp
accessible/src/msaa/XULMenuAccessibleWrap.h
accessible/src/msaa/XULTreeGridAccessibleWrap.cpp
accessible/src/msaa/XULTreeGridAccessibleWrap.h
accessible/src/msaa/moz.build
accessible/src/msaa/nsAccessNodeWrap.cpp
accessible/src/msaa/nsAccessNodeWrap.h
accessible/src/msaa/nsEventMap.h
accessible/src/msaa/nsWinUtils.cpp
accessible/src/msaa/nsWinUtils.h
browser/devtools/shared/Browser.jsm
browser/devtools/shared/test/browser_browser_basic.js
content/svg/content/src/DOMSVGTests.cpp
content/svg/content/src/DOMSVGTests.h
js/src/builtin/ParallelArray-inl.h
js/src/jit-test/tests/parallelarray/filter-1.js
js/src/jit-test/tests/parallelarray/filter-2.js
js/src/jit-test/tests/parallelarray/filter-3.js
js/src/jit-test/tests/parallelarray/filter-4.js
js/src/jit-test/tests/parallelarray/get-throws.js
js/src/jit-test/tests/parallelarray/map-1.js
mach
--- a/accessible/build/Makefile.in
+++ b/accessible/build/Makefile.in
@@ -23,25 +23,29 @@ CPPSRCS		= nsAccessibilityFactory.cpp
 
 LOCAL_INCLUDES	= -I$(srcdir)/../src
 
 SHARED_LIBRARY_LIBS = \
   ../src/base/$(LIB_PREFIX)accessibility_base_s.$(LIB_SUFFIX) \
   ../src/generic/$(LIB_PREFIX)accessibility_generic_s.$(LIB_SUFFIX) \
   ../src/html/$(LIB_PREFIX)accessibility_html_s.$(LIB_SUFFIX) \
   ../src/xpcom/$(LIB_PREFIX)accessibility_xpcom_s.$(LIB_SUFFIX) \
-  ../src/$(LIB_PREFIX)accessibility_toolkit_s.$(LIB_SUFFIX) \
   $(NULL)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 SHARED_LIBRARY_LIBS += \
+  ../src/windows/msaa/$(LIB_PREFIX)accessibility_toolkit_msaa_s.$(LIB_SUFFIX) \
   ../src/windows/ia2/$(LIB_PREFIX)accessibility_toolkit_ia2_s.$(LIB_SUFFIX) \
   ../src/windows/sdn/$(LIB_PREFIX)accessibility_toolkit_sdn_s.$(LIB_SUFFIX) \
   ../src/windows/uia/$(LIB_PREFIX)accessibility_toolkit_uia_s.$(LIB_SUFFIX) \
   $(NULL)
+else
+SHARED_LIBRARY_LIBS += \
+  ../src/$(LIB_PREFIX)accessibility_toolkit_s.$(LIB_SUFFIX) \
+  $(NULL)
 endif
 
 ifdef MOZ_XUL
 SHARED_LIBRARY_LIBS += ../src/xul/$(LIB_PREFIX)accessibility_xul_s.$(LIB_SUFFIX)
 endif
 
 include $(topsrcdir)/config/rules.mk
 
--- a/accessible/src/base/Makefile.in
+++ b/accessible/src/base/Makefile.in
@@ -89,17 +89,17 @@ LOCAL_INCLUDES += \
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
 LOCAL_INCLUDES += \
   -I$(srcdir)/../atk \
   $(NULL)
 else
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 LOCAL_INCLUDES += \
-  -I$(srcdir)/../msaa \
+  -I$(srcdir)/../windows/msaa \
   -I$(srcdir)/../windows/ia2 \
   $(NULL)
 else
 ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 LOCAL_INCLUDES += \
   -I$(srcdir)/../mac \
   $(NULL)
 else
--- a/accessible/src/generic/Makefile.in
+++ b/accessible/src/generic/Makefile.in
@@ -55,17 +55,17 @@ LOCAL_INCLUDES = \
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
 LOCAL_INCLUDES += \
   -I$(srcdir)/../atk \
   $(NULL)
 else
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 LOCAL_INCLUDES += \
-  -I$(srcdir)/../msaa \
+  -I$(srcdir)/../windows/msaa \
   $(NULL)
 else
 ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 LOCAL_INCLUDES += \
   -I$(srcdir)/../mac \
   $(NULL)
 else
 LOCAL_INCLUDES += \
--- a/accessible/src/html/Makefile.in
+++ b/accessible/src/html/Makefile.in
@@ -45,17 +45,17 @@ LOCAL_INCLUDES = \
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
 LOCAL_INCLUDES += \
   -I$(srcdir)/../atk \
   $(NULL)
 else
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 LOCAL_INCLUDES += \
-  -I$(srcdir)/../msaa \
+  -I$(srcdir)/../windows/msaa \
   -I$(srcdir)/../windows/ia2 \
   $(NULL)
 else
 ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 LOCAL_INCLUDES += \
   -I$(srcdir)/../mac \
   $(NULL)
 else
--- a/accessible/src/moz.build
+++ b/accessible/src/moz.build
@@ -3,17 +3,17 @@
 # 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/.
 
 toolkit = CONFIG['MOZ_WIDGET_TOOLKIT']
 
 if toolkit == 'gtk2':
     DIRS += ['atk']
 elif toolkit == 'windows':
-    DIRS += ['msaa', 'windows']
+    DIRS += ['windows']
 elif toolkit == 'cocoa':
     DIRS += ['mac']
 else:
     DIRS += ['other']
 
 
 DIRS += ['base', 'generic', 'html', 'jsat', 'xpcom']
 
--- a/accessible/src/windows/ia2/Makefile.in
+++ b/accessible/src/windows/ia2/Makefile.in
@@ -46,19 +46,19 @@ OS_CXXFLAGS += -DNOMINMAX
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
   -I$(srcdir) \
+  -I$(srcdir)/../msaa \
   -I$(srcdir)/../../base \
   -I$(srcdir)/../../generic \
   -I$(srcdir)/../../html \
-  -I$(srcdir)/../../msaa \
   -I$(srcdir)/../../xpcom \
   -I$(srcdir)/../../xul \
   $(NULL)
 
 ifdef A11Y_LOG
   DEFINES += -DA11Y_LOG
 endif
--- a/accessible/src/windows/moz.build
+++ b/accessible/src/windows/moz.build
@@ -1,7 +1,7 @@
 # vim: set filetype=python:
 # 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/.
 
-DIRS += ['ia2', 'sdn', 'uia']
+DIRS += ['msaa', 'ia2', 'sdn', 'uia']
 
rename from accessible/src/msaa/ARIAGridAccessibleWrap.cpp
rename to accessible/src/windows/msaa/ARIAGridAccessibleWrap.cpp
rename from accessible/src/msaa/ARIAGridAccessibleWrap.h
rename to accessible/src/windows/msaa/ARIAGridAccessibleWrap.h
rename from accessible/src/msaa/AccessibleWrap.cpp
rename to accessible/src/windows/msaa/AccessibleWrap.cpp
rename from accessible/src/msaa/AccessibleWrap.h
rename to accessible/src/windows/msaa/AccessibleWrap.h
rename from accessible/src/msaa/ApplicationAccessibleWrap.cpp
rename to accessible/src/windows/msaa/ApplicationAccessibleWrap.cpp
rename from accessible/src/msaa/ApplicationAccessibleWrap.h
rename to accessible/src/windows/msaa/ApplicationAccessibleWrap.h
rename from accessible/src/msaa/Compatibility.cpp
rename to accessible/src/windows/msaa/Compatibility.cpp
rename from accessible/src/msaa/Compatibility.h
rename to accessible/src/windows/msaa/Compatibility.h
rename from accessible/src/msaa/DocAccessibleWrap.cpp
rename to accessible/src/windows/msaa/DocAccessibleWrap.cpp
rename from accessible/src/msaa/DocAccessibleWrap.h
rename to accessible/src/windows/msaa/DocAccessibleWrap.h
rename from accessible/src/msaa/EnumVariant.cpp
rename to accessible/src/windows/msaa/EnumVariant.cpp
rename from accessible/src/msaa/EnumVariant.h
rename to accessible/src/windows/msaa/EnumVariant.h
rename from accessible/src/msaa/HTMLTableAccessibleWrap.cpp
rename to accessible/src/windows/msaa/HTMLTableAccessibleWrap.cpp
rename from accessible/src/msaa/HTMLTableAccessibleWrap.h
rename to accessible/src/windows/msaa/HTMLTableAccessibleWrap.h
rename from accessible/src/msaa/HTMLWin32ObjectAccessible.cpp
rename to accessible/src/windows/msaa/HTMLWin32ObjectAccessible.cpp
rename from accessible/src/msaa/HTMLWin32ObjectAccessible.h
rename to accessible/src/windows/msaa/HTMLWin32ObjectAccessible.h
rename from accessible/src/msaa/HyperTextAccessibleWrap.cpp
rename to accessible/src/windows/msaa/HyperTextAccessibleWrap.cpp
rename from accessible/src/msaa/HyperTextAccessibleWrap.h
rename to accessible/src/windows/msaa/HyperTextAccessibleWrap.h
rename from accessible/src/msaa/ImageAccessibleWrap.cpp
rename to accessible/src/windows/msaa/ImageAccessibleWrap.cpp
rename from accessible/src/msaa/ImageAccessibleWrap.h
rename to accessible/src/windows/msaa/ImageAccessibleWrap.h
rename from accessible/src/msaa/Makefile.in
rename to accessible/src/windows/msaa/Makefile.in
--- a/accessible/src/msaa/Makefile.in
+++ b/accessible/src/windows/msaa/Makefile.in
@@ -5,18 +5,18 @@
 DEPTH = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE = accessibility
-LIBRARY_NAME = accessibility_toolkit_s
-EXPORT_LIBRARY = ..
+LIBRARY_NAME = accessibility_toolkit_msaa_s
+EXPORT_LIBRARY = 1
 LIBXUL_LIBRARY = 1
 
 
 CPPSRCS = \
   AccessibleWrap.cpp \
   ApplicationAccessibleWrap.cpp \
   ARIAGridAccessibleWrap.cpp \
   DocAccessibleWrap.cpp \
@@ -58,23 +58,23 @@ EXPORTS_mozilla/a11y = \
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
   -I$(srcdir) \
-  -I$(srcdir)/../base \
-  -I$(srcdir)/../generic \
-  -I$(srcdir)/../html \
-  -I$(srcdir)/../xpcom \
-  -I$(srcdir)/../xul \
-  -I$(srcdir)/../windows/ia2 \
-  -I$(srcdir)/../windows/sdn \
-  -I$(srcdir)/../windows/uia \
-  -I$(srcdir)/../../../content/base/src \
-  -I$(srcdir)/../../../content/events/src \
+  -I$(srcdir)/../../base \
+  -I$(srcdir)/../../generic \
+  -I$(srcdir)/../../html \
+  -I$(srcdir)/../../xpcom \
+  -I$(srcdir)/../../xul \
+  -I$(srcdir)/../ia2 \
+  -I$(srcdir)/../sdn \
+  -I$(srcdir)/../uia \
+  -I$(srcdir)/../../../../content/base/src \
+  -I$(srcdir)/../../../../content/events/src \
   $(NULL)
 
 ifneq ($(A11Y_LOG),0)
   DEFINES += -DA11Y_LOG
 endif
rename from accessible/src/msaa/Platform.cpp
rename to accessible/src/windows/msaa/Platform.cpp
rename from accessible/src/msaa/RootAccessibleWrap.cpp
rename to accessible/src/windows/msaa/RootAccessibleWrap.cpp
rename from accessible/src/msaa/RootAccessibleWrap.h
rename to accessible/src/windows/msaa/RootAccessibleWrap.h
rename from accessible/src/msaa/ServiceProvider.cpp
rename to accessible/src/windows/msaa/ServiceProvider.cpp
rename from accessible/src/msaa/ServiceProvider.h
rename to accessible/src/windows/msaa/ServiceProvider.h
rename from accessible/src/msaa/TextLeafAccessibleWrap.cpp
rename to accessible/src/windows/msaa/TextLeafAccessibleWrap.cpp
rename from accessible/src/msaa/TextLeafAccessibleWrap.h
rename to accessible/src/windows/msaa/TextLeafAccessibleWrap.h
rename from accessible/src/msaa/XULListboxAccessibleWrap.cpp
rename to accessible/src/windows/msaa/XULListboxAccessibleWrap.cpp
rename from accessible/src/msaa/XULListboxAccessibleWrap.h
rename to accessible/src/windows/msaa/XULListboxAccessibleWrap.h
rename from accessible/src/msaa/XULMenuAccessibleWrap.cpp
rename to accessible/src/windows/msaa/XULMenuAccessibleWrap.cpp
rename from accessible/src/msaa/XULMenuAccessibleWrap.h
rename to accessible/src/windows/msaa/XULMenuAccessibleWrap.h
rename from accessible/src/msaa/XULTreeGridAccessibleWrap.cpp
rename to accessible/src/windows/msaa/XULTreeGridAccessibleWrap.cpp
rename from accessible/src/msaa/XULTreeGridAccessibleWrap.h
rename to accessible/src/windows/msaa/XULTreeGridAccessibleWrap.h
rename from accessible/src/msaa/moz.build
rename to accessible/src/windows/msaa/moz.build
rename from accessible/src/msaa/nsAccessNodeWrap.cpp
rename to accessible/src/windows/msaa/nsAccessNodeWrap.cpp
rename from accessible/src/msaa/nsAccessNodeWrap.h
rename to accessible/src/windows/msaa/nsAccessNodeWrap.h
rename from accessible/src/msaa/nsEventMap.h
rename to accessible/src/windows/msaa/nsEventMap.h
rename from accessible/src/msaa/nsWinUtils.cpp
rename to accessible/src/windows/msaa/nsWinUtils.cpp
rename from accessible/src/msaa/nsWinUtils.h
rename to accessible/src/windows/msaa/nsWinUtils.h
--- a/accessible/src/windows/sdn/Makefile.in
+++ b/accessible/src/windows/sdn/Makefile.in
@@ -24,15 +24,15 @@ CPPSRCS += \
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
   -I$(srcdir) \
+  -I$(srcdir)/../msaa \
   -I$(srcdir)/../../base \
   -I$(srcdir)/../../generic \
   -I$(srcdir)/../../html \
-  -I$(srcdir)/../../msaa \
   -I$(srcdir)/../../xpcom \
   -I$(srcdir)/../../xul \
   $(NULL)
--- a/accessible/src/windows/uia/Makefile.in
+++ b/accessible/src/windows/uia/Makefile.in
@@ -25,19 +25,19 @@ CPPSRCS += \
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
   -I$(srcdir) \
+  -I$(srcdir)/../msaa \
   -I$(srcdir)/../../base \
   -I$(srcdir)/../../generic \
   -I$(srcdir)/../../html \
-  -I$(srcdir)/../../msaa \
   -I$(srcdir)/../../xpcom \
   -I$(srcdir)/../../xul \
   $(NULL)
 
 ifdef A11Y_LOG
   DEFINES += -DA11Y_LOG
 endif
--- a/accessible/src/xpcom/Makefile.in
+++ b/accessible/src/xpcom/Makefile.in
@@ -33,17 +33,17 @@ LOCAL_INCLUDES = \
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
 LOCAL_INCLUDES += \
   -I$(srcdir)/../atk \
   $(NULL)
 else
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 LOCAL_INCLUDES += \
-  -I$(srcdir)/../msaa \
+  -I$(srcdir)/../windows/msaa \
   $(NULL)
 else
 ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 LOCAL_INCLUDES += \
   -I$(srcdir)/../mac \
   $(NULL)
 else
 LOCAL_INCLUDES += \
--- a/accessible/src/xul/Makefile.in
+++ b/accessible/src/xul/Makefile.in
@@ -48,17 +48,17 @@ LOCAL_INCLUDES = \
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
 LOCAL_INCLUDES += \
   -I$(srcdir)/../atk \
   $(NULL)
 else
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 LOCAL_INCLUDES += \
-  -I$(srcdir)/../msaa \
+  -I$(srcdir)/../windows/msaa \
   -I$(srcdir)/../windows/ia2 \
   $(NULL)
 else
 ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 LOCAL_INCLUDES += \
   -I$(srcdir)/../mac \
   $(NULL)
 else
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -346,18 +346,24 @@ let SocialChatBar = {
   get isAvailable() {
     return SocialUI.enabled && Social.haveLoggedInUser();
   },
   // Does this chatbar have any chats (whether minimized, collapsed or normal)
   get hasChats() {
     return !!this.chatbar.firstElementChild;
   },
   openChat: function(aProvider, aURL, aCallback, aMode) {
-    if (this.isAvailable)
+    if (this.isAvailable) {
       this.chatbar.openChat(aProvider, aURL, aCallback, aMode);
+      // We only want to focus the chat if it is as a result of user input.
+      let dwu = window.QueryInterface(Ci.nsIInterfaceRequestor)
+                      .getInterface(Ci.nsIDOMWindowUtils);
+      if (dwu.isHandlingUserInput)
+        this.chatbar.focus();
+    }
   },
   update: function() {
     let command = document.getElementById("Social:FocusChat");
     if (!this.isAvailable) {
       this.chatbar.removeAll();
       command.hidden = true;
     } else {
       this.chatbar.hidden = command.hidden = document.mozFullScreen;
--- a/browser/base/content/socialchat.xml
+++ b/browser/base/content/socialchat.xml
@@ -15,16 +15,47 @@
                            oncommand="document.getBindingParent(this).close();"/>
       </xul:hbox>
       <xul:iframe anonid="iframe" class="chat-frame" flex="1"
                   context="contentAreaContextMenu"
                   xbl:inherits="src,origin,collapsed=minimized" type="content"/>
     </content>
 
     <implementation implements="nsIDOMEventListener">
+      <constructor><![CDATA[
+        let Social = Components.utils.import("resource:///modules/Social.jsm", {}).Social;
+        Social.setErrorListener(this.iframe, function(iframe) {
+          iframe.webNavigation.loadURI("about:socialerror?mode=compactInfo", null, null, null, null);
+        });
+        let iframeWindow = this.iframe.contentWindow;
+        this.addEventListener("DOMContentLoaded", function DOMContentLoaded() {
+          this.removeEventListener("DOMContentLoaded", DOMContentLoaded);
+          this.isActive = !this.minimized;
+          // process this._callbacks, then set to null so the chatbox creator
+          // knows to make new callbacks immediately.
+          for (let callback of this._callbacks) {
+            if (callback)
+              callback(iframeWindow);
+          }
+          this._callbacks = null;
+
+          // content can send a socialChatActivity event to have the UI update.
+          let chatActivity = function() {
+            this.setAttribute("activity", true);
+            this.parentNode.updateTitlebar(this);
+          }.bind(this);
+          iframeWindow.addEventListener("socialChatActivity", chatActivity);
+          iframeWindow.addEventListener("unload", function unload() {
+            iframeWindow.removeEventListener("unload", unload);
+            iframeWindow.removeEventListener("socialChatActivity", chatActivity);
+          });
+        });
+        this.setAttribute("src", this.src);
+      ]]></constructor>
+
       <field name="iframe" readonly="true">
         document.getAnonymousElementByAttribute(this, "anonid", "iframe");
       </field>
 
       <property name="minimized">
         <getter>
           return this.getAttribute("minimized") == "true";
         </getter>
@@ -56,19 +87,22 @@
           evt.initCustomEvent(val ? "socialFrameShow" : "socialFrameHide", true, true, {});
           this.iframe.contentDocument.documentElement.dispatchEvent(evt);
         </setter>
       </property>
 
       <method name="onTitlebarClick">
         <parameter name="aEvent"/>
         <body><![CDATA[
-          if (aEvent.button == 0) // left-click: toggle minimized.
+          if (aEvent.button == 0) { // left-click: toggle minimized.
             this.toggle();
-          else if (aEvent.button == 1) // middle-click: close chat
+            // if we restored it, we want to focus it.
+            if (!this.minimized)
+              this.parentNode.focus();
+          } else if (aEvent.button == 1) // middle-click: close chat
             this.close();
         ]]></body>
       </method>
 
       <method name="close">
         <body><![CDATA[
           this.parentNode.remove(this);
         ]]></body>
@@ -140,18 +174,35 @@
       <field name="nub" readonly="true">
         document.getAnonymousElementByAttribute(this, "anonid", "nub");
       </field>
 
       <method name="focus">
         <body><![CDATA[
           if (!this.selectedChat)
             return;
-          let commandDispatcher = gBrowser.ownerDocument.commandDispatcher;
-          commandDispatcher.advanceFocusIntoSubtree(this.selectedChat);
+          Services.focus.focusedWindow = this.selectedChat.iframe.contentWindow;
+        ]]></body>
+      </method>
+
+      <method name="_isChatFocused">
+        <parameter name="aChatbox"/>
+        <body><![CDATA[
+          // If there are no XBL bindings for the chat it can't be focused.
+          if (!aChatbox.iframe)
+            return false;
+          let fw = Services.focus.focusedWindow;
+          if (!fw)
+            return false;
+          // We want to see if the focused window is in the subtree below our iframe...
+          let containingBrowser = fw.QueryInterface(Ci.nsIInterfaceRequestor)
+                                    .getInterface(Ci.nsIWebNavigation)
+                                    .QueryInterface(Ci.nsIDocShell)
+                                    .chromeEventHandler;
+          return containingBrowser == aChatbox.iframe;
         ]]></body>
       </method>
 
       <property name="selectedChat">
         <getter><![CDATA[
           return this._selectedChat;
         ]]></getter>
         <setter><![CDATA[
@@ -163,17 +214,16 @@
           // * need to handle either current or new being null.
           if (this._selectedChat != val) {
             if (this._selectedChat) {
               this._selectedChat.removeAttribute("selected");
             }
             this._selectedChat = val;
             if (val) {
               this._selectedChat.setAttribute("selected", "true");
-              this.focus();
             }
           }
           if (val) {
             this._selectedChat.removeAttribute("activity");
           }
         ]]></setter>
       </property>
 
@@ -226,19 +276,22 @@
         <body><![CDATA[
           // Select a different chat (as the currently selected one is no
           // longer suitable as the selection - maybe it is being minimized or
           // closed.)  We only select non-minimized and non-collapsed chats,
           // and if none are found, set the selectedChat to null.
           // It's possible in the future we will track most-recently-selected
           // chats or similar to find the "best" candidate - for now though
           // the choice is somewhat arbitrary.
+          let moveFocus = this.selectedChat && this._isChatFocused(this.selectedChat);
           for (let other of this.children) {
             if (other != this.selectedChat && !other.minimized && !other.collapsed) {
               this.selectedChat = other;
+              if (moveFocus)
+                this.focus();
               return;
             }
           }
           // can't find another - so set no chat as selected.
           this.selectedChat = null;
         ]]></body>
       </method>
 
@@ -376,61 +429,16 @@
           while (this.firstElementChild) {
             this._remove(this.firstElementChild);
           }
           // and the nub/popup must also die.
           this.nub.collapsed = true;
         ]]></body>
       </method>
 
-      <method name="initChatBox">
-        <!-- ideally this would be a method on the chatbox itself, but the
-             vagaries of XBL bindings means that in some edge cases the
-             chatbox methods don't exist yet when we need them to...
-        -->
-        <parameter name="aChatBox"/>
-        <parameter name="aProvider"/>
-        <parameter name="aURL"/>
-        <parameter name="aCallback"/>
-        <body><![CDATA[
-          // callbacks to be called when onload fires - more might be added
-          // if the same chat is requested before onload has fired.  Set back
-          // to null in DOMContentLoaded, so null means DOMContentLoaded has
-          // already fired and new callbacks can be made immediately.
-          aChatBox._callbacks = [aCallback];
-          var tmp = {};
-          Components.utils.import("resource:///modules/Social.jsm", tmp);
-          tmp.Social.setErrorListener(aChatBox.iframe, function(iframe) {
-            iframe.webNavigation.loadURI("about:socialerror?mode=compactInfo", null, null, null, null);
-          });
-          let iframeWindow = aChatBox.iframe.contentWindow;
-          aChatBox.addEventListener("DOMContentLoaded", function DOMContentLoaded() {
-            aChatBox.removeEventListener("DOMContentLoaded", DOMContentLoaded);
-            aChatBox.isActive = !aChatBox.minimized;
-            for (let callback of aChatBox._callbacks) {
-              if (callback)
-                callback(iframeWindow);
-            }
-            aChatBox._callbacks = null;
-            function chatActivity() {
-              aChatBox.setAttribute("activity", true);
-              aChatBox.parentNode.updateTitlebar(aChatBox);
-            };
-
-            iframeWindow.addEventListener("socialChatActivity", chatActivity);
-            iframeWindow.addEventListener("unload", function unload() {
-              iframeWindow.removeEventListener("unload", unload);
-              iframeWindow.removeEventListener("socialChatActivity", chatActivity);
-            });
-          });
-
-          aChatBox.setAttribute("origin", aProvider.origin);
-          aChatBox.setAttribute("src", aURL);
-        ]]></body>
-      </method>
       <method name="openChat">
         <parameter name="aProvider"/>
         <parameter name="aURL"/>
         <parameter name="aCallback"/>
         <parameter name="aMode"/>
         <body><![CDATA[
           let cb = this.chatboxForURL.get(aURL);
           if (cb) {
@@ -446,21 +454,26 @@
                   cb._callbacks.push(aCallback);
                 }
               }
               return;
             }
             this.chatboxForURL.delete(aURL);
           }
           cb = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "chatbox");
+          // _callbacks is a javascript property instead of a <field> as it
+          // must exist before the (possibly delayed) bindings are created.
+          cb._callbacks = [aCallback];
+          // src also a javascript property; the src attribute is set in the ctor.
+          cb.src = aURL;
           if (aMode == "minimized")
             cb.setAttribute("minimized", "true");
+          cb.setAttribute("origin", aProvider.origin);
           this.insertBefore(cb, this.firstChild);
           this.selectedChat = cb;
-          this.initChatBox(cb, aProvider, aURL, aCallback);
           this.chatboxForURL.set(aURL, Cu.getWeakReference(cb));
           this.resize();
         ]]></body>
       </method>
 
       <method name="resize">
         <body><![CDATA[
         // Checks the current size against the collapsed state of children
--- a/browser/base/content/test/social/Makefile.in
+++ b/browser/base/content/test/social/Makefile.in
@@ -19,16 +19,17 @@ include $(DEPTH)/config/autoconf.mk
                  browser_social_perwindowPB.js \
                  browser_social_toolbar.js \
                  browser_social_shareButton.js \
                  browser_social_sidebar.js \
                  browser_social_flyout.js \
                  browser_social_mozSocial_API.js \
                  browser_social_isVisible.js \
                  browser_social_chatwindow.js \
+                 browser_social_chatwindowfocus.js \
                  browser_social_multiprovider.js \
                  browser_social_errorPage.js \
                  social_panel.html \
                  social_share_image.png \
                  social_sidebar.html \
                  social_chat.html \
                  social_flyout.html \
                  social_window.html \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/social/browser_social_chatwindowfocus.js
@@ -0,0 +1,309 @@
+/* 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/. */
+
+// Is the currently opened tab focused?
+function isTabFocused() {
+  let tabb = gBrowser.getBrowserForTab(gBrowser.selectedTab);
+  return Services.focus.focusedWindow == tabb.contentWindow;
+}
+
+function isChatFocused(chat) {
+  return SocialChatBar.chatbar._isChatFocused(chat);
+}
+
+function openChatViaUser() {
+  let sidebarDoc = document.getElementById("social-sidebar-browser").contentDocument;
+  let button = sidebarDoc.getElementById("chat-opener");
+  // Note we must use synthesizeMouseAtCenter() rather than calling
+  // .click() directly as this causes nsIDOMWindowUtils.isHandlingUserInput
+  // to be true.
+  EventUtils.synthesizeMouseAtCenter(button, {}, sidebarDoc.defaultView);
+}
+
+function openChatViaSidebarMessage(port, data, callback) {
+  port.onmessage = function (e) {
+    if (e.data.topic == "chatbox-opened")
+      callback();
+  }
+  port.postMessage({topic: "test-chatbox-open", data: data});
+}
+
+function openChatViaWorkerMessage(port, data, callback) {
+  // sadly there is no message coming back to tell us when the chat has
+  // been opened, so we wait until one appears.
+  let chatbar = SocialChatBar.chatbar;
+  let numExpected = chatbar.childElementCount + 1;
+  port.postMessage({topic: "test-worker-chat", data: data});
+  waitForCondition(function() chatbar.childElementCount == numExpected,
+                   function() {
+                      // so the child has been added, but we don't know if it
+                      // has been intialized - re-request it and the callback
+                      // means it's done.  Minimized, same as the worker.
+                      SocialChatBar.openChat(Social.provider,
+                                             data,
+                                             function() {
+                                                callback();
+                                             },
+                                             "minimized");
+                   },
+                   "No new chat appeared");
+}
+
+
+let isSidebarLoaded = false;
+
+function startTestAndWaitForSidebar(callback) {
+  let doneCallback;
+  let port = Social.provider.getWorkerPort();
+  function maybeCallback() {
+    if (!doneCallback)
+      callback(port);
+    doneCallback = true;
+  }
+  port.onmessage = function(e) {
+    let topic = e.data.topic;
+    switch (topic) {
+      case "got-sidebar-message":
+        isSidebarLoaded = true;
+        maybeCallback();
+        break;
+      case "test-init-done":
+        if (isSidebarLoaded)
+          maybeCallback();
+        break;
+    }
+  }
+  port.postMessage({topic: "test-init"});
+}
+
+let manifest = { // normal provider
+  name: "provider 1",
+  origin: "https://example.com",
+  sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar.html",
+  workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js",
+  iconURL: "https://example.com/browser/browser/base/content/test/moz.png"
+};
+
+function test() {
+  waitForExplicitFinish();
+
+  // Note that (probably) due to bug 604289, if a tab is focused but the
+  // focused element is null, our chat windows can "steal" focus.  This is
+  // avoided if we explicitly focus an element in the tab.
+  // So we load a page with an <input> field and focus that before testing.
+  let url = "data:text/html;charset=utf-8," + encodeURI('<input id="theinput">');
+  let tab = gBrowser.selectedTab = gBrowser.addTab(url, {skipAnimation: true});
+  tab.linkedBrowser.addEventListener("load", function tabLoad(event) {
+    tab.linkedBrowser.removeEventListener("load", tabLoad, true);
+    // before every test we focus the input field.
+    let preSubTest = function(cb) {
+      // XXX - when bug 604289 is fixed it should be possible to just do:
+      // tab.linkedBrowser.contentWindow.focus()
+      // but instead we must do:
+      tab.linkedBrowser.contentDocument.getElementById("theinput").focus();
+      cb();
+    }
+    let postSubTest = function(cb) {
+      window.SocialChatBar.chatbar.removeAll();
+      cb();
+    }
+    // and run the tests.
+    runSocialTestWithProvider(manifest, function (finishcb) {
+      runSocialTests(tests, preSubTest, postSubTest, function () {
+        finishcb();
+      });
+    });
+  }, true);
+  registerCleanupFunction(function() {
+    gBrowser.removeTab(tab);
+  });
+
+}
+
+var tests = {
+  // In this test the worker asks the sidebar to open a chat.  As that means
+  // we aren't handling user-input we will not focus the chatbar.
+  // Then we do it again - should still not be focused.
+  // Then we perform a user-initiated request - it should get focus.
+  testNoFocusWhenViaWorker: function(next) {
+    startTestAndWaitForSidebar(function(port) {
+      openChatViaSidebarMessage(port, {stealFocus: 1}, function() {
+        ok(true, "got chatbox message");
+        is(SocialChatBar.chatbar.childElementCount, 1, "exactly 1 chat open");
+        ok(isTabFocused(), "tab should still be focused");
+        // re-request the same chat via a message.
+        openChatViaSidebarMessage(port, {stealFocus: 1}, function() {
+          is(SocialChatBar.chatbar.childElementCount, 1, "still exactly 1 chat open");
+          ok(isTabFocused(), "tab should still be focused");
+          // re-request the same chat via user event.
+          openChatViaUser();
+          is(SocialChatBar.chatbar.childElementCount, 1, "still exactly 1 chat open");
+          // should now be focused
+          ok(isChatFocused(SocialChatBar.chatbar.firstElementChild), "chat should be focused");
+          next();
+        });
+      });
+    });
+  },
+
+  // In this test we arrange for the sidebar to open the chat via a simulated
+  // click.  This should cause the new chat to be opened and focused.
+  testFocusWhenViaUser: function(next) {
+    startTestAndWaitForSidebar(function(port) {
+      openChatViaUser();
+      ok(SocialChatBar.chatbar.firstElementChild, "chat opened");
+      ok(isChatFocused(SocialChatBar.chatbar.firstElementChild), "chat should be focused");
+      next();
+    });
+  },
+
+  // Open a chat via the worker - it will open minimized and not have focus.
+  // Then open the same chat via a sidebar message - it will be restored but
+  // should still not have grabbed focus.
+  testNoFocusOnAutoRestore: function(next) {
+    const chatUrl = "https://example.com/browser/browser/base/content/test/social/social_chat.html?id=1";
+    let chatbar = SocialChatBar.chatbar;
+    startTestAndWaitForSidebar(function(port) {
+      openChatViaWorkerMessage(port, chatUrl, function() {
+        is(chatbar.childElementCount, 1, "exactly 1 chat open");
+        ok(chatbar.firstElementChild.minimized, "chat is minimized");
+        ok(isTabFocused(), "tab should be focused");
+        openChatViaSidebarMessage(port, {stealFocus: 1, id: 1}, function() {
+          is(chatbar.childElementCount, 1, "still 1 chat open");
+          ok(!chatbar.firstElementChild.minimized, "chat no longer minimized");
+          ok(isTabFocused(), "tab should still be focused");
+          next();
+        });
+      });
+    });
+  },
+
+  // Here we open a chat, which will not be focused.  Then we minimize it and
+  // restore it via a titlebar clock - it should get focus at that point.
+  testFocusOnExplicitRestore: function(next) {
+    startTestAndWaitForSidebar(function(port) {
+      openChatViaSidebarMessage(port, {stealFocus: 1}, function() {
+        ok(true, "got chatbox message");
+        ok(isTabFocused(), "tab should still be focused");
+        let chatbox = SocialChatBar.chatbar.firstElementChild;
+        ok(chatbox, "chat opened");
+        chatbox.minimized = true;
+        ok(isTabFocused(), "tab should still be focused");
+        // pretend we clicked on the titlebar
+        chatbox.onTitlebarClick({button: 0});
+        ok(!chatbox.minimized, "chat should have been restored");
+        ok(isChatFocused(chatbox), "chat should be focused");
+        next();
+      });
+    });
+  },
+
+  // Open 2 chats and give 1 focus.  Minimize the focused one - the second
+  // should get focus.
+  testMinimizeFocused: function(next) {
+    let chatbar = SocialChatBar.chatbar;
+    startTestAndWaitForSidebar(function(port) {
+      openChatViaSidebarMessage(port, {stealFocus: 1, id: 1}, function() {
+        let chat1 = chatbar.firstElementChild;
+        openChatViaSidebarMessage(port, {stealFocus: 1, id: 2}, function() {
+          is(chatbar.childElementCount, 2, "exactly 2 chats open");
+          let chat2 = chat1.nextElementSibling || chat1.previousElementSibling;
+          chatbar.selectedChat = chat1;
+          chatbar.focus();
+          ok(isChatFocused(chat1), "first chat should be focused");
+          chat1.minimized = true;
+          // minimizing the chat with focus should give it to another.
+          ok(isChatFocused(chat2), "second chat should be focused");
+          next();
+        });
+      });
+    });
+  },
+
+  // Open 2 chats, select (but not focus) one, then re-request it be
+  // opened via a message.  Focus should not move.
+  testReopenNonFocused: function(next) {
+    let chatbar = SocialChatBar.chatbar;
+    startTestAndWaitForSidebar(function(port) {
+      openChatViaSidebarMessage(port, {id: 1}, function() {
+        let chat1 = chatbar.firstElementChild;
+        openChatViaSidebarMessage(port, {id: 2}, function() {
+          let chat2 = chat1.nextElementSibling || chat1.previousElementSibling;
+          chatbar.selectedChat = chat2;
+          // tab still has focus
+          ok(isTabFocused(), "tab should still be focused");
+          // re-request the first.
+          openChatViaSidebarMessage(port, {id: 1}, function() {
+            is(chatbar.selectedChat, chat1, "chat1 now selected");
+            ok(isTabFocused(), "tab should still be focused");
+            next();
+          });
+        });
+      });
+    });
+  },
+
+  // Open 2 chats, select and focus the second.  Pressing the TAB key should
+  // cause focus to move between all elements in our chat window before moving
+  // to the next chat window.
+  testTab: function(next) {
+    let chatbar = SocialChatBar.chatbar;
+    startTestAndWaitForSidebar(function(port) {
+      openChatViaSidebarMessage(port, {id: 1}, function() {
+        let chat1 = chatbar.firstElementChild;
+        openChatViaSidebarMessage(port, {id: 2}, function() {
+          let chat2 = chat1.nextElementSibling || chat1.previousElementSibling;
+          chatbar.selectedChat = chat2;
+          chatbar.focus();
+          ok(isChatFocused(chat2), "new chat is focused");
+          // Our chats have 3 focusable elements, so it takes 4 TABs to move
+          // to the new chat.
+          EventUtils.sendKey("tab");
+          ok(isChatFocused(chat2), "new chat still focused after first tab");
+          is(chat2.iframe.contentDocument.activeElement.getAttribute("id"), "input1",
+             "first input field has focus");
+          EventUtils.sendKey("tab");
+          ok(isChatFocused(chat2), "new chat still focused after tab");
+          is(chat2.iframe.contentDocument.activeElement.getAttribute("id"), "input2",
+             "second input field has focus");
+          EventUtils.sendKey("tab");
+          ok(isChatFocused(chat2), "new chat still focused after tab");
+          is(chat2.iframe.contentDocument.activeElement.getAttribute("id"), "iframe",
+             "iframe has focus");
+          // this tab now should move to the next chat.
+          EventUtils.sendKey("tab");
+          ok(isChatFocused(chat1), "first chat is focused");
+          next();
+        });
+      });
+    });
+  },
+
+  // Open a chat and focus an element other than the first. Move focus to some
+  // other item (the tab itself in this case), then focus the chatbar - the
+  // same element that was previously focused should still have focus.
+  testFocusedElement: function(next) {
+    let chatbar = SocialChatBar.chatbar;
+    startTestAndWaitForSidebar(function(port) {
+      openChatViaUser();
+      let chat = chatbar.firstElementChild;
+      // need to wait for the content to load before we can focus it.
+      chat.addEventListener("DOMContentLoaded", function DOMContentLoaded() {
+        chat.removeEventListener("DOMContentLoaded", DOMContentLoaded);
+        chat.iframe.contentDocument.getElementById("input2").focus();
+        is(chat.iframe.contentDocument.activeElement.getAttribute("id"), "input2",
+           "correct input field has focus");
+        // set focus to the tab.
+        let tabb = gBrowser.getBrowserForTab(gBrowser.selectedTab);
+        Services.focus.moveFocus(tabb.contentWindow, null, Services.focus.MOVEFOCUS_ROOT, 0);
+        ok(isTabFocused(), "tab took focus");
+        chatbar.focus();
+        ok(isChatFocused(chat), "chat took focus");
+        is(chat.iframe.contentDocument.activeElement.getAttribute("id"), "input2",
+           "correct input field still has focus");
+        next();
+      });
+    });
+  },
+};
--- a/browser/base/content/test/social/social_chat.html
+++ b/browser/base/content/test/social/social_chat.html
@@ -16,12 +16,16 @@
       }, false);
       window.addEventListener("socialTest-CloseSelf", function(e) {
         window.close();
       }, false);
     </script>
   </head>
   <body onload="pingWorker();">
     <p>This is a test social chat window.</p>
+    <!-- a couple of input fields to help with focus testing -->
+    <input id="input1"/>
+    <input id="input2"/>
+
     <!-- an iframe here so this one page generates multiple load events -->
     <iframe id="iframe" src="data:text/plain:this is an iframe"></iframe>
   </body>
 </html>
--- a/browser/base/content/test/social/social_sidebar.html
+++ b/browser/base/content/test/social/social_sidebar.html
@@ -16,26 +16,32 @@
               break;
             case "test-chatbox-open":
               var url = "social_chat.html";
               var data = e.data.data;
               if (data && data.id) {
                 url = url + "?id="+data.id;
               }
               navigator.mozSocial.openChatWindow(url, function(chatwin) {
+                // Note that the following .focus() call should *not* arrange
+                // to steal focus - see browser_social_chatwindowfocus.js
+                if (data && data.stealFocus && chatwin) {
+                  chatwin.focus();
+                }
                 port.postMessage({topic: "chatbox-opened",
                                   result: chatwin ? "ok" : "failed"});
               });
               break;
             case "test-isVisible":
               port.postMessage({topic: "test-isVisible-response",
                                 result: navigator.mozSocial.isVisible});
               break;
           }
         }
         port.postMessage({topic: "sidebar-message", result: "ok"});
       }
     </script>
   </head>
   <body onload="pingWorker();">
     <p>This is a test social sidebar.</p>
+    <button id="chat-opener" onclick="navigator.mozSocial.openChatWindow('./social_chat.html');"/>
   </body>
 </html>
--- a/browser/metro/base/content/ContextCommands.js
+++ b/browser/metro/base/content/ContextCommands.js
@@ -5,16 +5,25 @@
 
  /*
   * context menu command handlers
   */
 
 var ContextCommands = {
   _picker: null,
 
+  get _ellipsis() {
+    delete this._ellipsis;
+    this._ellipsis = "\u2026";
+    try {
+      this._ellipsis = Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString).data;
+    } catch (ex) { }
+    return this._ellipsis;
+  },
+
   get clipboard() {
     return Cc["@mozilla.org/widget/clipboardhelper;1"]
              .getService(Ci.nsIClipboardHelper);
   },
 
   get docRef() {
     return Browser.selectedBrowser.contentWindow.document;
   },
@@ -93,31 +102,36 @@ var ContextCommands = {
       target.focus();
     }
   },
 
   // called on display of the search text menu item
   searchTextSetup: function cc_searchTextSetup(aRichListItem, aSearchString) {
     let defaultURI;
     let defaultName;
+    aSearchString = aSearchString.trim();
     try {
       let defaultPB = Services.prefs.getDefaultBranch(null);
       const nsIPLS = Ci.nsIPrefLocalizedString;
       defaultName = defaultPB.getComplexValue("browser.search.defaultenginename", nsIPLS).data;
       let defaultEngine = Services.search.getEngineByName(defaultName);
       defaultURI = defaultEngine.getSubmission(aSearchString).uri.spec;
     } catch (ex) {
       Cu.reportError(ex);
       return false;
     }
+    let displayString = aSearchString;
+    if (displayString.length > 15) {
+      displayString = displayString.substring(0, 15) + this._ellipsis;
+    }
     // label child node
     let label = Services.strings
                         .createBundle("chrome://browser/locale/browser.properties")
-                        .formatStringFromName("browser.search.contextTextSearchLabel",
-                                              [defaultName], 1);
+                        .formatStringFromName("browser.search.contextTextSearchLabel2",
+                                              [defaultName, displayString], 2);
     aRichListItem.childNodes[0].setAttribute("value", label);
     aRichListItem.setAttribute("searchString", defaultURI);
     return true;
   },
 
   searchText: function cc_searchText(aRichListItem) {
     let defaultURI = aRichListItem.getAttribute("searchString");
     aRichListItem.childNodes[0].setAttribute("value", "");
@@ -350,16 +364,15 @@ var ContextCommands = {
                                   this._pickerContentDisp,
                                   this._contentType, false, "SaveImageTitle",
                                   new AutoChosen(file, Util.makeURI(this._pickerUrl, null, null)),
                                   getBrowser().documentURI, this.docRef, true, null);
 
     var newDir = file.parent.QueryInterface(Ci.nsILocalFile);
     Services.prefs.setComplexValue("browser.download.lastDir", Ci.nsILocalFile, newDir);
   },
-
 };
 
 function AutoChosen(aFileAutoChosen, aUriAutoChosen) {
   this.file = aFileAutoChosen;
   this.uri  = aUriAutoChosen;
 }
 
--- a/browser/metro/base/content/browser-ui.js
+++ b/browser/metro/base/content/browser-ui.js
@@ -753,16 +753,42 @@ var BrowserUI = {
         CommandUpdater.doCommand("cmd_forward");
         break;
       case 1:
         CommandUpdater.doCommand("cmd_scrollPageDown");
         break;
     }
   },
 
+  openFile: function() {
+    try {
+      const nsIFilePicker = Ci.nsIFilePicker;
+      let fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
+      let self = this;
+      let fpCallback = function fpCallback_done(aResult) {
+        if (aResult == nsIFilePicker.returnOK) {
+          self.goToURI(fp.fileURL.spec);
+        }
+      };
+
+      let windowTitle = Strings.browser.GetStringFromName("browserForOpenLocation");
+      fp.init(window, windowTitle, nsIFilePicker.modeOpen);
+      fp.appendFilters(nsIFilePicker.filterAll | nsIFilePicker.filterText |
+                       nsIFilePicker.filterImages | nsIFilePicker.filterXML |
+                       nsIFilePicker.filterHTML);
+      fp.open(fpCallback);
+    } catch (ex) {
+      dump ('BrowserUI openFile exception: ' + ex + '\n');
+    }
+  },
+
+  savePage: function() {
+    Browser.savePage();
+  },
+
   receiveMessage: function receiveMessage(aMessage) {
     let browser = aMessage.target;
     let json = aMessage.json;
     switch (aMessage.name) {
       case "DOMTitleChanged":
         this._titleChanged(browser);
         break;
       case "DOMWillOpenModalDialog":
@@ -807,16 +833,18 @@ var BrowserUI = {
       case "cmd_actions":
       case "cmd_panel":
       case "cmd_flyout_back":
       case "cmd_sanitize":
       case "cmd_zoomin":
       case "cmd_zoomout":
       case "cmd_volumeLeft":
       case "cmd_volumeRight":
+      case "cmd_openFile":
+      case "cmd_savePage":
         isSupported = true;
         break;
       default:
         isSupported = false;
         break;
     }
     return isSupported;
   },
@@ -930,16 +958,22 @@ var BrowserUI = {
       case "cmd_volumeLeft":
         // Zoom in (portrait) or out (landscape)
         Browser.zoom(Util.isPortrait() ? -1 : 1);
         break;
       case "cmd_volumeRight":
         // Zoom out (portrait) or in (landscape)
         Browser.zoom(Util.isPortrait() ? 1 : -1);
         break;
+      case "cmd_openFile":
+        this.openFile();
+        break;
+      case "cmd_savePage":
+        this.savePage();
+        break;
     }
   }
 };
 
 /**
  * Tracks whether context UI (app bar, tab bar, url bar) is shown or hidden.
  * Manages events to summon and hide the context UI.
  */
--- a/browser/metro/base/content/browser.js
+++ b/browser/metro/base/content/browser.js
@@ -471,16 +471,20 @@ var Browser = {
     if (aOptions && "forceClose" in aOptions && aOptions.forceClose) {
       this._doCloseTab(aTab);
       return;
     }
 
     tab.browser.messageManager.sendAsyncMessage("Browser:CanUnload", {});
   },
 
+  savePage: function() {
+    ContentAreaUtils.saveDocument(this.selectedBrowser.contentWindow.document);
+  },
+
   _doCloseTab: function _doCloseTab(aTab) {
     let nextTab = this._getNextTab(aTab);
     if (!nextTab)
        return;
 
     // Tabs owned by the closed tab are now orphaned.
     this._tabs.forEach(function(item, index, array) {
       if (item.owner == aTab)
--- a/browser/metro/base/content/browser.xul
+++ b/browser/metro/base/content/browser.xul
@@ -62,16 +62,18 @@
     <command id="cmd_handleBackspace" oncommand="BrowserUI.handleBackspace();" />
     <command id="cmd_handleShiftBackspace" oncommand="BrowserUI.handleShiftBackspace();" />
     <command id="cmd_reload" oncommand="CommandUpdater.doCommand(this.id);"/>
     <command id="cmd_forceReload" oncommand="CommandUpdater.doCommand(this.id);"/>
     <command id="cmd_stop" oncommand="CommandUpdater.doCommand(this.id);"/>
     <command id="cmd_go" oncommand="CommandUpdater.doCommand(this.id);"/>
     <command id="cmd_openLocation" oncommand="CommandUpdater.doCommand(this.id);"/>
     <command id="cmd_home" oncommand="CommandUpdater.doCommand(this.id);"/>
+    <command id="cmd_openFile" oncommand="CommandUpdater.doCommand(this.id);"/>
+    <command id="cmd_savePage" oncommand="CommandUpdater.doCommand(this.id);"/>
 
     <!-- tabs -->
     <command id="cmd_newTab" oncommand="CommandUpdater.doCommand(this.id);"/>
     <command id="cmd_closeTab" oncommand="CommandUpdater.doCommand(this.id);"/>
     <command id="cmd_undoCloseTab" oncommand="CommandUpdater.doCommand(this.id);"/>
 #ifdef MOZ_SERVICES_SYNC
     <command id="cmd_remoteTabs" oncommand="CommandUpdater.doCommand(this.id);"/>
 #endif
@@ -128,16 +130,18 @@
     <key id="key_shift_backspace" keycode="VK_BACK" command="cmd_handleShiftBackspace" modifiers="shift"/>
     <key id="key_reload" keycode="VK_F5" command="cmd_reload"/>
     <key id="key_reload2" key="r" modifiers="accel" command="cmd_reload"/>
     <key id="key_forceReload" keycode="VK_F5" modifiers="shift" command="cmd_forceReload"/>
     <key id="key_forceReload2" key="r" modifiers="accel,shift" command="cmd_forceReload"/>
     <key id="key_focusURL" key="l" modifiers="accel" command="cmd_openLocation"/>
     <key id="key_focusURL2" key="&urlbar.accesskey;" modifiers="alt" command="cmd_openLocation"/>
     <key id="key_home" keycode="VK_HOME" modifiers="accel" command="cmd_home"/>
+    <key id="key_open" key="o" modifiers="accel" command="cmd_openFile"/>
+    <key id="key_save" key="s" modifiers="accel" command="cmd_savePage"/>
 
     <!-- misc -->
     <key id="key_zoomin" key="+" modifiers="accel" command="cmd_zoomin"/>
     <key id="key_zoomout" key="-" modifiers="accel" command="cmd_zoomout"/>
     <key id="key_find" key="f" modifiers="accel" command="cmd_find"/>
     <key id="key_find" key="/" command="cmd_find"/>
     <key id="key_findNext" keycode="VK_F3" command="cmd_findNext"/>
     <key id="key_findNext2" key="g" modifiers="accel" command="cmd_findNext"/>
@@ -567,31 +571,33 @@
     </box>
 #endif
 
     <box id="context-container" class="menu-container" hidden="true">
       <vbox id="context-popup" class="menu-popup">
         <richlistbox id="context-commands" bindingType="contextmenu" flex="1">
           <!-- priority="low" items are hidden by default when a context is being displayed
                for two or more media types. (e.g. a linked image) -->
+          <!-- content types preceeded by '!' act as exclusion rules, the menu item will not 
+               be displayed if the content type is present. -->
           <!-- Note the order of richlistitem here is important as it is reflected in the
                menu itself. -->
           <!-- ux spec: https://bug782810.bugzilla.mozilla.org/attachment.cgi?id=714804 -->
 
           <!-- Text related -->
           <!-- for text inputs, this will copy selected text, or if no text is selected, copy all -->
           <richlistitem id="context-copy" type="copy,selectable" onclick="ContextCommands.copy();">
             <label value="&contextTextCopy.label;"/>
           </richlistitem>
           <!-- only displayed if there is text on the clipboard -->
           <richlistitem id="context-paste" type="paste" onclick="ContextCommands.paste();">
             <label value="&contextTextPaste.label;"/>
           </richlistitem>
-          <!-- Search Bing for "..." -->
-          <richlistitem id="context-search" type="copy,selected-text" onclick="ContextCommands.searchText(this);">
+          <!-- Search Bing for "(text..)", displayed on selected content text only -->
+          <richlistitem id="context-search" type="selected-text,!input-text" onclick="ContextCommands.searchText(this);">
             <label id="context-search-label" value=""/>
           </richlistitem>
           <!-- only display if there is text on the clipboard and the target is the urlbar -->
           <richlistitem id="context-paste-n-go" type="paste-url" onclick="ContextCommands.pasteAndGo();">
             <label value="&contextTextPasteAndGo.label;"/>
           </richlistitem>
           <!-- only displayed in inputs with text that do not have selection -->
           <richlistitem id="context-select" type="selectable" onclick="ContextCommands.select();">
--- a/browser/metro/base/content/helperui/MenuUI.js
+++ b/browser/metro/base/content/helperui/MenuUI.js
@@ -156,16 +156,20 @@ var ContextMenuUI = {
         command.getAttribute("priority") == "low");
       let searchTextItem = (command.id == "context-search");
 
       // filter low priority items if we have more than one media type.
       if (multipleMediaTypes && lowPriority)
         continue;
 
       for (let i = 0; i < types.length; i++) {
+        // If one of the item's types has '!' before it, treat it as an exclusion rule. 
+        if (types[i].charAt(0) == '!' && contentTypes.indexOf(types[i].substring(1)) != -1) {
+          break;
+        }
         if (contentTypes.indexOf(types[i]) != -1) {
           // If this is the special search text item, we need to set its label dynamically.
           if (searchTextItem && !ContextCommands.searchTextSetup(command, this._popupState.string)) {
             break;
           }
           optionsAvailable = true;
           command.hidden = false;
           break;
--- a/browser/metro/locales/en-US/chrome/browser.properties
+++ b/browser/metro/locales/en-US/chrome/browser.properties
@@ -5,27 +5,28 @@
 # Default search engine
 browser.search.defaultenginename=Bing
 
 # Search engine order (order displayed in the search bar dropdown)s
 browser.search.order.1=Bing
 browser.search.order.2=Google
 browser.search.order.3=Yahoo
 
-# l10n: search context menu item text will be: |Search (browser.search.defaultenginename) for ".."
-browser.search.contextTextSearchLabel=Search %S for ".."
+# l10n: search context menu item text will be: |Search (browser.search.defaultenginename) for "(string).."
+browser.search.contextTextSearchLabel2=Search %S for "%S"
 
 # Settings Charms
 aboutCharm1=About
 optionsCharm=Options
 syncCharm=Sync
 helpOnlineCharm=Help (online)
 
 # General
 browserForSaveLocation=Save Location
+browserForOpenLocation=Open Location
 
 # Download Manager
 downloadsUnknownSize=Unknown size
 
 # Alerts
 alertLinkBookmarked=Bookmark added
 alertDownloads=Downloads
 alertDownloadsStart=Downloading: %S
old mode 100755
new mode 100644
copy from mach
copy to build/mach_bootstrap.py
--- a/mach
+++ b/build/mach_bootstrap.py
@@ -4,30 +4,21 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import print_function, unicode_literals
 
 import os
 import platform
 import sys
 
-# Ensure we are running Python 2.7+. We put this check here so we generate a
-# user-friendly error message rather than a cryptic stack trace on module
-# import.
-if sys.version_info[0] != 2 or sys.version_info[1] < 7:
-    print('Python 2.7 or above (but not Python 3) is required to run mach.')
-    print('You are running Python', platform.python_version())
-    sys.exit(1)
-
 # TODO Bug 794506 Integrate with the in-tree virtualenv configuration.
 SEARCH_PATHS = [
     'python/mach',
     'python/mozboot',
     'python/mozbuild',
-    'build',
     'build/pymake',
     'python/blessings',
     'python/psutil',
     'python/which',
     'other-licenses/ply',
     'xpcom/idl-parser',
     'testing',
     'testing/xpcshell',
@@ -43,24 +34,27 @@ MACH_MODULES = [
     'python/mozboot/mozboot/mach_commands.py',
     'python/mozbuild/mozbuild/config.py',
     'python/mozbuild/mozbuild/mach_commands.py',
     'python/mozbuild/mozbuild/frontend/mach_commands.py',
     'testing/mochitest/mach_commands.py',
     'testing/xpcshell/mach_commands.py',
 ]
 
-our_dir = os.path.dirname(os.path.abspath(__file__))
-
-try:
-    import mach.main
-except ImportError:
-    sys.path[0:0] = [os.path.join(our_dir, path) for path in SEARCH_PATHS]
+def bootstrap(topsrcdir):
+    # Ensure we are running Python 2.7+. We put this check here so we generate a
+    # user-friendly error message rather than a cryptic stack trace on module
+    # import.
+    if sys.version_info[0] != 2 or sys.version_info[1] < 7:
+        print('Python 2.7 or above (but not Python 3) is required to run mach.')
+        print('You are running Python', platform.python_version())
+        sys.exit(1)
 
-    import mach.main
-
-# All of the code is in a module because EVERYTHING IS A LIBRARY.
-mach = mach.main.Mach(our_dir)
+    try:
+        import mach.main
+    except ImportError:
+        sys.path[0:0] = [os.path.join(topsrcdir, path) for path in SEARCH_PATHS]
+        import mach.main
 
-for path in MACH_MODULES:
-    mach.load_commands_from_file(os.path.join(our_dir, path))
-
-sys.exit(mach.run(sys.argv[1:]))
+    mach = mach.main.Mach(topsrcdir)
+    for path in MACH_MODULES:
+        mach.load_commands_from_file(os.path.join(topsrcdir, path))
+    return mach
--- a/build/unix/stdc++compat/stdc++compat.cpp
+++ b/build/unix/stdc++compat/stdc++compat.cpp
@@ -28,16 +28,17 @@ namespace std {
     template ostream& ostream::_M_insert(unsigned long long);
     template ostream& ostream::_M_insert(bool);
     template ostream& ostream::_M_insert(const void*);
     template ostream& __ostream_insert(ostream&, const char*, streamsize);
     template istream& istream::_M_extract(double&);
     template istream& istream::_M_extract(float&);
     template istream& istream::_M_extract(unsigned int&);
     template istream& istream::_M_extract(unsigned long&);
+    template istream& istream::_M_extract(unsigned short&);
 #endif
 #if MOZ_LIBSTDCXX_VERSION >= GLIBCXX_VERSION(3, 4, 14)
     /* Instantiate these templates to avoid GLIBCXX_3.4.14 symbol versions
      * depending on optimization level */
     template char *string::_S_construct_aux_2(size_type, char, allocator<char> const&);
 #ifdef _GLIBCXX_USE_WCHAR_T
     template wchar_t *wstring::_S_construct_aux_2(size_type, wchar_t, allocator<wchar_t> const&);
 #endif /* _GLIBCXX_USE_WCHAR_T */
--- a/config/writemozinfo.py
+++ b/config/writemozinfo.py
@@ -23,16 +23,23 @@ def build_dict(env=os.environ):
     """
     d = {}
     # Check that all required variables are present first.
     required = ["TARGET_CPU", "OS_TARGET", "MOZ_WIDGET_TOOLKIT"]
     missing = [r for r in required if r not in env]
     if missing:
         raise Exception("Missing required environment variables: %s" %
                         ', '.join(missing))
+
+    if 'MOZCONFIG' in env:
+      d["mozconfig"] = env["MOZCONFIG"]
+
+    if 'TOPSRCDIR' in env:
+      d["topsrcdir"] = env["TOPSRCDIR"]
+
     # os
     o = env["OS_TARGET"]
     known_os = {"Linux": "linux",
                 "WINNT": "win",
                 "Darwin": "mac",
                 "Android": "b2g" if env["MOZ_WIDGET_TOOLKIT"] == "gonk" else "android"}
     if o in known_os:
         d["os"] = known_os[o]
--- a/configure.in
+++ b/configure.in
@@ -9113,16 +9113,17 @@ fi
 # build configuration details from in a standardized way.
 OS_TARGET=${OS_TARGET} \
 TARGET_CPU=${TARGET_CPU} \
 MOZ_DEBUG=${MOZ_DEBUG} \
 MOZ_WIDGET_TOOLKIT=${MOZ_WIDGET_TOOLKIT} \
 UNIVERSAL_BINARY=${UNIVERSAL_BINARY} \
 MOZ_CRASHREPORTER=${MOZ_CRASHREPORTER} \
 MOZ_APP_NAME=${MOZ_APP_NAME} \
+TOPSRCDIR=${_topsrcdir} \
   $PYTHON ${_topsrcdir}/config/writemozinfo.py ./mozinfo.json.tmp
 if cmp -s ./mozinfo.json.tmp ./mozinfo.json; then
   rm ./mozinfo.json.tmp
 else
   mv -f ./mozinfo.json.tmp ./mozinfo.json
 fi
 
 # Run jemalloc configure script
--- a/content/base/public/nsISelectionPrivate.idl
+++ b/content/base/public/nsISelectionPrivate.idl
@@ -9,33 +9,31 @@
 
 interface nsRange;
 interface nsIDOMNode;
 interface nsISelectionListener;
 interface nsIContent;
 interface nsINode;
 
 %{C++
-class nsFrameSelection;
 struct nsTextRangeStyle;
 struct nsPoint;
 struct ScrollAxis;
 #include "nsTArray.h"
 #include "nsIFrame.h"
 %}
 
-[ptr] native nsFrameSelection(nsFrameSelection);
 [ptr] native nsIFrame(nsIFrame);
 [ptr] native RangeArray(nsTArray<nsRange*>);
 [ref] native constTextRangeStyleRef(const nsTextRangeStyle);
 [ref] native nsPointRef(nsPoint);
 native nsDirection(nsDirection);
 native ScrollAxis(nsIPresShell::ScrollAxis);
 
-[scriptable, builtinclass, uuid(a6d2cedd-afbc-4d25-bffb-e725b9881e30)]
+[scriptable, builtinclass, uuid(3ede44eb-2df8-41de-ab79-6f3dbd10090b)]
 interface nsISelectionPrivate : nsISelection
  {
     const short ENDOFPRECEDINGLINE=0;
     const short STARTOFNEXTLINE=1;
     
     attribute boolean interlinePosition;
 
     /* startBatchChanges
@@ -78,21 +76,16 @@ interface nsISelectionPrivate : nsISelec
      */
     [noscript] attribute boolean canCacheFrameOffset;
 
     /* GetCachedOffsetForFrame
      * Returns cached value for nsTextFrame::GetPointFromOffset.
      */
     [noscript] void getCachedFrameOffset(in nsIFrame aFrame, in int32_t inOffset, in nsPointRef aPoint);
 
-    /* getFrameSelection
-     * Returnes a reference to the frame selection associated with this selection 
-     */
-    [noscript] nsFrameSelection getFrameSelection();
-
     [noscript] void setAncestorLimiter(in nsIContent aContent);
 
     /**
      * Set the painting style for the range. The range must be a range in
      * the selection. The textRangeStyle will be used by text frame
      * when it is painting the selection.
      */
     [noscript] void setTextRangeStyle(in nsIDOMRange range,
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -2255,17 +2255,20 @@ nsDocument::StartDocumentLoad(const char
 
   mHaveInputEncoding = true;
 
   if (aReset) {
     Reset(aChannel, aLoadGroup);
   }
 
   nsAutoCString contentType;
-  if (NS_SUCCEEDED(aChannel->GetContentType(contentType))) {
+  nsCOMPtr<nsIPropertyBag2> bag = do_QueryInterface(aChannel);
+  if ((bag && NS_SUCCEEDED(bag->GetPropertyAsACString(
+                NS_LITERAL_STRING("contentType"), contentType))) ||
+      NS_SUCCEEDED(aChannel->GetContentType(contentType))) {
     // XXX this is only necessary for viewsource:
     nsACString::const_iterator start, end, semicolon;
     contentType.BeginReading(start);
     contentType.EndReading(end);
     semicolon = start;
     FindCharInReadable(';', semicolon, end);
     SetContentTypeInternal(Substring(start, semicolon));
   }
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -2564,16 +2564,27 @@ SelectTextFieldOnFocus()
     } else {
       gSelectTextFieldOnFocus = selectTextfieldsOnKeyFocus != 0 ? 1 : -1;
     }
   }
 
   return gSelectTextFieldOnFocus == 1;
 }
 
+static bool
+IsLTR(Element* aElement)
+{
+  nsIFrame *frame = aElement->GetPrimaryFrame();
+  if (frame) {
+    return frame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR;
+  }
+  // at least for HTML, directionality is exclusively LTR or RTL
+  return aElement->GetDirectionality() == eDir_LTR;
+}
+
 nsresult
 nsHTMLInputElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
 {
   if (!aVisitor.mPresContext) {
     return NS_OK;
   }
 
   if (aVisitor.mEvent->message == NS_FOCUS_CONTENT ||
@@ -2830,16 +2841,84 @@ nsHTMLInputElement::PostHandleEvent(nsEv
                keyEvent->keyCode == NS_VK_ENTER) &&
                (IsSingleLineTextControl(false, mType) ||
                 IsExperimentalMobileType(mType))) {
             FireChangeEventIfNeeded();
             rv = MaybeSubmitForm(aVisitor.mPresContext);
             NS_ENSURE_SUCCESS(rv, rv);
           }
 
+          if (aVisitor.mEvent->message == NS_KEY_PRESS &&
+              mType == NS_FORM_INPUT_RANGE && !keyEvent->IsAlt() &&
+              !keyEvent->IsControl() && !keyEvent->IsMeta() &&
+              (keyEvent->keyCode == NS_VK_LEFT ||
+               keyEvent->keyCode == NS_VK_RIGHT ||
+               keyEvent->keyCode == NS_VK_UP ||
+               keyEvent->keyCode == NS_VK_DOWN ||
+               keyEvent->keyCode == NS_VK_PAGE_UP ||
+               keyEvent->keyCode == NS_VK_PAGE_DOWN ||
+               keyEvent->keyCode == NS_VK_HOME ||
+               keyEvent->keyCode == NS_VK_END)) {
+            double minimum = GetMinimum();
+            double maximum = GetMaximum();
+            MOZ_ASSERT(MOZ_DOUBLE_IS_FINITE(minimum) &&
+                       MOZ_DOUBLE_IS_FINITE(maximum));
+            if (minimum < maximum) { // else the value is locked to the minimum
+              double value = GetValueAsDouble();
+              double step = GetStep();
+              if (step == kStepAny) {
+                step = GetDefaultStep();
+              }
+              MOZ_ASSERT(MOZ_DOUBLE_IS_FINITE(value) &&
+                         MOZ_DOUBLE_IS_FINITE(step));
+              double newValue;
+              switch (keyEvent->keyCode) {
+                case  NS_VK_LEFT:
+                  newValue = value + (IsLTR(this) ? -step : step);
+                  break;
+                case  NS_VK_RIGHT:
+                  newValue = value + (IsLTR(this) ? step : -step);
+                  break;
+                case  NS_VK_UP:
+                  // Even for horizontal range, "up" means "increase"
+                  newValue = value + step;
+                  break;
+                case  NS_VK_DOWN:
+                  // Even for horizontal range, "down" means "decrease"
+                  newValue = value - step;
+                  break;
+                case  NS_VK_HOME:
+                  newValue = minimum;
+                  break;
+                case  NS_VK_END:
+                  newValue = maximum;
+                  break;
+                case  NS_VK_PAGE_UP:
+                  // For PgUp/PgDn we jump 10% of the total range, unless step
+                  // requires us to jump more.
+                  newValue = value + std::max(step, 0.1 * (maximum - minimum));
+                  break;
+                case  NS_VK_PAGE_DOWN:
+                  newValue = value - std::max(step, 0.1 * (maximum - minimum));
+                  break;
+              }
+              MOZ_ASSERT(MOZ_DOUBLE_IS_FINITE(newValue));
+              nsAutoString val;
+              ConvertNumberToString(newValue, val);
+              SetValueInternal(val, true, true);
+              nsIFrame* frame = GetPrimaryFrame();
+              if (frame) {
+                // Trigger reflow to update the position of the thumb:
+                frame->PresContext()->GetPresShell()->
+                  FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
+              }
+              aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
+            }
+          }
+
         } break; // NS_KEY_PRESS || NS_KEY_UP
 
         case NS_MOUSE_BUTTON_DOWN:
         case NS_MOUSE_BUTTON_UP:
         case NS_MOUSE_DOUBLECLICK:
         {
           // cancel all of these events for buttons
           //XXXsmaug Why?
@@ -4348,17 +4427,18 @@ nsHTMLInputElement::IsHTMLFocusable(bool
     return true;
   }
 
   if (IsDisabled()) {
     *aIsFocusable = false;
     return true;
   }
 
-  if (IsSingleLineTextControl(false)) {
+  if (IsSingleLineTextControl(false) ||
+      mType == NS_FORM_INPUT_RANGE) {
     *aIsFocusable = true;
     return false;
   }
 
 #ifdef XP_MACOSX
   const bool defaultFocusable = !aWithMouse || nsFocusManager::sMouseFocusesFormControl;
 #else
   const bool defaultFocusable = true;
--- a/content/html/content/test/forms/Makefile.in
+++ b/content/html/content/test/forms/Makefile.in
@@ -13,16 +13,17 @@ include $(DEPTH)/config/autoconf.mk
 MOCHITEST_FILES = \
 		save_restore_radio_groups.sjs \
 		test_save_restore_radio_groups.html \
 		test_change_event.html \
 		test_mozistextfield.html \
 		test_input_attributes_reflection.html \
 		test_input_list_attribute.html \
 		test_input_email.html \
+		test_input_range_key_events.html \
 		test_input_url.html \
 		test_pattern_attribute.html \
 		test_required_attribute.html \
 		test_novalidate_attribute.html \
 		test_formaction_attribute.html \
 		test_formnovalidate_attribute.html \
 		test_label_control_attribute.html \
 		test_output_element.html \
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/forms/test_input_range_key_events.html
@@ -0,0 +1,206 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=843725
+-->
+<head>
+  <title>Test key events for range</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <meta charset="UTF-8">
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=843725">Mozilla Bug 843725</a>
+<p id="display"></p>
+<div id="content">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/**
+ * Test for Bug 843725
+ * This test checks how the value of <input type=range> changes in response to
+ * various key events while it is in various states.
+ **/
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(function() {
+  test();
+  SimpleTest.finish();
+});
+
+const defaultMinimum = 0;
+const defaultMaximum = 100;
+const defaultStep = 1;
+
+// Helpers:
+// For the sake of simplicity, we do not currently support fractional value,
+// step, etc.
+
+function minimum(element) {
+  return Number(element.min || defaultMinimum);
+}
+
+function maximum(element) {
+  return Number(element.max || defaultMaximum);
+}
+
+function range(element) {
+  var max = maximum(element);
+  var min = minimum(element);
+  if (max < min) {
+    return 0;
+  }
+  return max - min;
+}
+
+function defaultValue(element) {
+  return minimum(element) + range(element)/2;
+}
+
+function value(element) {
+  return Number(element.value || defaultValue(element));
+}
+
+function step(element) {
+  var step = Number(element.step || defaultStep);
+  return step <= 0 ? defaultStep : step;
+}
+
+function clampToRange(value, element) {
+  var min = minimum(element);
+  var max = maximum(element);
+  if (max < min) {
+    return min;
+  }
+  if (value < min) {
+    return min;
+  }
+  if (value > max) {
+    return max;
+  }
+  return value;
+}
+
+// Functions used to specify expected test results:
+
+function valuePlusStep(element) {
+  return clampToRange(value(element) + step(element), element);
+}
+
+function valueMinusStep(element) {
+  return clampToRange(value(element) - step(element), element);
+}
+
+/**
+ * Returns the current value of the range plus whichever is greater of either
+ * 10% of the range or its current step value, clamped to the range's minimum/
+ * maximum. The reason for using the step if it is greater than 10% of the
+ * range is because otherwise the PgUp/PgDn keys would do nothing in that case.
+ */
+function valuePlusTenPctOrStep(element) {
+  var tenPct = range(element)/10;
+  var stp = step(element);
+  return clampToRange(value(element) + Math.max(tenPct, stp), element);
+}
+
+function valueMinusTenPctOrStep(element) {
+  var tenPct = range(element)/10;
+  var stp = step(element);
+  return clampToRange(value(element) - Math.max(tenPct, stp), element);
+}
+
+// Test table:
+
+const LTR = "ltr";
+const RTL = "rtl";
+
+var testTable = [
+  ["VK_LEFT",      LTR, valueMinusStep],
+  ["VK_LEFT",      RTL, valuePlusStep],
+  ["VK_RIGHT",     LTR, valuePlusStep],
+  ["VK_RIGHT",     RTL, valueMinusStep],
+  ["VK_UP",        LTR, valuePlusStep],
+  ["VK_UP",        RTL, valuePlusStep],
+  ["VK_DOWN",      LTR, valueMinusStep],
+  ["VK_DOWN",      RTL, valueMinusStep],
+  ["VK_PAGE_UP",   LTR, valuePlusTenPctOrStep],
+  ["VK_PAGE_UP",   RTL, valuePlusTenPctOrStep],
+  ["VK_PAGE_DOWN", LTR, valueMinusTenPctOrStep],
+  ["VK_PAGE_DOWN", RTL, valueMinusTenPctOrStep],
+  ["VK_HOME",      LTR, minimum],
+  ["VK_HOME",      RTL, minimum],
+  ["VK_END",       LTR, maximum],
+  ["VK_END",       RTL, maximum],
+]
+
+function test() {
+  var elem = document.createElement("input");
+  elem.type = "range";
+
+  var content = document.getElementById("content");
+  content.appendChild(elem);
+  elem.focus();
+
+  for (test of testTable) {
+    var [key, dir, expectedFunc] = test;
+    var oldVal, expectedVal;
+
+    elem.step = "2";
+    elem.style.direction = dir;
+    var flush = document.body.clientWidth;
+
+    // Start at middle:
+    elem.value = oldVal = defaultValue(elem);
+    expectedVal = expectedFunc(elem);
+    synthesizeKey(key, {});
+    is(elem.value, expectedVal, "Test " + key + " for " + dir + " range with value set to the midpoint (" + oldVal + ")");
+
+    // Same again:
+    expectedVal = expectedFunc(elem);
+    synthesizeKey(key, {});
+    is(elem.value, expectedVal, "Test repeat of " + key + " for " + dir + " range");
+
+    // Start at maximum:
+    elem.value = oldVal = maximum(elem);
+    expectedVal = expectedFunc(elem);
+    synthesizeKey(key, {});
+    is(elem.value, expectedVal, "Test " + key + " for " + dir + " range with value set to the maximum (" + oldVal + ")");
+
+    // Same again:
+    expectedVal = expectedFunc(elem);
+    synthesizeKey(key, {});
+    is(elem.value, expectedVal, "Test repeat of " + key + " for " + dir + " range");
+
+    // Start at minimum:
+    elem.value = oldVal = minimum(elem);
+    expectedVal = expectedFunc(elem);
+    synthesizeKey(key, {});
+    is(elem.value, expectedVal, "Test " + key + " for " + dir + " range with value set to the minimum (" + oldVal + ")");
+
+    // Same again:
+    expectedVal = expectedFunc(elem);
+    synthesizeKey(key, {});
+    is(elem.value, expectedVal, "Test repeat of " + key + " for " + dir + " range");
+
+    // Test for a step value that is greater than 10% of the range:
+    elem.step = 20;
+    elem.value = 60;
+    expectedVal = expectedFunc(elem);
+    synthesizeKey(key, {});
+    is(elem.value, expectedVal, "Test " + key + " for " + dir + " range with a step that is greater than 10% of the range (step=" + elem.step + ")");
+
+    // Same again:
+    expectedVal = expectedFunc(elem);
+    synthesizeKey(key, {});
+    is(elem.value, expectedVal, "Test repeat of " + key + " for " + dir + " range");
+
+    // reset step:
+    elem.step = 2;
+  }
+}
+
+</script>
+</pre>
+</body>
+</html>
--- a/content/html/document/test/test_bug478251.html
+++ b/content/html/document/test/test_bug478251.html
@@ -12,17 +12,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=478251">Mozilla Bug 478251</a>
 <p id="display"><iframe id="t"></iframe></p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script type="application/javascript">
 
-SimpleTest.expectAssertions(10);
+SimpleTest.expectAssertions(9, 10);
 
 /** Test for Bug 478251 **/
 var doc = $("t").contentDocument;
 doc.open();
 doc.write();
 doc.close();
 is(doc.documentElement.textContent, "", "Writing || failed");
 
--- a/content/media/test/test_seek.html
+++ b/content/media/test/test_seek.html
@@ -26,17 +26,17 @@
 var manager = new MediaTestManager;
 
 // https://bugzilla.mozilla.org/show_bug.cgi?id=634747
 if (navigator.platform.startsWith("Win")) {
   SimpleTest.expectAssertions(0, 5);
 } else {
   // This is "###!!! ASSERTION: Page read cursor should be inside range: 'mPageOffset <= endOffset'"
   // https://bugzilla.mozilla.org/show_bug.cgi?id=846769
-  SimpleTest.expectAssertions(0, 1);
+  SimpleTest.expectAssertions(0, 5);
 }
 
 const NUM_SEEK_TESTS = 13;
 
 function createTestArray() {
   var tests = [];
   var tmpVid = document.createElement("video");
 
--- a/content/svg/content/src/DOMSVGStringList.cpp
+++ b/content/svg/content/src/DOMSVGStringList.cpp
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "DOMSVGStringList.h"
-#include "DOMSVGTests.h"
+#include "mozilla/dom/SVGTests.h"
 #include "nsError.h"
 #include "nsCOMPtr.h"
 #include "nsSVGAttrTearoffTable.h"
 #include <algorithm>
 
 // See the architecture comment in this file's header.
 
 namespace mozilla {
@@ -180,15 +180,15 @@ DOMSVGStringList::AppendItem(const nsASt
 {
   return InsertItemBefore(newItem, InternalList().Length(), _retval);
 }
 
 SVGStringList &
 DOMSVGStringList::InternalList()
 {
   if (mIsConditionalProcessingAttribute) {
-    nsCOMPtr<DOMSVGTests> tests = do_QueryInterface(mElement);
+    nsCOMPtr<dom::SVGTests> tests = do_QueryInterface(mElement);
     return tests->mStringListAttributes[mAttrEnum];
   }
   return mElement->GetStringListInfo().mStringLists[mAttrEnum];
 }
 
 } // namespace mozilla
--- a/content/svg/content/src/Makefile.in
+++ b/content/svg/content/src/Makefile.in
@@ -25,17 +25,16 @@ CPPSRCS		= \
 		DOMSVGLengthList.cpp \
 		DOMSVGNumber.cpp \
 		DOMSVGNumberList.cpp \
 		DOMSVGPathSeg.cpp \
 		DOMSVGPathSegList.cpp \
 		DOMSVGPoint.cpp \
 		DOMSVGPointList.cpp \
 		DOMSVGStringList.cpp \
-		DOMSVGTests.cpp \
 		DOMSVGTransform.cpp \
 		DOMSVGTransformList.cpp \
 		nsDOMSVGZoomEvent.cpp \
 		nsDOMSVGEvent.cpp \
 		nsISVGPoint.cpp \
 		nsSVGAngle.cpp \
 		nsSVGBoolean.cpp \
 		nsSVGClass.cpp \
@@ -119,16 +118,17 @@ CPPSRCS		= \
 		SVGScriptElement.cpp \
 		SVGSetElement.cpp \
 		SVGStopElement.cpp \
 		SVGStringList.cpp \
 		SVGStyleElement.cpp \
 		SVGSymbolElement.cpp \
 		SVGSVGElement.cpp \
 		SVGSwitchElement.cpp \
+		SVGTests.cpp \
 		SVGTextContentElement.cpp \
 		SVGTextElement.cpp \
 		SVGTextPathElement.cpp \
 		SVGTextPositioningElement.cpp \
 		SVGTitleElement.cpp \
 		SVGTransform.cpp \
 		SVGTransformableElement.cpp \
 		SVGTransformList.cpp \
@@ -189,16 +189,17 @@ EXPORTS_mozilla/dom = \
 	SVGRectElement.h \
 	SVGScriptElement.h \
 	SVGSetElement.h \
 	SVGStopElement.h \
 	SVGStyleElement.h \
 	SVGSymbolElement.h \
 	SVGSVGElement.h \
 	SVGSwitchElement.h \
+	SVGTests.h \
 	SVGTextContentElement.h \
 	SVGTextElement.h \
 	SVGTextPathElement.h \
 	SVGTextPositioningElement.h \
 	SVGTitleElement.h \
 	SVGTransformableElement.h \
 	SVGTSpanElement.h \
 	SVGUseElement.h \
--- a/content/svg/content/src/SVGAnimationElement.cpp
+++ b/content/svg/content/src/SVGAnimationElement.cpp
@@ -17,17 +17,17 @@ namespace dom {
 //----------------------------------------------------------------------
 // nsISupports methods
 
 NS_IMPL_ADDREF_INHERITED(SVGAnimationElement, SVGAnimationElementBase)
 NS_IMPL_RELEASE_INHERITED(SVGAnimationElement, SVGAnimationElementBase)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SVGAnimationElement)
   NS_INTERFACE_MAP_ENTRY(nsISMILAnimationElement)
-  NS_INTERFACE_MAP_ENTRY(DOMSVGTests)
+  NS_INTERFACE_MAP_ENTRY(mozilla::dom::SVGTests)
 NS_INTERFACE_MAP_END_INHERITING(SVGAnimationElementBase)
 
 // Cycle collection magic -- based on nsSVGUseElement
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(SVGAnimationElement,
                                                 SVGAnimationElementBase)
   tmp->mHrefTarget.Unlink();
   tmp->mTimedElement.Unlink();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@@ -84,17 +84,17 @@ Element&
 SVGAnimationElement::AsElement()
 {
   return *this;
 }
 
 bool
 SVGAnimationElement::PassesConditionalProcessingTests()
 {
-  return DOMSVGTests::PassesConditionalProcessingTests();
+  return SVGTests::PassesConditionalProcessingTests();
 }
 
 const nsAttrValue*
 SVGAnimationElement::GetAnimAttr(nsIAtom* aName) const
 {
   return mAttrsAndChildren.GetAttr(aName, kNameSpaceID_None);
 }
 
--- a/content/svg/content/src/SVGAnimationElement.h
+++ b/content/svg/content/src/SVGAnimationElement.h
@@ -1,29 +1,29 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 #ifndef mozilla_dom_SVGAnimationElement_h
 #define mozilla_dom_SVGAnimationElement_h
 
-#include "DOMSVGTests.h"
+#include "mozilla/dom/SVGTests.h"
 #include "nsISMILAnimationElement.h"
 #include "nsReferencedElement.h"
 #include "nsSMILTimedElement.h"
 #include "nsSVGElement.h"
 
 typedef nsSVGElement SVGAnimationElementBase;
 
 namespace mozilla {
 namespace dom {
 
 class SVGAnimationElement : public SVGAnimationElementBase,
-                            public DOMSVGTests,
+                            public SVGTests,
                             public nsISMILAnimationElement
 {
 protected:
   SVGAnimationElement(already_AddRefed<nsINodeInfo> aNodeInfo);
   nsresult Init();
 
 public:
   // interfaces:
--- a/content/svg/content/src/SVGGraphicsElement.cpp
+++ b/content/svg/content/src/SVGGraphicsElement.cpp
@@ -10,17 +10,17 @@ namespace dom {
 
 //----------------------------------------------------------------------
 // nsISupports methods
 
 NS_IMPL_ADDREF_INHERITED(SVGGraphicsElement, SVGGraphicsElementBase)
 NS_IMPL_RELEASE_INHERITED(SVGGraphicsElement, SVGGraphicsElementBase)
 
 NS_INTERFACE_MAP_BEGIN(SVGGraphicsElement)
-  NS_INTERFACE_MAP_ENTRY(DOMSVGTests)
+  NS_INTERFACE_MAP_ENTRY(mozilla::dom::SVGTests)
 NS_INTERFACE_MAP_END_INHERITING(SVGGraphicsElementBase)
 
 //----------------------------------------------------------------------
 // Implementation
 
 SVGGraphicsElement::SVGGraphicsElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : SVGGraphicsElementBase(aNodeInfo)
 {
--- a/content/svg/content/src/SVGGraphicsElement.h
+++ b/content/svg/content/src/SVGGraphicsElement.h
@@ -1,26 +1,26 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 #ifndef mozilla_dom_SVGGraphicsElement_h
 #define mozilla_dom_SVGGraphicsElement_h
 
+#include "mozilla/dom/SVGTests.h"
 #include "mozilla/dom/SVGTransformableElement.h"
-#include "DOMSVGTests.h"
 
 namespace mozilla {
 namespace dom {
 
 typedef SVGTransformableElement SVGGraphicsElementBase;
 
 class SVGGraphicsElement : public SVGGraphicsElementBase,
-                           public DOMSVGTests
+                           public SVGTests
 {
 protected:
   SVGGraphicsElement(already_AddRefed<nsINodeInfo> aNodeInfo);
 
 public:
   // interfaces:
   NS_DECL_ISUPPORTS_INHERITED
 };
--- a/content/svg/content/src/SVGMatrix.cpp
+++ b/content/svg/content/src/SVGMatrix.cpp
@@ -10,29 +10,20 @@
 #include "nsContentUtils.h"
 #include "mozilla/dom/SVGMatrixBinding.h"
 
 const double radPerDegree = 2.0 * M_PI / 360.0;
 
 namespace mozilla {
 namespace dom {
 
-//----------------------------------------------------------------------
-// nsISupports methods:
-
-  NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(SVGMatrix, mTransform)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(SVGMatrix, mTransform)
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(SVGMatrix)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(SVGMatrix)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SVGMatrix)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_INTERFACE_MAP_ENTRY(mozilla::dom::SVGMatrix) // pseudo-interface
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
+NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(SVGMatrix, AddRef)
+NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(SVGMatrix, Release)
 
 DOMSVGTransform*
 SVGMatrix::GetParentObject() const
 {
   return mTransform;
 }
 
 JSObject*
@@ -117,17 +108,17 @@ SVGMatrix::SetF(float aF, ErrorResult& r
   gfxMatrix mx = Matrix();
   mx.y0 = aF;
   SetMatrix(mx);
 }
 
 already_AddRefed<SVGMatrix>
 SVGMatrix::Multiply(SVGMatrix& aMatrix)
 {
-  nsCOMPtr<SVGMatrix> matrix = new SVGMatrix(aMatrix.Matrix() * Matrix());
+  nsRefPtr<SVGMatrix> matrix = new SVGMatrix(aMatrix.Matrix() * Matrix());
   return matrix.forget();
 }
 
 already_AddRefed<SVGMatrix>
 SVGMatrix::Inverse(ErrorResult& rv)
 {
   if (Matrix().IsSingular()) {
     rv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
--- a/content/svg/content/src/SVGMatrix.h
+++ b/content/svg/content/src/SVGMatrix.h
@@ -39,38 +39,27 @@
 
 #include "DOMSVGTransform.h"
 #include "gfxMatrix.h"
 #include "nsAutoPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsWrapperCache.h"
 #include "mozilla/Attributes.h"
 
-// We make DOMSVGMatrix a pseudo-interface to allow us to QI to it in order
-// to check that the objects that scripts pass in are our *native* matrix
-// objects.
-//
-// {633419E5-7E88-4C3E-8A9A-856F635E90A3}
-#define MOZILLA_DOMSVGMATRIX_IID \
-  { 0x633419E5, 0x7E88, 0x4C3E, \
-    { 0x8A, 0x9A, 0x85, 0x6F, 0x63, 0x5E, 0x90, 0xA3 } }
-
 namespace mozilla {
 namespace dom {
 
 /**
  * DOM wrapper for an SVG matrix.
  */
-class SVGMatrix MOZ_FINAL : public nsISupports,
-                            public nsWrapperCache
+class SVGMatrix MOZ_FINAL : public nsWrapperCache
 {
 public:
-  NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_DOMSVGMATRIX_IID)
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(SVGMatrix)
+  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(SVGMatrix)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(SVGMatrix)
 
   /**
    * Ctor for SVGMatrix objects that belong to a DOMSVGTransform.
    */
   SVGMatrix(DOMSVGTransform& aTransform) : mTransform(&aTransform) {
     SetIsDOMBinding();
   }
 
@@ -136,14 +125,12 @@ private:
 
   nsRefPtr<DOMSVGTransform> mTransform;
 
   // Typically we operate on the matrix data accessed via mTransform but for
   // matrices that exist independently of an SVGTransform we use mMatrix below.
   gfxMatrix mMatrix;
 };
 
-NS_DEFINE_STATIC_IID_ACCESSOR(SVGMatrix, MOZILLA_DOMSVGMATRIX_IID)
-
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_SVGMatrix_h
--- a/content/svg/content/src/SVGSwitchElement.cpp
+++ b/content/svg/content/src/SVGSwitchElement.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "mozilla/Util.h"
 
 #include "mozilla/dom/SVGSwitchElement.h"
-#include "DOMSVGTests.h"
 #include "nsIFrame.h"
 #include "nsSVGUtils.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/SVGSwitchElementBinding.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Switch)
 
 namespace mozilla {
@@ -141,20 +140,20 @@ SVGSwitchElement::FindActiveChild() cons
     nsIContent *bestChild = nullptr;
     for (nsIContent* child = nsINode::GetFirstChild();
          child;
          child = child->GetNextSibling()) {
 
       if (!child->IsElement()) {
         continue;
       }
-      nsCOMPtr<DOMSVGTests> tests(do_QueryInterface(child));
+      nsCOMPtr<SVGTests> tests(do_QueryInterface(child));
       if (tests) {
         if (tests->PassesConditionalProcessingTests(
-                            DOMSVGTests::kIgnoreSystemLanguage)) {
+                            SVGTests::kIgnoreSystemLanguage)) {
           int32_t languagePreferenceRank =
               tests->GetBestLanguagePreferenceRank(acceptLangs);
           switch (languagePreferenceRank) {
           case 0:
             // best possible match
             return child;
           case -1:
             // not found
@@ -176,17 +175,17 @@ SVGSwitchElement::FindActiveChild() cons
   }
 
   for (nsIContent* child = nsINode::GetFirstChild();
        child;
        child = child->GetNextSibling()) {
     if (!child->IsElement()) {
       continue;
     }
-    nsCOMPtr<DOMSVGTests> tests(do_QueryInterface(child));
+    nsCOMPtr<SVGTests> tests(do_QueryInterface(child));
     if (!tests || tests->PassesConditionalProcessingTests(&acceptLangs)) {
       return child;
     }
   }
   return nullptr;
 }
 
 } // namespace dom
--- a/content/svg/content/src/SVGSymbolElement.cpp
+++ b/content/svg/content/src/SVGSymbolElement.cpp
@@ -17,17 +17,17 @@ SVGSymbolElement::WrapNode(JSContext *aC
   return SVGSymbolElementBinding::Wrap(aCx, aScope, this, aTriedToWrap);
 }
 
 //----------------------------------------------------------------------
 // nsISupports methods
 
 NS_IMPL_ISUPPORTS_INHERITED4(SVGSymbolElement, SVGSymbolElementBase,
                              nsIDOMNode, nsIDOMElement,
-                             nsIDOMSVGElement, DOMSVGTests)
+                             nsIDOMSVGElement, mozilla::dom::SVGTests)
 
 //----------------------------------------------------------------------
 // Implementation
 
 SVGSymbolElement::SVGSymbolElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : SVGSymbolElementBase(aNodeInfo)
 {
   SetIsDOMBinding();
--- a/content/svg/content/src/SVGSymbolElement.h
+++ b/content/svg/content/src/SVGSymbolElement.h
@@ -1,33 +1,33 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 #ifndef mozilla_dom_SVGSymbolElement_h
 #define mozilla_dom_SVGSymbolElement_h
 
-#include "DOMSVGTests.h"
+#include "mozilla/dom/SVGTests.h"
 #include "nsSVGElement.h"
 #include "nsSVGViewBox.h"
 #include "SVGAnimatedPreserveAspectRatio.h"
 #include "nsGkAtoms.h"
 
 nsresult NS_NewSVGSymbolElement(nsIContent **aResult,
                                 already_AddRefed<nsINodeInfo> aNodeInfo);
 
 namespace mozilla {
 namespace dom {
 
 typedef nsSVGElement SVGSymbolElementBase;
 
 class SVGSymbolElement MOZ_FINAL : public SVGSymbolElementBase,
                                    public nsIDOMSVGElement,
-                                   public DOMSVGTests
+                                   public SVGTests
 {
 protected:
   friend nsresult (::NS_NewSVGSymbolElement(nsIContent **aResult,
                                             already_AddRefed<nsINodeInfo> aNodeInfo));
   SVGSymbolElement(already_AddRefed<nsINodeInfo> aNodeInfo);
   virtual JSObject* WrapNode(JSContext *cx, JSObject *scope, bool *triedToWrap) MOZ_OVERRIDE;
 
 public:
rename from content/svg/content/src/DOMSVGTests.cpp
rename to content/svg/content/src/SVGTests.cpp
--- a/content/svg/content/src/DOMSVGTests.cpp
+++ b/content/svg/content/src/SVGTests.cpp
@@ -1,80 +1,81 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "DOMSVGTests.h"
+#include "mozilla/dom/SVGTests.h"
 #include "DOMSVGStringList.h"
 #include "nsSVGFeatures.h"
 #include "mozilla/dom/SVGSwitchElement.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsStyleUtil.h"
 #include "mozilla/Preferences.h"
 
-using namespace mozilla;
+namespace mozilla {
+namespace dom {
 
-NS_IMPL_ISUPPORTS0(DOMSVGTests)
+NS_IMPL_ISUPPORTS0(SVGTests)
 
-nsIAtom** DOMSVGTests::sStringListNames[3] =
+nsIAtom** SVGTests::sStringListNames[3] =
 {
   &nsGkAtoms::requiredFeatures,
   &nsGkAtoms::requiredExtensions,
   &nsGkAtoms::systemLanguage,
 };
 
-DOMSVGTests::DOMSVGTests()
+SVGTests::SVGTests()
 {
   mStringListAttributes[LANGUAGE].SetIsCommaSeparated(true);
 }
 
 already_AddRefed<nsIDOMSVGStringList>
-DOMSVGTests::RequiredFeatures()
+SVGTests::RequiredFeatures()
 {
   nsCOMPtr<nsSVGElement> element = do_QueryInterface(this);
   return DOMSVGStringList::GetDOMWrapper(
            &mStringListAttributes[FEATURES], element, true, FEATURES).get();
 }
 
 already_AddRefed<nsIDOMSVGStringList>
-DOMSVGTests::RequiredExtensions()
+SVGTests::RequiredExtensions()
 {
   nsCOMPtr<nsSVGElement> element = do_QueryInterface(this);
   return DOMSVGStringList::GetDOMWrapper(
            &mStringListAttributes[EXTENSIONS], element, true, EXTENSIONS).get();
 }
 
 already_AddRefed<nsIDOMSVGStringList>
-DOMSVGTests::SystemLanguage()
+SVGTests::SystemLanguage()
 {
   nsCOMPtr<nsSVGElement> element = do_QueryInterface(this);
   return DOMSVGStringList::GetDOMWrapper(
            &mStringListAttributes[LANGUAGE], element, true, LANGUAGE).get();
 }
 
 bool
-DOMSVGTests::HasExtension(const nsAString& aExtension)
+SVGTests::HasExtension(const nsAString& aExtension)
 {
   return nsSVGFeatures::HasExtension(aExtension);
 }
 
 bool
-DOMSVGTests::IsConditionalProcessingAttribute(const nsIAtom* aAttribute) const
+SVGTests::IsConditionalProcessingAttribute(const nsIAtom* aAttribute) const
 {
   for (uint32_t i = 0; i < ArrayLength(sStringListNames); i++) {
     if (aAttribute == *sStringListNames[i]) {
       return true;
     }
   }
   return false;
 }
 
 int32_t
-DOMSVGTests::GetBestLanguagePreferenceRank(const nsSubstring& aAcceptLangs) const
+SVGTests::GetBestLanguagePreferenceRank(const nsSubstring& aAcceptLangs) const
 {
   const nsDefaultStringComparator defaultComparator;
 
   int32_t lowestRank = -1;
 
   for (uint32_t i = 0; i < mStringListAttributes[LANGUAGE].Length(); i++) {
     nsCharSeparatedTokenizer languageTokenizer(aAcceptLangs, ',');
     int32_t index = 0;
@@ -95,28 +96,28 @@ DOMSVGTests::GetBestLanguagePreferenceRa
         lowestRank = 2 * index + prefixOnlyMatch;
       }
       ++index;
     }
   }
   return lowestRank;
 }
 
-const nsString * const DOMSVGTests::kIgnoreSystemLanguage = (nsString *) 0x01;
+const nsString * const SVGTests::kIgnoreSystemLanguage = (nsString *) 0x01;
 
 bool
-DOMSVGTests::PassesConditionalProcessingTests(const nsString *aAcceptLangs) const
+SVGTests::PassesConditionalProcessingTests(const nsString *aAcceptLangs) const
 {
   // Required Features
   if (mStringListAttributes[FEATURES].IsExplicitlySet()) {
     if (mStringListAttributes[FEATURES].IsEmpty()) {
       return false;
     }
     nsCOMPtr<nsIContent> content(
-      do_QueryInterface(const_cast<DOMSVGTests*>(this)));
+      do_QueryInterface(const_cast<SVGTests*>(this)));
 
     for (uint32_t i = 0; i < mStringListAttributes[FEATURES].Length(); i++) {
       if (!nsSVGFeatures::HasFeature(content, mStringListAttributes[FEATURES][i])) {
         return false;
       }
     }
   }
 
@@ -177,63 +178,66 @@ DOMSVGTests::PassesConditionalProcessing
     }
     return false;
   }
 
   return true;
 }
 
 bool
-DOMSVGTests::ParseConditionalProcessingAttribute(nsIAtom* aAttribute,
-                                                 const nsAString& aValue,
-                                                 nsAttrValue& aResult)
+SVGTests::ParseConditionalProcessingAttribute(nsIAtom* aAttribute,
+                                              const nsAString& aValue,
+                                              nsAttrValue& aResult)
 {
   for (uint32_t i = 0; i < ArrayLength(sStringListNames); i++) {
     if (aAttribute == *sStringListNames[i]) {
       nsresult rv = mStringListAttributes[i].SetValue(aValue);
       if (NS_FAILED(rv)) {
         mStringListAttributes[i].Clear();
       }
       MaybeInvalidate();
       return true;
     }
   }
   return false;
 }
 
 void
-DOMSVGTests::UnsetAttr(const nsIAtom* aAttribute)
+SVGTests::UnsetAttr(const nsIAtom* aAttribute)
 {
   for (uint32_t i = 0; i < ArrayLength(sStringListNames); i++) {
     if (aAttribute == *sStringListNames[i]) {
       mStringListAttributes[i].Clear();
       MaybeInvalidate();
       return;
     }
   }
 }
 
 nsIAtom*
-DOMSVGTests::GetAttrName(uint8_t aAttrEnum) const
+SVGTests::GetAttrName(uint8_t aAttrEnum) const
 {
   return *sStringListNames[aAttrEnum];
 }
 
 void
-DOMSVGTests::GetAttrValue(uint8_t aAttrEnum, nsAttrValue& aValue) const
+SVGTests::GetAttrValue(uint8_t aAttrEnum, nsAttrValue& aValue) const
 {
   MOZ_ASSERT(aAttrEnum < ArrayLength(sStringListNames),
              "aAttrEnum out of range");
   aValue.SetTo(mStringListAttributes[aAttrEnum], nullptr);
 }
 
 void
-DOMSVGTests::MaybeInvalidate()
+SVGTests::MaybeInvalidate()
 {
   nsCOMPtr<nsSVGElement> element = do_QueryInterface(this);
 
   nsIContent* parent = element->GetFlattenedTreeParent();
 
   if (parent &&
       parent->NodeInfo()->Equals(nsGkAtoms::svgSwitch, kNameSpaceID_SVG)) {
     static_cast<dom::SVGSwitchElement*>(parent)->MaybeInvalidate();
   }
 }
+
+} // namespace dom
+} // namespace mozilla
rename from content/svg/content/src/DOMSVGTests.h
rename to content/svg/content/src/SVGTests.h
--- a/content/svg/content/src/DOMSVGTests.h
+++ b/content/svg/content/src/SVGTests.h
@@ -1,41 +1,42 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
-#ifndef MOZILLA_DOMSVGTESTS_H__
-#define MOZILLA_DOMSVGTESTS_H__
+#ifndef mozilla_dom_SVGTests_h
+#define mozilla_dom_SVGTests_h
 
 #include "nsStringFwd.h"
 #include "SVGStringList.h"
 #include "nsCOMPtr.h"
 
 class nsAttrValue;
 class nsIAtom;
 class nsIDOMSVGStringList;
 class nsString;
 
 namespace mozilla {
 class DOMSVGStringList;
-}
 
 #define MOZILLA_DOMSVGTESTS_IID \
    { 0x92370da8, 0xda28, 0x4895, \
      {0x9b, 0x1b, 0xe0, 0x06, 0x0d, 0xb7, 0x3f, 0xc3 } }
 
-class DOMSVGTests : public nsISupports
+namespace dom {
+
+class SVGTests : public nsISupports
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_DOMSVGTESTS_IID)
   NS_DECL_ISUPPORTS
 
-  DOMSVGTests();
-  virtual ~DOMSVGTests() {}
+  SVGTests();
+  virtual ~SVGTests() {}
 
   friend class mozilla::DOMSVGStringList;
   typedef mozilla::SVGStringList SVGStringList;
 
   /**
    * Compare the language name(s) in a systemLanguage attribute to the
    * user's language preferences, as defined in
    * http://www.w3.org/TR/SVG11/struct.html#SystemLanguageAttribute
@@ -96,11 +97,14 @@ public:
   bool HasExtension(const nsAString& aExtension);
 
 private:
   enum { FEATURES, EXTENSIONS, LANGUAGE };
   SVGStringList mStringListAttributes[3];
   static nsIAtom** sStringListNames[3];
 };
 
-NS_DEFINE_STATIC_IID_ACCESSOR(DOMSVGTests, MOZILLA_DOMSVGTESTS_IID)
+NS_DEFINE_STATIC_IID_ACCESSOR(SVGTests, MOZILLA_DOMSVGTESTS_IID)
 
-#endif // MOZILLA_DOMSVGTESTS_H__
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_SVGTests_h
--- a/content/svg/content/src/SVGTransformableElement.cpp
+++ b/content/svg/content/src/SVGTransformableElement.cpp
@@ -185,46 +185,46 @@ already_AddRefed<SVGMatrix>
 SVGTransformableElement::GetCTM()
 {
   nsIDocument* currentDoc = GetCurrentDoc();
   if (currentDoc) {
     // Flush all pending notifications so that our frames are up to date
     currentDoc->FlushPendingNotifications(Flush_Layout);
   }
   gfxMatrix m = SVGContentUtils::GetCTM(this, false);
-  nsCOMPtr<SVGMatrix> mat = m.IsSingular() ? nullptr : new SVGMatrix(m);
+  nsRefPtr<SVGMatrix> mat = m.IsSingular() ? nullptr : new SVGMatrix(m);
   return mat.forget();
 }
 
 already_AddRefed<SVGMatrix>
 SVGTransformableElement::GetScreenCTM()
 {
   nsIDocument* currentDoc = GetCurrentDoc();
   if (currentDoc) {
     // Flush all pending notifications so that our frames are up to date
     currentDoc->FlushPendingNotifications(Flush_Layout);
   }
   gfxMatrix m = SVGContentUtils::GetCTM(this, true);
-  nsCOMPtr<SVGMatrix> mat = m.IsSingular() ? nullptr : new SVGMatrix(m);
+  nsRefPtr<SVGMatrix> mat = m.IsSingular() ? nullptr : new SVGMatrix(m);
   return mat.forget();
 }
 
 already_AddRefed<SVGMatrix>
 SVGTransformableElement::GetTransformToElement(SVGGraphicsElement& aElement,
                                                ErrorResult& rv)
 {
   // the easiest way to do this (if likely to increase rounding error):
-  nsCOMPtr<SVGMatrix> ourScreenCTM = GetScreenCTM();
-  nsCOMPtr<SVGMatrix> targetScreenCTM = aElement.GetScreenCTM();
+  nsRefPtr<SVGMatrix> ourScreenCTM = GetScreenCTM();
+  nsRefPtr<SVGMatrix> targetScreenCTM = aElement.GetScreenCTM();
   if (!ourScreenCTM || !targetScreenCTM) {
     rv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
-  nsCOMPtr<SVGMatrix> tmp = targetScreenCTM->Inverse(rv);
+  nsRefPtr<SVGMatrix> tmp = targetScreenCTM->Inverse(rv);
   if (rv.Failed()) return nullptr;
 
-  nsCOMPtr<SVGMatrix> mat = tmp->Multiply(*ourScreenCTM);
+  nsRefPtr<SVGMatrix> mat = tmp->Multiply(*ourScreenCTM);
   return mat.forget();
 }
 
 } // namespace dom
 } // namespace mozilla
 
--- a/content/svg/content/src/nsSVGElement.cpp
+++ b/content/svg/content/src/nsSVGElement.cpp
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Util.h"
 
 #include "nsSVGElement.h"
 
 #include "mozilla/dom/SVGSVGElement.h"
+#include "mozilla/dom/SVGTests.h"
 #include "nsIDocument.h"
 #include "nsRange.h"
 #include "nsIDOMAttr.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsMutationEvent.h"
 #include "nsXBLPrototypeBinding.h"
 #include "nsBindingManager.h"
@@ -43,17 +44,16 @@
 #include "nsSVGViewBox.h"
 #include "nsSVGString.h"
 #include "SVGAnimatedNumberList.h"
 #include "SVGAnimatedLengthList.h"
 #include "SVGAnimatedPointList.h"
 #include "SVGAnimatedPathSegList.h"
 #include "SVGAnimatedTransformList.h"
 #include "SVGContentUtils.h"
-#include "DOMSVGTests.h"
 #include "nsSVGRect.h"
 #include "nsIFrame.h"
 #include "prdtoa.h"
 #include <stdarg.h>
 #include "nsSMILMappedAttribute.h"
 #include "SVGMotionSMILAttr.h"
 #include "nsAttrValueOrString.h"
 #include "nsSMILAnimationController.h"
@@ -540,17 +540,17 @@ nsSVGElement::ParseAttribute(int32_t aNa
           foundMatch = true;
           break;
         }
       }
     }
 
     if (!foundMatch) {
       // Check for conditional processing attributes
-      nsCOMPtr<DOMSVGTests> tests(do_QueryInterface(this));
+      nsCOMPtr<SVGTests> tests(do_QueryInterface(this));
       if (tests && tests->ParseConditionalProcessingAttribute(
                             aAttribute, aValue, aResult)) {
         foundMatch = true;
       }
     }
 
     if (!foundMatch) {
       // Check for StringList attribute
@@ -824,17 +824,17 @@ nsSVGElement::UnsetAttrInternal(int32_t 
       if (transformList) {
         MaybeSerializeAttrBeforeRemoval(aName, aNotify);
         transformList->ClearBaseValue();
         return;
       }
     }
 
     // Check for conditional processing attributes
-    nsCOMPtr<DOMSVGTests> tests(do_QueryInterface(this));
+    nsCOMPtr<SVGTests> tests(do_QueryInterface(this));
     if (tests && tests->IsConditionalProcessingAttribute(aName)) {
       MaybeSerializeAttrBeforeRemoval(aName, aNotify);
       tests->UnsetAttr(aName);
       return;
     }
 
     // Check if this is a string list attribute going away
     StringListAttributesInfo stringListInfo = GetStringListInfo();
@@ -875,20 +875,20 @@ nsSVGElement::UnsetAttr(int32_t aNamespa
 
 nsChangeHint
 nsSVGElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
                                      int32_t aModType) const
 {
   nsChangeHint retval =
     nsSVGElementBase::GetAttributeChangeHint(aAttribute, aModType);
 
-  nsCOMPtr<DOMSVGTests> tests(do_QueryInterface(const_cast<nsSVGElement*>(this)));
+  nsCOMPtr<SVGTests> tests(do_QueryInterface(const_cast<nsSVGElement*>(this)));
   if (tests && tests->IsConditionalProcessingAttribute(aAttribute)) {
     // It would be nice to only reconstruct the frame if the value returned by
-    // DOMSVGTests::PassesConditionalProcessingTests has changed, but we don't
+    // SVGTests::PassesConditionalProcessingTests has changed, but we don't
     // know that
     NS_UpdateHint(retval, nsChangeHint_ReconstructFrame);
   }
   return retval;
 }
 
 bool
 nsSVGElement::IsNodeOfType(uint32_t aFlags) const
@@ -2442,32 +2442,32 @@ nsSVGElement::GetStringListInfo()
 }
 
 nsAttrValue
 nsSVGElement::WillChangeStringList(bool aIsConditionalProcessingAttribute,
                                    uint8_t aAttrEnum)
 {
   nsIAtom* name;
   if (aIsConditionalProcessingAttribute) {
-    nsCOMPtr<DOMSVGTests> tests(do_QueryInterface(this));
+    nsCOMPtr<SVGTests> tests(do_QueryInterface(this));
     name = tests->GetAttrName(aAttrEnum);
   } else {
     name = *GetStringListInfo().mStringListInfo[aAttrEnum].mName;
   }
   return WillChangeValue(name);
 }
 
 void
 nsSVGElement::DidChangeStringList(bool aIsConditionalProcessingAttribute,
                                   uint8_t aAttrEnum,
                                   const nsAttrValue& aEmptyOrOldValue)
 {
   nsIAtom* name;
   nsAttrValue newValue;
-  nsCOMPtr<DOMSVGTests> tests;
+  nsCOMPtr<SVGTests> tests;
 
   if (aIsConditionalProcessingAttribute) {
     tests = do_QueryInterface(this);
     name = tests->GetAttrName(aAttrEnum);
     tests->GetAttrValue(aAttrEnum, newValue);
   } else {
     StringListAttributesInfo info = GetStringListInfo();
 
--- a/dom/bindings/BindingDeclarations.h
+++ b/dom/bindings/BindingDeclarations.h
@@ -309,25 +309,25 @@ private:
   // Forbid copy-construction and assignment
   Optional(const Optional& other) MOZ_DELETE;
   const Optional &operator=(const Optional &other) MOZ_DELETE;
 
   bool mPassed;
   const nsAString* mStr;
 };
 
-// Class for representing sequences in arguments.  We use an auto array that can
-// hold 16 elements, to avoid having to allocate in common cases.  This needs to
-// be fallible because web content controls the length of the array, and can
-// easily try to create very large lengths.
+// Class for representing sequences in arguments.  We use a non-auto array
+// because that allows us to use sequences of sequences and the like.  This
+// needs to be fallible because web content controls the length of the array,
+// and can easily try to create very large lengths.
 template<typename T>
-class Sequence : public AutoFallibleTArray<T, 16>
+class Sequence : public FallibleTArray<T>
 {
 public:
-  Sequence() : AutoFallibleTArray<T, 16>()
+  Sequence() : FallibleTArray<T>()
   {}
 };
 
 class RootedJSValue
 {
 public:
   RootedJSValue()
     : mCx(nullptr)
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1553,16 +1553,30 @@ public:
     const T& Value() const {
       return *storage.addr();
     }
     void Destroy() {
       storage.addr()->~T();
     }
 };
 
+// Class for simple sequence arguments, only used internally by codegen.
+template<typename T>
+class AutoSequence : public AutoFallibleTArray<T, 16>
+{
+public:
+  AutoSequence() : AutoFallibleTArray<T, 16>()
+  {}
+
+  // Allow converting to const sequences as needed
+  operator const Sequence<T>&() const {
+    return *reinterpret_cast<const Sequence<T>*>(this);
+  }
+};
+
 inline bool
 IdEquals(jsid id, const char* string)
 {
   return JSID_IS_STRING(id) &&
          JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), string);
 }
 
 inline bool
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -6,22 +6,22 @@
 #
 # The WebIDL interfaces are defined in dom/webidl. For each such interface, there
 # is a corresponding entry in the configuration table below. The configuration
 # table maps each interface name to a |descriptor| or list of |descriptor|s.
 #
 # Valid fields for all descriptors:
 #   * nativeType - The native type (concrete class or XPCOM interface) that
 #                  instances of this interface will unwrap to.  If not
-#                  specified, defaults to "mozilla::dom::InterfaceName" for
+#                  specified, defaults to 'mozilla::dom::InterfaceName' for
 #                  non-worker non-external-or-callback interfaces, to
-#                  "mozilla::dom::workers::InterfaceName" for worker
+#                  'mozilla::dom::workers::InterfaceName' for worker
 #                  non-external interfaces, to 'nsIDOM' followed by the
 #                  interface name for non-worker external-or-callback
-#                  interfaces, and to "JSObject" for worker external-or-callback
+#                  interfaces, and to 'JSObject' for worker external-or-callback
 #                  interfaces.
 #   * headerFile - The file in which the nativeType is declared (defaults
 #                  to an educated guess).
 #   * concrete - Indicates whether there exist objects with this interface as
 #                their primary interface.  Always False for callback interfaces.
 #                defaults to True otherwise.
 #   * prefable - Indicates whether this bindings should be disabled if the
 #                global pref for Web IDL bindings is set to false.  This is a
@@ -48,32 +48,32 @@
 #   * wrapperCache: True if this object is a wrapper cache.  Objects that are
 #                   not can only be returned from a limited set of methods,
 #                   cannot be prefable, and must ensure that they disallow
 #                   XPConnect wrapping.  Always false for callback interfaces.
 #                   Always true for worker descriptors for non-callback
 #                   interfaces.  Defaults to true for non-worker non-callback
 #                   descriptors.
 #   * nativeOwnership: Describes how the native object is held. 4 possible
-#                      types: worker object ("worker"), non-refcounted object
-#                      ("owned"), refcounted non-nsISupports object
-#                      ("refcounted") or nsISupports ("nsisupports").
+#                      types: worker object ('worker'), non-refcounted object
+#                      ('owned'), refcounted non-nsISupports object
+#                      ('refcounted') or nsISupports ('nsisupports').
 #                      Non-refcounted objects need to inherit from
 #                      mozilla::dom::NonRefcountedDOMObject and preferably use
 #                      MOZ_COUNT_CTOR/MOZ_COUNT_DTOR in their
 #                      constructor/destructor so they participate in leak
 #                      logging.
 #                      This mostly determines how the finalizer releases the
 #                      binding's hold on the native object. For a worker object
 #                      it'll call Release, for a non-refcounted object it'll
 #                      call delete through XPConnect's deferred finalization
 #                      mechanism, for a refcounted object it'll call Release
 #                      through XPConnect's deferred finalization mechanism.
-#                      Always "worker" for worker descriptors. Defaults to
-#                      "nsisupports".
+#                      Always 'worker' for worker descriptors. Defaults to
+#                      'nsisupports'.
 #
 #   The following fields are either a string, an array (defaults to an empty
 #   array) or a dictionary with three possible keys (all, getterOnly and
 #   setterOnly) each having such an array as the value
 #
 #   * implicitJSContext - attributes and methods specified in the .webidl file
 #                         that require a JSContext as the first argument
 #   * resultNotAddRefed - attributes and methods specified in the .webidl file
@@ -166,31 +166,31 @@ DOMInterfaces = {
 'CSS': {
     'concrete': False,
 },
 
 'CSS2Properties': {
   'nativeType': 'nsDOMCSSDeclaration'
 },
 
-"CSSPrimitiveValue": {
-    "nativeType": "nsROCSSPrimitiveValue",
-    "resultNotAddRefed": ["getRGBColorValue", "getRectValue"]
+'CSSPrimitiveValue': {
+    'nativeType': 'nsROCSSPrimitiveValue',
+    'resultNotAddRefed': ['getRGBColorValue', 'getRectValue']
 },
 
 'CSSStyleDeclaration': {
   'nativeType': 'nsICSSDeclaration'
 },
 
-"CSSValue": {
-  "concrete": False
+'CSSValue': {
+  'concrete': False
 },
 
-"CSSValueList": {
-  "nativeType": "nsDOMCSSValueList"
+'CSSValueList': {
+  'nativeType': 'nsDOMCSSValueList'
 },
 
 'DelayNode': [
 {
     'resultNotAddRefed': [ 'delayTime' ],
     'wrapperCache': False
 }],
 
@@ -578,24 +578,24 @@ DOMInterfaces = {
 },
 
 'PropertyNodeList': {
     'headerFile': 'HTMLPropertiesCollection.h',
     'resultNotAddRefed': [ 'item' ]
 },
 
 'Rect': {
-    "nativeType": "nsDOMCSSRect",
-    'resultNotAddRefed': [ "top", "right", "bottom", "left" ]
+    'nativeType': 'nsDOMCSSRect',
+    'resultNotAddRefed': [ 'top', 'right', 'bottom', 'left' ]
 },
 
 'RGBColor': {
-    "nativeOwnership": "refcounted",
-    "nativeType": "nsDOMCSSRGBColor",
-    'resultNotAddRefed': [ "alpha", "blue", "green", "red" ]
+    'nativeOwnership': 'refcounted',
+    'nativeType': 'nsDOMCSSRGBColor',
+    'resultNotAddRefed': [ 'alpha', 'blue', 'green', 'red' ]
 },
 
 'Screen': {
     'nativeType': 'nsScreen',
 },
 
 'SVGAnimatedLengthList': {
     'nativeType': 'mozilla::DOMSVGAnimatedLengthList',
@@ -662,16 +662,20 @@ DOMInterfaces = {
     'headerFile': 'DOMSVGLengthList.h',
     'resultNotAddRefed': [ 'getItem' ]
 },
 
 'SVGLinearGradientElement': {
     'headerFile': 'mozilla/dom/SVGGradientElement.h',
 },
 
+'SVGMatrix' : {
+    'nativeOwnership': 'refcounted'
+},
+
 'SVGNumberList': {
     'nativeType': 'mozilla::DOMSVGNumberList',
     'headerFile': 'DOMSVGNumberList.h',
     'resultNotAddRefed': [ 'getItem' ]
 },
 
 'SVGPathSeg': {
     'nativeType': 'mozilla::DOMSVGPathSeg',
@@ -1193,17 +1197,17 @@ def addExternalHTMLElement(element):
                     headerFile=nativeElement + '.h')
 
 addExternalHTMLElement('HTMLFormElement')
 addExternalHTMLElement('HTMLVideoElement')
 addExternalIface('Attr')
 addExternalIface('CanvasGradient', headerFile='nsIDOMCanvasRenderingContext2D.h')
 addExternalIface('CanvasPattern', headerFile='nsIDOMCanvasRenderingContext2D.h')
 addExternalIface('ClientRect')
-addExternalIface("Counter")
+addExternalIface('Counter')
 addExternalIface('CSSRule')
 addExternalIface('DOMRequest')
 addExternalIface('DOMStringList')
 addExternalIface('File')
 addExternalIface('HitRegionOptions', nativeType='nsISupports')
 addExternalIface('HTMLCanvasElement', nativeType='mozilla::dom::HTMLCanvasElement')
 addExternalIface('imgINotificationObserver', nativeType='imgINotificationObserver')
 addExternalIface('imgIRequest', nativeType='imgIRequest', notflattened=True)
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2093,37 +2093,16 @@ if (NS_FAILED(rv) || !wrappedJS) {
 // Use a temp nsCOMPtr for the null-check, because ${target} might be
 // OwningNonNull, not an nsCOMPtr.
 nsCOMPtr<${nativeType}> tmp = do_QueryObject(wrappedJS.get());
 if (!tmp) {
 ${codeOnFailure}
 }
 ${target} = tmp.forget();""").substitute(self.substitution)
 
-def dictionaryHasSequenceMember(dictionary):
-    return (any(typeIsSequenceOrHasSequenceMember(m.type) for m in
-                dictionary.members) or
-            (dictionary.parent and
-             dictionaryHasSequenceMember(dictionary.parent)))
-
-def typeIsSequenceOrHasSequenceMember(type):
-    if type.nullable():
-        type = type.inner
-    if type.isSequence():
-        return True
-    if  type.isArray():
-        elementType = type.inner
-        return typeIsSequenceOrHasSequenceMember(elementType)
-    if type.isDictionary():
-        return dictionaryHasSequenceMember(type.inner)
-    if type.isUnion():
-        return any(typeIsSequenceOrHasSequenceMember(m.type) for m in
-                   type.flatMemberTypes)
-    return False
-
 # If this function is modified, modify CGNativeMember.getArg and
 # CGNativeMember.getRetvalInfo accordingly.  The latter cares about the decltype
 # and holdertype we end up using.
 def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
                                     isDefinitelyObject=False,
                                     isMember=False,
                                     isOptional=False,
                                     invalidEnumValueFatal=True,
@@ -2149,19 +2128,17 @@ def getJSToNativeConversionTemplate(type
     exceptionCode must end up doing a return, and every return from this
     function must happen via exceptionCode if exceptionCode is not None.
 
     If isDefinitelyObject is True, that means we know the value
     isObject() and we have no need to recheck that.
 
     if isMember is True, we're being converted from a property of some
     JS object, not from an actual method argument, so we can't rely on
-    our jsval being rooted or outliving us in any way.  Any caller
-    passing true needs to ensure that it is handled correctly in
-    typeIsSequenceOrHasSequenceMember.
+    our jsval being rooted or outliving us in any way.
 
     If isOptional is true, then we are doing conversion of an optional
     argument with no default value.
 
     invalidEnumValueFatal controls whether an invalid enum value conversion
     attempt will throw (if true) or simply return without doing anything (if
     false).
 
@@ -2321,77 +2298,84 @@ def getJSToNativeConversionTemplate(type
 
         nullable = type.nullable();
         # Be very careful not to change "type": we need it later
         if nullable:
             elementType = type.inner.inner
         else:
             elementType = type.inner
 
-        # We have to be careful with reallocation behavior for arrays.  In
-        # particular, if we have a sequence of elements which are themselves
-        # sequences (so nsAutoTArrays) or have sequences as members, we have a
-        # problem.  In that case, resizing the outermost nsAutoTarray to the
-        # right size will memmove its elements, but nsAutoTArrays are not
-        # memmovable and hence will end up with pointers to bogus memory, which
-        # is bad.  To deal with this, we disallow sequences, arrays,
-        # dictionaries, and unions which contain sequences as sequence item
-        # types.  If WebIDL ever adds another container type, we'd have to
-        # disallow it as well.
-        if typeIsSequenceOrHasSequenceMember(elementType):
-            raise TypeError("Can't handle a sequence containing another "
-                            "sequence as an element or member of an element.  "
-                            "See the big comment explaining why.\n%s" %
-                            str(type.location))
+        # We want to use auto arrays if we can, but we have to be careful with
+        # reallocation behavior for arrays.  In particular, if we use auto
+        # arrays for sequences and have a sequence of elements which are
+        # themselves sequences or have sequences as members, we have a problem.
+        # In that case, resizing the outermost nsAutoTarray to the right size
+        # will memmove its elements, but nsAutoTArrays are not memmovable and
+        # hence will end up with pointers to bogus memory, which is bad.  To
+        # deal with this, we typically map WebIDL sequences to our Sequence
+        # type, which is in fact memmovable.  The one exception is when we're
+        # passing in a sequence directly as an argument without any sort of
+        # optional or nullable complexity going on.  In that situation, we can
+        # use an AutoSequence instead.  We have to keep using Sequence in the
+        # nullable and optional cases because we don't want to leak the
+        # AutoSequence type to consumers, which would be unavoidable with
+        # Nullable<AutoSequence> or Optional<AutoSequence>.
+        if isMember or isOptional or nullable:
+            sequenceClass = "Sequence"
+        else:
+            sequenceClass = "AutoSequence"
 
         (elementTemplate, elementDeclType,
          elementHolderType, dealWithOptional) = getJSToNativeConversionTemplate(
             elementType, descriptorProvider, isMember=True,
             exceptionCode=exceptionCode, lenientFloatCode=lenientFloatCode)
         if dealWithOptional:
             raise TypeError("Shouldn't have optional things in sequences")
         if elementHolderType is not None:
             raise TypeError("Shouldn't need holders for sequences")
 
-        typeName = CGWrapper(elementDeclType, pre="Sequence< ", post=" >")
+        typeName = CGWrapper(elementDeclType,
+                             pre=("%s< " % sequenceClass), post=" >")
+        sequenceType = typeName.define()
         if nullable:
             typeName = CGWrapper(typeName, pre="Nullable< ", post=" >")
             arrayRef = "${declName}.Value()"
         else:
             arrayRef = "${declName}"
-        # If we're optional, the const will come from the Optional
+        # If we're optional or a member, the const will come from the Optional
+        # or whatever we're a member of.
         mutableTypeName = typeName
-        if not isOptional:
+        if not isOptional and not isMember:
             typeName = CGWrapper(typeName, pre="const ")
 
         # NOTE: Keep this in sync with variadic conversions as needed
         templateBody = ("""JSObject* seq = &${val}.toObject();\n
 if (!IsArrayLike(cx, seq)) {
 %s
 }
 uint32_t length;
 // JS_GetArrayLength actually works on all objects
 if (!JS_GetArrayLength(cx, seq, &length)) {
 %s
 }
-Sequence< %s > &arr = const_cast< Sequence< %s >& >(%s);
+%s &arr = const_cast< %s& >(%s);
 if (!arr.SetCapacity(length)) {
   JS_ReportOutOfMemory(cx);
 %s
 }
 for (uint32_t i = 0; i < length; ++i) {
   jsval temp;
   if (!JS_GetElement(cx, seq, i, &temp)) {
 %s
   }
   %s& slot = *arr.AppendElement();
 """ % (CGIndenter(CGGeneric(notSequence)).define(),
        exceptionCodeIndented.define(),
-       elementDeclType.define(),
-       elementDeclType.define(),
+       sequenceType,
+       sequenceType,
        arrayRef,
        exceptionCodeIndented.define(),
        CGIndenter(exceptionCodeIndented).define(),
        elementDeclType.define()))
 
         templateBody += CGIndenter(CGGeneric(
                 string.Template(elementTemplate).substitute(
                     {
@@ -3322,17 +3306,17 @@ class CGArgumentConverter(CGThing):
         (elementTemplate, elementDeclType,
          elementHolderType, dealWithOptional) = typeConversion
         if dealWithOptional:
             raise TypeError("Shouldn't have optional things in variadics")
         if elementHolderType is not None:
             raise TypeError("Shouldn't need holders for variadics")
 
         replacer = dict(self.argcAndIndex, **self.replacementVariables)
-        replacer["seqType"] = CGWrapper(elementDeclType, pre="Sequence< ", post=" >").define()
+        replacer["seqType"] = CGWrapper(elementDeclType, pre="AutoSequence< ", post=" >").define()
         replacer["elemType"] = elementDeclType.define()
 
         # NOTE: Keep this in sync with sequence conversions as needed
         variadicConversion = string.Template("""const ${seqType} ${declName};
 if (${argc} > ${index}) {
   ${seqType}& arr = const_cast< ${seqType}& >(${declName});
   if (!arr.SetCapacity(${argc} - ${index})) {
     JS_ReportOutOfMemory(cx);
@@ -5445,17 +5429,17 @@ class ClassConstructor(ClassItem):
                   'className': cgClass.getNameString(),
                   'args': args,
                   'body': body })
 
     def define(self, cgClass):
         if self.bodyInHeader:
             return ''
 
-        args = ', '.join([str(a) for a in self.args])
+        args = ', '.join([a.define() for a in self.args])
 
         body = '  ' + self.getBody()
         body = '\n' + stripTrailingWhitespace(body.replace('\n', '\n  '))
         if len(body) > 0:
             body += '\n'
 
         return string.Template("""${decorators}
 ${className}::${className}(${args})${initializationList}
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -332,16 +332,18 @@ public:
   void PassNullableExternalInterfaceSequence(const Sequence<nsRefPtr<TestExternalInterface> >&);
 
   void ReceiveStringSequence(nsTArray<nsString>&);
   void PassStringSequence(const Sequence<nsString>&);
 
   void ReceiveAnySequence(JSContext*, nsTArray<JS::Value>&);
   void ReceiveNullableAnySequence(JSContext*, Nullable<nsTArray<JS::Value> >);
 
+  void PassSequenceOfSequences(const Sequence< Sequence<int32_t> >&);
+
   // Typed array types
   void PassArrayBuffer(ArrayBuffer&);
   void PassNullableArrayBuffer(ArrayBuffer*);
   void PassOptionalArrayBuffer(const Optional<ArrayBuffer>&);
   void PassOptionalNullableArrayBuffer(const Optional<ArrayBuffer*>&);
   void PassOptionalNullableArrayBufferWithDefaultValue(ArrayBuffer*);
   void PassArrayBufferView(ArrayBufferView&);
   void PassInt8Array(Int8Array&);
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -311,16 +311,18 @@ interface TestInterface {
   void passNullableExternalInterfaceSequence(sequence<TestExternalInterface?> arg);
 
   sequence<DOMString> receiveStringSequence();
   void passStringSequence(sequence<DOMString> arg);
 
   sequence<any> receiveAnySequence();
   sequence<any>? receiveNullableAnySequence();
 
+  void passSequenceOfSequences(sequence<sequence<long>> arg);
+
   // Typed array types
   void passArrayBuffer(ArrayBuffer arg);
   void passNullableArrayBuffer(ArrayBuffer? arg);
   void passOptionalArrayBuffer(optional ArrayBuffer arg);
   void passOptionalNullableArrayBuffer(optional ArrayBuffer? arg);
   void passOptionalNullableArrayBufferWithDefaultValue(optional ArrayBuffer? arg= null);
   void passArrayBufferView(ArrayBufferView arg);
   void passInt8Array(Int8Array arg);
--- a/dom/bindings/test/TestExampleGen.webidl
+++ b/dom/bindings/test/TestExampleGen.webidl
@@ -227,16 +227,18 @@ interface TestExampleInterface {
   void passNullableExternalInterfaceSequence(sequence<TestExternalInterface?> arg);
 
   sequence<DOMString> receiveStringSequence();
   void passStringSequence(sequence<DOMString> arg);
 
   sequence<any> receiveAnySequence();
   sequence<any>? receiveNullableAnySequence();
 
+  void passSequenceOfSequences(sequence<sequence<long>> arg);
+
   // Typed array types
   void passArrayBuffer(ArrayBuffer arg);
   void passNullableArrayBuffer(ArrayBuffer? arg);
   void passOptionalArrayBuffer(optional ArrayBuffer arg);
   void passOptionalNullableArrayBuffer(optional ArrayBuffer? arg);
   void passOptionalNullableArrayBufferWithDefaultValue(optional ArrayBuffer? arg= null);
   void passArrayBufferView(ArrayBufferView arg);
   void passInt8Array(Int8Array arg);
--- a/dom/bluetooth/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/BluetoothHfpManager.cpp
@@ -269,17 +269,20 @@ public:
   {
     MOZ_ASSERT(NS_IsMainThread());
   }
 
   void Run() MOZ_OVERRIDE
   {
     MOZ_ASSERT(NS_IsMainThread());
 
-    NS_ENSURE_FALSE_VOID(sStopSendingRingFlag);
+    // Stop sending RING indicator
+    if (sStopSendingRingFlag) {
+      return;
+    }
 
     if (!gBluetoothHfpManager) {
       NS_WARNING("BluetoothHfpManager no longer exists, cannot send ring!");
       return;
     }
 
     const char* kHfpCrlf = "\xd\xa";
     nsAutoCString ringMsg(kHfpCrlf);
@@ -1153,25 +1156,27 @@ BluetoothHfpManager::HandleCallStateChan
     return;
   }
 
   while (aCallIndex >= mCurrentCallArray.Length()) {
     Call call;
     mCurrentCallArray.AppendElement(call);
   }
 
+  uint16_t prevCallState = mCurrentCallArray[aCallIndex].mState;
+  mCurrentCallArray[aCallIndex].mState = aCallState;
+
   // Same logic as implementation in ril_worker.js
   if (aNumber.Length() && aNumber[0] == '+') {
     mCurrentCallArray[aCallIndex].mType = TOA_INTERNATIONAL;
   }
   mCurrentCallArray[aCallIndex].mNumber = aNumber;
 
   nsRefPtr<nsRunnable> sendRingTask;
   nsString address;
-  uint16_t prevCallState = mCurrentCallArray[aCallIndex].mState;
   uint32_t callArrayLength = mCurrentCallArray.Length();
   uint32_t index = 1;
 
   switch (aCallState) {
     case nsIRadioInterfaceLayer::CALL_STATE_HELD:
       sCINDItems[CINDType::CALLHELD].value = CallHeldState::ONHOLD_ACTIVE;
       SendCommand("+CIEV: ", CINDType::CALLHELD);
       break;
@@ -1278,20 +1283,16 @@ BluetoothHfpManager::HandleCallStateChan
         case nsIRadioInterfaceLayer::CALL_STATE_HELD:
           UpdateCIND(CINDType::CALLHELD, CallHeldState::NO_CALLHELD, aSend);
           break;
         default:
           NS_WARNING("Not handling state changed");
       }
 
       if (aCallIndex == mCurrentCallIndex) {
-        NS_ASSERTION(mCurrentCallArray.Length() > aCallIndex,
-          "Call index out of bounds!");
-        mCurrentCallArray[aCallIndex].mState = aCallState;
-
         // Find the first non-disconnected call (like connected, held),
         // and update mCurrentCallIndex
         while (index < callArrayLength) {
           if (mCurrentCallArray[index].mState !=
               nsIRadioInterfaceLayer::CALL_STATE_DISCONNECTED) {
             mCurrentCallIndex = index;
             break;
           }
@@ -1306,18 +1307,16 @@ BluetoothHfpManager::HandleCallStateChan
       }
       break;
     default:
       NS_WARNING("Not handling state changed");
       sCINDItems[CINDType::CALL].value = CallState::NO_CALL;
       sCINDItems[CINDType::CALLSETUP].value = CallSetupState::NO_CALLSETUP;
       sCINDItems[CINDType::CALLHELD].value = CallHeldState::NO_CALLHELD;
   }
-
-  mCurrentCallArray[aCallIndex].mState = aCallState;
 }
 
 void
 BluetoothHfpManager::OnConnectSuccess()
 {
   nsCOMPtr<nsIRILContentHelper> ril =
     do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
   NS_ENSURE_TRUE_VOID(ril);
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -614,28 +614,16 @@ bool TabParent::SendRealTouchEvent(nsTou
     for (int i = e.touches.Length() - 1; i >= 0; i--) {
       if (!e.touches[i]->mChanged) {
         e.touches.RemoveElementAt(i);
       }
     }
   }
 
   MaybeForwardEventToRenderFrame(event, &e);
-
-  // Adjust the widget coordinates to be relative to our frame.
-  nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
-
-  if (!frameLoader) {
-    // No frame anymore?
-    sEventCapturer = nullptr;
-    return false;
-  }
-
-  nsEventStateManager::MapEventCoordinatesForChildProcess(frameLoader, &event);
-
   return (e.message == NS_TOUCH_MOVE) ?
     PBrowserParent::SendRealTouchMoveEvent(e) :
     PBrowserParent::SendRealTouchEvent(e);
 }
 
 /*static*/ TabParent*
 TabParent::GetEventCapturer()
 {
@@ -662,16 +650,27 @@ TabParent::TryCapture(const nsGUIEvent& 
     if (isTouchPointUp && 0 == --mEventCaptureDepth) {
       // All event series are un-captured, don't try to catch any
       // more.
       sEventCapturer = nullptr;
     }
     return false;
   }
 
+  // Adjust the widget coordinates to be relative to our frame.
+  nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
+
+  if (!frameLoader) {
+    // No frame anymore?
+    sEventCapturer = nullptr;
+    return false;
+  }
+
+  nsEventStateManager::MapEventCoordinatesForChildProcess(frameLoader, &event);
+
   SendRealTouchEvent(event);
   return true;
 }
 
 bool
 TabParent::RecvSyncMessage(const nsString& aMessage,
                            const ClonedMessageData& aData,
                            InfallibleTArray<nsString>* aJSONRetVal)
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -624,24 +624,17 @@ nsEditor::GetSelection(nsISelection **aS
 
 Selection*
 nsEditor::GetSelection()
 {
   nsCOMPtr<nsISelection> sel;
   nsresult res = GetSelection(getter_AddRefs(sel));
   NS_ENSURE_SUCCESS(res, nullptr);
 
-  nsCOMPtr<nsISelectionPrivate> selPrivate = do_QueryInterface(sel);
-  NS_ENSURE_TRUE(selPrivate, nullptr);
-
-  nsRefPtr<nsFrameSelection> frameSel;
-  res = selPrivate->GetFrameSelection(getter_AddRefs(frameSel));
-  NS_ENSURE_SUCCESS(res, nullptr);
-
-  return frameSel->GetSelection(nsISelectionController::SELECTION_NORMAL);
+  return static_cast<Selection*>(sel.get());
 }
 
 NS_IMETHODIMP
 nsEditor::DoTransaction(nsITransaction* aTxn)
 {
   if (mPlaceHolderBatch && !mPlaceHolderTxn) {
     nsCOMPtr<nsIAbsorbingTransaction> plcTxn = new PlaceholderTxn();
 
--- a/editor/libeditor/text/nsTextEditRulesBidi.cpp
+++ b/editor/libeditor/text/nsTextEditRulesBidi.cpp
@@ -7,24 +7,26 @@
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsError.h"
 #include "nsFrameSelection.h"
 #include "nsIContent.h"
 #include "nsIDOMNode.h"
 #include "nsIEditor.h"
 #include "nsIPresShell.h"
-#include "nsISelection.h"
+#include "mozilla/Selection.h"
 #include "nsISelectionPrivate.h"
 #include "nsISupportsImpl.h"
 #include "nsPlaintextEditor.h"
 #include "nsPresContext.h"
 #include "nsTextEditRules.h"
 #include "nscore.h"
 
+using namespace mozilla;
+
 // Test for distance between caret and text that will be deleted
 nsresult
 nsTextEditRules::CheckBidiLevelForDeletion(nsISelection         *aSelection,
                                            nsIDOMNode           *aSelNode, 
                                            int32_t               aSelOffset, 
                                            nsIEditor::EDirection aAction,
                                            bool                 *aCancel)
 {
@@ -40,22 +42,18 @@ nsTextEditRules::CheckBidiLevelForDeleti
   if (!context->BidiEnabled())
     return NS_OK;
   
   nsCOMPtr<nsIContent> content = do_QueryInterface(aSelNode);
   NS_ENSURE_TRUE(content, NS_ERROR_NULL_POINTER);
 
   uint8_t levelBefore;
   uint8_t levelAfter;
-
-  nsCOMPtr<nsISelectionPrivate> privateSelection(do_QueryInterface(aSelection));
-  NS_ENSURE_TRUE(privateSelection, NS_ERROR_NULL_POINTER);
-  
-  nsRefPtr<nsFrameSelection> frameSelection;
-  privateSelection->GetFrameSelection(getter_AddRefs(frameSelection));
+  nsRefPtr<nsFrameSelection> frameSelection =
+    static_cast<Selection*>(aSelection)->GetFrameSelection();
   NS_ENSURE_TRUE(frameSelection, NS_ERROR_NULL_POINTER);
   
   nsPrevNextBidiLevels levels = frameSelection->
     GetPrevNextBidiLevels(content, aSelOffset, true);
     
   levelBefore = levels.mLevelBefore;
   levelAfter = levels.mLevelAfter;
 
--- a/ipc/unixsocket/UnixSocket.cpp
+++ b/ipc/unixsocket/UnixSocket.cpp
@@ -723,16 +723,17 @@ UnixSocketImpl::OnFileCanReadWithoutBloc
       NS_WARNING("Could not set up socket!");
       return;
     }
 
     mReadWatcher.StopWatchingFileDescriptor();
     mWriteWatcher.StopWatchingFileDescriptor();
 
     mFd.reset(client_fd);
+    mIOLoop = nullptr;
 
     nsRefPtr<OnSocketEventTask> t =
       new OnSocketEventTask(this, OnSocketEventTask::CONNECT_SUCCESS);
     NS_DispatchToMainThread(t);
 
     // Due to the fact that we've dispatched our OnConnectSuccess message before
     // starting reading, we're guaranteed that any subsequent read tasks will
     // happen after the object has been notified of a successful connect.
--- a/js/src/builtin/Intl.js
+++ b/js/src/builtin/Intl.js
@@ -1659,8 +1659,329 @@ function InitializeDateTimeFormat(dateTi
     internals.pattern = pattern;
 
     // Step 30.
     internals.boundFormat = undefined;
 
     // Step 31.
     internals.initializedDateTimeFormat = true;
 }
+
+
+/**
+ * Returns a new options object that includes the provided options (if any)
+ * and fills in default components if required components are not defined.
+ * Required can be "date", "time", or "any".
+ * Defaults can be "date", "time", or "all".
+ *
+ * Spec: ECMAScript Internationalization API Specification, 12.1.1.
+ */
+function ToDateTimeOptions(options, required, defaults) {
+    assert(typeof required === "string", "ToDateTimeOptions");
+    assert(typeof defaults === "string", "ToDateTimeOptions");
+
+    // Steps 1-3.
+    if (options === undefined)
+        options = null;
+    else
+        options = ToObject(options);
+    options = std_Object_create(options);
+
+    // Step 4.
+    var needDefaults = true;
+
+    // Step 5.
+    if ((required === "date" || required === "any") &&
+        (options.weekday !== undefined || options.year !== undefined ||
+         options.month !== undefined || options.day !== undefined))
+    {
+        needDefaults = false;
+    }
+
+    // Step 6.
+    if ((required === "time" || required === "any") &&
+        (options.hour !== undefined || options.minute !== undefined ||
+         options.second !== undefined))
+    {
+        needDefaults = false;
+    }
+
+    // Step 7.
+    if (needDefaults && (defaults === "date" || defaults === "all")) {
+        // The specification says to call [[DefineOwnProperty]] with false for
+        // the Throw parameter, while Object.defineProperty uses true. For the
+        // calls here, the difference doesn't matter because we're adding
+        // properties to a new object.
+        defineProperty(options, "year", "numeric");
+        defineProperty(options, "month", "numeric");
+        defineProperty(options, "day", "numeric");
+    }
+
+    // Step 8.
+    if (needDefaults && (defaults === "time" || defaults === "all")) {
+        // See comment for step 7.
+        defineProperty(options, "hour", "numeric");
+        defineProperty(options, "minute", "numeric");
+        defineProperty(options, "second", "numeric");
+    }
+
+    // Step 9.
+    return options;
+}
+
+
+/**
+ * Compares the date and time components requested by options with the available
+ * date and time formats in formats, and selects the best match according
+ * to a specified basic matching algorithm.
+ *
+ * Spec: ECMAScript Internationalization API Specification, 12.1.1.
+ */
+function BasicFormatMatcher(options, formats) {
+    // Steps 1-6.
+    var removalPenalty = 120,
+        additionPenalty = 20,
+        longLessPenalty = 8,
+        longMorePenalty = 6,
+        shortLessPenalty = 6,
+        shortMorePenalty = 3;
+
+    // Table 3.
+    var properties = ["weekday", "era", "year", "month", "day",
+        "hour", "minute", "second", "timeZoneName"];
+
+    // Step 11.c.vi.1.
+    var values = ["2-digit", "numeric", "narrow", "short", "long"];
+
+    // Steps 7-8.
+    var bestScore = -Infinity;
+    var bestFormat;
+
+    // Steps 9-11.
+    var i = 0;
+    var len = formats.length;
+    while (i < len) {
+        // Steps 11.a-b.
+        var format = formats[i];
+        var score = 0;
+
+        // Step 11.c.
+        var formatProp;
+        for (var j = 0; j < properties.length; j++) {
+            var property = properties[j];
+
+            // Step 11.c.i.
+            var optionsProp = options[property];
+            // Step missing from spec.
+            // https://bugs.ecmascript.org/show_bug.cgi?id=1254
+            formatProp = undefined;
+
+            // Steps 11.c.ii-iii.
+            if (callFunction(std_Object_hasOwnProperty, format, property))
+                formatProp = format[property];
+
+            if (optionsProp === undefined && formatProp !== undefined) {
+                // Step 11.c.iv.
+                score -= additionPenalty;
+            } else if (optionsProp !== undefined && formatProp === undefined) {
+                // Step 11.c.v.
+                score -= removalPenalty;
+            } else {
+                // Step 11.c.vi.
+                var optionsPropIndex = callFunction(std_Array_indexOf, values, optionsProp);
+                var formatPropIndex = callFunction(std_Array_indexOf, values, formatProp);
+                var delta = std_Math_max(std_Math_min(formatPropIndex - optionsPropIndex, 2), -2);
+                if (delta === 2)
+                    score -= longMorePenalty;
+                else if (delta === 1)
+                    score -= shortMorePenalty;
+                else if (delta === -1)
+                    score -= shortLessPenalty;
+                else if (delta === -2)
+                    score -= longLessPenalty;
+            }
+        }
+
+        // Step 11.d.
+        if (score > bestScore) {
+            bestScore = score;
+            bestFormat = format;
+        }
+
+        // Step 11.e.
+        i++;
+    }
+
+    // Step 12.
+    return bestFormat;
+}
+
+
+/**
+ * Compares the date and time components requested by options with the available
+ * date and time formats in formats, and selects the best match according
+ * to an unspecified best-fit matching algorithm.
+ *
+ * Spec: ECMAScript Internationalization API Specification, 12.1.1.
+ */
+function BestFitFormatMatcher(options, formats) {
+    // this implementation doesn't have anything better
+    return BasicFormatMatcher(options, formats);
+}
+
+
+/**
+ * Returns the subset of the given locale list for which this locale list has a
+ * matching (possibly fallback) locale. Locales appear in the same order in the
+ * returned list as in the input list.
+ *
+ * Spec: ECMAScript Internationalization API Specification, 12.2.2.
+ */
+function Intl_DateTimeFormat_supportedLocalesOf(locales /*, options*/) {
+    var options = arguments.length > 1 ? arguments[1] : undefined;
+
+    var availableLocales = dateTimeFormatInternalProperties.availableLocales;
+    var requestedLocales = CanonicalizeLocaleList(locales);
+    return SupportedLocales(availableLocales, requestedLocales, options);
+}
+
+
+/**
+ * DateTimeFormat internal properties.
+ *
+ * Spec: ECMAScript Internationalization API Specification, 9.1 and 12.2.3.
+ */
+var dateTimeFormatInternalProperties = {
+    localeData: dateTimeFormatLocaleData,
+    availableLocales: runtimeAvailableLocales, // stub
+    relevantExtensionKeys: ["ca", "nu"]
+};
+
+
+function dateTimeFormatLocaleData(locale) {
+    // the following data may or may not match any actual locale support
+    var localeData = {
+        ca: ["gregory"],
+        nu: ["latn"],
+        hour12: false,
+        hourNo0: false
+    };
+
+    var formatDate = {
+        weekday: "short",
+        year: "numeric",
+        month: "short",
+        day: "numeric"
+    };
+    var formatTime = {
+        hour: "numeric",
+        minute: "numeric",
+        second: "numeric"
+    };
+    var formatFull = {
+        weekday: "short",
+        year: "numeric",
+        month: "short",
+        day: "numeric",
+        hour: "numeric",
+        minute: "numeric",
+        second: "numeric"
+    };
+    localeData.formats = [formatDate, formatTime, formatFull];
+
+    return localeData;
+}
+
+
+/**
+ * Function to be bound and returned by Intl.DateTimeFormat.prototype.format.
+ *
+ * Spec: ECMAScript Internationalization API Specification, 12.3.2.
+ */
+function dateTimeFormatFormatToBind() {
+    // Steps 1.a.i-ii
+    var date = arguments.length > 0 ? arguments[0] : undefined;
+    var x = (date === undefined) ? std_Date_now() : ToNumber(date);
+
+    // Step 1.a.iii.
+    return FormatDateTime(this, x);
+}
+
+
+/**
+ * Returns a function bound to this DateTimeFormat that returns a String value
+ * representing the result of calling ToNumber(date) according to the
+ * effective locale and the formatting options of this DateTimeFormat.
+ *
+ * Spec: ECMAScript Internationalization API Specification, 12.3.2.
+ */
+function Intl_DateTimeFormat_format_get() {
+    // Check "this DateTimeFormat object" per introduction of section 12.3.
+    var internals = checkIntlAPIObject(this, "DateTimeFormat", "format");
+
+    // Step 1.
+    if (internals.boundFormat === undefined) {
+        // Step 1.a.
+        var F = dateTimeFormatFormatToBind;
+
+        // Step 1.b-d.
+        var bf = callFunction(std_Function_bind, F, this);
+        internals.boundFormat = bf;
+    }
+
+    // Step 2.
+    return internals.boundFormat;
+}
+
+
+/**
+ * Returns a String value representing the result of calling ToNumber(date)
+ * according to the effective locale and the formatting options of this
+ * DateTimeFormat.
+ *
+ * Spec: ECMAScript Internationalization API Specification, 12.3.2.
+ */
+function FormatDateTime(dateTimeFormat, x) {
+    // ??? stub
+    if (!std_isFinite(x))
+        ThrowError(JSMSG_DATE_NOT_FINITE);
+    var X = new Std_Date(x);
+    var internals = getInternals(dateTimeFormat);
+    var wantDate = callFunction(std_Object_hasOwnProperty, internals, "weekday") ||
+        callFunction(std_Object_hasOwnProperty, internals, "year") ||
+        callFunction(std_Object_hasOwnProperty, internals, "month") ||
+        callFunction(std_Object_hasOwnProperty, internals, "day");
+    var wantTime = callFunction(std_Object_hasOwnProperty, internals, "hour") ||
+        callFunction(std_Object_hasOwnProperty, internals, "minute") ||
+        callFunction(std_Object_hasOwnProperty, internals, "second");
+    if (wantDate) {
+        if (wantTime)
+            return X.toLocaleString();
+        return X.toLocaleDateString();
+    }
+    return X.toLocaleTimeString();
+}
+
+
+/**
+ * Returns the resolved options for a DateTimeFormat object.
+ *
+ * Spec: ECMAScript Internationalization API Specification, 12.3.3 and 12.4.
+ */
+function Intl_DateTimeFormat_resolvedOptions() {
+    // Check "this DateTimeFormat object" per introduction of section 12.3.
+    var internals = checkIntlAPIObject(this, "DateTimeFormat", "resolvedOptions");
+
+    var result = {
+        locale: internals.locale,
+        calendar: internals.calendar,
+        numberingSystem: internals.numberingSystem,
+        timeZone: internals.timeZone
+    };
+    for (var i = 0; i < dateTimeComponents.length; i++) {
+        var p = dateTimeComponents[i];
+        if (callFunction(std_Object_hasOwnProperty, internals, p))
+            defineProperty(result, p, internals[p]);
+    }
+    if (callFunction(std_Object_hasOwnProperty, internals, "hour12"))
+        defineProperty(result, "hour12", internals.hour12);
+    return result;
+}
--- a/js/src/builtin/embedjs.py
+++ b/js/src/builtin/embedjs.py
@@ -8,36 +8,41 @@
 # It expects error messages in the JS code to be referenced by their C enum
 # keys as literals.
 
 from __future__ import with_statement
 import re, sys, os, js2c, fileinput
 
 def replaceErrorMsgs(source_files, messages_file, output_file):
     messages = buildMessagesTable(messages_file)
+    # For cases where one key is a prefix of another, we need to check
+    # for the longer one first. Using a reverse-sorted key list ensures that.
+    message_keys = messages.keys()
+    message_keys.sort(reverse=True)
     with open(output_file, 'w') as output:
         if len(source_files) == 0:
             return
         for line in fileinput.input(source_files):
-            output.write(replaceMessages(line if line[-1] == '\n' else line + '\n', messages))
+            line = line if line[-1] == '\n' else line + '\n'
+            output.write(replaceMessages(line, messages, message_keys))
 
 def buildMessagesTable(messages_file):
     table = {}
     pattern = re.compile(r"MSG_DEF\(([\w_]+),\s*(\d+)")
     for line in fileinput.input(messages_file):
         match = pattern.match(line)
         if match:
             table[match.group(1)] = match.group(2)
     return table
 
-def replaceMessages(line, messages):
+def replaceMessages(line, messages, message_keys):
     if not 'JSMSG_' in line:
         return line
-    for message_str, message_num in messages.iteritems():
-        line = line.replace(message_str, message_num)
+    for key in message_keys:
+        line = line.replace(key, messages[key])
     return line
 
 def main():
     debug = sys.argv[1] == '-d'
     if debug:
         sys.argv.pop(1)
     output_file = sys.argv[1]
     messages_file = sys.argv[2]
--- a/js/src/jit-test/jit_test.py
+++ b/js/src/jit-test/jit_test.py
@@ -13,21 +13,16 @@ def add_libdir_to_path():
     sys.path.append(join(js_src_dir, 'tests', 'lib'))
 
 add_libdir_to_path()
 
 import jittests
 
 def main(argv):
 
-    script_path = os.path.abspath(__file__)
-    script_dir = os.path.dirname(script_path)
-    test_dir = os.path.join(script_dir, 'tests')
-    lib_dir = os.path.join(script_dir, 'lib')
-
     # If no multiprocessing is available, fallback to serial test execution
     max_jobs_default = 1
     if jittests.HAVE_MULTIPROCESSING:
         try:
             max_jobs_default = jittests.cpu_count()
         except NotImplementedError:
             pass
 
@@ -79,17 +74,17 @@ def main(argv):
                   help='Run tests with all IonMonkey option combinations (ignores --jitflags)')
     op.add_option('-j', '--worker-count', dest='max_jobs', type=int, default=max_jobs_default,
                   help='Number of tests to run in parallel (default %default)')
 
     options, args = op.parse_args(argv)
     if len(args) < 1:
         op.error('missing JS_SHELL argument')
     # We need to make sure we are using backslashes on Windows.
-    options.js_shell, test_args = os.path.abspath(args[0]), args[1:]
+    test_args = args[1:]
 
     if jittests.stdio_might_be_broken():
         # Prefer erring on the side of caution and not using stdio if
         # it might be broken on this platform.  The file-redirect
         # fallback should work on any platform, so at worst by
         # guessing wrong we might have slowed down the tests a bit.
         #
         # XXX technically we could check for broken stdio, but it
@@ -101,41 +96,41 @@ def main(argv):
         options.write_failures = options.retest
 
     test_list = []
     read_all = True
 
     if test_args:
         read_all = False
         for arg in test_args:
-            test_list += jittests.find_tests(test_dir, arg)
+            test_list += jittests.find_tests(arg)
 
     if options.read_tests:
         read_all = False
         try:
             f = open(options.read_tests)
             for line in f:
-                test_list.append(os.path.join(test_dir, line.strip('\n')))
+                test_list.append(os.path.join(TEST_DIR, line.strip('\n')))
             f.close()
         except IOError:
             if options.retest:
                 read_all = True
             else:
                 sys.stderr.write("Exception thrown trying to read test file '%s'\n"%
                                  options.read_tests)
                 traceback.print_exc()
                 sys.stderr.write('---\n')
 
     if read_all:
-        test_list = jittests.find_tests(test_dir)
+        test_list = jittests.find_tests()
 
     if options.exclude:
         exclude_list = []
         for exclude in options.exclude:
-            exclude_list += jittests.find_tests(test_dir, exclude)
+            exclude_list += jittests.find_tests(exclude)
         test_list = [ test for test in test_list if test not in set(exclude_list) ]
 
     if not test_list:
         print >> sys.stderr, "No tests found matching command line arguments."
         sys.exit(0)
 
     test_list = [jittests.Test.from_file(_, options) for _ in test_list]
 
@@ -174,39 +169,39 @@ def main(argv):
     else:
         jitflags_list = jittests.parse_jitflags(options)
         for test in test_list:
             for jitflags in jitflags_list:
                 new_test = test.copy()
                 new_test.jitflags.extend(jitflags)
                 job_list.append(new_test)
 
-    shell_args = shlex.split(options.shell_args)
-
+    prefix = [os.path.abspath(args[0])] + shlex.split(options.shell_args)
+    prefix += ['-f', os.path.join(jittests.LIB_DIR, 'prolog.js')]
     if options.debug:
         if len(job_list) > 1:
             print 'Multiple tests match command line arguments, debugger can only run one'
             for tc in job_list:
                 print '    %s' % tc.path
             sys.exit(1)
 
         tc = job_list[0]
-        cmd = [ 'gdb', '--args' ] + jittests.get_test_cmd(options.js_shell, tc.path, tc.jitflags, lib_dir, shell_args)
+        cmd = ['gdb', '--args'] + tc.command(prefix)
         subprocess.call(cmd)
         sys.exit()
 
     try:
         ok = None
         if options.max_jobs > 1 and jittests.HAVE_MULTIPROCESSING:
-            ok = jittests.run_tests_parallel(job_list, test_dir, lib_dir, shell_args, options)
+            ok = jittests.run_tests_parallel(job_list, prefix, options)
         else:
-            ok = jittests.run_tests(job_list, test_dir, lib_dir, shell_args, options)
+            ok = jittests.run_tests(job_list, prefix, options)
         if not ok:
             sys.exit(2)
     except OSError:
-        if not os.path.exists(options.js_shell):
-            print >> sys.stderr, "JS shell argument: file does not exist: '%s'" % options.js_shell
+        if not os.path.exists(prefix[0]):
+            print >> sys.stderr, "JS shell argument: file does not exist: '%s'" % prefix[0]
             sys.exit(1)
         else:
             raise
 
 if __name__ == '__main__':
     main(sys.argv[1:])
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -5248,16 +5248,17 @@ CheckNewScriptProperties(JSContext *cx, 
     NewScriptPropertiesState state(cx);
     state.thisFunction = fun;
 
     /* Strawman object to add properties to and watch for duplicates. */
     state.baseobj = NewBuiltinClassInstance(cx, &ObjectClass, gc::FINALIZE_OBJECT16);
     if (!state.baseobj) {
         if (type->newScript)
             type->clearNewScript(cx);
+        cx->compartment->types.setPendingNukeTypes(cx);
         return;
     }
 
     AnalyzeNewScriptProperties(cx, type, fun, state);
     if (!state.baseobj ||
         state.baseobj->slotSpan() == 0 ||
         !!(type->flags & OBJECT_FLAG_NEW_SCRIPT_CLEARED))
     {
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -17,17 +17,16 @@
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/GuardObjects.h"
 #include "mozilla/Util.h"
 
 #include "jstypes.h"
 #include "jsutil.h"
 #include "jsprf.h"
-#include "jswrapper.h"
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsdate.h"
 #include "jsdbgapi.h"
 #include "jsfun.h"
 #include "jsgc.h"
@@ -36,16 +35,17 @@
 #include "jsnum.h"
 #include "jsobj.h"
 #include "json.h"
 #include "jsreflect.h"
 #include "jsscript.h"
 #include "jstypedarray.h"
 #include "jstypedarrayinlines.h"
 #include "jsworkers.h"
+#include "jswrapper.h"
 #include "jsperf.h"
 
 #include "builtin/TestingFunctions.h"
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/Parser.h"
 #include "methodjit/MethodJIT.h"
 #include "vm/Shape.h"
 
--- a/js/src/tests/lib/jittests.py
+++ b/js/src/tests/lib/jittests.py
@@ -15,16 +15,22 @@ import signal
 
 try:
     from multiprocessing import Process, Manager, cpu_count
     HAVE_MULTIPROCESSING = True
 except ImportError:
     HAVE_MULTIPROCESSING = False
 
 from progressbar import ProgressBar, NullProgressBar
+from results import TestOutput
+
+TESTS_LIB_DIR = os.path.dirname(os.path.abspath(__file__))
+JS_DIR = os.path.dirname(os.path.dirname(TESTS_LIB_DIR))
+TEST_DIR = os.path.join(JS_DIR, 'jit-test', 'tests')
+LIB_DIR = os.path.join(JS_DIR, 'jit-test', 'lib') + os.path.sep
 
 # Backported from Python 3.1 posixpath.py
 def _relpath(path, start=None):
     """Return a relative version of a path"""
 
     if not path:
         raise ValueError("no path specified")
 
@@ -40,16 +46,32 @@ def _relpath(path, start=None):
     rel_list = [os.pardir] * (len(start_list)-i) + path_list[i:]
     if not rel_list:
         return os.curdir
     return os.path.join(*rel_list)
 
 os.path.relpath = _relpath
 
 class Test:
+
+    VALGRIND_CMD = []
+    paths = (d for d in os.environ['PATH'].split(os.pathsep))
+    valgrinds = (os.path.join(d, 'valgrind') for d in paths)
+    if any(os.path.exists(p) for p in valgrinds):
+        VALGRIND_CMD = [
+            'valgrind', '-q', '--smc-check=all-non-file',
+            '--error-exitcode=1', '--gen-suppressions=all',
+            '--show-possibly-lost=no', '--leak-check=full',
+        ]
+        if os.uname()[0] == 'Darwin':
+            VALGRIND_CMD.append('--dsymutil=yes')
+
+    del paths
+    del valgrinds
+
     def __init__(self, path):
         self.path = path       # path to test file
 
         self.jitflags = []     # jit flags to enable
         self.slow = False      # True means the test is slow-running
         self.allow_oom = False # True means that OOM is not considered a failure
         self.valgrind = False  # True means run under valgrind
         self.tz_pacific = False # True means force Pacific time for the test
@@ -118,47 +140,46 @@ class Test:
                     else:
                         print('warning: unrecognized |jit-test| attribute %s' % part)
 
         if options.valgrind_all:
             test.valgrind = True
 
         return test
 
-def find_tests(dir, substring = None):
+    def command(self, prefix):
+        scriptdir_var = os.path.dirname(self.path);
+        if not scriptdir_var.endswith('/'):
+            scriptdir_var += '/'
+        expr = ("const platform=%r; const libdir=%r; const scriptdir=%r"
+                % (sys.platform, LIB_DIR, scriptdir_var))
+        # We may have specified '-a' or '-d' twice: once via --jitflags, once
+        # via the "|jit-test|" line.  Remove dups because they are toggles.
+        cmd = prefix + list(set(self.jitflags)) + ['-e', expr, '-f', self.path]
+        if self.valgrind:
+            cmd = self.VALGRIND_CMD + cmd
+        return cmd
+
+def find_tests(substring=None):
     ans = []
-    for dirpath, dirnames, filenames in os.walk(dir):
+    for dirpath, dirnames, filenames in os.walk(TEST_DIR):
         dirnames.sort()
         filenames.sort()
         if dirpath == '.':
             continue
         for filename in filenames:
             if not filename.endswith('.js'):
                 continue
             if filename in ('shell.js', 'browser.js', 'jsref.js'):
                 continue
             test = os.path.join(dirpath, filename)
-            if substring is None or substring in os.path.relpath(test, dir):
+            if substring is None or substring in os.path.relpath(test, TEST_DIR):
                 ans.append(test)
     return ans
 
-def get_test_cmd(js, path, jitflags, lib_dir, shell_args):
-    libdir_var = lib_dir
-    if not libdir_var.endswith('/'):
-        libdir_var += '/'
-    scriptdir_var = os.path.dirname(path);
-    if not scriptdir_var.endswith('/'):
-        scriptdir_var += '/'
-    expr = ("const platform=%r; const libdir=%r; const scriptdir=%r"
-            % (sys.platform, libdir_var, scriptdir_var))
-    # We may have specified '-a' or '-d' twice: once via --jitflags, once
-    # via the "|jit-test|" line.  Remove dups because they are toggles.
-    return ([js] + list(set(jitflags)) + shell_args +
-            [ '-e', expr, '-f', os.path.join(lib_dir, 'prolog.js'), '-f', path ])
-
 def tmppath(token):
     fd, path = tempfile.mkstemp(prefix=token)
     os.close(fd)
     return path
 
 def read_and_unlink(path):
     f = open(path)
     d = f.read()
@@ -234,55 +255,32 @@ def run_cmd(cmdline, env, timeout):
 
 def run_cmd_avoid_stdio(cmdline, env, timeout):
     stdoutPath, stderrPath = tmppath('jsstdout'), tmppath('jsstderr')
     env['JS_STDOUT'] = stdoutPath
     env['JS_STDERR'] = stderrPath
     _, __, code = run_timeout_cmd(cmdline, { 'env': env }, timeout)
     return read_and_unlink(stdoutPath), read_and_unlink(stderrPath), code
 
-def run_test(test, lib_dir, shell_args, options):
-    cmd = get_test_cmd(options.js_shell, test.path, test.jitflags, lib_dir, shell_args)
-
-    if (test.valgrind and
-        any([os.path.exists(os.path.join(d, 'valgrind'))
-             for d in os.environ['PATH'].split(os.pathsep)])):
-        valgrind_prefix = [ 'valgrind',
-                            '-q',
-                            '--smc-check=all-non-file',
-                            '--error-exitcode=1',
-                            '--gen-suppressions=all',
-                            '--show-possibly-lost=no',
-                            '--leak-check=full']
-        if os.uname()[0] == 'Darwin':
-            valgrind_prefix += ['--dsymutil=yes']
-        cmd = valgrind_prefix + cmd
-
+def run_test(test, prefix, options):
+    cmd = test.command(prefix)
     if options.show_cmd:
         print(subprocess.list2cmdline(cmd))
 
     if options.avoid_stdio:
         run = run_cmd_avoid_stdio
     else:
         run = run_cmd
 
     env = os.environ.copy()
     if test.tz_pacific:
         env['TZ'] = 'PST8PDT'
 
     out, err, code, timed_out = run(cmd, env, options.timeout)
-
-    if options.show_output:
-        sys.stdout.write(out)
-        sys.stdout.write(err)
-        sys.stdout.write('Exit code: %s\n' % code)
-    if test.valgrind:
-        sys.stdout.write(err)
-    return (check_output(out, err, code, test),
-            out, err, code, timed_out)
+    return TestOutput(test, cmd, out, err, code, None, timed_out)
 
 def check_output(out, err, rc, test):
     if test.expect_error:
         return test.expect_error in err
 
     for line in out.split('\n'):
         if line.startswith('Trace stats check failed'):
             return False
@@ -304,24 +302,24 @@ def print_tinderbox(label, test, message
         result = "%s | jit_test.py %-15s| %s" % (label, jitflags, test.path)
     else:
         result = "%s | jit_test.py " % label
 
     if message:
         result += ": " + message
     print(result)
 
-def wrap_parallel_run_test(test, lib_dir, shell_args, resultQueue, options):
+def wrap_parallel_run_test(test, prefix, resultQueue, options):
     # Ignore SIGINT in the child
     signal.signal(signal.SIGINT, signal.SIG_IGN)
-    result = run_test(test, lib_dir, shell_args, options) + (test,)
+    result = run_test(test, prefix, options)
     resultQueue.put(result)
     return result
 
-def run_tests_parallel(tests, test_dir, lib_dir, shell_args, options):
+def run_tests_parallel(tests, prefix, options):
     # This queue will contain the results of the various tests run.
     # We could make this queue a global variable instead of using
     # a manager to share, but this will not work on Windows.
     queue_manager = Manager()
     async_test_result_queue = queue_manager.Queue()
 
     # This queue will be used by the result process to indicate
     # that it has received a result and we can start a new process
@@ -329,17 +327,17 @@ def run_tests_parallel(tests, test_dir, 
     # check for worker completion ourselves regularly.
     notify_queue = queue_manager.Queue()
 
     # This queue will contain the return value of the function
     # processing the test results.
     result_process_return_queue = queue_manager.Queue()
     result_process = Process(target=process_test_results_parallel,
                              args=(async_test_result_queue, result_process_return_queue,
-                                   notify_queue, len(tests), options, lib_dir, shell_args))
+                                   notify_queue, len(tests), options))
     result_process.start()
 
     # Ensure that a SIGTERM is handled the same way as SIGINT
     # to terminate all child processes.
     sigint_handler = signal.getsignal(signal.SIGINT)
     signal.signal(signal.SIGTERM, sigint_handler)
 
     worker_processes = []
@@ -359,17 +357,17 @@ def run_tests_parallel(tests, test_dir, 
         for i in range(min(options.max_jobs,len(tests))):
             notify_queue.put(True)
 
         # For every item in the notify queue, start one new worker.
         # Every completed worker adds a new item to this queue.
         while notify_queue.get():
             if (testcnt < len(tests)):
                 # Start one new worker
-                worker_process = Process(target=wrap_parallel_run_test, args=(tests[testcnt], lib_dir, shell_args, async_test_result_queue, options))
+                worker_process = Process(target=wrap_parallel_run_test, args=(tests[testcnt], prefix, async_test_result_queue, options))
                 worker_processes.append(worker_process)
                 worker_process.start()
                 testcnt += 1
 
                 # Collect completed workers
                 worker_processes = remove_completed_workers(worker_processes)
             else:
                 break
@@ -408,124 +406,130 @@ def get_parallel_results(async_test_resu
         if (async_test_result == None):
             return
 
         # Notify parent that we got a result
         notify_queue.put(True)
 
         yield async_test_result
 
-def process_test_results_parallel(async_test_result_queue, return_queue, notify_queue, num_tests, options, lib_dir, shell_args):
+def process_test_results_parallel(async_test_result_queue, return_queue, notify_queue, num_tests, options):
     gen = get_parallel_results(async_test_result_queue, notify_queue)
-    ok = process_test_results(gen, num_tests, options, lib_dir, shell_args)
+    ok = process_test_results(gen, num_tests, options)
     return_queue.put(ok)
 
-def print_test_summary(failures, complete, doing, options, lib_dir, shell_args):
+def print_test_summary(failures, complete, doing, options):
     if failures:
         if options.write_failures:
             try:
                 out = open(options.write_failures, 'w')
                 # Don't write duplicate entries when we are doing multiple failures per job.
                 written = set()
-                for test, fout, ferr, fcode, _ in failures:
-                    if test.path not in written:
-                        out.write(os.path.relpath(test.path, test_dir) + '\n')
+                for res in failures:
+                    if res.test.path not in written:
+                        out.write(os.path.relpath(res.test.path, TEST_DIR) + '\n')
                         if options.write_failure_output:
-                            out.write(fout)
-                            out.write(ferr)
-                            out.write('Exit code: ' + str(fcode) + "\n")
-                        written.add(test.path)
+                            out.write(res.out)
+                            out.write(res.err)
+                            out.write('Exit code: ' + str(res.rc) + "\n")
+                        written.add(res.test.path)
                 out.close()
             except IOError:
                 sys.stderr.write("Exception thrown trying to write failure file '%s'\n"%
                                  options.write_failures)
                 traceback.print_exc()
                 sys.stderr.write('---\n')
 
-        def show_test(test):
+        def show_test(res):
             if options.show_failed:
-                print('    ' + subprocess.list2cmdline(get_test_cmd(options.js_shell, test.path, test.jitflags, lib_dir, shell_args)))
+                print('    ' + subprocess.list2cmdline(res.cmd))
             else:
-                print('    ' + ' '.join(test.jitflags + [test.path]))
+                print('    ' + ' '.join(res.test.jitflags + [res.test.path]))
 
         print('FAILURES:')
-        for test, _, __, ___, timed_out in failures:
-            if not timed_out:
-                show_test(test)
+        for res in failures:
+            if not res.timed_out:
+                show_test(res)
 
         print('TIMEOUTS:')
-        for test, _, __, ___, timed_out in failures:
-            if timed_out:
-                show_test(test)
+        for res in failures:
+            if res.timed_out:
+                show_test(res)
 
         return False
     else:
         print('PASSED ALL' + ('' if complete else ' (partial run -- interrupted by user %s)' % doing))
         return True
 
-def process_test_results(results, num_tests, options, lib_dir, shell_args):
+def process_test_results(results, num_tests, options):
     pb = NullProgressBar()
     if not options.hide_progress and not options.show_cmd and ProgressBar.conservative_isatty():
         fmt = [
             {'value': 'PASS',    'color': 'green'},
             {'value': 'FAIL',    'color': 'red'},
             {'value': 'TIMEOUT', 'color': 'blue'},
             {'value': 'SKIP',    'color': 'brightgray'},
         ]
         pb = ProgressBar(num_tests, fmt)
 
     failures = []
     timeouts = 0
     complete = False
     doing = 'before starting'
     try:
-        for i, (ok, out, err, code, timed_out, test) in enumerate(results):
-            doing = 'after %s'%test.path
+        for i, res in enumerate(results):
 
+            if options.show_output:
+                sys.stdout.write(res.out)
+                sys.stdout.write(res.err)
+                sys.stdout.write('Exit code: %s\n' % res.rc)
+            if res.test.valgrind:
+                sys.stdout.write(res.err)
+
+            ok = check_output(res.out, res.err, res.rc, res.test)
+            doing = 'after %s' % res.test.path
             if not ok:
-                failures.append([ test, out, err, code, timed_out ])
-                pb.message("FAIL - %s" % test.path)
-            if timed_out:
+                failures.append(res)
+                pb.message("FAIL - %s" % res.test.path)
+            if res.timed_out:
                 timeouts += 1
 
             if options.tinderbox:
                 if ok:
-                    print_tinderbox("TEST-PASS", test);
+                    print_tinderbox("TEST-PASS", res.test);
                 else:
-                    lines = [ _ for _ in out.split('\n') + err.split('\n')
+                    lines = [ _ for _ in res.out.split('\n') + res.err.split('\n')
                               if _ != '' ]
                     if len(lines) >= 1:
                         msg = lines[-1]
                     else:
                         msg = ''
-                    print_tinderbox("TEST-UNEXPECTED-FAIL", test, msg);
+                    print_tinderbox("TEST-UNEXPECTED-FAIL", res.test, msg);
 
             n = i + 1
             pb.update(n, {
                 'PASS': n - len(failures),
                 'FAIL': len(failures),
                 'TIMEOUT': timeouts,
                 'SKIP': 0}
             )
         complete = True
     except KeyboardInterrupt:
         print_tinderbox("TEST-UNEXPECTED-FAIL", None, "Test execution interrupted by user");
 
     pb.finish(True)
-    return print_test_summary(failures, complete, doing, options, lib_dir, shell_args)
+    return print_test_summary(failures, complete, doing, options)
 
-
-def get_serial_results(tests, lib_dir, shell_args, options):
+def get_serial_results(tests, prefix, options):
     for test in tests:
-        result = run_test(test, lib_dir, shell_args, options)
-        yield result + (test,)
+        yield run_test(test, prefix, options)
 
-def run_tests(tests, test_dir, lib_dir, shell_args, options):
-    gen = get_serial_results(tests, lib_dir, shell_args, options)
-    ok = process_test_results(gen, len(tests), options, lib_dir, shell_args)
+def run_tests(tests, prefix, options):
+    gen = get_serial_results(tests, prefix, options)
+    ok = process_test_results(gen, len(tests), options)
     return ok
 
 def parse_jitflags(options):
     jitflags = [ [ '-' + flag for flag in flags ]
                  for flags in options.jitflags.split(',') ]
     for flags in jitflags:
         for flag in flags:
             if flag not in ('-m', '-a', '-p', '-d', '-n'):
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1202,27 +1202,16 @@ void XPCJSRuntime::SystemIsBeingShutDown
 {
     DOM_ClearInterfaces();
 
     if (mDetachedWrappedNativeProtoMap)
         mDetachedWrappedNativeProtoMap->
             Enumerate(DetachedWrappedNativeProtoShutdownMarker, nullptr);
 }
 
-JSContext *
-XPCJSRuntime::GetJSCycleCollectionContext()
-{
-    if (!mJSCycleCollectionContext) {
-        mJSCycleCollectionContext = JS_NewContext(mJSRuntime, 0);
-        if (!mJSCycleCollectionContext)
-            return nullptr;
-    }
-    return mJSCycleCollectionContext;
-}
-
 XPCJSRuntime::~XPCJSRuntime()
 {
     MOZ_ASSERT(!mReleaseRunnable);
 
     js::SetGCSliceCallback(mJSRuntime, mPrevGCSliceCallback);
 
     xpc_DelocalizeRuntime(mJSRuntime);
 
@@ -1239,19 +1228,16 @@ XPCJSRuntime::~XPCJSRuntime()
                 PR_WaitCondVar(mWatchdogWakeup, PR_INTERVAL_NO_TIMEOUT);
             }
         }
         PR_DestroyCondVar(mWatchdogWakeup);
         PR_DestroyLock(mWatchdogLock);
         mWatchdogWakeup = nullptr;
     }
 
-    if (mJSCycleCollectionContext)
-        JS_DestroyContextNoGC(mJSCycleCollectionContext);
-
     if (mCallContext)
         mCallContext->SystemIsBeingShutDown();
 
 #ifdef XPC_DUMP_AT_SHUTDOWN
     {
     // count the total JSContexts in use
     JSContext* iter = nullptr;
     int count = 0;
@@ -2489,17 +2475,16 @@ SourceHook(JSContext *cx, JSScript *scri
 
   return true;
 }
 
 XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
  : mXPConnect(aXPConnect),
    mJSRuntime(nullptr),
    mJSContextStack(new XPCJSContextStack()),
-   mJSCycleCollectionContext(nullptr),
    mCallContext(nullptr),
    mAutoRoots(nullptr),
    mResolveName(JSID_VOID),
    mResolvingWrapper(nullptr),
    mWrappedJSMap(JSObject2WrappedJSMap::newMap(XPC_JS_MAP_SIZE)),
    mWrappedJSClassMap(IID2WrappedJSClassMap::newMap(XPC_JS_CLASS_MAP_SIZE)),
    mIID2NativeInterfaceMap(IID2NativeInterfaceMap::newMap(XPC_NATIVE_INTERFACE_MAP_SIZE)),
    mClassInfo2NativeSetMap(ClassInfo2NativeSetMap::newMap(XPC_NATIVE_SET_MAP_SIZE)),
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -74,18 +74,17 @@ const char XPC_XPCONNECT_CONTRACTID[]   
 /***************************************************************************/
 
 nsXPConnect::nsXPConnect()
     :   mRuntime(nullptr),
         mInterfaceInfoManager(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)),
         mDefaultSecurityManager(nullptr),
         mDefaultSecurityManagerFlags(0),
         mShuttingDown(false),
-        mEventDepth(0),
-        mCycleCollectionContext(nullptr)
+        mEventDepth(0)
 {
     mRuntime = XPCJSRuntime::newXPCJSRuntime(this);
 
     nsCycleCollector_registerJSRuntime(this);
 
     char* reportableEnv = PR_GetEnv("MOZ_REPORT_ALL_JS_EXCEPTIONS");
     if (reportableEnv && *reportableEnv)
         gReportAllJSExceptions = 1;
@@ -537,43 +536,28 @@ nsXPConnect::FixWeakMappingGrayBits()
 {
     FixWeakMappingGrayBitsTracer fixer(GetRuntime()->GetJSRuntime());
     fixer.FixAll();
 }
 
 nsresult
 nsXPConnect::BeginCycleCollection(nsCycleCollectionTraversalCallback &cb)
 {
-    // It is important not to call GetSafeJSContext while on the
-    // cycle-collector thread since this context will be destroyed
-    // asynchronously and race with the main thread. In particular, we must
-    // ensure that a context is passed to the XPCCallContext constructor.
-    JSContext *cx = mRuntime->GetJSCycleCollectionContext();
-    if (!cx)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    NS_ASSERTION(!mCycleCollectionContext, "Didn't call FinishTraverse?");
-    mCycleCollectionContext = new XPCCallContext(NATIVE_CALLER, cx);
-    if (!mCycleCollectionContext->IsValid()) {
-        mCycleCollectionContext = nullptr;
-        return NS_ERROR_FAILURE;
-    }
-
+    JSRuntime* rt = GetRuntime()->GetJSRuntime();
     static bool gcHasRun = false;
     if (!gcHasRun) {
-        JSRuntime* rt = GetRuntime()->GetJSRuntime();
         uint32_t gcNumber = JS_GetGCParameter(rt, JSGC_NUMBER);
         if (!gcNumber)
             NS_RUNTIMEABORT("Cannot cycle collect if GC has not run first!");
         gcHasRun = true;
     }
 
     GetRuntime()->AddXPConnectRoots(cb);
 
-    NoteWeakMapsTracer trc(GetRuntime()->GetJSRuntime(), TraceWeakMapping, cb);
+    NoteWeakMapsTracer trc(rt, TraceWeakMapping, cb);
     js::TraceWeakMaps(&trc);
 
     return NS_OK;
 }
 
 bool
 nsXPConnect::NotifyLeaveMainThread()
 {
@@ -601,24 +585,16 @@ nsXPConnect::NotifyLeaveCycleCollectionT
 
 void
 nsXPConnect::NotifyEnterMainThread()
 {
     NS_ABORT_IF_FALSE(NS_IsMainThread(), "Off main thread");
     JS_SetRuntimeThread(mRuntime->GetJSRuntime());
 }
 
-nsresult
-nsXPConnect::FinishTraverse()
-{
-    if (mCycleCollectionContext)
-        mCycleCollectionContext = nullptr;
-    return NS_OK;
-}
-
 class nsXPConnectParticipant: public nsCycleCollectionParticipant
 {
 public:
     static NS_METHOD RootImpl(void *n)
     {
         return NS_OK;
     }
     static NS_METHOD UnlinkImpl(void *n)
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -524,27 +524,21 @@ public:
     nsresult GetInfoForName(const char * name, nsIInterfaceInfo** info);
 
     // nsCycleCollectionJSRuntime
     virtual bool NotifyLeaveMainThread();
     virtual void NotifyEnterCycleCollectionThread();
     virtual void NotifyLeaveCycleCollectionThread();
     virtual void NotifyEnterMainThread();
     virtual nsresult BeginCycleCollection(nsCycleCollectionTraversalCallback &cb);
-    virtual nsresult FinishTraverse();
     virtual nsCycleCollectionParticipant *GetParticipant();
     virtual void FixWeakMappingGrayBits();
     virtual bool NeedCollect();
     virtual void Collect(uint32_t reason);
 
-    XPCCallContext *GetCycleCollectionContext()
-    {
-        return mCycleCollectionContext;
-    }
-
     // This returns the singleton nsCycleCollectionParticipant for JSContexts.
     static nsCycleCollectionParticipant *JSContextParticipant();
 
     virtual nsIPrincipal* GetPrincipal(JSObject* obj,
                                        bool allowShortCircuit) const;
 
     void RecordTraversal(void *p, nsISupports *s);
     virtual char* DebugPrintJSStack(bool showArgs,
@@ -577,17 +571,16 @@ private:
     JSBool                   mShuttingDown;
 
     // nsIThreadInternal doesn't remember which observers it called
     // OnProcessNextEvent on when it gets around to calling AfterProcessNextEvent.
     // So if XPConnect gets initialized mid-event (which can happen), we'll get
     // an 'after' notification without getting an 'on' notification. If we don't
     // watch out for this, we'll do an unmatched |pop| on the context stack.
     uint16_t                   mEventDepth;
-    nsAutoPtr<XPCCallContext> mCycleCollectionContext;
 
     nsCOMPtr<nsIXPCScriptable> mBackstagePass;
 
     static uint32_t gReportAllJSExceptions;
     static JSBool gDebugMode;
     static JSBool gDesiredDebugMode;
 
 public:
@@ -664,18 +657,16 @@ public:
     static XPCJSRuntime* Get() { return nsXPConnect::GetXPConnect()->GetRuntime(); }
 
     JSRuntime*     GetJSRuntime() const {return mJSRuntime;}
     nsXPConnect*   GetXPConnect() const {return mXPConnect;}
 
     XPCJSContextStack* GetJSContextStack() {return mJSContextStack;}
     void DestroyJSContextStack();
 
-    JSContext*     GetJSCycleCollectionContext();
-
     XPCCallContext*  GetCallContext() const {return mCallContext;}
     XPCCallContext*  SetCallContext(XPCCallContext* ccx)
         {XPCCallContext* old = mCallContext; mCallContext = ccx; return old;}
 
     jsid GetResolveName() const {return mResolveName;}
     jsid SetResolveName(jsid name)
         {jsid old = mResolveName; mResolveName = name; return old;}
 
@@ -936,17 +927,16 @@ private:
 
     static const char* mStrings[IDX_TOTAL_COUNT];
     jsid mStrIDs[IDX_TOTAL_COUNT];
     jsval mStrJSVals[IDX_TOTAL_COUNT];
 
     nsXPConnect*             mXPConnect;
     JSRuntime*               mJSRuntime;
     XPCJSContextStack*       mJSContextStack;
-    JSContext*               mJSCycleCollectionContext;
     XPCCallContext*          mCallContext;
     AutoMarkingPtr*          mAutoRoots;
     jsid                     mResolveName;
     XPCWrappedNative*        mResolvingWrapper;
     JSObject2WrappedJSMap*   mWrappedJSMap;
     IID2WrappedJSClassMap*   mWrappedJSClassMap;
     IID2NativeInterfaceMap*  mIID2NativeInterfaceMap;
     ClassInfo2NativeSetMap*  mClassInfo2NativeSetMap;
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -918,16 +918,17 @@ FrameLayerBuilder::RemoveFrameFromLayerM
     if (t) {
       ThebesDisplayItemLayerUserData* thebesData =
           static_cast<ThebesDisplayItemLayerUserData*>(t->GetUserData(&gThebesDisplayItemLayerUserData));
       if (thebesData) {
         nsRegion old = data->mGeometry->ComputeInvalidationRegion();
         nsIntRegion rgn = old.ScaleToOutsidePixels(thebesData->mXScale, thebesData->mYScale, thebesData->mAppUnitsPerDevPixel);
         rgn.MoveBy(-GetTranslationForThebesLayer(t));
         thebesData->mRegionToInvalidate.Or(thebesData->mRegionToInvalidate, rgn);
+        thebesData->mRegionToInvalidate.SimplifyOutward(8);
       }
     }
 
     data->mParent->mDisplayItems.RemoveEntry(data);
   }
 
   arrayCopy.Clear();
   delete array;
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -114,17 +114,17 @@
 #include "nsIScrollableFrame.h"
 
 #include "nsXBLService.h"
 
 #undef NOISY_FIRST_LETTER
 
 #include "nsMathMLParts.h"
 #include "nsIDOMSVGFilters.h"
-#include "DOMSVGTests.h"
+#include "mozilla/dom/SVGTests.h"
 #include "nsSVGEffects.h"
 #include "nsSVGTextFrame2.h"
 #include "nsSVGTextPathFrame.h"
 #include "nsSVGUtils.h"
 
 #include "nsRefreshDriver.h"
 #include "nsRuleProcessorData.h"
 #include "sampler.h"
@@ -4900,18 +4900,18 @@ nsCSSFrameConstructor::FindSVGData(Eleme
     // SVG frames assume that one exists.  We handle the non-rendering
     // of failing outer <svg> element contents like <switch> statements,
     // and do the PassesConditionalProcessingTests call in
     // nsSVGOuterSVGFrame::Init.
     static const FrameConstructionData sOuterSVGData =
       FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructOuterSVG);
     return &sOuterSVGData;
   }
-  
-  nsCOMPtr<DOMSVGTests> tests(do_QueryInterface(aElement));
+
+  nsCOMPtr<SVGTests> tests(do_QueryInterface(aElement));
   if (tests && !tests->PassesConditionalProcessingTests()) {
     // Elements with failing conditional processing attributes never get
     // rendered.  Note that this is not where we select which frame in a
     // <switch> to render!  That happens in nsSVGSwitchFrame::PaintSVG.
     return &sContainerData;
   }
 
   // Prevent bad frame types being children of filters or parents of filter
--- a/layout/base/nsCaret.cpp
+++ b/layout/base/nsCaret.cpp
@@ -30,16 +30,17 @@
 #include "nsCaret.h"
 #include "nsTextFrame.h"
 #include "nsXULPopupManager.h"
 #include "nsMenuPopupFrame.h"
 #include "nsTextFragment.h"
 #include "nsThemeConstants.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/LookAndFeel.h"
+#include "mozilla/Selection.h"
 #include <algorithm>
 
 // The bidi indicator hangs off the caret to one side, to show which
 // direction the typing is in. It needs to be at least 2x2 to avoid looking like 
 // an insignificant dot
 static const int32_t kMinBidiIndicatorPixels = 2;
 
 #ifdef IBMBIDI
@@ -1122,25 +1123,24 @@ void nsCaret::CaretBlinkCallback(nsITime
   nsCaret   *theCaret = reinterpret_cast<nsCaret*>(aClosure);
   if (!theCaret) return;
   
   theCaret->DrawCaret(true);
 }
 
 
 //-----------------------------------------------------------------------------
-already_AddRefed<nsFrameSelection>
+nsFrameSelection*
 nsCaret::GetFrameSelection()
 {
-  nsCOMPtr<nsISelectionPrivate> privateSelection(do_QueryReferent(mDomSelectionWeak));
-  if (!privateSelection)
+  nsCOMPtr<nsISelection> sel = do_QueryReferent(mDomSelectionWeak);
+  if (!sel)
     return nullptr;
-  nsFrameSelection* frameSelection = nullptr;
-  privateSelection->GetFrameSelection(&frameSelection);
-  return frameSelection;
+
+  return static_cast<Selection*>(sel.get())->GetFrameSelection();
 }
 
 void
 nsCaret::SetIgnoreUserModify(bool aIgnoreUserModify)
 {
   if (!aIgnoreUserModify && mIgnoreUserModify && mDrawn) {
     // We're turning off mIgnoreUserModify. If the caret's drawn
     // in a read-only node we must erase it, else the next call
--- a/layout/base/nsCaret.h
+++ b/layout/base/nsCaret.h
@@ -204,17 +204,17 @@ protected:
 #ifdef IBMBIDI
       return mHookRect;
 #else
       return nsRect();
 #endif
     }
     void          ToggleDrawnStatus() { mDrawn = !mDrawn; }
 
-    already_AddRefed<nsFrameSelection> GetFrameSelection();
+    nsFrameSelection* GetFrameSelection();
 
     // Returns true if we should not draw the caret because of XUL menu popups.
     // The caret should be hidden if:
     // 1. An open popup contains the caret, but a menu popup exists before the
     //    caret-owning popup in the popup list (i.e. a menu is in front of the
     //    popup with the caret). If the menu itself contains the caret we don't
     //    hide it.
     // 2. A menu popup is open, but there is no caret present in any popup.
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -4758,18 +4758,17 @@ PresShell::PaintRangePaintInfo(nsTArray<
   // translate so that points are relative to the surface area
   rc->Translate(-aArea.TopLeft());
 
   // temporarily hide the selection so that text is drawn normally. If a
   // selection is being rendered, use that, otherwise use the presshell's
   // selection.
   nsRefPtr<nsFrameSelection> frameSelection;
   if (aSelection) {
-    nsCOMPtr<nsISelectionPrivate> selpriv = do_QueryInterface(aSelection);
-    selpriv->GetFrameSelection(getter_AddRefs(frameSelection));
+    frameSelection = static_cast<Selection*>(aSelection)->GetFrameSelection();
   }
   else {
     frameSelection = FrameSelection();
   }
   int16_t oldDisplaySelection = frameSelection->GetDisplaySelection();
   frameSelection->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN);
 
   // next, paint each range in the selection
--- a/layout/base/tests/chrome/test_printpreview.xul
+++ b/layout/base/tests/chrome/test_printpreview.xul
@@ -14,23 +14,25 @@ if (navigator.platform.startsWith("Linux
   SimpleTest.expectAssertions(1); // bug 671976
 } else if (navigator.platform.startsWith("Win")) {
   // reliable 1 on Win7, but not on XP
   SimpleTest.expectAssertions(0, 1); // bug 671976
 }
 
 function parentFinish() {
   // This is called while the helper window is still open.  Call
-  // doFinish after it closes.
-  setTimeout(doFinish, 0);
+  // doGC after it closes.
+  setTimeout(doGC, 0);
 }
-function doFinish() {
+function doGC() {
   // Garbage collecting the windows created in this test can cause
   // assertions, so GC now to blame those assertions to this test.
   // ("Destroying a currently-showing document", bug 671976)
   SpecialPowers.gc();
-
+  setTimeout(doFinish, 0);
+}
+function doFinish() {
   SimpleTest.finish();
 }
 SimpleTest.waitForExplicitFinish();
 window.open("printpreview_helper.xul", "printpreview", "chrome,width=100,height=100");
 ]]></script>
 </window>
--- a/layout/base/tests/chrome/test_printpreview_bug396024.xul
+++ b/layout/base/tests/chrome/test_printpreview_bug396024.xul
@@ -20,23 +20,25 @@ if (navigator.platform.startsWith("Linux
   SimpleTest.expectAssertions(2); // bug 671976
 } else if (navigator.platform.startsWith("Win")) {
   // reliable 2 on Win7, but not on XP
   SimpleTest.expectAssertions(0, 2); // bug 671976
 }
 
 function parentFinish() {
   // This is called while the helper window is still open.  Call
-  // doFinish after it closes.
-  setTimeout(doFinish, 0);
+  // doGC after it closes.
+  setTimeout(doGC, 0);
 }
-function doFinish() {
+function doGC() {
   // Garbage collecting the windows created in this test can cause
   // assertions, so GC now to blame those assertions to this test.
   // ("Destroying a currently-showing document", bug 671976)
   SpecialPowers.gc();
-
+  setTimeout(doFinish, 0);
+}
+function doFinish() {
   SimpleTest.finish();
 }
 SimpleTest.waitForExplicitFinish();
 window.open("printpreview_bug396024_helper.xul", "bug396024", "chrome,width=100,height=100");
 ]]></script>
 </window>
--- a/layout/base/tests/chrome/test_printpreview_bug482976.xul
+++ b/layout/base/tests/chrome/test_printpreview_bug482976.xul
@@ -14,29 +14,30 @@ https://bugzilla.mozilla.org/show_bug.cg
    target="_blank">Mozilla Bug 482976</a>
 </body>
   <!-- test code goes here -->
 <script type="application/javascript">
 <![CDATA[
 if (navigator.platform.startsWith("Linux")) {
   SimpleTest.expectAssertions(1); // bug 671976
 } else if (navigator.platform.startsWith("Win")) {
-  // reliable 1 on Win7, but not on XP
-  SimpleTest.expectAssertions(0, 1); // bug 671976
+  SimpleTest.expectAssertions(0, 2); // bug 671976
 }
 
 SimpleTest.waitForExplicitFinish();
 function parentFinish() {
   // This is called while the helper window is still open.  Call
-  // doFinish after it closes.
-  setTimeout(doFinish, 0);
+  // doGC after it closes.
+  setTimeout(doGC, 0);
 }
-function doFinish() {
+function doGC() {
   // Garbage collecting the windows created in this test can cause
   // assertions, so GC now to blame those assertions to this test.
   // ("Destroying a currently-showing document", bug 671976)
   SpecialPowers.gc();
-
+  setTimeout(doFinish, 0);
+}
+function doFinish() {
   SimpleTest.finish();
 }
 window.open("printpreview_bug482976_helper.xul", "bug482976", "chrome,width=100,height=100");
 ]]></script>
 </window>
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -1069,44 +1069,36 @@ nsTextControlFrame::GetSelectionRange(in
   nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
   NS_ASSERTION(txtCtrl, "Content not a text control element");
   nsISelectionController* selCon = txtCtrl->GetSelectionController();
   NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
   nsCOMPtr<nsISelection> selection;
   rv = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));  
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
-  nsCOMPtr<nsISelectionPrivate> selPriv = do_QueryInterface(selection);
-  NS_ENSURE_TRUE(selPriv, NS_ERROR_FAILURE);
-  nsRefPtr<nsFrameSelection> frameSel;
-  rv = selPriv->GetFrameSelection(getter_AddRefs(frameSel));
-  NS_ENSURE_SUCCESS(rv, rv);
-  NS_ENSURE_TRUE(frameSel, NS_ERROR_FAILURE);
-  nsRefPtr<Selection> typedSel =
-    frameSel->GetSelection(nsISelectionController::SELECTION_NORMAL);
-  NS_ENSURE_TRUE(typedSel, NS_ERROR_FAILURE);
 
+  Selection* sel = static_cast<Selection*>(selection.get());
   if (aDirection) {
-    nsDirection direction = typedSel->GetSelectionDirection();
+    nsDirection direction = sel->GetSelectionDirection();
     if (direction == eDirNext) {
       *aDirection = eForward;
     } else if (direction == eDirPrevious) {
       *aDirection = eBackward;
     } else {
       NS_NOTREACHED("Invalid nsDirection enum value");
     }
   }
 
   if (!aSelectionStart || !aSelectionEnd) {
     return NS_OK;
   }
 
   mozilla::dom::Element* root = GetRootNodeAndInitializeEditor();
   NS_ENSURE_STATE(root);
-  nsContentUtils::GetSelectionInTextControl(typedSel, root,
+  nsContentUtils::GetSelectionInTextControl(sel, root,
                                             *aSelectionStart, *aSelectionEnd);
 
   return NS_OK;
 }
 
 /////END INTERFACE IMPLEMENTATIONS
 
 ////NSIFRAME
--- a/layout/forms/test/test_bug536567_perwindowpb.html
+++ b/layout/forms/test/test_bug536567_perwindowpb.html
@@ -10,16 +10,20 @@ https://bugzilla.mozilla.org/show_bug.cg
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=536567">Mozilla Bug 536567</a>
 <p id="display"></p>
 <pre id="test">
 <script type="application/javascript">
 
+if (navigator.platform.startsWith("Win")) {
+  SimpleTest.expectAssertions(0, 1); // bug 671976 assertions leak to this test on Windows
+}
+
 /** Test for Bug 536567 **/
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 const Cm = Components.manager;
 
 Cu.import("resource://gre/modules/Services.jsm");
--- a/layout/generic/Selection.h
+++ b/layout/generic/Selection.h
@@ -48,16 +48,17 @@ public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(Selection, nsISelectionPrivate)
   NS_DECL_NSISELECTION
   NS_DECL_NSISELECTIONPRIVATE
 
   // utility methods for scrolling the selection into view
   nsPresContext* GetPresContext() const;
   nsIPresShell* GetPresShell() const;
+  nsFrameSelection* GetFrameSelection() const { return mFrameSelection; }
   // Returns a rect containing the selection region, and frame that that
   // position is relative to. For SELECTION_ANCHOR_REGION or
   // SELECTION_FOCUS_REGION the rect is a zero-width rectangle. For
   // SELECTION_WHOLE_SELECTION the rect contains both the anchor and focus
   // region rects.
   nsIFrame*     GetSelectionAnchorGeometry(SelectionRegion aRegion, nsRect *aRect);
   // Returns the position of the region (SELECTION_ANCHOR_REGION or
   // SELECTION_FOCUS_REGION only), and frame that that position is relative to.
--- a/layout/generic/nsFrameSelection.h
+++ b/layout/generic/nsFrameSelection.h
@@ -2,16 +2,17 @@
  * 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/. */
 
 #ifndef nsFrameSelection_h___
 #define nsFrameSelection_h___
 
 #include "mozilla/Attributes.h"
 
+#include "mozilla/Selection.h"
 #include "nsIFrame.h"
 #include "nsIContent.h"
 #include "nsISelectionController.h"
 #include "nsITableCellLayout.h"
 #include "nsIDOMElement.h"
 #include "nsGUIEvent.h"
 #include "nsRange.h"
 
@@ -180,23 +181,23 @@ class Selection;
 class nsIScrollableFrame;
 
 /**
  * Methods which are marked with *unsafe* should be handled with special care.
  * They may cause nsFrameSelection to be deleted, if strong pointer isn't used,
  * or they may cause other objects to be deleted.
  */
 
-class nsFrameSelection MOZ_FINAL : public nsISupports {
+class nsFrameSelection MOZ_FINAL {
 public:
   enum HINT { HINTLEFT = 0, HINTRIGHT = 1};  //end of this line or beginning of next
   /*interfaces for addref and release and queryinterface*/
   
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_CLASS(nsFrameSelection)
+  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsFrameSelection)
+  NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsFrameSelection)
 
   /** Init will initialize the frame selector with the necessary pres shell to 
    *  be used by most of the methods
    *  @param aShell is the parameter to be used for most of the other calls for callbacks etc
    *  @param aLimiter limits the selection to nodes with aLimiter parents
    */
   void Init(nsIPresShell *aShell, nsIContent *aLimiter);
 
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -410,21 +410,18 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEndSelectedCell)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAppendStartSelectedCell)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUnselectCellOnMouseUp)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMaintainRange)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLimiter)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAncestorLimiter)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFrameSelection)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrameSelection)
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameSelection)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
+NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsFrameSelection, AddRef)
+NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsFrameSelection, Release)
 
 
 nsresult
 nsFrameSelection::FetchDesiredX(nscoord &aDesiredX) //the x position requested by the Key Handling for up down
 {
   if (!mShell)
   {
     NS_ERROR("fetch desired X failed");
@@ -4113,24 +4110,16 @@ Selection::GetCachedFrameOffset(nsIFrame
        mCachedOffsetForFrame->mLastContentOffset = inOffset; 
      }
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
-Selection::GetFrameSelection(nsFrameSelection** aFrameSelection) {
-  NS_ENSURE_ARG_POINTER(aFrameSelection);
-  *aFrameSelection = mFrameSelection;
-  NS_IF_ADDREF(*aFrameSelection);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 Selection::SetAncestorLimiter(nsIContent* aContent)
 {
   if (mFrameSelection)
     mFrameSelection->SetAncestorLimiter(aContent);
   return NS_OK;
 }
 
 RangeData*
--- a/layout/style/forms.css
+++ b/layout/style/forms.css
@@ -715,22 +715,24 @@ meter {
 :-moz-meter-sub-sub-optimum::-moz-meter-bar {
   /* red. */
   background: -moz-linear-gradient(top, #f77, #f77, #fcc 20%, #d44 45%, #d44 55%);
 }
 
 input[type="range"] {
   -moz-appearance: none;
   display: inline-block !important;
-  cursor: default;
   width: 12em;
   height: 1.3em;
+  margin: 0 0.7em;
+  /* Override some rules that apply on all input types: */
+  cursor: default;
   background: none;
   border: none;
-  margin: 0 0.7em;
+  -moz-binding: none; /* we don't want any of platformHTMLBindings.xml#inputFields */
 }
 
 /**
  * Layout handles positioning of this pseudo-element specially (so that content
  * authors can concentrate on styling the thumb without worrying about the
  * logic to position it). Specifically the 'margin', 'top' and 'left'
  * properties are ignored.
  *
new file mode 100644
--- /dev/null
+++ b/layout/svg/crashtests/843072-1.svg
@@ -0,0 +1,11 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+  <defs>
+    <text id="t"></text>
+  </defs>
+
+  <script>
+    window.addEventListener("load", function() {
+      document.getElementById("t").getExtentOfChar(0);
+    }, false);
+  </script>
+</svg>
--- a/layout/svg/crashtests/crashtests.list
+++ b/layout/svg/crashtests/crashtests.list
@@ -149,8 +149,9 @@ load 788831-1.svg
 load 790072.svg
 load 791826-1.svg
 load 789390-1.html
 load 808318-1.svg
 load 813420-1.svg
 load 841163-1.svg
 load 841812-1.svg
 load 842009-1.svg
+load 843072-1.svg
--- a/layout/svg/nsSVGOuterSVGFrame.cpp
+++ b/layout/svg/nsSVGOuterSVGFrame.cpp
@@ -2,17 +2,16 @@
 /* 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/. */
 
 // Main header first:
 #include "nsSVGOuterSVGFrame.h"
 
 // Keep others in (case-insensitive) order:
-#include "DOMSVGTests.h"
 #include "gfxMatrix.h"
 #include "nsDisplayList.h"
 #include "nsIDocument.h"
 #include "nsIDOMWindow.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIObjectLoadingContent.h"
 #include "nsRenderingContext.h"
 #include "nsStubMutationObserver.h"
--- a/layout/svg/nsSVGTextFrame2.cpp
+++ b/layout/svg/nsSVGTextFrame2.cpp
@@ -3650,17 +3650,18 @@ nsSVGTextFrame2::GetSubStringLength(nsIC
     return 0.0f;
   }
 
   // Convert charnum/nchars from addressable characters relative to
   // aContent to global character indices.
   CharIterator chit(this, CharIterator::eAddressable, aContent);
   if (!chit.AdvanceToSubtree() ||
       !chit.Next(charnum) ||
-      chit.IsAfterSubtree()) {
+      chit.IsAfterSubtree() ||
+      chit.AtEnd()) {
     return 0.0f;
   }
   charnum = chit.TextElementCharIndex();
   chit.NextWithinSubtree(nchars);
   nchars = chit.TextElementCharIndex() - charnum;
 
   // Find each rendered run that intersects with the range defined
   // by charnum/nchars.
@@ -3749,17 +3750,18 @@ nsresult
 nsSVGTextFrame2::GetStartPositionOfChar(nsIContent* aContent,
                                         uint32_t aCharNum,
                                         mozilla::nsISVGPoint** aResult)
 {
   UpdateGlyphPositioning(false);
 
   CharIterator it(this, CharIterator::eAddressable, aContent);
   if (!it.AdvanceToSubtree() ||
-      !it.Next(aCharNum)) {
+      !it.Next(aCharNum) ||
+      it.AtEnd()) {
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   }
 
   // We need to return the start position of the whole glyph.
   uint32_t startIndex = it.GlyphStartTextElementCharIndex();
 
   NS_ADDREF(*aResult = new DOMSVGPoint(mPositions[startIndex].mPosition));
   return NS_OK;
@@ -3773,17 +3775,18 @@ nsresult
 nsSVGTextFrame2::GetEndPositionOfChar(nsIContent* aContent,
                                       uint32_t aCharNum,
                                       mozilla::nsISVGPoint** aResult)
 {
   UpdateGlyphPositioning(false);
 
   CharIterator it(this, CharIterator::eAddressable, aContent);
   if (!it.AdvanceToSubtree() ||
-      !it.Next(aCharNum)) {
+      !it.Next(aCharNum) ||
+      it.AtEnd()) {
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   }
 
   // We need to return the end position of the whole glyph.
   uint32_t startIndex = it.GlyphStartTextElementCharIndex();
 
   // Get the advance of the glyph.
   gfxFloat advance = it.GetGlyphAdvance(PresContext());
@@ -3810,17 +3813,18 @@ nsresult
 nsSVGTextFrame2::GetExtentOfChar(nsIContent* aContent,
                                  uint32_t aCharNum,
                                  nsIDOMSVGRect** aResult)
 {
   UpdateGlyphPositioning(false);
 
   CharIterator it(this, CharIterator::eAddressable, aContent);
   if (!it.AdvanceToSubtree() ||
-      !it.Next(aCharNum)) {
+      !it.Next(aCharNum) ||
+      it.AtEnd()) {
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   }
 
   nsPresContext* presContext = PresContext();
 
   float cssPxPerDevPx = presContext->
     AppUnitsToFloatCSSPixels(presContext->AppUnitsPerDevPixel());
 
@@ -3861,17 +3865,18 @@ nsresult
 nsSVGTextFrame2::GetRotationOfChar(nsIContent* aContent,
                                    uint32_t aCharNum,
                                    float* aResult)
 {
   UpdateGlyphPositioning(false);
 
   CharIterator it(this, CharIterator::eAddressable, aContent);
   if (!it.AdvanceToSubtree() ||
-      !it.Next(aCharNum)) {
+      !it.Next(aCharNum) ||
+      it.AtEnd()) {
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   }
 
   *aResult = mPositions[it.TextElementCharIndex()].mAngle * 180.0 / M_PI;
   return NS_OK;
 }
 
 //----------------------------------------------------------------------
--- a/mach
+++ b/mach
@@ -1,66 +1,51 @@
 #!/usr/bin/env python
 # 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/.
 
 from __future__ import print_function, unicode_literals
 
 import os
-import platform
 import sys
 
-# Ensure we are running Python 2.7+. We put this check here so we generate a
-# user-friendly error message rather than a cryptic stack trace on module
-# import.
-if sys.version_info[0] != 2 or sys.version_info[1] < 7:
-    print('Python 2.7 or above (but not Python 3) is required to run mach.')
-    print('You are running Python', platform.python_version())
-    sys.exit(1)
+def ancestors(path):
+    while path:
+        yield path
+        (path, child) = os.path.split(path)
+        if child == "":
+            break
 
-# TODO Bug 794506 Integrate with the in-tree virtualenv configuration.
-SEARCH_PATHS = [
-    'python/mach',
-    'python/mozboot',
-    'python/mozbuild',
-    'build',
-    'build/pymake',
-    'python/blessings',
-    'python/psutil',
-    'python/which',
-    'other-licenses/ply',
-    'xpcom/idl-parser',
-    'testing',
-    'testing/xpcshell',
-    'testing/mozbase/mozprocess',
-    'testing/mozbase/mozfile',
-    'testing/mozbase/mozinfo',
-]
+def load_mach(topsrcdir):
+    sys.path[0:0] = [os.path.join(topsrcdir, "build")]
+    import mach_bootstrap
+    return mach_bootstrap.bootstrap(topsrcdir)
 
-# Individual files providing mach commands.
-MACH_MODULES = [
-    'addon-sdk/mach_commands.py',
-    'layout/tools/reftest/mach_commands.py',
-    'python/mozboot/mozboot/mach_commands.py',
-    'python/mozbuild/mozbuild/config.py',
-    'python/mozbuild/mozbuild/mach_commands.py',
-    'python/mozbuild/mozbuild/frontend/mach_commands.py',
-    'testing/mochitest/mach_commands.py',
-    'testing/xpcshell/mach_commands.py',
-]
-
-our_dir = os.path.dirname(os.path.abspath(__file__))
+# Check whether the current directory is within a mach src or obj dir.
+for dir_path in ancestors(os.getcwd()):
+    # If we find a "mozinfo.json" file, we are in the objdir.
+    mozinfo_path = os.path.join(dir_path, "mozinfo.json")
+    if os.path.isfile(mozinfo_path):
+        import json
+        info = json.load(open(mozinfo_path))
+        if "mozconfig" in info and "MOZCONFIG" not in os.environ:
+            # If the MOZCONFIG environment variable is not already set, set it
+            # to the value from mozinfo.json.  This will tell the build system
+            # to look for a config file at the path in $MOZCONFIG rather than
+            # its default locations.
+            #
+            # Note: subprocess requires native strings in os.environ Python
+            # 2.7.2 and earlier on Windows.
+            os.environ[b"MOZCONFIG"] = str(info["mozconfig"])
 
-try:
-    import mach.main
-except ImportError:
-    sys.path[0:0] = [os.path.join(our_dir, path) for path in SEARCH_PATHS]
-
-    import mach.main
+        if "topsrcdir" in info:
+            # Continue searching for mach_bootstrap in the source directory.
+            dir_path = info["topsrcdir"]
 
-# All of the code is in a module because EVERYTHING IS A LIBRARY.
-mach = mach.main.Mach(our_dir)
+    # If we find the mach bootstrap module, we are in the srcdir.
+    mach_path = os.path.join(dir_path, "build/mach_bootstrap.py")
+    if os.path.isfile(mach_path):
+        mach = load_mach(dir_path)
+        sys.exit(mach.run(sys.argv[1:]))
 
-for path in MACH_MODULES:
-    mach.load_commands_from_file(os.path.join(our_dir, path))
-
-sys.exit(mach.run(sys.argv[1:]))
+print("Could not run mach: No mach source directory found")
+sys.exit(1)
--- a/media/mtransport/third_party/nrappkit/src/log/r_log.c
+++ b/media/mtransport/third_party/nrappkit/src/log/r_log.c
@@ -85,18 +85,16 @@ static char *log_level_reg_strings[]={
      "info",
      "debug"
 };
 
 #define LOGGING_REG_PREFIX "logging"
 
 #define MAX_ERROR_STRING_SIZE   512
 
-static char log_fmt_buf[MAX_ERROR_STRING_SIZE];
-
 #define R_LOG_INITTED1   1
 #define R_LOG_INITTED2   2
 
 #define LOG_NUM_DESTINATIONS 3
 
 typedef struct log_type_ {
      char *facility_name;
      int level[LOG_NUM_DESTINATIONS];
@@ -328,16 +326,17 @@ int r_dump(int facility,int level,char *
       r_log(facility,level,"%s",hex);
 
     RFREE(hex);
     return(0);
   }
 
 int r_vlog(int facility,int level,const char *format,va_list ap)
   {
+    char log_fmt_buf[MAX_ERROR_STRING_SIZE];
     char *level_str="unknown";
     char *facility_str="unknown";
     char *fmt_str=(char *)format;
     int i;
 
     if(r_log_env_verbose){
       if((level>=LOG_EMERG) && (level<=LOG_DEBUG))
         level_str=log_level_strings[level];
@@ -400,16 +399,17 @@ int r_log_e(int facility,int level,const
     r_vlog_e(facility,level,format,ap);
     va_end(ap);
 
     return(0);
   }
 
 int r_vlog_e(int facility,int level,const char *format,va_list ap)
   {
+    char log_fmt_buf[MAX_ERROR_STRING_SIZE];
     if(r_logging(facility,level)) {
       int formatlen = strlen(format);
 
       if(formatlen+2 > MAX_ERROR_STRING_SIZE)
         return(1);
 
       strncpy(log_fmt_buf, format, formatlen);
       strcpy(&log_fmt_buf[formatlen], ": ");
@@ -434,16 +434,17 @@ int r_log_nr(int facility,int level,int 
     r_vlog_nr(facility,level,r,format,ap);
     va_end(ap);
 
     return(0);
   }
 
 int r_vlog_nr(int facility,int level,int r,const char *format,va_list ap)
   {
+    char log_fmt_buf[MAX_ERROR_STRING_SIZE];
     if(r_logging(facility,level)) {
       int formatlen = strlen(format);
 
       if(formatlen+2 > MAX_ERROR_STRING_SIZE)
         return(1);
       strncpy(log_fmt_buf, format, formatlen);
       strcpy(&log_fmt_buf[formatlen], ": ");
       snprintf(&log_fmt_buf[formatlen+2], MAX_ERROR_STRING_SIZE - formatlen - 2, "%s",
--- a/mobile/android/base/AwesomeBarTabs.java
+++ b/mobile/android/base/AwesomeBarTabs.java
@@ -229,25 +229,24 @@ public class AwesomeBarTabs extends TabH
                 if (i == selIndex)
                     view.resetTheme();
                 else if (mActivity.getLightweightTheme().isEnabled())
                     view.setTheme(mActivity.getLightweightTheme().isLightTheme());
                 else
                     view.resetTheme();
             }
 
-            if (i == selIndex)
-                continue;
-
-            if (i == (selIndex - 1))
+            if (i < (selIndex - 1))
+                view.getBackground().setLevel(3);
+            else if (i == (selIndex - 1))
                 view.getBackground().setLevel(1);
             else if (i == (selIndex + 1))
                 view.getBackground().setLevel(2);
-            else
-                view.getBackground().setLevel(0);
+            else if (i > (selIndex + 1))
+                view.getBackground().setLevel(4);
         }
 
         if (selIndex == 0)
             findViewById(R.id.tab_widget_left).getBackground().setLevel(1);
         else
             findViewById(R.id.tab_widget_left).getBackground().setLevel(0);
 
         if (selIndex == (tabWidget.getTabCount() - 1))
--- a/mobile/android/base/BrowserToolbar.java
+++ b/mobile/android/base/BrowserToolbar.java
@@ -277,18 +277,23 @@ public class BrowserToolbar implements V
             }
         });
 
         mReader = (ImageButton) mLayout.findViewById(R.id.reader);
         mReader.setOnClickListener(new Button.OnClickListener() {
             @Override
             public void onClick(View view) {
                 Tab tab = Tabs.getInstance().getSelectedTab();
-                if (tab != null)
-                    tab.readerMode();
+                if (tab != null) {
+                    if (ReaderModeUtils.isAboutReader(tab.getURL())) {
+                        tab.doBack();
+                    } else {
+                        tab.readerMode();
+                    }
+                }
             }
         });
 
         mShadow = (ImageView) mLayout.findViewById(R.id.shadow);
 
         mHandler = new Handler();
         mSlideUpIn = new TranslateAnimation(0, 0, 40, 0);
         mSlideUpOut = new TranslateAnimation(0, 0, 0, -40);
@@ -933,22 +938,31 @@ public class BrowserToolbar implements V
     }
 
     public void setPageActionVisibility(boolean isLoading) {
         // Handle the loading mode page actions
         mStop.setVisibility(isLoading ? View.VISIBLE : View.GONE);
 
         // Handle the viewing mode page actions
         setSiteSecurityVisibility(mShowSiteSecurity && !isLoading);
-        mReader.setVisibility(mShowReader && !isLoading ? View.VISIBLE : View.GONE);
+
+        // Handle the readerMode image and visibility: We show the reader mode button if 1) you can
+        // enter reader mode for current page or 2) if you're already in reader mode and can exit back,
+        // in which case we show the reader mode "close" (reader_active) icon.
+        boolean exitableReaderMode = false;
+        Tab tab = Tabs.getInstance().getSelectedTab();
+        if (tab != null)
+            exitableReaderMode = ReaderModeUtils.isAboutReader(tab.getURL()) && tab.canDoBack();
+        mReader.setImageResource(exitableReaderMode ? R.drawable.reader_active : R.drawable.reader);
+        mReader.setVisibility(!isLoading && (mShowReader || exitableReaderMode) ? View.VISIBLE : View.GONE);
 
         // We want title to fill the whole space available for it when there are icons
         // being shown on the right side of the toolbar as the icons already have some
         // padding in them. This is just to avoid wasting space when icons are shown.
-        mTitle.setPadding(0, 0, (!mShowReader && !isLoading ? mTitlePadding : 0), 0);
+        mTitle.setPadding(0, 0, (!isLoading && !(mShowReader || exitableReaderMode) ? mTitlePadding : 0), 0);
 
         updateFocusOrder();
     }
 
     private void setSiteSecurityVisibility(final boolean visible) {
         if (visible == mSiteSecurityVisible)
             return;
 
--- a/mobile/android/base/FormAssistPopup.java
+++ b/mobile/android/base/FormAssistPopup.java
@@ -1,16 +1,17 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.gfx.FloatSize;
+import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
 import org.mozilla.gecko.util.GeckoEventListener;
 
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import android.content.Context;
 import android.content.res.Resources;
@@ -46,17 +47,17 @@ public class FormAssistPopup extends Rel
 
     private static int sAutoCompleteMinWidth = 0;
     private static int sAutoCompleteRowHeight = 0;
     private static int sValidationMessageHeight = 0;
     private static int sValidationTextMarginTop = 0;
     private static RelativeLayout.LayoutParams sValidationTextLayoutNormal;
     private static RelativeLayout.LayoutParams sValidationTextLayoutInverted;
 
-    private static final String LOGTAG = "FormAssistPopup";
+    private static final String LOGTAG = "GeckoFormAssistPopup";
 
     // The blocklist is so short that ArrayList is probably cheaper than HashSet.
     private static final Collection<String> sInputMethodBlocklist = Arrays.asList(new String[] {
                                             InputMethods.METHOD_GOOGLE_JAPANESE_INPUT, // bug 775850
                                             InputMethods.METHOD_OPENWNN_PLUS,          // bug 768108
                                             InputMethods.METHOD_SIMEJI,                // bug 768108
                                             InputMethods.METHOD_SWYPE,                 // bug 755909
                                             InputMethods.METHOD_SWYPE_BETA,            // bug 755909
@@ -94,48 +95,46 @@ public class FormAssistPopup extends Rel
             }
         } catch (Exception e) {
             Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
         }
     }
 
     private void handleAutoCompleteMessage(JSONObject message) throws JSONException  {
         final JSONArray suggestions = message.getJSONArray("suggestions");
-        final JSONArray rect = message.getJSONArray("rect");
-        final double zoom = message.getDouble("zoom");
+        final JSONObject rect = message.getJSONObject("rect");
         GeckoApp.mAppContext.mMainHandler.post(new Runnable() {
             @Override
             public void run() {
-                showAutoCompleteSuggestions(suggestions, rect, zoom);
+                showAutoCompleteSuggestions(suggestions, rect);
             }
         });
     }
 
     private void handleValidationMessage(JSONObject message) throws JSONException {
         final String validationMessage = message.getString("validationMessage");
-        final JSONArray rect = message.getJSONArray("rect");
-        final double zoom = message.getDouble("zoom");
+        final JSONObject rect = message.getJSONObject("rect");
         GeckoApp.mAppContext.mMainHandler.post(new Runnable() {
             @Override
             public void run() {
-                showValidationMessage(validationMessage, rect, zoom);
+                showValidationMessage(validationMessage, rect);
             }
         });
     }
     
     private void handleHideMessage(JSONObject message) {
         GeckoApp.mAppContext.mMainHandler.post(new Runnable() {
             @Override
             public void run() {
                 hide();
             }
         });
     }
 
-    private void showAutoCompleteSuggestions(JSONArray suggestions, JSONArray rect, double zoom) {
+    private void showAutoCompleteSuggestions(JSONArray suggestions, JSONObject rect) {
         if (mAutoCompleteList == null) {
             LayoutInflater inflater = LayoutInflater.from(mContext);
             mAutoCompleteList = (ListView) inflater.inflate(R.layout.autocomplete_list, null);
 
             mAutoCompleteList.setOnItemClickListener(new OnItemClickListener() {
                 @Override
                 public void onItemClick(AdapterView<?> parentView, View view, int position, long id) {
                     // Use the value stored with the autocomplete view, not the label text,
@@ -149,20 +148,20 @@ public class FormAssistPopup extends Rel
 
             addView(mAutoCompleteList);
         }
         
         AutoCompleteListAdapter adapter = new AutoCompleteListAdapter(mContext, R.layout.autocomplete_list_item);
         adapter.populateSuggestionsList(suggestions);
         mAutoCompleteList.setAdapter(adapter);
 
-        positionAndShowPopup(rect, zoom, true);
+        positionAndShowPopup(rect, true);
     }
 
-    private void showValidationMessage(String validationMessage, JSONArray rect, double zoom) {
+    private void showValidationMessage(String validationMessage, JSONObject rect) {
         if (mValidationMessage == null) {
             LayoutInflater inflater = LayoutInflater.from(mContext);
             mValidationMessage = (RelativeLayout) inflater.inflate(R.layout.validation_message, null);
 
             addView(mValidationMessage);
             mValidationMessageText = (TextView) mValidationMessage.findViewById(R.id.validation_message_text);
 
             sValidationTextMarginTop = (int) (mContext.getResources().getDimension(R.dimen.validation_message_margin_top));
@@ -177,63 +176,64 @@ public class FormAssistPopup extends Rel
             mValidationMessageArrowInverted = (ImageView) mValidationMessage.findViewById(R.id.validation_message_arrow_inverted);
         }
 
         mValidationMessageText.setText(validationMessage);
 
         // We need to set the text as selected for the marquee text to work.
         mValidationMessageText.setSelected(true);
 
-        positionAndShowPopup(rect, zoom, false);
+        positionAndShowPopup(rect, false);
     }
 
-    // Returns true if the popup is successfully shown, false otherwise
-    private boolean positionAndShowPopup(JSONArray rect, double zoom, boolean isAutoComplete) {
+    private void positionAndShowPopup(JSONObject rect, boolean isAutoComplete) {
         // Don't show the form assist popup when using fullscreen VKB
         InputMethodManager imm =
                 (InputMethodManager) GeckoApp.mAppContext.getSystemService(Context.INPUT_METHOD_SERVICE);
         if (imm.isFullscreenMode())
-            return false;
-
-        if (!isShown()) {
-            setVisibility(VISIBLE);
-            startAnimation(mAnimation);
-        }
+            return;
 
         // Hide/show the appropriate popup contents
         if (mAutoCompleteList != null)
             mAutoCompleteList.setVisibility(isAutoComplete ? VISIBLE : GONE);
         if (mValidationMessage != null)
             mValidationMessage.setVisibility(isAutoComplete ? GONE : VISIBLE);
 
         if (sAutoCompleteMinWidth == 0) {
             Resources res = mContext.getResources();
             sAutoCompleteMinWidth = (int) (res.getDimension(R.dimen.autocomplete_min_width));
             sAutoCompleteRowHeight = (int) (res.getDimension(R.dimen.autocomplete_row_height));
             sValidationMessageHeight = (int) (res.getDimension(R.dimen.validation_message_height));
         }
 
+        ImmutableViewportMetrics viewportMetrics = GeckoApp.mAppContext.getLayerView().getViewportMetrics();
+        float zoom = viewportMetrics.zoomFactor;
+
         // These values correspond to the input box for which we want to
         // display the FormAssistPopup.
         int left = 0;
         int top = 0; 
         int width = 0;
         int height = 0;
 
         try {
-            left = (int) (rect.getDouble(0) * zoom);
-            top = (int) (rect.getDouble(1) * zoom);
-            width = (int) (rect.getDouble(2) * zoom);
-            height = (int) (rect.getDouble(3) * zoom);
-        } catch (JSONException e) { } 
+            left = (int) (rect.getDouble("x") * zoom - viewportMetrics.viewportRectLeft);
+            top = (int) (rect.getDouble("y") * zoom - viewportMetrics.viewportRectTop);
+            width = (int) (rect.getDouble("w") * zoom);
+            height = (int) (rect.getDouble("h") * zoom);
+        } catch (JSONException e) {
+            // Bail if we can't get the correct dimensions for the popup.
+            Log.e(LOGTAG, "Error getting FormAssistPopup dimensions", e);
+            return;
+        }
 
         int popupWidth = RelativeLayout.LayoutParams.FILL_PARENT;
         int popupLeft = left < 0 ? 0 : left;
 
-        FloatSize viewport = GeckoApp.mAppContext.getLayerView().getViewportMetrics().getSize();
+        FloatSize viewport = viewportMetrics.getSize();
 
         // For autocomplete suggestions, if the input is smaller than the screen-width,
         // shrink the popup's width. Otherwise, keep it as FILL_PARENT.
         if (isAutoComplete && (left + width) < viewport.width) {
             popupWidth = left < 0 ? left + width : width;
 
             // Ensure the popup has a minimum width.
             if (popupWidth < sAutoCompleteMinWidth) {
@@ -285,17 +285,20 @@ public class FormAssistPopup extends Rel
         }
 
         RelativeLayout.LayoutParams layoutParams =
                 new RelativeLayout.LayoutParams(popupWidth, popupHeight);
         layoutParams.setMargins(popupLeft, popupTop, 0, 0);
         setLayoutParams(layoutParams);
         requestLayout();
 
-        return true;
+        if (!isShown()) {
+            setVisibility(VISIBLE);
+            startAnimation(mAnimation);
+        }
     }
 
     public void hide() {
         if (isShown()) {
             setVisibility(GONE);
             broadcastGeckoEvent("FormAssist:Hidden", null);
         }
     }
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -500,16 +500,20 @@ RES_VALUES_XLARGE_V11 = \
   res/values-xlarge-v11/integers.xml \
   res/values-xlarge-v11/styles.xml \
   $(NULL)
 
 RES_VALUES_LAND_V14 = \
   res/values-land-v14/dimens.xml \
   $(NULL)
 
+RES_VALUES_V14 = \
+  res/values-v14/styles.xml \
+  $(NULL)
+
 RES_XML = \
         res/xml/gecko_appwidget_info.xml \
 	$(SYNC_RES_XML) \
 	$(NULL)
 
 RES_ANIM = \
   res/anim/awesomebar_fade_in.xml \
   res/anim/awesomebar_fade_out.xml \
@@ -537,16 +541,18 @@ RES_DRAWABLE_MDPI = \
   res/drawable-mdpi/alert_addon.png \
   res/drawable-mdpi/alert_app.png \
   res/drawable-mdpi/alert_download.png \
   res/drawable-mdpi/appwidget_bg.9.png \
   res/drawable-mdpi/autocomplete_list_bg.9.png \
   res/drawable-mdpi/awesomebar_tab_center.9.png \
   res/drawable-mdpi/awesomebar_tab_left.9.png \
   res/drawable-mdpi/awesomebar_tab_right.9.png \
+  res/drawable-mdpi/awesomebar_sep_left.9.png \
+  res/drawable-mdpi/awesomebar_sep_right.9.png \
   res/drawable-mdpi/desktop_notification.png \
   res/drawable-mdpi/ic_addons_empty.png \
   res/drawable-mdpi/ic_awesomebar_go.png \
   res/drawable-mdpi/ic_awesomebar_reader.png \
   res/drawable-mdpi/ic_awesomebar_search.png \
   res/drawable-mdpi/ic_awesomebar_star.png \
   res/drawable-mdpi/ic_menu_addons_filler.png \
   res/drawable-mdpi/ic_menu_bookmark_add.png \
@@ -605,16 +611,17 @@ RES_DRAWABLE_MDPI = \
   res/drawable-mdpi/menu_item_uncheck.png \
   res/drawable-mdpi/site_security_identified.png \
   res/drawable-mdpi/site_security_verified.png \
   res/drawable-mdpi/tabs_normal.png \
   res/drawable-mdpi/tabs_private.png \
   res/drawable-mdpi/tabs_synced.png \
   res/drawable-mdpi/urlbar_stop.png \
   res/drawable-mdpi/reader.png \
+  res/drawable-mdpi/reader_active.png \
   res/drawable-mdpi/reading_list.png \
   res/drawable-mdpi/validation_arrow.png \
   res/drawable-mdpi/validation_arrow_inverted.png \
   res/drawable-mdpi/validation_bg.9.png \
   res/drawable-mdpi/bookmarkdefaults_favicon_support.png \
   res/drawable-mdpi/bookmarkdefaults_favicon_addons.png \
   res/drawable-mdpi/handle_end.png \
   res/drawable-mdpi/handle_middle.png \
@@ -649,16 +656,18 @@ RES_DRAWABLE_HDPI = \
   res/drawable-hdpi/address_bar_bg_shadow.png \
   res/drawable-hdpi/alert_addon.png \
   res/drawable-hdpi/alert_app.png \
   res/drawable-hdpi/alert_download.png \
   res/drawable-hdpi/appwidget_bg.9.png \
   res/drawable-hdpi/awesomebar_tab_center.9.png \
   res/drawable-hdpi/awesomebar_tab_left.9.png \
   res/drawable-hdpi/awesomebar_tab_right.9.png \
+  res/drawable-hdpi/awesomebar_sep_left.9.png \
+  res/drawable-hdpi/awesomebar_sep_right.9.png \
   res/drawable-hdpi/ic_addons_empty.png \
   res/drawable-hdpi/ic_awesomebar_go.png \
   res/drawable-hdpi/ic_awesomebar_reader.png \
   res/drawable-hdpi/ic_awesomebar_search.png \
   res/drawable-hdpi/ic_awesomebar_star.png \
   res/drawable-hdpi/ic_menu_addons_filler.png \
   res/drawable-hdpi/ic_menu_bookmark_add.png \
   res/drawable-hdpi/ic_menu_bookmark_remove.png \
@@ -704,16 +713,17 @@ RES_DRAWABLE_HDPI = \
   res/drawable-hdpi/menu_item_uncheck.png \
   res/drawable-hdpi/site_security_identified.png \
   res/drawable-hdpi/site_security_verified.png \
   res/drawable-hdpi/tabs_normal.png \
   res/drawable-hdpi/tabs_private.png \
   res/drawable-hdpi/tabs_synced.png \
   res/drawable-hdpi/urlbar_stop.png \
   res/drawable-hdpi/reader.png \
+  res/drawable-hdpi/reader_active.png \
   res/drawable-hdpi/reading_list.png \
   res/drawable-hdpi/validation_arrow.png \
   res/drawable-hdpi/validation_arrow_inverted.png \
   res/drawable-hdpi/validation_bg.9.png \
   res/drawable-hdpi/handle_end.png \
   res/drawable-hdpi/handle_middle.png \
   res/drawable-hdpi/handle_start.png \
   $(addprefix res/drawable-hdpi/,$(notdir $(SYNC_RES_DRAWABLE_HDPI))) \
@@ -740,16 +750,18 @@ RES_DRAWABLE_XHDPI = \
   res/drawable-xhdpi/address_bar_url_pressed_pb.9.png \
   res/drawable-xhdpi/alert_addon.png \
   res/drawable-xhdpi/alert_app.png \
   res/drawable-xhdpi/alert_download.png \
   res/drawable-xhdpi/appwidget_bg.9.png \
   res/drawable-xhdpi/awesomebar_tab_center.9.png \
   res/drawable-xhdpi/awesomebar_tab_left.9.png \
   res/drawable-xhdpi/awesomebar_tab_right.9.png \
+  res/drawable-xhdpi/awesomebar_sep_left.9.png \
+  res/drawable-xhdpi/awesomebar_sep_right.9.png \
   res/drawable-xhdpi/ic_addons_empty.png \
   res/drawable-xhdpi/ic_awesomebar_go.png \
   res/drawable-xhdpi/ic_awesomebar_reader.png \
   res/drawable-xhdpi/ic_awesomebar_search.png \
   res/drawable-xhdpi/ic_awesomebar_star.png \
   res/drawable-xhdpi/ic_menu_addons_filler.png \
   res/drawable-xhdpi/ic_menu_bookmark_add.png \
   res/drawable-xhdpi/ic_menu_bookmark_remove.png \
@@ -772,16 +784,17 @@ RES_DRAWABLE_XHDPI = \
   res/drawable-xhdpi/doorhanger_bg.9.png \
   res/drawable-xhdpi/doorhanger_shadow_bg.9.png \
   res/drawable-xhdpi/doorhanger_popup_bg.9.png \
   res/drawable-xhdpi/find_close.png \
   res/drawable-xhdpi/find_next.png \
   res/drawable-xhdpi/find_prev.png \
   res/drawable-xhdpi/urlbar_stop.png \
   res/drawable-xhdpi/reader.png \
+  res/drawable-xhdpi/reader_active.png \
   res/drawable-xhdpi/reading_list.png \
   res/drawable-xhdpi/larry_blue.png \
   res/drawable-xhdpi/larry_green.png \
   res/drawable-xhdpi/menu.png \
   res/drawable-xhdpi/menu_pb.png \
   res/drawable-xhdpi/menu_panel_bg.9.png \
   res/drawable-xhdpi/menu_popup_bg.9.png \
   res/drawable-xhdpi/menu_popup_arrow_bottom.png \
@@ -923,32 +936,38 @@ RES_DRAWABLE_LARGE_XHDPI_V11 = \
   res/drawable-large-xhdpi-v11/tabs_carat_contracted.png \
   res/drawable-large-xhdpi-v11/tabs_carat_expanded.png \
   $(NULL)
 
 RES_DRAWABLE_XLARGE_MDPI_V11 = \
   res/drawable-xlarge-mdpi-v11/awesomebar_tab_center.9.png \
   res/drawable-xlarge-mdpi-v11/awesomebar_tab_left.9.png \
   res/drawable-xlarge-mdpi-v11/awesomebar_tab_right.9.png \
+  res/drawable-xlarge-mdpi-v11/awesomebar_sep_left.9.png \
+  res/drawable-xlarge-mdpi-v11/awesomebar_sep_right.9.png \
   res/drawable-xlarge-mdpi-v11/ic_menu_bookmark_add.png \
   res/drawable-xlarge-mdpi-v11/ic_menu_bookmark_remove.png \
   $(NULL)
 
 RES_DRAWABLE_XLARGE_HDPI_V11 = \
   res/drawable-xlarge-hdpi-v11/awesomebar_tab_center.9.png \
   res/drawable-xlarge-hdpi-v11/awesomebar_tab_left.9.png \
   res/drawable-xlarge-hdpi-v11/awesomebar_tab_right.9.png \
+  res/drawable-xlarge-hdpi-v11/awesomebar_sep_left.9.png \
+  res/drawable-xlarge-hdpi-v11/awesomebar_sep_right.9.png \
   res/drawable-xlarge-hdpi-v11/ic_menu_bookmark_add.png \
   res/drawable-xlarge-hdpi-v11/ic_menu_bookmark_remove.png \
   $(NULL)
 
 RES_DRAWABLE_XLARGE_XHDPI_V11 = \
   res/drawable-xlarge-xhdpi-v11/awesomebar_tab_center.9.png \
   res/drawable-xlarge-xhdpi-v11/awesomebar_tab_left.9.png \
   res/drawable-xlarge-xhdpi-v11/awesomebar_tab_right.9.png \
+  res/drawable-xlarge-xhdpi-v11/awesomebar_sep_left.9.png \
+  res/drawable-xlarge-xhdpi-v11/awesomebar_sep_right.9.png \
   res/drawable-xlarge-xhdpi-v11/ic_menu_bookmark_add.png \
   res/drawable-xlarge-xhdpi-v11/ic_menu_bookmark_remove.png \
   $(NULL)
 
 RES_COLOR = \
   res/color/menu_item_title.xml \
   res/color/select_item_multichoice.xml \
   $(NULL)
@@ -998,17 +1017,17 @@ MOZ_ANDROID_DRAWABLES += \
   mobile/android/base/resources/drawable/tabs_panel_indicator.xml               \
   mobile/android/base/resources/drawable/webapp_titlebar_bg.xml                 \
   $(NULL)
 
 MOZ_BRANDING_DRAWABLE_MDPI = $(shell if test -e $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/android-resources.mn; then cat $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/android-resources.mn | tr '\n' ' ';  fi)
 MOZ_BRANDING_DRAWABLE_HDPI = $(shell if test -e $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/android-resources-hdpi.mn; then cat $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/android-resources-hdpi.mn | tr '\n' ' ';  fi)
 MOZ_BRANDING_DRAWABLE_XHDPI = $(shell if test -e $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/android-resources-xhdpi.mn; then cat $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/android-resources-xhdpi.mn | tr '\n' ' ';  fi)
 
-RESOURCES=$(RES_LAYOUT) $(RES_LAYOUT_LARGE_LAND_V11) $(RES_LAYOUT_LARGE_V11) $(RES_LAYOUT_XLARGE_V11) $(RES_VALUES) $(RES_VALUES_LAND) $(RES_VALUES_V11) $(RES_VALUES_LARGE_V11) $(RES_VALUES_LARGE_LAND_V11) $(RES_VALUES_XLARGE_V11) $(RES_VALUES_LAND_V14) $(RES_XML) $(RES_ANIM) $(RES_DRAWABLE_MDPI) $(RES_DRAWABLE_LDPI) $(RES_DRAWABLE_HDPI) $(RES_DRAWABLE_XHDPI) $(RES_DRAWABLE_MDPI_V11) $(RES_DRAWABLE_HDPI_V11) $(RES_DRAWABLE_XHDPI_V11) $(RES_DRAWABLE_LAND_MDPI_V14) $(RES_DRAWABLE_LAND_HDPI_V14) $(RES_DRAWABLE_LAND_XHDPI_V14) $(RES_DRAWABLE_LARGE_LAND_V11) $(RES_DRAWABLE_LARGE_MDPI_V11) $(RES_DRAWABLE_LARGE_HDPI_V11) $(RES_DRAWABLE_LARGE_XHDPI_V11) $(RES_DRAWABLE_XLARGE_MDPI_V11) $(RES_DRAWABLE_XLARGE_HDPI_V11) $(RES_DRAWABLE_XLARGE_XHDPI_V11) $(RES_COLOR) $(RES_MENU)
+RESOURCES=$(RES_LAYOUT) $(RES_LAYOUT_LARGE_LAND_V11) $(RES_LAYOUT_LARGE_V11) $(RES_LAYOUT_XLARGE_V11) $(RES_VALUES) $(RES_VALUES_LAND) $(RES_VALUES_V11) $(RES_VALUES_LARGE_V11) $(RES_VALUES_LARGE_LAND_V11) $(RES_VALUES_XLARGE_V11) $(RES_VALUES_LAND_V14) $(RES_VALUES_V14) $(RES_XML) $(RES_ANIM) $(RES_DRAWABLE_MDPI) $(RES_DRAWABLE_LDPI) $(RES_DRAWABLE_HDPI) $(RES_DRAWABLE_XHDPI) $(RES_DRAWABLE_MDPI_V11) $(RES_DRAWABLE_HDPI_V11) $(RES_DRAWABLE_XHDPI_V11) $(RES_DRAWABLE_LAND_MDPI_V14) $(RES_DRAWABLE_LAND_HDPI_V14) $(RES_DRAWABLE_LAND_XHDPI_V14) $(RES_DRAWABLE_LARGE_LAND_V11) $(RES_DRAWABLE_LARGE_MDPI_V11) $(RES_DRAWABLE_LARGE_HDPI_V11) $(RES_DRAWABLE_LARGE_XHDPI_V11) $(RES_DRAWABLE_XLARGE_MDPI_V11) $(RES_DRAWABLE_XLARGE_HDPI_V11) $(RES_DRAWABLE_XLARGE_XHDPI_V11) $(RES_COLOR) $(RES_MENU)
 
 RES_DIRS= \
   res/layout                    \
   res/layout-land-v14           \
   res/layout-large-v11          \
   res/layout-large-land-v11     \
   res/layout-xlarge-v11         \
   res/layout-xlarge-land-v11    \
--- a/mobile/android/base/PromptService.java
+++ b/mobile/android/base/PromptService.java
@@ -62,27 +62,29 @@ public class PromptService implements On
     private AlertDialog mDialog;
 
     private final int mGroupPaddingSize;
     private final int mLeftRightTextWithIconPadding;
     private final int mTopBottomTextWithIconPadding;
     private final int mIconTextPadding;
     private final int mIconSize;
     private final int mInputPaddingSize;
+    private final int mMinRowSize;
 
     PromptService() {
         sInflater = LayoutInflater.from(GeckoApp.mAppContext);
 
         Resources res = GeckoApp.mAppContext.getResources();
         mGroupPaddingSize = (int) (res.getDimension(R.dimen.prompt_service_group_padding_size));
         mLeftRightTextWithIconPadding = (int) (res.getDimension(R.dimen.prompt_service_left_right_text_with_icon_padding));
         mTopBottomTextWithIconPadding = (int) (res.getDimension(R.dimen.prompt_service_top_bottom_text_with_icon_padding));
         mIconTextPadding = (int) (res.getDimension(R.dimen.prompt_service_icon_text_padding));
         mIconSize = (int) (res.getDimension(R.dimen.prompt_service_icon_size));
         mInputPaddingSize = (int) (res.getDimension(R.dimen.prompt_service_inputs_padding));
+        mMinRowSize = (int) (res.getDimension(R.dimen.prompt_service_min_list_item_height));
 
         GeckoAppShell.getEventDispatcher().registerEventListener("Prompt:Show", this);
     }
 
     void destroy() {
         GeckoAppShell.getEventDispatcher().unregisterEventListener("Prompt:Show", this);
     }
 
@@ -687,16 +689,17 @@ public class PromptService implements On
 
             if (convertView == null) {
                 int resourceId = mResourceId;
                 if (item.isGroup) {
                     resourceId = R.layout.list_item_header;
                 }
 
                 convertView = sInflater.inflate(resourceId, null);
+                convertView.setMinimumHeight(mMinRowSize);
 
                 TextView tv = (TextView) convertView.findViewById(android.R.id.text1);
                 viewHolder = new ViewHolder(tv, tv.getPaddingLeft(), tv.getPaddingRight(),
                                             tv.getPaddingTop(), tv.getPaddingBottom());
 
                 convertView.setTag(viewHolder);
             } else {
                 viewHolder = (ViewHolder) convertView.getTag();
--- a/mobile/android/base/gfx/Axis.java
+++ b/mobile/android/base/gfx/Axis.java
@@ -130,17 +130,17 @@ abstract class Axis {
     private float mFirstTouchPos;           /* Position of the first touch event on the current drag. */
     private float mTouchPos;                /* Position of the most recent touch event on the current drag. */
     private float mLastTouchPos;            /* Position of the touch event before touchPos. */
     private float mVelocity;                /* Velocity in this direction; pixels per animation frame. */
     private boolean mScrollingDisabled;     /* Whether movement on this axis is locked. */
     private boolean mDisableSnap;           /* Whether overscroll snapping is disabled. */
     private float mDisplacement;
 
-    private FlingStates mFlingState;        /* The fling state we're in on this axis. */
+    private FlingStates mFlingState = FlingStates.STOPPED; /* The fling state we're in on this axis. */
 
     protected abstract float getOrigin();
     protected abstract float getViewportLength();
     protected abstract float getPageStart();
     protected abstract float getPageLength();
 
     Axis(SubdocumentScrollHelper subscroller) {
         mSubscroller = subscroller;
@@ -334,17 +334,17 @@ abstract class Axis {
     void displace() {
         // if this isn't scrollable just return
         if (!scrollable())
             return;
 
         if (mFlingState == FlingStates.PANNING)
             mDisplacement += (mLastTouchPos - mTouchPos) * getEdgeResistance(false);
         else
-            mDisplacement += mVelocity;
+            mDisplacement += mVelocity * getEdgeResistance(false);
 
         // if overscroll is disabled and we're trying to overscroll, reset the displacement
         // to remove any excess. Using getExcess alone isn't enough here since it relies on
         // getOverscroll which doesn't take into account any new displacment being applied.
         // If we using a subscroller, we don't want to alter the scrolling being done
         if (getOverScrollMode() == View.OVER_SCROLL_NEVER && !mSubscroller.scrolling()) {
             if (mDisplacement + getOrigin() < getPageStart()) {
                 mDisplacement = getPageStart() - getOrigin();
@@ -356,9 +356,17 @@ abstract class Axis {
         }
     }
 
     float resetDisplacement() {
         float d = mDisplacement;
         mDisplacement = 0.0f;
         return d;
     }
+
+    void setAutoscrollVelocity(float velocity) {
+        if (mFlingState != FlingStates.STOPPED) {
+            Log.e(LOGTAG, "Setting autoscroll velocity while in a fling is not allowed!");
+            return;
+        }
+        mVelocity = velocity;
+    }
 }
--- a/mobile/android/base/gfx/GLController.java
+++ b/mobile/android/base/gfx/GLController.java
@@ -118,19 +118,17 @@ public class GLController {
         // that will run once this call unwinds all the way out and Android finishes
         // doing its thing.
 
         mView.post(new Runnable() {
             public void run() {
                 // If we haven't yet created the compositor, and the GfxInfoThread
                 // isn't done it's data gathering activities, then postpone creating
                 // the compositor a little bit more. Don't block though, since this is
-                // the UI thread we're running on. This conditional also ensures that
-                // we don't call GfxInfoThread.hasData() once we have created the
-                // compositor, as that is not allowed (see GfxInfoThread).
+                // the UI thread we're running on.
                 if (!mCompositorCreated && !GfxInfoThread.hasData()) {
                     mView.postDelayed(this, 1);
                     return;
                 }
 
                 try {
                     // Re-check mSurfaceValid in case the surface was destroyed between
                     // where we set it to true above and this runnable getting run.
--- a/mobile/android/base/gfx/GfxInfoThread.java
+++ b/mobile/android/base/gfx/GfxInfoThread.java
@@ -28,20 +28,29 @@ public class GfxInfoThread extends Threa
     public static void startThread() {
         if (sInstance == null) {
             sInstance = new GfxInfoThread();
             sInstance.start();
         }
     }
 
     public static boolean hasData() {
-        // This should never be called before startThread() or after getData()
-        // so we know sInstance will be non-null here
-        synchronized (sInstance) {
-            return sInstance.mData != null;
+        // This should never be called before startThread(), so if
+        // sInstance is null here, then we know the thread was created,
+        // ran to completion, and getData() was called. Therefore hasData()
+        // should return true. If sInstance is not null, then we need to
+        // check if the mData field on it is null or not and return accordingly.
+        // Note that we keep a local copy of sInstance to avoid race conditions
+        // as getData() may be called concurrently.
+        GfxInfoThread instance = sInstance;
+        if (instance == null) {
+            return true;
+        }
+        synchronized (instance) {
+            return instance.mData != null;
         }
     }
 
     public static String getData() {
         // This should be called exactly once after startThread(), so we
         // know sInstance will be non-null here
         String data = sInstance.getDataImpl();
         sInstance = null;
--- a/mobile/android/base/gfx/JavaPanZoomController.java
+++ b/mobile/android/base/gfx/JavaPanZoomController.java
@@ -18,16 +18,17 @@ import org.mozilla.gecko.util.GeckoEvent
 import org.json.JSONObject;
 
 import android.graphics.PointF;
 import android.graphics.RectF;
 import android.os.Build;
 import android.util.FloatMath;
 import android.util.Log;
 import android.view.GestureDetector;
+import android.view.KeyEvent;
 import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.View;
 
 import java.util.Timer;
 import java.util.TimerTask;
 
 /*
@@ -76,16 +77,19 @@ class JavaPanZoomController
         PANNING_HOLD_LOCKED, /* like PANNING_HOLD, but axis lock still in effect */
         PINCHING,       /* nth touch-start, where n > 1. this mode allows pan and zoom */
         ANIMATED_ZOOM,  /* animated zoom to a new rect */
         BOUNCE,         /* in a bounce animation */
 
         WAITING_LISTENERS, /* a state halfway between NOTHING and TOUCHING - the user has
                         put a finger down, but we don't yet know if a touch listener has
                         prevented the default actions yet. we still need to abort animations. */
+        AUTOSCROLL,     /* We are scrolling using an AutoscrollRunnable animation. This is similar
+                        to the FLING state except that it must be stopped manually by the code that
+                        started it, and it's velocity can be updated while it's running. */
     }
 
     private final PanZoomTarget mTarget;
     private final SubdocumentScrollHelper mSubscroller;
     private final Axis mX;
     private final Axis mY;
     private final TouchEventHandler mTouchEventHandler;
     private final EventDispatcher mEventDispatcher;
@@ -213,27 +217,52 @@ class JavaPanZoomController
             }
         } catch (Exception e) {
             Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
         }
     }
 
     /** This function MUST be called on the UI thread */
     @Override
+    public boolean onKeyEvent(KeyEvent event) {
+        if (Build.VERSION.SDK_INT <= 11) {
+            return false;
+        }
+
+        if ((event.getSource() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD
+            && event.getAction() == KeyEvent.ACTION_DOWN) {
+
+            switch (event.getKeyCode()) {
+            case KeyEvent.KEYCODE_ZOOM_IN:
+                return animatedScale(0.2f);
+            case KeyEvent.KEYCODE_ZOOM_OUT:
+                return animatedScale(-0.2f);
+            }
+        }
+        return false;
+    }
+
+    /** This function MUST be called on the UI thread */
+    @Override
     public boolean onMotionEvent(MotionEvent event) {
         if (Build.VERSION.SDK_INT <= 11) {
             return false;
         }
 
         switch (event.getSource() & InputDevice.SOURCE_CLASS_MASK) {
         case InputDevice.SOURCE_CLASS_POINTER:
             switch (event.getAction() & MotionEvent.ACTION_MASK) {
             case MotionEvent.ACTION_SCROLL: return handlePointerScroll(event);
             }
             break;
+        case InputDevice.SOURCE_CLASS_JOYSTICK:
+            switch (event.getAction() & MotionEvent.ACTION_MASK) {
+            case MotionEvent.ACTION_MOVE: return handleJoystickScroll(event);
+            }
+            break;
         }
         return false;
     }
 
     /** This function MUST be called on the UI thread */
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         return mTouchEventHandler.handleEvent(event);
@@ -335,16 +364,17 @@ class JavaPanZoomController
         switch (mState) {
         case ANIMATED_ZOOM:
             // We just interrupted a double-tap animation, so force a redraw in
             // case this touchstart is just a tap that doesn't end up triggering
             // a redraw
             mTarget.forceRedraw();
             // fall through
         case FLING:
+        case AUTOSCROLL:
         case BOUNCE:
         case NOTHING:
         case WAITING_LISTENERS:
             startTouch(event.getX(0), event.getY(0), event.getEventTime());
             return false;
         case TOUCHING:
         case PANNING:
         case PANNING_LOCKED:
@@ -357,16 +387,17 @@ class JavaPanZoomController
         Log.e(LOGTAG, "Unhandled case " + mState + " in handleTouchStart");
         return false;
     }
 
     private boolean handleTouchMove(MotionEvent event) {
 
         switch (mState) {
         case FLING:
+        case AUTOSCROLL:
         case BOUNCE:
         case WAITING_LISTENERS:
             // should never happen
             Log.e(LOGTAG, "Received impossible touch move while in " + mState);
             // fall through
         case ANIMATED_ZOOM:
         case NOTHING:
             // may happen if user double-taps and drags without lifting after the
@@ -404,16 +435,17 @@ class JavaPanZoomController
         Log.e(LOGTAG, "Unhandled case " + mState + " in handleTouchMove");
         return false;
     }
 
     private boolean handleTouchEnd(MotionEvent event) {
 
         switch (mState) {
         case FLING:
+        case AUTOSCROLL:
         case BOUNCE:
         case WAITING_LISTENERS:
             // should never happen
             Log.e(LOGTAG, "Received impossible touch end while in " + mState);
             // fall through
         case ANIMATED_ZOOM:
         case NOTHING:
             // may happen if user double-taps and drags without lifting after the
@@ -468,16 +500,53 @@ class JavaPanZoomController
 
             scrollBy(scrollX * MAX_SCROLL, scrollY * MAX_SCROLL);
             bounce();
             return true;
         }
         return false;
     }
 
+    private float normalizeJoystick(float value, InputDevice.MotionRange range) {
+        // The 1e-2 here should really be range.getFlat() + range.getFuzz() but the
+        // values those functions return on the Ouya are zero so we're just hard-coding
+        // it for now.
+        if (Math.abs(value) < 1e-2) {
+            return 0;
+        }
+        // joystick axis positions are already normalized to [-1, 1] so just scale it up by how much we want
+        return value * MAX_SCROLL;
+    }
+
+    // Since this event is a position-based event rather than a motion-based event, we need to
+    // set up an AUTOSCROLL animation to keep scrolling even while we don't get events.
+    private boolean handleJoystickScroll(MotionEvent event) {
+        float velocityX = normalizeJoystick(event.getX(0), event.getDevice().getMotionRange(MotionEvent.AXIS_X));
+        float velocityY = normalizeJoystick(event.getY(0), event.getDevice().getMotionRange(MotionEvent.AXIS_Y));
+
+        if (velocityX == 0 && velocityY == 0) {
+            if (mState == PanZoomState.AUTOSCROLL) {
+                bounce(); // if not needed, this will automatically go to state NOTHING
+                return true;
+            }
+            return false;
+        }
+
+        if (mState == PanZoomState.NOTHING) {
+            setState(PanZoomState.AUTOSCROLL);
+            startAnimationTimer(new AutoscrollRunnable());
+        }
+        if (mState == PanZoomState.AUTOSCROLL) {
+            mX.setAutoscrollVelocity(velocityX);
+            mY.setAutoscrollVelocity(velocityY);
+            return true;
+        }
+        return false;
+    }
+
     private void startTouch(float x, float y, long time) {
         mX.startTouch(x);
         mY.startTouch(y);
         setState(PanZoomState.TOUCHING);
         mLastEventTime = time;
     }
 
     private void startPanning(float x, float y, long time) {
@@ -592,17 +661,17 @@ class JavaPanZoomController
     /* Performs a bounce-back animation to the nearest valid viewport metrics. */
     private void bounce() {
         bounce(getValidViewportMetrics(), PanZoomState.BOUNCE);
     }
 
     /* Starts the fling or bounce animation. */
     private void startAnimationTimer(final AnimationRunnable runnable) {
         if (mAnimationTimer != null) {
-            Log.e(LOGTAG, "Attempted to start a new fling without canceling the old one!");
+            Log.e(LOGTAG, "Attempted to start a new timer without canceling the old one!");
             stopAnimationTimer();
         }
 
         mAnimationTimer = new Timer("Animation Timer");
         mAnimationRunnable = runnable;
         mAnimationTimer.scheduleAtFixedRate(new TimerTask() {
             @Override
             public void run() { mTarget.post(runnable); }
@@ -675,16 +744,27 @@ class JavaPanZoomController
         protected abstract void animateFrame();
 
         /* This should always run on the UI thread */
         protected final void terminate() {
             mAnimationTerminated = true;
         }
     }
 
+    private class AutoscrollRunnable extends AnimationRunnable {
+        protected void animateFrame() {
+            if (mState != PanZoomState.AUTOSCROLL) {
+                finishAnimation();
+                return;
+            }
+
+            updatePosition();
+        }
+    }
+
     /* The callback that performs the bounce animation. */
     private class BounceRunnable extends AnimationRunnable {
         /* The current frame of the bounce-back animation */
         private int mBounceFrame;
         /*
          * The viewport metrics that represent the start and end of the bounce-back animation,
          * respectively.
          */
@@ -915,71 +995,89 @@ class JavaPanZoomController
             return false;
 
         float prevSpan = detector.getPreviousSpan();
         if (FloatUtils.fuzzyEquals(prevSpan, 0.0f)) {
             // let's eat this one to avoid setting the new zoom to infinity (bug 711453)
             return true;
         }
 
-        float spanRatio = detector.getCurrentSpan() / prevSpan;
+        synchronized (mTarget.getLock()) {
+            float zoomFactor = getAdjustedZoomFactor(detector.getCurrentSpan() / prevSpan);
+            scrollBy(mLastZoomFocus.x - detector.getFocusX(),
+                     mLastZoomFocus.y - detector.getFocusY());
+            mLastZoomFocus.set(detector.getFocusX(), detector.getFocusY());
+            ImmutableViewportMetrics target = getMetrics().scaleTo(zoomFactor, mLastZoomFocus);
+            mTarget.setViewportMetrics(target);
+        }
+
+        GeckoEvent event = GeckoEvent.createNativeGestureEvent(GeckoEvent.ACTION_MAGNIFY, mLastZoomFocus, getMetrics().zoomFactor);
+        GeckoAppShell.sendEventToGecko(event);
+
+        return true;
+    }
 
+    private boolean animatedScale(float zoomDelta) {
+        if (mState != PanZoomState.NOTHING && mState != PanZoomState.BOUNCE) {
+            return false;
+        }
+        synchronized (mTarget.getLock()) {
+            ImmutableViewportMetrics metrics = getMetrics();
+            float oldZoom = metrics.zoomFactor;
+            float newZoom = oldZoom + zoomDelta;
+            float adjustedZoom = getAdjustedZoomFactor(newZoom / oldZoom);
+            PointF center = new PointF(metrics.getWidth() / 2.0f, metrics.getHeight() / 2.0f);
+            metrics = metrics.scaleTo(adjustedZoom, center);
+            bounce(getValidViewportMetrics(metrics), PanZoomState.BOUNCE);
+        }
+        return true;
+    }
+
+    private float getAdjustedZoomFactor(float zoomRatio) {
         /*
          * Apply edge resistance if we're zoomed out smaller than the page size by scaling the zoom
          * factor toward 1.0.
          */
         float resistance = Math.min(mX.getEdgeResistance(true), mY.getEdgeResistance(true));
-        if (spanRatio > 1.0f)
-            spanRatio = 1.0f + (spanRatio - 1.0f) * resistance;
+        if (zoomRatio > 1.0f)
+            zoomRatio = 1.0f + (zoomRatio - 1.0f) * resistance;
         else
-            spanRatio = 1.0f - (1.0f - spanRatio) * resistance;
+            zoomRatio = 1.0f - (1.0f - zoomRatio) * resistance;
 
-        synchronized (mTarget.getLock()) {
-            float newZoomFactor = getMetrics().zoomFactor * spanRatio;
-            float minZoomFactor = 0.0f;
-            float maxZoomFactor = MAX_ZOOM;
+        float newZoomFactor = getMetrics().zoomFactor * zoomRatio;
+        float minZoomFactor = 0.0f;
+        float maxZoomFactor = MAX_ZOOM;
 
-            ZoomConstraints constraints = mTarget.getZoomConstraints();
-
-            if (constraints.getMinZoom() > 0)
-                minZoomFactor = constraints.getMinZoom();
-            if (constraints.getMaxZoom() > 0)
-                maxZoomFactor = constraints.getMaxZoom();
+        ZoomConstraints constraints = mTarget.getZoomConstraints();
 
-            if (newZoomFactor < minZoomFactor) {
-                // apply resistance when zooming past minZoomFactor,
-                // such that it asymptotically reaches minZoomFactor / 2.0
-                // but never exceeds that
-                final float rate = 0.5f; // controls how quickly we approach the limit
-                float excessZoom = minZoomFactor - newZoomFactor;
-                excessZoom = 1.0f - (float)Math.exp(-excessZoom * rate);
-                newZoomFactor = minZoomFactor * (1.0f - excessZoom / 2.0f);
-            }
+        if (constraints.getMinZoom() > 0)
+            minZoomFactor = constraints.getMinZoom();
+        if (constraints.getMaxZoom() > 0)
+            maxZoomFactor = constraints.getMaxZoom();
 
-            if (newZoomFactor > maxZoomFactor) {
-                // apply resistance when zooming past maxZoomFactor,
-                // such that it asymptotically reaches maxZoomFactor + 1.0
-                // but never exceeds that
-                float excessZoom = newZoomFactor - maxZoomFactor;
-                excessZoom = 1.0f - (float)Math.exp(-excessZoom);
-                newZoomFactor = maxZoomFactor + excessZoom;
-            }
-
-            scrollBy(mLastZoomFocus.x - detector.getFocusX(),
-                     mLastZoomFocus.y - detector.getFocusY());
-            PointF focus = new PointF(detector.getFocusX(), detector.getFocusY());
-            scaleWithFocus(newZoomFactor, focus);
+        if (newZoomFactor < minZoomFactor) {
+            // apply resistance when zooming past minZoomFactor,
+            // such that it asymptotically reaches minZoomFactor / 2.0
+            // but never exceeds that
+            final float rate = 0.5f; // controls how quickly we approach the limit
+            float excessZoom = minZoomFactor - newZoomFactor;
+            excessZoom = 1.0f - (float)Math.exp(-excessZoom * rate);
+            newZoomFactor = minZoomFactor * (1.0f - excessZoom / 2.0f);
         }
 
-        mLastZoomFocus.set(detector.getFocusX(), detector.getFocusY());
+        if (newZoomFactor > maxZoomFactor) {
+            // apply resistance when zooming past maxZoomFactor,
+            // such that it asymptotically reaches maxZoomFactor + 1.0
+            // but never exceeds that
+            float excessZoom = newZoomFactor - maxZoomFactor;
+            excessZoom = 1.0f - (float)Math.exp(-excessZoom);
+            newZoomFactor = maxZoomFactor + excessZoom;
+        }
 
-        GeckoEvent event = GeckoEvent.createNativeGestureEvent(GeckoEvent.ACTION_MAGNIFY, mLastZoomFocus, getMetrics().zoomFactor);
-        GeckoAppShell.sendEventToGecko(event);
-
-        return true;
+        return newZoomFactor;
     }
 
     @Override
     public void onScaleEnd(SimpleScaleGestureDetector detector) {
         if (mState == PanZoomState.ANIMATED_ZOOM)
             return;
 
         // switch back to the touching state
@@ -993,26 +1091,16 @@ class JavaPanZoomController
 
         if (event == null) {
             return;
         }
 
         GeckoAppShell.sendEventToGecko(event);
     }
 
-    /**
-     * Scales the viewport, keeping the given focus point in the same place before and after the
-     * scale operation. You must hold the monitor while calling this.
-     */
-    private void scaleWithFocus(float zoomFactor, PointF focus) {
-        ImmutableViewportMetrics viewportMetrics = getMetrics();
-        viewportMetrics = viewportMetrics.scaleTo(zoomFactor, focus);
-        mTarget.setViewportMetrics(viewportMetrics);
-    }
-
     @Override
     public boolean getRedrawHint() {
         switch (mState) {
             case PINCHING:
             case ANIMATED_ZOOM:
             case BOUNCE:
                 // don't redraw during these because the zoom is (or might be, in the case
                 // of BOUNCE) be changing rapidly and gecko will have to redraw the entire
--- a/mobile/android/base/gfx/LayerView.java
+++ b/mobile/android/base/gfx/LayerView.java
@@ -202,17 +202,19 @@ public class LayerView extends FrameLayo
     public GeckoLayerClient getLayerClient() { return mLayerClient; }
     public PanZoomController getPanZoomController() { return mPanZoomController; }
 
     public ImmutableViewportMetrics getViewportMetrics() {
         return mLayerClient.getViewportMetrics();
     }
 
     public void abortPanning() {
-        mLayerClient.getPanZoomController().abortPanning();
+        if (mPanZoomController != null) {
+            mPanZoomController.abortPanning();
+        }
     }
 
     public PointF convertViewPointToLayerPoint(PointF viewPoint) {
         return mLayerClient.convertViewPointToLayerPoint(viewPoint);
     }
 
     int getBackgroundColor() {
         return mBackgroundColor;
@@ -244,46 +246,54 @@ public class LayerView extends FrameLayo
     public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
         if (mInputConnectionHandler != null)
             return mInputConnectionHandler.onCreateInputConnection(outAttrs);
         return null;
     }
 
     @Override
     public boolean onKeyPreIme(int keyCode, KeyEvent event) {
-        if (mInputConnectionHandler != null)
-            return mInputConnectionHandler.onKeyPreIme(keyCode, event);
+        if (mInputConnectionHandler != null && mInputConnectionHandler.onKeyPreIme(keyCode, event)) {
+            return true;
+        }
         return false;
     }
 
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (mInputConnectionHandler != null)
-            return mInputConnectionHandler.onKeyDown(keyCode, event);
+        if (mPanZoomController != null && mPanZoomController.onKeyEvent(event)) {
+            return true;
+        }
+        if (mInputConnectionHandler != null && mInputConnectionHandler.onKeyDown(keyCode, event)) {
+            return true;
+        }
         return false;
     }
 
     @Override
     public boolean onKeyLongPress(int keyCode, KeyEvent event) {
-        if (mInputConnectionHandler != null)
-            return mInputConnectionHandler.onKeyLongPress(keyCode, event);
+        if (mInputConnectionHandler != null && mInputConnectionHandler.onKeyLongPress(keyCode, event)) {
+            return true;
+        }
         return false;
     }
 
     @Override
     public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
-        if (mInputConnectionHandler != null)
-            return mInputConnectionHandler.onKeyMultiple(keyCode, repeatCount, event);
+        if (mInputConnectionHandler != null && mInputConnectionHandler.onKeyMultiple(keyCode, repeatCount, event)) {
+            return true;
+        }
         return false;
     }
 
     @Override
     public boolean onKeyUp(int keyCode, KeyEvent event) {
-        if (mInputConnectionHandler != null)
-            return mInputConnectionHandler.onKeyUp(keyCode, event);
+        if (mInputConnectionHandler != null && mInputConnectionHandler.onKeyUp(keyCode, event)) {
+            return true;
+        }
         return false;
     }
 
     public boolean isIMEEnabled() {
         if (mInputConnectionHandler != null) {
             return mInputConnectionHandler.isIMEEnabled();
         }
         return false;
@@ -473,24 +483,26 @@ public class LayerView extends FrameLayo
         public void onSurfaceTextureUpdated(SurfaceTexture surface) {
 
         }
     }
 
     @Override
     public void setOverScrollMode(int overscrollMode) {
         super.setOverScrollMode(overscrollMode);
-        if (mLayerClient != null)
-            mLayerClient.getPanZoomController().setOverScrollMode(overscrollMode);
+        if (mPanZoomController != null) {
+            mPanZoomController.setOverScrollMode(overscrollMode);
+        }
     }
 
     @Override
     public int getOverScrollMode() {
-        if (mLayerClient != null)
-            return mLayerClient.getPanZoomController().getOverScrollMode();
+        if (mPanZoomController != null) {
+            return mPanZoomController.getOverScrollMode();
+        }
         return super.getOverScrollMode();
     }
 
     @Override
     public void onFocusChanged (boolean gainFocus, int direction, Rect previouslyFocusedRect) {
         super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
         GeckoAccessibility.onLayerViewFocusChanged(this, gainFocus);
     }
--- a/mobile/android/base/gfx/PanZoomController.java
+++ b/mobile/android/base/gfx/PanZoomController.java
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.gfx;
 
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.util.EventDispatcher;
 
 import android.graphics.PointF;
+import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
 
 public interface PanZoomController {
     // The distance the user has to pan before we recognize it as such (e.g. to avoid 1-pixel pans
     // between the touch-down and touch-up of a click). In units of density-independent pixels.
     public static final float PAN_THRESHOLD = 1/16f * GeckoAppShell.getDpi();
 
@@ -22,16 +23,17 @@ public interface PanZoomController {
             return new JavaPanZoomController(target, view, dispatcher);
         }
     }
 
     public void destroy();
 
     public boolean onTouchEvent(MotionEvent event);
     public boolean onMotionEvent(MotionEvent event);
+    public boolean onKeyEvent(KeyEvent event);
     public void notifyDefaultActionPrevented(boolean prevented);
 
     public boolean getRedrawHint();
     public PointF getVelocityVector();
 
     public void pageRectUpdated();
     public void abortPanning();
     public void abortAnimation();
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9efdd76be3eee2d49c62b9d6a8559412afa0bb83
GIT binary patch
literal 216
zc%17D@N?(olHy`uVBq!ia0vp^EI@3^!3HGLu6vb%1kxRS9T^xl_H+M9WCij$3p^r=
z85sBuf-vKbiP>*~g6t)pzOL+d8F^TY%-z|teglQ1N?apKg7ec#$`gxH83GbB^Gfvm
zTtgJfjP*?Q3=Isv6fFd*a`bd@46*P}PH<@WZ=g1ZQG{VLC%3_$|NYD6sxg(8mKtO$
zd|7cIqoP5Wsqcxy<dBX;jcq<Hy2g&NT$lJwncw6v<R9E@@wY`I9cUPXr>mdKI;Vst
E0O{gCIRF3v
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ce36b7407eda5dc0c954d1526c1f70c25c58c4e3
GIT binary patch
literal 206
zc%17D@N?(olHy`uVBq!ia0vp^EI@3^!3HGLu6vb%1kxRS9T^xl_H+M9WCij$3p^r=
z85sBufG}g$wN6f;AbW|YuPggqMjjR;b9c6^-#{U$64!{5;QX|b^2DN4hJeJ(yb?V>
z*ARs=V?9$nLj!{^MGJwd%spKkLoEE08=C$HNbyXtOfZ|s^#8x|kxcb~@Njl<Nl^(=
t1r3MEAsvbhJRIB&3>P~7J3O*yW>|l9vqeFP=1ZUv44$rjF6*2UngFGVI5_|S
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..811168736a3ab00f5c629475c705aa1ab88f0db7
GIT binary patch
literal 482
zc$@*^0UiE{P)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00050Nkl<Zc-rmP
zKTASU7=ZB`HAM+Qf2h0~v=>1^ZjH6{1sV!k8XBUZPf!s=AE33lu`!xlf|kgX%o?JM
zAjBjW%if;h4bI@zbLDD5cldGe$i)ZGt6m)u`BTE6FenTPgO*p<&LEcFaf(?u=)ek+
zc!e}@W)mb$C}R=_5I<THq)t$6X^^q!WgPqXKm~#;ETS6@JYFOCAk%^dCDCK-2Oq>5
zLlII#QJ;6PjbS(zL3s#XnhA38ghCB@Bd8OOR}kwKG8n}Kc96gT&aoNXk*NkjHxOM%
zb#D+U2r}&sisK%FET)W@JGiz-7DuVh7h~Ke=w}{{s4rb}aQzLncTfp2t02YW8Hgbf
z{Kww@9U8(l#E?U@?LiuohTs+n+?mH_ePlt*5bK38&{5rUHAax~Gt}ieKdNJvL7PY;
ziU{V>uTdFnwDrhL8X(B}{k89FAmSb3eO;?>KOV5I5hFOlTadROACM+2;S%CQ)h1{U
z1xue0m4g^67S|s(3^G{^buU)%3{l6JMwc<vo`MWAxp>5`x&LcHYR==HDEy-s2L11#
YZ}&7dlE~uz)&Kwi07*qoM6N<$f?M{<F8}}l
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..707c0ed921bc3827bfef2265276cb3df3ff49321
GIT binary patch
literal 208
zc%17D@N?(olHy`uVBq!ia0vp^EI_Qn!3HGP#m@Es38XvvIx;Y9?C1WI$O`0h7I;J!
zGcfQS1YyP<6SLm}1=&kHeO=k_GV-wK=^d4tp9U0?Dshb{3C>R|DNig)We7;j%q!9J
za}7}_GuAWJGc+*xQnV1L%F@%tF+?LcIl-afzk%8uMiGY1hAa~Q{<{bJwmHPc%AOJ6
wu+?&C|Dd3}$Y4u?w@Jql<{-YSOyBq!UOuZ*W~;fF12lxe)78&qol`;+0F=r)U;qFB
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..716ad8e91c5e680cde9d76119a925c7efc63251e
GIT binary patch
literal 202
zc%17D@N?(olHy`uVBq!ia0vp^EI_Qn!3HGP#m@Es38XvvIx;Y9?C1WI$O`0h7I;J!
zGcfQS0Aa?gYn_}xLG}_)Usv|Kj65uQdPk+^rvZheN?apKg7ec#$`gxH83GbB^Gfvm
zTtgJfjP*?Q3=Isv6fFd*GWK+F4ABTqZfN=+AjLDmGQq5@@&A9pM^Ct}T)leG)s6Lq
pszdJ#XEq5Y1%@jh<vsqS11(FfQdWL0?+(<?;OXk;vd$@?2>@9rIQjqp
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3b9aa76d116b57d0495bb9ee8a3b8c63dc90c3e7
GIT binary patch
literal 295
zc$@(z0oeYDP)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv0002)Nkl<Zc-rmN
z!3zOF6vuIQ`Fl`u;NU;N&B1|EQj()}mp_NIl7pLrQi_mr<D!&!zFSVy?7l`6W$V*6
zZ)f+{n{9R@BJxrHfG-Oum8(05#T7GT5yu2)h{Y}}Konc7wRvg)hgpvzkHb?QQOmp*
z_AUYD^%RnpdJ%1-*6{@faNZcLZ$g4Q5HyXk7Z~7*`??SeA@KaVTL*f`2!et74g%@R
zG{zmZw{&2x`E%UE9hJ9q;6K=B)cR;B0nR~n%wE~aH_VYn0#jUG*~tq?h!vK~oV6uD
tZ9RqpjyR!!nEU5i56U6)|D*j@zyskf8mfvZm+Alj002ovPDHLkV1kSAfwlku
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..df1b602a22b9fc628151cf01787b1db48b0bd1e1
GIT binary patch
literal 220
zc%17D@N?(olHy`uVBq!ia0vp^EI{nW!3HE>Cz?uv1kxRS9T^xl_H+M9WCij$3p^r=
z85sBuf-vKbiP>*~g6t)pzOL+d8F^StMOG>F`T>QcN?apKg7ec#$`gxH83GbB^Gfvm
zTtgJfjP*?Q3=Isv6fFd*a`kj^46*P}PH<@WZ=g1ZQG{XhNr8kP|K-o_VH8@idUdlU
zi&H;WPaC_1BG3LO1`d%thof>@xwai*mEu+StC6O_*`UnHpp*T{J@47JK%jvPp00i_
I>zopr0Cy5TrvLx|
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0a9aa330ddb611d01cf5da1b16a2a68321b68e23
GIT binary patch
literal 207
zc%17D@N?(olHy`uVBq!ia0vp^EI{nW!3HE>Cz?uv1kxRS9T^xl_H+M9WCij$3p^r=
z85sBufG}g$wN6f;AbW|YuPggqMjjSZkyQ%4en26q64!{5;QX|b^2DN4hJeJ(yb?V>
z*ARs=V?9$nLj!{^MGJwdEIeHtLoEE08=C$HNbyXtOfcKY^#8x|5%!=3>(=q<8EF}4
v8O&kLnACVez=6$$tKp1;A-mFt`HT$l!JphE8ft$4&0z3!^>bP0l+XkK(*HQ}
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..83bbd50e4770ca5501334781cb28425b59132af6
GIT binary patch
literal 554
zc$@($0@eMAP)<h;3K|Lk000e1NJLTq001xm001xu1^@s6R|5Hm0005;Nkl<Zc-rmQ
zJxg0r7{Kv^1*LItC{C_fnt~R;fot&_bSSh-Td2lO2v+D&$5ICu$L0%EC~bzi7%E7i
zxJW^KiTDN<!O4O*dHfI05Dxd|Cijr!1kUh-aC5nN{^8tQPK<~Qv=9&iLO=)z0U;m+
zcp32G)$7l=gLL2)dsx9E7&VNSsNe#1NSp4knk68DI5@!s#;^l%5M>DvxcY)Mh^u}D
zT;j@$06pI7{1N2w4mF6ShB@T*T+__HUOxhwJwzFz%6iOL{0vYJ@B<ZnZ8{8?MHO3k
z*7E>WP^JyjIK^Cx&v=V{JjooO--x8xg6YsX1Pv4uhHpS{(CvU~hJX^pj<APU#cnJi
zCwh$~J0fQI1>syD17ahRhId&)+mIB$G6W<<*u%RAe8qK&4W|HIHc9t{&r8T2-d6NA
zAo14*OK}lCJ_p{|!?(C6=3N4+U3v~2#tokk@z=X0gr_*ge2dR0;Rug?3y8a30pHb>
z{l51B)_%M`Z~@)eQeG#hL(~m^W6|2c4B<Jx;S9HF*Y#mf{0Czg#m|21iT^_!eZogb
z7OwZe2SgAD$2f8w9_uLq?sTb4;ywOB5Gm1P%X-de+D&ZhML@H0Y(mtg9y1m{15^&X
sDhD%A0cu8>6yfjn5D)@FKnUoMdv&?D+49_Gq5uE@07*qoM6N<$g124q?f?J)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..697c696a7aa7e8a3d1372d36ceba0e30db1432af
GIT binary patch
literal 221
zc%17D@N?(olHy`uVBq!ia0vp^EI{nV!3HGfEdH7V5=eLSb!1@J*w6hZkrl}2Ebxdd
zW?<ku2*QjzCT70{3bL1Y`ns~;W#nNomwk9DJOd~sRpJ^^5}cn_Ql40p$`Fv4nOCCc
z=Nh6=W~^tbXJ}yXrD!2gm7AxFV~B-+a)Lv{e*?8Sj3Nx1S1KO(@ZWwGYjfCwb?f+^
zg>cwv8A!=JXfe1l>F|QHNfLaA!}t=l`zI`7+%GnPHz4}JMm7e;)*oK?-s{EyO=R$N
L^>bP0l+XkKR%k=p
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2469120423dbb5b8f1726c0b067bb1bd2bd0112c
GIT binary patch
literal 208
zc%17D@N?(olHy`uVBq!ia0vp^EI{nV!3HGfEdH7V5=eLSb!1@J*w6hZkrl}2Ebxdd
zW?<ku0K$w}*E%_Yg6t)pzOL+d8F^UDWgngj&j1QZmAFQf1m~xflqVLYG6W=M=9TFA
zxrQi|8S9zq85$UTDOw0rW$EeS7-Hd{+|cwtK#FIAWrEpNmVf`<JNWY&ckQy;abm@R
x6$dVeF7W)epp(I9K^p@HgYHj$m4C(z3_XHByhOzxG6D@@@O1TaS?83{1OU%DJ{tf4
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..721997f85b68dbd991dc00c1cfe476b45ab0f3b4
GIT binary patch
literal 213
zc%17D@N?(olHy`uVBq!ia0vp^EI@3;!3HF&FIAlb38XvvIx;Y9?C1WI$O`0h7I;J!
zGcfQS1YyP<6SLm}1=&kHeO=k_GV-uk@+SSuY61#LmAFQf1m~xflqVLYG6W=M=9TFA
zxrQi|8S9zq85$UTDOw0rW#{SQ7-Hd{oZ!&#-#~2+qX@%hPHuxg|NEECRbwhGEj7qi
z__E>v2N(Y=6-^%JjZZmpESYt_$<O()Fs)%R6T_lcD=u`*=JN)c#Ng@b=d#Wzp$P!8
C^FI#&
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c88a504435e058bccd07c1375cebb7adf011bdec
GIT binary patch
literal 205
zc%17D@N?(olHy`uVBq!ia0vp^EI@3;!3HF&FIAlb38XvvIx;Y9?C1WI$O`0h7I;J!
zGcfQS0Aa?gYn_}xLG}_)Usv|Kj65usyh;DEnt(!5C9V-A!TD(=<%vb93;~Imc_n&&
zt|1C##(JiDh6V;-iWUM@nR&W6hFJI~H#GeZkm8wOnP4`N>HmM_Bbn*};o<D!lA;os
tOeUT|5=<u=HZX87^#0&i`De_)aOd2L3#*>~_5+&0;OXk;vd$@?2>=|rIu8H<
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..163e955eb851af5b44b2d2824fb9fbe8ebb331c4
GIT binary patch
literal 225
zc%17D@N?(olHy`uVBq!ia0vp^EI^#Z!3HGDV~Q+60_l#vjtmSN`?>!lvI6;>1s;*b
z3=Dh+K$tP>S|=w^kiEpy*OmP)BM*x;V`QC+Hc&{a#5JNMI6tkVJh3R1As{g`uSCz!
zHAJDzSkF|?(7@nJ(L$gqFHaZ85DWk0AOHW`GjlLA&TvRP!1B;2MA%`ISkhww@fE9A
zH?s;I(O=B8_#xw2pT#E=E1t7ue6-X#Wf&pKpg;MffP$4x1J{3J28NsYsVla7Z*c*d
O%HZkh=d#Wzp$Pz5u0cis
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..cb5d678fa1c880c284c667369bdfad28792a4992
GIT binary patch
literal 212
zc%17D@N?(olHy`uVBq!ia0vp^EI^#Z!3HGDV~Q+60_l#vjtmSN`?>!lvI6;>1s;*b
z3=DkxL735kHCP2G$X?><>&kwYk%z^aF|y7@8z>}I;u=vBoS#-wo>-L15RjOeSEA?V
z8lq5UtY@lcXkhTAXdzIQt*47)h=qT0L(_i;1|<a<15U;Sv$re;Yh({Gm6nz|{9ADV
x1U-Zq3fsCFI0Cd79wmr3bTMg8I8e{VuvI;E#RTu|j6j1JJYD@<);T3K0RZ+NIJf`+
--- a/mobile/android/base/resources/drawable/awesomebar_tab_unselected.xml
+++ b/mobile/android/base/resources/drawable/awesomebar_tab_unselected.xml
@@ -36,9 +36,35 @@
                 </shape>
             </item>
 
             <item android:bottom="2dip"
                   android:drawable="@drawable/awesomebar_tab_right"/>
         </layer-list>
     </item>
 
+    <item android:maxLevel="3">
+        <layer-list>
+            <item android:top="@dimen/awesomebar_tab_transparency_height">
+                <shape android:shape="rectangle">
+                    <solid android:color="#EEF1F5"/>
+                </shape>
+            </item>
+
+            <item android:bottom="2dip"
+                  android:drawable="@drawable/awesomebar_sep_right"/>
+        </layer-list>
+    </item>
+
+    <item android:maxLevel="4">
+        <layer-list>
+            <item android:top="@dimen/awesomebar_tab_transparency_height">
+                <shape android:shape="rectangle">
+                    <solid android:color="#EEF1F5"/>
+                </shape>
+            </item>
+
+            <item android:bottom="2dip"
+                  android:drawable="@drawable/awesomebar_sep_left"/>
+        </layer-list>
+    </item>
+
 </level-list>
--- a/mobile/android/base/resources/layout/site_setting_title.xml
+++ b/mobile/android/base/resources/layout/site_setting_title.xml
@@ -5,28 +5,25 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               android:layout_width="fill_parent"
               android:layout_height="wrap_content"
               android:layout_weight="1"
               android:orientation="vertical"
               android:gravity="center_vertical">
 
     <TextView android:id="@+id/title"
-              android:textAppearance="?android:attr/textAppearanceLarge"
-              android:textColor="@color/dialogtitle_textcolor"
+              style="@style/GeckoDialogTitle"
               android:layout_width="fill_parent" 
               android:layout_height="wrap_content"
               android:paddingTop="6dip"
               android:paddingBottom="0dip"
               android:paddingLeft="10dip"
               android:paddingRight="10dip"/>
 
     <TextView android:id="@+id/host"
-              android:textAppearance="?android:attr/textAppearanceMedium"
-              android:textColor="@color/dialogtitle_textcolor"
-              android:layout_width="fill_parent" 
+              style="@style/GeckoDialogTitle.SubTitle"
+              android:layout_width="fill_parent"
               android:layout_height="wrap_content"
               android:paddingTop="2dip"
               android:paddingBottom="6dip"
-              android:paddingLeft="10dip"
-              android:paddingRight="10dip"/>
+              android:textSize="14sp"/>
 
 </LinearLayout>
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/resources/values-v14/styles.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+    
+    <style name="GeckoDialogTitle">
+        <!-- Override this to use a Holo theme on v14+ -->
+        <item name="android:textAppearance">@android:style/TextAppearance.Holo.DialogWindowTitle</item>
+    </style>
+
+</resources>
--- a/mobile/android/base/resources/values/dimens.xml
+++ b/mobile/android/base/resources/values/dimens.xml
@@ -39,16 +39,17 @@
     <dimen name="menu_popup_width">256dp</dimen>
     <dimen name="nav_button_border_width">0.75dp</dimen>
     <dimen name="prompt_service_group_padding_size">32dp</dimen>
     <dimen name="prompt_service_icon_size">72dp</dimen>
     <dimen name="prompt_service_icon_text_padding">10dp</dimen>
     <dimen name="prompt_service_inputs_padding">16dp</dimen>
     <dimen name="prompt_service_left_right_text_with_icon_padding">10dp</dimen>
     <dimen name="prompt_service_top_bottom_text_with_icon_padding">8dp</dimen>
+    <dimen name="prompt_service_min_list_item_height">48dp</dimen>
     <dimen name="remote_tab_child_row_height">64dp</dimen>
     <dimen name="remote_tab_group_row_height">26dp</dimen>
     <dimen name="popup_width">400dp</dimen>
     <dimen name="tab_thumbnail_height">90dp</dimen>
     <dimen name="tab_thumbnail_width">160dp</dimen>
     <dimen name="tabs_counter_size">22sp</dimen>
     <dimen name="tabs_panel_indicator_width">60dp</dimen>
     <dimen name="tabs_panel_list_padding">16dip</dimen>
--- a/mobile/android/base/resources/values/styles.xml
+++ b/mobile/android/base/resources/values/styles.xml
@@ -279,9 +279,15 @@
         <item name="android:textColor">@color/abouthome_section_title</item>
     </style>
 
     <style name="AboutHome.TextAppearance.SubTitle">
         <item name="android:textSize">12sp</item>
         <item name="android:textColor">@color/abouthome_section_subtitle</item>
     </style>
 
+    <style name="GeckoDialogTitle">
+        <item name="android:textAppearance">@android:style/TextAppearance.DialogWindowTitle</item>
+    </style>
+
+    <style name="GeckoDialogTitle.SubTitle" />
+
 </resources>
--- a/mobile/android/base/tests/BaseTest.java.in
+++ b/mobile/android/base/tests/BaseTest.java.in
@@ -32,16 +32,17 @@ import java.util.HashMap;
  */
 abstract class BaseTest extends ActivityInstrumentationTestCase2<Activity> {
     public static final int TEST_MOCHITEST = 0;
     public static final int TEST_TALOS = 1;
 
     private static final String TARGET_PACKAGE_ID = "org.mozilla.gecko";
     private static final String LAUNCH_ACTIVITY_FULL_CLASSNAME="@ANDROID_PACKAGE_NAME@.App";
     private static final int VERIFY_URL_TIMEOUT = 2000;
+    private static final int MAX_LIST_ATTEMPTS = 3;
     public static final int MAX_WAIT_MS = 3000;
 
     private static Class<Activity> mLauncherActivityClass;
     private Activity mActivity;
     protected Solo mSolo;
     protected Driver mDriver;
     protected Assert mAsserter;
     protected Actions mActions;
@@ -401,65 +402,84 @@ abstract class BaseTest extends Activity
     public final void verifyTabCount(int expectedTabCount) {
         Activity activity = getActivity();
         Element tabCount = mDriver.findElement(activity, "tabs_count");
         String tabCountText = tabCount.getText();
         int tabCountInt = Integer.parseInt(tabCountText);
         mAsserter.is(tabCountInt, expectedTabCount, "The correct number of tabs are opened");
     }
 
-    /**
-     * Click on the awesome bar, and return the ListView for the 
-     * All Pages ("Top Sites") tab.
-     */
-    protected ListView getAllPagesList(String waitText) {
-        Activity awesomeBarActivity = clickOnAwesomeBar();
-        waitForText(waitText);
-
-        ArrayList<ListView> views = mSolo.getCurrentListViews();
-        for (ListView view : views) {
-            if (view.getTag() == "allPages") {
-                return view;
+    private ListView getAwesomeList(String waitText, int expectedChildCount,
+         String clickText, String tagName, String callerName) {
+        ArrayList<ListView> views;
+        ListView tabView = null;
+        int childCount = 0;
+        for (int i = 0; i < MAX_LIST_ATTEMPTS; i++) {
+            tabView = null;
+            childCount = 0;
+            Activity awesomeBarActivity = clickOnAwesomeBar();
+            mSolo.clickOnText(clickText);
+            if (waitForText(waitText)) {
+                views = mSolo.getCurrentListViews();
+                for (ListView view : views) {
+                    if (view.getTag().equals(tagName)) {
+                        tabView = view;
+                        childCount = view.getAdapter().getCount();
+                        if (expectedChildCount < 0 || expectedChildCount == childCount) {
+                            return view;
+                        }
+                    }
+                }
             }
         }
+        if (tabView == null) {
+            mAsserter.dumpLog(callerName+" did not find ListView");
+        } else if (expectedChildCount >= 0) {
+            mAsserter.dumpLog(callerName+" found ListView with "+childCount+" children");
+        }
         return null;
     }
 
+    /**
+     * Click on the awesome bar, click on the Top Sites tab, and return 
+     * the ListView for the All Pages ("Top Sites") tab.
+     */
+    protected ListView getAllPagesList(String waitText, int expectedChildCount) {
+        return getAwesomeList(waitText, expectedChildCount, 
+            "Top Sites", "allPages", "getAllPagesList");
+    }
+
+    protected ListView getAllPagesList(String waitText) {
+        return getAllPagesList(waitText, -1);
+    }
+
     /** 
      * Click on the awesome bar, click on the Bookmarks tab, and return
      * the ListView for the Bookmarks tab.
      */
-    protected ListView getBookmarksList() {
-        Activity awesomeBarActivity = clickOnAwesomeBar();
-        mSolo.clickOnText("Bookmarks");
+    protected ListView getBookmarksList(String waitText, int expectedChildCount) {
+        return getAwesomeList(waitText, expectedChildCount, 
+            "Bookmarks", "bookmarks", "getBookmarksList");
+    }
 
-        ArrayList<ListView> views = mSolo.getCurrentListViews();
-        for (ListView view : views) {
-            if (view.getTag().equals("bookmarks")) {
-                return view;
-            }
-        }
-        return null;
+    protected ListView getBookmarksList(String waitText) {
+        return getBookmarksList(waitText, -1);
     }
 
     /**
      * Click on the awesome bar, click on the History tab, and return
      * the ListView for the History tab.
      */
-    protected ListView getHistoryList() {
-        Activity awesomeBarActivity = clickOnAwesomeBar();
-        mSolo.clickOnText("History");
-        waitForText("Today|Yesterday");
-        ArrayList<ListView> views = mSolo.getCurrentListViews();
-        for (ListView view : views) {
-            if (view.getTag().equals("history")) {
-                return view;
-            }
-        }
-        return null;
+    protected ListView getHistoryList(String waitText, int expectedChildCount) {
+        return getAwesomeList(waitText, expectedChildCount, 
+            "History", "history", "getHistoryList");
+    }
+
+    protected ListView getHistoryList(String waitText) {
+        return getHistoryList(waitText, -1);
     }
 
     public long addOrUpdateBookmark(String title, String url, boolean bookmarklet) {
         ContentResolver resolver = getActivity().getContentResolver();
         Uri bookmarksUri = Uri.parse("content://@ANDROID_PACKAGE_NAME@.db.browser/bookmarks");
         bookmarksUri = bookmarksUri.buildUpon().appendQueryParameter("profile", "default").build();
         long folderId = -1;
         Cursor c = null;
--- a/mobile/android/base/tests/robocop.ini
+++ b/mobile/android/base/tests/robocop.ini
@@ -1,9 +1,9 @@
-# [testAllPagesTab] # see bug 825152
+[testAllPagesTab]
 [testHistoryTab]
 [testBookmarksTab]
 [testAwesomebar]
 [testAwesomebarSwipes]
 [testBookmark]
 [testBookmarklets]
 [testMigration]
 [testLoad]
--- a/mobile/android/base/tests/testAllPagesTab.java.in
+++ b/mobile/android/base/tests/testAllPagesTab.java.in
@@ -51,31 +51,30 @@ public class testAllPagesTab extends Bas
         loadUrl(url);
 
         testList(url);
         testClick(url);
         testContextMenu(url);
     }
 
     private void testList(String url) {
-        final ListView list = getAllPagesList(bookmarks[0]);
+        final ListView list = getAllPagesList(bookmarks[0], 5);
 
         // some basic checks for the tab strip
         TabWidget tabwidget = (TabWidget)mSolo.getView(TabWidget.class, 0);
         mAsserter.is(tabwidget.getTabCount(), 3, "Three tabs shown");
         mAsserter.is(tabwidget.isStripEnabled(), false, "Strip is hidden");
 
         // check that the right tab is selected
         TabHost host = (TabHost)mSolo.getView(TabHost.class, 0);
         // This test fails, only when we're running tests
         // mAsserter.is(host.getCurrentTab(), 0, "All pages tab is selected in tab strip");
 
-        mAsserter.isnot(list, null, "checking that all pages list exists");
+        mAsserter.isnot(list, null, "checking that all pages list exists and has 5 children (the default bookmarks)");
         final int count = list.getAdapter().getCount();
-        mAsserter.is(count, 5, "all pages list has 5 children (the default bookmarks)");
 
         String loadUrl = "";
         for (int i = count - 1; i >= 0; i--) {
             View child = list.getChildAt(i);
 
             ArrayList<View> views = mSolo.getViews(child);
             ArrayList<ImageView> imageViews = new ArrayList<ImageView>();
 
--- a/mobile/android/base/tests/testBookmark.java.in
+++ b/mobile/android/base/tests/testBookmark.java.in
@@ -71,28 +71,22 @@ public class testBookmark extends PixelT
     }
 
     public void runAwesomeScreenTest() {
         final long PAINT_CLEAR_DELAY = 1000;  // milliseconds
 
         blockForGeckoReady();
 
         // Open the bookmark list and check the root folder view
-        ListView bookmarksList = getBookmarksList();
+        ListView bookmarksList = getBookmarksList(ABOUT_HOME_URL, 4);
 
-        // Wait for bookmark to appear in list
-        waitForText(ABOUT_HOME_URL);
-
-        mAsserter.ok(bookmarksList != null, "checking that bookmarks list exists", "bookmarks list exists");
+        mAsserter.ok(bookmarksList != null, "checking that bookmarks list exists", "bookmarks list exists and has 4 children (the default bookmarks)");
 
         // No folders should be visible if no desktop bookmarks exist
         int count = bookmarksList.getAdapter().getCount();
-        mAsserter.is(count, 4,
-            "bookmarks list has 4 children (the default bookmarks)");
-
         for (int i = 0; i < count; i++) {
             Cursor c = (Cursor)bookmarksList.getItemAtPosition(i);
             String url = c.getString(c.getColumnIndexOrThrow("url"));
             mAsserter.ok(Arrays.binarySearch(defaultBookmarks, url) > -1,
                          "Find default bookmark", "Default bookmark for " + url + " found");
         }
 
         insertOneBookmark();
--- a/mobile/android/base/tests/testBookmarklets.java.in
+++ b/mobile/android/base/tests/testBookmarklets.java.in
@@ -38,33 +38,31 @@ public class testBookmarklets extends Pi
         }, 3000);
         mAsserter.is(alerted, false, "Alert was not shown for user-entered bookmarklet");
 
         // add the bookmarklet to the database. there's currently no way to
         // add this using the UI, so we go through the content provider.
         addOrUpdateBookmark(title, js, true);
 
         // verify that bookmarklets clicked in awesomescreen work
-        ListView bookmarks = getBookmarksList();
+        ListView bookmarks = getBookmarksList(title);
 
         Boolean found = false;
         if (bookmarks == null) {
             mAsserter.is(true, true, "Did not find the bookmarks section in the awesomebar");
-        } else if (mSolo.waitForText(title)) {
+        } else {
             for (int i = 0; i < bookmarks.getAdapter().getCount(); i++) {
                 Cursor c = (Cursor)bookmarks.getItemAtPosition(i);
                 String turl = c.getString(c.getColumnIndexOrThrow("url"));
                 if (turl.equals(js)) {
                     found = true;
                     mAsserter.is(1, 1, "Found bookmarklet added to bookmarks: " + js);
                     mSolo.clickOnView(bookmarks.getChildAt(i));
                 }
             }
-        } else {
-            mAsserter.is(true, true, "Did not find the title '" + title + "' of the bookmark in the list");
         }
         if (!found) {
             mAsserter.is(found, true, "Found the bookmark: " + js + " and clicked on it");
         }
 
         alerted = waitForTest(new BooleanTest() {
             @Override
             public boolean test() {
--- a/mobile/android/base/tests/testBookmarksTab.java.in
+++ b/mobile/android/base/tests/testBookmarksTab.java.in
@@ -13,25 +13,24 @@ import android.widget.ImageView;
 import android.widget.TabHost;
 import android.text.TextUtils;
 
 import java.util.Arrays;
 import java.util.ArrayList;
 import java.io.File;
 
 /**
- * Tests the Bookamrks Tab
+ * Tests the Bookmarks Tab
  * - opening the bookmarks tab
  * - items look correct
  * - clicking on an item
  * - long tapping on an item
  * - editing the name, url and keyword of a bookmark from the context menu
  * - removing a bookmark
  */
-
 public class testBookmarksTab extends BaseTest {
     private View mFirstChild;
     private ListView list;
 
     @Override
     protected int getTestType() {
         return TEST_MOCHITEST;
     }
@@ -44,24 +43,20 @@ public class testBookmarksTab extends Ba
         addOrUpdateBookmark("BOOKMARK_TITLE", url, false);
 
         testList(url);
         testContextMenu(url);
     }
 
     private void testList(String url) {
         View child;
-        ListView list = getBookmarksList();
-
-        waitForText("Desktop Bookmarks");
-        mAsserter.isnot(list, null, "checking that bookmarks list exists");
+        ListView list = getBookmarksList("about:firefox", 5);
+        mAsserter.isnot(list, null, "checking that bookmarks list exists and has 5 children (defaults + a folder)");
 
         int count = list.getAdapter().getCount();
-        mAsserter.is(count, 5, "bookmarks list has 5 children (defaults + a folder)");
- 
         for (int i = count - 1; i >= 0; i--) {
             child = list.getChildAt(i);
             compareRow(child, i == 0 ? 1 : 2, 1);
         }
 
         child = list.getChildAt(0);
         mSolo.clickOnView(child);
         waitForText("Bookmarks Toolbar");
@@ -90,19 +85,17 @@ public class testBookmarksTab extends Ba
 
         mActions.sendSpecialKey(Actions.SpecialKey.BACK);
         mAsserter.ok(mSolo.waitForText("about:home"), "Back moved up one level", "");
 
         mActions.sendSpecialKey(Actions.SpecialKey.BACK);
     }
 
     private void testContextMenu(String url) {
-        list = getBookmarksList();
-        waitForText(url);
-
+        list = getBookmarksList(url);
         // wait for the bookmarks list to be populated
         View child;
         mFirstChild = null;
         boolean success = waitForTest(new BooleanTest() {
             @Override
             public boolean test() {
                 mFirstChild = list.getChildAt(1);
                 if (mFirstChild == null) {
@@ -145,17 +138,17 @@ public class testBookmarksTab extends Ba
             // test long tap on a folder, this should fail but will still open the folder
             child = list.getChildAt(0);
             mSolo.clickLongOnView(child);
             mAsserter.is(mSolo.waitForText("Open in New Tab"), false, "Folders have no context menu");
         } else {
             mAsserter.ok(false, "waiting for bookmark item", "bookmark item available");
         }
 
-        list = getBookmarksList();
+        list = getBookmarksList(url);
 
         // Test edit bookmark name
         editBookmark(1,0," Bookmark Name ");
         mAsserter.is(checkBookmarkEdit(1," Bookmark Name "), true, "Bookmark Name was changed");
 
         // Test edit bookmark link
         editBookmark(1,1," Bookmark Link ");
         mAsserter.is(checkBookmarkEdit(1,"Bookmark Link"), true, "Bookmark Link was changed");
@@ -167,17 +160,17 @@ public class testBookmarksTab extends Ba
         // Remove Bookmark from Context Menu
         waitForText("Bookmarks");
         child = list.getChildAt(1);
         mSolo.clickLongOnView(child);
         waitForText("Open in New Tab");
         mSolo.clickOnText("Remove");
 
         // Wait for the toaster notification
-        waitForText("Bookmark Removed");
+        waitForText("Bookmark removed");
 
         // Verify Bookmark is removed
         child = list.getChildAt(1);
         mSolo.clickLongOnView(child);
         waitForText("Open in New Tab");
         mAsserter.is(mSolo.searchText("Bookmark Name"), false, "Removed bookmark has been deleted");
         mActions.sendSpecialKey(Actions.SpecialKey.BACK); // Exit the Context Menu
 
@@ -186,59 +179,59 @@ public class testBookmarksTab extends Ba
     }
 
     private void editBookmark(int bookmarkIndex, int fieldIndex, String addedText) {
 
         // Open the Edit Bookmark context menu
         View child;
         mSolo.clickOnText("Bookmarks");
         child = list.getChildAt(bookmarkIndex);
-        waitForText("Desktop Bookmarks");
+        waitForText("about:firefox");
         mSolo.clickLongOnView(child);
         waitForText("Open in New Tab");
         mSolo.clickOnText("Edit");
         waitForText("Edit Bookmark");
 
         // Clear the Field
         mSolo.clearEditText(fieldIndex);
 
         // Enter the new text
         mSolo.clickOnEditText(fieldIndex);
         mActions.sendKeys(addedText);
         mSolo.clickOnText("OK");
-        waitForText("Bookmark Updated");
+        waitForText("Bookmark updated");
         mActions.sendSpecialKey(Actions.SpecialKey.BACK); // close the VKB
     }
 
     private boolean checkBookmarkEdit(int bookmarkIndex, String addedText) {
         Device mDevice = new Device();
         // Open the Edit Bookmark context menu
         View child;
         mSolo.clickOnText("Bookmarks");
         child = list.getChildAt(bookmarkIndex);
-        waitForText("Desktop Bookmarks");
+        waitForText("about:firefox");
         mSolo.clickLongOnView(child);
         waitForText("Open in New Tab");
         mSolo.clickOnText("Edit");
         waitForText("Edit Bookmark");
 
         // If the OS is not Gingerbread the vkb will be opened so we need to close it in order to press the "Cancel" button
         if (!(mDevice.version.equals("2.x"))) {
             mActions.sendSpecialKey(Actions.SpecialKey.BACK); // close the VKB
         }
 
         // Check if the new text was added
         if (mSolo.searchText(addedText)) {
            mSolo.clickOnText("Cancel");
-           waitForText("Desktop Bookmarks");
+           waitForText("about:firefox");
            mActions.sendSpecialKey(Actions.SpecialKey.BACK); // close the VKB
            return true;
         } else {
            mSolo.clickOnText("Cancel");
-           waitForText("Desktop Bookmarks");
+           waitForText("about:firefox");
            mActions.sendSpecialKey(Actions.SpecialKey.BACK); // close the VKB
            return false;
         }
     }
 
     private void compareRow(View child, int numTextViews, int numImageViews) {
         ArrayList<View> views = mSolo.getViews(child);
         ArrayList<ImageView> imageViews = new ArrayList<ImageView>();
--- a/mobile/android/base/tests/testClearPrivateData.java.in
+++ b/mobile/android/base/tests/testClearPrivateData.java.in
@@ -23,30 +23,30 @@ public class testClearPrivateData extend
         clearHistory();
     }
 
     private void clearHistory() {
         // Loading a page so we are sure that there is at leats one history entry
         String url = getAbsoluteUrl("/robocop/robocop_blank_01.html");
         loadAndPaint(url);
 
-        // Checking that the history list in not empty
-        ListView hList = getHistoryList();
+        // Checking that the history list is not empty
+        ListView hList = getHistoryList("Today|Yesterday");
         mAsserter.ok(hList.getAdapter().getCount() > 0,"checking history exists","history exists");
 
         // Quit the awesomescreen
         mActions.sendSpecialKey(Actions.SpecialKey.BACK);
         waitForText("Browser Blank Page 01");
 
         // Clearing private data
         selectMenuItem("Settings");
         if (waitForText("^Clear private data$")) {
             mSolo.clickOnText("^Clear private data$");
         }
         mAsserter.ok(mSolo.searchButton("Clear data"),"checking clear button","clear button exists");
         mSolo.clickOnButton("Clear data");
         mAsserter.is(mSolo.waitForText("Private data cleared"),true,"private data cleared successfully");
 
         // Checking that history list is empty
-        hList = getHistoryList();
-        mAsserter.ok(hList.getAdapter().getCount() == 0,"checking history is cleared ","history is cleared");
+        hList = getHistoryList("History", 0);
+        mAsserter.ok(hList != null,"checking history is cleared ","history is cleared");
     }
 }
--- a/mobile/android/base/tests/testDoorHanger.java.in
+++ b/mobile/android/base/tests/testDoorHanger.java.in
@@ -71,27 +71,27 @@ public class testDoorHanger extends Base
         // Test doorhanger dismissed when tapping "Allow" and is not displayed again
         mSolo.clickOnText("Allow");
         mAsserter.is(mSolo.searchText("wants to store data on your device for offline use"), false, "Doorhanger notification is hidden");
         loadUrl(OFFLINE_STORAGE_URL);
         mAsserter.is(mSolo.searchText("wants to store data on your device for offline use"), false, "Doorhanger is no longer triggered");
 
         // Load login page
         loadUrl(LOGIN_URL);
-        waitForText("to remeber password for");
+        waitForText("to remember password for");
 
         // Test doorhanger is dismissed when tapping "Not Now"
         mSolo.clickOnText("Not Now");
-        mAsserter.is(mSolo.searchText("to remeber password for"), false, "Doorhanger notification is hidden");
+        mAsserter.is(mSolo.searchText("to remember password for"), false, "Doorhanger notification is hidden");
 
         // Load login page
         loadUrl(LOGIN_URL);
         waitForText("prevented this site from opening");
 
         // Test doorhanger is dismissed when tapping "Never show" and is no longer triggered
         mSolo.clickOnText("Remember");
-        mAsserter.is(mSolo.searchText("to remeber password for"), false, "Doorhanger notification is hidden");
+        mAsserter.is(mSolo.searchText("to remember password for"), false, "Doorhanger notification is hidden");
 
         // Reload the page and check that there is no doorhanger displayed
         loadUrl(LOGIN_URL);
-        mAsserter.is(mSolo.searchText("to remeber password for"), false, "Doorhanger notification is hidden");
+        mAsserter.is(mSolo.searchText("to remember password for"), false, "Doorhanger notification is hidden");
     }
 }
--- a/mobile/android/base/tests/testHistoryTab.java.in
+++ b/mobile/android/base/tests/testHistoryTab.java.in
@@ -93,35 +93,24 @@ public class testHistoryTab extends Pixe
         mAsserter.is(mSolo.waitForText("Bookmark added"), true, "bookmark added successfully");
 
         testList(url);
         testContextMenu(url);
         testClick(url);
     }
 
     private void testList(String url) {
-        listview = getHistoryList();
-
-        // Around midnight we will switch from Today -> Yesterday, account for both
-        if (!mSolo.waitForText("Today")) {
-            waitForText("Yesterday");
-        }
-
-        mAsserter.isnot(listview,  null, "checking that history list exists");
-
+        listview = getHistoryList("Today|Yesterday", 3);
+        mAsserter.isnot(listview,  null, "checking that history list exists and has 3 children");
         final int count = listview.getAdapter().getCount();
-        mAsserter.is(count, 3, "history list has 3 children");
-
         String loadUrl = "";
         for (int i = count - 1; i >= 0; i--) {
             View child = listview.getChildAt(i);
-
             ArrayList<View> views = mSolo.getViews(child);
             ArrayList<ImageView> imageViews = new ArrayList<ImageView>();
-
             int expectedImages = 1;
             for (int j = 0; j < views.size(); j++) {
                 View v = views.get(j);
                 if (i == 0) {
                     ArrayList<TextView> views2 = mSolo.getCurrentTextViews(v);
                     TextView t = views2.get(0);
                     String string = t.getText().toString();
                     boolean headerTextOK = string.equals("Today");
@@ -155,17 +144,17 @@ public class testHistoryTab extends Pixe
 
             mAsserter.is(visible, expectedImages, "Correct number of ImageViews visible");
         }
 
         mActions.sendSpecialKey(Actions.SpecialKey.BACK);
     }
 
     private void testContextMenu(String url) {
-        listview = getHistoryList();
+        listview = getHistoryList("Today|Yesterday");
         waitForText(url);
 
         // wait for the history list to be populated
         mFirstChild = null;
         boolean success = waitForTest(new BooleanTest() {
             @Override
             public boolean test() {
                 mFirstChild = listview.getChildAt(1);
@@ -208,18 +197,17 @@ public class testHistoryTab extends Pixe
 
         } else {
             mAsserter.ok(false, "waiting for history item", "history item available");
         }
         mActions.sendSpecialKey(Actions.SpecialKey.BACK);
     }
 
     private void testClick(String url) {
-        listview = getHistoryList();
-
+        listview = getHistoryList("Today|Yesterday");
         waitForText(url);
 
         View child = listview.getChildAt(0);
         mSolo.clickOnView(child);
         // nothing should happen
 
         Actions.EventExpecter contentEventExpecter = mActions.expectGeckoEvent("DOMContentLoaded");
         mFirstChild = null;
--- a/mobile/android/base/tests/testSearchSuggestions.java.in
+++ b/mobile/android/base/tests/testSearchSuggestions.java.in
@@ -37,19 +37,16 @@ public class testSearchSuggestions exten
 
         // Map of expected values. See robocop_suggestions.sjs.
         final HashMap<String, ArrayList<String>> suggestMap = new HashMap<String, ArrayList<String>>();
         buildSuggestMap(suggestMap);
 
         final int suggestionLayoutId = mDriver.findElement(getActivity(), "suggestion_layout").getId();
         final int suggestionTextId = mDriver.findElement(getActivity(), "suggestion_text").getId();
 
-        // workaround for bug 769524
-        mSolo.sleep(5000);
-
         Actions.EventExpecter enginesEventExpecter = mActions.expectGeckoEvent("SearchEngines:Data");
         final Activity awesomeBarActivity = clickOnAwesomeBar();
         enginesEventExpecter.blockForEvent();
         connectSuggestClient(awesomeBarActivity);
 
         for (int i = 0; i < TEST_QUERY.length(); i++) {
             mActions.sendKeys(TEST_QUERY.substring(i, i+1));
 
--- a/mobile/android/base/tests/testShareLink.java.in
+++ b/mobile/android/base/tests/testShareLink.java.in
@@ -30,17 +30,17 @@ public class testShareLink extends BaseT
     public void testShareLink() {
         url = getAbsoluteUrl("/robocop/robocop_big_link.html");
         ArrayList<String> shareOptions;
         blockForGeckoReady();
 
         loadUrl(url);
         waitForText("Big Link"); // Waiting for page title to ensure the page is loaded
         selectMenuItem("Share");
-        waitForText("Share Via");
+        waitForText("Share via");
 
         // Get list of current avaliable share activities and verify them
         shareOptions = getShareOptions();
         ArrayList<String> displayedOptions = getSharePopupOption();
         for (String option:shareOptions) {
              // Verify if the option is present in the list of displayed share options
              mAsserter.ok(optionDisplayed(option, displayedOptions), "Share option found", option);
         }
@@ -74,34 +74,32 @@ public class testShareLink extends BaseT
             verifySharePopup(shareOptions,"Top Sites");
         } else {
             // The view should not be null but sometimes getChildAt fails
             // TODO: Investigate why this fails
             mAsserter.todo_isnot(allpages, null, "View should not be null but sometimes it is");
         }
 
         // Test the share popup in the Bookmarks tab
-        ListView blist = getBookmarksList();
-        mSolo.clickOnText("Bookmarks");
+        ListView blist = getBookmarksList("about:firefox");
         View bookmark = blist.getChildAt(1); // Getting child at 1 because 0 might be the Desktop folder
         mSolo.clickLongOnView(bookmark);
         verifySharePopup(shareOptions,"bookmarks");
 
         // Test the share popup in the History tab
-        ListView hlist = getHistoryList();
-        mSolo.clickOnText("History");
+        ListView hlist = getHistoryList("Today|Yesterday");
         View history = hlist.getChildAt(1); // Getting child at 1 because 0 might be the "Today" label
         mSolo.clickLongOnView(history);
         verifySharePopup(shareOptions,"history");
     }
 
     public void verifySharePopup(ArrayList<String> shareOptions, String openedFrom) {
         waitForText("Share");
         mSolo.clickOnText("Share");
-        waitForText("Share Via");
+        waitForText("Share via");
         ArrayList<String> displayedOptions = getSharePopupOption();
         for (String option:shareOptions) {
              // Verify if the option is present in the list of displayed share options
              mAsserter.ok(optionDisplayed(option, displayedOptions), "Share option for " + openedFrom + (openedFrom.equals("Awesomebar") ? "" : " item") + " found", option);
         }
         mActions.sendSpecialKey(Actions.SpecialKey.BACK);
     }
 
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -2391,19 +2391,16 @@ var SelectionHandler = {
 
     sendMessageToJava({
       type: "TextSelection:HideHandles",
       handles: [this.HANDLE_TYPE_MIDDLE]
     });
   },
 
   positionHandles: function sh_positionHandles() {
-    // Translate coordinates to account for selections in sub-frames. We can't cache
-    // this because the top-level page may have scrolled since selection started.
-    let offset = this._getViewOffset();
     let scrollX = {}, scrollY = {};
     this._view.top.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).getScrollXY(false, scrollX, scrollY);
 
     // the checkHidden function tests to see if the given point is hidden inside an
     // iframe/subdocument. this is so that if we select some text inside an iframe and
     // scroll the iframe so the selection is out of view, we hide the handles rather
     // than having them float on top of the main page content.
     let checkHidden = function(x, y) {
@@ -2413,36 +2410,43 @@ var SelectionHandler = {
       let bounds = this._view.frameElement.getBoundingClientRect();
       checkHidden = function(x, y) {
         return x < 0 || y < 0 || x > bounds.width || y > bounds.height;
       }
     }
 
     let positions = null;
     if (this._activeType == this.TYPE_CURSOR) {
+      // The left and top properties returned are relative to the client area
+      // of the window, so we don't need to account for a sub-frame offset.
       let cursor = this._cwu.sendQueryContentEvent(this._cwu.QUERY_CARET_RECT, this._target.selectionEnd, 0, 0, 0);
       let x = cursor.left;
       let y = cursor.top + cursor.height;
-      positions = [ { handle: this.HANDLE_TYPE_MIDDLE,
-                     left: x + offset.x + scrollX.value,
-                     top: y + offset.y + scrollY.value,
-                     hidden: checkHidden(x, y) } ];
+      positions = [{ handle: this.HANDLE_TYPE_MIDDLE,
+                     left: x + scrollX.value,
+                     top: y + scrollY.value,
+                     hidden: checkHidden(x, y) }];
     } else {
       let sx = this.cache.start.x;
       let sy = this.cache.start.y;
       let ex = this.cache.end.x;
       let ey = this.cache.end.y;
-      positions = [ { handle: this.HANDLE_TYPE_START,
+
+      // Translate coordinates to account for selections in sub-frames. We can't cache
+      // this because the top-level page may have scrolled since selection started.
+      let offset = this._getViewOffset();
+
+      positions = [{ handle: this.HANDLE_TYPE_START,
                      left: sx + offset.x + scrollX.value,
                      top: sy + offset.y + scrollY.value,
                      hidden: checkHidden(sx, sy) },
                    { handle: this.HANDLE_TYPE_END,
                      left: ex + offset.x + scrollX.value,
                      top: ey + offset.y + scrollY.value,
-                     hidden: checkHidden(ex, ey) } ];
+                     hidden: checkHidden(ex, ey) }];
     }
 
     sendMessageToJava({
       type: "TextSelection:PositionHandles",
       positions: positions,
       rtl: this._isRTL
     });
   },
@@ -3072,18 +3076,18 @@ Tab.prototype = {
     // visible zoom. for foreground tabs, however, if we are drawing at some other
     // resolution, we need to set the resolution as specified.
     let cwu = window.top.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
     if (BrowserApp.selectedTab == this) {
       if (resolution != this._drawZoom) {
         this._drawZoom = resolution;
         cwu.setResolution(resolution, resolution);
       }
-    } else if (resolution != zoom) {
-      dump("Warning: setDisplayPort resolution did not match zoom for background tab!");
+    } else if (Math.abs(resolution - zoom) >= 1e-6) {
+      dump("Warning: setDisplayPort resolution did not match zoom for background tab! (" + resolution + " != " + zoom + ")");
     }
 
     // Finally, we set the display port, taking care to convert everything into the CSS-pixel
     // coordinate space, because that is what the function accepts. Also we have to fudge the
     // displayport somewhat to make sure it gets through all the conversions gecko will do on it
     // without deforming too much. See https://bugzilla.mozilla.org/show_bug.cgi?id=737510#c10
     // for details on what these operations are.
     let geckoScrollX = this.browser.contentWindow.scrollX;
@@ -3938,17 +3942,19 @@ Tab.prototype = {
   },
 
   observe: function(aSubject, aTopic, aData) {
     switch (aTopic) {
       case "before-first-paint":
         // Is it on the top level?
         let contentDocument = aSubject;
         if (contentDocument == this.browser.contentDocument) {
-          BrowserApp.displayedDocumentChanged();
+          if (BrowserApp.selectedTab == this) {
+            BrowserApp.displayedDocumentChanged();
+          }
           this.contentDocumentIsDisplayed = true;
 
           // reset CSS viewport and zoom to default on new page, and then calculate
           // them properly using the actual metadata from the page. note that the
           // updateMetadata call takes into account the existing CSS viewport size
           // and zoom when calculating the new ones, so we need to reset these
           // things here before calling updateMetadata.
           this.setBrowserSize(kDefaultCSSViewportWidth, kDefaultCSSViewportHeight);
@@ -5173,28 +5179,16 @@ var FormAssistant = {
       if (filter && label.toLowerCase().indexOf(lowerFieldValue) == -1)
         continue;
       suggestions.push({ label: label, value: item.value });
     }
 
     return suggestions;
   },
 
-  // Gets the element position data necessary for the Java UI to position
-  // the form assist popup.
-  _getElementPositionData: function _getElementPositionData(aElement) {
-    let rect = ElementTouchHelper.getBoundingContentRect(aElement);
-    let viewport = BrowserApp.selectedTab.getViewport();
-    
-    return { rect: [rect.x - (viewport.x / viewport.zoom),
-                    rect.y - (viewport.y / viewport.zoom),
-                    rect.w, rect.h],
-             zoom: viewport.zoom }
-  },
-
   // Retrieves autocomplete suggestions for an element from the form autocomplete service
   // and sends the suggestions to the Java UI, along with element position data.
   // Returns true if there are suggestions to show, false otherwise.
   _showAutoCompleteSuggestions: function _showAutoCompleteSuggestions(aElement) {
     if (!this._isAutoComplete(aElement))
       return false;
 
     // Don't display the form auto-complete popup after the user starts typing
@@ -5209,22 +5203,20 @@ var FormAssistant = {
     // On desktop, we show datalist suggestions below autocomplete suggestions,
     // without duplicates removed.
     let suggestions = autoCompleteSuggestions.concat(listSuggestions);
 
     // Return false if there are no suggestions to show
     if (!suggestions.length)
       return false;
 
-    let positionData = this._getElementPositionData(aElement);
     sendMessageToJava({
       type:  "FormAssist:AutoComplete",
       suggestions: suggestions,
-      rect: positionData.rect,
-      zoom: positionData.zoom
+      rect: ElementTouchHelper.getBoundingContentRect(aElement)
     });
 
     // Keep track of input element so we can fill it in if the user
     // selects an autocomplete suggestion
     this._currentInputElement = aElement;
 
     return true;
   },
@@ -5244,22 +5236,20 @@ var FormAssistant = {
   },
 
   // Sends a validation message and position data for an element to the Java UI.
   // Returns true if there's a validation message to show, false otherwise.
   _showValidationMessage: function _sendValidationMessage(aElement) {
     if (!this._isValidateable(aElement))
       return false;
 
-    let positionData = this._getElementPositionData(aElement);
     sendMessageToJava({
       type: "FormAssist:ValidationMessage",
       validationMessage: aElement.validationMessage,
-      rect: positionData.rect,
-      zoom: positionData.zoom
+      rect: ElementTouchHelper.getBoundingContentRect(aElement)
     });
 
     return true;
   },
 
   _hideFormAssistPopup: function _hideFormAssistPopup() {
     sendMessageToJava({ type: "FormAssist:Hide" });
   }
--- a/toolkit/components/satchel/test/test_form_autocomplete.html
+++ b/toolkit/components/satchel/test/test_form_autocomplete.html
@@ -770,17 +770,17 @@ function runTest(testNum) {
         restoreForm();
         doKey("down");
         break;
 
       case 407:
         checkMenuEntries([]); // type=range does not have a drop down menu
         doKey("down");
         doKey("return");
-        checkForm("32"); // default (midway between minimum (0) and maximum (64))
+        checkForm("30"); // default (midway between minimum (0) and maximum (64)) - step
 
         // Go to test 500.
         fh.addEntry("field1", "value1");
         input = $_(1, "field1");
         testNum = 499;
 
         restoreForm();
         doKey("down");
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -1,18 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 <algorithm>
 
-#ifdef XP_MACOSX
 #include <fstream>
-#endif
 
 #include <prio.h>
 
 #include "mozilla/Attributes.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Likely.h"
 
 #include "base/histogram.h"
@@ -1634,17 +1632,16 @@ IsValidBreakpadId(const std::string &bre
   return true;
 }
 
 // Read a stack from the given file name. In case of any error, aStack is
 // unchanged.
 static void
 ReadStack(const char *aFileName, Telemetry::ProcessedStack &aStack)
 {
-#ifdef XP_MACOSX
   std::ifstream file(aFileName);
 
   size_t numModules;
   file >> numModules;
   if (file.fail()) {
     return;
   }
 
@@ -1702,17 +1699,16 @@ ReadStack(const char *aFileName, Telemet
     Telemetry::ProcessedStack::Frame frame = {
       offset,
       index
     };
     stack.AddFrame(frame);
   }
 
   aStack = stack;
-#endif
 }
 
 void
 TelemetryImpl::ReadLateWritesStacks()
 {
   nsCOMPtr<nsIFile> profileDir;
   nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
                                        getter_AddRefs(profileDir));
--- a/toolkit/content/tests/chrome/test_bug451286.xul
+++ b/toolkit/content/tests/chrome/test_bug451286.xul
@@ -42,17 +42,18 @@ https://bugzilla.mozilla.org/show_bug.cg
         // stack.  We need to GC everything in that window, so do that
         // from a timeout and then call SimpleTest.finish().
         setTimeout(doFinish, 0);
       }
 
       function doFinish() {
         // Garbage collect objects created in this test can cause
         // assertions, so GC now to blame those assertions to this test.
-        SpecialPowers.gc();
+        SpecialPowers.forceGC();
+        SpecialPowers.forceCC();
         SimpleTest.finish();
       }
 
       /** Test for Bug 451286 **/
       SimpleTest.waitForExplicitFinish();
       window.open("bug451286_window.xul", "451286test", 
                   "chrome,width=600,height=600");
 
--- a/toolkit/modules/Timer.jsm
+++ b/toolkit/modules/Timer.jsm
@@ -18,20 +18,21 @@ Cu.import("resource://gre/modules/XPCOMU
 
 // This gives us >=2^30 unique timer IDs, enough for 1 per ms for 12.4 days.
 let gNextTimeoutId = 1; // setTimeout must return a positive integer
 
 let gTimeoutTable = new Map(); // int -> nsITimer
 
 this.setTimeout = function setTimeout(aCallback, aMilliseconds) {
   let id = gNextTimeoutId++;
+  let args = Array.slice(arguments, 2);
   let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
   timer.initWithCallback(function setTimeout_timer() {
     gTimeoutTable.delete(id);
-    aCallback();
+    aCallback.apply(null, args);
   }, aMilliseconds, timer.TYPE_ONE_SHOT);
 
   gTimeoutTable.set(id, timer);
   return id;
 }
 
 this.clearTimeout = function clearTimeout(aId) {
   if (gTimeoutTable.has(aId)) {
--- a/toolkit/modules/tests/xpcshell/test_timer.js
+++ b/toolkit/modules/tests/xpcshell/test_timer.js
@@ -10,19 +10,21 @@ Components.utils.import("resource://gre/
 
 function run_test(browser, tab, document) {
   do_test_pending();
 
   let timeout1 = imported.setTimeout(function() do_throw("Should not be called"), 100);
   do_check_eq(typeof timeout1, "number", "setTimeout returns a number");
   do_check_true(timeout1 > 0, "setTimeout returns a positive number");
 
-  let timeout2 = imported.setTimeout(function() {
+  let timeout2 = imported.setTimeout(function(param1, param2) {
     do_check_true(true, "Should be called");
+    do_check_eq(param1, 5, "first parameter is correct");
+    do_check_eq(param2, "test", "second parameter is correct");
     do_test_finished();
-  }, 100);
+  }, 100, 5, "test");
 
   do_check_eq(typeof timeout2, "number", "setTimeout returns a number");
   do_check_true(timeout2 > 0, "setTimeout returns a positive number");
   do_check_neq(timeout1, timeout2, "Calling setTimeout again returns a different value");
 
   imported.clearTimeout(timeout1);
 }
--- a/toolkit/themes/windows/global/global.css
+++ b/toolkit/themes/windows/global/global.css
@@ -21,20 +21,16 @@ menulist > menupopup,
 .menulist-menupopup {
   -moz-binding: url("chrome://global/content/bindings/popup.xml#popup-scrollbars");
 }
 
 .menulist-compact {
   -moz-binding: url("chrome://global/skin/globalBindings.xml#menulist-compact");
 }
 
-progressmeter[mode="undetermined"] {
-  -moz-binding: url("chrome://global/content/bindings/progressmeter.xml#progressmeter-undetermined");
-}
-
 /* ::::: root elements ::::: */
 
 window,
 page,
 dialog,
 wizard,
 prefwindow {
   -moz-appearance: window;
--- a/widget/cocoa/nsNativeThemeCocoa.h
+++ b/widget/cocoa/nsNativeThemeCocoa.h
@@ -63,20 +63,16 @@ public:
 
 protected:  
 
   nsIntMargin RTLAwareMargin(const nsIntMargin& aMargin, nsIFrame* aFrame);
   nsIFrame* SeparatorResponsibility(nsIFrame* aBefore, nsIFrame* aAfter);
   CGRect SeparatorAdjustedRect(CGRect aRect, nsIFrame* aLeft,
                                nsIFrame* aCurrent, nsIFrame* aRight);
 
-  // Helpers for progressbar.
-  double GetProgressValue(nsIFrame* aFrame);
-  double GetProgressMaxValue(nsIFrame* aFrame);
-
   // HITheme drawing routines
   void DrawFrame(CGContextRef context, HIThemeFrameKind inKind,
                  const HIRect& inBoxRect, bool inReadOnly,
                  nsEventStates inState);
   void DrawProgress(CGContextRef context, const HIRect& inBoxRect,
                     bool inIsIndeterminate, bool inIsHorizontal,
                     double inValue, double inMaxValue, nsIFrame* aFrame);
   void DrawMeter(CGContextRef context, const HIRect& inBoxRect,
--- a/widget/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/cocoa/nsNativeThemeCocoa.mm
@@ -18,17 +18,16 @@
 #include "nsEventStates.h"
 #include "nsINameSpaceManager.h"
 #include "nsPresContext.h"
 #include "nsGkAtoms.h"
 #include "nsCocoaFeatures.h"
 #include "nsCocoaWindow.h"
 #include "nsNativeThemeColors.h"
 #include "nsIScrollableFrame.h"
-#include "nsIDOMHTMLProgressElement.h"
 #include "nsIDOMHTMLMeterElement.h"
 #include "mozilla/dom/Element.h"
 
 #include "gfxContext.h"
 #include "gfxQuartzSurface.h"
 #include "gfxQuartzNativeDrawing.h"
 #include <algorithm>
 
@@ -2989,44 +2988,8 @@ nsNativeThemeCocoa::GetWidgetTransparenc
     // Knowing that scrollbars and statusbars are opaque improves
     // performance, because we create layers for them.
     return eOpaque;
 
   default:
     return eUnknownTransparency;
   }
 }
-
-double
-nsNativeThemeCocoa::GetProgressValue(nsIFrame* aFrame)
-{
-  // When we are using the HTML progress element,
-  // we can get the value from the IDL property.
-  if (aFrame) {
-    nsCOMPtr<nsIDOMHTMLProgressElement> progress =
-      do_QueryInterface(aFrame->GetContent());
-    if (progress) {
-      double value;
-      progress->GetValue(&value);
-      return value;
-    }
-  }
-
-  return (double)CheckIntAttr(aFrame, nsGkAtoms::value, 0);
-}
-
-double
-nsNativeThemeCocoa::GetProgressMaxValue(nsIFrame* aFrame)
-{
-  // When we are using the HTML progress element,
-  // we can get the max from the IDL property.
-  if (aFrame) {
-    nsCOMPtr<nsIDOMHTMLProgressElement> progress =
-      do_QueryInterface(aFrame->GetContent());
-    if (progress) {
-      double max;
-      progress->GetMax(&max);
-      return max;
-    }
-  }
-
-  return (double)std::max(CheckIntAttr(aFrame, nsGkAtoms::max, 100), 1);
-}
--- a/widget/windows/Makefile.in
+++ b/widget/windows/Makefile.in
@@ -88,17 +88,17 @@ endif
 ifdef MOZ_ENABLE_D3D10_LAYER
 DEFINES		+= -DMOZ_ENABLE_D3D10_LAYER
 endif
 
 SHARED_LIBRARY_LIBS = \
   ../xpwidgets/$(LIB_PREFIX)xpwidgets_s.$(LIB_SUFFIX) \
   $(NULL)
 
-EXPORTS		= nsdefs.h WindowHook.h
+EXPORTS		= nsdefs.h WindowHook.h WinUtils.h
 EXPORTS_NAMESPACES = mozilla/widget
 EXPORTS_mozilla/widget = AudioSession.h
 
 LOCAL_INCLUDES	= \
 		-I. \
 		-I$(srcdir)/../xpwidgets \
 		-I$(srcdir)/../shared \
 		-I$(srcdir) \
--- a/widget/windows/WinUtils.cpp
+++ b/widget/windows/WinUtils.cpp
@@ -37,18 +37,22 @@ namespace widget {
   NS_IMPL_THREADSAFE_ISUPPORTS1(AsyncWriteIconToDisk, nsIRunnable)
   NS_IMPL_THREADSAFE_ISUPPORTS1(AsyncDeleteIconFromDisk, nsIRunnable)
   NS_IMPL_THREADSAFE_ISUPPORTS1(AsyncDeleteAllFaviconsFromDisk, nsIRunnable)
 
 
   const char FaviconHelper::kJumpListCacheDir[] = "jumpListCache";
   const char FaviconHelper::kShortcutCacheDir[] = "shortcutCache";
 
-// SHCreateItemFromParsingName is only available on vista and up.
-WinUtils::SHCreateItemFromParsingNamePtr WinUtils::sCreateItemFromParsingName = nullptr;
+// apis available on vista and up.
+WinUtils::SHCreateItemFromParsingNamePtr WinUtils::sCreateItemFromParsingName = NULL;
+WinUtils::SHGetKnownFolderPathPtr WinUtils::sGetKnownFolderPath = NULL;
+
+static const PRUnichar kSehllLibraryName[] =  L"shell32.dll";
+static HMODULE sShellDll = NULL;
 
 /* static */ 
 WinUtils::WinVersion
 WinUtils::GetWindowsVersion()
 {
   static int32_t version = 0;
 
   if (version) {
@@ -359,47 +363,65 @@ WinUtils::InitMSG(UINT aMessage, WPARAM 
   MSG msg;
   msg.message = aMessage;
   msg.wParam  = wParam;
   msg.lParam  = lParam;
   return msg;
 }
 
 /* static */
-bool
-WinUtils::VistaCreateItemFromParsingNameInit()
-{
-  // Load and store Vista+ SHCreateItemFromParsingName
-  if (sCreateItemFromParsingName) {
-    return true;
-  }
-  static HMODULE sShellDll = nullptr;
-  if (sShellDll) {
-    return false;
-  }
-  static const PRUnichar kSehllLibraryName[] =  L"shell32.dll";
-  sShellDll = ::LoadLibraryW(kSehllLibraryName);
-  if (!sShellDll) {
-    return false;
-  }
-  sCreateItemFromParsingName = (SHCreateItemFromParsingNamePtr)
-    GetProcAddress(sShellDll, "SHCreateItemFromParsingName");
-  return sCreateItemFromParsingName != nullptr;
-}
-
-/* static */
 HRESULT
 WinUtils::SHCreateItemFromParsingName(PCWSTR pszPath, IBindCtx *pbc,
                                       REFIID riid, void **ppv)
 {
-  if (!VistaCreateItemFromParsingNameInit())
+  if (sCreateItemFromParsingName) {
+    return sCreateItemFromParsingName(pszPath, pbc, riid, ppv);
+  }
+
+  if (!sShellDll) {
+    sShellDll = ::LoadLibraryW(kSehllLibraryName);
+    if (!sShellDll) {
+      return false;
+    }
+  }
+
+  sCreateItemFromParsingName = (SHCreateItemFromParsingNamePtr)
+    GetProcAddress(sShellDll, "SHCreateItemFromParsingName");
+  if (!sCreateItemFromParsingName)
     return E_FAIL;
+
   return sCreateItemFromParsingName(pszPath, pbc, riid, ppv);
 }
 
+/* static */
+HRESULT 
+WinUtils::SHGetKnownFolderPath(REFKNOWNFOLDERID rfid,
+                               DWORD dwFlags,
+                               HANDLE hToken,
+                               PWSTR *ppszPath)
+{
+  if (sGetKnownFolderPath) {
+    return sGetKnownFolderPath(rfid, dwFlags, hToken, ppszPath);
+  }
+
+  if (!sShellDll) {
+    sShellDll = ::LoadLibraryW(kSehllLibraryName);
+    if (!sShellDll) {
+      return false;
+    }
+  }
+
+  sGetKnownFolderPath = (SHGetKnownFolderPathPtr)
+    GetProcAddress(sShellDll, "SHGetKnownFolderPath");
+  if (!sGetKnownFolderPath)
+    return E_FAIL;
+
+  return sGetKnownFolderPath(rfid, dwFlags, hToken, ppszPath);
+}
+
 #ifdef MOZ_PLACES
 /************************************************************************/
 /* Constructs as AsyncFaviconDataReady Object
 /* @param aIOThread : the thread which performs the action
 /* @param aURLShortcut : Differentiates between (false)Jumplistcache and (true)Shortcutcache
 /************************************************************************/
 
 AsyncFaviconDataReady::AsyncFaviconDataReady(nsIURI *aNewURI, 
--- a/widget/windows/WinUtils.h
+++ b/widget/windows/WinUtils.h
@@ -185,23 +185,30 @@ public:
    * GetMouseInputSource() returns a pointing device information.  The value is
    * one of nsIDOMMouseEvent::MOZ_SOURCE_*.  This method MUST be called during
    * mouse message handling.
    */
   static uint16_t GetMouseInputSource();
 
   /**
    * SHCreateItemFromParsingName() calls native SHCreateItemFromParsingName()
-   * API.  Note that you must call VistaCreateItemFromParsingNameInit() before
-   * calling this.  And the result must be TRUE.  Otherwise, returns E_FAIL.
+   * API which is available on Vista and up.
    */
   static HRESULT SHCreateItemFromParsingName(PCWSTR pszPath, IBindCtx *pbc,
                                              REFIID riid, void **ppv);
 
   /**
+   * SHGetKnownFolderPath() calls native SHGetKnownFolderPath()
+   * API which is available on Vista and up.
+   */
+  static HRESULT SHGetKnownFolderPath(REFKNOWNFOLDERID rfid,
+                                      DWORD dwFlags,
+                                      HANDLE hToken,
+                                      PWSTR *ppszPath);
+  /**
    * GetShellItemPath return the file or directory path of a shell item.
    * Internally calls IShellItem's GetDisplayName.
    *
    * aItem  the shell item containing the path.
    * aResultString  the resulting string path.
    * returns  true if a path was retreived.
    */
   static bool GetShellItemPath(IShellItem* aItem,
@@ -224,23 +231,21 @@ public:
   static nsIntRect ToIntRect(const RECT& aRect);
 
 private:
   typedef HRESULT (WINAPI * SHCreateItemFromParsingNamePtr)(PCWSTR pszPath,
                                                             IBindCtx *pbc,
                                                             REFIID riid,
                                                             void **ppv);
   static SHCreateItemFromParsingNamePtr sCreateItemFromParsingName;
-
-  /**
-   * VistaCreateItemFromParsingNameInit() initializes the static pointer for
-   * SHCreateItemFromParsingName() API which is usable only on Vista and later.
-   * This returns TRUE if the API is available.  Otherwise, FALSE.
-   */
-  static bool VistaCreateItemFromParsingNameInit();
+  typedef HRESULT (WINAPI * SHGetKnownFolderPathPtr)(REFKNOWNFOLDERID rfid,
+                                                     DWORD dwFlags,
+                                                     HANDLE hToken,
+                                                     PWSTR *ppszPath);
+  static SHGetKnownFolderPathPtr sGetKnownFolderPath;
 };
 
 #ifdef MOZ_PLACES
 class AsyncFaviconDataReady MOZ_FINAL : public nsIFaviconDataCallback
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIFAVICONDATACALLBACK
--- a/widget/windows/nsNativeThemeWin.cpp
+++ b/widget/windows/nsNativeThemeWin.cpp
@@ -39,144 +39,164 @@
 using namespace mozilla::widget;
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gWindowsLog;
 #endif
 
 NS_IMPL_ISUPPORTS_INHERITED1(nsNativeThemeWin, nsNativeTheme, nsITheme)
 
-static inline bool IsHTMLContent(nsIFrame *frame)
+nsNativeThemeWin::nsNativeThemeWin() :
+  mProgressDeterminateTimeStamp(TimeStamp::Now()),
+  mProgressIndeterminateTimeStamp(TimeStamp::Now())
 {
-  nsIContent* content = frame->GetContent();
-  return content && content->IsHTML();
+  // If there is a relevant change in forms.css for windows platform,
+  // static widget style variables (e.g. sButtonBorderSize) should be 
+  // reinitialized here.
 }
 
-static int32_t GetTopLevelWindowActiveState(nsIFrame *aFrame)
+nsNativeThemeWin::~nsNativeThemeWin()
+{
+  nsUXThemeData::Invalidate();
+}
+
+static int32_t
+GetTopLevelWindowActiveState(nsIFrame *aFrame)
 {
   // Get the widget. nsIFrame's GetNearestWidget walks up the view chain
   // until it finds a real window.
   nsIWidget* widget = aFrame->GetNearestWidget();
   nsWindow * window = static_cast<nsWindow*>(widget);
   if (!window)
     return mozilla::widget::themeconst::FS_INACTIVE;
   if (widget && !window->IsTopLevelWidget() &&
       !(window = window->GetParentWindow(false)))
     return mozilla::widget::themeconst::FS_INACTIVE;
 
   if (window->GetWindowHandle() == ::GetActiveWindow())
     return mozilla::widget::themeconst::FS_ACTIVE;
   return mozilla::widget::themeconst::FS_INACTIVE;
 }
 
-static int32_t GetWindowFrameButtonState(nsIFrame *aFrame, nsEventStates eventState)
+static int32_t
+GetWindowFrameButtonState(nsIFrame *aFrame, nsEventStates eventState)
 {
   if (GetTopLevelWindowActiveState(aFrame) ==
       mozilla::widget::themeconst::FS_INACTIVE) {
     if (eventState.HasState(NS_EVENT_STATE_HOVER))
       return mozilla::widget::themeconst::BS_HOT;
     return mozilla::widget::themeconst::BS_INACTIVE;
   }
 
   if (eventState.HasState(NS_EVENT_STATE_HOVER)) {
     if (eventState.HasState(NS_EVENT_STATE_ACTIVE))
       return mozilla::widget::themeconst::BS_PUSHED;
     return mozilla::widget::themeconst::BS_HOT;
   }
   return mozilla::widget::themeconst::BS_NORMAL;
 }
 
-static int32_t GetClassicWindowFrameButtonState(nsEventStates eventState)
+static int32_t
+GetClassicWindowFrameButtonState(nsEventStates eventState)
 {
   if (eventState.HasState(NS_EVENT_STATE_ACTIVE) &&
       eventState.HasState(NS_EVENT_STATE_HOVER))
     return DFCS_BUTTONPUSH|DFCS_PUSHED;
   return DFCS_BUTTONPUSH;
 }
 
-static void QueryForButtonData(nsIFrame *aFrame)
+static void
+QueryForButtonData(nsIFrame *aFrame)
 {
   if (nsUXThemeData::sTitlebarInfoPopulatedThemed && nsUXThemeData::sTitlebarInfoPopulatedAero)
     return;
   nsIWidget* widget = aFrame->GetNearestWidget();
   nsWindow * window = static_cast<nsWindow*>(widget);
   if (!window)
     return;
   if (!window->IsTopLevelWidget() &&
       !(window = window->GetParentWindow(false)))
     return;
 
   nsUXThemeData::UpdateTitlebarInfo(window->GetWindowHandle());
 }
 
-nsNativeThemeWin::nsNativeThemeWin() {
-  // If there is a relevant change in forms.css for windows platform,
-  // static widget style variables (e.g. sButtonBorderSize) should be 
-  // reinitialized here.
-}
-
-nsNativeThemeWin::~nsNativeThemeWin() {
-  nsUXThemeData::Invalidate();
-}
-
-static bool IsTopLevelMenu(nsIFrame *aFrame)
+static bool
+IsTopLevelMenu(nsIFrame *aFrame)
 {
   bool isTopLevel(false);
   nsMenuFrame *menuFrame = do_QueryFrame(aFrame);
   if (menuFrame) {
     isTopLevel = menuFrame->IsOnMenuBar();
   }
   return isTopLevel;
 }
 
-static MARGINS GetCheckboxMargins(HANDLE theme, HDC hdc)
+static MARGINS
+GetCheckboxMargins(HANDLE theme, HDC hdc)
 {
     MARGINS checkboxContent = {0};
-    GetThemeMargins(theme, hdc, MENU_POPUPCHECK, MCB_NORMAL, TMT_CONTENTMARGINS, NULL, &checkboxContent);
+    GetThemeMargins(theme, hdc, MENU_POPUPCHECK, MCB_NORMAL,
+                    TMT_CONTENTMARGINS, NULL, &checkboxContent);
     return checkboxContent;
 }
-static SIZE GetCheckboxBGSize(HANDLE theme, HDC hdc)
+
+static SIZE
+GetCheckboxBGSize(HANDLE theme, HDC hdc)
 {
     SIZE checkboxSize;
-    GetThemePartSize(theme, hdc, MENU_POPUPCHECK, MC_CHECKMARKNORMAL, NULL, TS_TRUE, &checkboxSize);
+    GetThemePartSize(theme, hdc, MENU_POPUPCHECK, MC_CHECKMARKNORMAL,
+                     NULL, TS_TRUE, &checkboxSize);
 
     MARGINS checkboxMargins = GetCheckboxMargins(theme, hdc);
 
     int leftMargin = checkboxMargins.cxLeftWidth;
     int rightMargin = checkboxMargins.cxRightWidth;
     int topMargin = checkboxMargins.cyTopHeight;
     int bottomMargin = checkboxMargins.cyBottomHeight;
 
     int width = leftMargin + checkboxSize.cx + rightMargin;
     int height = topMargin + checkboxSize.cy + bottomMargin;
     SIZE ret;
     ret.cx = width;
     ret.cy = height;
     return ret;
 }
-static SIZE GetCheckboxBGBounds(HANDLE theme, HDC hdc)
+
+static SIZE
+GetCheckboxBGBounds(HANDLE theme, HDC hdc)
 {
     MARGINS checkboxBGSizing = {0};
     MARGINS checkboxBGContent = {0};
-    GetThemeMargins(theme, hdc, MENU_POPUPCHECKBACKGROUND, MCB_NORMAL, TMT_SIZINGMARGINS, NULL, &checkboxBGSizing);
-    GetThemeMargins(theme, hdc, MENU_POPUPCHECKBACKGROUND, MCB_NORMAL, TMT_CONTENTMARGINS, NULL, &checkboxBGContent);
+    GetThemeMargins(theme, hdc, MENU_POPUPCHECKBACKGROUND, MCB_NORMAL,
+                    TMT_SIZINGMARGINS, NULL, &checkboxBGSizing);
+    GetThemeMargins(theme, hdc, MENU_POPUPCHECKBACKGROUND, MCB_NORMAL,
+                    TMT_CONTENTMARGINS, NULL, &checkboxBGContent);
 
 #define posdx(d) ((d) > 0 ? d : 0)
 
-    int dx = posdx(checkboxBGContent.cxRightWidth - checkboxBGSizing.cxRightWidth) + posdx(checkboxBGContent.cxLeftWidth - checkboxBGSizing.cxLeftWidth);
-    int dy = posdx(checkboxBGContent.cyTopHeight - checkboxBGSizing.cyTopHeight) + posdx(checkboxBGContent.cyBottomHeight - checkboxBGSizing.cyBottomHeight);
+    int dx = posdx(checkboxBGContent.cxRightWidth -
+                   checkboxBGSizing.cxRightWidth) +
+             posdx(checkboxBGContent.cxLeftWidth -
+                   checkboxBGSizing.cxLeftWidth);
+    int dy = posdx(checkboxBGContent.cyTopHeight -
+                   checkboxBGSizing.cyTopHeight) +
+             posdx(checkboxBGContent.cyBottomHeight -
+                   checkboxBGSizing.cyBottomHeight);
 
 #undef posdx
 
     SIZE ret(GetCheckboxBGSize(theme, hdc));
     ret.cx += dx;
     ret.cy += dy;
     return ret;
 }
-static SIZE GetGutterSize(HANDLE theme, HDC hdc)
+
+static SIZE
+GetGutterSize(HANDLE theme, HDC hdc)
 {
     SIZE gutterSize;
     GetThemePartSize(theme, hdc, MENU_POPUPGUTTER, 0, NULL, TS_TRUE, &gutterSize);
 
     SIZE checkboxBGSize(GetCheckboxBGBounds(theme, hdc));
 
     SIZE itemSize;
     GetThemePartSize(theme, hdc, MENU_POPUPITEM, MPI_NORMAL, NULL, TS_TRUE, &itemSize);
@@ -184,113 +204,117 @@ static SIZE GetGutterSize(HANDLE theme, 
     int width = std::max(itemSize.cx, checkboxBGSize.cx + gutterSize.cx);
     int height = std::max(itemSize.cy, checkboxBGSize.cy);
     SIZE ret;
     ret.cx = width;
     ret.cy = height;
     return ret;
 }
 
-static HRESULT DrawThemeBGRTLAware(HANDLE theme, HDC hdc, int part, int state,
-                                   const RECT *widgetRect, const RECT *clipRect,
-                                   bool isRTL)
+/* DrawThemeBGRTLAware - render a theme part based on rtl state.
+ * Some widgets are not direction-neutral and need to be drawn reversed for
+ * RTL.  Windows provides a way to do this with SetLayout, but this reverses
+ * the entire drawing area of a given device context, which means that its
+ * use will also affect the positioning of the widget.  There are two ways
+ * to work around this:
+ *
+ * Option 1: Alter the position of the rect that we send so that we cancel
+ *           out the positioning effects of SetLayout
+ * Option 2: Create a memory DC with the widgetRect's dimensions, draw onto
+ *           that, and then transfer the results back to our DC
+ *
+ * This function tries to implement option 1, under the assumption that the
+ * correct way to reverse the effects of SetLayout is to translate the rect
+ * such that the offset from the DC bitmap's left edge to the old rect's
+ * left edge is equal to the offset from the DC bitmap's right edge to the
+ * new rect's right edge.  In other words,
+ * (oldRect.left + vpOrg.x) == ((dcBMP.width - vpOrg.x) - newRect.right)
+ */
+static HRESULT
+DrawThemeBGRTLAware(HANDLE aTheme, HDC aHdc, int aPart, int aState,
+                    const RECT *aWidgetRect, const RECT *aClipRect,
+                    bool aIsRtl)
 {
-  /* Some widgets are not direction-neutral and need to be drawn reversed for
-   * RTL.  Windows provides a way to do this with SetLayout, but this reverses
-   * the entire drawing area of a given device context, which means that its
-   * use will also affect the positioning of the widget.  There are two ways
-   * to work around this:
-   *
-   * Option 1: Alter the position of the rect that we send so that we cancel
-   *           out the positioning effects of SetLayout
-   * Option 2: Create a memory DC with the widgetRect's dimensions, draw onto
-   *           that, and then transfer the results back to our DC
-   *
-   * This function tries to implement option 1, under the assumption that the
-   * correct way to reverse the effects of SetLayout is to translate the rect
-   * such that the offset from the DC bitmap's left edge to the old rect's
-   * left edge is equal to the offset from the DC bitmap's right edge to the
-   * new rect's right edge.  In other words,
-   * (oldRect.left + vpOrg.x) == ((dcBMP.width - vpOrg.x) - newRect.right)
-   *
-   * I am not 100% sure that this is the correct approach, but I have yet to
-   * find a problem with it.
-   */
-
-  if (isRTL) {
-    HGDIOBJ hObj = GetCurrentObject(hdc, OBJ_BITMAP);
-    BITMAP bitmap;
-    POINT vpOrg;
-
-    if (hObj &&
-        GetObject(hObj, sizeof(bitmap), &bitmap) &&
-        GetViewportOrgEx(hdc, &vpOrg))
-    {
-      RECT newWRect(*widgetRect);
-      newWRect.left = bitmap.bmWidth - (widgetRect->right + 2*vpOrg.x);
-      newWRect.right = bitmap.bmWidth - (widgetRect->left + 2*vpOrg.x);
-
-      RECT newCRect;
-      RECT *newCRectPtr = NULL;
-
-      if (clipRect) {
-        newCRect.top = clipRect->top;
-        newCRect.bottom = clipRect->bottom;
-        newCRect.left = bitmap.bmWidth - (clipRect->right + 2*vpOrg.x);
-        newCRect.right = bitmap.bmWidth - (clipRect->left + 2*vpOrg.x);
-        newCRectPtr = &newCRect;
-      }
-
-      SetLayout(hdc, LAYOUT_RTL);
-      HRESULT hr = DrawThemeBackground(theme, hdc, part, state, &newWRect, newCRectPtr);
-      SetLayout(hdc, 0);
-
-      if (hr == S_OK)
-        return hr;
+  NS_ASSERTION(aTheme, "Bad theme handle.");
+  NS_ASSERTION(aHdc, "Bad hdc.");
+  NS_ASSERTION(aWidgetRect, "Bad rect.");
+  NS_ASSERTION(aClipRect, "Bad clip rect.");
+
+  if (!aIsRtl) {
+    return DrawThemeBackground(aTheme, aHdc, aPart, aState,
+                               aWidgetRect, aClipRect);
+  }
+
+  HGDIOBJ hObj = GetCurrentObject(aHdc, OBJ_BITMAP);
+  BITMAP bitmap;
+  POINT vpOrg;
+
+  if (hObj && GetObject(hObj, sizeof(bitmap), &bitmap) &&
+      GetViewportOrgEx(aHdc, &vpOrg)) {
+    RECT newWRect(*aWidgetRect);
+    newWRect.left = bitmap.bmWidth - (aWidgetRect->right + 2*vpOrg.x);
+    newWRect.right = bitmap.bmWidth - (aWidgetRect->left + 2*vpOrg.x);
+
+    RECT newCRect;
+    RECT *newCRectPtr = NULL;
+
+    if (aClipRect) {
+      newCRect.top = aClipRect->top;
+      newCRect.bottom = aClipRect->bottom;
+      newCRect.left = bitmap.bmWidth - (aClipRect->right + 2*vpOrg.x);
+      newCRect.right = bitmap.bmWidth - (aClipRect->left + 2*vpOrg.x);
+      newCRectPtr = &newCRect;
+    }
+
+    SetLayout(aHdc, LAYOUT_RTL);
+    HRESULT hr = DrawThemeBackground(aTheme, aHdc, aPart, aState, &newWRect,
+                                     newCRectPtr);
+    SetLayout(aHdc, 0);
+    if (SUCCEEDED(hr)) {
+      return hr;
     }
   }
-
-  // Draw normally if LTR or if anything went wrong
-  return DrawThemeBackground(theme, hdc, part, state, widgetRect, clipRect);
+  return DrawThemeBackground(aTheme, aHdc, aPart, aState,
+                             aWidgetRect, aClipRect);
 }
 
 /*
-  Caption button padding data - 'hot' button padding.
-  These areas are considered hot, in that they activate
-  a button when hovered or clicked. The button graphic
-  is drawn inside the padding border. Unrecognized themes
-  are treated as their recognized counterparts for now.
-                       left      top    right   bottom
-  classic min             1        2        0        1
-  classic max             0        2        1        1
-  classic close           1        2        2        1
-
-  aero basic min          1        2        0        2
-  aero basic max          0        2        1        2
-  aero basic close        1        2        1        2
-
-  xp theme min            0        2        0        2
-  xp theme max            0        2        1        2
-  xp theme close          1        2        2        2
-
-  'cold' button padding - generic button padding, should
-  be handled in css.
-                       left      top    right   bottom
-  classic min             0        0        0        0
-  classic max             0        0        0        0
-  classic close           0        0        0        0
-
-  aero basic min          0        0        1        0
-  aero basic max          1        0        0        0
-  aero basic close        0        0        0        0
-
-  xp theme min            0        0        1        0
-  xp theme max            1        0        0        0
-  xp theme close          0        0        0        0
-*/
+ *  Caption button padding data - 'hot' button padding.
+ *  These areas are considered hot, in that they activate
+ *  a button when hovered or clicked. The button graphic
+ *  is drawn inside the padding border. Unrecognized themes
+ *  are treated as their recognized counterparts for now.
+ *                       left      top    right   bottom
+ *  classic min             1        2        0        1
+ *  classic max             0        2        1        1
+ *  classic close           1        2        2        1
+ *
+ *  aero basic min          1        2        0        2
+ *  aero basic max          0        2        1        2
+ *  aero basic close        1        2        1        2
+ *
+ *  xp theme min            0        2        0        2
+ *  xp theme max            0        2        1        2
+ *  xp theme close          1        2        2        2
+ *
+ *  'cold' button padding - generic button padding, should
+ *  be handled in css.
+ *                       left      top    right   bottom
+ *  classic min             0        0        0        0
+ *  classic max             0        0        0        0
+ *  classic close           0        0        0        0
+ *
+ *  aero basic min          0        0        1        0
+ *  aero basic max          1        0        0        0
+ *  aero basic close        0        0        0        0
+ *
+ *  xp theme min            0        0        1        0
+ *  xp theme max            1        0        0        0
+ *  xp theme close          0        0        0        0
+ */
 
 enum CaptionDesktopTheme {
   CAPTION_CLASSIC = 0,
   CAPTION_BASIC,
   CAPTION_XPTHEME,
 };
 
 enum CaptionButton {
@@ -311,71 +335,385 @@ static CaptionButtonPadding buttonData[3
   { 
     { { 1, 2, 0, 2 }, { 0, 2, 1, 2 }, { 1, 2, 2, 2 } }
   },
   { 
     { { 0, 2, 0, 2 }, { 0, 2, 1, 2 }, { 1, 2, 2, 2 } }
   }
 };
 
-/**
- * Progress bar related constants.
- * These values are found by experimenting and comparing against native widgets
- * used by the system. They are very unlikely exact but try to not be too wrong.
+// Adds "hot" caption button padding to minimum widget size.
+static void
+AddPaddingRect(nsIntSize* aSize, CaptionButton button) {
+  if (!aSize)
+    return;
+  RECT offset;
+  if (!IsAppThemed())
+    offset = buttonData[CAPTION_CLASSIC].hotPadding[button];
+  else if (WinUtils::GetWindowsVersion() < WinUtils::VISTA_VERSION)
+    offset = buttonData[CAPTION_XPTHEME].hotPadding[button];
+  else
+    offset = buttonData[CAPTION_BASIC].hotPadding[button];
+  aSize->width += offset.left + offset.right;
+  aSize->height += offset.top + offset.bottom;
+}
+
+// If we've added padding to the minimum widget size, offset
+// the area we draw into to compensate.
+static void
+OffsetBackgroundRect(RECT& rect, CaptionButton button) {
+  RECT offset;
+  if (!IsAppThemed())
+    offset = buttonData[CAPTION_CLASSIC].hotPadding[button];
+  else if (WinUtils::GetWindowsVersion() < WinUtils::VISTA_VERSION)
+    offset = buttonData[CAPTION_XPTHEME].hotPadding[button];
+  else
+    offset = buttonData[CAPTION_BASIC].hotPadding[button];
+  rect.left += offset.left;
+  rect.top += offset.top;
+  rect.right -= offset.right;
+  rect.bottom -= offset.bottom;
+}
+
+/*
+ * Notes on progress track and meter part constants:
+ * xp and up:
+ * PP_BAR(_VERT)            - base progress track
+ * PP_TRANSPARENTBAR(_VERT) - transparent progress track. this only works if
+ *                            the underlying surface supports alpha. otherwise
+ *                            theme lib's DrawThemeBackground falls back on
+ *                            opaque PP_BAR. we currently don't use this.
+ * PP_CHUNK(_VERT)          - xp progress meter. this does not draw an xp style
+ *                            progress w/chunks, it draws fill using the chunk
+ *                            graphic.
+ * vista and up:
+ * PP_FILL(_VERT)           - progress meter. these have four states/colors.
+ * PP_PULSEOVERLAY(_VERT)   - white reflection - an overlay, not sure what this
+ *                            is used for.
+ * PP_MOVEOVERLAY(_VERT)    - green pulse - the pulse effect overlay on
+ *                            determined progress bars. we also use this for
+ *                            indeterminate chunk.
+ *
+ * Notes on state constants:
+ * PBBS_NORMAL               - green progress
+ * PBBVS_PARTIAL/PBFVS_ERROR - red error progress
+ * PBFS_PAUSED               - yellow paused progress
+ *
+ * There is no common controls style indeterminate part on vista and up.
  */
+
+/*
+ * Progress bar related constants. These values are found by experimenting and
+ * comparing against native widgets used by the system. They are very unlikely
+ * exact but try to not be too wrong.
+ */
+// The amount of time we animate progress meters parts across the frame.
+static const double kProgressDeterminateTimeSpan = 3.0;
+static const double kProgressIndeterminateTimeSpan = 5.0;
 // The width of the overlay used to animate the horizontal progress bar (Vista and later).
 static const int32_t kProgressHorizontalVistaOverlaySize = 120;
 // The width of the overlay used for the horizontal indeterminate progress bars on XP.
 static const int32_t kProgressHorizontalXPOverlaySize = 55;
 // The height of the overlay used to animate the vertical progress bar (Vista and later).
 static const int32_t kProgressVerticalOverlaySize = 45;
 // The height of the overlay used for the vertical indeterminate progress bar (Vista and later).
 static const int32_t kProgressVerticalIndeterminateOverlaySize = 60;
 // The width of the overlay used to animate the indeterminate progress bar (Windows Classic).
 static const int32_t kProgressClassicOverlaySize = 40;
-// Speed (px per ms) of the animation for determined Vista and later progress bars.
-static const double kProgressDeterminedVistaSpeed = 0.225;
-// Speed (px per ms) of the animation for indeterminate progress bars.
-static const double kProgressIndeterminateSpeed = 0.175;
-// Speed (px per ms) of the animation for indeterminate progress bars (Windows Classic).
-static const double kProgressClassicIndeterminateSpeed = 0.0875;
-// Delay (in ms) between two indeterminate progress bar cycles.
-static const int32_t kProgressIndeterminateDelay = 500;
-// Delay (in ms) between two determinate progress bar animation on Vista/7.
-static const int32_t kProgressDeterminedVistaDelay = 1000;
-
-// Adds "hot" caption button padding to minimum widget size.
-static void AddPaddingRect(nsIntSize* aSize, CaptionButton button) {
-  if (!aSize)
+
+/*
+ * GetProgressOverlayStyle - returns the proper overlay part for themed
+ * progress bars based on os and orientation.
+ */
+static int32_t
+GetProgressOverlayStyle(bool aIsVertical)
+{ 
+  if (aIsVertical) {
+    if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION) {
+      return PP_MOVEOVERLAYVERT;
+    }
+    return PP_CHUNKVERT;
+  } else {
+    if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION) {
+      return PP_MOVEOVERLAY;
+    }
+    return PP_CHUNK;
+  }
+}
+
+/*
+ * GetProgressOverlaySize - returns the minimum width or height for themed
+ * progress bar overlays. This includes the width of indeterminate chunks
+ * and vista pulse overlays.
+ */
+static int32_t
+GetProgressOverlaySize(bool aIsVertical, bool aIsIndeterminate)
+{
+  if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION) {
+    if (aIsVertical) {
+      return aIsIndeterminate ? kProgressVerticalIndeterminateOverlaySize
+                              : kProgressVerticalOverlaySize;
+    }
+    return kProgressHorizontalVistaOverlaySize;
+  }
+  return kProgressHorizontalXPOverlaySize;
+}
+
+/*
+ * IsProgressMeterFilled - Determines if a progress meter is at 100% fill based
+ * on a comparison of the current value and maximum.
+ */
+static bool
+IsProgressMeterFilled(nsIFrame* aFrame)
+{
+  NS_ENSURE_TRUE(aFrame, false);
+  nsIFrame* parentFrame = aFrame->GetParent();
+  NS_ENSURE_TRUE(parentFrame, false);
+  return nsNativeTheme::GetProgressValue(parentFrame) ==
+         nsNativeTheme::GetProgressMaxValue(parentFrame);
+}
+
+/*
+ * CalculateProgressOverlayRect - returns the padded overlay animation rect
+ * used in rendering progress bars. Resulting rects are used in rendering
+ * vista+ pulse overlays and indeterminate progress meters. Graphics should
+ * be rendered at the origin.
+ */
+RECT
+nsNativeThemeWin::CalculateProgressOverlayRect(nsIFrame* aFrame,
+                                               RECT* aWidgetRect,
+                                               bool aIsVertical,
+                                               bool aIsIndeterminate,
+                                               bool aIsClassic)
+{
+  NS_ASSERTION(aFrame, "bad frame pointer");
+  NS_ASSERTION(aWidgetRect, "bad rect pointer");
+
+  int32_t frameSize = aIsVertical ? aWidgetRect->bottom - aWidgetRect->top
+                                  : aWidgetRect->right - aWidgetRect->left;
+
+  // Recycle a set of progress pulse timers - these timers control the position
+  // of all progress overlays and indeterminate chunks that get rendered.
+  double span = aIsIndeterminate ? kProgressIndeterminateTimeSpan
+                                 : kProgressDeterminateTimeSpan;
+  TimeDuration period;
+  if (!aIsIndeterminate) {
+    if (TimeStamp::Now() > (mProgressDeterminateTimeStamp +
+                            TimeDuration::FromSeconds(span))) {
+      mProgressDeterminateTimeStamp = TimeStamp::Now();
+    }
+    period = TimeStamp::Now() - mProgressDeterminateTimeStamp;
+  } else {
+    if (TimeStamp::Now() > (mProgressIndeterminateTimeStamp +
+                            TimeDuration::FromSeconds(span))) {
+      mProgressIndeterminateTimeStamp = TimeStamp::Now();
+    }
+    period = TimeStamp::Now() - mProgressIndeterminateTimeStamp;
+  }
+
+  double percent = period / TimeDuration::FromSeconds(span);
+
+  if (!aIsVertical && IsFrameRTL(aFrame))
+    percent = 1 - percent;
+
+  RECT overlayRect = *aWidgetRect;
+  int32_t overlaySize;
+  if (!aIsClassic) {
+    overlaySize = GetProgressOverlaySize(aIsVertical, aIsIndeterminate);
+  } else {
+    overlaySize = kProgressClassicOverlaySize;
+  } 
+
+  // Calculate a bounds that is larger than the meters frame such that the
+  // overlay starts and ends completely off the edge of the frame:
+  // [overlay][frame][overlay]
+  // This also yields a nice delay on rotation. Use overlaySize as the minimum
+  // size for [overlay] based on the graphics dims. If [frame] is larger, use
+  // the frame size instead.
+  int trackWidth = frameSize > overlaySize ? frameSize : overlaySize;
+  if (!aIsVertical) {
+    int xPos = aWidgetRect->left - trackWidth;
+    xPos += (int)ceil(((double)(trackWidth*2) * percent));
+    overlayRect.left = xPos;
+    overlayRect.right = xPos + overlaySize;
+  } else {
+    int yPos = aWidgetRect->bottom + trackWidth;
+    yPos -= (int)ceil(((double)(trackWidth*2) * percent));
+    overlayRect.bottom = yPos;
+    overlayRect.top = yPos - overlaySize;
+  }
+  return overlayRect;
+}
+
+/*
+ * DrawChunkProgressMeter - renders an xp style chunked progress meter. Called
+ * by DrawProgressMeter.
+ *
+ * @param aTheme       progress theme handle
+ * @param aHdc         hdc returned by gfxWindowsNativeDrawing
+ * @param aPart        the PP_X progress part
+ * @param aState       the theme state
+ * @param aFrame       the elements frame
+ * @param aWidgetRect  bounding rect for the widget
+ * @param aClipRect    dirty rect that needs drawing.
+ * @param aAppUnits    app units per device pixel
+ * @param aIsIndeterm  is an indeterminate progress?
+ * @param aIsVertical  render a vertical progress?
+ * @param aIsRtl       direction is rtl
+ */
+static void
+DrawChunkProgressMeter(HTHEME aTheme, HDC aHdc, int aPart,
+                       int aState, nsIFrame* aFrame, RECT* aWidgetRect,
+                       RECT* aClipRect, gfxFloat aAppUnits, bool aIsIndeterm,
+                       bool aIsVertical, bool aIsRtl)
+{
+  NS_ASSERTION(aTheme, "Bad theme.");
+  NS_ASSERTION(aHdc, "Bad hdc.");
+  NS_ASSERTION(aWidgetRect, "Bad rect.");
+  NS_ASSERTION(aClipRect, "Bad clip rect.");
+  NS_ASSERTION(aFrame, "Bad frame.");
+
+  // For horizontal meters, the theme lib paints the right graphic but doesn't
+  // paint the chunks, so we do that manually. For vertical meters, the theme
+  // library draws everything correctly.
+  if (aIsVertical) {
+    DrawThemeBackground(aTheme, aHdc, aPart, aState, aWidgetRect, aClipRect);
     return;
-  RECT offset;
-  if (!IsAppThemed())
-    offset = buttonData[CAPTION_CLASSIC].hotPadding[button];
-  else if (WinUtils::GetWindowsVersion() == WinUtils::WINXP_VERSION)
-    offset = buttonData[CAPTION_XPTHEME].hotPadding[button];
-  else
-    offset = buttonData[CAPTION_BASIC].hotPadding[button];
-  aSize->width += offset.left + offset.right;
-  aSize->height += offset.top + offset.bottom;
+  }
+
+  // query for the proper chunk metrics
+  int chunkSize, spaceSize;
+  if (FAILED(GetThemeMetric(aTheme, aHdc, aPart, aState,
+                            TMT_PROGRESSCHUNKSIZE, &chunkSize)) ||
+      FAILED(GetThemeMetric(aTheme, aHdc, aPart, aState,
+                            TMT_PROGRESSSPACESIZE, &spaceSize))) {
+    DrawThemeBackground(aTheme, aHdc, aPart, aState, aWidgetRect, aClipRect);
+    return;
+  }
+
+  // render chunks
+  if (!aIsRtl || aIsIndeterm) {
+    for (int chunk = aWidgetRect->left; chunk <= aWidgetRect->right;
+         chunk += (chunkSize+spaceSize)) {
+      if (!aIsIndeterm && ((chunk + chunkSize) > aWidgetRect->right)) {
+        // aWidgetRect->right represents the end of the meter. Partial blocks
+        // don't get rendered with one exception, so exit here if we don't have
+        // a full chunk to draw.
+        // The above is true *except* when the meter is at 100% fill, in which
+        // case Windows renders any remaining partial block. Query the parent
+        // frame to find out if we're at 100%.
+        if (!IsProgressMeterFilled(aFrame)) {
+          break;
+        }
+      }
+      RECT bounds =
+        { chunk, aWidgetRect->top, chunk + chunkSize, aWidgetRect->bottom };
+      DrawThemeBackground(aTheme, aHdc, aPart, aState, &bounds, aClipRect);
+    }
+  } else {
+    // rtl needs to grow in the opposite direction to look right.
+    for (int chunk = aWidgetRect->right; chunk >= aWidgetRect->left;
+         chunk -= (chunkSize+spaceSize)) {
+      if ((chunk - chunkSize) < aWidgetRect->left) {
+        if (!IsProgressMeterFilled(aFrame)) {
+          break;
+        }
+      }
+      RECT bounds =
+        { chunk - chunkSize, aWidgetRect->top, chunk, aWidgetRect->bottom };
+      DrawThemeBackground(aTheme, aHdc, aPart, aState, &bounds, aClipRect);
+    }
+  }
 }
 
-// If we've added padding to the minimum widget size, offset
-// the area we draw into to compensate.
-static void OffsetBackgroundRect(RECT& rect, CaptionButton button) {
-  RECT offset;
-  if (!IsAppThemed())
-    offset = buttonData[CAPTION_CLASSIC].hotPadding[button];
-  else if (WinUtils::GetWindowsVersion() == WinUtils::WINXP_VERSION)
-    offset = buttonData[CAPTION_XPTHEME].hotPadding[button];
-  else
-    offset = buttonData[CAPTION_BASIC].hotPadding[button];
-  rect.left += offset.left;
-  rect.top += offset.top;
-  rect.right -= offset.right;
-  rect.bottom -= offset.bottom;
+/*
+ * DrawProgressMeter - render an appropriate progress meter based on progress
+ * meter style, orientation, and os. Note, this does not render the underlying
+ * progress track.
+ *
+ * @param aFrame       the widget frame
+ * @param aWidgetType  type of widget
+ * @param aTheme       progress theme handle
+ * @param aHdc         hdc returned by gfxWindowsNativeDrawing
+ * @param aPart        the PP_X progress part
+ * @param aState       the theme state
+ * @param aWidgetRect  bounding rect for the widget
+ * @param aClipRect    dirty rect that needs drawing.
+ * @param aAppUnits    app units per device pixel
+ */
+void
+nsNativeThemeWin::DrawThemedProgressMeter(nsIFrame* aFrame, int aWidgetType,
+                                          HANDLE aTheme, HDC aHdc,
+                                          int aPart, int aState,
+                                          RECT* aWidgetRect, RECT* aClipRect,
+                                          gfxFloat aAppUnits)
+{
+  if (!aFrame || !aTheme || !aHdc)
+    return;
+
+  NS_ASSERTION(aWidgetRect, "bad rect pointer");
+  NS_ASSERTION(aClipRect, "bad clip rect pointer");
+
+  RECT adjWidgetRect, adjClipRect;
+  adjWidgetRect = *aWidgetRect;
+  adjClipRect = *aClipRect;
+  if (WinUtils::GetWindowsVersion() < WinUtils::VISTA_VERSION) {
+    // Adjust clipping out by one pixel. XP progress meters are inset,
+    // Vista+ are not.
+    InflateRect(&adjWidgetRect, 1, 1);
+    InflateRect(&adjClipRect, 1, 1);
+  }
+
+  nsIFrame* parentFrame = aFrame->GetParent();
+  if (!parentFrame) {
+    // We have no parent to work with, just bail.
+    NS_WARNING("No parent frame for progress rendering. Can't paint.");
+    return;
+  }
+
+  nsEventStates eventStates = GetContentState(parentFrame, aWidgetType);
+  bool vertical = IsVerticalProgress(parentFrame) ||
+                  aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL;
+  bool indeterminate = IsIndeterminateProgress(parentFrame, eventStates);
+  bool animate = indeterminate;
+
+  if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION) {
+    // Vista and up progress meter is fill style, rendered here. We render
+    // the pulse overlay in the follow up section below.
+    DrawThemeBackground(aTheme, aHdc, aPart, aState,
+                        &adjWidgetRect, &adjClipRect);
+    if (!IsProgressMeterFilled(aFrame)) {
+      animate = true;
+    }
+  } else if (!indeterminate) {
+    // XP progress meters are 'chunk' style.
+    DrawChunkProgressMeter(aTheme, aHdc, aPart, aState, aFrame,
+                           &adjWidgetRect, &adjClipRect, aAppUnits,
+                           indeterminate, vertical, IsFrameRTL(aFrame));
+  }    
+
+  if (animate) {
+    // Indeterminate rendering
+    int32_t overlayPart = GetProgressOverlayStyle(vertical);
+    RECT overlayRect =
+      CalculateProgressOverlayRect(aFrame, &adjWidgetRect, vertical,
+                                   indeterminate, false);
+    if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION) {
+      DrawThemeBackground(aTheme, aHdc, overlayPart, aState, &overlayRect,
+                          &adjClipRect);
+    } else {
+      DrawChunkProgressMeter(aTheme, aHdc, overlayPart, aState, aFrame,
+                             &overlayRect, &adjClipRect, aAppUnits,
+                             indeterminate, vertical, IsFrameRTL(aFrame));
+    }
+
+    if (!QueueAnimatedContentForRefresh(aFrame->GetContent(), 60)) {
+      NS_WARNING("unable to animate progress widget!");
+    }
+  }
 }
 
 HANDLE
 nsNativeThemeWin::GetTheme(uint8_t aWidgetType)
 { 
   if (WinUtils::GetWindowsVersion() < WinUtils::VISTA_VERSION) {
     // On XP or earlier, render dropdowns as textfields;
     // doing it the right way works fine with the MS themes,
@@ -647,48 +985,41 @@ nsNativeThemeWin::GetThemePartAndState(n
 
       return NS_OK;
     }
     case NS_THEME_TOOLTIP: {
       aPart = TTP_STANDARD;
       aState = TS_NORMAL;
       return NS_OK;
     }
-    case NS_THEME_PROGRESSBAR: {
-      aPart = IsVerticalProgress(aFrame) ? PP_BARVERT : PP_BAR;
-      aState = TS_NORMAL;
+    case NS_THEME_PROGRESSBAR:
+    case NS_THEME_PROGRESSBAR_VERTICAL: {
+      // Note IsVerticalProgress only tests for orient css attrribute,
+      // NS_THEME_PROGRESSBAR_VERTICAL is dedicated to -moz-appearance:
+      // progressbar-vertical.
+      bool vertical = IsVerticalProgress(aFrame) ||
+                      aWidgetType == NS_THEME_PROGRESSBAR_VERTICAL;
+      aPart = vertical ? PP_BARVERT : PP_BAR;
+      aState = PBBS_NORMAL;
       return NS_OK;
     }
-    case NS_THEME_PROGRESSBAR_CHUNK: {
-      nsIFrame* stateFrame = aFrame->GetParent();
-      nsEventStates eventStates = GetContentState(stateFrame, aWidgetType);
-
-      if (IsIndeterminateProgress(stateFrame, eventStates)) {
-        // If the element is indeterminate, we are going to render it ourself so
-        // we have to return aPart = -1.
-        aPart = -1;
-      } else if (IsVerticalProgress(stateFrame)) {
+    case NS_THEME_PROGRESSBAR_CHUNK:
+    case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: {
+      nsIFrame* parentFrame = aFrame->GetParent();
+      nsEventStates eventStates = GetContentState(parentFrame, aWidgetType);
+      if (aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL ||
+          IsVerticalProgress(parentFrame)) {
         aPart = WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION ?
           PP_FILLVERT : PP_CHUNKVERT;
       } else {
         aPart = WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION ?
           PP_FILL : PP_CHUNK;
       }
 
-      aState = TS_NORMAL;
-      return NS_OK;
-    }
-    case NS_THEME_PROGRESSBAR_VERTICAL: {
-      aPart = PP_BARVERT;
-      aState = TS_NORMAL;
-      return NS_OK;
-    }
-    case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: {
-      aPart = PP_CHUNKVERT;
-      aState = TS_NORMAL;
+      aState = PBBVS_NORMAL;
       return NS_OK;
     }
     case NS_THEME_TOOLBAR_BUTTON: {
       aPart = BP_BUTTON;
       if (!aFrame) {
         aState = TS_NORMAL;
         return NS_OK;
       }
@@ -1433,16 +1764,34 @@ RENDER_AGAIN:
   // The following widgets need to be RTL-aware
   else if (aWidgetType == NS_THEME_MENUARROW ||
            aWidgetType == NS_THEME_RESIZER ||
            aWidgetType == NS_THEME_DROPDOWN_BUTTON)
   {
     DrawThemeBGRTLAware(theme, hdc, part, state,
                         &widgetRect, &clipRect, IsFrameRTL(aFrame));
   }
+  else if (aWidgetType == NS_THEME_PROGRESSBAR ||
+           aWidgetType == NS_THEME_PROGRESSBAR_VERTICAL) {
+    // DrawThemeBackground renders each corner with a solid white pixel.
+    // Restore these pixels to the underlying color. Tracks are rendered
+    // using alpha recovery, so this makes the corners transparent.
+    COLORREF color;
+    color = GetPixel(hdc, widgetRect.left, widgetRect.top);
+    DrawThemeBackground(theme, hdc, part, state, &widgetRect, &clipRect);
+    SetPixel(hdc, widgetRect.left, widgetRect.top, color);
+    SetPixel(hdc, widgetRect.right-1, widgetRect.top, color);
+    SetPixel(hdc, widgetRect.right-1, widgetRect.bottom-1, color);
+    SetPixel(hdc, widgetRect.left, widgetRect.bottom-1, color);
+  }
+  else if (aWidgetType == NS_THEME_PROGRESSBAR_CHUNK ||
+           aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL) {
+    DrawThemedProgressMeter(aFrame, aWidgetType, theme, hdc, part, state,
+                            &widgetRect, &clipRect, p2a);
+  }
   // If part is negative, the element wishes us to not render a themed
   // background, instead opting to be drawn specially below.
   else if (part >= 0) {
     DrawThemeBackground(theme, hdc, part, state, &widgetRect, &clipRect);
   }
 
   // Draw focus rectangles for XP HTML checkboxes and radio buttons
   // XXX it'd be nice to draw these outside of the frame
@@ -1553,105 +1902,18 @@ RENDER_AGAIN:
     ctx->Fill();
 
     ctx->NewPath();
     ctx->Rectangle(buttonbox3, true);
     ctx->Fill();
 
     ctx->Restore();
     ctx->SetOperator(currentOp);
-  } else if (aWidgetType == NS_THEME_PROGRESSBAR_CHUNK) {
-    /**
-     * Here, we draw the animated part of the progress bar.
-     * A progress bar has always an animated part on Windows Vista and later.
-     * On Windows XP, a progress bar has an animated part when in an
-     * indeterminated state.
-     * When the progress bar is indeterminated, no background is painted so we
-     * only see the animated part.
-     * When the progress bar is determinated, the animated part is a glow draw
-     * on top of the background (PP_FILL).
-     */
-    nsIFrame* stateFrame = aFrame->GetParent();
-    nsEventStates eventStates = GetContentState(stateFrame, aWidgetType);
-    bool indeterminate = IsIndeterminateProgress(stateFrame, eventStates);
-    bool vertical = IsVerticalProgress(stateFrame);
-
-    if (indeterminate ||
-        WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION) {
-      if (!QueueAnimatedContentForRefresh(aFrame->GetContent(), 30)) {
-        NS_WARNING("unable to animate progress widget!");
-      }
-
-      /**
-       * Unfortunately, vertical progress bar support on Windows seems weak and
-       * PP_MOVEOVERLAYRECT looks really different from PP_MOVEOVERLAY.
-       * Thus, we have to change the size and even don't use it for vertical
-       * indeterminate progress bars.
-       */
-      int32_t overlaySize;
-      if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION) {
-        if (vertical) {
-          overlaySize = indeterminate ? kProgressVerticalIndeterminateOverlaySize
-                                      : kProgressVerticalOverlaySize;
-        } else {
-          overlaySize = kProgressHorizontalVistaOverlaySize;
-        }
-      } else {
-        overlaySize = kProgressHorizontalXPOverlaySize;
-      }
-
-      const double pixelsPerMillisecond = indeterminate
-                                            ? kProgressIndeterminateSpeed
-                                            : kProgressDeterminedVistaSpeed;
-      const int32_t delay = indeterminate ? kProgressIndeterminateDelay
-                                          : kProgressDeterminedVistaDelay;
-
-      const int32_t frameSize = vertical ? widgetRect.bottom - widgetRect.top
-                                         : widgetRect.right - widgetRect.left;
-      const int32_t animationSize = frameSize + overlaySize +
-                                     static_cast<int32_t>(pixelsPerMillisecond * delay);
-      const double interval = animationSize / pixelsPerMillisecond;
-      // We have to pass a double* to modf and we can't pass NULL.
-      double tempValue;
-      double ratio = modf(PR_IntervalToMilliseconds(PR_IntervalNow())/interval,
-                          &tempValue);
-      // If the frame direction is RTL, we want to have the animation going RTL.
-      // ratio is in [0.0; 1.0[ range, inverting it reverse the animation.
-      if (!vertical && IsFrameRTL(aFrame)) {
-        ratio = 1.0 - ratio;
-      }
-      int32_t dx = static_cast<int32_t>(animationSize * ratio) - overlaySize;
-
-      RECT overlayRect = widgetRect;
-      if (vertical) {
-        overlayRect.bottom -= dx;
-        overlayRect.top = overlayRect.bottom - overlaySize;
-      } else {
-        overlayRect.left += dx;
-        overlayRect.right = overlayRect.left + overlaySize;
-      }
-
-      int32_t overlayPart;
-      if (vertical) {
-        if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION) {
-          overlayPart = indeterminate ? PP_MOVEOVERLAY : PP_MOVEOVERLAYVERT;
-        } else {
-          overlayPart = PP_CHUNKVERT;
-        }
-      } else {
-        overlayPart = WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION ?
-          PP_MOVEOVERLAY : PP_CHUNK;
-      }
-
-      DrawThemeBackground(theme, hdc, overlayPart, state, &overlayRect,
-                          &clipRect);
-    }
   }
 
-
   nativeDrawing.EndNativeDrawing();
 
   if (nativeDrawing.ShouldRenderAgain())
     goto RENDER_AGAIN;
 
   nativeDrawing.PaintToContext();
 
   return NS_OK;
@@ -2300,16 +2562,20 @@ nsNativeThemeWin::GetWidgetTransparency(
     // performance, because we create layers for them. This better be
     // true across all Windows themes! If it's not true, we should
     // paint an opaque background for them to make it true!
     return eOpaque;
   case NS_THEME_WIN_GLASS:
   case NS_THEME_WIN_BORDERLESS_GLASS:
   case NS_THEME_SCALE_HORIZONTAL:
   case NS_THEME_SCALE_VERTICAL:
+  case NS_THEME_PROGRESSBAR:
+  case NS_THEME_PROGRESSBAR_VERTICAL:
+  case NS_THEME_PROGRESSBAR_CHUNK:
+  case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL:
     return eTransparent;
   }
 
   HANDLE theme = GetTheme(aWidgetType);
   // For the classic theme we don't really have a way of knowing
   if (!theme) {
     // menu backgrounds and tooltips which can't be themed are opaque
     if (aWidgetType == NS_THEME_MENUPOPUP || aWidgetType == NS_THEME_TOOLTIP) {
@@ -3360,85 +3626,37 @@ RENDER_AGAIN:
     }
     case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL:
       ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_HIGHLIGHT+1));
       break;
 
     case NS_THEME_PROGRESSBAR_CHUNK: {
       nsIFrame* stateFrame = aFrame->GetParent();
       nsEventStates eventStates = GetContentState(stateFrame, aWidgetType);
-      const bool indeterminate = IsIndeterminateProgress(stateFrame, eventStates);
-
-      if (!indeterminate) {
+
+      bool indeterminate = IsIndeterminateProgress(stateFrame, eventStates);
+      bool vertical = IsVerticalProgress(stateFrame) ||
+                      aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL;
+      int32_t overlayPart = GetProgressOverlayStyle(vertical);
+
+      nsIContent* content = aFrame->GetContent();
+      if (!indeterminate || !content) {
         ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_HIGHLIGHT+1));
         break;
       }
 
-      /**
-       * The indeterminate rendering is animated: the bar goes from one side to
-       * another.
-       */
+      RECT overlayRect =
+        CalculateProgressOverlayRect(aFrame, &widgetRect, vertical,
+                                     indeterminate, true);
+
+      ::FillRect(hdc, &overlayRect, (HBRUSH) (COLOR_HIGHLIGHT+1));
+
       if (!QueueAnimatedContentForRefresh(aFrame->GetContent(), 30)) {
         NS_WARNING("unable to animate progress widget!");
       }
-
-      const bool vertical = IsVerticalProgress(stateFrame);
-      const int32_t overlaySize = kProgressClassicOverlaySize;
-      const double pixelsPerMillisecond = kProgressClassicIndeterminateSpeed;
-      const int32_t frameSize = vertical ? widgetRect.bottom - widgetRect.top
-                                         : widgetRect.right - widgetRect.left;
-      const double interval = frameSize / pixelsPerMillisecond;
-      // We have to pass a double* to modf and we can't pass NULL.
-      double tempValue;
-      double ratio = modf(PR_IntervalToMilliseconds(PR_IntervalNow())/interval,
-                          &tempValue);
-      int32_t dx = 0;
-
-      // If the frame direction is RTL, we want to have the animation going RTL.
-      // ratio is in [0.0; 1.0[ range, inverting it reverse the animation.
-      if (!vertical && IsFrameRTL(aFrame)) {
-        ratio = 1.0 - ratio;
-        dx -= overlaySize;
-      }
-      dx += static_cast<int32_t>(frameSize * ratio);
-
-      RECT overlayRect = widgetRect;
-      if (vertical) {
-        overlayRect.bottom -= dx;
-        overlayRect.top = overlayRect.bottom - overlaySize;
-      } else {
-        overlayRect.left += dx;
-        overlayRect.right = overlayRect.left + overlaySize;
-      }
-
-      // Compute the leftover part.
-      RECT leftoverRect = widgetRect;
-      if (vertical) {
-        if (overlayRect.top < widgetRect.top) {
-          leftoverRect.bottom = widgetRect.bottom;
-          leftoverRect.top = leftoverRect.bottom + overlayRect.top - widgetRect.top;
-        }
-      } else if (IsFrameRTL(aFrame)) {
-        if (overlayRect.left < widgetRect.left) {
-          leftoverRect.right = widgetRect.right;
-          leftoverRect.left = leftoverRect.right + overlayRect.left - widgetRect.left;
-        }
-      } else if (overlayRect.right > widgetRect.right) {
-        leftoverRect.left = widgetRect.left;
-        leftoverRect.right = leftoverRect.left + overlayRect.right - widgetRect.right;
-      }
-
-      // Only show the leftover if the rect has been modified.
-      if (leftoverRect.top != widgetRect.top ||
-          leftoverRect.left != widgetRect.left ||
-          leftoverRect.right != widgetRect.right) {
-        ::FillRect(hdc, &leftoverRect, (HBRUSH) (COLOR_HIGHLIGHT+1));
-      }
-
-      ::FillRect(hdc, &overlayRect, (HBRUSH) (COLOR_HIGHLIGHT+1));
       break;
     }
 
     // Draw Tab
     case NS_THEME_TAB: {
       DrawTab(hdc, widgetRect,
         IsBottomTab(aFrame) ? BF_BOTTOM : BF_TOP, 
         IsSelectedTab(aFrame),
--- a/widget/windows/nsNativeThemeWin.h
+++ b/widget/windows/nsNativeThemeWin.h
@@ -3,24 +3,29 @@
  * 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 "nsITheme.h"
 #include "nsCOMPtr.h"
 #include "nsIAtom.h"
 #include "nsNativeTheme.h"
+#include "gfxTypes.h"
 #include <windows.h>
+#include "mozilla/TimeStamp.h"
 
 struct nsIntRect;
 struct nsIntSize;
 
 class nsNativeThemeWin : private nsNativeTheme,
                          public nsITheme {
 public:
+  typedef mozilla::TimeStamp TimeStamp;
+  typedef mozilla::TimeDuration TimeDuration;
+
   NS_DECL_ISUPPORTS_INHERITED
 
   // The nsITheme interface.
   NS_IMETHOD DrawWidgetBackground(nsRenderingContext* aContext,
                                   nsIFrame* aFrame,
                                   uint8_t aWidgetType,
                                   const nsRect& aRect,
                                   const nsRect& aDirtyRect);
@@ -65,42 +70,47 @@ public:
   nsNativeThemeWin();
   virtual ~nsNativeThemeWin();
 
 protected:
   HANDLE GetTheme(uint8_t aWidgetType);
   nsresult GetThemePartAndState(nsIFrame* aFrame, uint8_t aWidgetType,
                                 int32_t& aPart, int32_t& aState);
   nsresult ClassicGetThemePartAndState(nsIFrame* aFrame, uint8_t aWidgetType,
-                                   int32_t& aPart, int32_t& aState, bool& aFocused);
+                                       int32_t& aPart, int32_t& aState, bool& aFocused);
   nsresult ClassicDrawWidgetBackground(nsRenderingContext* aContext,
+                                       nsIFrame* aFrame,
+                                       uint8_t aWidgetType,
+                                       const nsRect& aRect,
+                                       const nsRect& aClipRect);
+  nsresult ClassicGetWidgetBorder(nsDeviceContext* aContext, 
                                   nsIFrame* aFrame,
                                   uint8_t aWidgetType,
-                                  const nsRect& aRect,
-                                  const nsRect& aClipRect);
-  nsresult ClassicGetWidgetBorder(nsDeviceContext* aContext, 
-                             nsIFrame* aFrame,
-                             uint8_t aWidgetType,
-                             nsIntMargin* aResult);
-
+                                  nsIntMargin* aResult);
   bool ClassicGetWidgetPadding(nsDeviceContext* aContext,
-                            nsIFrame* aFrame,
-                            uint8_t aWidgetType,
-                            nsIntMargin* aResult);
-
+                               nsIFrame* aFrame,
+                               uint8_t aWidgetType,
+                               nsIntMargin* aResult);
   nsresult ClassicGetMinimumWidgetSize(nsRenderingContext* aContext, nsIFrame* aFrame,
-                                  uint8_t aWidgetType,
-                                  nsIntSize* aResult,
-                                  bool* aIsOverridable);
-
+                                       uint8_t aWidgetType,
+                                       nsIntSize* aResult,
+                                       bool* aIsOverridable);
   bool ClassicThemeSupportsWidget(nsPresContext* aPresContext, 
-                             nsIFrame* aFrame,
-                             uint8_t aWidgetType);
-
+                                  nsIFrame* aFrame,
+                                  uint8_t aWidgetType);
   void DrawCheckedRect(HDC hdc, const RECT& rc, int32_t fore, int32_t back,
                        HBRUSH defaultBack);
-
   uint32_t GetWidgetNativeDrawingFlags(uint8_t aWidgetType);
-
   int32_t StandardGetState(nsIFrame* aFrame, uint8_t aWidgetType, bool wantFocused);
+  bool IsMenuActive(nsIFrame* aFrame, uint8_t aWidgetType);
+  RECT CalculateProgressOverlayRect(nsIFrame* aFrame, RECT* aWidgetRect,
+                                    bool aIsVertical, bool aIsIndeterminate,
+                                    bool aIsClassic);
+  void DrawThemedProgressMeter(nsIFrame* aFrame, int aWidgetType,
+                               HANDLE aTheme, HDC aHdc,
+                               int aPart, int aState,
+                               RECT* aWidgetRect, RECT* aClipRect,
+                               gfxFloat aAppUnits);
 
-  bool IsMenuActive(nsIFrame* aFrame, uint8_t aWidgetType);
+private:
+  TimeStamp mProgressDeterminateTimeStamp;
+  TimeStamp mProgressIndeterminateTimeStamp;
 };
--- a/widget/windows/nsUXThemeConstants.h
+++ b/widget/windows/nsUXThemeConstants.h
@@ -5,34 +5,34 @@
  * 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/. */
 
 /* 
  * The following constants are used to determine how a widget is drawn using
  * Windows' Theme API. For more information on theme parts and states see
  * http://msdn.microsoft.com/en-us/library/bb773210(VS.85).aspx
  */
+
+#include <vssym32.h>
+#include <vsstyle.h>
+
 #define THEME_COLOR 204
 #define THEME_FONT  210
 
 // Generic state constants
 #define TS_NORMAL    1
 #define TS_HOVER     2
 #define TS_ACTIVE    3
 #define TS_DISABLED  4
 #define TS_FOCUSED   5
 
 // These constants are reversed for the trackbar (scale) thumb
 #define TKP_FOCUSED   4
 #define TKP_DISABLED  5
 
-// Toolbar constants
-#define TP_BUTTON 1
-#define TP_SEPARATOR 5
-
 // Toolbarbutton constants
 #define TB_CHECKED       5
 #define TB_HOVER_CHECKED 6
 
 // Button constants
 #define BP_BUTTON    1
 #define BP_RADIO     2
 #define BP_CHECKBOX  3
@@ -73,26 +73,16 @@
 #define TKP_TRACKVERT      2
 #define TKP_THUMB          3
 #define TKP_THUMBVERT      6
 
 // Spin constants
 #define SPNP_UP            1
 #define SPNP_DOWN          2
 
-// Progress bar constants
-#define PP_BAR             1
-#define PP_BARVERT         2
-#define PP_CHUNK           3
-#define PP_CHUNKVERT       4
-#define PP_FILL            5
-#define PP_FILLVERT        6
-#define PP_MOVEOVERLAY     8
-#define PP_MOVEOVERLAYVERT 9
-
 // Tab constants
 #define TABP_TAB             4
 #define TABP_TAB_SELECTED    5
 #define TABP_PANELS          9
 #define TABP_PANEL           10
 
 // Tooltip constants
 #define TTP_STANDARD         1
@@ -146,22 +136,16 @@
 #define MPI_NORMAL 1
 #define MPI_HOT 2
 #define MPI_DISABLED 3
 #define MPI_DISABLEDHOT 4
 
 #define MSM_NORMAL 1
 #define MSM_DISABLED 2
 
-// From tmschema.h in the Vista SDK
-#define TMT_TEXTCOLOR 3803
-#define TMT_SIZINGMARGINS 3601
-#define TMT_CONTENTMARGINS 3602
-#define TMT_CAPTIONMARGINS 3603
-
 // Rebar constants
 #define RP_BAND              3
 #define RP_BACKGROUND        6
 
 // Constants only found in new (98+, 2K+, XP+, etc.) Windows.
 #ifdef DFCS_HOT
 #undef DFCS_HOT
 #endif
--- a/widget/xpwidgets/nsNativeTheme.cpp
+++ b/widget/xpwidgets/nsNativeTheme.cpp
@@ -9,16 +9,17 @@
 #include "nsIContent.h"
 #include "nsIFrame.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsEventStateManager.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIDOMHTMLInputElement.h"
+#include "nsIDOMHTMLProgressElement.h"
 #include "nsIDOMXULMenuListElement.h"
 #include "nsThemeConstants.h"
 #include "nsIComponentManager.h"
 #include "nsPIDOMWindow.h"
 #include "nsProgressFrame.h"
 #include "nsMeterFrame.h"
 #include "nsMenuFrame.h"
 #include "mozilla/dom/Element.h"
@@ -96,16 +97,17 @@ nsNativeTheme::GetContentState(nsIFrame*
   nsPIDOMWindow* window = doc->GetWindow();
   if (window && !window->ShouldShowFocusRing())
     flags &= ~NS_EVENT_STATE_FOCUS;
 #endif
   
   return flags;
 }
 
+/* static */
 bool
 nsNativeTheme::CheckBooleanAttr(nsIFrame* aFrame, nsIAtom* aAtom)
 {
   if (!aFrame)
     return false;
 
   nsIContent* content = aFrame->GetContent();
   if (!content)
@@ -116,32 +118,71 @@ nsNativeTheme::CheckBooleanAttr(nsIFrame
 
   // For XML/XUL elements, an attribute must be equal to the literal
   // string "true" to be counted as true.  An empty string should _not_
   // be counted as true.
   return content->AttrValueIs(kNameSpaceID_None, aAtom,
                               NS_LITERAL_STRING("true"), eCaseMatters);
 }
 
+/* static */
 int32_t
 nsNativeTheme::CheckIntAttr(nsIFrame* aFrame, nsIAtom* aAtom, int32_t defaultValue)
 {
   if (!aFrame)
     return defaultValue;
 
   nsAutoString attr;
   aFrame->GetContent()->GetAttr(kNameSpaceID_None, aAtom, attr);
   nsresult err;
   int32_t value = attr.ToInteger(&err);
   if (attr.IsEmpty() || NS_FAILED(err))
     return defaultValue;
 
   return value;
 }
 
+/* static */
+double
+nsNativeTheme::GetProgressValue(nsIFrame* aFrame)
+{
+  // When we are using the HTML progress element,
+  // we can get the value from the IDL property.
+  if (aFrame) {
+    nsCOMPtr<nsIDOMHTMLProgressElement> progress =
+      do_QueryInterface(aFrame->GetContent());
+    if (progress) {
+      double value;
+      progress->GetValue(&value);
+      return value;
+    }
+  }
+
+  return (double)nsNativeTheme::CheckIntAttr(aFrame, nsGkAtoms::value, 0);
+}
+
+/* static */
+double
+nsNativeTheme::GetProgressMaxValue(nsIFrame* aFrame)
+{
+  // When we are using the HTML progress element,
+  // we can get the max from the IDL property.
+  if (aFrame) {
+    nsCOMPtr<nsIDOMHTMLProgressElement> progress =
+      do_QueryInterface(aFrame->GetContent());
+    if (progress) {
+      double max;
+      progress->GetMax(&max);
+      return max;
+    }
+  }
+
+  return (double)std::max(nsNativeTheme::CheckIntAttr(aFrame, nsGkAtoms::max, 100), 1);
+}
+
 bool
 nsNativeTheme::GetCheckedOrSelected(nsIFrame* aFrame, bool aCheckSelected)
 {
   if (!aFrame)
     return false;
 
   nsIContent* content = aFrame->GetContent();
 
@@ -298,16 +339,27 @@ nsNativeTheme::IsDisabled(nsIFrame* aFra
 }
 
 bool
 nsNativeTheme::IsFrameRTL(nsIFrame* aFrame)
 {
   return aFrame && aFrame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
 }
 
+bool
+nsNativeTheme::IsHTMLContent(nsIFrame *aFrame)
+{
+  if (!aFrame) {
+    return false;
+  }
+  nsIContent* content = aFrame->GetContent();
+  return content && content->IsHTML();
+}
+
+
 // scrollbar button:
 int32_t
 nsNativeTheme::GetScrollbarButtonType(nsIFrame* aFrame)
 {
   if (!aFrame)
     return 0;
 
   static nsIContent::AttrValuesArray strings[] =
--- a/widget/xpwidgets/nsNativeTheme.h
+++ b/widget/xpwidgets/nsNativeTheme.h
@@ -54,37 +54,39 @@ class nsNativeTheme : public nsITimerCal
 
   // Accessors to widget-specific state information
 
   bool IsDisabled(nsIFrame* aFrame, nsEventStates aEventStates);
 
   // RTL chrome direction
   bool IsFrameRTL(nsIFrame* aFrame);
 
+  bool IsHTMLContent(nsIFrame *aFrame);
+  
   // button:
   bool IsDefaultButton(nsIFrame* aFrame) {
     return CheckBooleanAttr(aFrame, nsGkAtoms::_default);
   }
 
   bool IsButtonTypeMenu(nsIFrame* aFrame);
 
   // checkbox:
   bool IsChecked(nsIFrame* aFrame) {
     return GetCheckedOrSelected(aFrame, false);
   }
 
   // radiobutton:
   bool IsSelected(nsIFrame* aFrame) {
     return GetCheckedOrSelected(aFrame, true);
   }
-  
+
   bool IsFocused(nsIFrame* aFrame) {
     return CheckBooleanAttr(aFrame, nsGkAtoms::focused);
   }
-  
+
   // scrollbar button:
   int32_t GetScrollbarButtonType(nsIFrame* aFrame);
 
   // tab:
   bool IsSelectedTab(nsIFrame* aFrame) {
     return CheckBooleanAttr(aFrame, nsGkAtoms::selected);
   }
   
@@ -148,18 +150,22 @@ class nsNativeTheme : public nsITimerCal
   bool IsSubmenu(nsIFrame* aFrame, bool* aLeftOfParent);
 
   // True if it's not a menubar item or menulist item
   bool IsRegularMenuItem(nsIFrame *aFrame);
 
   bool IsMenuListEditable(nsIFrame *aFrame);
 
   nsIPresShell *GetPresShell(nsIFrame* aFrame);
-  int32_t CheckIntAttr(nsIFrame* aFrame, nsIAtom* aAtom, int32_t defaultValue);
-  bool CheckBooleanAttr(nsIFrame* aFrame, nsIAtom* aAtom);
+  static bool CheckBooleanAttr(nsIFrame* aFrame, nsIAtom* aAtom);
+  static int32_t CheckIntAttr(nsIFrame* aFrame, nsIAtom* aAtom, int32_t defaultValue);
+
+  // Helpers for progressbar.
+  static double GetProgressValue(nsIFrame* aFrame);
+  static double GetProgressMaxValue(nsIFrame* aFrame);
 
   bool GetCheckedOrSelected(nsIFrame* aFrame, bool aCheckSelected);
   bool GetIndeterminate(nsIFrame* aFrame);
 
   bool QueueAnimatedContentForRefresh(nsIContent* aContent,
                                         uint32_t aMinimumFrameRate);
 
   nsIFrame* GetAdjacentSiblingFrameWithSameAppearance(nsIFrame* aFrame,
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -2539,21 +2539,16 @@ nsCycleCollector::BeginCollection(bool a
                 if (pi->mColor == black &&
                     pi->mRefCount > 0 && pi->mRefCount < UINT32_MAX &&
                     pi->mInternalRefs != pi->mRefCount) {
                     aListener->DescribeRoot((uint64_t)pi->mPointer,
                                             pi->mInternalRefs);
                 }
             }
         }
-
-        if (mJSRuntime) {
-            mJSRuntime->FinishTraverse();
-            timeLog.Checkpoint("mJSRuntime->FinishTraverse()");
-        }
     } else {
         mScanInProgress = false;
     }
 
     return true;
 }
 
 bool
--- a/xpcom/base/nsCycleCollector.h
+++ b/xpcom/base/nsCycleCollector.h
@@ -41,17 +41,16 @@ void nsCycleCollector_collect(bool aMerg
 uint32_t nsCycleCollector_suspectedCount();
 void nsCycleCollector_shutdownThreads();
 void nsCycleCollector_shutdown();
 
 // Various methods the cycle collector needs to deal with Javascript.
 struct nsCycleCollectionJSRuntime
 {
     virtual nsresult BeginCycleCollection(nsCycleCollectionTraversalCallback &cb) = 0;
-    virtual nsresult FinishTraverse() = 0;
 
     /**
      * Called before/after transitioning to/from the main thread.
      *
      * NotifyLeaveMainThread may return 'false' to prevent the cycle collector
      * from leaving the main thread.
      */
     virtual bool NotifyLeaveMainThread() = 0;