Merge inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 10 Jun 2013 15:43:58 -0400
changeset 134554 9115d8b717e130d229e314e9b26a9557aec3f81b
parent 134553 b817144c8fff21ea590265cf5867be736458e262 (current diff)
parent 134531 48d63831553ff33f9ce5f352d5e249fae0a192b0 (diff)
child 134555 2f6978e0b8e30a815365c0f674830d985d06e22c
child 134619 0729c58e4977fb14290ad0babe8826f3e8471fc8
child 134670 fd5b82351fac9504e11f7ffcd6df806d494c1711
child 155479 6f6a26b8f4c34c14e60af3ba955653fe38988a8e
push id29266
push userryanvm@gmail.com
push dateMon, 10 Jun 2013 19:46:08 +0000
treeherdermozilla-inbound@2f6978e0b8e3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone24.0a1
first release with
nightly linux32
9115d8b717e1 / 24.0a1 / 20130611031140 / files
nightly linux64
9115d8b717e1 / 24.0a1 / 20130611031140 / files
nightly mac
9115d8b717e1 / 24.0a1 / 20130611031140 / files
nightly win32
9115d8b717e1 / 24.0a1 / 20130611031140 / files
nightly win64
9115d8b717e1 / 24.0a1 / 20130611031140 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c.
mobile/android/themes/core/images/reader-list-icon-hdpi.png
mobile/android/themes/core/images/reader-list-icon-mdpi.png
mobile/android/themes/core/images/reader-list-icon-xhdpi.png
testing/marionette/marionette-actors.js
--- a/accessible/src/atk/Makefile.in
+++ b/accessible/src/atk/Makefile.in
@@ -13,18 +13,20 @@ LIBRARY_NAME = accessibility_toolkit_s
 EXPORT_LIBRARY = ..
 LIBXUL_LIBRARY = 1
 
 # we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
-CFLAGS  	+= $(MOZ_GTK2_CFLAGS)
-CXXFLAGS  += $(MOZ_GTK2_CFLAGS)
+ifdef MOZ_ENABLE_GTK
+CFLAGS      += $(TK_CFLAGS)
+CXXFLAGS    += $(TK_CFLAGS)
+endif
 
 ifdef MOZ_ENABLE_DBUS
 CXXFLAGS += $(MOZ_DBUS_CFLAGS)
 endif
 
 LOCAL_INCLUDES += \
   -I$(srcdir) \
   -I$(srcdir)/../base \
--- a/accessible/src/atk/nsStateMap.h
+++ b/accessible/src/atk/nsStateMap.h
@@ -56,17 +56,17 @@ struct AtkStateMap {
       ++ stateIndex;
       aState >>= 1;
     }
     return stateIndex;  // Returns -1 if not mapped
   }
 };
 
 
-// Map array from cross platform roles to  ATK roles
+// Map array from cross platform states to ATK states
 static const AtkStateMap gAtkStateMap[] = {                     // Cross Platform States
   { kNone,                                    kMapOpposite },   // states::UNAVAILABLE             = 1 << 0
   { ATK_STATE_SELECTED,                       kMapDirectly },   // states::SELECTED                = 1 << 1
   { ATK_STATE_FOCUSED,                        kMapDirectly },   // states::FOCUSED                 = 1 << 2
   { ATK_STATE_PRESSED,                        kMapDirectly },   // states::PRESSED                 = 1 << 3
   { ATK_STATE_CHECKED,                        kMapDirectly },   // states::CHECKED                 = 1 << 4
   { ATK_STATE_INDETERMINATE,                  kMapDirectly },   // states::MIXED                   = 1 << 5
   { kNone,                                    kMapDirectly },   // states::READONLY                = 1 << 6
--- a/accessible/src/base/Makefile.in
+++ b/accessible/src/base/Makefile.in
@@ -23,19 +23,21 @@ LOCAL_INCLUDES += \
   -I$(srcdir)/../html \
   -I$(srcdir)/../xpcom \
   -I$(srcdir)/../xul \
   -I$(srcdir)/../../../layout/generic \
   -I$(srcdir)/../../../layout/style \
   -I$(srcdir)/../../../layout/svg \
   -I$(srcdir)/../../../layout/xul/base/src \
   -I$(srcdir)/../../../layout/xul/tree/ \
+  -I$(srcdir)/../../../ipc/chromium/src \
   $(NULL)
 
-ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
+ifdef MOZ_ENABLE_GTK
+CXXFLAGS        += $(MOZ_CAIRO_CFLAGS)
 LOCAL_INCLUDES += \
   -I$(srcdir)/../atk \
   $(NULL)
 else
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 LOCAL_INCLUDES += \
   -I$(srcdir)/../windows/msaa \
   -I$(srcdir)/../windows/ia2 \
--- a/accessible/src/generic/Makefile.in
+++ b/accessible/src/generic/Makefile.in
@@ -23,17 +23,17 @@ LOCAL_INCLUDES = \
   -I$(srcdir)/../html \
   -I$(srcdir)/../xul \
   -I$(srcdir)/../../../content/base/src \
   -I$(srcdir)/../../../content/html/content/src \
   -I$(srcdir)/../../../layout/generic \
   -I$(srcdir)/../../../layout/xul/base/src \
   $(NULL)
 
-ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
+ifdef MOZ_ENABLE_GTK
 LOCAL_INCLUDES += \
   -I$(srcdir)/../atk \
   $(NULL)
 else
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 LOCAL_INCLUDES += \
   -I$(srcdir)/../windows/msaa \
   $(NULL)
--- a/accessible/src/html/Makefile.in
+++ b/accessible/src/html/Makefile.in
@@ -24,17 +24,17 @@ LOCAL_INCLUDES = \
   -I$(srcdir)/../xpcom \
   -I$(srcdir)/../../../content/base/src \
   -I$(srcdir)/../../../content/html/content/src \
   -I$(srcdir)/../../../layout/generic \
   -I$(srcdir)/../../../layout/tables \
   -I$(srcdir)/../../../layout/xul/base/src \
   $(NULL)
 
-ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
+ifdef MOZ_ENABLE_GTK
 LOCAL_INCLUDES += \
   -I$(srcdir)/../atk \
   $(NULL)
 else
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 LOCAL_INCLUDES += \
   -I$(srcdir)/../windows/msaa \
   -I$(srcdir)/../windows/ia2 \
--- a/accessible/src/jsat/AccessFu.jsm
+++ b/accessible/src/jsat/AccessFu.jsm
@@ -407,17 +407,17 @@ var Output = {
         highlightBox.style.display = 'block';
 
         break;
       }
       case 'hideBounds':
       {
         let highlightBox = this.highlightBox ? this.highlightBox.get() : null;
         if (highlightBox)
-          highlightBox.get().style.display = 'none';
+          highlightBox.style.display = 'none';
         break;
       }
       case 'showAnnouncement':
       {
         let announceBox = this.announceBox ? this.announceBox.get() : null;
         if (!announceBox) {
           announceBox = Utils.win.document.
             createElementNS('http://www.w3.org/1999/xhtml', 'div');
--- a/accessible/src/moz.build
+++ b/accessible/src/moz.build
@@ -1,17 +1,17 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # 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/.
 
 toolkit = CONFIG['MOZ_WIDGET_TOOLKIT']
 
-if toolkit == 'gtk2':
+if CONFIG['MOZ_ENABLE_GTK']:
     DIRS += ['atk']
 elif toolkit == 'windows':
     DIRS += ['windows']
 elif toolkit == 'cocoa':
     DIRS += ['mac']
 else:
     DIRS += ['other']
 
--- a/accessible/src/xpcom/Makefile.in
+++ b/accessible/src/xpcom/Makefile.in
@@ -20,17 +20,17 @@ EXTRA_MDDEPEND_FILES = xpcAccEvents.pp
 
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES = \
   -I$(srcdir)/../base \
   -I$(srcdir)/../generic \
   $(NULL)
 
-ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
+ifdef MOZ_ENABLE_GTK
 LOCAL_INCLUDES += \
   -I$(srcdir)/../atk \
   $(NULL)
 else
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 LOCAL_INCLUDES += \
   -I$(srcdir)/../windows/msaa \
   $(NULL)
--- a/accessible/src/xul/Makefile.in
+++ b/accessible/src/xul/Makefile.in
@@ -24,17 +24,17 @@ LOCAL_INCLUDES = \
   -I$(srcdir)/../generic \
   -I$(srcdir)/../html \
   -I$(srcdir)/../xpcom \
   -I$(srcdir)/../../../layout/generic \
   -I$(srcdir)/../../../layout/xul/base/src \
   -I$(srcdir)/../../../layout/xul/tree// \
   $(NULL)
 
-ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
+ifdef MOZ_ENABLE_GTK
 LOCAL_INCLUDES += \
   -I$(srcdir)/../atk \
   $(NULL)
 else
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 LOCAL_INCLUDES += \
   -I$(srcdir)/../windows/msaa \
   -I$(srcdir)/../windows/ia2 \
--- a/accessible/src/xul/XULTabAccessible.cpp
+++ b/accessible/src/xul/XULTabAccessible.cpp
@@ -85,20 +85,20 @@ XULTabAccessible::NativeState()
 
   // Check whether the tab is selected and/or pinned
   nsCOMPtr<nsIDOMXULSelectControlItemElement> tab(do_QueryInterface(mContent));
   if (tab) {
     bool selected = false;
     if (NS_SUCCEEDED(tab->GetSelected(&selected)) && selected)
       state |= states::SELECTED;
 
-    if (mContent && mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::pinned) &&
-        mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::pinned,
+    if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::pinned,
                               nsGkAtoms::_true, eCaseMatters))
       state |= states::PINNED;
+
   }
 
   return state;
 }
 
 uint64_t
 XULTabAccessible::NativeInteractiveState() const
 {
--- a/browser/components/Makefile.in
+++ b/browser/components/Makefile.in
@@ -4,17 +4,17 @@
 
 DEPTH     = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
-EXTRA_COMPONENTS = \
+DISABLED_EXTRA_COMPONENTS = \
   BrowserComponents.manifest \
   $(NULL)
 
 EXTRA_PP_COMPONENTS = \
   nsBrowserContentHandler.js \
   nsBrowserGlue.js \
   $(NULL)
 
--- a/browser/components/downloads/content/indicator.js
+++ b/browser/components/downloads/content/indicator.js
@@ -354,16 +354,20 @@ const DownloadsIndicatorView = {
    *        Set to "start" for new downloads, "finish" for completed downloads.
    */
   showEventNotification: function DIV_showEventNotification(aType)
   {
     if (!this._initialized) {
       return;
     }
 
+    if (!DownloadsCommon.animateNotifications) {
+      return;
+    }
+
     // No need to show visual notification if the panel is visible.
     if (DownloadsPanel.isPanelShowing) {
       return;
     }
 
     function DIV_SEN_callback() {
       if (this._notificationTimeout) {
         clearTimeout(this._notificationTimeout);
--- a/browser/components/downloads/src/DownloadsCommon.jsm
+++ b/browser/components/downloads/src/DownloadsCommon.jsm
@@ -87,55 +87,77 @@ const kDownloadsStringsRequiringPluralFo
 
 XPCOMUtils.defineLazyGetter(this, "DownloadsLocalFileCtor", function () {
   return Components.Constructor("@mozilla.org/file/local;1",
                                 "nsILocalFile", "initWithPath");
 });
 
 const kPartialDownloadSuffix = ".part";
 
-const kPrefDebug = "browser.download.debug";
+const kPrefBranch = Services.prefs.getBranch("browser.download.");
 
-let DebugPrefObserver = {
+let PrefObserver = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
                                          Ci.nsISupportsWeakReference]),
-  observe: function PDO_observe(aSubject, aTopic, aData) {
-    this.debugEnabled = Services.prefs.getBoolPref(kPrefDebug);
-  }
-}
+  getPref: function PO_getPref(name) {
+    try {
+      switch (typeof this.prefs[name]) {
+        case "boolean":
+          return kPrefBranch.getBoolPref(name);
+      }
+    } catch (ex) { }
+    return this.prefs[name];
+  },
+  observe: function PO_observe(aSubject, aTopic, aData) {
+    if (this.prefs.hasOwnProperty(aData)) {
+      return this[aData] = this.getPref(aData);
+    }
+  },
+  register: function PO_register(prefs) {
+    this.prefs = prefs;
+    kPrefBranch.addObserver("", this, true);
+    for (let key in prefs) {
+      let name = key;
+      XPCOMUtils.defineLazyGetter(this, name, function () {
+        return PrefObserver.getPref(name);
+      });
+    }
+  },
+};
 
-XPCOMUtils.defineLazyGetter(DebugPrefObserver, "debugEnabled", function () {
-  Services.prefs.addObserver(kPrefDebug, DebugPrefObserver, true);
-  return Services.prefs.getBoolPref(kPrefDebug);
+PrefObserver.register({
+  // prefName: defaultValue
+  debug: false,
+  animateNotifications: true
 });
 
 
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadsCommon
 
 /**
  * This object is exposed directly to the consumers of this JavaScript module,
  * and provides shared methods for all the instances of the user interface.
  */
 this.DownloadsCommon = {
   log: function DC_log(...aMessageArgs) {
     delete this.log;
     this.log = function DC_log(...aMessageArgs) {
-      if (!DebugPrefObserver.debugEnabled) {
+      if (!PrefObserver.debug) {
         return;
       }
       DownloadsLogger.log.apply(DownloadsLogger, aMessageArgs);
     }
     this.log.apply(this, aMessageArgs);
   },
 
   error: function DC_error(...aMessageArgs) {
     delete this.error;
     this.error = function DC_error(...aMessageArgs) {
-      if (!DebugPrefObserver.debugEnabled) {
+      if (!PrefObserver.debug) {
         return;
       }
       DownloadsLogger.reportError.apply(DownloadsLogger, aMessageArgs);
     }
     this.error.apply(this, aMessageArgs);
   },
   /**
    * Returns an object whose keys are the string names from the downloads string
@@ -213,16 +235,25 @@ this.DownloadsCommon = {
   {
     try {
       return Services.prefs.getBoolPref("browser.download.useToolkitUI");
     } catch (ex) { }
     return false;
   },
 
   /**
+   * Indicates whether we should show visual notification on the indicator
+   * when a download event is triggered.
+   */
+  get animateNotifications()
+  {
+    return PrefObserver.animateNotifications;
+  },
+
+  /**
    * Get access to one of the DownloadsData or PrivateDownloadsData objects,
    * depending on the privacy status of the window in question.
    *
    * @param aWindow
    *        The browser window which owns the download button.
    */
   getData: function DC_getData(aWindow) {
     if (PrivateBrowsingUtils.isWindowPrivate(aWindow)) {
--- a/browser/components/downloads/src/Makefile.in
+++ b/browser/components/downloads/src/Makefile.in
@@ -4,17 +4,17 @@
 
 DEPTH     = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
-EXTRA_COMPONENTS = \
+DISABLED_EXTRA_COMPONENTS = \
   BrowserDownloads.manifest \
   DownloadsUI.js \
   DownloadsStartup.js \
   $(NULL)
 
 EXTRA_JS_MODULES = \
   DownloadsCommon.jsm \
   DownloadsLogger.jsm \
--- a/browser/components/downloads/src/moz.build
+++ b/browser/components/downloads/src/moz.build
@@ -1,6 +1,11 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # 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/.
 
+EXTRA_COMPONENTS += [
+    'BrowserDownloads.manifest',
+    'DownloadsStartup.js',
+    'DownloadsUI.js',
+]
--- a/browser/components/feeds/src/Makefile.in
+++ b/browser/components/feeds/src/Makefile.in
@@ -14,17 +14,17 @@ LIBRARY_NAME = browser_feeds_s
 FORCE_STATIC_LIB = 1
 USE_STATIC_LIBS = 1
 
 DEFINES += \
 	-DMOZ_APP_NAME=$(MOZ_APP_NAME) \
 	-DMOZ_MACBUNDLE_NAME=$(MOZ_MACBUNDLE_NAME) \
 	$(NULL)
 
-EXTRA_COMPONENTS = \
+DISABLED_EXTRA_COMPONENTS = \
   BrowserFeeds.manifest \
 	FeedConverter.js \
 	WebContentConverter.js \
   $(NULL)
 
 EXTRA_PP_COMPONENTS = \
 	FeedWriter.js \
 	$(NULL)
--- a/browser/components/feeds/src/moz.build
+++ b/browser/components/feeds/src/moz.build
@@ -5,8 +5,13 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MODULE = 'browser_feeds'
 
 CPP_SOURCES += [
     'nsFeedSniffer.cpp',
 ]
 
+EXTRA_COMPONENTS += [
+    'BrowserFeeds.manifest',
+    'FeedConverter.js',
+    'WebContentConverter.js',
+]
--- a/browser/components/migration/src/Makefile.in
+++ b/browser/components/migration/src/Makefile.in
@@ -9,27 +9,27 @@ VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME	= migration_s
 
 FORCE_STATIC_LIB = 1
 USE_STATIC_LIBS = 1
 
-EXTRA_COMPONENTS = \
+DISABLED_EXTRA_COMPONENTS = \
   ProfileMigrator.js \
   FirefoxProfileMigrator.js \
   $(NULL)
 
 EXTRA_PP_COMPONENTS = \
   ChromeProfileMigrator.js \
   $(NULL)
 
 ifeq ($(OS_ARCH),WINNT)
-EXTRA_COMPONENTS += IEProfileMigrator.js \
+DISABLED_EXTRA_COMPONENTS += IEProfileMigrator.js \
                     $(NULL)
 
 EXTRA_PP_COMPONENTS += SafariProfileMigrator.js \
                        $(NULL)
 
 DEFINES += -DHAS_IE_MIGRATOR -DHAS_SAFARI_MIGRATOR
 endif
 
--- a/browser/components/migration/src/moz.build
+++ b/browser/components/migration/src/moz.build
@@ -5,8 +5,18 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MODULE = 'migration'
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     CPP_SOURCES += [
         'nsIEHistoryEnumerator.cpp',
     ]
+
+EXTRA_COMPONENTS += [
+    'FirefoxProfileMigrator.js',
+    'ProfileMigrator.js',
+]
+
+if CONFIG['OS_ARCH'] == 'WINNT':
+    EXTRA_COMPONENTS += [
+        'IEProfileMigrator.js',
+    ]
--- a/browser/components/moz.build
+++ b/browser/components/moz.build
@@ -31,8 +31,11 @@ XPIDL_SOURCES += [
     'nsIBrowserGlue.idl',
     'nsIBrowserHandler.idl',
 ]
 
 XPIDL_MODULE = 'browsercompsbase'
 
 MODULE = 'browsercomps'
 
+EXTRA_COMPONENTS += [
+    'BrowserComponents.manifest',
+]
--- a/browser/components/places/src/Makefile.in
+++ b/browser/components/places/src/Makefile.in
@@ -5,17 +5,17 @@
 
 DEPTH = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
-EXTRA_COMPONENTS = \
+DISABLED_EXTRA_COMPONENTS = \
   BrowserPlaces.manifest \
   PlacesProtocolHandler.js \
   $(NULL)
 
 EXTRA_JS_MODULES = \
   PlacesUIUtils.jsm \
   $(NULL)
 
--- a/browser/components/places/src/moz.build
+++ b/browser/components/places/src/moz.build
@@ -3,8 +3,12 @@
 # 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/.
 
 XPIDL_FLAGS += [
     '-I$(topsrcdir)/browser/components',
 ]
 
+EXTRA_COMPONENTS += [
+    'BrowserPlaces.manifest',
+    'PlacesProtocolHandler.js',
+]
--- a/browser/components/sessionstore/src/Makefile.in
+++ b/browser/components/sessionstore/src/Makefile.in
@@ -5,17 +5,17 @@
 DEPTH     = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/config.mk
 
-EXTRA_COMPONENTS = \
+DISABLED_EXTRA_COMPONENTS = \
   nsSessionStore.manifest \
   nsSessionStore.js \
   nsSessionStartup.js \
   $(NULL)
 
 JS_MODULES_PATH := $(FINAL_TARGET)/modules/sessionstore
 
 EXTRA_JS_MODULES := \
--- a/browser/components/sessionstore/src/moz.build
+++ b/browser/components/sessionstore/src/moz.build
@@ -1,6 +1,11 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # 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/.
 
+EXTRA_COMPONENTS += [
+    'nsSessionStartup.js',
+    'nsSessionStore.js',
+    'nsSessionStore.manifest',
+]
--- a/browser/components/shell/src/Makefile.in
+++ b/browser/components/shell/src/Makefile.in
@@ -27,17 +27,17 @@ ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 LIBRARY_NAME = shellservice_s
 else
 ifeq ($(MOZ_WIDGET_TOOLKIT), gtk2)
 LIBRARY_NAME = shellservice_s
 endif
 endif
 endif
 
-EXTRA_COMPONENTS = nsSetDefaultBrowser.js nsSetDefaultBrowser.manifest
+DISABLED_EXTRA_COMPONENTS = nsSetDefaultBrowser.js nsSetDefaultBrowser.manifest
 
 include $(topsrcdir)/config/rules.mk
 
 DEFINES += -DMOZ_APP_NAME=\"$(MOZ_APP_NAME)\" \
   -DMOZ_APP_VERSION=\"$(MOZ_APP_VERSION)\"
 
 CXXFLAGS += $(TK_CFLAGS)
 
--- a/browser/components/shell/src/moz.build
+++ b/browser/components/shell/src/moz.build
@@ -13,8 +13,13 @@ if CONFIG['OS_ARCH'] == 'WINNT':
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     CPP_SOURCES += [
         'nsMacShellService.cpp',
     ]
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk2':
     CPP_SOURCES += [
         'nsGNOMEShellService.cpp',
     ]
+
+EXTRA_COMPONENTS += [
+    'nsSetDefaultBrowser.js',
+    'nsSetDefaultBrowser.manifest',
+]
--- a/browser/components/sidebar/Makefile.in
+++ b/browser/components/sidebar/Makefile.in
@@ -5,15 +5,15 @@
 
 DEPTH		= @DEPTH@
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
-EXTRA_COMPONENTS = \
+DISABLED_EXTRA_COMPONENTS = \
   nsSidebar.manifest \
   nsSidebar.js \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
--- a/browser/components/sidebar/moz.build
+++ b/browser/components/sidebar/moz.build
@@ -1,6 +1,10 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # 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/.
 
+EXTRA_COMPONENTS += [
+    'nsSidebar.js',
+    'nsSidebar.manifest',
+]
--- a/browser/devtools/debugger/test/binary_search.js
+++ b/browser/devtools/debugger/test/binary_search.js
@@ -20,10 +20,10 @@
     } else {
       return -1;
     }
   };
 
 }).call(this);
 
 /*
-//@ sourceMappingURL=binary_search.map
+//# sourceMappingURL=binary_search.map
 */
--- a/browser/fuel/src/Makefile.in
+++ b/browser/fuel/src/Makefile.in
@@ -4,12 +4,12 @@
 
 DEPTH     = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
-EXTRA_COMPONENTS = fuelApplication.manifest
+DISABLED_EXTRA_COMPONENTS = fuelApplication.manifest
 EXTRA_PP_COMPONENTS = fuelApplication.js
 
 include $(topsrcdir)/config/rules.mk
--- a/browser/fuel/src/moz.build
+++ b/browser/fuel/src/moz.build
@@ -1,8 +1,11 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # 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/.
 
 MODULE = 'fuel'
 
+EXTRA_COMPONENTS += [
+    'fuelApplication.manifest',
+]
--- a/browser/metro/base/tests/mochitest/browser_context_menu_tests_03.html
+++ b/browser/metro/base/tests/mochitest/browser_context_menu_tests_03.html
@@ -44,11 +44,45 @@ Hello there. <a id="rlink1" href="#hello
 <br />
 <br />
 <br />
 <br />
 <br />
 <br />
 <br />
 <br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
+<br />
 
 </div>
 </body></html>
\ No newline at end of file
--- a/build/unix/stdc++compat/Makefile.in
+++ b/build/unix/stdc++compat/Makefile.in
@@ -5,17 +5,17 @@
 DEPTH		= @DEPTH@
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME	= stdc++compat
-HOST_LIBRARY_NAME = host_stdc++compat
+DISABLED_HOST_LIBRARY_NAME = host_stdc++compat
 FORCE_STATIC_LIB= 1
 STL_FLAGS =
 NO_EXPAND_LIBS = 1
 NO_PROFILE_GUIDED_OPTIMIZE = 1
 
   $(NULL)
 
 HOST_CPPSRCS = $(CPPSRCS)
--- a/build/unix/stdc++compat/moz.build
+++ b/build/unix/stdc++compat/moz.build
@@ -5,8 +5,9 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MODULE = 'build'
 
 CPP_SOURCES += [
     'stdc++compat.cpp',
 ]
 
+HOST_LIBRARY_NAME = 'host_stdc++compat'
--- a/dom/activities/src/Makefile.in
+++ b/dom/activities/src/Makefile.in
@@ -11,17 +11,17 @@ include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME     = dom_activities_s
 LIBXUL_LIBRARY   = 1
 FORCE_STATIC_LIB = 1
 FAIL_ON_WARNINGS := 1
 
 include $(topsrcdir)/dom/dom-config.mk
 
-EXTRA_COMPONENTS = \
+DISABLED_EXTRA_COMPONENTS = \
   ActivityOptions.js \
   ActivityProxy.js \
   ActivityRequestHandler.js \
   ActivityWrapper.js \
   Activities.manifest \
   $(NULL)
 
 EXTRA_JS_MODULES =   \
--- a/dom/activities/src/moz.build
+++ b/dom/activities/src/moz.build
@@ -9,8 +9,15 @@ MODULE = 'dom'
 EXPORTS.mozilla.dom += [
     'Activity.h',
 ]
 
 CPP_SOURCES += [
     'Activity.cpp',
 ]
 
+EXTRA_COMPONENTS += [
+    'Activities.manifest',
+    'ActivityOptions.js',
+    'ActivityProxy.js',
+    'ActivityRequestHandler.js',
+    'ActivityWrapper.js',
+]
--- a/dom/alarm/Makefile.in
+++ b/dom/alarm/Makefile.in
@@ -11,17 +11,17 @@ include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME        = domalarm_s
 LIBXUL_LIBRARY      = 1
 FORCE_STATIC_LIB    = 1
 FAIL_ON_WARNINGS := 1
 
 include $(topsrcdir)/dom/dom-config.mk
 
-EXTRA_COMPONENTS =       \
+DISABLED_EXTRA_COMPONENTS =       \
   AlarmsManager.js       \
   AlarmsManager.manifest \
   $(NULL)
 
 EXTRA_JS_MODULES = \
   AlarmDB.jsm      \
   AlarmService.jsm \
   $(NULL)
--- a/dom/alarm/moz.build
+++ b/dom/alarm/moz.build
@@ -22,8 +22,12 @@ MODULE = 'dom'
 EXPORTS.mozilla.dom.alarm += [
     'AlarmHalService.h',
 ]
 
 CPP_SOURCES += [
     'AlarmHalService.cpp',
 ]
 
+EXTRA_COMPONENTS += [
+    'AlarmsManager.js',
+    'AlarmsManager.manifest',
+]
--- a/dom/apps/src/Makefile.in
+++ b/dom/apps/src/Makefile.in
@@ -4,17 +4,17 @@
 
 DEPTH     = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
-EXTRA_COMPONENTS = \
+DISABLED_EXTRA_COMPONENTS = \
   AppsService.js \
   AppsService.manifest \
   Webapps.manifest \
   $(NULL)
 
 EXTRA_PP_COMPONENTS = \
   Webapps.js \
   $(NULL)
--- a/dom/apps/src/moz.build
+++ b/dom/apps/src/moz.build
@@ -1,6 +1,11 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # 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/.
 
+EXTRA_COMPONENTS += [
+    'AppsService.js',
+    'AppsService.manifest',
+    'Webapps.manifest',
+]
--- a/dom/base/Makefile.in
+++ b/dom/base/Makefile.in
@@ -10,17 +10,17 @@ VPATH		= @srcdir@
 include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME	= jsdombase_s
 MSVC_ENABLE_PGO := 1
 LIBXUL_LIBRARY	= 1
 FORCE_STATIC_LIB = 1
 FAIL_ON_WARNINGS := 1
 
-EXTRA_COMPONENTS = \
+DISABLED_EXTRA_COMPONENTS = \
   SiteSpecificUserAgent.js \
   SiteSpecificUserAgent.manifest \
   ConsoleAPI.js \
   ConsoleAPI.manifest \
   $(NULL)
 
 EXTRA_JS_MODULES = ConsoleAPIStorage.jsm \
   $(NULL)
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -92,8 +92,14 @@ CPP_SOURCES += [
     'nsQueryContentEventResult.cpp',
     'nsScreen.cpp',
     'nsScriptNameSpaceManager.cpp',
     'nsStructuredCloneContainer.cpp',
     'nsWindowMemoryReporter.cpp',
     'nsWindowRoot.cpp',
 ]
 
+EXTRA_COMPONENTS += [
+    'ConsoleAPI.js',
+    'ConsoleAPI.manifest',
+    'SiteSpecificUserAgent.js',
+    'SiteSpecificUserAgent.manifest',
+]
--- a/dom/browser-element/BrowserElementParent.cpp
+++ b/dom/browser-element/BrowserElementParent.cpp
@@ -240,29 +240,29 @@ BrowserElementParent::OpenWindowInProces
   window.forget(aReturnWindow);
   return !!*aReturnWindow;
 }
 
 class DispatchAsyncScrollEventRunnable : public nsRunnable
 {
 public:
   DispatchAsyncScrollEventRunnable(TabParent* aTabParent,
-                                   const gfx::Rect& aContentRect,
-                                   const gfx::Size& aContentSize)
+                                   const CSSRect& aContentRect,
+                                   const CSSSize& aContentSize)
     : mTabParent(aTabParent)
     , mContentRect(aContentRect)
     , mContentSize(aContentSize)
   {}
 
   NS_IMETHOD Run();
 
 private:
   nsRefPtr<TabParent> mTabParent;
-  const gfx::Rect mContentRect;
-  const gfx::Size mContentSize;
+  const CSSRect mContentRect;
+  const CSSSize mContentSize;
 };
 
 NS_IMETHODIMP DispatchAsyncScrollEventRunnable::Run()
 {
   nsIDOMElement* element = mTabParent->GetOwnerElement();
   nsCOMPtr<Element> frameElement = do_QueryInterface(element);
   // Create the event's detail object.
   nsRefPtr<nsAsyncScrollEventDetail> detail =
@@ -272,18 +272,18 @@ NS_IMETHODIMP DispatchAsyncScrollEventRu
   DispatchCustomDOMEvent(frameElement,
                          NS_LITERAL_STRING("mozbrowserasyncscroll"),
                          detail);
   return NS_OK;
 }
 
 bool
 BrowserElementParent::DispatchAsyncScrollEvent(TabParent* aTabParent,
-                                               const gfx::Rect& aContentRect,
-                                               const gfx::Size& aContentSize)
+                                               const CSSRect& aContentRect,
+                                               const CSSSize& aContentSize)
 {
   nsRefPtr<DispatchAsyncScrollEventRunnable> runnable =
     new DispatchAsyncScrollEventRunnable(aTabParent, aContentRect,
                                          aContentSize);
   return NS_SUCCEEDED(NS_DispatchToMainThread(runnable));
 }
 
 } // namespace mozilla
--- a/dom/browser-element/BrowserElementParent.h
+++ b/dom/browser-element/BrowserElementParent.h
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_BrowserElementHelpers_h
 #define mozilla_BrowserElementHelpers_h
 
 #include "nsAString.h"
 #include "mozilla/gfx/Point.h"
 #include "mozilla/gfx/Rect.h"
+#include "Units.h"
 
 class nsIDOMWindow;
 class nsIURI;
 
 namespace mozilla {
 
 namespace dom {
 class TabParent;
@@ -101,15 +102,15 @@ public:
    * aContentRect.top + aContentRect.height may be larger than aContentSize.height.
    * This indicates that the content is over-scrolled, which occurs when the
    * page "rubber-bands" after being scrolled all the way to the bottom.
    * Similarly, aContentRect.left + aContentRect.width may be greater than
    * contentSize.width, and both left and top may be negative.
    */
   static bool
   DispatchAsyncScrollEvent(dom::TabParent* aTabParent,
-                           const gfx::Rect& aContentRect,
-                           const gfx::Size& aContentSize);
+                           const CSSRect& aContentRect,
+                           const CSSSize& aContentSize);
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/browser-element/Makefile.in
+++ b/dom/browser-element/Makefile.in
@@ -11,17 +11,17 @@ include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME     = dom_browserelement_s
 LIBXUL_LIBRARY   = 1
 FORCE_STATIC_LIB = 1
 FAIL_ON_WARNINGS := 1
 
 include $(topsrcdir)/dom/dom-config.mk
 
-EXTRA_COMPONENTS = \
+DISABLED_EXTRA_COMPONENTS = \
   BrowserElementParent.js \
   BrowserElementParent.manifest \
   $(NULL)
 
 EXTRA_JS_MODULES = \
   BrowserElementPromptService.jsm \
   BrowserElementParent.jsm \
   $(NULL)
--- a/dom/browser-element/moz.build
+++ b/dom/browser-element/moz.build
@@ -25,8 +25,12 @@ EXPORTS.mozilla += [
 ]
 
 CPP_SOURCES += [
     'BrowserElementParent.cpp',
     'nsAsyncScrollEventDetail.cpp',
     'nsOpenWindowEventDetail.cpp',
 ]
 
+EXTRA_COMPONENTS += [
+    'BrowserElementParent.js',
+    'BrowserElementParent.manifest',
+]
--- a/dom/contacts/Makefile.in
+++ b/dom/contacts/Makefile.in
@@ -6,17 +6,17 @@ DEPTH     = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 VPATH += $(srcdir)/fallback
 
-EXTRA_COMPONENTS =        \
+DISABLED_EXTRA_COMPONENTS =        \
   ContactManager.js       \
   ContactManager.manifest \
   $(NULL)
 
 EXTRA_JS_MODULES =   \
   ContactService.jsm \
   ContactDB.jsm      \
   $(NULL)
--- a/dom/contacts/moz.build
+++ b/dom/contacts/moz.build
@@ -1,7 +1,12 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # 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/.
 
 TEST_DIRS += ['tests']
+
+EXTRA_COMPONENTS += [
+    'ContactManager.js',
+    'ContactManager.manifest',
+]
--- a/dom/identity/Makefile.in
+++ b/dom/identity/Makefile.in
@@ -6,17 +6,17 @@ DEPTH            = @DEPTH@
 topsrcdir        = @top_srcdir@
 srcdir           = @srcdir@
 VPATH            = @srcdir@
 
 relativesrcdir   = @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
-EXTRA_COMPONENTS = \
+DISABLED_EXTRA_COMPONENTS = \
     nsDOMIdentity.js \
     nsIDService.js \
     Identity.manifest \
     $(NULL)
 
 EXTRA_PP_JS_MODULES = \
     DOMIdentity.jsm \
     $(NULL)
--- a/dom/identity/moz.build
+++ b/dom/identity/moz.build
@@ -1,7 +1,13 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # 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/.
 
 TEST_DIRS += ['tests']
+
+EXTRA_COMPONENTS += [
+    'Identity.manifest',
+    'nsDOMIdentity.js',
+    'nsIDService.js',
+]
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -46,16 +46,17 @@ using mozilla::widget::WheelEvent;
 using nsQueryContentEvent;
 using nsRect;
 using nsSelectionEvent;
 using nsTextEvent;
 using nsTouchEvent;
 using RemoteDOMEvent;
 using mozilla::dom::ScreenOrientation;
 using mozilla::layers::TextureFactoryIdentifier;
+using mozilla::CSSIntPoint;
 namespace mozilla {
 namespace dom {
 
 rpc protocol PBrowser
 {
     manager PContent;
 
     manages PContentDialog;
@@ -302,31 +303,31 @@ child:
 
     UpdateFrame(FrameMetrics frame) compress;
 
     /**
      * Requests handling of a double tap. |point| is in CSS pixels, relative to
      * the scroll offset. This message is expected to round-trip back to
      * ZoomToRect() with a rect indicating where we should zoom to.
      */
-    HandleDoubleTap(nsIntPoint point);
+    HandleDoubleTap(CSSIntPoint point);
 
     /**
      * Requests handling of a single tap. |point| is in CSS pixels, relative to
      * the scroll offset. This message is expected to send a "mousedown" and
      * "mouseup" series of events at this point.
      */
-    HandleSingleTap(nsIntPoint point);
+    HandleSingleTap(CSSIntPoint point);
 
     /**
      * Requests handling of a long tap. |point| is in CSS pixels, relative to
      * the scroll offset. This message is expected to send a "contextmenu"
      * events at this point.
      */
-    HandleLongTap(nsIntPoint point);
+    HandleLongTap(CSSIntPoint point);
 
     /**
      * Sending an activate message moves focus to the child.
      */
     Activate();
 
     Deactivate();
 
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -93,17 +93,17 @@ using namespace mozilla::ipc;
 using namespace mozilla::layers;
 using namespace mozilla::layout;
 using namespace mozilla::docshell;
 using namespace mozilla::dom::indexedDB;
 using namespace mozilla::widget;
 
 NS_IMPL_ISUPPORTS1(ContentListener, nsIDOMEventListener)
 
-static const nsIntSize kDefaultViewportSize(980, 480);
+static const CSSSize kDefaultViewportSize(980, 480);
 
 static const char CANCEL_DEFAULT_PAN_ZOOM[] = "cancel-default-pan-zoom";
 static const char BROWSER_ZOOM_TO_RECT[] = "browser-zoom-to-rect";
 static const char BEFORE_FIRST_PAINT[] = "before-first-paint";
 static const char DETECT_SCROLLABLE_SUBFRAME[] = "detect-scrollable-subframe";
 
 NS_IMETHODIMP
 ContentListener::HandleEvent(nsIDOMEvent* aEvent)
@@ -336,25 +336,23 @@ TabChild::Observe(nsISupports *aSubject,
       if (SameCOMIdentity(subject, doc)) {
         nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
 
         mContentDocumentIsDisplayed = true;
 
         // Reset CSS viewport and zoom to default on new page, then
         // calculate them properly using the actual metadata from the
         // page.
-        SetCSSViewport(kDefaultViewportSize.width, kDefaultViewportSize.height);
+        SetCSSViewport(kDefaultViewportSize);
 
         // Calculate a really simple resolution that we probably won't
         // be keeping, as well as putting the scroll offset back to
         // the top-left of the page.
         mLastMetrics.mZoom = gfxSize(1.0, 1.0);
-        mLastMetrics.mViewport =
-            gfx::Rect(0, 0,
-                      kDefaultViewportSize.width, kDefaultViewportSize.height);
+        mLastMetrics.mViewport = CSSRect(CSSPoint(), kDefaultViewportSize);
         // I don't know what units mInnerSize is in, hence FromUnknownRect
         mLastMetrics.mCompositionBounds = LayerIntRect::FromUnknownRect(
           gfx::IntRect(0, 0, mInnerSize.width, mInnerSize.height));
         mLastMetrics.mResolution =
           AsyncPanZoomController::CalculateResolution(mLastMetrics);
         mLastMetrics.mScrollOffset = CSSPoint(0, 0);
         utils->SetResolution(mLastMetrics.mResolution.width,
                              mLastMetrics.mResolution.height);
@@ -466,23 +464,23 @@ TabChild::OnSecurityChange(nsIWebProgres
                            nsIRequest* aRequest,
                            uint32_t aState)
 {
   NS_NOTREACHED("not implemented in TabChild");
   return NS_OK;
 }
 
 void
-TabChild::SetCSSViewport(float aWidth, float aHeight)
+TabChild::SetCSSViewport(const CSSSize& aSize)
 {
-  mOldViewportWidth = aWidth;
+  mOldViewportWidth = aSize.width;
 
   if (mContentDocumentIsDisplayed) {
     nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
-    utils->SetCSSViewport(aWidth, aHeight);
+    utils->SetCSSViewport(aSize.width, aSize.height);
   }
 }
 
 void
 TabChild::HandlePossibleViewportChange()
 {
   if (!IsAsyncPanZoomEnabled()) {
     return;
@@ -497,37 +495,35 @@ TabChild::HandlePossibleViewportChange()
   nsViewportInfo viewportInfo =
     nsContentUtils::GetViewportInfo(document, mInnerSize.width, mInnerSize.height);
   SendUpdateZoomConstraints(viewportInfo.IsZoomAllowed(),
                             viewportInfo.GetMinZoom(),
                             viewportInfo.GetMaxZoom());
 
   float screenW = mInnerSize.width;
   float screenH = mInnerSize.height;
-  float viewportW = viewportInfo.GetWidth();
-  float viewportH = viewportInfo.GetHeight();
+  CSSSize viewport(viewportInfo.GetWidth(), viewportInfo.GetHeight());
 
   // We're not being displayed in any way; don't bother doing anything because
   // that will just confuse future adjustments.
   if (!screenW || !screenH) {
     return;
   }
 
   // Make sure the viewport height is not shorter than the window when the page
   // is zoomed out to show its full width. Note that before we set the viewport
   // width, the "full width" of the page isn't properly defined, so that's why
   // we have to call SetCSSViewport twice - once to set the width, and the
   // second time to figure out the height based on the layout at that width.
   float oldBrowserWidth = mOldViewportWidth;
-  mLastMetrics.mViewport.width = viewportW;
-  mLastMetrics.mViewport.height = viewportH;
+  mLastMetrics.mViewport.SizeTo(viewport);
   if (!oldBrowserWidth) {
     oldBrowserWidth = kDefaultViewportSize.width;
   }
-  SetCSSViewport(viewportW, viewportH);
+  SetCSSViewport(viewport);
 
   // If this page has not been painted yet, then this must be getting run
   // because a meta-viewport element was added (via the DOMMetaAdded handler).
   // in this case, we should not do anything that forces a reflow (see bug
   // 759678) such as requesting the page size or sending a viewport update. this
   // code will get run again in the before-first-paint handler and that point we
   // will run though all of it. the reason we even bother executing up to this
   // point on the DOMMetaAdded handler is so that scripts that use
@@ -548,34 +544,36 @@ TabChild::HandlePossibleViewportChange()
     htmlDOMElement->GetScrollHeight(&htmlHeight);
   }
   int32_t bodyWidth = 0, bodyHeight = 0;
   if (bodyDOMElement) {
     bodyWidth = bodyDOMElement->ScrollWidth();
     bodyHeight = bodyDOMElement->ScrollHeight();
   }
 
-  float pageWidth, pageHeight;
+  CSSSize pageSize;
   if (htmlDOMElement || bodyDOMElement) {
-    pageWidth = std::max(htmlWidth, bodyWidth);
-    pageHeight = std::max(htmlHeight, bodyHeight);
+    pageSize = CSSSize(std::max(htmlWidth, bodyWidth),
+                       std::max(htmlHeight, bodyHeight));
   } else {
     // For non-HTML content (e.g. SVG), just assume page size == viewport size.
-    pageWidth = viewportW;
-    pageHeight = viewportH;
+    pageSize = viewport;
   }
-  NS_ENSURE_TRUE_VOID(pageWidth); // (return early rather than divide by 0)
+  if (!pageSize.width) {
+    // Return early rather than divide by 0.
+    return;
+  }
 
-  minScale = mInnerSize.width / pageWidth;
+  minScale = mInnerSize.width / pageSize.width;
   minScale = clamped((double)minScale, viewportInfo.GetMinZoom(),
                      viewportInfo.GetMaxZoom());
   NS_ENSURE_TRUE_VOID(minScale); // (return early rather than divide by 0)
 
-  viewportH = std::max(viewportH, screenH / minScale);
-  SetCSSViewport(viewportW, viewportH);
+  viewport.height = std::max(viewport.height, screenH / minScale);
+  SetCSSViewport(viewport);
 
   // This change to the zoom accounts for all types of changes I can conceive:
   // 1. screen size changes, CSS viewport does not (pages with no meta viewport
   //    or a fixed size viewport)
   // 2. screen size changes, CSS viewport also does (pages with a device-width
   //    viewport)
   // 3. screen size remains constant, but CSS viewport changes (meta viewport
   //    tag is added or removed)
@@ -585,18 +583,18 @@ TabChild::HandlePossibleViewportChange()
   // within the screen width. Note that "actual content" may be different with
   // respect to CSS pixels because of the CSS viewport size changing.
   int32_t oldScreenWidth = mLastMetrics.mCompositionBounds.width;
   if (!oldScreenWidth) {
     oldScreenWidth = mInnerSize.width;
   }
 
   FrameMetrics metrics(mLastMetrics);
-  metrics.mViewport = gfx::Rect(0.0f, 0.0f, viewportW, viewportH);
-  metrics.mScrollableRect = CSSRect(0.0f, 0.0f, pageWidth, pageHeight);
+  metrics.mViewport = CSSRect(CSSPoint(), viewport);
+  metrics.mScrollableRect = CSSRect(CSSPoint(), pageSize);
   // I don't know what units mInnerSize is in, hence FromUnknownRect
   metrics.mCompositionBounds = LayerIntRect::FromUnknownRect(
     gfx::IntRect(0, 0, mInnerSize.width, mInnerSize.height));
 
   // Changing the zoom when we're not doing a first paint will get ignored
   // by AsyncPanZoomController and causes a blurry flash.
   bool isFirstPaint;
   nsresult rv = utils->GetIsFirstPaint(&isFirstPaint);
@@ -1547,48 +1545,48 @@ TabChild::ProcessUpdateFrame(const Frame
     }
 
     mLastMetrics = aFrameMetrics;
 
     return true;
 }
 
 bool
-TabChild::RecvHandleDoubleTap(const nsIntPoint& aPoint)
+TabChild::RecvHandleDoubleTap(const CSSIntPoint& aPoint)
 {
     if (!mCx || !mTabChildGlobal) {
         return true;
     }
 
     nsCString data;
     data += nsPrintfCString("{ \"x\" : %d", aPoint.x);
     data += nsPrintfCString(", \"y\" : %d", aPoint.y);
     data += nsPrintfCString(" }");
 
     DispatchMessageManagerMessage(NS_LITERAL_STRING("Gesture:DoubleTap"), data);
 
     return true;
 }
 
 bool
-TabChild::RecvHandleSingleTap(const nsIntPoint& aPoint)
+TabChild::RecvHandleSingleTap(const CSSIntPoint& aPoint)
 {
   if (!mCx || !mTabChildGlobal) {
     return true;
   }
 
   RecvMouseEvent(NS_LITERAL_STRING("mousemove"), aPoint.x, aPoint.y, 0, 1, 0, false);
   RecvMouseEvent(NS_LITERAL_STRING("mousedown"), aPoint.x, aPoint.y, 0, 1, 0, false);
   RecvMouseEvent(NS_LITERAL_STRING("mouseup"), aPoint.x, aPoint.y, 0, 1, 0, false);
 
   return true;
 }
 
 bool
-TabChild::RecvHandleLongTap(const nsIntPoint& aPoint)
+TabChild::RecvHandleLongTap(const CSSIntPoint& aPoint)
 {
   if (!mCx || !mTabChildGlobal) {
     return true;
   }
 
   RecvMouseEvent(NS_LITERAL_STRING("contextmenu"), aPoint.x, aPoint.y,
                  2 /* Right button */,
                  1 /* Click count */,
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -200,19 +200,19 @@ public:
 
     virtual bool RecvLoadURL(const nsCString& uri);
     virtual bool RecvCacheFileDescriptor(const nsString& aPath,
                                          const FileDescriptor& aFileDescriptor)
                                          MOZ_OVERRIDE;
     virtual bool RecvShow(const nsIntSize& size);
     virtual bool RecvUpdateDimensions(const nsRect& rect, const nsIntSize& size, const ScreenOrientation& orientation);
     virtual bool RecvUpdateFrame(const mozilla::layers::FrameMetrics& aFrameMetrics);
-    virtual bool RecvHandleDoubleTap(const nsIntPoint& aPoint);
-    virtual bool RecvHandleSingleTap(const nsIntPoint& aPoint);
-    virtual bool RecvHandleLongTap(const nsIntPoint& aPoint);
+    virtual bool RecvHandleDoubleTap(const CSSIntPoint& aPoint);
+    virtual bool RecvHandleSingleTap(const CSSIntPoint& aPoint);
+    virtual bool RecvHandleLongTap(const CSSIntPoint& aPoint);
     virtual bool RecvActivate();
     virtual bool RecvDeactivate();
     virtual bool RecvMouseEvent(const nsString& aType,
                                 const float&    aX,
                                 const float&    aY,
                                 const int32_t&  aButton,
                                 const int32_t&  aClickCount,
                                 const int32_t&  aModifiers,
@@ -379,17 +379,17 @@ private:
     void SetProcessNameToAppName();
     bool ProcessUpdateFrame(const mozilla::layers::FrameMetrics& aFrameMetrics);
 
     // Call RecvShow(nsIntSize(0, 0)) and block future calls to RecvShow().
     void DoFakeShow();
 
     // Wrapper for nsIDOMWindowUtils.setCSSViewport(). This updates some state
     // variables local to this class before setting it.
-    void SetCSSViewport(float aX, float aY);
+    void SetCSSViewport(const CSSSize& aSize);
 
     // Recalculates the display state, including the CSS
     // viewport. This should be called whenever we believe the
     // viewport data on a document may have changed. If it didn't
     // change, this function doesn't do anything.  However, it should
     // not be called all the time as it is fairly expensive.
     void HandlePossibleViewportChange();
 
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -472,31 +472,31 @@ TabParent::UpdateDimensions(const nsRect
 void
 TabParent::UpdateFrame(const FrameMetrics& aFrameMetrics)
 {
   if (!mIsDestroyed) {
     unused << SendUpdateFrame(aFrameMetrics);
   }
 }
 
-void TabParent::HandleDoubleTap(const nsIntPoint& aPoint)
+void TabParent::HandleDoubleTap(const CSSIntPoint& aPoint)
 {
   if (!mIsDestroyed) {
     unused << SendHandleDoubleTap(aPoint);
   }
 }
 
-void TabParent::HandleSingleTap(const nsIntPoint& aPoint)
+void TabParent::HandleSingleTap(const CSSIntPoint& aPoint)
 {
   if (!mIsDestroyed) {
     unused << SendHandleSingleTap(aPoint);
   }
 }
 
-void TabParent::HandleLongTap(const nsIntPoint& aPoint)
+void TabParent::HandleLongTap(const CSSIntPoint& aPoint)
 {
   if (!mIsDestroyed) {
     unused << SendHandleLongTap(aPoint);
   }
 }
 
 void
 TabParent::Activate()
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -170,19 +170,19 @@ public:
 
     void LoadURL(nsIURI* aURI);
     // XXX/cjones: it's not clear what we gain by hiding these
     // message-sending functions under a layer of indirection and
     // eating the return values
     void Show(const nsIntSize& size);
     void UpdateDimensions(const nsRect& rect, const nsIntSize& size);
     void UpdateFrame(const layers::FrameMetrics& aFrameMetrics);
-    void HandleDoubleTap(const nsIntPoint& aPoint);
-    void HandleSingleTap(const nsIntPoint& aPoint);
-    void HandleLongTap(const nsIntPoint& aPoint);
+    void HandleDoubleTap(const CSSIntPoint& aPoint);
+    void HandleSingleTap(const CSSIntPoint& aPoint);
+    void HandleLongTap(const CSSIntPoint& aPoint);
     void Activate();
     void Deactivate();
 
     void SendMouseEvent(const nsAString& aType, float aX, float aY,
                         int32_t aButton, int32_t aClickCount,
                         int32_t aModifiers, bool aIgnoreRootScrollFrame);
     void SendKeyEvent(const nsAString& aType, int32_t aKeyCode,
                       int32_t aCharCode, int32_t aModifiers,
--- a/dom/media/Makefile.in
+++ b/dom/media/Makefile.in
@@ -12,17 +12,17 @@ include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME     = dom_media_s
 LIBXUL_LIBRARY   = 1
 FORCE_STATIC_LIB = 1
 FAIL_ON_WARNINGS := 1
 
 include $(topsrcdir)/dom/dom-config.mk
 
-EXTRA_COMPONENTS = \
+DISABLED_EXTRA_COMPONENTS = \
   PeerConnection.js \
   PeerConnection.manifest \
   $(NULL)
 
 ifdef MOZ_WEBRTC
 LOCAL_INCLUDES += \
   -I$(topsrcdir)/media/webrtc/trunk/webrtc \
   -I$(topsrcdir)/media/webrtc/signaling/src/common \
--- a/dom/media/moz.build
+++ b/dom/media/moz.build
@@ -22,8 +22,12 @@ MODULE = 'dom'
 EXPORTS.mozilla += [
     'MediaManager.h',
 ]
 
 CPP_SOURCES += [
     'MediaManager.cpp',
 ]
 
+EXTRA_COMPONENTS += [
+    'PeerConnection.js',
+    'PeerConnection.manifest',
+]
--- a/dom/messages/Makefile.in
+++ b/dom/messages/Makefile.in
@@ -6,17 +6,17 @@ DEPTH            = @DEPTH@
 topsrcdir        = @top_srcdir@
 srcdir           = @srcdir@
 VPATH            = @srcdir@
 
 relativesrcdir   = @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
-EXTRA_COMPONENTS = \
+DISABLED_EXTRA_COMPONENTS = \
   SystemMessageManager.js \
   SystemMessageInternal.js \
   SystemMessageManager.manifest \
   $(NULL)
 
 EXTRA_JS_MODULES += \
   SystemMessagePermissionsChecker.jsm \
   $(NULL)
--- a/dom/messages/moz.build
+++ b/dom/messages/moz.build
@@ -1,7 +1,13 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # 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/.
 
 PARALLEL_DIRS += ['interfaces']
+
+EXTRA_COMPONENTS += [
+    'SystemMessageInternal.js',
+    'SystemMessageManager.js',
+    'SystemMessageManager.manifest',
+]
--- a/dom/network/src/Makefile.in
+++ b/dom/network/src/Makefile.in
@@ -9,24 +9,24 @@ VPATH            = $(srcdir)
 
 include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME     = dom_network_s
 LIBXUL_LIBRARY   = 1
 FORCE_STATIC_LIB = 1
 FAIL_ON_WARNINGS := 1
 
-EXTRA_COMPONENTS = \
+DISABLED_EXTRA_COMPONENTS = \
 	TCPSocket.js \
 	TCPSocketParentIntermediary.js \
 	TCPSocket.manifest \
 	$(NULL)
 
 ifdef MOZ_B2G_RIL
-EXTRA_COMPONENTS += \
+DISABLED_EXTRA_COMPONENTS += \
   NetworkStatsManager.manifest \
   NetworkStatsManager.js \
   $(NULL)
 
 EXTRA_JS_MODULES =   \
   NetworkStatsService.jsm \
   NetworkStatsDB.jsm \
   $(NULL)
--- a/dom/network/src/moz.build
+++ b/dom/network/src/moz.build
@@ -18,8 +18,20 @@ CPP_SOURCES += [
     'TCPSocketParent.cpp',
     'Utils.cpp',
 ]
 
 if CONFIG['MOZ_B2G_RIL']:
     CPP_SOURCES += [
         'MobileConnection.cpp',
     ]
+
+EXTRA_COMPONENTS += [
+    'TCPSocket.js',
+    'TCPSocket.manifest',
+    'TCPSocketParentIntermediary.js',
+]
+
+if CONFIG['MOZ_B2G_RIL']:
+    EXTRA_COMPONENTS += [
+        'NetworkStatsManager.js',
+        'NetworkStatsManager.manifest',
+    ]
--- a/dom/permission/Makefile.in
+++ b/dom/permission/Makefile.in
@@ -4,17 +4,17 @@
 
 DEPTH = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
-EXTRA_COMPONENTS =        \
+DISABLED_EXTRA_COMPONENTS =        \
   PermissionSettings.js       \
   PermissionSettings.manifest \
   PermissionPromptService.js \
   PermissionPromptService.manifest \
   $(NULL)
 
 EXTRA_JS_MODULES =   \
   PermissionPromptHelper.jsm \
--- a/dom/permission/moz.build
+++ b/dom/permission/moz.build
@@ -1,7 +1,14 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # 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/.
 
 TEST_DIRS += ['tests']
+
+EXTRA_COMPONENTS += [
+    'PermissionPromptService.js',
+    'PermissionPromptService.manifest',
+    'PermissionSettings.js',
+    'PermissionSettings.manifest',
+]
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -49,17 +49,19 @@ using namespace std;
 #ifdef MOZ_WIDGET_GTK
 
 #include <gtk/gtk.h>
 #if (MOZ_WIDGET_GTK == 3)
 #include <gtk/gtkx.h>
 #endif
 #include <gdk/gdkx.h>
 #include <gdk/gdk.h>
+#if (MOZ_WIDGET_GTK == 2)
 #include "gtk2xtbin.h"
+#endif
 
 #elif defined(MOZ_WIDGET_QT)
 #undef KeyPress
 #undef KeyRelease
 #elif defined(OS_WIN)
 #ifndef WM_MOUSEHWHEEL
 #define WM_MOUSEHWHEEL     0x020E
 #endif
@@ -108,17 +110,17 @@ PluginInstanceChild::PluginInstanceChild
     , mContentsScaleFactor(1.0)
 #endif
     , mDrawingModel(kDefaultDrawingModel)
     , mCurrentAsyncSurface(0)
     , mAsyncInvalidateMutex("PluginInstanceChild::mAsyncInvalidateMutex")
     , mAsyncInvalidateTask(0)
     , mCachedWindowActor(nullptr)
     , mCachedElementActor(nullptr)
-#if defined(MOZ_WIDGET_GTK)
+#if (MOZ_WIDGET_GTK == 2)
     , mXEmbed(false)
 #endif // MOZ_WIDGET_GTK
 #if defined(OS_WIN)
     , mPluginWindowHWND(0)
     , mPluginWndProc(0)
     , mPluginParentHWND(0)
     , mCachedWinlessPluginHWND(0)
     , mWinlessPopupSurrogateHWND(0)
@@ -156,17 +158,17 @@ PluginInstanceChild::PluginInstanceChild
     memset(&mWindow, 0, sizeof(mWindow));
     mWindow.type = NPWindowTypeWindow;
     mData.ndata = (void*) this;
     mData.pdata = nullptr;
     mAsyncBitmaps.Init();
 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
     mWindow.ws_info = &mWsInfo;
     memset(&mWsInfo, 0, sizeof(mWsInfo));
-#if defined(MOZ_WIDGET_GTK)
+#if (MOZ_WIDGET_GTK == 2)
     mWsInfo.display = NULL;
     mXtClient.top_widget = NULL;
 #else
     mWsInfo.display = DefaultXDisplay();
 #endif
 #endif // MOZ_X11 && XP_UNIX && !XP_MACOSX
 #if defined(OS_WIN)
     memset(&mAlphaExtract, 0, sizeof(mAlphaExtract));
@@ -498,17 +500,17 @@ PluginInstanceChild::NPN_SetValue(NPPVar
     case NPPVpluginWindowBool: {
         NPError rv;
         bool windowed = (NPBool) (intptr_t) aValue;
 
         if (!CallNPN_SetValue_NPPVpluginWindow(windowed, &rv))
             return NPERR_GENERIC_ERROR;
 
         NPWindowType newWindowType = windowed ? NPWindowTypeWindow : NPWindowTypeDrawable;
-#if defined(MOZ_WIDGET_GTK)
+#if (MOZ_WIDGET_GTK == 2)
         if (mWindow.type != newWindowType && mWsInfo.display) {
            // plugin type has been changed but we already have a valid display
            // so update it for the recent plugin mode
            if (mXEmbed || !windowed) {
                // Use default GTK display for XEmbed and windowless plugins
                mWsInfo.display = DefaultXDisplay();
            }
            else {
@@ -1042,17 +1044,17 @@ PluginInstanceChild::RecvContentsScaleFa
 bool PluginInstanceChild::CreateWindow(const NPRemoteWindow& aWindow)
 { 
     PLUGIN_LOG_DEBUG(("%s (aWindow=<window: 0x%lx, x: %d, y: %d, width: %d, height: %d>)",
                       FULLFUNCTION,
                       aWindow.window,
                       aWindow.x, aWindow.y,
                       aWindow.width, aWindow.height));
 
-#if defined(MOZ_WIDGET_GTK)
+#if (MOZ_WIDGET_GTK == 2)
     if (mXEmbed) {
         mWindow.window = reinterpret_cast<void*>(aWindow.window);
     }
     else {
         Window browserSocket = (Window)(aWindow.window);
         xt_client_init(&mXtClient, mWsInfo.visual, mWsInfo.colormap, mWsInfo.depth);
         xt_client_create(&mXtClient, browserSocket, mWindow.width, mWindow.height); 
         mWindow.window = (void *)XtWindow(mXtClient.child_widget);
@@ -1071,17 +1073,17 @@ void PluginInstanceChild::DeleteWindow()
                     FULLFUNCTION,
                     mWindow.window,
                     mWindow.x, mWindow.y,
                     mWindow.width, mWindow.height));
 
   if (!mWindow.window)
       return;
 
-#if defined(MOZ_WIDGET_GTK)
+#if (MOZ_WIDGET_GTK == 2)
   if (mXtClient.top_widget) {     
       xt_client_unrealize(&mXtClient);
       xt_client_destroy(&mXtClient); 
       mXtClient.top_widget = NULL;
   }
 #endif
 
   // We don't have to keep the plug-in window ID any longer.
@@ -1252,17 +1254,17 @@ PluginInstanceChild::AnswerNPP_SetWindow
 #endif
 
     return true;
 }
 
 bool
 PluginInstanceChild::Initialize()
 {
-#if defined(MOZ_WIDGET_GTK)
+#if (MOZ_WIDGET_GTK == 2)
     NPError rv;
 
     if (mWsInfo.display) {
         // Already initialized
         return false;
     }
 
     // Request for windowless plugins is set in newp(), before this call.
@@ -4142,17 +4144,17 @@ PluginInstanceChild::AnswerNPP_Destroy(N
 
     mPendingAsyncCalls.Clear();
     
     if (mAsyncBitmaps.Count()) {
         NS_ERROR("Not all AsyncBitmaps were finalized by a plugin!");
         mAsyncBitmaps.Enumerate(DeleteSurface, this);
     }
 
-#if defined(MOZ_WIDGET_GTK)
+#if (MOZ_WIDGET_GTK == 2)
     if (mWindow.type == NPWindowTypeWindow && !mXEmbed) {
       xt_client_xloop_destroy();
     }
 #endif
 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
     DeleteWindow();
 #endif
 
--- a/dom/plugins/ipc/PluginInstanceChild.h
+++ b/dom/plugins/ipc/PluginInstanceChild.h
@@ -29,17 +29,17 @@
 #include "ChildTimer.h"
 #include "nsRect.h"
 #include "nsTHashtable.h"
 #include "mozilla/PaintTracker.h"
 #include "gfxASurface.h"
 
 #include <map>
 
-#if defined(MOZ_WIDGET_GTK)
+#if (MOZ_WIDGET_GTK == 2)
 #include "gtk2xtbin.h"
 #endif
 
 namespace mozilla {
 
 namespace layers {
 struct RemoteImageData;
 }
@@ -378,17 +378,17 @@ private:
     CancelableTask *mAsyncInvalidateTask;
 
     // Cached scriptable actors to avoid IPC churn
     PluginScriptableObjectChild* mCachedWindowActor;
     PluginScriptableObjectChild* mCachedElementActor;
 
 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
     NPSetWindowCallbackStruct mWsInfo;
-#if defined(MOZ_WIDGET_GTK)
+#if (MOZ_WIDGET_GTK == 2)
     bool mXEmbed;
     XtClient mXtClient;
 #endif
 #elif defined(OS_WIN)
     HWND mPluginWindowHWND;
     WNDPROC mPluginWndProc;
     HWND mPluginParentHWND;
     int mNestedEventLevelDepth;
--- a/dom/plugins/ipc/PluginModuleChild.cpp
+++ b/dom/plugins/ipc/PluginModuleChild.cpp
@@ -1093,17 +1093,17 @@ NPError NP_CALLBACK
         case NPNVSupportsWindowless: { // Intentional fall-through
             NPError result;
             bool value;
             PluginModuleChild::current()->
                 CallNPN_GetValue_WithBoolReturn(aVariable, &result, &value);
             *(NPBool*)aValue = value ? true : false;
             return result;
         }
-#if defined(MOZ_WIDGET_GTK)
+#if (MOZ_WIDGET_GTK == 2)
         case NPNVxDisplay: {
             if (aNPP) {
                 return InstCast(aNPP)->NPN_GetValue(aVariable, aValue);
             } 
             else {
                 *(void **)aValue = xt_client_get_display();
             }          
             return NPERR_NO_ERROR;
--- a/dom/plugins/test/mochitest/Makefile.in
+++ b/dom/plugins/test/mochitest/Makefile.in
@@ -158,16 +158,16 @@ MOCHITEST_FILES += \
   test_cocoa_window_focus.html \
   cocoa_window_focus.html \
   test_cocoa_focus.html \
   cocoa_focus.html \
   test_queryContentsScaleFactor.html \
   $(NULL)
 endif
 
-ifeq (gtk2,$(MOZ_WIDGET_TOOLKIT))
+ifeq (,$(filter-out gtk2 gtk3,$(MOZ_WIDGET_TOOLKIT)))
 MOCHITEST_FILES += \
 		test_copyText.html \
 		test_crash_nested_loop.html \
 		$(NULL)
 endif
 
 include $(topsrcdir)/config/rules.mk
--- a/dom/plugins/test/moz.build
+++ b/dom/plugins/test/moz.build
@@ -1,14 +1,14 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # 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 += ['testplugin']
 
-if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'cocoa', 'windows'):
+if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3', 'cocoa', 'windows'):
     TEST_DIRS += ['mochitest']
 
 MODULE = 'test_plugin'
 
 XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
--- a/dom/push/src/Makefile.in
+++ b/dom/push/src/Makefile.in
@@ -4,17 +4,17 @@
 
 DEPTH     = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
-EXTRA_COMPONENTS = \
+DISABLED_EXTRA_COMPONENTS = \
   Push.js \
   Push.manifest \
   $(NULL)
 
 EXTRA_JS_MODULES = \
   PushService.jsm \
   $(NULL)
 
--- a/dom/push/src/moz.build
+++ b/dom/push/src/moz.build
@@ -1,5 +1,10 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # 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/.
 
+EXTRA_COMPONENTS += [
+    'Push.js',
+    'Push.manifest',
+]
--- a/dom/settings/Makefile.in
+++ b/dom/settings/Makefile.in
@@ -4,17 +4,17 @@
 
 DEPTH     = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
-EXTRA_COMPONENTS =         \
+DISABLED_EXTRA_COMPONENTS =         \
   SettingsManager.js       \
   SettingsManager.manifest \
   SettingsService.js \
   SettingsService.manifest \
   $(NULL)
 
 EXTRA_JS_MODULES =   \
   SettingsQueue.jsm  \
--- a/dom/settings/moz.build
+++ b/dom/settings/moz.build
@@ -1,7 +1,14 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # 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/.
 
 TEST_DIRS += ['tests']
+
+EXTRA_COMPONENTS += [
+    'SettingsManager.js',
+    'SettingsManager.manifest',
+    'SettingsService.js',
+    'SettingsService.manifest',
+]
--- a/dom/system/moz.build
+++ b/dom/system/moz.build
@@ -1,17 +1,17 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # 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/.
 
 toolkit = CONFIG['MOZ_WIDGET_TOOLKIT']
 
-if toolkit in ('qt', 'gtk2'):
+if toolkit in ('qt', 'gtk2', 'gtk3'):
     DIRS += ['unix']
 elif toolkit == 'windows':
     DIRS += ['windows']
 elif toolkit == 'android':
     DIRS += ['android']
 
 if CONFIG['MOZ_B2G_RIL']:
     DIRS += ['gonk']
--- a/gfx/2d/BaseRect.h
+++ b/gfx/2d/BaseRect.h
@@ -338,16 +338,28 @@ struct BaseRect {
 
     x = x0;
     y = y0;
 
     width = x1 - x0;
     height = y1 - y0;
   }
 
+  // Scale 'this' by aScale without doing any rounding.
+  void Scale(T aScale) { Scale(aScale, aScale); }
+  // Scale 'this' by aXScale and aYScale, without doing any rounding.
+  void Scale(T aXScale, T aYScale)
+  {
+    T right = XMost() * aXScale;
+    T bottom = YMost() * aYScale;
+    x = x * aXScale;
+    y = y * aYScale;
+    width = right - x;
+    height = bottom - y;
+  }
   // Scale 'this' by aScale, converting coordinates to integers so that the result is
   // the smallest integer-coordinate rectangle containing the unrounded result.
   // Note: this can turn an empty rectangle into a non-empty rectangle
   void ScaleRoundOut(double aScale) { ScaleRoundOut(aScale, aScale); }
   // Scale 'this' by aXScale and aYScale, converting coordinates to integers so
   // that the result is the smallest integer-coordinate rectangle containing the
   // unrounded result.
   // Note: this can turn an empty rectangle into a non-empty rectangle
--- a/gfx/layers/FrameMetrics.h
+++ b/gfx/layers/FrameMetrics.h
@@ -150,70 +150,70 @@ public:
   // May be larger or smaller than |mScrollableRect|.
   //
   // To pre-render a margin of 100 CSS pixels around the window,
   // { x = -100, y = - 100,
   //   width = window.innerWidth + 100, height = window.innerHeight + 100 }
   //
   // This is only valid on the root layer. Nested iframes do not have a
   // displayport set on them. See bug 775452.
-  gfx::Rect mDisplayPort;
+  CSSRect mDisplayPort;
 
   // If non-empty, the area of a frame's contents that is considered critical
   // to paint. Area outside of this area (i.e. area inside mDisplayPort, but
   // outside of mCriticalDisplayPort) is considered low-priority, and may be
   // painted with lower precision, or not painted at all.
   //
   // The same restrictions for mDisplayPort apply here.
-  gfx::Rect mCriticalDisplayPort;
+  CSSRect mCriticalDisplayPort;
 
   // The CSS viewport, which is the dimensions we're using to constrain the
   // <html> element of this frame, relative to the top-left of the layer. Note
   // that its offset is structured in such a way that it doesn't depend on the
   // method layout uses to scroll content.
   //
   // This is mainly useful on the root layer, however nested iframes can have
   // their own viewport, which will just be the size of the window of the
   // iframe. For layers that don't correspond to a document, this metric is
   // meaningless and invalid.
-  gfx::Rect mViewport;
+  CSSRect mViewport;
 
   // The position of the top-left of the CSS viewport, relative to the document
   // (or the document relative to the viewport, if that helps understand it).
   //
   // Thus it is relative to the document. It is in the same coordinate space as
   // |mScrollableRect|, but a different coordinate space than |mViewport| and
   // |mDisplayPort|.
   //
   // It is required that the rect:
   // { x = mScrollOffset.x, y = mScrollOffset.y,
   //   width = mCompositionBounds.x / mResolution.width,
   //   height = mCompositionBounds.y / mResolution.height }
   // Be within |mScrollableRect|.
   //
   // This is valid for any layer, but is always relative to this frame and
   // not any parents, regardless of parent transforms.
-  mozilla::CSSPoint mScrollOffset;
+  CSSPoint mScrollOffset;
 
   // A unique ID assigned to each scrollable frame (unless this is
   // ROOT_SCROLL_ID, in which case it is not unique).
   ViewID mScrollId;
 
   // The scrollable bounds of a frame. This is determined by reflow.
   // For the top-level |window|,
   // { x = window.scrollX, y = window.scrollY, // could be 0, 0
   //   width = window.innerWidth, height = window.innerHeight }
   //
   // This is relative to the document. It is in the same coordinate space as
   // |mScrollOffset|, but a different coordinate space than |mViewport| and
   // |mDisplayPort|. Note also that this coordinate system is understood by
   // window.scrollTo().
   //
   // This is valid on any layer unless it has no content.
-  mozilla::CSSRect mScrollableRect;
+  CSSRect mScrollableRect;
 
   // ---------------------------------------------------------------------------
   // The following metrics are dimensionless.
   //
 
   // The resolution, along both axes, that the current frame has been painted
   // at.
   //
--- a/gfx/layers/LayersLogging.cpp
+++ b/gfx/layers/LayersLogging.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * vim: sw=2 ts=8 et :
  */
 /* 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 "LayersLogging.h"
-#include "nsPrintfCString.h"
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 nsACString&
 AppendToString(nsACString& s, const void* p,
@@ -90,49 +89,28 @@ nsACString&
 AppendToString(nsACString& s, const nsIntPoint& p,
                const char* pfx, const char* sfx)
 {
   s += pfx;
   s += nsPrintfCString("(x=%d, y=%d)", p.x, p.y);
   return s += sfx;
 }
 
-template<class T>
-nsACString&
-AppendToString(nsACString& s, const PointTyped<T>& p,
-               const char* pfx, const char* sfx)
-{
-  s += pfx;
-  s += nsPrintfCString("(x=%f, y=%f)", p.x, p.y);
-  return s += sfx;
-}
-
 nsACString&
 AppendToString(nsACString& s, const nsIntRect& r,
                const char* pfx, const char* sfx)
 {
   s += pfx;
   s += nsPrintfCString(
     "(x=%d, y=%d, w=%d, h=%d)",
     r.x, r.y, r.width, r.height);
   return s += sfx;
 }
 
 nsACString&
-AppendToString(nsACString& s, const Rect& r,
-               const char* pfx, const char* sfx)
-{
-  s += pfx;
-  s.AppendPrintf(
-    "(x=%f, y=%f, w=%f, h=%f)",
-    r.x, r.y, r.width, r.height);
-  return s += sfx;
-}
-
-nsACString&
 AppendToString(nsACString& s, const nsIntRegion& r,
                const char* pfx, const char* sfx)
 {
   s += pfx;
 
   nsIntRegionRectIterator it(r);
   s += "< ";
   while (const nsIntRect* sr = it.Next())
--- a/gfx/layers/LayersLogging.h
+++ b/gfx/layers/LayersLogging.h
@@ -11,16 +11,17 @@
 #include "mozilla/gfx/Point.h"
 #include "mozilla/gfx/Rect.h"
 #include "mozilla/layers/Compositor.h"
 #include "FrameMetrics.h"
 #include "gfxPattern.h"
 #include "gfxColor.h"
 #include "gfx3DMatrix.h"
 #include "nsRegion.h"
+#include "nsPrintfCString.h"
 
 namespace mozilla {
 namespace layers {
 
 nsACString&
 AppendToString(nsACString& s, const void* p,
                const char* pfx="", const char* sfx="");
 
@@ -42,25 +43,38 @@ AppendToString(nsACString& s, const gfx3
 
 nsACString&
 AppendToString(nsACString& s, const nsIntPoint& p,
                const char* pfx="", const char* sfx="");
 
 template<class T>
 nsACString&
 AppendToString(nsACString& s, const mozilla::gfx::PointTyped<T>& p,
-               const char* pfx="", const char* sfx="");
+               const char* pfx="", const char* sfx="")
+{
+  s += pfx;
+  s += nsPrintfCString("(x=%f, y=%f)", p.x, p.y);
+  return s += sfx;
+}
 
 nsACString&
 AppendToString(nsACString& s, const nsIntRect& r,
                const char* pfx="", const char* sfx="");
 
+template<class T>
 nsACString&
-AppendToString(nsACString& s, const mozilla::gfx::Rect& r,
-               const char* pfx="", const char* sfx="");
+AppendToString(nsACString& s, const mozilla::gfx::RectTyped<T>& r,
+               const char* pfx="", const char* sfx="")
+{
+  s += pfx;
+  s.AppendPrintf(
+    "(x=%f, y=%f, w=%f, h=%f)",
+    r.x, r.y, r.width, r.height);
+  return s += sfx;
+}
 
 nsACString&
 AppendToString(nsACString& s, const nsIntRegion& r,
                const char* pfx="", const char* sfx="");
 
 nsACString&
 AppendToString(nsACString& s, const nsIntSize& sz,
                const char* pfx="", const char* sfx="");
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -392,23 +392,21 @@ ClientLayerManager::ProgressiveUpdateCal
   if (primaryScrollable) {
     const FrameMetrics& metrics = primaryScrollable->AsContainerLayer()->GetFrameMetrics();
 
     // This is derived from the code in
     // gfx/layers/ipc/CompositorParent.cpp::TransformShadowTree.
     const gfx3DMatrix& rootTransform = GetRoot()->GetTransform();
     float devPixelRatioX = 1 / rootTransform.GetXScale();
     float devPixelRatioY = 1 / rootTransform.GetYScale();
-    const gfx::Rect& metricsDisplayPort =
+    const CSSRect& metricsDisplayPort =
       (aDrawingCritical && !metrics.mCriticalDisplayPort.IsEmpty()) ?
         metrics.mCriticalDisplayPort : metrics.mDisplayPort;
-    gfx::Rect displayPort((metricsDisplayPort.x + metrics.mScrollOffset.x) * devPixelRatioX,
-                          (metricsDisplayPort.y + metrics.mScrollOffset.y) * devPixelRatioY,
-                          metricsDisplayPort.width * devPixelRatioX,
-                          metricsDisplayPort.height * devPixelRatioY);
+    LayerRect displayPort = LayerRect::FromCSSRect(metricsDisplayPort + metrics.mScrollOffset,
+                                                   devPixelRatioX, devPixelRatioY);
 
     return AndroidBridge::Bridge()->ProgressiveUpdateCallback(
       aHasPendingNewThebesContent, displayPort, devPixelRatioX, aDrawingCritical,
       aViewport, aScaleX, aScaleY);
   }
 #endif
 
   return false;
--- a/gfx/layers/client/ClientTiledThebesLayer.cpp
+++ b/gfx/layers/client/ClientTiledThebesLayer.cpp
@@ -52,17 +52,18 @@ ClientTiledThebesLayer::BeginPaint()
     if (parent->UseIntermediateSurface()) {
       mPaintData.mTransformScreenToLayer.PreMultiply(parent->GetEffectiveTransform());
     }
   }
   mPaintData.mTransformScreenToLayer.Invert();
 
   // Compute the critical display port in layer space.
   mPaintData.mLayerCriticalDisplayPort.SetEmpty();
-  const gfx::Rect& criticalDisplayPort = GetParent()->GetFrameMetrics().mCriticalDisplayPort;
+  const gfx::Rect& criticalDisplayPort =
+    GetParent()->GetFrameMetrics().mCriticalDisplayPort.ToUnknownRect();
   if (!criticalDisplayPort.IsEmpty()) {
     gfxRect transformedCriticalDisplayPort =
       mPaintData.mTransformScreenToLayer.TransformBounds(
         gfxRect(criticalDisplayPort.x, criticalDisplayPort.y,
                 criticalDisplayPort.width, criticalDisplayPort.height));
     transformedCriticalDisplayPort.RoundOut();
     mPaintData.mLayerCriticalDisplayPort = nsIntRect(transformedCriticalDisplayPort.x,
                                              transformedCriticalDisplayPort.y,
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -346,22 +346,22 @@ AsyncCompositionManager::ApplyAsyncConte
     *aWantNextFrame |=
       controller->SampleContentTransformForFrame(aCurrentFrame,
                                                  container,
                                                  &treeTransform,
                                                  scrollOffset);
 
     const gfx3DMatrix& rootTransform = mLayerManager->GetRoot()->GetTransform();
     const FrameMetrics& metrics = container->GetFrameMetrics();
-    gfx::Rect displayPortLayersPixels(metrics.mCriticalDisplayPort.IsEmpty() ?
-                                      metrics.mDisplayPort : metrics.mCriticalDisplayPort);
+    CSSRect displayPort(metrics.mCriticalDisplayPort.IsEmpty() ?
+                        metrics.mDisplayPort : metrics.mCriticalDisplayPort);
     gfx::Margin fixedLayerMargins(0, 0, 0, 0);
     ScreenPoint offset(0, 0);
     SyncFrameMetrics(scrollOffset, treeTransform.mScale.width, metrics.mScrollableRect,
-                     mLayersUpdated, displayPortLayersPixels, 1 / rootTransform.GetXScale(),
+                     mLayersUpdated, displayPort, 1 / rootTransform.GetXScale(),
                      mIsFirstPaint, fixedLayerMargins, offset);
 
     mIsFirstPaint = false;
     mLayersUpdated = false;
 
     // Apply the render offset
     mLayerManager->GetCompositor()->SetScreenRenderOffset(offset);
 
@@ -420,24 +420,22 @@ AsyncCompositionManager::TransformScroll
   } else if (!metrics.mContentRect.IsEqualEdges(mContentRect)) {
     mContentRect = metrics.mContentRect;
     SetPageRect(metrics.mScrollableRect);
   }
 
   // We synchronise the viewport information with Java after sending the above
   // notifications, so that Java can take these into account in its response.
   // Calculate the absolute display port to send to Java
-  LayerIntRect displayPort = LayerIntRect::FromCSSRectRounded(
-    CSSRect::FromUnknownRect(metrics.mCriticalDisplayPort.IsEmpty()
-                             ? metrics.mDisplayPort
-                             : metrics.mCriticalDisplayPort),
-    layerPixelRatioX, layerPixelRatioY);
-
-  displayPort.x += scrollOffsetLayerPixels.x;
-  displayPort.y += scrollOffsetLayerPixels.y;
+  LayerIntRect displayPort =
+    LayerIntRect::FromCSSRectRounded(metrics.mCriticalDisplayPort.IsEmpty()
+                                       ? metrics.mDisplayPort
+                                       : metrics.mCriticalDisplayPort,
+                                     layerPixelRatioX, layerPixelRatioY);
+  displayPort += scrollOffsetLayerPixels;
 
   gfx::Margin fixedLayerMargins(0, 0, 0, 0);
   ScreenPoint offset(0, 0);
   ScreenPoint scrollOffset(0, 0);
   float scaleX = 1.0,
         scaleY = 1.0;
   SyncViewportInfo(displayPort, layerPixelRatioX, mLayersUpdated,
                    scrollOffset, scaleX, scaleY, fixedLayerMargins,
@@ -590,17 +588,17 @@ AsyncCompositionManager::SyncViewportInf
 #endif
 }
 
 void
 AsyncCompositionManager::SyncFrameMetrics(const gfx::Point& aScrollOffset,
                                           float aZoom,
                                           const CSSRect& aCssPageRect,
                                           bool aLayersUpdated,
-                                          const gfx::Rect& aDisplayPort,
+                                          const CSSRect& aDisplayPort,
                                           float aDisplayResolution,
                                           bool aIsFirstPaint,
                                           gfx::Margin& aFixedLayerMargins,
                                           ScreenPoint& aOffset)
 {
 #ifdef MOZ_WIDGET_ANDROID
   AndroidBridge::Bridge()->SyncFrameMetrics(aScrollOffset, aZoom, aCssPageRect,
                                             aLayersUpdated, aDisplayPort,
--- a/gfx/layers/composite/AsyncCompositionManager.h
+++ b/gfx/layers/composite/AsyncCompositionManager.h
@@ -125,17 +125,17 @@ private:
                         ScreenPoint& aScrollOffset,
                         float& aScaleX, float& aScaleY,
                         gfx::Margin& aFixedLayerMargins,
                         ScreenPoint& aOffset);
   void SyncFrameMetrics(const gfx::Point& aScrollOffset,
                         float aZoom,
                         const CSSRect& aCssPageRect,
                         bool aLayersUpdated,
-                        const gfx::Rect& aDisplayPort,
+                        const CSSRect& aDisplayPort,
                         float aDisplayResolution,
                         bool aIsFirstPaint,
                         gfx::Margin& aFixedLayerMargins,
                         ScreenPoint& aOffset);
 
   /**
    * Recursively applies the given translation to all top-level fixed position
    * layers that are descendants of the given layer.
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -430,17 +430,17 @@ GetRegionArea(const nsIntRegion& aRegion
   while (const nsIntRect* rect = it.Next()) {
     area += rect->width * rect->height;
   }
   return area;
 }
 
 #ifdef MOZ_ANDROID_OMTC
 static float
-GetDisplayportCoverage(const gfx::Rect& aDisplayPort,
+GetDisplayportCoverage(const CSSRect& aDisplayPort,
                        const gfx3DMatrix& aTransformToScreen,
                        const nsIntRect& aScreenRect)
 {
   gfxRect transformedDisplayport =
     aTransformToScreen.TransformBounds(gfxRect(aDisplayPort.x,
                                                aDisplayPort.y,
                                                aDisplayPort.width,
                                                aDisplayPort.height));
--- a/gfx/layers/composite/ThebesLayerComposite.cpp
+++ b/gfx/layers/composite/ThebesLayerComposite.cpp
@@ -250,17 +250,17 @@ ThebesLayerComposite::GetCompositionBoun
       float scaleY = rootTransform.GetYScale();
 
       // Get the content document bounds, in screen-space.
       const FrameMetrics& metrics = scrollableLayer->GetFrameMetrics();
       const LayerIntSize& contentSize = metrics.mContentRect.Size();
       gfx::Point scrollOffset =
         gfx::Point((metrics.mScrollOffset.x * metrics.LayersPixelsPerCSSPixel().width) / scaleX,
                    (metrics.mScrollOffset.y * metrics.LayersPixelsPerCSSPixel().height) / scaleY);
-      const nsIntPoint& contentOrigin = nsIntPoint(
+      const nsIntPoint contentOrigin(
         metrics.mContentRect.x - NS_lround(scrollOffset.x),
         metrics.mContentRect.y - NS_lround(scrollOffset.y));
       gfxRect contentRect = gfxRect(contentOrigin.x, contentOrigin.y,
                                     contentSize.width, contentSize.height);
       gfxRect contentBounds = scrollableLayer->GetEffectiveTransform().
         TransformBounds(contentRect);
 
       // Clip the composition bounds to the content bounds
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -648,56 +648,56 @@ nsEventStatus AsyncPanZoomController::On
   return nsEventStatus_eConsumeNoDefault;
 }
 
 nsEventStatus AsyncPanZoomController::OnLongPress(const TapGestureInput& aEvent) {
   if (mGeckoContentController) {
     MonitorAutoLock monitor(mMonitor);
 
     gfxFloat resolution = CalculateResolution(mFrameMetrics).width;
-    gfx::Point point = WidgetSpaceToCompensatedViewportSpace(
-      gfx::Point(aEvent.mPoint.x, aEvent.mPoint.y),
-      resolution);
-    mGeckoContentController->HandleLongTap(nsIntPoint(NS_lround(point.x),
-                                                      NS_lround(point.y)));
+    CSSPoint point = CSSPoint::FromUnknownPoint(
+      WidgetSpaceToCompensatedViewportSpace(
+        gfx::Point(aEvent.mPoint.x, aEvent.mPoint.y),
+        resolution));
+    mGeckoContentController->HandleLongTap(CSSIntPoint::RoundToInt(point));
     return nsEventStatus_eConsumeNoDefault;
   }
   return nsEventStatus_eIgnore;
 }
 
 nsEventStatus AsyncPanZoomController::OnSingleTapUp(const TapGestureInput& aEvent) {
   return nsEventStatus_eIgnore;
 }
 
 nsEventStatus AsyncPanZoomController::OnSingleTapConfirmed(const TapGestureInput& aEvent) {
   if (mGeckoContentController) {
     MonitorAutoLock monitor(mMonitor);
 
     gfxFloat resolution = CalculateResolution(mFrameMetrics).width;
-    gfx::Point point = WidgetSpaceToCompensatedViewportSpace(
-      gfx::Point(aEvent.mPoint.x, aEvent.mPoint.y),
-      resolution);
-    mGeckoContentController->HandleSingleTap(nsIntPoint(NS_lround(point.x),
-                                                        NS_lround(point.y)));
+    CSSPoint point = CSSPoint::FromUnknownPoint(
+      WidgetSpaceToCompensatedViewportSpace(
+        gfx::Point(aEvent.mPoint.x, aEvent.mPoint.y),
+        resolution));
+    mGeckoContentController->HandleSingleTap(CSSIntPoint::RoundToInt(point));
     return nsEventStatus_eConsumeNoDefault;
   }
   return nsEventStatus_eIgnore;
 }
 
 nsEventStatus AsyncPanZoomController::OnDoubleTap(const TapGestureInput& aEvent) {
   if (mGeckoContentController) {
     MonitorAutoLock monitor(mMonitor);
 
     if (mAllowZoom) {
       gfxFloat resolution = CalculateResolution(mFrameMetrics).width;
-      gfx::Point point = WidgetSpaceToCompensatedViewportSpace(
-        gfx::Point(aEvent.mPoint.x, aEvent.mPoint.y),
-        resolution);
-      mGeckoContentController->HandleDoubleTap(nsIntPoint(NS_lround(point.x),
-                                                          NS_lround(point.y)));
+      CSSPoint point = CSSPoint::FromUnknownPoint(
+        WidgetSpaceToCompensatedViewportSpace(
+          gfx::Point(aEvent.mPoint.x, aEvent.mPoint.y),
+          resolution));
+      mGeckoContentController->HandleDoubleTap(CSSIntPoint::RoundToInt(point));
     }
 
     return nsEventStatus_eConsumeNoDefault;
   }
   return nsEventStatus_eIgnore;
 }
 
 nsEventStatus AsyncPanZoomController::OnCancelTap(const TapGestureInput& aEvent) {
@@ -834,17 +834,17 @@ void AsyncPanZoomController::ScrollBy(co
 
 void AsyncPanZoomController::SetPageRect(const CSSRect& aCSSPageRect) {
   FrameMetrics metrics = mFrameMetrics;
   gfxFloat resolution = CalculateResolution(mFrameMetrics).width;
 
   // The page rect is the css page rect scaled by the current zoom.
   // Round the page rect so we don't get any truncation, then get the nsIntRect
   // from this.
-  metrics.mContentRect = LayerRect::FromCSSRectRoundOut(aCSSPageRect, resolution);
+  metrics.mContentRect = LayerRect::FromCSSRectRoundOut(aCSSPageRect, resolution, resolution);
   metrics.mScrollableRect = aCSSPageRect;
 
   mFrameMetrics = metrics;
 }
 
 void AsyncPanZoomController::ScaleWithFocus(float aZoom,
                                             const nsIntPoint& aFocus) {
   float zoomFactor = aZoom / mFrameMetrics.mZoom.width;
@@ -895,34 +895,34 @@ bool AsyncPanZoomController::EnlargeDisp
       // and to the left when skating negatively.
       *aDisplayPortOffset -= aVelocity < 0 ? aCompositionBounds : 0;
     }
     return true;
   }
   return false;
 }
 
-const gfx::Rect AsyncPanZoomController::CalculatePendingDisplayPort(
+const CSSRect AsyncPanZoomController::CalculatePendingDisplayPort(
   const FrameMetrics& aFrameMetrics,
   const gfx::Point& aVelocity,
   const gfx::Point& aAcceleration,
   double aEstimatedPaintDuration)
 {
   // If we don't get an estimated paint duration, we probably don't have any
   // data. In this case, we're dealing with either a stationary frame or a first
   // paint. In either of these cases, we can just assume it'll take 1 second to
   // paint. Getting this correct is not important anyways since it's only really
   // useful when accelerating, which can't be happening at this point.
   double estimatedPaintDuration =
     aEstimatedPaintDuration > EPSILON ? aEstimatedPaintDuration : 1.0;
 
   gfxSize resolution = CalculateResolution(aFrameMetrics);
   CSSIntRect compositionBounds = LayerIntRect::ToCSSIntRectRoundIn(
-    aFrameMetrics.mCompositionBounds, resolution);
-  gfx::Rect scrollableRect = aFrameMetrics.mScrollableRect.ToUnknownRect();
+    aFrameMetrics.mCompositionBounds, resolution.width, resolution.height);
+  CSSRect scrollableRect = aFrameMetrics.mScrollableRect;
 
   // Ensure the scrollableRect is at least as big as the compositionBounds
   // because the scrollableRect can be smaller if the content is not large
   // and the scrollableRect hasn't been updated yet.
   // We move the scrollableRect up because we don't know if we can move it
   // down. i.e. we know that scrollableRect can go back as far as zero.
   // but we don't know how much further ahead it can go.
   if (scrollableRect.width < compositionBounds.width) {
@@ -933,19 +933,19 @@ const gfx::Rect AsyncPanZoomController::
   if (scrollableRect.height < compositionBounds.height) {
       scrollableRect.y = std::max(0.f,
                                   scrollableRect.y - (compositionBounds.height - scrollableRect.height));
       scrollableRect.height = compositionBounds.height;
   }
 
   CSSPoint scrollOffset = aFrameMetrics.mScrollOffset;
 
-  gfx::Rect displayPort(0, 0,
-                        compositionBounds.width * gXStationarySizeMultiplier,
-                        compositionBounds.height * gYStationarySizeMultiplier);
+  CSSRect displayPort = CSSRect(compositionBounds);
+  displayPort.MoveTo(0, 0);
+  displayPort.Scale(gXStationarySizeMultiplier, gYStationarySizeMultiplier);
 
   // If there's motion along an axis of movement, and it's above a threshold,
   // then we want to paint a larger area in the direction of that motion so that
   // it's less likely to checkerboard.
   bool enlargedX = EnlargeDisplayPortAlongAxis(
     gXSkateSizeMultiplier, estimatedPaintDuration,
     compositionBounds.width, aVelocity.x, aAcceleration.x,
     &displayPort.x, &displayPort.width);
@@ -976,22 +976,18 @@ const gfx::Rect AsyncPanZoomController::
     scrollOffset.x = scrollableRect.x;
   }
   if (scrollOffset.y + compositionBounds.height > scrollableRect.height) {
     scrollOffset.y -= compositionBounds.height + scrollOffset.y - scrollableRect.height;
   } else if (scrollOffset.y < scrollableRect.y) {
     scrollOffset.y = scrollableRect.y;
   }
 
-  gfx::Rect shiftedDisplayPort = displayPort;
-  shiftedDisplayPort.MoveBy(scrollOffset.x, scrollOffset.y);
-  displayPort = scrollableRect.ClampRect(shiftedDisplayPort);
-  displayPort.MoveBy(-scrollOffset.x, -scrollOffset.y);
-
-  return displayPort;
+  CSSRect shiftedDisplayPort = displayPort + scrollOffset;
+  return scrollableRect.ClampRect(shiftedDisplayPort) - scrollOffset;
 }
 
 /*static*/ gfxSize
 AsyncPanZoomController::CalculateIntrinsicScale(const FrameMetrics& aMetrics)
 {
   gfxFloat intrinsicScale = (gfxFloat(aMetrics.mCompositionBounds.width) / 
                              gfxFloat(aMetrics.mViewport.width));
   return gfxSize(intrinsicScale, intrinsicScale);
@@ -1006,17 +1002,17 @@ AsyncPanZoomController::CalculateResolut
                  intrinsicScale.height * userZoom.height);
 }
 
 /*static*/ CSSRect
 AsyncPanZoomController::CalculateCompositedRectInCssPixels(const FrameMetrics& aMetrics)
 {
   gfxSize resolution = CalculateResolution(aMetrics);
   CSSIntRect rect = LayerIntRect::ToCSSIntRectRoundIn(
-    aMetrics.mCompositionBounds, resolution);
+    aMetrics.mCompositionBounds, resolution.width, resolution.height);
   return CSSRect(rect);
 }
 
 void AsyncPanZoomController::SetDPI(int aDPI) {
   mDPI = aDPI;
 }
 
 int AsyncPanZoomController::GetDPI() {
@@ -1043,26 +1039,22 @@ void AsyncPanZoomController::RequestCont
   }
 
   mFrameMetrics.mDisplayPort =
     CalculatePendingDisplayPort(mFrameMetrics,
                                 GetVelocityVector(),
                                 GetAccelerationVector(),
                                 estimatedPaintDuration);
 
-  CSSPoint oldScrollOffset = mLastPaintRequestMetrics.mScrollOffset,
-           newScrollOffset = mFrameMetrics.mScrollOffset;
-
   // If we're trying to paint what we already think is painted, discard this
   // request since it's a pointless paint.
-  gfx::Rect oldDisplayPort = mLastPaintRequestMetrics.mDisplayPort;
-  gfx::Rect newDisplayPort = mFrameMetrics.mDisplayPort;
-
-  oldDisplayPort.MoveBy(oldScrollOffset.x, oldScrollOffset.y);
-  newDisplayPort.MoveBy(newScrollOffset.x, newScrollOffset.y);
+  CSSRect oldDisplayPort = mLastPaintRequestMetrics.mDisplayPort
+                         + mLastPaintRequestMetrics.mScrollOffset;
+  CSSRect newDisplayPort = mFrameMetrics.mDisplayPort
+                         + mFrameMetrics.mScrollOffset;
 
   if (fabsf(oldDisplayPort.x - newDisplayPort.x) < EPSILON &&
       fabsf(oldDisplayPort.y - newDisplayPort.y) < EPSILON &&
       fabsf(oldDisplayPort.width - newDisplayPort.width) < EPSILON &&
       fabsf(oldDisplayPort.height - newDisplayPort.height) < EPSILON &&
       mFrameMetrics.mResolution.width == mLastPaintRequestMetrics.mResolution.width) {
     return;
   }
@@ -1179,17 +1171,17 @@ bool AsyncPanZoomController::SampleConte
     // during runtime, but we must wait for Gecko to repaint.
     localScale = CalculateResolution(mFrameMetrics);
 
     if (frame.IsScrollable()) {
       metricsScrollOffset = frame.GetScrollOffsetInLayerPixels();
     }
 
     scrollOffset = gfxPoint(mFrameMetrics.mScrollOffset.x, mFrameMetrics.mScrollOffset.y);
-    mCurrentAsyncScrollOffset = mFrameMetrics.mScrollOffset.ToUnknownPoint();
+    mCurrentAsyncScrollOffset = mFrameMetrics.mScrollOffset;
   }
 
   // Cancel the mAsyncScrollTimeoutTask because we will fire a
   // mozbrowserasyncscroll event or renew the mAsyncScrollTimeoutTask again.
   if (mAsyncScrollTimeoutTask) {
     mAsyncScrollTimeoutTask->Cancel();
     mAsyncScrollTimeoutTask = nullptr;
   }
@@ -1367,17 +1359,17 @@ void AsyncPanZoomController::ZoomToRect(
     // 1. If the rect is empty, request received from browserElementScrolling.js
     // 2. currentZoom is equal to mMaxZoom and user still double-tapping it
     // 3. currentZoom is equal to localMinZoom and user still double-tapping it
     // Treat these three cases as a request to zoom out as much as possible.
     if (zoomToRect.IsEmpty() ||
         (currentZoom.width == mMaxZoom && targetZoom >= mMaxZoom) ||
         (currentZoom.width == localMinZoom && targetZoom <= localMinZoom)) {
       CSSIntRect cssCompositionBounds = LayerIntRect::ToCSSIntRectRoundIn(
-        compositionBounds, resolution);
+        compositionBounds, resolution.width, resolution.height);
 
       float y = scrollOffset.y;
       float newHeight =
         cssCompositionBounds.height * cssPageRect.width / cssCompositionBounds.width;
       float dh = cssCompositionBounds.height - newHeight;
 
       zoomToRect = CSSRect(0.0f,
                            y + dh/2,
@@ -1496,22 +1488,20 @@ void AsyncPanZoomController::PostDelayed
   mGeckoContentController->PostDelayedTask(aTask, aDelayMs);
 }
 
 void AsyncPanZoomController::SendAsyncScrollEvent() {
   if (!mGeckoContentController) {
     return;
   }
 
-  gfx::Rect contentRect;
-  gfx::Size scrollableSize;
+  CSSRect contentRect;
+  CSSSize scrollableSize;
   {
-    scrollableSize = gfx::Size(mFrameMetrics.mScrollableRect.width,
-                               mFrameMetrics.mScrollableRect.height);
-    contentRect = AsyncPanZoomController::CalculateCompositedRectInCssPixels(mFrameMetrics)
-        .ToUnknownRect();
+    scrollableSize = mFrameMetrics.mScrollableRect.Size();
+    contentRect = AsyncPanZoomController::CalculateCompositedRectInCssPixels(mFrameMetrics);
     contentRect.MoveTo(mCurrentAsyncScrollOffset);
   }
 
   mGeckoContentController->SendAsyncScrollDOMEvent(contentRect, scrollableSize);
 }
 }
 }
--- a/gfx/layers/ipc/AsyncPanZoomController.h
+++ b/gfx/layers/ipc/AsyncPanZoomController.h
@@ -218,17 +218,17 @@ public:
   int GetDPI();
 
   /**
    * Recalculates the displayport. Ideally, this should paint an area bigger
    * than the composite-to dimensions so that when you scroll down, you don't
    * checkerboard immediately. This includes a bunch of logic, including
    * algorithms to bias painting in the direction of the velocity.
    */
-  static const gfx::Rect CalculatePendingDisplayPort(
+  static const CSSRect CalculatePendingDisplayPort(
     const FrameMetrics& aFrameMetrics,
     const gfx::Point& aVelocity,
     const gfx::Point& aAcceleration,
     double aEstimatedPaintDuration);
 
   /**
    * Return the scale factor needed to fit the viewport in |aMetrics|
    * into its composition bounds.
@@ -563,21 +563,21 @@ private:
 
   // When the last paint request started. Used to determine the duration of
   // previous paints.
   TimeStamp mPreviousPaintStartTime;
 
   // The last time and offset we fire the mozbrowserasyncscroll event when
   // compositor has sampled the content transform for this frame.
   TimeStamp mLastAsyncScrollTime;
-  gfx::Point mLastAsyncScrollOffset;
+  CSSPoint mLastAsyncScrollOffset;
 
   // The current offset drawn on the screen, it may not be sent since we have
   // throttling policy for mozbrowserasyncscroll event.
-  gfx::Point mCurrentAsyncScrollOffset;
+  CSSPoint mCurrentAsyncScrollOffset;
 
   // The delay task triggered by the throttling mozbrowserasyncscroll event
   // ensures the last mozbrowserasyncscroll event is always been fired.
   CancelableTask* mAsyncScrollTimeoutTask;
 
   // The time period in ms that throttles mozbrowserasyncscroll event.
   // Default is 100ms if there is no "apzc.asyncscroll.throttle" in preference.
   uint32_t mAsyncScrollThrottleTime;
--- a/gfx/layers/ipc/Axis.cpp
+++ b/gfx/layers/ipc/Axis.cpp
@@ -313,19 +313,19 @@ float Axis::GetPageLength() {
   return GetRectLength(pageRect);
 }
 
 bool Axis::ScaleWillOverscrollBothSides(float aScale) {
   const FrameMetrics& metrics = mAsyncPanZoomController->GetFrameMetrics();
 
   CSSRect cssContentRect = metrics.mScrollableRect;
 
-  float currentScale = metrics.mZoom.width;
+  float scale = metrics.mZoom.width * aScale;
   CSSIntRect cssCompositionBounds = LayerIntRect::ToCSSIntRectRoundIn(
-    metrics.mCompositionBounds, currentScale * aScale);
+    metrics.mCompositionBounds, scale, scale);
 
   return GetRectLength(cssContentRect) < GetRectLength(CSSRect(cssCompositionBounds));
 }
 
 AxisX::AxisX(AsyncPanZoomController* aAsyncPanZoomController)
   : Axis(aAsyncPanZoomController)
 {
 
--- a/gfx/layers/ipc/GeckoContentController.h
+++ b/gfx/layers/ipc/GeckoContentController.h
@@ -26,38 +26,38 @@ public:
   virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) = 0;
 
   /**
    * Requests handling of a double tap. |aPoint| is in CSS pixels, relative to
    * the current scroll offset. This should eventually round-trip back to
    * AsyncPanZoomController::ZoomToRect with the dimensions that we want to zoom
    * to.
    */
-  virtual void HandleDoubleTap(const nsIntPoint& aPoint) = 0;
+  virtual void HandleDoubleTap(const CSSIntPoint& aPoint) = 0;
 
   /**
    * Requests handling a single tap. |aPoint| is in CSS pixels, relative to the
    * current scroll offset. This should simulate and send to content a mouse
    * button down, then mouse button up at |aPoint|.
    */
-  virtual void HandleSingleTap(const nsIntPoint& aPoint) = 0;
+  virtual void HandleSingleTap(const CSSIntPoint& aPoint) = 0;
 
   /**
    * Requests handling a long tap. |aPoint| is in CSS pixels, relative to the
    * current scroll offset.
    */
-  virtual void HandleLongTap(const nsIntPoint& aPoint) = 0;
+  virtual void HandleLongTap(const CSSIntPoint& aPoint) = 0;
 
   /**
    * Requests sending a mozbrowserasyncscroll domevent to embedder.
    * |aContentRect| is in CSS pixels, relative to the current cssPage.
    * |aScrollableSize| is the current content width/height in CSS pixels.
    */
-  virtual void SendAsyncScrollDOMEvent(const gfx::Rect &aContentRect,
-                                       const gfx::Size &aScrollableSize) = 0;
+  virtual void SendAsyncScrollDOMEvent(const CSSRect &aContentRect,
+                                       const CSSSize &aScrollableSize) = 0;
 
   /**
    * Schedules a runnable to run on the controller/UI thread at some time
    * in the future.
    */
   virtual void PostDelayedTask(Task* aTask, int aDelayMs) = 0;
 
   GeckoContentController() {}
--- a/ipc/glue/IPCMessageUtils.h
+++ b/ipc/glue/IPCMessageUtils.h
@@ -801,16 +801,34 @@ struct ParamTraits< mozilla::gfx::PointT
 
   static bool Read(const Message* msg, void** iter, paramType* result)
   {
     return (ReadParam(msg, iter, &result->x) &&
             ReadParam(msg, iter, &result->y));
   }
 };
 
+template<class T>
+struct ParamTraits< mozilla::gfx::IntPointTyped<T> >
+{
+  typedef mozilla::gfx::IntPointTyped<T> paramType;
+
+  static void Write(Message* msg, const paramType& param)
+  {
+    WriteParam(msg, param.x);
+    WriteParam(msg, param.y);
+  }
+
+  static bool Read(const Message* msg, void** iter, paramType* result)
+  {
+    return (ReadParam(msg, iter, &result->x) &&
+            ReadParam(msg, iter, &result->y));
+  }
+};
+
 template<>
 struct ParamTraits<mozilla::gfx::Size>
 {
   typedef mozilla::gfx::Size paramType;
 
   static void Write(Message* msg, const paramType& param)
   {
     WriteParam(msg, param.width);
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -852,31 +852,34 @@ CharsMatch(const jschar *p, const char *
     while (*q) {
         if (*p++ != *q++)
             return false;
     }
     return true;
 }
 
 bool
-TokenStream::getAtSourceMappingURL(bool isMultiline)
+TokenStream::getSourceMappingURL(bool isMultiline, bool shouldWarnDeprecated)
 {
-    /* Match comments of the form "//@ sourceMappingURL=<url>" or
-     * "/\* //@ sourceMappingURL=<url> *\/"
+    /* Match comments of the form "//# sourceMappingURL=<url>" or
+     * "/\* //# sourceMappingURL=<url> *\/"
      *
-     * To avoid a crashing bug in IE, several JavaScript transpilers
-     * wrap single line comments containing a source mapping URL
-     * inside a multiline comment to avoid a crashing bug in IE. To
-     * avoid potentially expensive lookahead and backtracking, we
-     * only check for this case if we encounter an '@' character.
+     * To avoid a crashing bug in IE, several JavaScript transpilers wrap single
+     * line comments containing a source mapping URL inside a multiline
+     * comment. To avoid potentially expensive lookahead and backtracking, we
+     * only check for this case if we encounter a '#' character.
      */
     jschar peeked[18];
     int32_t c;
 
     if (peekChars(18, peeked) && CharsMatch(peeked, " sourceMappingURL=")) {
+        if (shouldWarnDeprecated && !reportWarning(JSMSG_DEPRECATED_SOURCE_MAP)) {
+            return false;
+        }
+
         skipChars(18);
         tokenbuf.clear();
 
         while ((c = peekChar()) && c != EOF && !IsSpaceOrBOM2(c)) {
             getChar();
             /*
              * Source mapping URLs can occur in both single- and multiline
              * comments. If we're currently inside a multiline comment, we also
@@ -1595,18 +1598,21 @@ TokenStream::getTokenInternal()
         tt = matchChar('=') ? TOK_MULASSIGN : TOK_STAR;
         break;
 
       case '/':
         /*
          * Look for a single-line comment.
          */
         if (matchChar('/')) {
-            if (matchChar('@') && !getAtSourceMappingURL(false))
-                goto error;
+            c = peekChar();
+            if (c == '@' || c == '#') {
+                if (!getSourceMappingURL(false, getChar() == '@'))
+                    goto error;
+            }
 
   skipline:
             /* Optimize line skipping if we are not in an HTML comment. */
             if (flags & TSF_IN_HTML_COMMENT) {
                 while ((c = getChar()) != EOF && c != '\n') {
                     if (c == '-' && matchChar('-') && matchChar('>'))
                         flags &= ~TSF_IN_HTML_COMMENT;
                 }
@@ -1621,18 +1627,20 @@ TokenStream::getTokenInternal()
 
         /*
          * Look for a multi-line comment.
          */
         if (matchChar('*')) {
             unsigned linenoBefore = lineno;
             while ((c = getChar()) != EOF &&
                    !(c == '*' && matchChar('/'))) {
-                if (c == '@' && !getAtSourceMappingURL(true))
-                   goto error;
+                if (c == '@' || c == '#') {
+                    if (!getSourceMappingURL(true, c == '@'))
+                        goto error;
+                }
             }
             if (c == EOF) {
                 reportError(JSMSG_UNTERMINATED_COMMENT);
                 goto error;
             }
             if (linenoBefore != lineno)
                 updateFlagsForEOL();
             cursor = (cursor - 1) & ntokensMask;
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -873,17 +873,17 @@ class MOZ_STACK_CLASS TokenStream
     int32_t getCharIgnoreEOL();
     void ungetChar(int32_t c);
     void ungetCharIgnoreEOL(int32_t c);
     Token *newToken(ptrdiff_t adjust);
     bool peekUnicodeEscape(int32_t *c);
     bool matchUnicodeEscapeIdStart(int32_t *c);
     bool matchUnicodeEscapeIdent(int32_t *c);
     bool peekChars(int n, jschar *cp);
-    bool getAtSourceMappingURL(bool isMultiline);
+    bool getSourceMappingURL(bool isMultiline, bool shouldWarnDeprecated);
 
     // |expect| cannot be an EOL char.
     bool matchChar(int32_t expect) {
         MOZ_ASSERT(!TokenBuf::isRawEOLChar(expect));
         return JS_LIKELY(userbuf.hasRawChars()) &&
                userbuf.matchRawChar(expect);
     }
 
--- a/js/src/ion/Ion.h
+++ b/js/src/ion/Ion.h
@@ -97,22 +97,16 @@ struct IonOptions
     uint32_t baselineUsesBeforeCompile;
 
     // How many invocations or loop iterations are needed before functions
     // are compiled.
     //
     // Default: 1,000
     uint32_t usesBeforeCompile;
 
-    // How many invocations or loop iterations are needed before functions
-    // are compiled when JM is disabled.
-    //
-    // Default: 40
-    uint32_t usesBeforeCompileNoJaeger;
-
     // How many invocations or loop iterations are needed before calls
     // are inlined, as a fraction of usesBeforeCompile.
     //
     // Default: .125
     double usesBeforeInliningFactor;
 
     // How many times we will try to enter a script via OSR before
     // invalidating the script.
@@ -178,17 +172,17 @@ struct IonOptions
 
     // How many uses of a parallel kernel before we attempt compilation.
     //
     // Default: 1
     uint32_t usesBeforeCompileParallel;
 
     void setEagerCompilation() {
         eagerCompilation = true;
-        usesBeforeCompile = usesBeforeCompileNoJaeger = 0;
+        usesBeforeCompile = 0;
         baselineUsesBeforeCompile = 0;
 
         parallelCompilation = false;
     }
 
     IonOptions()
       : gvn(true),
         gvnIsOptimistic(true),
@@ -199,17 +193,16 @@ struct IonOptions
         inlining(true),
         edgeCaseAnalysis(true),
         rangeAnalysis(true),
         uce(true),
         eaa(true),
         parallelCompilation(false),
         baselineUsesBeforeCompile(10),
         usesBeforeCompile(1000),
-        usesBeforeCompileNoJaeger(40),
         usesBeforeInliningFactor(.125),
         osrPcMismatchesBeforeRecompile(6000),
         frequentBailoutThreshold(10),
         maxStackArgs(4096),
         maxInlineDepth(3),
         smallFunctionMaxInlineDepth(10),
         smallFunctionMaxBytecodeLength(100),
         polyInlineMax(4),
--- a/js/src/ion/IonFrameIterator-inl.h
+++ b/js/src/ion/IonFrameIterator-inl.h
@@ -21,25 +21,25 @@ SnapshotIterator::readFrameArgs(Op &op, 
                                 unsigned start, unsigned formalEnd, unsigned iterEnd,
                                 JSScript *script)
 {
     if (scopeChain)
         *scopeChain = read();
     else
         skip();
 
+    // Skip slot for arguments object.
+    if (script->argumentsHasVarBinding())
+        skip();
+
     if (thisv)
         *thisv = read();
     else
         skip();
 
-    // Skip slot for arguments object.
-    if (script->argumentsHasVarBinding())
-        skip();
-
     unsigned i = 0;
     if (formalEnd < start)
         i = start;
 
     for (; i < start; i++)
         skip();
     for (; i < formalEnd && i < iterEnd; i++) {
         // We are not always able to read values from the snapshots, some values
@@ -154,16 +154,20 @@ inline JSObject *
 InlineFrameIteratorMaybeGC<allowGC>::thisObject() const
 {
     // JS_ASSERT(isConstructing(...));
     SnapshotIterator s(si_);
 
     // scopeChain
     s.skip();
 
+    // Arguments object.
+    if (script()->argumentsHasVarBinding())
+        s.skip();
+
     // In strict modes, |this| may not be an object and thus may not be
     // readable which can either segv in read or trigger the assertion.
     Value v = s.read();
     JS_ASSERT(v.isObject());
     return &v.toObject();
 }
 
 template <AllowGC allowGC>
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug877378.js
@@ -0,0 +1,19 @@
+evalcx("\
+    let z = 'x';\
+    for (var v of z) {\
+        y = evaluate(\"Object.defineProperty(this,\\\"y\\\",\
+                         {get:  function() {}}\
+                    );\",\
+               {catchTermination: true, saveFrameChain: true}\
+        );\
+    }",
+    newGlobal('')
+)
+
+evalcx("\
+    for (x = 0; x < 1; ++x) { \
+        v = evaluate(\"gc\",{ \
+            saveFrameChain: true \
+        })\
+    }\
+", newGlobal(''));
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Script-sourceMapURL-deprecated.js
@@ -0,0 +1,70 @@
+// Script.prototype.sourceMapURL can be a string or null.
+
+let g = newGlobal('new-compartment');
+let dbg = new Debugger;
+let gw = dbg.addDebuggee(g);
+
+function getSourceMapURL() {
+    let fw = gw.makeDebuggeeValue(g.f);
+    return fw.script.sourceMapURL;
+}
+
+// Without a source map
+g.evaluate("function f(x) { return 2*x; }");
+assertEq(getSourceMapURL(), null);
+
+// With a source map
+g.evaluate("function f(x) { return 2*x; }", {sourceMapURL: 'file:///var/foo.js.map'});
+assertEq(getSourceMapURL(), 'file:///var/foo.js.map');
+
+// Nested functions
+let fired = false;
+dbg.onDebuggerStatement = function (frame) {
+    fired = true;
+    assertEq(frame.script.sourceMapURL, 'file:///var/bar.js.map');
+};
+g.evaluate('(function () { (function () { debugger; })(); })();',
+           {sourceMapURL: 'file:///var/bar.js.map'});
+assertEq(fired, true);
+
+// Comment pragmas
+g.evaluate('function f() {}\n' +
+           '//@ sourceMappingURL=file:///var/quux.js.map');
+assertEq(getSourceMapURL(), 'file:///var/quux.js.map');
+
+g.evaluate('function f() {}\n' +
+           '/*//@ sourceMappingURL=file:///var/quux.js.map*/');
+assertEq(getSourceMapURL(), 'file:///var/quux.js.map');
+
+g.evaluate('function f() {}\n' +
+           '/*\n' +
+           '//@ sourceMappingURL=file:///var/quux.js.map\n' +
+           '*/');
+assertEq(getSourceMapURL(), 'file:///var/quux.js.map');
+
+// Spaces are disallowed by the URL spec (they should have been
+// percent-encoded).
+g.evaluate('function f() {}\n' +
+           '//@ sourceMappingURL=http://example.com/has illegal spaces.map');
+assertEq(getSourceMapURL(), 'http://example.com/has');
+
+// When the URL is missing, we don't set the sourceMapURL and we don't skip the
+// next line of input.
+g.evaluate('function f() {}\n' +
+           '//@ sourceMappingURL=\n' +
+           'function z() {}');
+assertEq(getSourceMapURL(), null);
+assertEq('z' in g, true);
+
+// The last comment pragma we see should be the one which sets the source map's
+// URL.
+g.evaluate('function f() {}\n' +
+           '//@ sourceMappingURL=http://example.com/foo.js.map\n' +
+           '//@ sourceMappingURL=http://example.com/bar.js.map');
+assertEq(getSourceMapURL(), 'http://example.com/bar.js.map');
+
+// With both a comment and the evaluate option.
+g.evaluate('function f() {}\n' +
+           '//@ sourceMappingURL=http://example.com/foo.js.map',
+           {sourceMapURL: 'http://example.com/bar.js.map'});
+assertEq(getSourceMapURL(), 'http://example.com/foo.js.map');
--- a/js/src/jit-test/tests/debug/Script-sourceMapURL.js
+++ b/js/src/jit-test/tests/debug/Script-sourceMapURL.js
@@ -24,47 +24,47 @@ dbg.onDebuggerStatement = function (fram
     assertEq(frame.script.sourceMapURL, 'file:///var/bar.js.map');
 };
 g.evaluate('(function () { (function () { debugger; })(); })();',
            {sourceMapURL: 'file:///var/bar.js.map'});
 assertEq(fired, true);
 
 // Comment pragmas
 g.evaluate('function f() {}\n' +
-           '//@ sourceMappingURL=file:///var/quux.js.map');
+           '//# sourceMappingURL=file:///var/quux.js.map');
 assertEq(getSourceMapURL(), 'file:///var/quux.js.map');
 
 g.evaluate('function f() {}\n' +
-           '/*//@ sourceMappingURL=file:///var/quux.js.map*/');
+           '/*//# sourceMappingURL=file:///var/quux.js.map*/');
 assertEq(getSourceMapURL(), 'file:///var/quux.js.map');
 
 g.evaluate('function f() {}\n' +
            '/*\n' +
-           '//@ sourceMappingURL=file:///var/quux.js.map\n' +
+           '//# sourceMappingURL=file:///var/quux.js.map\n' +
            '*/');
 assertEq(getSourceMapURL(), 'file:///var/quux.js.map');
 
 // Spaces are disallowed by the URL spec (they should have been
 // percent-encoded).
 g.evaluate('function f() {}\n' +
-           '//@ sourceMappingURL=http://example.com/has illegal spaces.map');
+           '//# sourceMappingURL=http://example.com/has illegal spaces.map');
 assertEq(getSourceMapURL(), 'http://example.com/has');
 
 // When the URL is missing, we don't set the sourceMapURL and we don't skip the
 // next line of input.
 g.evaluate('function f() {}\n' +
-           '//@ sourceMappingURL=\n' +
+           '//# sourceMappingURL=\n' +
            'function z() {}');
 assertEq(getSourceMapURL(), null);
 assertEq('z' in g, true);
 
 // The last comment pragma we see should be the one which sets the source map's
 // URL.
 g.evaluate('function f() {}\n' +
-           '//@ sourceMappingURL=http://example.com/foo.js.map\n' +
-           '//@ sourceMappingURL=http://example.com/bar.js.map');
+           '//# sourceMappingURL=http://example.com/foo.js.map\n' +
+           '//# sourceMappingURL=http://example.com/bar.js.map');
 assertEq(getSourceMapURL(), 'http://example.com/bar.js.map');
 
 // With both a comment and the evaluate option.
 g.evaluate('function f() {}\n' +
-           '//@ sourceMappingURL=http://example.com/foo.js.map',
+           '//# sourceMappingURL=http://example.com/foo.js.map',
            {sourceMapURL: 'http://example.com/bar.js.map'});
 assertEq(getSourceMapURL(), 'http://example.com/foo.js.map');
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug876465.js
@@ -0,0 +1,20 @@
+function initialize() {};
+function test() {
+eval("\
+var Class = {\
+  create : function() {\
+    return function() {\
+      this.initialize.apply(this, arguments);\
+    }\
+  }\
+};\
+var Foo = Class.create();\
+Foo.prototype = {\
+  initialize : function() {\
+    this.bar = Foo();\
+  }\
+};\
+var foo = new Foo();\
+");
+}
+test();
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -395,8 +395,9 @@ MSG_DEF(JSMSG_USE_ASM_DIRECTIVE_FAIL, 34
 MSG_DEF(JSMSG_USE_ASM_TYPE_FAIL,      342, 1, JSEXN_TYPEERR, "asm.js type error: {0}")
 MSG_DEF(JSMSG_USE_ASM_LINK_FAIL,      343, 1, JSEXN_TYPEERR, "asm.js link error: {0}")
 MSG_DEF(JSMSG_USE_ASM_TYPE_OK,        344, 0, JSEXN_ERR,     "successfully compiled asm.js code")
 MSG_DEF(JSMSG_BAD_ARROW_ARGS,         345, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)")
 MSG_DEF(JSMSG_YIELD_IN_ARROW,         346, 0, JSEXN_SYNTAXERR, "arrow function may not contain yield")
 MSG_DEF(JSMSG_WRONG_VALUE,            347, 2, JSEXN_ERR, "expected {0} but found {1}")
 MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_BAD_TARGET, 348, 1, JSEXN_ERR, "target for index {0} is not an integer")
 MSG_DEF(JSMSG_SELFHOSTED_UNBOUND_NAME,349, 0, JSEXN_TYPEERR, "self-hosted code may not contain unbound name lookups")
+MSG_DEF(JSMSG_DEPRECATED_SOURCE_MAP,  350, 0, JSEXN_SYNTAXERR, "Using //@ to indicate source map URL pragmas is deprecated. Use //# instead")
--- a/js/src/jsanalyze.cpp
+++ b/js/src/jsanalyze.cpp
@@ -61,18 +61,16 @@ ScriptAnalysis::addJump(JSContext *cx, u
         }
         code->stackDepth = stackDepth;
     }
     JS_ASSERT(code->stackDepth == stackDepth);
 
     code->jumpTarget = true;
 
     if (offset < *currentOffset) {
-        /* Scripts containing loops are never inlined. */
-        isJaegerInlineable = false;
         hasLoops_ = true;
 
         if (code->analyzed) {
             /*
              * Backedge in a do-while loop, the body has been analyzed. Rewalk
              * the body to set inLoop bits.
              */
             for (unsigned i = offset; i <= *currentOffset; i++) {
@@ -148,23 +146,19 @@ ScriptAnalysis::analyzeBytecode(JSContex
      * If the script is in debug mode, JS_SetFrameReturnValue can be called at
      * any safe point.
      */
     if (cx->compartment->debugMode())
         usesReturnValue_ = true;
 
     bool heavyweight = script_->function() && script_->function()->isHeavyweight();
 
-    isJaegerCompileable = true;
-
-    isJaegerInlineable = isIonInlineable = true;
+    isIonInlineable = true;
     if (heavyweight || cx->compartment->debugMode())
-        isJaegerInlineable = isIonInlineable = false;
-    if (script_->argumentsHasVarBinding())
-        isJaegerInlineable = false;
+        isIonInlineable = false;
 
     modifiesArguments_ = false;
     if (heavyweight)
         modifiesArguments_ = true;
 
     canTrackVars = true;
 
     /*
@@ -243,17 +237,17 @@ ScriptAnalysis::analyzeBytecode(JSContex
         code->analyzed = true;
 
         if (forwardCatch)
             code->inTryBlock = true;
 
         if (script_->hasBreakpointsAt(pc)) {
             code->safePoint = true;
             canTrackVars = false;
-            isJaegerInlineable = isIonInlineable = false;
+            isIonInlineable = false;
         }
 
         unsigned stackDepth = code->stackDepth;
 
         if (!forwardJump)
             code->unconditional = true;
 
         unsigned nuses = GetUseCount(script_, offset);
@@ -268,70 +262,70 @@ ScriptAnalysis::analyzeBytecode(JSContex
           case JSOP_RETURN:
           case JSOP_STOP:
             numReturnSites_++;
             break;
 
           case JSOP_SETRVAL:
           case JSOP_POPV:
             usesReturnValue_ = true;
-            isJaegerInlineable = isIonInlineable = false;
+            isIonInlineable = false;
             break;
 
           case JSOP_NAME:
           case JSOP_CALLNAME:
           case JSOP_BINDNAME:
           case JSOP_SETNAME:
           case JSOP_DELNAME:
           case JSOP_GETALIASEDVAR:
           case JSOP_CALLALIASEDVAR:
           case JSOP_SETALIASEDVAR:
           case JSOP_LAMBDA:
             usesScopeChain_ = true;
-            isJaegerInlineable = isIonInlineable = false;
+            isIonInlineable = false;
             break;
 
           case JSOP_DEFFUN:
           case JSOP_DEFVAR:
           case JSOP_DEFCONST:
           case JSOP_SETCONST:
             usesScopeChain_ = true; // Requires access to VarObj via ScopeChain.
             canTrackVars = false;
-            isJaegerInlineable = isIonInlineable = false;
+            isIonInlineable = false;
             break;
 
           case JSOP_EVAL:
             canTrackVars = false;
-            isJaegerInlineable = isIonInlineable = false;
+            isIonInlineable = false;
             break;
 
           case JSOP_ENTERWITH:
-            isJaegerCompileable = canTrackVars = false;
-            isJaegerInlineable = isIonInlineable = false;
+            canTrackVars = false;
+            isIonInlineable = false;
             break;
 
           case JSOP_ENTERLET0:
           case JSOP_ENTERLET1:
           case JSOP_ENTERBLOCK:
           case JSOP_LEAVEBLOCK:
-            isJaegerInlineable = isIonInlineable = false;
+            isIonInlineable = false;
             break;
 
           case JSOP_THIS:
             usesThisValue_ = true;
             break;
 
           case JSOP_CALL:
           case JSOP_NEW:
             /* Only consider potentially inlineable calls here. */
             hasFunctionCalls_ = true;
             break;
 
           case JSOP_TABLESWITCH: {
-            isJaegerInlineable = isIonInlineable = false;
+            isIonInlineable = false;
             unsigned defaultOffset = offset + GET_JUMP_OFFSET(pc);
             jsbytecode *pc2 = pc + JUMP_OFFSET_LEN;
             int32_t low = GET_JUMP_OFFSET(pc2);
             pc2 += JUMP_OFFSET_LEN;
             int32_t high = GET_JUMP_OFFSET(pc2);
             pc2 += JUMP_OFFSET_LEN;
 
             if (!addJump(cx, defaultOffset, &nextOffset, &forwardJump, &forwardLoop, stackDepth))
@@ -352,17 +346,17 @@ ScriptAnalysis::analyzeBytecode(JSContex
 
           case JSOP_TRY: {
             /*
              * Everything between a try and corresponding catch or finally is conditional.
              * Note that there is no problem with code which is skipped by a thrown
              * exception but is not caught by a later handler in the same function:
              * no more code will execute, and it does not matter what is defined.
              */
-            isJaegerInlineable = isIonInlineable = false;
+            isIonInlineable = false;
             JSTryNote *tn = script_->trynotes()->vector;
             JSTryNote *tnlimit = tn + script_->trynotes()->length;
             for (; tn < tnlimit; tn++) {
                 unsigned startOffset = script_->mainOffset + tn->start;
                 if (startOffset == offset + 1) {
                     unsigned catchOffset = startOffset + tn->length;
 
                     /* This will overestimate try block code, for multiple catch/finally. */
@@ -404,41 +398,37 @@ ScriptAnalysis::analyzeBytecode(JSContex
                 localsAliasStack_ = true;
                 break;
             }
             break;
           }
 
           case JSOP_SETARG:
             modifiesArguments_ = true;
-            isJaegerInlineable = false;
             break;
 
           case JSOP_GETPROP:
           case JSOP_CALLPROP:
           case JSOP_LENGTH:
           case JSOP_GETELEM:
           case JSOP_CALLELEM:
             numPropertyReads_++;
             break;
 
-          /* Additional opcodes which can be compiled but which can't be inlined. */
-          case JSOP_ARGUMENTS:
-          case JSOP_FUNAPPLY:
-          case JSOP_CALLEE:
-            isJaegerInlineable = false;
-            break;
           case JSOP_THROW:
           case JSOP_EXCEPTION:
           case JSOP_DEBUGGER:
           case JSOP_FUNCALL:
-            isIonInlineable = isJaegerInlineable = false;
+            isIonInlineable = false;
             break;
 
           /* Additional opcodes which can be both compiled both normally and inline. */
+          case JSOP_ARGUMENTS:
+          case JSOP_FUNAPPLY:
+          case JSOP_CALLEE:
           case JSOP_NOP:
           case JSOP_UNDEFINED:
           case JSOP_GOTO:
           case JSOP_DEFAULT:
           case JSOP_IFEQ:
           case JSOP_IFNE:
           case JSOP_ITERNEXT:
           case JSOP_DUP:
@@ -525,18 +515,17 @@ ScriptAnalysis::analyzeBytecode(JSContex
           case JSOP_HOLE:
           case JSOP_LOOPHEAD:
           case JSOP_LOOPENTRY:
           case JSOP_NOTEARG:
           case JSOP_REST:
             break;
 
           default:
-            isJaegerCompileable = false;
-            isJaegerInlineable = isIonInlineable = false;
+            isIonInlineable = false;
             break;
         }
 
         bool jump = IsJumpOpcode(op);
 
         /* Check basic jump opcodes, which may or may not have a fallthrough. */
         if (jump) {
             /* Case instructions do not push the lvalue back when branching. */
--- a/js/src/jsanalyze.h
+++ b/js/src/jsanalyze.h
@@ -723,19 +723,17 @@ class ScriptAnalysis
     /* --------- Bytecode analysis --------- */
 
     bool usesReturnValue_:1;
     bool usesScopeChain_:1;
     bool usesThisValue_:1;
     bool hasFunctionCalls_:1;
     bool modifiesArguments_:1;
     bool localsAliasStack_:1;
-    bool isJaegerInlineable:1;
     bool isIonInlineable:1;
-    bool isJaegerCompileable:1;
     bool canTrackVars:1;
     bool hasLoops_:1;
 
     uint32_t numReturnSites_;
 
     /* --------- Lifetime analysis --------- */
 
     LifetimeVariable *lifetimes;
@@ -763,19 +761,16 @@ class ScriptAnalysis
     /* Analyze the effect of invoking 'new' on script. */
     void analyzeTypesNew(JSContext *cx);
 
     bool OOM() const { return outOfMemory; }
     bool failed() const { return hadFailure; }
     bool ionInlineable() const { return isIonInlineable; }
     bool ionInlineable(uint32_t argc) const { return isIonInlineable && argc == script_->function()->nargs; }
     void setIonUninlineable() { isIonInlineable = false; }
-    bool jaegerInlineable() const { return isJaegerInlineable; }
-    bool jaegerInlineable(uint32_t argc) const { return isJaegerInlineable && argc == script_->function()->nargs; }
-    bool jaegerCompileable() { return isJaegerCompileable; }
 
     /* Number of property read opcodes in the script. */
     uint32_t numPropertyReads() const { return numPropertyReads_; }
 
     /* Whether there are POPV/SETRVAL bytecodes which can write to the frame's rval. */
     bool usesReturnValue() const { return usesReturnValue_; }
 
     /* Whether there are NAME bytecodes which can access the frame's scope chain. */
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -62,36 +62,16 @@ fun_getProperty(JSContext *cx, HandleObj
     while (!obj->isFunction()) {
         if (!JSObject::getProto(cx, obj, &obj))
             return false;
         if (!obj)
             return true;
     }
     RootedFunction fun(cx, obj->toFunction());
 
-    /*
-     * Mark the function's script as uninlineable, to expand any of its
-     * frames on the stack before we go looking for them. This allows the
-     * below walk to only check each explicit frame rather than needing to
-     * check any calls that were inlined.
-     */
-    if (fun->isInterpreted()) {
-        if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
-            return false;
-        fun->nonLazyScript()->uninlineable = true;
-        MarkTypeObjectFlags(cx, fun, OBJECT_FLAG_UNINLINEABLE);
-
-        /* If we're a callsite clone, mark the original as unlineable also. */
-        if (fun->nonLazyScript()->isCallsiteClone) {
-            RootedFunction original(cx, fun->nonLazyScript()->originalFunction());
-            original->nonLazyScript()->uninlineable = true;
-            MarkTypeObjectFlags(cx, original, OBJECT_FLAG_UNINLINEABLE);
-        }
-    }
-
     /* Set to early to null in case of error */
     vp.setNull();
 
     /* Find fun's top-most activation record. */
     NonBuiltinScriptFrameIter iter(cx);
     for (; !iter.done(); ++iter) {
         if (!iter.isFunctionFrame() || iter.isEvalFrame())
             continue;
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -3792,18 +3792,16 @@ TypeObject::setFlags(JSContext *cx, Type
 {
     if ((this->flags & flags) == flags)
         return;
 
     AutoEnterAnalysis enter(cx);
 
     if (singleton) {
         /* Make sure flags are consistent with persistent object state. */
-        JS_ASSERT_IF(flags & OBJECT_FLAG_UNINLINEABLE,
-                     interpretedFunction->nonLazyScript()->uninlineable);
         JS_ASSERT_IF(flags & OBJECT_FLAG_ITERATED,
                      singleton->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON));
     }
 
     this->flags |= flags;
 
     InferSpew(ISpewOps, "%s: setFlags 0x%x", TypeObjectString(this), flags);
 
@@ -3974,18 +3972,16 @@ TypeObject::print()
         printf(" unknown");
     } else {
         if (!hasAnyFlags(OBJECT_FLAG_SPARSE_INDEXES))
             printf(" dense");
         if (!hasAnyFlags(OBJECT_FLAG_NON_PACKED))
             printf(" packed");
         if (!hasAnyFlags(OBJECT_FLAG_LENGTH_OVERFLOW))
             printf(" noLengthOverflow");
-        if (hasAnyFlags(OBJECT_FLAG_UNINLINEABLE))
-            printf(" uninlineable");
         if (hasAnyFlags(OBJECT_FLAG_EMULATES_UNDEFINED))
             printf(" emulatesUndefined");
         if (hasAnyFlags(OBJECT_FLAG_ITERATED))
             printf(" iterated");
         if (interpretedFunction)
             printf(" ifun");
     }
 
@@ -6077,21 +6073,18 @@ JSObject::makeLazyType(JSContext *cx, Ha
     }
 
     AutoEnterAnalysis enter(cx);
 
     /* Fill in the type according to the state of this object. */
 
     type->singleton = obj;
 
-    if (obj->isFunction() && obj->toFunction()->isInterpreted()) {
+    if (obj->isFunction() && obj->toFunction()->isInterpreted())
         type->interpretedFunction = obj->toFunction();
-        if (type->interpretedFunction->nonLazyScript()->uninlineable)
-            type->flags |= OBJECT_FLAG_UNINLINEABLE;
-    }
 
     if (obj->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON))
         type->flags |= OBJECT_FLAG_ITERATED;
 
     if (obj->getClass()->emulatesUndefined())
         type->flags |= OBJECT_FLAG_EMULATES_UNDEFINED;
 
     /*
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -378,18 +378,19 @@ enum {
     OBJECT_FLAG_NON_PACKED            = 0x00020000,
 
     /*
      * Whether any objects this represents may be arrays whose length does not
      * fit in an int32.
      */
     OBJECT_FLAG_LENGTH_OVERFLOW       = 0x00040000,
 
-    /* Whether any represented script is considered uninlineable in JM. */
-    OBJECT_FLAG_UNINLINEABLE          = 0x00080000,
+    /*
+     * UNUSED FLAG                    = 0x00080000,
+     */
 
     /* Whether any objects have been iterated over. */
     OBJECT_FLAG_ITERATED              = 0x00100000,
 
     /* For a global object, whether flags were set on the RegExpStatics. */
     OBJECT_FLAG_REGEXP_FLAGS_SET      = 0x00200000,
 
     /* Whether any objects emulate undefined; see EmulatesUndefined. */
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -532,17 +532,16 @@ class JSScript : public js::gc::Cell
                                                    undefined properties in this
                                                    script */
     bool            hasSingletons:1;  /* script has singleton objects */
     bool            treatAsRunOnce:1; /* script is a lambda to treat as running once. */
     bool            hasRunOnce:1;     /* if treatAsRunOnce, whether script has executed. */
     bool            hasBeenCloned:1;  /* script has been reused for a clone. */
     bool            isActiveEval:1;   /* script came from eval(), and is still active */
     bool            isCachedEval:1;   /* script came from eval(), and is in eval cache */
-    bool            uninlineable:1;   /* script is considered uninlineable by analysis */
 
     /* Set for functions defined at the top level within an 'eval' script. */
     bool directlyInsideEval:1;
 
     /* script is attempted to be cloned anew at each callsite. This is
        temporarily needed for ParallelArray selfhosted code until type
        information can be made context sensitive. See discussion in
        bug 826148. */
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1034,21 +1034,21 @@ Evaluate(JSContext *cx, unsigned argc, j
 
     AutoNewContext ancx;
     if (newContext) {
         if (!ancx.enter(cx))
             return false;
         cx = ancx.get();
     }
 
-    AutoSaveFrameChain asfc(cx);
-    if (saveFrameChain && !asfc.save())
-        return false;
-
     {
+        AutoSaveFrameChain asfc(cx);
+        if (saveFrameChain && !asfc.save())
+            return false;
+
         JSAutoCompartment ac(cx, global);
         uint32_t oldopts = JS_GetOptions(cx);
         uint32_t opts = oldopts & ~(JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL);
         if (compileAndGo)
             opts |= JSOPTION_COMPILE_N_GO;
         if (noScriptRval)
             opts |= JSOPTION_NO_SCRIPT_RVAL;
 
--- a/layout/base/Units.h
+++ b/layout/base/Units.h
@@ -6,77 +6,116 @@
 #ifndef MOZ_UNITS_H_
 #define MOZ_UNITS_H_
 
 #include "mozilla/gfx/Point.h"
 #include "nsDeviceContext.h"
 
 namespace mozilla {
 
-// The pixels that content authors use to specify sizes in.
+/*
+ * The pixels that content authors use to specify sizes in.
+ */
 struct CSSPixel {
-  static gfx::PointTyped<CSSPixel> FromAppUnits(const nsPoint &pt) {
-    return gfx::PointTyped<CSSPixel>(NSAppUnitsToFloatPixels(pt.x, float(nsDeviceContext::AppUnitsPerCSSPixel())),
-                                     NSAppUnitsToFloatPixels(pt.y, float(nsDeviceContext::AppUnitsPerCSSPixel())));
+  static gfx::IntPointTyped<CSSPixel> RoundToInt(const gfx::PointTyped<CSSPixel>& aPoint) {
+    return gfx::IntPointTyped<CSSPixel>(NS_lround(aPoint.x),
+                                        NS_lround(aPoint.y));
+  }
+
+  static gfx::PointTyped<CSSPixel> FromAppUnits(const nsPoint& aPoint) {
+    return gfx::PointTyped<CSSPixel>(NSAppUnitsToFloatPixels(aPoint.x, float(nsDeviceContext::AppUnitsPerCSSPixel())),
+                                     NSAppUnitsToFloatPixels(aPoint.y, float(nsDeviceContext::AppUnitsPerCSSPixel())));
   }
 
-  static nsPoint ToAppUnits(const gfx::PointTyped<CSSPixel> &pt) {
-    return nsPoint(NSFloatPixelsToAppUnits(pt.x, float(nsDeviceContext::AppUnitsPerCSSPixel())),
-                   NSFloatPixelsToAppUnits(pt.y, float(nsDeviceContext::AppUnitsPerCSSPixel())));
+  static nsPoint ToAppUnits(const gfx::PointTyped<CSSPixel>& aPoint) {
+    return nsPoint(NSFloatPixelsToAppUnits(aPoint.x, float(nsDeviceContext::AppUnitsPerCSSPixel())),
+                   NSFloatPixelsToAppUnits(aPoint.y, float(nsDeviceContext::AppUnitsPerCSSPixel())));
   }
 
-  static gfx::RectTyped<CSSPixel> FromAppUnits(const nsRect &rect) {
-    return gfx::RectTyped<CSSPixel>(NSAppUnitsToFloatPixels(rect.x, float(nsDeviceContext::AppUnitsPerCSSPixel())),
-                                    NSAppUnitsToFloatPixels(rect.y, float(nsDeviceContext::AppUnitsPerCSSPixel())),
-                                    NSAppUnitsToFloatPixels(rect.width, float(nsDeviceContext::AppUnitsPerCSSPixel())),
-                                    NSAppUnitsToFloatPixels(rect.height, float(nsDeviceContext::AppUnitsPerCSSPixel())));
+  static gfx::RectTyped<CSSPixel> FromAppUnits(const nsRect& aRect) {
+    return gfx::RectTyped<CSSPixel>(NSAppUnitsToFloatPixels(aRect.x, float(nsDeviceContext::AppUnitsPerCSSPixel())),
+                                    NSAppUnitsToFloatPixels(aRect.y, float(nsDeviceContext::AppUnitsPerCSSPixel())),
+                                    NSAppUnitsToFloatPixels(aRect.width, float(nsDeviceContext::AppUnitsPerCSSPixel())),
+                                    NSAppUnitsToFloatPixels(aRect.height, float(nsDeviceContext::AppUnitsPerCSSPixel())));
+  }
+
+  static nsRect ToAppUnits(const gfx::RectTyped<CSSPixel>& aRect) {
+    return nsRect(NSFloatPixelsToAppUnits(aRect.x, float(nsDeviceContext::AppUnitsPerCSSPixel())),
+                  NSFloatPixelsToAppUnits(aRect.y, float(nsDeviceContext::AppUnitsPerCSSPixel())),
+                  NSFloatPixelsToAppUnits(aRect.width, float(nsDeviceContext::AppUnitsPerCSSPixel())),
+                  NSFloatPixelsToAppUnits(aRect.height, float(nsDeviceContext::AppUnitsPerCSSPixel())));
   }
 };
 
 typedef gfx::PointTyped<CSSPixel> CSSPoint;
+typedef gfx::IntPointTyped<CSSPixel> CSSIntPoint;
+typedef gfx::SizeTyped<CSSPixel> CSSSize;
 typedef gfx::RectTyped<CSSPixel> CSSRect;
 typedef gfx::IntRectTyped<CSSPixel> CSSIntRect;
 
+/*
+ * The pixels that layout rasterizes and delivers to the graphics code.
+ * These are generally referred to as "device pixels" in layout code. Layer
+ * pixels are affected by:
+ * 1) the "display resolution" (see nsIPresShell::SetResolution)
+ * 2) the "full zoom" (see nsPresContext::SetFullZoom)
+ * 3) the "widget scale" (nsIWidget::GetDefaultScale)
+ */
 struct LayerPixel {
-  static gfx::IntPointTyped<LayerPixel> FromCSSPointRounded(const CSSPoint& pt, float resolutionX, float resolutionY) {
-    return gfx::IntPointTyped<LayerPixel>(NS_lround(pt.x * resolutionX),
-                                          NS_lround(pt.y * resolutionY));
+  static gfx::IntPointTyped<LayerPixel> FromCSSPointRounded(const CSSPoint& aPoint, float aResolutionX, float aResolutionY) {
+    return gfx::IntPointTyped<LayerPixel>(NS_lround(aPoint.x * aResolutionX),
+                                          NS_lround(aPoint.y * aResolutionY));
   }
 
-  static gfx::IntRectTyped<LayerPixel> FromCSSRectRounded(const CSSRect& rect, float resolutionX, float resolutionY) {
-    return gfx::IntRectTyped<LayerPixel>(NS_lround(rect.x * resolutionX),
-                                         NS_lround(rect.y * resolutionY),
-                                         NS_lround(rect.width * resolutionX),
-                                         NS_lround(rect.height * resolutionY));
+  static gfx::IntRectTyped<LayerPixel> RoundToInt(const gfx::RectTyped<LayerPixel>& aRect) {
+    return gfx::IntRectTyped<LayerPixel>(NS_lround(aRect.x),
+                                         NS_lround(aRect.y),
+                                         NS_lround(aRect.width),
+                                         NS_lround(aRect.height));
   }
 
-  static gfx::IntRectTyped<LayerPixel> FromCSSRectRoundOut(const CSSRect& rect, gfxFloat resolution) {
-    gfx::RectTyped<LayerPixel> scaled(rect.x, rect.y, rect.width, rect.height);
-    scaled.ScaleInverseRoundOut(resolution);
+  static gfx::RectTyped<LayerPixel> FromCSSRect(const CSSRect& aRect, float aResolutionX, float aResolutionY) {
+    return gfx::RectTyped<LayerPixel>(aRect.x * aResolutionX,
+                                      aRect.y * aResolutionY,
+                                      aRect.width * aResolutionX,
+                                      aRect.height * aResolutionY);
+  }
+
+  static gfx::IntRectTyped<LayerPixel> FromCSSRectRounded(const CSSRect& aRect, float aResolutionX, float aResolutionY) {
+    return RoundToInt(FromCSSRect(aRect, aResolutionX, aResolutionY));
+  }
+
+  static gfx::IntRectTyped<LayerPixel> FromCSSRectRoundOut(const CSSRect& aRect, float aResolutionX, float aResolutionY) {
+    gfx::RectTyped<LayerPixel> scaled(aRect.x, aRect.y, aRect.width, aRect.height);
+    scaled.ScaleInverseRoundOut(aResolutionX, aResolutionY);
     return gfx::IntRectTyped<LayerPixel>(scaled.x, scaled.y, scaled.width, scaled.height);
   }
 
-  static CSSIntRect ToCSSIntRectRoundIn(const gfx::IntRectTyped<LayerPixel>& rect, gfxFloat resolution) {
-    gfx::IntRectTyped<CSSPixel> ret(rect.x, rect.y, rect.width, rect.height);
-    ret.ScaleInverseRoundIn(resolution, resolution);
-    return ret;
-  }
-
-  static CSSIntRect ToCSSIntRectRoundIn(const gfx::IntRectTyped<LayerPixel>& rect, gfxSize resolution) {
-    gfx::IntRectTyped<CSSPixel> ret(rect.x, rect.y, rect.width, rect.height);
-    ret.ScaleInverseRoundIn(resolution.width, resolution.height);
+  static CSSIntRect ToCSSIntRectRoundIn(const gfx::IntRectTyped<LayerPixel>& aRect, float aResolutionX, float aResolutionY) {
+    gfx::IntRectTyped<CSSPixel> ret(aRect.x, aRect.y, aRect.width, aRect.height);
+    ret.ScaleInverseRoundIn(aResolutionX, aResolutionY);
     return ret;
   }
 };
 
+typedef gfx::PointTyped<LayerPixel> LayerPoint;
 typedef gfx::IntPointTyped<LayerPixel> LayerIntPoint;
 typedef gfx::IntSizeTyped<LayerPixel> LayerIntSize;
 typedef gfx::RectTyped<LayerPixel> LayerRect;
 typedef gfx::IntRectTyped<LayerPixel> LayerIntRect;
 
+/*
+ * The pixels that are displayed on the screen.
+ * On non-OMTC platforms this should be equivalent to LayerPixel units.
+ * On OMTC platforms these may diverge from LayerPixel units temporarily,
+ * while an asynchronous zoom is happening, but should eventually converge
+ * back to LayerPixel units. Some variables (such as those representing
+ * chrome UI element sizes) that are not subject to content zoom should
+ * generally be represented in ScreenPixel units.
+ */
 struct ScreenPixel {
 };
 
 typedef gfx::PointTyped<ScreenPixel> ScreenPoint;
 
 };
 
 #endif
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -630,37 +630,22 @@ static void RecordFrameMetrics(nsIFrame*
   nsPresContext* presContext = aForFrame->PresContext();
   int32_t auPerDevPixel = presContext->AppUnitsPerDevPixel();
 
   nsIntRect visible = aVisibleRect.ScaleToNearestPixels(
     aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
   aRoot->SetVisibleRegion(nsIntRegion(visible));
 
   FrameMetrics metrics;
-
-  metrics.mViewport = mozilla::gfx::Rect(
-    NSAppUnitsToDoublePixels(aViewport.x, auPerDevPixel),
-    NSAppUnitsToDoublePixels(aViewport.y, auPerDevPixel),
-    NSAppUnitsToDoublePixels(aViewport.width, auPerDevPixel),
-    NSAppUnitsToDoublePixels(aViewport.height, auPerDevPixel));
-
+  metrics.mViewport = CSSRect::FromAppUnits(aViewport);
   if (aDisplayPort) {
-    metrics.mDisplayPort = mozilla::gfx::Rect(
-      NSAppUnitsToDoublePixels(aDisplayPort->x, auPerDevPixel),
-      NSAppUnitsToDoublePixels(aDisplayPort->y, auPerDevPixel),
-      NSAppUnitsToDoublePixels(aDisplayPort->width, auPerDevPixel),
-      NSAppUnitsToDoublePixels(aDisplayPort->height, auPerDevPixel));
-
-      if (aCriticalDisplayPort) {
-        metrics.mCriticalDisplayPort = mozilla::gfx::Rect(
-          NSAppUnitsToDoublePixels(aCriticalDisplayPort->x, auPerDevPixel),
-          NSAppUnitsToDoublePixels(aCriticalDisplayPort->y, auPerDevPixel),
-          NSAppUnitsToDoublePixels(aCriticalDisplayPort->width, auPerDevPixel),
-          NSAppUnitsToDoublePixels(aCriticalDisplayPort->height, auPerDevPixel));
-      }
+    metrics.mDisplayPort = CSSRect::FromAppUnits(*aDisplayPort);
+    if (aCriticalDisplayPort) {
+      metrics.mCriticalDisplayPort = CSSRect::FromAppUnits(*aCriticalDisplayPort);
+    }
   }
 
   nsIScrollableFrame* scrollableFrame = nullptr;
   if (aScrollFrame)
     scrollableFrame = aScrollFrame->GetScrollTargetFrame();
 
   if (scrollableFrame) {
     nsRect contentBounds = scrollableFrame->GetScrollRange();
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -220,22 +220,19 @@ BuildListForLayer(Layer* aLayer,
     // As mentioned above, bounds calculation also depends on the scale
     // of this layer.
     gfx3DMatrix tmpTransform = aTransform;
     Scale(tmpTransform, GetXScale(applyTransform), GetYScale(applyTransform));
 
     // Calculate rect for this layer based on aTransform.
     nsRect bounds;
     {
+      bounds = CSSRect::ToAppUnits(metrics->mViewport);
       nscoord auPerDevPixel = aSubdocFrame->PresContext()->AppUnitsPerDevPixel();
-      gfx::Rect viewport = metrics->mViewport;
-      bounds = nsIntRect(viewport.x, viewport.y,
-                         viewport.width, viewport.height).ToAppUnits(auPerDevPixel);
       ApplyTransform(bounds, tmpTransform, auPerDevPixel);
-
     }
 
     aShadowTree.AppendToTop(
       new (aBuilder) nsDisplayRemoteShadow(aBuilder, aSubdocFrame, bounds, scrollId));
 
   } else {
     transform = aLayer->GetTransform() * aTransform;
   }
@@ -406,19 +403,22 @@ BuildViewMap(ViewMap& oldContentViews, V
       config.mScrollOffset = nsPoint(
         NSIntPixelsToAppUnits(metrics.mScrollOffset.x, auPerCSSPixel) * aXScale,
         NSIntPixelsToAppUnits(metrics.mScrollOffset.y, auPerCSSPixel) * aYScale);
       view = new nsContentView(aFrameLoader, scrollId, config);
       view->mParentScaleX = aAccConfigXScale;
       view->mParentScaleY = aAccConfigYScale;
     }
 
+    // I don't know what units mViewportSize is in, hence use ToUnknownRect
+    // here to mark the current frontier in type info propagation
+    gfx::Rect viewport = metrics.mViewport.ToUnknownRect();
     view->mViewportSize = nsSize(
-      NSIntPixelsToAppUnits(metrics.mViewport.width, auPerDevPixel) * aXScale,
-      NSIntPixelsToAppUnits(metrics.mViewport.height, auPerDevPixel) * aYScale);
+      NSIntPixelsToAppUnits(viewport.width, auPerDevPixel) * aXScale,
+      NSIntPixelsToAppUnits(viewport.height, auPerDevPixel) * aYScale);
     view->mContentSize = nsSize(
       NSIntPixelsToAppUnits(metrics.mContentRect.width, auPerDevPixel) * aXScale,
       NSIntPixelsToAppUnits(metrics.mContentRect.height, auPerDevPixel) * aYScale);
 
     newContentViews[scrollId] = view;
   }
 
   for (Layer* child = aLayer->GetFirstChild();
@@ -494,51 +494,51 @@ public:
     // We always need to post requests into the "UI thread" otherwise the
     // requests may get processed out of order.
     mUILoop->PostTask(
       FROM_HERE,
       NewRunnableMethod(this, &RemoteContentController::DoRequestContentRepaint,
                         aFrameMetrics));
   }
 
-  virtual void HandleDoubleTap(const nsIntPoint& aPoint) MOZ_OVERRIDE
+  virtual void HandleDoubleTap(const CSSIntPoint& aPoint) MOZ_OVERRIDE
   {
     if (MessageLoop::current() != mUILoop) {
       // We have to send this message from the "UI thread" (main
       // thread).
       mUILoop->PostTask(
         FROM_HERE,
         NewRunnableMethod(this, &RemoteContentController::HandleDoubleTap,
                           aPoint));
       return;
     }
     if (mRenderFrame) {
       TabParent* browser = static_cast<TabParent*>(mRenderFrame->Manager());
       browser->HandleDoubleTap(aPoint);
     }
   }
 
-  virtual void HandleSingleTap(const nsIntPoint& aPoint) MOZ_OVERRIDE
+  virtual void HandleSingleTap(const CSSIntPoint& aPoint) MOZ_OVERRIDE
   {
     if (MessageLoop::current() != mUILoop) {
       // We have to send this message from the "UI thread" (main
       // thread).
       mUILoop->PostTask(
         FROM_HERE,
         NewRunnableMethod(this, &RemoteContentController::HandleSingleTap,
                           aPoint));
       return;
     }
     if (mRenderFrame) {
       TabParent* browser = static_cast<TabParent*>(mRenderFrame->Manager());
       browser->HandleSingleTap(aPoint);
     }
   }
 
-  virtual void HandleLongTap(const nsIntPoint& aPoint) MOZ_OVERRIDE
+  virtual void HandleLongTap(const CSSIntPoint& aPoint) MOZ_OVERRIDE
   {
     if (MessageLoop::current() != mUILoop) {
       // We have to send this message from the "UI thread" (main
       // thread).
       mUILoop->PostTask(
         FROM_HERE,
         NewRunnableMethod(this, &RemoteContentController::HandleLongTap,
                           aPoint));
@@ -547,18 +547,18 @@ public:
     if (mRenderFrame) {
       TabParent* browser = static_cast<TabParent*>(mRenderFrame->Manager());
       browser->HandleLongTap(aPoint);
     }
   }
 
   void ClearRenderFrame() { mRenderFrame = nullptr; }
 
-  virtual void SendAsyncScrollDOMEvent(const gfx::Rect& aContentRect,
-                                       const gfx::Size& aContentSize) MOZ_OVERRIDE
+  virtual void SendAsyncScrollDOMEvent(const CSSRect& aContentRect,
+                                       const CSSSize& aContentSize) MOZ_OVERRIDE
   {
     if (MessageLoop::current() != mUILoop) {
       mUILoop->PostTask(
         FROM_HERE,
         NewRunnableMethod(this,
                           &RemoteContentController::SendAsyncScrollDOMEvent,
                           aContentRect, aContentSize));
       return;
--- a/layout/style/nsCSSScanner.cpp
+++ b/layout/style/nsCSSScanner.cpp
@@ -529,18 +529,24 @@ nsCSSScanner::SkipComment()
  * additional form of escape sequence allowed within string-like tokens.
  */
 bool
 nsCSSScanner::GatherEscape(nsString& aOutput, bool aInString)
 {
   MOZ_ASSERT(Peek() == '\\', "should not have been called");
   int32_t ch = Peek(1);
   if (ch < 0) {
-    // Backslash followed by EOF is not an escape.
-    return false;
+    // If we are in a string (or a url() containing a string), we want to drop
+    // the backslash on the floor.  Otherwise, we want to treat it as a U+FFFD
+    // character.
+    Advance();
+    if (!aInString) {
+      aOutput.Append(0xFFFD);
+    }
+    return true;
   }
   if (IsVertSpace(ch)) {
     if (aInString) {
       // In strings (and in url() containing a string), escaped
       // newlines are completely removed, to allow splitting over
       // multiple lines.
       Advance();
       AdvanceLine();
--- a/layout/style/test/Makefile.in
+++ b/layout/style/test/Makefile.in
@@ -128,16 +128,17 @@ MOCHITEST_FILES =	test_acid3_test46.html
 		test_keyframes_rules.html \
 		test_media_queries.html \
 		test_media_queries_dynamic.html \
 		test_media_queries_dynamic_xbl.html \
 		test_media_query_list.html \
 		test_moz_device_pixel_ratio.html \
 		test_namespace_rule.html \
 		test_of_type_selectors.xhtml \
+		test_parse_eof.html \
 		test_parse_ident.html \
 		test_parse_rule.html \
 		test_parse_url.html \
 		test_parser_diagnostics_unprintables.html \
 		test_pixel_lengths.html \
 		test_pointer-events.html \
 		test_property_database.html \
 		test_priority_preservation.html \
new file mode 100644
--- /dev/null
+++ b/layout/style/test/test_parse_eof.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset=utf-8>
+  <title>Test parsing behaviour of backslash just before EOF</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
+  <meta name="flags" content="">
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+
+<style>#a::before { content: "ab\</style>
+<style>#b { background-image: url("ab\</style>
+<style>#c { background-image: url(ab\</style>
+<style>#d { counter-reset: ab\</style>
+
+<style>
+#a-ref::before { content: "ab"; }
+#b-ref { background-image: url("ab"); }
+#c-ref { background-image: url(ab�); }
+#d-ref { counter-reset: ab�; }
+</style>
+
+<div style="display: none">
+  <div id="a"></div>
+  <div id="b"></div>
+  <div id="c"></div>
+  <div id="d"></div>
+
+  <div id="a-ref"></div>
+  <div id="b-ref"></div>
+  <div id="c-ref"></div>
+  <div id="d-ref"></div>
+</div>
+
+<script>
+var a = document.getElementById("a");
+var b = document.getElementById("b");
+var c = document.getElementById("c");
+var d = document.getElementById("d");
+var a_ref = document.getElementById("a-ref");
+var b_ref = document.getElementById("b-ref");
+var c_ref = document.getElementById("c-ref");
+var d_ref = document.getElementById("d-ref");
+
+test(function() {
+  assert_equals(window.getComputedStyle(a, ":before").content,
+                window.getComputedStyle(a_ref, ":before").content);
+}, "test backslash before EOF inside a string");
+
+test(function() {
+  assert_equals(window.getComputedStyle(b, "").backgroundImage,
+                window.getComputedStyle(b_ref, "").backgroundImage);
+}, "test backslash before EOF inside a url(\"\")");
+
+test(function() {
+  assert_equals(window.getComputedStyle(c, "").backgroundImage,
+                window.getComputedStyle(c_ref, "").backgroundImage);
+}, "test backslash before EOF inside a url()");
+
+test(function() {
+  assert_equals(window.getComputedStyle(d, "").counterReset,
+                window.getComputedStyle(d_ref, "").counterReset);
+}, "test backslash before EOF outside a string");
+</script>
+
+</body>
+</html>
--- a/layout/style/test/test_selectors.html
+++ b/layout/style/test/test_selectors.html
@@ -241,16 +241,28 @@ function run() {
         } catch(ex) {
           is(ex.name, "SyntaxError",
              "selector '" + selector + "' plus EOF is parse error");
           is(ex.code, DOMException.SYNTAX_ERR,
              "selector '" + selector + "' plus EOF is parse error");
         }
     }
 
+    function test_parseable_via_api(selector)
+    {
+        var threw = false;
+        try {
+          // Test that a selector is parseable when followed by EOF.
+          ifdoc.body.mozMatchesSelector(selector);
+        } catch(ex) {
+          threw = true;
+        }
+        ok(!threw, "selector '" + selector + "' was parsed");
+    }
+
     function test_balanced_unparseable(selector)
     {
         var zi1 = ++gCounter;
         var zi2 = ++gCounter;
         ifdoc.body.innerHTML = "<p></p><div></div>";
         style_text.data = "p, " + selector + "{ z-index: " + zi1 + " }" +
                           "div { z-index: " + zi2 + " }";
         var should_not_match = ifdoc.getElementsByTagName("p")[0];
@@ -1154,18 +1166,21 @@ function run() {
     test_balanced_unparseable("# ");
     test_balanced_unparseable("#, p");
     test_balanced_unparseable("# , p");
     test_balanced_unparseable("p #");
     test_balanced_unparseable("p # ");
     test_balanced_unparseable("p #, p");
     test_balanced_unparseable("p # , p");
 
-    // Test that a backslash alone is not treated as an escape.
-    test_unparseable_via_api("#\\");
+    // Test that a backslash alone at EOF outside of a string is treated
+    // as U+FFFD.
+    test_parseable_via_api("#a\\");
+    test_parseable_via_api("#\\");
+    test_parseable_via_api("\\");
 
     // Test that newline escapes are only supported in strings.
     test_balanced_unparseable("di\\\nv");
     test_balanced_unparseable("div \\\n p");
     test_balanced_unparseable("div\\\n p");
     test_balanced_unparseable("div \\\np");
     test_balanced_unparseable("div\\\np");
 
--- a/mobile/android/base/AwesomeBar.java
+++ b/mobile/android/base/AwesomeBar.java
@@ -705,38 +705,45 @@ public class AwesomeBar extends GeckoAct
                 // Add the TextWatcher Listeners
                 locationText.addTextChangedListener(locationTextWatcher);
                 keywordText.addTextChangedListener(keywordTextWatcher);
 
                 dialog.show();
                 break;
             }
             case R.id.remove_bookmark: {
-                (new UiAsyncTask<Void, Void, Void>(ThreadUtils.getBackgroundHandler()) {
+                (new UiAsyncTask<Void, Void, Integer>(ThreadUtils.getBackgroundHandler()) {
                     private boolean mInReadingList;
 
                     @Override
                     public void onPreExecute() {
                         mInReadingList = mAwesomeTabs.isInReadingList();
                     }
 
                     @Override
-                    public Void doInBackground(Void... params) {
+                    public Integer doInBackground(Void... params) {
                         BrowserDB.removeBookmark(getContentResolver(), id);
-                        return null;
+                        Integer count = mInReadingList ?
+                            BrowserDB.getReadingListCount(getContentResolver()) : 0;
+
+                        return count;
                     }
 
                     @Override
-                    public void onPostExecute(Void result) {
+                    public void onPostExecute(Integer aCount) {
                         int messageId = R.string.bookmark_removed;
                         if (mInReadingList) {
                             messageId = R.string.reading_list_removed;
 
                             GeckoEvent e = GeckoEvent.createBroadcastEvent("Reader:Remove", url);
                             GeckoAppShell.sendEventToGecko(e);
+
+                            // Delete from Awesomebar context menu can alter reading list bookmark count
+                            e = GeckoEvent.createBroadcastEvent("Reader:ListCountUpdated", Integer.toString(aCount));
+                            GeckoAppShell.sendEventToGecko(e);
                         }
 
                         Toast.makeText(AwesomeBar.this, messageId, Toast.LENGTH_SHORT).show();
                     }
                 }).execute();
                 break;
             }
             case R.id.remove_history: {
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -309,42 +309,58 @@ abstract public class BrowserApp extends
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         if (onKey(null, keyCode, event)) {
             return true;
         }
 
         return super.onKeyDown(keyCode, event);
     }
 
+    void handleReaderListCountRequest() {
+        ThreadUtils.postToBackgroundThread(new Runnable() {
+            @Override
+            public void run() {
+                final int count = BrowserDB.getReadingListCount(getContentResolver());
+                GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Reader:ListCountReturn", Integer.toString(count)));
+            }
+        });
+    }
+
     void handleReaderAdded(int result, final String title, final String url) {
         if (result != READER_ADD_SUCCESS) {
             if (result == READER_ADD_FAILED) {
                 showToast(R.string.reading_list_failed, Toast.LENGTH_SHORT);
             } else if (result == READER_ADD_DUPLICATE) {
                 showToast(R.string.reading_list_duplicate, Toast.LENGTH_SHORT);
             }
 
             return;
         }
 
         ThreadUtils.postToBackgroundThread(new Runnable() {
             @Override
             public void run() {
                 BrowserDB.addReadingListItem(getContentResolver(), title, url);
                 showToast(R.string.reading_list_added, Toast.LENGTH_SHORT);
+
+                final int count = BrowserDB.getReadingListCount(getContentResolver());
+                GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Reader:ListCountUpdated", Integer.toString(count)));
             }
         });
     }
 
     void handleReaderRemoved(final String url) {
         ThreadUtils.postToBackgroundThread(new Runnable() {
             @Override
             public void run() {
                 BrowserDB.removeReadingListItemWithURL(getContentResolver(), url);
                 showToast(R.string.reading_list_removed, Toast.LENGTH_SHORT);
+
+                final int count = BrowserDB.getReadingListCount(getContentResolver());
+                GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Reader:ListCountUpdated", Integer.toString(count)));
             }
         });
     }
 
     @Override
     void onStatePurged() {
         ThreadUtils.postToUiThread(new Runnable() {
             @Override
@@ -998,16 +1014,18 @@ abstract public class BrowserApp extends
                     DataReportingNotification.checkAndNotifyPolicy(GeckoAppShell.getContext());
                 }
 
             } else if (event.equals("Telemetry:Gather")) {
                 Telemetry.HistogramAdd("PLACES_PAGES_COUNT", BrowserDB.getCount(getContentResolver(), "history"));
                 Telemetry.HistogramAdd("PLACES_BOOKMARKS_COUNT", BrowserDB.getCount(getContentResolver(), "bookmarks"));
                 Telemetry.HistogramAdd("FENNEC_FAVICONS_COUNT", BrowserDB.getCount(getContentResolver(), "favicons"));
                 Telemetry.HistogramAdd("FENNEC_THUMBNAILS_COUNT", BrowserDB.getCount(getContentResolver(), "thumbnails"));
+            } else if (event.equals("Reader:ListCountRequest")) {
+                handleReaderListCountRequest();
             } else if (event.equals("Reader:Added")) {
                 final int result = message.getInt("result");
                 final String title = message.getString("title");
                 final String url = message.getString("url");
                 handleReaderAdded(result, title, url);
             } else if (event.equals("Reader:Removed")) {
                 final String url = message.getString("url");
                 handleReaderRemoved(url);
--- a/mobile/android/base/BrowserToolbar.java
+++ b/mobile/android/base/BrowserToolbar.java
@@ -467,16 +467,18 @@ public class BrowserToolbar implements T
                 if (Tabs.getInstance().isSelectedTab(tab)) {
                     updateBackButton(tab.canDoBack());
                     updateForwardButton(tab.canDoForward());
                     setProgressVisibility(false);
                     // Reset the title in case we haven't navigated to a new page yet.
                     updateTitle();
                 }
                 break;
+            case RESTORED:
+                // TabCount fixup after OOM
             case SELECTED:
                 updateTabCount(Tabs.getInstance().getDisplayCount());
                 mSwitchingTabs = true;
                 // fall through
             case LOCATION_CHANGE:
             case LOAD_ERROR:
                 if (Tabs.getInstance().isSelectedTab(tab)) {
                     refresh();
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -53,16 +53,17 @@ import android.location.LocationListener
 import android.net.wifi.ScanResult;
 import android.net.Uri;
 import android.net.wifi.WifiManager;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.PowerManager;
 import android.os.StrictMode;
+import android.provider.ContactsContract;
 
 import android.telephony.CellLocation;
 import android.telephony.NeighboringCellInfo;
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyManager;
 import android.telephony.PhoneStateListener;
 import android.telephony.SignalStrength;
 import android.telephony.gsm.GsmCellLocation;
@@ -667,16 +668,29 @@ abstract public class GeckoApp
                 startService(new Intent(UpdateServiceHelper.ACTION_APPLY_UPDATE, null, this, UpdateService.class));
             } else if (event.equals("PrivateBrowsing:Data")) {
                 // null strings return "null" (http://code.google.com/p/android/issues/detail?id=13830)
                 if (message.isNull("session")) {
                     mPrivateBrowsingSession = null;
                 } else {
                     mPrivateBrowsingSession = message.getString("session");
                 }
+            } else if (event.equals("Contact:Add")) {                
+                if (!message.isNull("email")) {
+                    Uri contactUri = Uri.parse(message.getString("email"));       
+                    Intent i = new Intent(ContactsContract.Intents.SHOW_OR_CREATE_CONTACT, contactUri);
+                    startActivity(i);
+                } else if (!message.isNull("phone")) {
+                    Uri contactUri = Uri.parse(message.getString("phone"));       
+                    Intent i = new Intent(ContactsContract.Intents.SHOW_OR_CREATE_CONTACT, contactUri);
+                    startActivity(i);
+                } else {
+                    // something went wrong.
+                    Log.e(LOGTAG, "Received Contact:Add message with no email nor phone number");
+                }                
             }
         } catch (Exception e) {
             Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
         }
     }
 
     public String getResponse(JSONObject origMessage) {
         String res = mCurrentResponse;
@@ -1416,16 +1430,17 @@ abstract public class GeckoApp
             }, 1000 * 5 /* 5 seconds */);
         }
 
         //app state callbacks
         mAppStateListeners = new LinkedList<GeckoAppShell.AppStateListener>();
 
         //register for events
         registerEventListener("log");
+        registerEventListener("Reader:ListCountRequest");
         registerEventListener("Reader:Added");
         registerEventListener("Reader:Removed");
         registerEventListener("Reader:Share");
         registerEventListener("Reader:FaviconRequest");
         registerEventListener("Reader:GoToReadingList");
         registerEventListener("onCameraCapture");
         registerEventListener("Menu:Add");
         registerEventListener("Menu:Remove");
@@ -1452,16 +1467,17 @@ abstract public class GeckoApp
         registerEventListener("Share:Text");
         registerEventListener("Share:Image");
         registerEventListener("Wallpaper:Set");
         registerEventListener("Sanitize:ClearHistory");
         registerEventListener("Update:Check");
         registerEventListener("Update:Download");
         registerEventListener("Update:Install");
         registerEventListener("PrivateBrowsing:Data");
+        registerEventListener("Contact:Add");
 
         if (SmsManager.getInstance() != null) {
           SmsManager.getInstance().start();
         }
 
         mPromptService = new PromptService(this);
 
         mTextSelection = new TextSelection((TextSelectionHandle) findViewById(R.id.start_handle),
@@ -1897,16 +1913,17 @@ abstract public class GeckoApp
 
         super.onRestart();
     }
 
     @Override
     public void onDestroy()
     {
         unregisterEventListener("log");
+        unregisterEventListener("Reader:ListCountRequest");
         unregisterEventListener("Reader:Added");
         unregisterEventListener("Reader:Removed");
         unregisterEventListener("Reader:Share");
         unregisterEventListener("Reader:FaviconRequest");
         unregisterEventListener("Reader:GoToReadingList");
         unregisterEventListener("onCameraCapture");
         unregisterEventListener("Menu:Add");
         unregisterEventListener("Menu:Remove");
@@ -1933,16 +1950,17 @@ abstract public class GeckoApp
         unregisterEventListener("Share:Text");
         unregisterEventListener("Share:Image");
         unregisterEventListener("Wallpaper:Set");
         unregisterEventListener("Sanitize:ClearHistory");
         unregisterEventListener("Update:Check");
         unregisterEventListener("Update:Download");
         unregisterEventListener("Update:Install");
         unregisterEventListener("PrivateBrowsing:Data");
+        unregisterEventListener("Contact:Add");
 
         deleteTempFiles();
 
         if (mLayerView != null)
             mLayerView.destroy();
         if (mDoorHangerPopup != null)
             mDoorHangerPopup.destroy();
         if (mFormAssistPopup != null)
--- a/mobile/android/base/GeckoEditable.java
+++ b/mobile/android/base/GeckoEditable.java
@@ -136,40 +136,43 @@ final class GeckoEditable
         Handler mHandler;
 
         Action(int type) {
             mType = type;
         }
 
         static Action newReplaceText(CharSequence text, int start, int end) {
             if (start < 0 || start > end) {
-                throw new IllegalArgumentException("invalid replace text offsets");
+                throw new IllegalArgumentException(
+                    "invalid replace text offsets: " + start + " to " + end);
             }
             final Action action = new Action(TYPE_REPLACE_TEXT);
             action.mSequence = text;
             action.mStart = start;
             action.mEnd = end;
             return action;
         }
 
         static Action newSetSelection(int start, int end) {
             // start == -1 when the start offset should remain the same
             // end == -1 when the end offset should remain the same
             if (start < -1 || end < -1) {
-                throw new IllegalArgumentException("invalid selection offsets");
+                throw new IllegalArgumentException(
+                    "invalid selection offsets: " + start + " to " + end);
             }
             final Action action = new Action(TYPE_SET_SELECTION);
             action.mStart = start;
             action.mEnd = end;
             return action;
         }
 
         static Action newSetSpan(Object object, int start, int end, int flags) {
             if (start < 0 || start > end) {
-                throw new IllegalArgumentException("invalid span offsets");
+                throw new IllegalArgumentException(
+                    "invalid span offsets: " + start + " to " + end);
             }
             final Action action = new Action(TYPE_SET_SPAN);
             action.mSpanObject = object;
             action.mStart = start;
             action.mEnd = end;
             action.mSpanFlags = flags;
             return action;
         }
@@ -788,17 +791,18 @@ final class GeckoEditable
     @Override
     public void onSelectionChange(final int start, final int end) {
         if (DEBUG) {
             // GeckoEditableListener methods should all be called from the Gecko thread
             ThreadUtils.assertOnGeckoThread();
             Log.d(LOGTAG, "onSelectionChange(" + start + ", " + end + ")");
         }
         if (start < 0 || start > mText.length() || end < 0 || end > mText.length()) {
-            throw new IllegalArgumentException("invalid selection notification range");
+            throw new IllegalArgumentException("invalid selection notification range: " +
+                start + " to " + end + ", length: " + mText.length());
         }
         final int seqnoWhenPosted = ++mGeckoUpdateSeqno;
 
         /* An event (keypress, etc.) has potentially changed the selection,
            synchronize the selection here. There is not a race with the IC thread
            because the IC thread should be blocked on the event action */
         if (!mActionQueue.isEmpty() &&
             mActionQueue.peek().mType == Action.TYPE_EVENT) {
@@ -839,24 +843,26 @@ final class GeckoEditable
                       final int unboundedOldEnd, final int unboundedNewEnd) {
         if (DEBUG) {
             // GeckoEditableListener methods should all be called from the Gecko thread
             ThreadUtils.assertOnGeckoThread();
             Log.d(LOGTAG, "onTextChange(\"" + text + "\", " + start + ", " +
                           unboundedOldEnd + ", " + unboundedNewEnd + ")");
         }
         if (start < 0 || start > unboundedOldEnd) {
-            throw new IllegalArgumentException("invalid text notification range");
+            throw new IllegalArgumentException("invalid text notification range: " +
+                start + " to " + unboundedOldEnd);
         }
         /* For the "end" parameters, Gecko can pass in a large
            number to denote "end of the text". Fix that here */
         final int oldEnd = unboundedOldEnd > mText.length() ? mText.length() : unboundedOldEnd;
         // new end should always match text
         if (start != 0 && unboundedNewEnd != (start + text.length())) {
-            throw new IllegalArgumentException("newEnd does not match text");
+            throw new IllegalArgumentException("newEnd does not match text: " +
+                unboundedNewEnd + " vs " + (start + text.length()));
         }
         final int newEnd = start + text.length();
 
         /* Text changes affect the selection as well, and we may not receive another selection
            update as a result of selection notification masking on the Gecko side; therefore,
            in order to prevent previous stale selection notifications from occurring, we need
            to increment the seqno here as well */
         ++mGeckoUpdateSeqno;
@@ -1082,17 +1088,18 @@ final class GeckoEditable
     }
 
     @Override
     public Editable replace(int st, int en,
             CharSequence source, int start, int end) {
 
         CharSequence text = source;
         if (start < 0 || start > end || end > text.length()) {
-            throw new IllegalArgumentException("invalid replace offsets");
+            throw new IllegalArgumentException("invalid replace offsets: " +
+                start + " to " + end + ", length: " + text.length());
         }
         if (start != 0 || end != text.length()) {
             text = text.subSequence(start, end);
         }
         if (mFilters != null) {
             // Filter text before sending the request to Gecko
             for (int i = 0; i < mFilters.length; ++i) {
                 final CharSequence cs = mFilters[i].filter(
--- a/mobile/android/base/GeckoInputConnection.java
+++ b/mobile/android/base/GeckoInputConnection.java
@@ -393,19 +393,16 @@ class GeckoInputConnection
 
     private void resetInputConnection() {
         if (mBatchEditCount != 0) {
             Log.w(LOGTAG, "resetting with mBatchEditCount = " + mBatchEditCount);
             mBatchEditCount = 0;
         }
         mBatchSelectionChanged = false;
         mBatchTextChanged = false;
-        mUpdateRequest = null;
-
-        mCurrentInputMethod = "";
 
         // Do not reset mIMEState here; see comments in notifyIMEContext
     }
 
     @Override
     public void onTextChange(String text, int start, int oldEnd, int newEnd) {
 
         if (mUpdateRequest == null) {
@@ -899,34 +896,37 @@ class GeckoInputConnection
         // is 11 or greater, for datetime/month/week as well.
         if (typeHint != null &&
             (typeHint.equalsIgnoreCase("date") ||
              typeHint.equalsIgnoreCase("time") ||
              (Build.VERSION.SDK_INT >= 11 && (typeHint.equalsIgnoreCase("datetime") ||
                                               typeHint.equalsIgnoreCase("month") ||
                                               typeHint.equalsIgnoreCase("week") ||
                                               typeHint.equalsIgnoreCase("datetime-local"))))) {
-            mIMEState = IME_STATE_DISABLED;
-            return;
+            state = IME_STATE_DISABLED;
         }
 
         // mIMEState and the mIME*Hint fields should only be changed by notifyIMEContext,
         // and not reset anywhere else. Usually, notifyIMEContext is called right after a
         // focus or blur, so resetting mIMEState during the focus or blur seems harmless.
         // However, this behavior is not guaranteed. Gecko may call notifyIMEContext
         // independent of focus change; that is, a focus change may not be accompanied by
         // a notifyIMEContext call. So if we reset mIMEState inside focus, there may not
         // be another notifyIMEContext call to set mIMEState to a proper value (bug 829318)
         /* When IME is 'disabled', IME processing is disabled.
            In addition, the IME UI is hidden */
         mIMEState = state;
         mIMETypeHint = (typeHint == null) ? "" : typeHint;
         mIMEModeHint = (modeHint == null) ? "" : modeHint;
         mIMEActionHint = (actionHint == null) ? "" : actionHint;
 
+        // These fields are reset here and will be updated when restartInput is called below
+        mUpdateRequest = null;
+        mCurrentInputMethod = "";
+
         View v = getView();
         if (v == null || !v.hasFocus()) {
             // When using Find In Page, we can still receive notifyIMEContext calls due to the
             // selection changing when highlighting. However in this case we don't want to reset/
             // show/hide the keyboard because the find box has the focus and is taking input from
             // the keyboard.
             return;
         }
--- a/mobile/android/base/db/BrowserDB.java
+++ b/mobile/android/base/db/BrowserDB.java
@@ -60,16 +60,18 @@ public class BrowserDB {
         public void removeHistoryEntry(ContentResolver cr, String url);
 
         public void clearHistory(ContentResolver cr);
 
         public Cursor getBookmarksInFolder(ContentResolver cr, long folderId);
 
         public boolean isVisited(ContentResolver cr, String uri);
 
+        public int getReadingListCount(ContentResolver cr);
+
         public boolean isBookmark(ContentResolver cr, String uri);
 
         public boolean isReadingListItem(ContentResolver cr, String uri);
 
         public String getUrlForKeyword(ContentResolver cr, String keyword);
 
         public void addBookmark(ContentResolver cr, String title, String uri);
 
@@ -188,16 +190,20 @@ public class BrowserDB {
     public static String getUrlForKeyword(ContentResolver cr, String keyword) {
         return sDb.getUrlForKeyword(cr, keyword);
     }
 
     public static boolean isVisited(ContentResolver cr, String uri) {
         return sDb.isVisited(cr, uri);
     }
 
+    public static int getReadingListCount(ContentResolver cr) {
+        return sDb.getReadingListCount(cr);
+    }
+
     public static boolean isBookmark(ContentResolver cr, String uri) {
         return sDb.isBookmark(cr, uri);
     }
 
     public static boolean isReadingListItem(ContentResolver cr, String uri) {
         return sDb.isReadingListItem(cr, uri);
     }
 
--- a/mobile/android/base/db/LocalBrowserDB.java
+++ b/mobile/android/base/db/LocalBrowserDB.java
@@ -468,16 +468,36 @@ public class LocalBrowserDB implements B
         }
 
         // Cache result for future queries
         mReadingListItemsExist = (count > 0);
         return mReadingListItemsExist;
     }
 
     @Override
+    public int getReadingListCount(ContentResolver cr) {
+        // This method is about the Reading List, not normal bookmarks
+        Cursor c = null;
+        int count = 0;
+
+        try {
+            c = cr.query(mBookmarksUriWithProfile,
+                         new String[] { Bookmarks._ID },
+                         Bookmarks.PARENT + " = ?",
+                         new String[] { String.valueOf(Bookmarks.FIXED_READING_LIST_ID) },
+                         null);
+            count = c.getCount();
+        } finally {
+            c.close();
+        }
+
+        return count;
+    }
+
+    @Override
     public boolean isBookmark(ContentResolver cr, String uri) {
         // This method is about normal bookmarks, not the Reading List
         int count = 0;
         try {
             Cursor c = cr.query(bookmarksUriWithLimit(1),
                                 new String[] { Bookmarks._ID },
                                 Bookmarks.URL + " = ? AND " +
                                 Bookmarks.PARENT + " != ? AND " +
--- a/mobile/android/chrome/content/aboutReader.js
+++ b/mobile/android/chrome/content/aboutReader.js
@@ -26,16 +26,18 @@ let AboutReader = function(doc, win) {
   dump("Init()");
 
   this._docRef = Cu.getWeakReference(doc);
   this._winRef = Cu.getWeakReference(win);
 
   Services.obs.addObserver(this, "Reader:FaviconReturn", false);
   Services.obs.addObserver(this, "Reader:Add", false);
   Services.obs.addObserver(this, "Reader:Remove", false);
+  Services.obs.addObserver(this, "Reader:ListCountReturn", false);
+  Services.obs.addObserver(this, "Reader:ListCountUpdated", false);
 
   this._article = null;
 
   dump("Feching toolbar, header and content notes from about:reader");
   this._headerElementRef = Cu.getWeakReference(doc.getElementById("reader-header"));
   this._domainElementRef = Cu.getWeakReference(doc.getElementById("reader-domain"));
   this._titleElementRef = Cu.getWeakReference(doc.getElementById("reader-title"));
   this._creditsElementRef = Cu.getWeakReference(doc.getElementById("reader-credits"));
@@ -115,16 +117,21 @@ let AboutReader = function(doc, win) {
   this._setFontSize(fontSize);
 
   dump("Decoding query arguments");
   let queryArgs = this._decodeQueryString(win.location.href);
 
   this._isReadingListItem = (queryArgs.readingList == "1");
   this._updateToggleButton();
 
+  // Track status of reader toolbar list button
+  this._readingListCount = 0;
+  this._updateListButton();
+  this._requestReadingListCount();
+
   let url = queryArgs.url;
   let tabId = queryArgs.tabId;
   if (tabId) {
     dump("Loading from tab with ID: " + tabId + ", URL: " + url);
     this._loadFromTab(tabId, url);
   } else {
     dump("Fetching page with URL: " + url);
     this._loadFromURL(url);
@@ -197,16 +204,26 @@ AboutReader.prototype = {
         if (aData == this._article.url) {
           if (this._isReadingListItem) {
             this._isReadingListItem = false;
             this._updateToggleButton();
           }
         }
         break;
       }
+
+      case "Reader:ListCountReturn":
+      case "Reader:ListCountUpdated":  {
+        let count = parseInt(aData);
+        if (this._readingListCount != count) {
+          this._readingListCount = count;
+          this._updateListButton();
+        }
+        break;
+      }
     }
   },
 
   handleEvent: function Reader_handleEvent(aEvent) {
     if (!aEvent.isTrusted)
       return;
 
     switch (aEvent.type) {
@@ -233,30 +250,46 @@ AboutReader.prototype = {
 
       case "devicelight":
         this._handleDeviceLight(aEvent.value);
         break;
 
       case "unload":
         Services.obs.removeObserver(this, "Reader:Add");
         Services.obs.removeObserver(this, "Reader:Remove");
+        Services.obs.removeObserver(this, "Reader:ListCountReturn");
+        Services.obs.removeObserver(this, "Reader:ListCountUpdated");
         break;
     }
   },
 
   _updateToggleButton: function Reader_updateToggleButton() {
     let classes = this._doc.getElementById("toggle-button").classList;
 
     if (this._isReadingListItem) {
       classes.add("on");
     } else {
       classes.remove("on");
     }
   },
 
+  _updateListButton: function Reader_updateListButton() {
+    let classes = this._doc.getElementById("list-button").classList;
+
+    if (this._readingListCount > 0) {
+      classes.add("on");
+    } else {
+      classes.remove("on");
+    }
+  },
+
+  _requestReadingListCount: function Reader_requestReadingListCount() {
+    gChromeWin.sendMessageToJava({ type: "Reader:ListCountRequest" });
+  },
+
   _onReaderToggle: function Reader_onToggle() {
     if (!this._article)
       return;
 
     this._isReadingListItem = !this._isReadingListItem;
     this._updateToggleButton();
 
     if (this._isReadingListItem) {
@@ -286,17 +319,17 @@ AboutReader.prototype = {
           type: "Reader:Removed",
           url: this._article.url
         });
       }.bind(this));
     }
   },
 
   _onList: function Reader_onList() {
-    if (!this._article)
+    if (!this._article || this._readingListCount == 0)
       return;
 
     gChromeWin.sendMessageToJava({ type: "Reader:GoToReadingList" });
   },
 
   _onShare: function Reader_onShare() {
     if (!this._article)
       return;
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -464,16 +464,36 @@ var BrowserApp = {
       NativeWindow.contextmenus.phoneNumberLinkContext,
       function(aTarget) {
         let url = NativeWindow.contextmenus._getLinkURL(aTarget);
         let phoneNumber = NativeWindow.contextmenus._stripScheme(url);
         let title = aTarget.textContent || aTarget.title;
         NativeWindow.contextmenus._shareStringWithDefault(phoneNumber, title);
       });
 
+    NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.addToContacts"),
+      NativeWindow.contextmenus.emailLinkContext,
+      function(aTarget) {
+        let url = NativeWindow.contextmenus._getLinkURL(aTarget);
+        sendMessageToJava({
+          type: "Contact:Add",
+          email: url
+        });
+      });
+
+    NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.addToContacts"),
+      NativeWindow.contextmenus.phoneNumberLinkContext,
+      function(aTarget) {
+        let url = NativeWindow.contextmenus._getLinkURL(aTarget);
+        sendMessageToJava({
+          type: "Contact:Add",
+          phone: url
+        });
+      });
+
     NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.bookmarkLink"),
       NativeWindow.contextmenus.linkBookmarkableContext,
       function(aTarget) {
         let url = NativeWindow.contextmenus._getLinkURL(aTarget);
         let title = aTarget.textContent || aTarget.title || url;
         sendMessageToJava({
           type: "Bookmark:Insert",
           url: url,
--- a/mobile/android/locales/en-US/chrome/browser.properties
+++ b/mobile/android/locales/en-US/chrome/browser.properties
@@ -161,16 +161,17 @@ contextmenu.saveImage=Save Image
 contextmenu.setWallpaper=Set as Wallpaper
 contextmenu.addSearchEngine=Add Search Engine
 contextmenu.playMedia=Play
 contextmenu.pauseMedia=Pause
 contextmenu.shareMedia=Share Video
 contextmenu.showControls2=Show Controls
 contextmenu.saveVideo=Save Video
 contextmenu.saveAudio=Save Audio
+contextmenu.addToContacts=Add to Contacts
 
 contextmenu.copy=Copy
 contextmenu.copyAll=Copy All
 contextmenu.selectWord=Select Word
 contextmenu.selectAll=Select All
 contextmenu.paste=Paste
 
 # Select UI
--- a/mobile/android/themes/core/aboutReader.css
+++ b/mobile/android/themes/core/aboutReader.css
@@ -497,18 +497,22 @@ body {
 .toggle-button.on {
   background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-mdpi.png');
 }
 
 .toggle-button {
   background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-mdpi.png');
 }
 
+.list-button.on {
+  background-image: url('chrome://browser/skin/images/reader-list-on-icon-mdpi.png');
+}
+
 .list-button {
-  background-image: url('chrome://browser/skin/images/reader-list-icon-mdpi.png');
+  background-image: url('chrome://browser/skin/images/reader-list-off-icon-mdpi.png');
 }
 
 .share-button {
   background-image: url('chrome://browser/skin/images/reader-share-icon-mdpi.png');
 }
 
 .style-button {
   background-image: url('chrome://browser/skin/images/reader-style-icon-mdpi.png');
@@ -530,18 +534,22 @@ body {
   .toggle-button.on {
     background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-hdpi.png');
   }
 
   .toggle-button {
     background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-hdpi.png');
   }
 
+  .list-button.on {
+    background-image: url('chrome://browser/skin/images/reader-list-on-icon-hdpi.png');
+  }
+
   .list-button {
-    background-image: url('chrome://browser/skin/images/reader-list-icon-hdpi.png');
+    background-image: url('chrome://browser/skin/images/reader-list-off-icon-hdpi.png');
   }
 
   .share-button {
     background-image: url('chrome://browser/skin/images/reader-share-icon-hdpi.png');
   }
 
   .style-button {
     background-image: url('chrome://browser/skin/images/reader-style-icon-hdpi.png');
@@ -564,18 +572,22 @@ body {
   .toggle-button.on {
     background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-xhdpi.png');
   }
 
   .toggle-button {
     background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-xhdpi.png');
   }
 
+  .list-button.on {
+    background-image: url('chrome://browser/skin/images/reader-list-on-icon-xhdpi.png');
+  }
+
   .list-button {
-    background-image: url('chrome://browser/skin/images/reader-list-icon-xhdpi.png');
+    background-image: url('chrome://browser/skin/images/reader-list-off-icon-xhdpi.png');
   }
 
   .share-button {
     background-image: url('chrome://browser/skin/images/reader-share-icon-xhdpi.png');
   }
 
   .style-button {
     background-image: url('chrome://browser/skin/images/reader-style-icon-xhdpi.png');
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0242843558b138642a03210b3b2d7d12b2e586eb
GIT binary patch
literal 380
zc%17D@N?(olHy`uVBq!ia0vp^x<IVL!3HE{MK^;47>k44ofy`glX(f`u%tWsIx;Y9
z?C1WI$O`0h7I;J!GcfQS24TkI`72U@f>I@}5hcO-X(i=}MX3w{iJ5sNdVa1U3T4K6
zrh0}3249L60#&{Cba4!caDRJAk*~>6z$G!S>p+2t%%sOtLvl7n#%-JVN7Om!<4pB!
z%2m?Ie`I^!8SFazf^V^P&&}6=C2!_@KmK|7d!hGb25BW<dh{OM<vZ5XcdK8m_={*s
zaARR>o5qV}Opm#E126cp9_#scr)I~uScsx|7hU(<J~-oI;O~nmefyg7v<%i=5MaF<
zk`S{{k!#n=12ZnppUr=LpEp?1MdMu^<<=6$R$2D5&Rh%!873;VXu)i*9&HmBM{`jL
z<6p&}AKohO1S_g?6aSdUp6urS*4_FL*sWkk=ib>@(eyxt;c8(x(Ax~2u6{1-oD!M<
D!ke2C
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bcc26589ef113a7662b452aa1f0fce1d621000a5
GIT binary patch
literal 435
zc%17D@N?(olHy`uVBq!ia0vp^azHG>!3HGXX8P_2QjEnx?oJHr&dIz4a#+$GeH|GX
zHuiJ>Nn{1`ISV`@iy0XB4ude`@%$AjKtZVz*NBqf{Irtt#G+J&fW*wa5<NfH5QQ>h
zJyShH1A{L`3xUQedAc};cz7SZV(snhDA4w>!jbtNhm(TB5$~leDr}cDGMhQJE%N2k
zkGQp>{^Yq!^SAF~c9*!ZUechri+$7mn>QoX+AnJ^-Qv_HnKHw%E$!ovUA?wn-`Jm+
z(Dpq3zWvb;zr`N!FBRDudv!4v&+PRv51I4+Bnn<RwKB9Z@$)`yo5LsM#T?%*dlkqU
znQ}sRcf~PowigdqM!M^4SXC7QRI*e$^i{o0Y3uhL-`ZURcCQ8ta_Jc~_SVWiPLnkZ
zdM+)QHbK!`c2}Tp;j81~j&Iw5X0@GNTkGH#^N`1K{uv%4lRIBHj&Cr(b??*RG}*!h
z=gf?jBs_8}ZQm&$&$88emAj~f+4gTmxeuA=ODyXDo+kUT%@pX`O(zVRd8V%~sbjnn
Xvc+?W0N+|*m@;^}`njxgN@xNA1%t1F
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a356191a2312d7f839fc145ffac7dbc7a2759d82
GIT binary patch
literal 627
zc%17D@N?(olHy`uVBq!ia0vp^Hb88^!3HFK?IbyY6k~CayA#8@b22Z19F}xPUq=Rp
zjs4tz5?O(K&H|6fVg?4j!ywFfJby(BP*AGGHKHUqKdq!Zu_%=xATcwqM9<GPM4`-B
z&s5LQz~D>KLZGpaJY5_^GMwLDxAkIi6gc|vYJkYzrip618}A+9UeVamdB3a5$k@5x
zd|#7pW>>xOS%s~ab|2(#3qO4Abwc~hn+81DtcT|%-Z18=Zc99G@J6!j;`8g@1@7AJ
zt^E;moqLyh_xFs(L>KR#^Q8~UXQh9X(>3VH==}Ke*@2UL+_`y_qmpXYG236V0V`X=
z9D7{#l-SW4{d1c$zWd%R<!KAf_;@N{z7)^$1xk@C{CV4g119QRS<ZIY!+w|c^48Xz
z_G-TF%4K&q9hcxyu8NSDpZ!wu?B<GoF$uRVM}EYx-`i7>@(E_AmE4c6XOUoQWnXyA
zds_N3>|6KGX)!wKGuK=W#BW=bj{c+nbE_>io_&+w7jw=ia{1#;uR(SiNzKpBjQ7t3
zdn7;3#;6i%d5tXpo$J>p@ul29tp4c!g5sb2_YYrt`F?+UG;T}e<V8-^-7hHFEBrii
zO*F_wg1Sa_*DtXnLT)GDp309Wp4dhuNL&<p{CTUz2EL!qiet~eoTqbdF>9Oc;SK2$
h-+16rvcK&nKgaI<|8B-<PXwk322WQ%mvv4FO#r}d4;=si
rename from mobile/android/themes/core/images/reader-list-icon-hdpi.png
rename to mobile/android/themes/core/images/reader-list-on-icon-hdpi.png
rename from mobile/android/themes/core/images/reader-list-icon-mdpi.png
rename to mobile/android/themes/core/images/reader-list-on-icon-mdpi.png
rename from mobile/android/themes/core/images/reader-list-icon-xhdpi.png
rename to mobile/android/themes/core/images/reader-list-on-icon-xhdpi.png
--- a/mobile/android/themes/core/jar.mn
+++ b/mobile/android/themes/core/jar.mn
@@ -63,19 +63,22 @@ chrome.jar:
   skin/images/reader-plus-icon-hdpi.png     (images/reader-plus-icon-hdpi.png)
   skin/images/reader-plus-icon-xhdpi.png    (images/reader-plus-icon-xhdpi.png)
   skin/images/reader-minus-icon-mdpi.png    (images/reader-minus-icon-mdpi.png)
   skin/images/reader-minus-icon-hdpi.png    (images/reader-minus-icon-hdpi.png)
   skin/images/reader-minus-icon-xhdpi.png   (images/reader-minus-icon-xhdpi.png)
   skin/images/reader-dropdown-arrow-mdpi.png     (images/reader-dropdown-arrow-mdpi.png)
   skin/images/reader-dropdown-arrow-hdpi.png     (images/reader-dropdown-arrow-hdpi.png)
   skin/images/reader-dropdown-arrow-xhdpi.png    (images/reader-dropdown-arrow-xhdpi.png)
-  skin/images/reader-list-icon-mdpi.png          (images/reader-list-icon-mdpi.png)
-  skin/images/reader-list-icon-hdpi.png          (images/reader-list-icon-hdpi.png)
-  skin/images/reader-list-icon-xhdpi.png         (images/reader-list-icon-xhdpi.png)
+  skin/images/reader-list-on-icon-mdpi.png       (images/reader-list-on-icon-mdpi.png)
+  skin/images/reader-list-on-icon-hdpi.png       (images/reader-list-on-icon-hdpi.png)
+  skin/images/reader-list-on-icon-xhdpi.png      (images/reader-list-on-icon-xhdpi.png)
+  skin/images/reader-list-off-icon-mdpi.png      (images/reader-list-off-icon-mdpi.png)
+  skin/images/reader-list-off-icon-hdpi.png      (images/reader-list-off-icon-hdpi.png)
+  skin/images/reader-list-off-icon-xhdpi.png     (images/reader-list-off-icon-xhdpi.png)
   skin/images/reader-toggle-on-icon-mdpi.png     (images/reader-toggle-on-icon-mdpi.png)
   skin/images/reader-toggle-on-icon-hdpi.png     (images/reader-toggle-on-icon-hdpi.png)
   skin/images/reader-toggle-on-icon-xhdpi.png    (images/reader-toggle-on-icon-xhdpi.png)
   skin/images/reader-toggle-off-icon-mdpi.png    (images/reader-toggle-off-icon-mdpi.png)
   skin/images/reader-toggle-off-icon-hdpi.png    (images/reader-toggle-off-icon-hdpi.png)
   skin/images/reader-toggle-off-icon-xhdpi.png   (images/reader-toggle-off-icon-xhdpi.png)
   skin/images/reader-share-icon-mdpi.png         (images/reader-share-icon-mdpi.png)
   skin/images/reader-share-icon-hdpi.png         (images/reader-share-icon-hdpi.png)
--- a/modules/libbz2/src/Makefile.in
+++ b/modules/libbz2/src/Makefile.in
@@ -7,17 +7,17 @@
 DEPTH		= @DEPTH@
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME	= bz2
-HOST_LIBRARY_NAME = hostbz2
+DISABLED_HOST_LIBRARY_NAME = hostbz2
 FORCE_STATIC_LIB= 1
 ifeq ($(OS_ARCH),WINNT)
 USE_STATIC_LIBS = 1
 endif
 
 # This is defined by the bzip2-1.0.3 Makefile.  It appears to be used to
 # configure GLIBC to support large files.  This isn't something we care about
 # at this stage, since we're only interested in the streaming API, but we
--- a/modules/libbz2/src/moz.build
+++ b/modules/libbz2/src/moz.build
@@ -5,8 +5,9 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MODULE = 'libbz2'
 
 EXPORTS += [
     'bzlib.h',
 ]
 
+HOST_LIBRARY_NAME = 'hostbz2'
--- a/modules/libmar/src/Makefile.in
+++ b/modules/libmar/src/Makefile.in
@@ -7,17 +7,17 @@
 DEPTH		= @DEPTH@
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME	= mar
-HOST_LIBRARY_NAME = hostmar
+DISABLED_HOST_LIBRARY_NAME = hostmar
 FORCE_STATIC_LIB = 1
 ifeq ($(OS_ARCH),WINNT)
 USE_STATIC_LIBS = 1
 endif
 
 # This makefile just builds support for reading archives.
 
 
--- a/modules/libmar/src/moz.build
+++ b/modules/libmar/src/moz.build
@@ -6,8 +6,9 @@
 
 MODULE = 'libmar'
 
 EXPORTS += [
     'mar.h',
     'mar_cmdline.h',
 ]
 
+HOST_LIBRARY_NAME = 'hostmar'
--- a/netwerk/base/src/nsStreamTransportService.cpp
+++ b/netwerk/base/src/nsStreamTransportService.cpp
@@ -425,24 +425,31 @@ nsOutputStreamTransport::IsNonBlocking(b
     *result = false;
     return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // nsStreamTransportService
 //-----------------------------------------------------------------------------
 
+bool nsStreamTransportService::sHasBeenShutdown = false;
+
 nsStreamTransportService::~nsStreamTransportService()
 {
     NS_ASSERTION(!mPool, "thread pool wasn't shutdown");
 }
 
 nsresult
 nsStreamTransportService::Init()
 {
+    if (sHasBeenShutdown) {
+      // Prevent any attempt at resurrection
+      // (see bug 845190)
+      return NS_ERROR_NOT_AVAILABLE;
+    }
     mPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID);
     NS_ENSURE_STATE(mPool);
 
     // Configure the pool
     mPool->SetName(NS_LITERAL_CSTRING("StreamTrans"));
     mPool->SetThreadLimit(25);
     mPool->SetIdleThreadLimit(1);
     mPool->SetIdleThreadTimeout(PR_SecondsToInterval(30));
@@ -503,15 +510,15 @@ nsStreamTransportService::CreateOutputTr
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStreamTransportService::Observe(nsISupports *subject, const char *topic,
                                   const PRUnichar *data)
 {
   NS_ASSERTION(strcmp(topic, "xpcom-shutdown-threads") == 0, "oops");
-
+  sHasBeenShutdown = true;
   if (mPool) {
     mPool->Shutdown();
     mPool = nullptr;
   }
   return NS_OK;
 }
--- a/netwerk/base/src/nsStreamTransportService.h
+++ b/netwerk/base/src/nsStreamTransportService.h
@@ -22,9 +22,15 @@ public:
     nsresult Init();
 
     nsStreamTransportService() {}
 
 private:
     ~nsStreamTransportService();
 
     nsCOMPtr<nsIThreadPool> mPool;
+
+    /**
+     * |true| if we have shutdown once already, in which
+     * case we should reject any attempt to resurrect.
+     */
+    static bool sHasBeenShutdown;
 };
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -4399,30 +4399,16 @@ nsHttpChannel::AsyncOpen(nsIStreamListen
 }
 
 nsresult
 nsHttpChannel::BeginConnect()
 {
     LOG(("nsHttpChannel::BeginConnect [this=%p]\n", this));
     nsresult rv;
 
-    // notify "http-on-modify-request" observers
-    CallOnModifyRequestObservers();
-
-    // Check to see if we should redirect this channel elsewhere by
-    // nsIHttpChannel.redirectTo API request
-    if (mAPIRedirectToURI) {
-        return AsyncCall(&nsHttpChannel::HandleAsyncAPIRedirect);
-    }
-
-    // If mTimingEnabled flag is not set after OnModifyRequest() then
-    // clear the already recorded AsyncOpen value for consistency.
-    if (!mTimingEnabled)
-        mAsyncOpenTime = TimeStamp();
-
     // Construct connection info object
     nsAutoCString host;
     int32_t port = -1;
     bool usingSSL = false;
 
     rv = mURI->SchemeIs("https", &usingSSL);
     if (NS_SUCCEEDED(rv))
         rv = mURI->GetAsciiHost(host);
@@ -4451,16 +4437,30 @@ nsHttpChannel::BeginConnect()
     if (NS_SUCCEEDED(rv))
         rv = mAuthProvider->Init(this);
     if (NS_FAILED(rv))
         return rv;
 
     // check to see if authorization headers should be included
     mAuthProvider->AddAuthorizationHeaders();
 
+    // notify "http-on-modify-request" observers
+    CallOnModifyRequestObservers();
+
+    // Check to see if we should redirect this channel elsewhere by
+    // nsIHttpChannel.redirectTo API request
+    if (mAPIRedirectToURI) {
+        return AsyncCall(&nsHttpChannel::HandleAsyncAPIRedirect);
+    }
+
+    // If mTimingEnabled flag is not set after OnModifyRequest() then
+    // clear the already recorded AsyncOpen value for consistency.
+    if (!mTimingEnabled)
+        mAsyncOpenTime = TimeStamp();
+
     // when proxying only use the pipeline bit if ProxyPipelining() allows it.
     if (!mConnectionInfo->UsingConnect() && mConnectionInfo->UsingHttpProxy()) {
         mCaps &= ~NS_HTTP_ALLOW_PIPELINING;
         if (gHttpHandler->ProxyPipelining())
             mCaps |= NS_HTTP_ALLOW_PIPELINING;
     }
 
     // if this somehow fails we can go on without it
new file mode 100644
--- /dev/null
+++ b/netwerk/test/unit/test_bug856978.js
@@ -0,0 +1,139 @@
+/* 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/. */
+
+// This test makes sure that the authorization header can get deleted e.g. by
+// extensions if they are observing "http-on-modify-request". In a first step
+// the auth cache is filled with credentials which then get added to the
+// following request. On "http-on-modify-request" it is tested whether the
+// authorization header got added at all and if so it gets removed. This test
+// passes iff both succeeds.
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cr = Components.results;
+
+Components.utils.import("resource://testing-common/httpd.js");
+
+var notification = "http-on-modify-request";
+
+var httpServer = null;
+
+var authCredentials = "guest:guest";
+var authPath = "/authTest";
+var authCredsURL = "http://" + authCredentials + "@localhost:8888" + authPath;
+var authURL = "http://localhost:8888" + authPath;
+
+function authHandler(metadata, response) {
+  if (metadata.hasHeader("Test")) {
+    // Lets see if the auth header got deleted.
+    var noAuthHeader = false;
+    if (!metadata.hasHeader("Authorization")) {
+      noAuthHeader = true;
+    }
+    do_check_true(noAuthHeader);
+  } else {
+    // Not our test request yet.
+    if (!metadata.hasHeader("Authorization")) {
+      response.setStatusLine(metadata.httpVersion, 401, "Unauthorized");
+      response.setHeader("WWW-Authenticate", 'Basic realm="secret"', false);
+    }
+  }
+}
+
+function RequestObserver() {
+  this.register();
+}
+
+RequestObserver.prototype = {
+  register: function() {
+    do_print("Registering " + notification);
+    Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService).
+      addObserver(this, notification, true);
+  },
+
+  QueryInterface: function(iid) {
+    if (iid.equals(Ci.nsIObserver) || iid.equals(Ci.nsISupportsWeakReference) ||
+        iid.equals(Ci.nsISupports)) {
+      return this;
+    }
+    throw Cr.NS_ERROR_NO_INTERFACE;
+  },
+
+  observe: function(subject, topic, data) {
+    if (topic == notification) {
+      if (!(subject instanceof Ci.nsIHttpChannel)) {
+        do_throw(notification + " observed a non-HTTP channel.");
+      }
+      try {
+        let authHeader = subject.getRequestHeader("Authorization");
+      } catch (e) {
+        // Throw if there is no header to delete. We should get one iff caching
+        // the auth credentials is working and the header gets added _before_
+        // "http-on-modify-request" gets called.
+        httpServer.stop(do_test_finished);
+        do_throw("No authorization header found, aborting!");
+      }
+      // We are still here. Let's remove the authorization header now.
+      subject.setRequestHeader("Authorization", null, false);
+    }
+  }
+}
+
+var listener = {
+  onStartRequest: function test_onStartR(request, ctx) {},
+
+  onDataAvailable: function test_ODA() {
+    do_throw("Should not get any data!");
+  },
+
+  onStopRequest: function test_onStopR(request, ctx, status) {
+    if (current_test < (tests.length - 1)) {
+      current_test++;
+      tests[current_test]();
+    } else {
+      do_test_pending();
+      httpServer.stop(do_test_finished);
+    }
+    do_test_finished();
+  }
+};
+
+function makeChan(url) {
+  var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
+  var chan = ios.newChannel(url, null, null).QueryInterface(Ci.nsIHttpChannel);
+  return chan;
+}
+
+var tests = [startAuthHeaderTest, removeAuthHeaderTest];
+
+var current_test = 0;
+
+var requestObserver = null;
+
+function run_test() {
+  httpServer = new HttpServer();
+  httpServer.registerPathHandler(authPath, authHandler);
+  httpServer.start(8888);
+
+  tests[0]();
+}
+
+function startAuthHeaderTest() {
+  var chan = makeChan(authCredsURL);
+  chan.asyncOpen(listener, null);
+
+  do_test_pending();
+}
+
+function removeAuthHeaderTest() {
+  // After caching the auth credentials in the first test, lets try to remove
+  // the authorization header now...
+  requestObserver = new RequestObserver();
+  var chan = makeChan(authURL);
+  // Indicating that the request is coming from the second test.
+  chan.setRequestHeader("Test", "1", false);
+  chan.asyncOpen(listener, null);
+
+  do_test_pending();
+}
--- a/netwerk/test/unit/xpcshell.ini
+++ b/netwerk/test/unit/xpcshell.ini
@@ -185,8 +185,9 @@ run-if = hasNode
 [test_XHR_redirects.js]
 [test_pinned_app_cache.js]
 [test_offlinecache_custom-directory.js]
 [test_bug767025.js]
 [test_bug826063.js]
 [test_bug812167.js]
 [test_tldservice_nextsubdomain.js]
 [test_about_protocol.js]
+[test_bug856978.js]
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -84,16 +84,17 @@ class TreeMetadataEmitter(object):
             CPPSRCS='CPP_SOURCES',
             CSRCS='CSRCS',
             DEFINES='DEFINES',
             EXTRA_COMPONENTS='EXTRA_COMPONENTS',
             HOST_CSRCS='HOST_CSRCS',
             HOST_LIBRARY_NAME='HOST_LIBRARY_NAME',
             MODULE='MODULE',
             SIMPLE_PROGRAMS='SIMPLE_PROGRAMS',
+            SSRCS='SSRCS',
             XPIDL_FLAGS='XPIDL_FLAGS',
             XPIDL_MODULE='XPIDL_MODULE',
             XPIDLSRCS='XPIDL_SOURCES',
             )
         for mak, moz in varmap.items():
             if sandbox[moz]:
                 passthru.variables[mak] = sandbox[moz]
 
--- a/python/mozbuild/mozbuild/frontend/sandbox_symbols.py
+++ b/python/mozbuild/mozbuild/frontend/sandbox_symbols.py
@@ -124,16 +124,22 @@ VARIABLES = {
         """),
 
     'SIMPLE_PROGRAMS': (StrictOrderingOnAppendList, list, [],
         """Generate a list of binaries from source.
 
         A list of sources, one per program, to compile & link with libs into standalone programs.
         """),
 
+    'SSRCS': (StrictOrderingOnAppendList, list, [],
+        """Assembly source files.
+
+        This variable contains a list of files to invoke the assembler on.
+        """),
+
     'TOOL_DIRS': (list, list, [],
         """Like DIRS but for tools.
 
         Tools are for pieces of the build system that aren't required to
         produce a working binary (in theory). They provide things like test
         code and utilities.
         """),
 
--- a/python/mozbuild/mozbuild/test/backend/data/variable_passthru/moz.build
+++ b/python/mozbuild/mozbuild/test/backend/data/variable_passthru/moz.build
@@ -16,8 +16,10 @@ HOST_CSRCS = ['bar.c', 'foo.c']
 
 HOST_LIBRARY_NAME = 'host_bar'
 
 SIMPLE_PROGRAMS = ['bar.x', 'foo.x']
 
 CSRCS += ['bar.c', 'foo.c']
 
 CMMSRCS = ['bar.mm', 'foo.mm']
+
+SSRCS = ['bar.S', 'foo.S']
--- a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
+++ b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
@@ -164,16 +164,20 @@ class TestRecursiveMakeBackend(BackendTe
             ],
             'HOST_LIBRARY_NAME': [
                 'HOST_LIBRARY_NAME := host_bar',
             ],
             'SIMPLE_PROGRAMS': [
                 'SIMPLE_PROGRAMS += bar.x',
                 'SIMPLE_PROGRAMS += foo.x',
             ],
+            'SSRCS': [
+                'SSRCS += bar.S',
+                'SSRCS += foo.S',
+            ],
             'XPIDL_FLAGS': [
                 'XPIDL_FLAGS += -Idir1',
                 'XPIDL_FLAGS += -Idir2',
                 'XPIDL_FLAGS += -Idir3',
             ],
             'XPIDL_MODULE': [
                 'XPIDL_MODULE := module_name'
             ],
--- a/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/moz.build
+++ b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/moz.build
@@ -16,8 +16,10 @@ HOST_CSRCS += ['fans.c', 'tans.c']
 
 HOST_LIBRARY_NAME = 'host_fans'
 
 SIMPLE_PROGRAMS += ['fans.x', 'tans.x']
 
 CSRCS += ['fans.c', 'tans.c']
 
 CMMSRCS = ['fans.mm', 'tans.mm']
+
+SSRCS = ['fans.S', 'tans.S']
--- a/python/mozbuild/mozbuild/test/frontend/test_emitter.py
+++ b/python/mozbuild/mozbuild/test/frontend/test_emitter.py
@@ -128,16 +128,17 @@ class TestEmitterBasic(unittest.TestCase
             ASFILES=['fans.asm', 'tans.s'],
             CMMSRCS=['fans.mm', 'tans.mm'],
             CSRCS=['fans.c', 'tans.c'],
             DEFINES=['-Dfans', '-Dtans'],
             EXTRA_COMPONENTS=['fans.js', 'tans.js'],
             HOST_CSRCS=['fans.c', 'tans.c'],
             HOST_LIBRARY_NAME='host_fans',
             SIMPLE_PROGRAMS=['fans.x', 'tans.x'],
+            SSRCS=['fans.S', 'tans.S'],
             XPIDLSRCS=['bar.idl', 'biz.idl', 'foo.idl'],
             XPIDL_MODULE='module_name',
             XPIDL_FLAGS=['-Idir1', '-Idir2', '-Idir3'],
             )
 
         variables = objs[1].variables
         self.assertEqual(len(variables), len(wanted))
 
--- a/testing/marionette/components/marionettecomponent.js
+++ b/testing/marionette/components/marionettecomponent.js
@@ -1,30 +1,34 @@
 /* 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/. */
 
-const {Constructor: CC, classes: Cc, interfaces: Ci, utils: Cu} = Components;
+this.CC = Components.Constructor;
+this.Cc = Components.classes;
+this.Ci = Components.interfaces;
+this.Cu = Components.utils;
 
 const MARIONETTE_CONTRACTID = "@mozilla.org/marionette;1";
 const MARIONETTE_CID = Components.ID("{786a1369-dca5-4adc-8486-33d23c88010a}");
-const DEBUGGER_ENABLED_PREF = 'devtools.debugger.remote-enabled';
 const MARIONETTE_ENABLED_PREF = 'marionette.defaultPrefs.enabled';
-const DEBUGGER_FORCELOCAL_PREF = 'devtools.debugger.force-local';
 const MARIONETTE_FORCELOCAL_PREF = 'marionette.force-local';
 
-const ServerSocket = CC("@mozilla.org/network/server-socket;1",
-                        "nsIServerSocket",
-                        "initSpecialConnection");
+this.ServerSocket = CC("@mozilla.org/network/server-socket;1",
+                       "nsIServerSocket",
+                       "initSpecialConnection");
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/FileUtils.jsm");
 Cu.import("resource://gre/modules/services-common/log4moz.js");
 
+let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
+               .getService(Ci.mozIJSSubScriptLoader);
+
 function MarionetteComponent() {
   this._loaded = false;
   this.observerService = Services.obs;
 
   // set up the logger
   this.logger = Log4Moz.repository.getLogger("Marionette");
   this.logger.level = Log4Moz.Level["Info"];
   let logf = FileUtils.getFile('ProfD', ['marionette.log']);
@@ -46,17 +50,16 @@ function MarionetteComponent() {
 
 MarionetteComponent.prototype = {
   classDescription: "Marionette component",
   classID: MARIONETTE_CID,
   contractID: MARIONETTE_CONTRACTID,
   QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler, Ci.nsIObserver]),
   _xpcom_categories: [{category: "command-line-handler", entry: "b-marionette"},
                       {category: "profile-after-change", service: true}],
-  original_forcelocal: null,
   appName: Services.appinfo.name,
   enabled: false,
   finalUiStartup: false,
 
   onSocketAccepted: function mc_onSocketAccepted(aSocket, aTransport) {
     this.logger.info("onSocketAccepted for Marionette dummy socket");
   },
 
@@ -107,27 +110,22 @@ MarionetteComponent.prototype = {
         break;
     }
   },
 
   init: function mc_init() {
     if (!this._loaded && this.enabled && this.finalUiStartup) {
       this._loaded = true;
 
-      try {
-        this.original_forcelocal = Services.prefs.getBoolPref(DEBUGGER_FORCELOCAL_PREF);
-      }
-      catch(e) {}
-
       let marionette_forcelocal = this.appName == 'B2G' ? false : true;
       try {
         marionette_forcelocal = Services.prefs.getBoolPref(MARIONETTE_FORCELOCAL_PREF);
       }
       catch(e) {}
-      Services.prefs.setBoolPref(DEBUGGER_FORCELOCAL_PREF, marionette_forcelocal);
+      Services.prefs.setBoolPref(MARIONETTE_FORCELOCAL_PREF, marionette_forcelocal);
 
       if (!marionette_forcelocal) {
         // See bug 800138.  Because the first socket that opens with
         // force-local=false fails, we open a dummy socket that will fail.
         // keepWhenOffline=true so that it still work when offline (local).
         // This allows the following attempt by Marionette to open a socket
         // to succeed.
         let insaneSacrificialGoat = new ServerSocket(666, Ci.nsIServerSocket.KeepWhenOffline, 4);
@@ -137,45 +135,27 @@ MarionetteComponent.prototype = {
       let port;
       try {
         port = Services.prefs.getIntPref('marionette.defaultPrefs.port');
       }
       catch(e) {
         port = 2828;
       }
       try {
-        Cu.import('resource://gre/modules/devtools/dbg-server.jsm');
-        DebuggerServer.addActors('chrome://marionette/content/marionette-actors.js');
-        // This pref is required for the remote debugger to open a socket,
-        // so force it to true.  See bug 761252.
-
-        let original = false;
-        try {
-          original = Services.prefs.getBoolPref(DEBUGGER_ENABLED_PREF);
-        }
-        catch(e) { }
-        Services.prefs.setBoolPref(DEBUGGER_ENABLED_PREF, true);
-
-        // Always allow remote connections.
-        DebuggerServer.initTransport(function () { return true; });
-        DebuggerServer.openListener(port);
-
-        Services.prefs.setBoolPref(DEBUGGER_ENABLED_PREF, original);
-        if (this.original_forcelocal != null) {
-          Services.prefs.setBoolPref(DEBUGGER_FORCELOCAL_PREF,
-                                     this.original_forcelocal);
-        }
-        this.logger.info("marionette listener opened");
+        loader.loadSubScript("chrome://marionette/content/marionette-server.js");
+        let forceLocal = Services.prefs.getBoolPref(MARIONETTE_FORCELOCAL_PREF);
+        this._marionetteServer = new MarionetteServer(port, forceLocal);
+        this.logger.info("Marionette server ready");
       }
       catch(e) {
         this.logger.error('exception: ' + e.name + ', ' + e.message);
       }
     }
   },
 
   uninit: function mc_uninit() {
-    DebuggerServer.closeListener();
+    this._marionetteServer.closeListener();
     this._loaded = false;
   },
 
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([MarionetteComponent]);
--- a/testing/marionette/jar.mn
+++ b/testing/marionette/jar.mn
@@ -1,15 +1,15 @@
 # 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/.
 
 marionette.jar:
 % content marionette %content/
-  content/marionette-actors.js      (marionette-actors.js)
+  content/marionette-server.js      (marionette-server.js)
   content/marionette-listener.js    (marionette-listener.js)
   content/marionette-elements.js    (marionette-elements.js)
   content/marionette-sendkeys.js    (marionette-sendkeys.js)
   content/marionette-log-obj.js     (marionette-log-obj.js)
   content/marionette-simpletest.js  (marionette-simpletest.js)
   content/EventUtils.js  (EventUtils.js)
   content/ChromeUtils.js  (ChromeUtils.js)
 #ifdef ENABLE_TESTS
deleted file mode 100644
--- a/testing/marionette/marionette-actors.js
+++ /dev/null
@@ -1,2380 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-/**
- * Gecko-specific actors.
- */
-
-const FRAME_SCRIPT = "chrome://marionette/content/marionette-listener.js";
-
-let {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
-
-let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
-               .getService(Ci.mozIJSSubScriptLoader);
-loader.loadSubScript("chrome://marionette/content/marionette-simpletest.js");
-loader.loadSubScript("chrome://marionette/content/marionette-log-obj.js");
-Cu.import("chrome://marionette/content/marionette-elements.js");
-let utils = {};
-loader.loadSubScript("chrome://marionette/content/EventUtils.js", utils);
-loader.loadSubScript("chrome://marionette/content/ChromeUtils.js", utils);
-loader.loadSubScript("chrome://marionette/content/atoms.js", utils);
-
-let specialpowers = {};
-loader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserver.js",
-                     specialpowers);
-specialpowers.specialPowersObserver = new specialpowers.SpecialPowersObserver();
-specialpowers.specialPowersObserver.init();
-
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/FileUtils.jsm");
-Cu.import("resource://gre/modules/NetUtil.jsm");  
-
-Services.prefs.setBoolPref("marionette.contentListener", false);
-let appName = Services.appinfo.name;
-
-// import logger
-Cu.import("resource://gre/modules/services-common/log4moz.js");
-let logger = Log4Moz.repository.getLogger("Marionette");
-logger.info('marionette-actors.js loaded');
-
-let bypassOffline = false;
-
-try {
-  XPCOMUtils.defineLazyGetter(this, "libcutils", function () {
-    Cu.import("resource://gre/modules/systemlibs.js");
-    return libcutils;
-  });
-  if (libcutils) {
-    let qemu = libcutils.property_get("ro.kernel.qemu");
-    logger.info("B2G emulator: " + (qemu == "1" ? "yes" : "no"));
-    let platform = libcutils.property_get("ro.product.device");
-    logger.info("Platform detected is " + platform);
-    bypassOffline = (qemu == "1" || platform == "panda");
-  }
-}
-catch(e) {}
-
-if (bypassOffline) {
-  logger.info("Bypassing offline status.");
-  Services.prefs.setBoolPref("network.gonk.manage-offline-status", false);
-  Services.io.manageOfflineStatus = false;
-  Services.io.offline = false;
-}
-
-// This is used to prevent newSession from returning before the telephony
-// API's are ready; see bug 792647.  This assumes that marionette-actors.js
-// will be loaded before the 'system-message-listener-ready' message
-// is fired.  If this stops being true, this approach will have to change.
-let systemMessageListenerReady = false;
-Services.obs.addObserver(function() {
-  systemMessageListenerReady = true;
-}, "system-message-listener-ready", false);
-
-/**
- * Creates the root actor once a connection is established
- */
-
-function createRootActor(aConnection)
-{
-  return new MarionetteRootActor(aConnection);
-}
-
-/**
- * Root actor for Marionette. Add any future actors to its actor pool.
- * Implements methods needed by resource:///modules/devtools/dbg-server.jsm
- */
-
-function MarionetteRootActor(aConnection)
-{
-  this.conn = aConnection;
-  this._marionetteActor = new MarionetteDriverActor(this.conn);
-  this._marionetteActorPool = null; //hold future actors
-
-  this._marionetteActorPool = new ActorPool(this.conn);
-  this._marionetteActorPool.addActor(this._marionetteActor);
-  this.conn.addActorPool(this._marionetteActorPool);
-}
-
-MarionetteRootActor.prototype = {
-  /**
-   * Called when a client first makes a connection
-   *
-   * @return object
-   *         returns the name of the actor, the application type, and any traits
-   */
-  sayHello: function MRA_sayHello() {
-    return { from: "root",
-             applicationType: "gecko",
-             traits: [] };
-  },
-
-  /**
-   * Called when client disconnects. Cleans up marionette driver actions.
-   */
-  disconnect: function MRA_disconnect() {
-    this._marionetteActor.deleteSession();
-  },
-
-  /**
-   * Used to get the running marionette actor, so we can issue commands
-   *
-   * @return object
-   *         Returns the ID the client can use to communicate with the
-   *         MarionetteDriverActor
-   */
-  getMarionetteID: function MRA_getMarionette() {
-    return { "from": "root",
-             "id": this._marionetteActor.actorID } ;
-  }
-};
-
-// register the calls
-MarionetteRootActor.prototype.requestTypes = {
-  "getMarionetteID": MarionetteRootActor.prototype.getMarionetteID,
-  "sayHello": MarionetteRootActor.prototype.sayHello
-};
-
-/**
- * An object representing a frame that Marionette has loaded a
- * frame script in.
- */
-function MarionetteRemoteFrame(windowId, frameId) {
-  this.windowId = windowId;
-  this.frameId = frameId;
-  this.targetFrameId = null;
-  this.messageManager = null;
-  this.command_id = null;
-}
-// persistent list of remote frames that Marionette has loaded a frame script in
-let remoteFrames = [];
-
-/*
- * Custom exceptions
- */
-function FrameSendNotInitializedError(frame) {
-  this.code = 54;
-  this.frame = frame;
-  this.message = "Error sending message to frame (NS_ERROR_NOT_INITIALIZED)";
-  this.toString = function() {
-    return this.message + " " + this.frame + "; frame has closed.";
-  }
-}
-
-function FrameSendFailureError(frame) {
-  this.code = 55;
-  this.frame = frame;
-  this.message = "Error sending message to frame (NS_ERROR_FAILURE)";
-  this.toString = function() {
-    return this.message + " " + this.frame + "; frame not responding.";
-  }
-}
-
-/**
- * This actor is responsible for all marionette API calls. It gets created
- * for each connection and manages all chrome and browser based calls. It
- * mediates content calls by issuing appropriate messages to the content process.
- */
-function MarionetteDriverActor(aConnection)
-{
-  this.uuidGen = Cc["@mozilla.org/uuid-generator;1"]
-                   .getService(Ci.nsIUUIDGenerator);
-
-  this.conn = aConnection;
-  this.globalMessageManager = Cc["@mozilla.org/globalmessagemanager;1"]
-                             .getService(Ci.nsIMessageBroadcaster);
-  this.messageManager = this.globalMessageManager;
-  this.browsers = {}; //holds list of BrowserObjs
-  this.curBrowser = null; // points to current browser
-  this.context = "content";
-  this.scriptTimeout = null;
-  this.searchTimeout = null;
-  this.pageTimeout = null;
-  this.timer = null;
-  this.marionetteLog = new MarionetteLogObj();
-  this.command_id = null;
-  this.mainFrame = null; //topmost chrome frame
-  this.curFrame = null; //subframe that currently has focus
-  this.importedScripts = FileUtils.getFile('TmpD', ['marionettescriptchrome']);
-  this.currentRemoteFrame = null; // a member of remoteFrames
-  this.testName = null;
-  this.mozBrowserClose = null;
-
-  //register all message listeners
-  this.addMessageManagerListeners(this.messageManager);
-}
-
-MarionetteDriverActor.prototype = {
-
-  //name of the actor
-  actorPrefix: "marionette",
-
-  /**
-   * Helper methods:
-   */
-
-  /**
-   * Switches to the global ChromeMessageBroadcaster, potentially replacing a frame-specific
-   * ChromeMessageSender.  Has no effect if the global ChromeMessageBroadcaster is already
-   * in use.  If this replaces a frame-specific ChromeMessageSender, it removes the message
-   * listeners from that sender, and then puts the corresponding frame script "to sleep",
-   * which removes most of the message listeners from it as well.
-   */
-  switchToGlobalMessageManager: function MDA_switchToGlobalMM() {
-    if (this.currentRemoteFrame !== null) {
-      this.removeMessageManagerListeners(this.messageManager);
-      this.sendAsync("sleepSession", null, null, true);
-    }
-    this.messageManager = this.globalMessageManager;
-    this.currentRemoteFrame = null;
-  },
-
-  /**
-   * Helper method to send async messages to the content listener
-   *
-   * @param string name
-   *        Suffix of the targetted message listener (Marionette:<suffix>)
-   * @param object values
-   *        Object to send to the listener
-   */
-  sendAsync: function MDA_sendAsync(name, values, commandId, ignoreFailure) {
-    let success = true;
-    if (values instanceof Object && commandId) {
-      values.command_id = commandId;
-    }
-    if (this.currentRemoteFrame !== null) {
-      try {
-        this.messageManager.sendAsyncMessage(
-          "Marionette:" + name + this.currentRemoteFrame.targetFrameId, values);
-      }
-      catch(e) {
-        if (!ignoreFailure) {
-          success = false;
-          let error = e;
-          switch(e.result) {
-            case Components.results.NS_ERROR_FAILURE:
-              error = new FrameSendFailureError(this.currentRemoteFrame);
-              break;
-            case Components.results.NS_ERROR_NOT_INITIALIZED:
-              error = new FrameSendNotInitializedError(this.currentRemoteFrame);
-              break;
-            default:
-              break;
-          }
-          let code = error.hasOwnProperty('code') ? e.code : 500;
-          this.sendError(error.toString(), code, error.stack, commandId);
-        }
-      }
-    }
-    else {
-      this.messageManager.broadcastAsyncMessage(
-        "Marionette:" + name + this.curBrowser.curFrameId, values);
-    }
-    return success;
-  },
-
-  /**
-   * Adds listeners for messages from content frame scripts.
-   *
-   * @param object messageManager
-   *        The messageManager object (ChromeMessageBroadcaster or ChromeMessageSender)
-   *        to which the listeners should be added.
-   */
-  addMessageManagerListeners: function MDA_addMessageManagerListeners(messageManager) {
-    messageManager.addMessageListener("Marionette:ok", this);
-    messageManager.addMessageListener("Marionette:done", this);
-    messageManager.addMessageListener("Marionette:error", this);
-    messageManager.addMessageListener("Marionette:log", this);
-    messageManager.addMessageListener("Marionette:shareData", this);
-    messageManager.addMessageListener("Marionette:register", this);
-    messageManager.addMessageListener("Marionette:runEmulatorCmd", this);
-    messageManager.addMessageListener("Marionette:switchToFrame", this);
-  },
-
-  /**
-   * Removes listeners for messages from content frame scripts.
-   *
-   * @param object messageManager
-   *        The messageManager object (ChromeMessageBroadcaster or ChromeMessageSender)
-   *        from which the listeners should be removed.
-   */
-  removeMessageManagerListeners: function MDA_removeMessageManagerListeners(messageManager) {
-    messageManager.removeMessageListener("Marionette:ok", this);
-    messageManager.removeMessageListener("Marionette:done", this);
-    messageManager.removeMessageListener("Marionette:error", this);
-    messageManager.removeMessageListener("Marionette:log", this);
-    messageManager.removeMessageListener("Marionette:shareData", this);
-    messageManager.removeMessageListener("Marionette:register", this);
-    messageManager.removeMessageListener("Marionette:runEmulatorCmd", this);
-    messageManager.removeMessageListener("Marionette:switchToFrame", this);
-  },
-
-  logRequest: function MDA_logRequest(type, data) {
-    logger.debug("Got request: " + type + ", data: " + JSON.stringify(data) + ", id: " + this.command_id);
-  },
-
-  /**
-   * Generic method to pass a response to the client
-   *
-   * @param object msg
-   *        Response to send back to client
-   * @param string command_id
-   *        Unique identifier assigned to the client's request.
-   *        Used to distinguish the asynchronous responses.
-   */
-  sendToClient: function MDA_sendToClient(msg, command_id) {
-    logger.info("sendToClient: " + JSON.stringify(msg) + ", " + command_id +
-                ", " + this.command_id);
-    if (!command_id) {
-      logger.warn("got a response with no command_id");
-      return;
-    }
-    else if (command_id != -1) {
-      // A command_id of -1 is used for emulator callbacks, and those
-      // don't use this.command_id.
-      if (!this.command_id) {
-        // A null value for this.command_id means we've already processed
-        // a message for the previous value, and so the current message is a
-        // duplicate.
-        logger.warn("ignoring duplicate response for command_id " + command_id);
-        return;
-      }
-      else if (this.command_id != command_id) {
-        logger.warn("ignoring out-of-sync response");
-        return;
-      }
-    }
-    this.conn.send(msg);
-    if (command_id != -1) {
-      // Don't unset this.command_id if this message is to process an
-      // emulator callback, since another response for this command_id is
-      // expected, after the containing call to execute_async_script finishes.
-      this.command_id = null;
-    }
-  },
-
-  /**
-   * Send a value to client
-   *
-   * @param object value
-   *        Value to send back to client
-   * @param string command_id
-   *        Unique identifier assigned to the client's request.
-   *        Used to distinguish the asynchronous responses.
-   */
-  sendResponse: function MDA_sendResponse(value, command_id) {
-    if (typeof(value) == 'undefined')
-        value = null;
-    this.sendToClient({from:this.actorID, value: value}, command_id);
-  },
-
-  /**
-   * Send ack to client
-   * 
-   * @param string command_id
-   *        Unique identifier assigned to the client's request.
-   *        Used to distinguish the asynchronous responses.
-   */
-  sendOk: function MDA_sendOk(command_id) {
-    this.sendToClient({from:this.actorID, ok: true}, command_id);
-  },
-
-  /**
-   * Send error message to client
-   *
-   * @param string message
-   *        Error message
-   * @param number status
-   *        Status number
-   * @param string trace
-   *        Stack trace
-   * @param string command_id
-   *        Unique identifier assigned to the client's request.
-   *        Used to distinguish the asynchronous responses.
-   */
-  sendError: function MDA_sendError(message, status, trace, command_id) {
-    let error_msg = {message: message, status: status, stacktrace: trace};
-    this.sendToClient({from:this.actorID, error: error_msg}, command_id);
-  },
-
-  /**
-   * Gets the current active window
-   * 
-   * @return nsIDOMWindow
-   */
-  getCurrentWindow: function MDA_getCurrentWindow() {
-    let type = null;
-    if (this.curFrame == null) {
-      if (this.curBrowser == null) {
-        if (this.context == "content") {
-          type = 'navigator:browser';
-        }
-        return Services.wm.getMostRecentWindow(type);
-      }
-      else {
-        return this.curBrowser.window;
-      }
-    }
-    else {
-      return this.curFrame;
-    }
-  },
-
-  /**
-   * Gets the the window enumerator
-   *
-   * @return nsISimpleEnumerator
-   */
-  getWinEnumerator: function MDA_getWinEnumerator() {
-    let type = null;
-    if (appName != "B2G" && this.context == "content") {
-      type = 'navigator:browser';
-    }
-    return Services.wm.getEnumerator(type);
-  },
-
-  /**
-   * Create a new BrowserObj for window and add to known browsers
-   * 
-   * @param nsIDOMWindow win
-   *        Window for which we will create a BrowserObj
-   *
-   * @return string
-   *        Returns the unique server-assigned ID of the window
-   */
-  addBrowser: function MDA_addBrowser(win) {
-    let browser = new BrowserObj(win);
-    let winId = win.QueryInterface(Ci.nsIInterfaceRequestor).
-                    getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
-    winId = winId + ((appName == "B2G") ? '-b2g' : '');
-    this.browsers[winId] = browser;
-    this.curBrowser = this.browsers[winId];
-    if (this.curBrowser.elementManager.seenItems[winId] == undefined) {
-      //add this to seenItems so we can guarantee the user will get winId as this window's id
-      this.curBrowser.elementManager.seenItems[winId] = Cu.getWeakReference(win);
-    }
-  },
-
-  /**
-   * Start a new session in a new browser. 
-   *
-   * If newSession is true, we will switch focus to the start frame 
-   * when it registers. Also, if it is in desktop, then a new tab 
-   * with the start page uri (about:blank) will be opened.
-   *
-   * @param nsIDOMWindow win
-   *        Window whose browser we need to access
-   * @param boolean newSession
-   *        True if this is the first time we're talking to this browser
-   */
-  startBrowser: function MDA_startBrowser(win, newSession) {
-    this.mainFrame = win;
-    this.curFrame = null;
-    this.addBrowser(win);
-    this.curBrowser.newSession = newSession;
-    this.curBrowser.startSession(newSession, win, this.whenBrowserStarted.bind(this));
-  },
-
-  /**
-   * Callback invoked after a new session has been started in a browser.
-   * Loads the Marionette frame script into the browser if needed.
-   *
-   * @param nsIDOMWindow win
-   *        Window whose browser we need to access
-   * @param boolean newSession
-   *        True if this is the first time we're talking to this browser
-   */
-  whenBrowserStarted: function MDA_whenBrowserStarted(win, newSession) {
-    try {
-      if (!Services.prefs.getBoolPref("marionette.contentListener") || !newSession) {
-        this.curBrowser.loadFrameScript(FRAME_SCRIPT, win);
-      }
-    }
-    catch (e) {
-      //there may not always be a content process
-      logger.info("could not load listener into content for page: " + win.location.href);
-    }
-    utils.window = win;
-  },
-
-  /**
-   * Recursively get all labeled text
-   *
-   * @param nsIDOMElement el
-   *        The parent element
-   * @param array lines
-   *        Array that holds the text lines
-   */
-  getVisibleText: function MDA_getVisibleText(el, lines) {
-    let nodeName = el.nodeName;
-    try {
-      if (utils.isElementDisplayed(el)) {
-        if (el.value) {
-          lines.push(el.value);
-        }
-        for (var child in el.childNodes) {
-          this.getVisibleText(el.childNodes[child], lines);
-        };
-      }
-    }
-    catch (e) {
-      if (nodeName == "#text") {
-        lines.push(el.textContent);
-      }
-    }
-  },
-
-  getCommandId: function MDA_getCommandId() {
-    return this.uuidGen.generateUUID().toString();
-  },
-
-  /**
-   * Marionette API:
-   *
-   * All methods implementing a command from the client should create a
-   * command_id, and then use this command_id in all messages exchanged with
-   * the frame scripts and with responses sent to the client.  This prevents
-   * commands and responses from getting out-of-sync, which can happen in
-   * the case of execute_async calls that timeout and then later send a
-   * response, and other situations.  See bug 779011. See setScriptTimeout()
-   * for a basic example.
-   */
-
-  /**
-   * Create a new session. This creates a BrowserObj.
-   *
-   * In a desktop environment, this opens a new 'about:blank' tab for 
-   * the client to test in.
-   *
-   */
-  newSession: function MDA_newSession() {
-    this.command_id = this.getCommandId();
-    this.newSessionCommandId = this.command_id;
-
-    this.scriptTimeout = 10000;
-
-    function waitForWindow() {
-      let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-      let win = this.getCurrentWindow();
-      if (!win ||
-          (appName == "Firefox" && !win.gBrowser) ||
-          (appName == "Fennec" && !win.BrowserApp)) { 
-        checkTimer.initWithCallback(waitForWindow.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
-      }
-      else {
-        this.startBrowser(win, true);
-      }
-    }
-
-    this.switchToGlobalMessageManager();
-
-    if (!Services.prefs.getBoolPref("marionette.contentListener")) {
-      waitForWindow.call(this);
-    }
-    else if ((appName != "Firefox") && (this.curBrowser == null)) {
-      //if there is a content listener, then we just wake it up
-      this.addBrowser(this.getCurrentWindow());
-      this.curBrowser.startSession(false, this.getCurrentWindow(), this.whenBrowserStarted);
-      this.messageManager.broadcastAsyncMessage("Marionette:restart", {});
-    }
-    else {
-      this.sendError("Session already running", 500, null, this.command_id);
-    }
-  },
-
-  getSessionCapabilities: function MDA_getSessionCapabilities(){
-    this.command_id = this.getCommandId();
-
-    let rotatable = appName == "B2G" ? true : false;
-
-    let value = {
-          'appBuildId' : Services.appinfo.appBuildID,
-          'XULappId' : Services.appinfo.ID,
-          'cssSelectorsEnabled': true,
-          'browserName': appName,
-          'handlesAlerts': false,
-          'javascriptEnabled': true,
-          'nativeEvents': false,
-          'platform': Services.appinfo.OS,
-          'rotatable': rotatable,
-          'takesScreenshot': false,
-          'version': Services.appinfo.version
-    };
-
-    this.sendResponse(value, this.command_id);
-  },
-
-  getStatus: function MDA_getStatus(){
-    this.command_id = this.getCommandId();
-
-    let arch;
-    try {
-      arch = (Services.appinfo.XPCOMABI || 'unknown').split('-')[0]
-    }
-    catch (ignored) {
-      arch = 'unknown'
-    };
-
-    let value = {
-          'os': {
-            'arch': arch,
-            'name': Services.appinfo.OS,
-            'version': 'unknown'
-          },
-          'build': {
-            'revision': 'unknown',
-            'time': Services.appinfo.platformBuildID,
-            'version': Services.appinfo.version
-          }
-    };
-
-    this.sendResponse(value, this.command_id);
-  },
-
-  /**
-   * Log message. Accepts user defined log-level.
-   *
-   * @param object aRequest
-   *        'value' member holds log message
-   *        'level' member hold log level
-   */
-  log: function MDA_log(aRequest) {
-    this.command_id = this.getCommandId();
-    this.marionetteLog.log(aRequest.value, aRequest.level);
-    this.sendOk(this.command_id);
-  },
-
-  /**
-   * Return all logged messages.
-   */
-  getLogs: function MDA_getLogs() {
-    this.command_id = this.getCommandId();
-    this.sendResponse(this.marionetteLog.getLogs(), this.command_id);
-  },
-
-  /**
-   * Sets the context of the subsequent commands to be either 'chrome' or 'content'
-   *
-   * @param object aRequest
-   *        'value' member holds the name of the context to be switched to
-   */
-  setContext: function MDA_setContext(aRequest) {
-    this.command_id = this.getCommandId();
-    this.logRequest("setContext", aRequest);
-    let context = aRequest.value;
-    if (context != "content" && context != "chrome") {
-      this.sendError("invalid context", 500, null, this.command_id);
-    }
-    else {
-      this.context = context;
-      this.sendOk(this.command_id);
-    }
-  },
-
-  /**
-   * Returns a chrome sandbox that can be used by the execute_foo functions.
-   *
-   * @param nsIDOMWindow aWindow
-   *        Window in which we will execute code
-   * @param Marionette marionette
-   *        Marionette test instance
-   * @param object args
-   *        Client given args
-   * @return Sandbox
-   *        Returns the sandbox
-   */
-  createExecuteSandbox: function MDA_createExecuteSandbox(aWindow, marionette, args, specialPowers, command_id) {
-    try {
-      args = this.curBrowser.elementManager.convertWrappedArguments(args, aWindow);
-    }
-    catch(e) {
-      this.sendError(e.message, e.code, e.stack, command_id);
-      return;
-    }
-
-    let _chromeSandbox = new Cu.Sandbox(aWindow,
-       { sandboxPrototype: aWindow, wantXrays: false, sandboxName: ''});
-    _chromeSandbox.__namedArgs = this.curBrowser.elementManager.applyNamedArgs(args);
-    _chromeSandbox.__marionetteParams = args;
-    _chromeSandbox.testUtils = utils;
-
-    marionette.exports.forEach(function(fn) {
-      try {
-        _chromeSandbox[fn] = marionette[fn].bind(marionette);
-      }
-      catch(e) {
-        _chromeSandbox[fn] = marionette[fn];
-      }
-    });
-
-    _chromeSandbox.isSystemMessageListenerReady =
-        function() { return systemMessageListenerReady; }
-
-    if (specialPowers == true) {
-      loader.loadSubScript("chrome://specialpowers/content/specialpowersAPI.js",
-                           _chromeSandbox);
-      loader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserverAPI.js",
-                           _chromeSandbox);
-      loader.loadSubScript("chrome://specialpowers/content/ChromePowers.js",
-                           _chromeSandbox);
-    }
-
-    return _chromeSandbox;
-  },
-
-  /**
-   * Executes a script in the given sandbox.
-   *
-   * @param Sandbox sandbox
-   *        Sandbox in which the script will run
-   * @param string script
-   *        The script to run
-   * @param boolean directInject
-   *        If true, then the script will be run as is,
-   *        and not as a function body (as you would
-   *        do using the WebDriver spec)
-   * @param boolean async
-   *        True if the script is asynchronous
-   */
-  executeScriptInSandbox: function MDA_executeScriptInSandbox(sandbox, script,
-     directInject, async, command_id, timeout) {
-
-    if (directInject && async &&
-        (timeout == null || timeout == 0)) {
-      this.sendError("Please set a timeout", 21, null, command_id);
-      return;
-    }
-
-    if (this.importedScripts.exists()) {
-      let stream = Cc["@mozilla.org/network/file-input-stream;1"].  
-                    createInstance(Ci.nsIFileInputStream);
-      stream.init(this.importedScripts, -1, 0, 0);
-      let data = NetUtil.readInputStreamToString(stream, stream.available());
-      script = data + script;
-    }
-
-    let res = Cu.evalInSandbox(script, sandbox, "1.8");
-
-    if (directInject && !async &&
-        (res == undefined || res.passed == undefined)) {
-      this.sendError("finish() not called", 500, null, command_id);
-      return;
-    }
-
-    if (!async) {
-      this.sendResponse(this.curBrowser.elementManager.wrapValue(res),
-                        command_id);
-    }
-  },
-
-  /**
-   * Execute the given script either as a function body (executeScript)
-   * or directly (for 'mochitest' like JS Marionette tests)
-   *
-   * @param object aRequest
-   *        'value' member is the script to run
-   *        'args' member holds the arguments to the script
-   * @param boolean directInject
-   *        if true, it will be run directly and not as a 
-   *        function body
-   */
-  execute: function MDA_execute(aRequest, directInject) {
-    let timeout = aRequest.scriptTimeout ? aRequest.scriptTimeout : this.scriptTimeout;
-    let command_id = this.command_id = this.getCommandId();
-    this.logRequest("execute", aRequest);
-    if (aRequest.newSandbox == undefined) {
-      //if client does not send a value in newSandbox, 
-      //then they expect the same behaviour as webdriver
-      aRequest.newSandbox = true;
-    }
-    if (this.context == "content") {
-      this.sendAsync("executeScript",
-                     {
-                       value: aRequest.value,
-                       args: aRequest.args,
-                       newSandbox: aRequest.newSandbox,
-                       timeout: timeout,
-                       specialPowers: aRequest.specialPowers
-                     },
-                     command_id);
-      return;
-    }
-
-    let curWindow = this.getCurrentWindow();
-    let marionette = new Marionette(this, curWindow, "chrome",
-                                    this.marionetteLog,
-                                    timeout, this.testName);
-    let _chromeSandbox = this.createExecuteSandbox(curWindow,
-                                                   marionette,
-                                                   aRequest.args,
-                                                   aRequest.specialPowers,
-                                                   command_id);
-    if (!_chromeSandbox)
-      return;
-
-    try {
-      _chromeSandbox.finish = function chromeSandbox_finish() {
-        return marionette.generate_results();
-      };
-
-      let script;
-      if (directInject) {
-        script = aRequest.value;
-      }
-      else {
-        script = "let func = function() {" +
-                       aRequest.value + 
-                     "};" +
-                     "func.apply(null, __marionetteParams);";
-      }
-      this.executeScriptInSandbox(_chromeSandbox, script, directInject,
-                                  false, command_id, timeout);
-    }
-    catch (e) {
-      this.sendError(e.name + ': ' + e.message, 17, e.stack, command_id);
-    }
-  },
-
-  /**
-   * Set the timeout for asynchronous script execution
-   *
-   * @param object aRequest
-   *        'value' member is time in milliseconds to set timeout
-   */
-  setScriptTimeout: function MDA_setScriptTimeout(aRequest) {
-    this.command_id = this.getCommandId();
-    let timeout = parseInt(aRequest.value);
-    if(isNaN(timeout)){
-      this.sendError("Not a Number", 500, null, this.command_id);
-    }
-    else {
-      this.scriptTimeout = timeout;
-      this.sendOk(this.command_id);
-    }
-  },
-
-  /**
-   * execute pure JS script. Used to execute 'mochitest'-style Marionette tests.
-   *
-   * @param object aRequest
-   *        'value' member holds the script to execute
-   *        'args' member holds the arguments to the script
-   *        'timeout' member will be used as the script timeout if it is given
-   */
-  executeJSScript: function MDA_executeJSScript(aRequest) {
-    let timeout = aRequest.scriptTimeout ? aRequest.scriptTimeout : this.scriptTimeout;
-    let command_id = this.command_id = this.getCommandId();
-    //all pure JS scripts will need to call Marionette.finish() to complete the test.
-    if (aRequest.newSandbox == undefined) {
-      //if client does not send a value in newSandbox, 
-      //then they expect the same behaviour as webdriver
-      aRequest.newSandbox = true;
-    }
-    if (this.context == "chrome") {
-      if (aRequest.async) {
-        this.executeWithCallback(aRequest, aRequest.async);
-      }
-      else {
-        this.execute(aRequest, true);
-      }
-    }
-    else {
-      this.sendAsync("executeJSScript",
-                     {
-                       value: aRequest.value,
-                       args: aRequest.args,
-                       newSandbox: aRequest.newSandbox,
-                       async: aRequest.async,
-                       timeout: timeout,
-                       specialPowers: aRequest.specialPowers
-                     },
-                     command_id);
-   }
-  },
-
-  /**
-   * This function is used by executeAsync and executeJSScript to execute a script
-   * in a sandbox. 
-   * 
-   * For executeJSScript, it will return a message only when the finish() method is called.
-   * For executeAsync, it will return a response when marionetteScriptFinished/arguments[arguments.length-1] 
-   * method is called, or if it times out.
-   *
-   * @param object aRequest
-   *        'value' member holds the script to execute
-   *        'args' member holds the arguments for the script
-   * @param boolean directInject
-   *        if true, it will be run directly and not as a 
-   *        function body
-   */
-  executeWithCallback: function MDA_executeWithCallback(aRequest, directInject) {
-    let timeout = aRequest.scriptTimeout ? aRequest.scriptTimeout : this.scriptTimeout;
-    let command_id = this.command_id = this.getCommandId();
-    this.logRequest("executeWithCallback", aRequest);
-    if (aRequest.newSandbox == undefined) {
-      //if client does not send a value in newSandbox, 
-      //then they expect the same behaviour as webdriver
-      aRequest.newSandbox = true;
-    }
-
-    if (this.context == "content") {
-      this.sendAsync("executeAsyncScript",
-                     {
-                       value: aRequest.value,
-                       args: aRequest.args,
-                       id: this.command_id,
-                       newSandbox: aRequest.newSandbox,
-                       timeout: timeout,
-                       specialPowers: aRequest.specialPowers
-                     },
-                     command_id);
-      return;
-    }
-
-    let curWindow = this.getCurrentWindow();
-    let original_onerror = curWindow.onerror;
-    let that = this;
-    that.timeout = timeout;
-    let marionette = new Marionette(this, curWindow, "chrome",
-                                    this.marionetteLog,
-                                    timeout, this.testName);
-    marionette.command_id = this.command_id;
-
-    function chromeAsyncReturnFunc(value, status) {
-      if (that._emu_cbs && Object.keys(that._emu_cbs).length) {
-        value = "Emulator callback still pending when finish() called";
-        status = 500;
-        that._emu_cbs = null;
-      }
-
-      if (value == undefined)
-        value = null;
-      if (that.command_id == marionette.command_id) {
-        if (that.timer != null) {
-          that.timer.cancel();
-          that.timer = null;
-        }
-
-        curWindow.onerror = original_onerror;
-
-        if (status == 0 || status == undefined) {
-          that.sendToClient({from: that.actorID, value: that.curBrowser.elementManager.wrapValue(value), status: status},
-                            marionette.command_id);
-        }
-        else {
-          let error_msg = {message: value, status: status, stacktrace: null};
-          that.sendToClient({from: that.actorID, error: error_msg},
-                            marionette.command_id);
-        }
-      }
-    }
-
-    curWindow.onerror = function (errorMsg, url, lineNumber) {
-      chromeAsyncReturnFunc(errorMsg + " at: " + url + " line: " + lineNumber, 17);
-      return true;
-    };
-
-    function chromeAsyncFinish() {
-      chromeAsyncReturnFunc(marionette.generate_results(), 0);
-    }
-
-    let _chromeSandbox = this.createExecuteSandbox(curWindow,
-                                                   marionette,
-                                                   aRequest.args,
-                                                   aRequest.specialPowers,
-                                                   command_id);
-    if (!_chromeSandbox)
-      return;
-
-    try {
-
-      this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-      if (this.timer != null) {
-        this.timer.initWithCallback(function() {
-          chromeAsyncReturnFunc("timed out", 28);
-        }, that.timeout, Ci.nsITimer.TYPE_ONESHOT);
-      }
-
-      _chromeSandbox.returnFunc = chromeAsyncReturnFunc;
-      _chromeSandbox.finish = chromeAsyncFinish;
-
-      let script;
-      if (directInject) {
-        script = aRequest.value;
-      }
-      else {
-        script =  '__marionetteParams.push(returnFunc);'
-                + 'let marionetteScriptFinished = returnFunc;'
-                + 'let __marionetteFunc = function() {' + aRequest.value + '};'
-                + '__marionetteFunc.apply(null, __marionetteParams);';
-      }
-
-      this.executeScriptInSandbox(_chromeSandbox, script, directInject,
-                                  true, command_id, timeout);
-    } catch (e) {
-      chromeAsyncReturnFunc(e.name + ": " + e.message, 17);
-    }
-  },
-
-  /**
-   * Navigates to given url
-   *
-   * @param object aRequest
-   *        'value' member holds the url to navigate to
-   */
-  goUrl: function MDA_goUrl(aRequest) {
-    let command_id = this.command_id = this.getCommandId();
-    if (this.context != "chrome") {
-      aRequest.command_id = command_id;
-      aRequest.pageTimeout = this.pageTimeout;
-      this.sendAsync("goUrl", aRequest, command_id);
-      return;
-    }
-
-    this.getCurrentWindow().location.href = aRequest.value;
-    let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-    let start = new Date().getTime();
-    let end = null;
-    function checkLoad() { 
-      end = new Date().getTime();
-      let elapse = end - start;
-      if (this.pageTimeout == null || elapse <= this.pageTimeout){
-        if (curWindow.document.readyState == "complete") { 
-          sendOk(command_id);
-          return;
-        }
-        else{ 
-          checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
-        }
-      }
-      else{
-        sendError("Error loading page", 13, null, command_id);
-        return;
-      }
-    }//end
-    checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
-  },
-
-  /**
-   * Gets current url
-   */
-  getUrl: function MDA_getUrl() {
-    this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
-      this.sendResponse(this.getCurrentWindow().location.href, this.command_id);
-    }
-    else {
-      this.sendAsync("getUrl", {}, this.command_id);
-    }
-  },
-
-  /**
-   * Gets the current title of the window
-   */
-  getTitle: function MDA_getTitle() {
-    this.command_id = this.getCommandId();
-    if (this.context == "chrome"){
-      var curWindow = this.getCurrentWindow();
-      var title = curWindow.document.documentElement.getAttribute('title');
-      this.sendResponse(title, this.command_id);
-    }
-    else {
-      this.sendAsync("getTitle", {}, this.command_id);
-    }
-  },
-
-  /**
-   * Gets the current type of the window
-   */
-  getWindowType: function MDA_getWindowType() {
-    this.command_id = this.getCommandId();
-      var curWindow = this.getCurrentWindow();
-      var type = curWindow.document.documentElement.getAttribute('windowtype');
-      this.sendResponse(type, this.command_id);
-  },
-
-  /**
-   * Gets the page source of the content document
-   */
-  getPageSource: function MDA_getPageSource(){
-    this.command_id = this.getCommandId();
-    if (this.context == "chrome"){
-      let curWindow = this.getCurrentWindow();
-      let XMLSerializer = curWindow.XMLSerializer; 
-      let pageSource = new XMLSerializer().serializeToString(curWindow.document);
-      this.sendResponse(pageSource, this.command_id);
-    }
-    else {
-      this.sendAsync("getPageSource", {}, this.command_id);
-    }
-  },
-
-  /**
-   * Go back in history
-   */
-  goBack: function MDA_goBack() {
-    this.command_id = this.getCommandId();
-    this.sendAsync("goBack", {}, this.command_id);
-  },
-
-  /**
-   * Go forward in history
-   */
-  goForward: function MDA_goForward() {
-    this.command_id = this.getCommandId();
-    this.sendAsync("goForward", {}, this.command_id);
-  },
-
-  /**
-   * Refresh the page
-   */
-  refresh: function MDA_refresh() {
-    this.command_id = this.getCommandId();
-    this.sendAsync("refresh", {}, this.command_id);
-  },
-
-  /**
-   * Get the current window's server-assigned ID
-   */
-  getWindow: function MDA_getWindow() {
-    this.command_id = this.getCommandId();
-    for (let i in this.browsers) {
-      if (this.curBrowser == this.browsers[i]) {
-        this.sendResponse(i, this.command_id);
-      }
-    }
-  },
-
-  /**
-   * Get the server-assigned IDs of all available windows
-   */
-  getWindows: function MDA_getWindows() {
-    this.command_id = this.getCommandId();
-    let res = [];
-    let winEn = this.getWinEnumerator(); 
-    while(winEn.hasMoreElements()) {
-      let foundWin = winEn.getNext();
-      let winId = foundWin.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
-      winId = winId + ((appName == "B2G") ? '-b2g' : '');
-      res.push(winId)
-    }
-    this.sendResponse(res, this.command_id);
-  },
-
-  /**
-   * Switch to a window based on name or server-assigned id.
-   * Searches based on name, then id.
-   *
-   * @param object aRequest
-   *        'value' member holds the name or id of the window to switch to
-   */
-  switchToWindow: function MDA_switchToWindow(aRequest) {
-    let command_id = this.command_id = this.getCommandId();
-    let winEn = this.getWinEnumerator(); 
-    while(winEn.hasMoreElements()) {
-      let foundWin = winEn.getNext();
-      let winId = foundWin.QueryInterface(Ci.nsIInterfaceRequestor)
-                          .getInterface(Ci.nsIDOMWindowUtils)
-                          .outerWindowID;
-      winId = winId + ((appName == "B2G") ? '-b2g' : '');
-      if (aRequest.value == foundWin.name || aRequest.value == winId) {
-        if (this.browsers[winId] == undefined) {
-          //enable Marionette in that browser window
-          this.startBrowser(foundWin, false);
-        }
-        else {
-          utils.window = foundWin;
-          this.curBrowser = this.browsers[winId];
-        }
-        this.sendOk(command_id);
-        return;
-      }
-    }
-    this.sendError("Unable to locate window " + aRequest.value, 23, null,
-                   command_id);
-  },
- 
-  /**
-   * Switch to a given frame within the current window
-   *
-   * @param object aRequest
-   *        'element' is the element to switch to
-   *        'value' if element is not set, then this
-   *                holds either the id, name or index 
-   *                of the frame to switch to
-   */
-  switchToFrame: function MDA_switchToFrame(aRequest) {
-    let command_id = this.command_id = this.getCommandId();
-    this.logRequest("switchToFrame", aRequest);
-    let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-    let curWindow = this.getCurrentWindow();
-    let checkLoad = function() { 
-      let errorRegex = /about:.+(error)|(blocked)\?/;
-      if (curWindow.document.readyState == "complete") { 
-        this.sendOk(command_id);
-        return;
-      } 
-      else if (curWindow.document.readyState == "interactive" && errorRegex.exec(curWindow.document.baseURI)) {
-        this.sendError("Error loading page", 13, null, command_id);
-        return;
-      }
-      
-      checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
-    }
-    if (this.context == "chrome") {
-      let foundFrame = null;
-      if ((aRequest.value == null) && (aRequest.element == null)) {
-        this.curFrame = null;
-        if (aRequest.focus) {
-          this.mainFrame.focus();
-        }
-        checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
-        return;
-      }
-      if (aRequest.element != undefined) {
-        if (this.curBrowser.elementManager.seenItems[aRequest.element] != undefined) {
-          let wantedFrame = this.curBrowser.elementManager.getKnownElement(aRequest.element, curWindow); //HTMLIFrameElement
-          let numFrames = curWindow.frames.length;
-          for (let i = 0; i < numFrames; i++) {
-            if (curWindow.frames[i].frameElement == wantedFrame) {
-              curWindow = curWindow.frames[i]; 
-              this.curFrame = curWindow;
-              if (aRequest.focus) {
-                this.curFrame.focus();
-              }
-              checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
-              return;
-          }
-        }
-      }
-    }
-    switch(typeof(aRequest.value)) {
-      case "string" :
-        let foundById = null;
-        let numFrames = curWindow.frames.length;
-        for (let i = 0; i < numFrames; i++) {
-          //give precedence to name
-          let frame = curWindow.frames[i];
-          let frameElement = frame.frameElement;
-          if (frame.name == aRequest.value) {
-            foundFrame = i;
-            break;
-          } else if ((foundById == null) && (frameElement.id == aRequest.value)) {
-            foundById = i;
-          }
-        }
-        if ((foundFrame == null) && (foundById != null)) {
-          foundFrame = foundById;
-        }
-        break;
-      case "number":
-        if (curWindow.frames[aRequest.value] != undefined) {
-          foundFrame = aRequest.value;
-        }
-        break;
-      }
-      if (foundFrame != null) {
-        curWindow = curWindow.frames[foundFrame];
-        this.curFrame = curWindow;
-        if (aRequest.focus) {
-          this.curFrame.focus();
-        }
-        checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
-      } else {
-        this.sendError("Unable to locate frame: " + aRequest.value, 8, null,
-                       command_id);
-      }
-    }
-    else {
-      if ((!aRequest.value) && (!aRequest.element) &&
-          (this.currentRemoteFrame !== null)) {
-        // We're currently using a ChromeMessageSender for a remote frame, so this
-        // request indicates we need to switch back to the top-level (parent) frame.
-        // We'll first switch to the parent's (global) ChromeMessageBroadcaster, so
-        // we send the message to the right listener.
-        this.switchToGlobalMessageManager();
-      }
-      aRequest.command_id = command_id;
-      this.sendAsync("switchToFrame", aRequest, command_id);
-    }
-  },
-
-  /**
-   * Set timeout for searching for elements
-   *
-   * @param object aRequest
-   *        'value' holds the search timeout in milliseconds
-   */
-  setSearchTimeout: function MDA_setSearchTimeout(aRequest) {
-    this.command_id = this.getCommandId();
-    let timeout = parseInt(aRequest.value);
-    if (isNaN(timeout)) {
-      this.sendError("Not a Number", 500, null, this.command_id);
-    }
-    else {
-      this.searchTimeout = timeout;
-      this.sendOk(this.command_id);
-    }
-  },
-
-  /**
-   * Set timeout for page loading, searching and scripts
-   *
-   * @param object aRequest
-   *        'type' hold the type of timeout
-   *        'ms' holds the timeout in milliseconds
-   */
-  timeouts: function MDA_timeouts(aRequest){
-    /*setTimeout*/
-    this.command_id = this.getCommandId();
-    let timeout_type = aRequest.timeoutType;
-    let timeout = parseInt(aRequest.ms);
-    if (isNaN(timeout)) {
-      this.sendError("Not a Number", 500, null, this.command_id);
-    }
-    else {
-      if (timeout_type == "implicit") {
-        aRequest.value = aRequest.ms;
-        this.setSearchTimeout(aRequest);
-      }
-      else if (timeout_type == "script") {
-        aRequest.value = aRequest.ms;
-        this.setScriptTimeout(aRequest);
-      }
-      else {
-        this.pageTimeout = timeout;
-        this.sendOk(this.command_id);
-      }
-    }
-  },
-
-  /**
-   * Single Tap
-   *
-   * @param object aRequest
-            'element' represents the ID of the element to single tap on
-   */
-  singleTap: function MDA_singleTap(aRequest) {
-    this.command_id = this.getCommandId();
-    let serId = aRequest.element;
-    let x = aRequest.x;
-    let y = aRequest.y;
-    if (this.context == "chrome") {
-      this.sendError("Command 'singleTap' is not available in chrome context", 500, null, this.command_id);
-    }
-    else {
-      this.sendAsync("singleTap",
-                     {
-                       value: serId,
-                       corx: x,
-                       cory: y
-                     },
-                     this.command_id);
-    }
-  },
-
-  /**
-   * actionChain
-   *
-   * @param object aRequest
-   *        'value' represents a nested array: inner array represents each event; outer array represents collection of events
-   */
-  actionChain: function MDA_actionChain(aRequest) {
-    this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
-      this.sendError("Command 'actionChain' is not available in chrome context", 500, null, this.command_id);
-    }
-    else {
-      this.sendAsync("actionChain",
-                     {
-                       chain: aRequest.chain,
-                       nextId: aRequest.nextId
-                     },
-                     this.command_id);
-    }
-  },
-
-  /**
-   * multiAction
-   *
-   * @param object aRequest
-   *        'value' represents a nested array: inner array represents each event;
-   *        middle array represents collection of events for each finger
-   *        outer array represents all the fingers
-   */
-
-  multiAction: function MDA_multiAction(aRequest) {
-    this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
-       this.sendError("Command 'multiAction' is not available in chrome context", 500, null, this.command_id);
-    }
-    else {
-      this.sendAsync("multiAction",
-                     {
-                       value: aRequest.value,
-                       maxlen: aRequest.max_length
-                     },
-                     this.command_id);
-   }
- },
-
-  /**
-   * Find an element using the indicated search strategy.
-   *
-   * @param object aRequest
-   *        'using' member indicates which search method to use
-   *        'value' member is the value the client is looking for
-   */
-  findElement: function MDA_findElement(aRequest) {
-    let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
-      let id;
-      try {
-        let on_success = this.sendResponse.bind(this);
-        let on_error = this.sendError.bind(this);
-        id = this.curBrowser.elementManager.find(
-                              this.getCurrentWindow(),
-                              aRequest,
-                              this.searchTimeout,
-                              on_success,
-                              on_error,
-                              false,
-                              command_id);
-      }
-      catch (e) {
-        this.sendError(e.message, e.code, e.stack, command_id);
-        return;
-      }
-    }
-    else {
-      this.sendAsync("findElementContent",
-                     {
-                       value: aRequest.value,
-                       using: aRequest.using,
-                       element: aRequest.element,
-                       searchTimeout: this.searchTimeout
-                     },
-                     command_id);
-    }
-  },
-
-  /**
-   * Find elements using the indicated search strategy.
-   *
-   * @param object aRequest
-   *        'using' member indicates which search method to use
-   *        'value' member is the value the client is looking for
-   */
-  findElements: function MDA_findElements(aRequest) {
-    let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
-      let id;
-      try {
-        let on_success = this.sendResponse.bind(this);
-        let on_error = this.sendError.bind(this);
-        id = this.curBrowser.elementManager.find(this.getCurrentWindow(),
-                                                 aRequest,
-                                                 this.searchTimeout,
-                                                 on_success,
-                                                 on_error,
-                                                 true,
-                                                 command_id);
-      }
-      catch (e) {
-        this.sendError(e.message, e.code, e.stack, command_id);
-        return;
-      }
-    }
-    else {
-      this.sendAsync("findElementsContent",
-                     {
-                       value: aRequest.value,
-                       using: aRequest.using,
-                       element: aRequest.element,
-                       searchTimeout: this.searchTimeout
-                     },
-                     command_id);
-    }
-  },
-
-  /**
-   * Return the active element on the page
-   */
-  getActiveElement: function MDA_getActiveElement(){
-    let command_id = this.command_id = this.getCommandId();
-    this.sendAsync("getActiveElement", {}, command_id);
-  },
-
-  /**
-   * Send click event to element
-   *
-   * @param object aRequest
-   *        'element' member holds the reference id to
-   *        the element that will be clicked
-   */
-  clickElement: function MDA_clickElement(aRequest) {
-    let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
-      try {
-        //NOTE: click atom fails, fall back to click() action
-        let el = this.curBrowser.elementManager.getKnownElement(
-            aRequest.element, this.getCurrentWindow());
-        el.click();
-        this.sendOk(command_id);
-      }
-      catch (e) {
-        this.sendError(e.message, e.code, e.stack, command_id);
-      }
-    }
-    else {
-      // We need to protect against the click causing an OOP frame to close. 
-      // This fires the mozbrowserclose event when it closes so we need to 
-      // listen for it and then just send an error back. The person making the
-      // call should be aware something isnt right and handle accordingly
-      let curWindow = this.getCurrentWindow();
-      let self = this;
-      this.mozBrowserClose = function() { 
-        curWindow.removeEventListener('mozbrowserclose', self.mozBrowserClose, true);
-        self.switchToGlobalMessageManager();
-        self.sendError("The frame closed during the click, recovering to allow further communications", 500, null, command_id);
-      };
-      curWindow.addEventListener('mozbrowserclose', this.mozBrowserClose, true);
-      this.sendAsync("clickElement",
-                     { element: aRequest.element },
-                     command_id);
-    }
-  },
-
-  /**
-   * Get a given attribute of an element
-   *
-   * @param object aRequest
-   *        'element' member holds the reference id to
-   *        the element that will be inspected
-   *        'name' member holds the name of the attribute to retrieve
-   */
-  getElementAttribute: function MDA_getElementAttribute(aRequest) {
-    let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
-      try {
-        let el = this.curBrowser.elementManager.getKnownElement(
-            aRequest.element, this.getCurrentWindow());
-        this.sendResponse(utils.getElementAttribute(el, aRequest.name),
-                          command_id);
-      }
-      catch (e) {
-        this.sendError(e.message, e.code, e.stack, command_id);
-      }
-    }
-    else {
-      this.sendAsync("getElementAttribute",
-                     {
-                       element: aRequest.element,
-                       name: aRequest.name
-                     },
-                     command_id);
-    }
-  },
-
-  /**
-   * Get the text of an element, if any. Includes the text of all child elements.
-   *
-   * @param object aRequest
-   *        'element' member holds the reference id to
-   *        the element that will be inspected 
-   */
-  getElementText: function MDA_getElementText(aRequest) {
-    let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
-      //Note: for chrome, we look at text nodes, and any node with a "label" field
-      try {
-        let el = this.curBrowser.elementManager.getKnownElement(
-            aRequest.element, this.getCurrentWindow());
-        let lines = [];
-        this.getVisibleText(el, lines);
-        lines = lines.join("\n");
-        this.sendResponse(lines, command_id);
-      }
-      catch (e) {
-        this.sendError(e.message, e.code, e.stack, command_id);
-      }
-    }
-    else {
-      this.sendAsync("getElementText",
-                     { element: aRequest.element },
-                     command_id);
-    }
-  },
-
-  /**
-   * Get the tag name of the element.
-   *
-   * @param object aRequest
-   *        'element' member holds the reference id to
-   *        the element that will be inspected 
-   */
-  getElementTagName: function MDA_getElementTagName(aRequest) {
-    let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
-      try {
-        let el = this.curBrowser.elementManager.getKnownElement(
-            aRequest.element, this.getCurrentWindow());
-        this.sendResponse(el.tagName.toLowerCase(), command_id);
-      }
-      catch (e) {
-        this.sendError(e.message, e.code, e.stack, command_id);
-      }
-    }
-    else {
-      this.sendAsync("getElementTagName",
-                     { element: aRequest.element },
-                     command_id);
-    }
-  },
-
-  /**
-   * Check if element is displayed
-   *
-   * @param object aRequest
-   *        'element' member holds the reference id to
-   *        the element that will be checked 
-   */
-  isElementDisplayed: function MDA_isElementDisplayed(aRequest) {
-    let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
-      try {
-        let el = this.curBrowser.elementManager.getKnownElement(
-            aRequest.element, this.getCurrentWindow());
-        this.sendResponse(utils.isElementDisplayed(el), command_id);
-      }
-      catch (e) {
-        this.sendError(e.message, e.code, e.stack, command_id);
-      }
-    }
-    else {
-      this.sendAsync("isElementDisplayed",
-                     { element:aRequest.element },
-                     command_id);
-    }
-  },
-
-  /**
-   * Return the property of the computed style of an element
-   *
-   * @param object aRequest
-   *               'element' member holds the reference id to
-   *               the element that will be checked
-   *               'propertyName' is the CSS rule that is being requested
-   */
-  getElementValueOfCssProperty: function MDA_getElementValueOfCssProperty(aRequest){
-    let command_id = this.command_id = this.getCommandId();
-    this.sendAsync("getElementValueOfCssProperty",
-                   {element: aRequest.element, propertyName: aRequest.propertyName},
-                   command_id);
-  },
-
-  /**
-   * Check if element is enabled
-   *
-   * @param object aRequest
-   *        'element' member holds the reference id to
-   *        the element that will be checked
-   */
-  isElementEnabled: function MDA_isElementEnabled(aRequest) {
-    let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
-      try {
-        //Selenium atom doesn't quite work here
-        let el = this.curBrowser.elementManager.getKnownElement(
-            aRequest.element, this.getCurrentWindow());
-        if (el.disabled != undefined) {
-          this.sendResponse(!!!el.disabled, command_id);
-        }
-        else {
-        this.sendResponse(true, command_id);
-        }
-      }
-      catch (e) {
-        this.sendError(e.message, e.code, e.stack, command_id);
-      }
-    }
-    else {
-      this.sendAsync("isElementEnabled",
-                     { element:aRequest.element },
-                     command_id);
-    }
-  },
-
-  /**
-   * Check if element is selected
-   *
-   * @param object aRequest
-   *        'element' member holds the reference id to
-   *        the element that will be checked
-   */
-  isElementSelected: function MDA_isElementSelected(aRequest) {
-    let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
-      try {
-        //Selenium atom doesn't quite work here
-        let el = this.curBrowser.elementManager.getKnownElement(
-            aRequest.element, this.getCurrentWindow());
-        if (el.checked != undefined) {
-          this.sendResponse(!!el.checked, command_id);
-        }
-        else if (el.selected != undefined) {
-          this.sendResponse(!!el.selected, command_id);
-        }
-        else {
-          this.sendResponse(true, command_id);
-        }
-      }
-      catch (e) {
-        this.sendError(e.message, e.code, e.stack, command_id);
-      }
-    }
-    else {
-      this.sendAsync("isElementSelected",
-                     { element:aRequest.element },
-                     command_id);
-    }
-  },
-
-  getElementSize: function MDA_getElementSize(aRequest) {
-    let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
-      try {
-        let el = this.curBrowser.elementManager.getKnownElement(
-            aRequest.element, this.getCurrentWindow());
-        let clientRect = el.getBoundingClientRect();  
-        this.sendResponse({width: clientRect.width, height: clientRect.height},
-                          command_id);
-      }
-      catch (e) {
-        this.sendError(e.message, e.code, e.stack, command_id);
-      }
-    }
-    else {
-      this.sendAsync("getElementSize",
-                     { element:aRequest.element },
-                     command_id);
-    }
-  },
-
-  /**
-   * Send key presses to element after focusing on it
-   *
-   * @param object aRequest
-   *        'element' member holds the reference id to
-   *        the element that will be checked
-   *        'value' member holds the value to send to the element
-   */
-  sendKeysToElement: function MDA_sendKeysToElement(aRequest) {
-    let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
-      try {
-        let el = this.curBrowser.elementManager.getKnownElement(
-            aRequest.element, this.getCurrentWindow());
-        el.focus();
-        utils.sendString(aRequest.value.join(""), utils.window);
-        this.sendOk(command_id);
-      }
-      catch (e) {
-        this.sendError(e.message, e.code, e.stack, command_id);
-      }
-    }
-    else {
-      this.sendAsync("sendKeysToElement",
-                     {
-                       element:aRequest.element,
-                       value: aRequest.value
-                     },
-                     command_id);
-    }
-  },
-
-  /**
-   * Sets the test name
-   *
-   * The test name is used in logging messages.
-   */
-  setTestName: function MDA_setTestName(aRequest) {
-    this.command_id = this.getCommandId();
-    this.logRequest("setTestName", aRequest);
-    this.testName = aRequest.value;
-    this.sendAsync("setTestName",
-                   { value: aRequest.value },
-                   this.command_id);
-  },
-
-  /**
-   * Clear the text of an element
-   *
-   * @param object aRequest
-   *        'element' member holds the reference id to
-   *        the element that will be cleared 
-   */
-  clearElement: function MDA_clearElement(aRequest) {
-    let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
-      //the selenium atom doesn't work here
-      try {
-        let el = this.curBrowser.elementManager.getKnownElement(
-            aRequest.element, this.getCurrentWindow());
-        if (el.nodeName == "textbox") {
-          el.value = "";
-        }
-        else if (el.nodeName == "checkbox") {
-          el.checked = false;
-        }
-        this.sendOk(command_id);
-      }
-      catch (e) {
-        this.sendError(e.message, e.code, e.stack, command_id);
-      }
-    }
-    else {
-      this.sendAsync("clearElement",
-                     { element:aRequest.element },
-                     command_id);
-    }
-  },
-
-  getElementPosition: function MDA_getElementPosition(aRequest) {
-    this.command_id = this.getCommandId();
-    this.sendAsync("getElementPosition",
-                   { element:aRequest.element },
-                   this.command_id);
-  },
-
-  /**
-   * Add a cookie to the document.
-   */
-  addCookie: function MDA_addCookie(aRequest) {
-    this.command_id = this.getCommandId();
-    this.sendAsync("addCookie",
-                   { cookie:aRequest.cookie },
-                   this.command_id);
-  },
-
-  /**
-   * Get all visible cookies for a document
-   */
-  getAllCookies: function MDA_getAllCookies() {
-    this.command_id = this.getCommandId();
-    this.sendAsync("getAllCookies", {}, this.command_id);
-  },
-
-  /**
-   * Delete all cookies that are visible to a document
-   */
-  deleteAllCookies: function MDA_deleteAllCookies() {
-    this.command_id = this.getCommandId();
-    this.sendAsync("deleteAllCookies", {}, this.command_id);
-  },
-
-  /**
-   * Delete a cookie by name
-   */
-  deleteCookie: function MDA_deleteCookie(aRequest) {
-    this.command_id = this.getCommandId();
-    this.sendAsync("deleteCookie",
-                   { name:aRequest.name },
-                   this.command_id);
-  },
-
-  /**
-   * Closes the Browser Window.
-   *
-   * If it is B2G it returns straight away and does not do anything
-   *
-   * If is desktop it calculates how many windows are open and if there is only 
-   * 1 then it deletes the session otherwise it closes the window
-   */
-  closeWindow: function MDA_closeWindow() {
-    let command_id = this.command_id = this.getCommandId();
-    if (appName == "B2G") {
-      // We can't close windows so just return
-      this.sendOk(command_id);
-    }
-    else {
-      // Get the total number of windows
-      let numOpenWindows = 0;
-      let winEnum = this.getWinEnumerator();
-      while (winEnum.hasMoreElements()) {
-        numOpenWindows += 1;
-        winEnum.getNext(); 
-      }
-
-      // if there is only 1 window left, delete the session
-      if (numOpenWindows === 1){
-        this.deleteSession();
-        return;
-      }
-
-      try{
-        this.messageManager.removeDelayedFrameScript(FRAME_SCRIPT); 
-        this.getCurrentWindow().close();
-        this.sendOk(command_id);
-      }
-      catch (e) {
-        this.sendError("Could not close window: " + e.message, 13, e.stack,
-                       command_id);
-      }
-    }
-  }, 
-
-  /**
-   * Deletes the session.
-   * 
-   * If it is a desktop environment, it will close the session's tab and close all listeners
-   *
-   * If it is a B2G environment, it will make the main content listener sleep, and close
-   * all other listeners. The main content listener persists after disconnect (it's the homescreen),
-   * and can safely be reused.
-   */
-  deleteSession: function MDA_deleteSession() {
-    let command_id = this.command_id = this.getCommandId();
-    if (this.curBrowser != null) {
-      if (appName == "B2G") {
-        this.globalMessageManager.broadcastAsyncMessage(
-            "Marionette:sleepSession" + this.curBrowser.mainContentId, {});
-        this.curBrowser.knownFrames.splice(
-            this.curBrowser.knownFrames.indexOf(this.curBrowser.mainContentId), 1);
-      }
-      else {
-        //don't set this pref for B2G since the framescript can be safely reused
-        Services.prefs.setBoolPref("marionette.contentListener", false);
-      }
-      this.curBrowser.closeTab();
-      //delete session in each frame in each browser
-      for (let win in this.browsers) {
-        for (let i in this.browsers[win].knownFrames) {
-          this.globalMessageManager.broadcastAsyncMessage("Marionette:deleteSession" + this.browsers[win].knownFrames[i], {});
-        }
-      }
-      let winEnum = this.getWinEnumerator();
-      while (winEnum.hasMoreElements()) {
-        winEnum.getNext().messageManager.removeDelayedFrameScript(FRAME_SCRIPT); 
-      }
-    }
-    this.sendOk(command_id);
-    this.removeMessageManagerListeners(this.globalMessageManager);
-    this.switchToGlobalMessageManager();
-    // reset frame to the top-most frame
-    this.curFrame = null;
-    if (this.mainFrame) {
-      this.mainFrame.focus();
-    }
-    this.curBrowser = null;
-    try {
-      this.importedScripts.remove(false);
-    }
-    catch (e) {
-    }
-  },
-
-  /**
-   * Returns the current status of the Application Cache
-   */
-  getAppCacheStatus: function MDA_getAppCacheStatus(aRequest) {
-    this.command_id = this.getCommandId();
-    this.sendAsync("getAppCacheStatus", {}, this.command_id);
-  },
-
-  _emu_cb_id: 0,
-  _emu_cbs: null,
-  runEmulatorCmd: function runEmulatorCmd(cmd, callback) {
-    if (callback) {
-      if (!this._emu_cbs) {
-        this._emu_cbs = {};
-      }
-      this._emu_cbs[this._emu_cb_id] = callback;
-    }
-    this.sendToClient({emulator_cmd: cmd, id: this._emu_cb_id}, -1);
-    this._emu_cb_id += 1;
-  },
-
-  emulatorCmdResult: function emulatorCmdResult(message) {
-    if (this.context != "chrome") {
-      this.sendAsync("emulatorCmdResult", message, -1);
-      return;
-    }
-
-    if (!this._emu_cbs) {
-      return;
-    }
-
-    let cb = this._emu_cbs[message.id];
-    delete this._emu_cbs[message.id];
-    if (!cb) {
-      return;
-    }
-    try {
-      cb(message.result);
-    }
-    catch(e) {
-      this.sendError(e.message, e.code, e.stack, -1);
-      return;
-    }
-  },
-  
-  importScript: function MDA_importScript(aRequest) {
-    let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
-      let file;
-      if (this.importedScripts.exists()) {
-        file = FileUtils.openFileOutputStream(this.importedScripts,
-            FileUtils.MODE_APPEND | FileUtils.MODE_WRONLY);
-      }
-      else {
-        //Note: The permission bits here don't actually get set (bug 804563)
-        this.importedScripts.createUnique(
-            Components.interfaces.nsIFile.NORMAL_FILE_TYPE, parseInt("0666", 8));
-        file = FileUtils.openFileOutputStream(this.importedScripts,
-            FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE);
-        this.importedScripts.permissions = parseInt("0666", 8); //actually set permissions
-      }
-      file.write(aRequest.script, aRequest.script.length);
-      file.close();
-      this.sendOk(command_id);
-    }
-    else {
-      this.sendAsync("importScript",
-                     { script: aRequest.script },
-                     command_id);
-    }
-  },
-
-  /**
-   * Takes a screenshot of a DOM node. If there is no node given a screenshot
-   * of the window will be taken.
-   */
-  screenShot: function MDA_saveScreenshot(aRequest) {
-    this.command_id = this.getCommandId();
-    this.sendAsync("screenShot",
-                   {
-                     element: aRequest.element,
-                     highlights: aRequest.highlights
-                   },
-                   this.command_id);
-  },
-
-  /**
-   * Helper function to convert an outerWindowID into a UID that Marionette
-   * tracks.
-   */
-  generateFrameId: function MDA_generateFrameId(id) {
-    let uid = id + (appName == "B2G" ? "-b2g" : "");
-    return uid;
-  },
-
-  /**
-   * Receives all messages from content messageManager
-   */
-  receiveMessage: function MDA_receiveMessage(message) {
-    // We need to just check if we need to remove the mozbrowserclose listener
-    if (this.mozBrowserClose !== null){
-      let curWindow = this.getCurrentWindow();
-      curWindow.removeEventListener('mozbrowserclose', this.mozBrowserClose, true);
-      this.mozBrowserClose = null;
-    }
-
-    switch (message.name) {
-      case "Marionette:done":
-        this.sendResponse(message.json.value, message.json.command_id);
-        break;
-      case "Marionette:ok":
-        this.sendOk(message.json.command_id);
-        break;
-      case "Marionette:error":
-        this.sendError(message.json.message, message.json.status, message.json.stacktrace, message.json.command_id);
-        break;
-      case "Marionette:log":
-        //log server-side messages
-        logger.info(message.json.message);
-        break;
-      case "Marionette:shareData":
-        //log messages from tests
-        if (message.json.log) {
-          this.marionetteLog.addLogs(message.json.log);
-        }
-        break;
-      case "Marionette:runEmulatorCmd":
-        this.sendToClient(message.json, -1);
-        break;
-      case "Marionette:switchToFrame":
-        // Switch to a remote frame.
-        let frameWindow = Services.wm.getOuterWindowWithId(message.json.win);
-        let thisFrame = frameWindow.document.getElementsByTagName("iframe")[message.json.frame];
-        let mm = thisFrame.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader.messageManager;
-
-        // See if this frame already has our frame script loaded in it; if so,
-        // just wake it up.
-        for (let i = 0; i < remoteFrames.length; i++) {
-          let frame = remoteFrames[i];
-          if ((frame.messageManager == mm)) {
-            this.currentRemoteFrame = frame;
-            this.currentRemoteFrame.command_id = message.json.command_id;
-            this.messageManager = frame.messageManager;
-            this.addMessageManagerListeners(this.messageManager);
-            this.messageManager.sendAsyncMessage("Marionette:restart", {});
-            return;
-          }
-        }
-
-        // Load the frame script in this frame, and set the frame's ChromeMessageSender
-        // as the active message manager.
-        this.addMessageManagerListeners(mm);
-        mm.loadFrameScript(FRAME_SCRIPT, true);
-        this.messageManager = mm;
-        let aFrame = new MarionetteRemoteFrame(message.json.win, message.json.frame);
-        aFrame.messageManager = this.messageManager;
-        aFrame.command_id = message.json.command_id;
-        remoteFrames.push(aFrame);
-        this.currentRemoteFrame = aFrame;
-        break;
-      case "Marionette:register":
-        // This code processes the content listener's registration information
-        // and either accepts the listener, or ignores it
-        let nullPrevious = (this.curBrowser.curFrameId == null);
-        let listenerWindow =
-          Services.wm.getOuterWindowWithId(message.json.value);
-
-        if (!listenerWindow || (listenerWindow.location.href != message.json.href) &&
-            (this.currentRemoteFrame !== null)) {
-          // The outerWindowID from an OOP frame will not be meaningful to
-          // the parent process here, since each process maintains its own
-          // independent window list.  So, it will either be null (!listenerWindow)
-          // or it will point to some random window, which will hopefully 
-          // cause an href mistmach.  Currently this only happens
-          // in B2G for OOP frames registered in Marionette:switchToFrame, so
-          // we'll acknowledge the switchToFrame message here.
-          // XXX: Should have a better way of determining that this message
-          // is from a remote frame.
-          this.currentRemoteFrame.targetFrameId = this.generateFrameId(message.json.value);
-          this.sendOk(this.currentRemoteFrame.command_id);
-        }
-
-        let browserType;
-        try {
-          browserType = message.target.getAttribute("type");
-        } catch (ex) {
-          // browserType remains undefined.
-        }
-        let reg = {};
-        if (!browserType || browserType != "content") {
-          reg.id = this.curBrowser.register(this.generateFrameId(message.json.value),
-                                            listenerWindow);
-        }
-        this.curBrowser.elementManager.seenItems[reg.id] = Cu.getWeakReference(listenerWindow);
-        reg.importedScripts = this.importedScripts.path;
-        if (nullPrevious && (this.curBrowser.curFrameId != null)) {
-          if (!this.sendAsync("newSession",
-                              { B2G: (appName == "B2G") },
-                              this.newSessionCommandId)) {
-            return;
-          }
-          if (this.curBrowser.newSession) {
-            this.sendResponse(reg.id, this.newSessionCommandId);
-            this.newSessionCommandId = null;
-          }
-        }
-        return reg;
-    }
-  }
-};
-
-MarionetteDriverActor.prototype.requestTypes = {
-  "newSession": MarionetteDriverActor.prototype.newSession,
-  "getSessionCapabilities": MarionetteDriverActor.prototype.getSessionCapabilities,
-  "getStatus": MarionetteDriverActor.prototype.getStatus,
-  "log": MarionetteDriverActor.prototype.log,
-  "getLogs": MarionetteDriverActor.prototype.getLogs,
-  "setContext": MarionetteDriverActor.prototype.setContext,
-  "executeScript": MarionetteDriverActor.prototype.execute,
-  "setScriptTimeout": MarionetteDriverActor.prototype.setScriptTimeout,
-  "timeouts": MarionetteDriverActor.prototype.timeouts,
-  "singleTap": MarionetteDriverActor.prototype.singleTap,
-  "actionChain": MarionetteDriverActor.prototype.actionChain,
-  "multiAction": MarionetteDriverActor.prototype.multiAction,
-  "executeAsyncScript": MarionetteDriverActor.prototype.executeWithCallback,
-  "executeJSScript": MarionetteDriverActor.prototype.executeJSScript,
-  "setSearchTimeout": MarionetteDriverActor.prototype.setSearchTimeout,
-  "findElement": MarionetteDriverActor.prototype.findElement,
-  "findElements": MarionetteDriverActor.prototype.findElements,
-  "clickElement": MarionetteDriverActor.prototype.clickElement,
-  "getElementAttribute": MarionetteDriverActor.prototype.getElementAttribute,
-  "getElementText": MarionetteDriverActor.prototype.getElementText,
-  "getElementTagName": MarionetteDriverActor.prototype.getElementTagName,
-  "isElementDisplayed": MarionetteDriverActor.prototype.isElementDisplayed,
-  "getElementValueOfCssProperty": MarionetteDriverActor.prototype.getElementValueOfCssProperty,
-  "getElementSize": MarionetteDriverActor.prototype.getElementSize,
-  "isElementEnabled": MarionetteDriverActor.prototype.isElementEnabled,
-  "isElementSelected": MarionetteDriverActor.prototype.isElementSelected,
-  "sendKeysToElement": MarionetteDriverActor.prototype.sendKeysToElement,
-  "getElementPosition": MarionetteDriverActor.prototype.getElementPosition,
-  "clearElement": MarionetteDriverActor.prototype.clearElement,
-  "getTitle": MarionetteDriverActor.prototype.getTitle,
-  "getWindowType": MarionetteDriverActor.prototype.getWindowType,
-  "getPageSource": MarionetteDriverActor.prototype.getPageSource,
-  "goUrl": MarionetteDriverActor.prototype.goUrl,
-  "getUrl": MarionetteDriverActor.prototype.getUrl,
-  "goBack": MarionetteDriverActor.prototype.goBack,
-  "goForward": MarionetteDriverActor.prototype.goForward,
-  "refresh":  MarionetteDriverActor.prototype.refresh,
-  "getWindow":  MarionetteDriverActor.prototype.getWindow,
-  "getWindows":  MarionetteDriverActor.prototype.getWindows,
-  "switchToFrame": MarionetteDriverActor.prototype.switchToFrame,
-  "switchToWindow": MarionetteDriverActor.prototype.switchToWindow,
-  "deleteSession": MarionetteDriverActor.prototype.deleteSession,
-  "emulatorCmdResult": MarionetteDriverActor.prototype.emulatorCmdResult,
-  "importScript": MarionetteDriverActor.prototype.importScript,
-  "getAppCacheStatus": MarionetteDriverActor.prototype.getAppCacheStatus,
-  "closeWindow": MarionetteDriverActor.prototype.closeWindow,
-  "setTestName": MarionetteDriverActor.prototype.setTestName,
-  "screenShot": MarionetteDriverActor.prototype.screenShot,
-  "addCookie": MarionetteDriverActor.prototype.addCookie,
-  "getAllCookies": MarionetteDriverActor.prototype.getAllCookies,
-  "deleteAllCookies": MarionetteDriverActor.prototype.deleteAllCookies,
-  "deleteCookie": MarionetteDriverActor.prototype.deleteCookie,
-  "getActiveElement": MarionetteDriverActor.prototype.getActiveElement
-};
-
-/**
- * Creates a BrowserObj. BrowserObjs handle interactions with the
- * browser, according to the current environment (desktop, b2g, etc.)
- *
- * @param nsIDOMWindow win
- *        The window whose browser needs to be accessed
- */
-
-function BrowserObj(win) {
-  this.DESKTOP = "desktop";
-  this.B2G = "B2G";
-  this.browser;
-  this.tab = null;
-  this.window = win;
-  this.knownFrames = [];
-  this.curFrameId = null;
-  this.startPage = "about:blank";
-  this.mainContentId = null; // used in B2G to identify the homescreen content page
-  this.newSession = true; //used to set curFrameId upon new session
-  this.elementManager = new ElementManager([SELECTOR, NAME, LINK_TEXT, PARTIAL_LINK_TEXT]);
-  this.setBrowser(win);
-}
-
-BrowserObj.prototype = {
-  /**
-   * Set the browser if the application is not B2G
-   *
-   * @param nsIDOMWindow win
-   *        current window reference
-   */
-  setBrowser: function BO_setBrowser(win) {
-    switch (appName) {
-      case "Firefox":
-        this.browser = win.gBrowser;
-        break;
-      case "Fennec":
-        this.browser = win.BrowserApp;
-        break;
-    }
-  },
-  /**
-   * Called when we start a session with this browser.
-   *
-   * In a desktop environment, if newTab is true, it will start 
-   * a new 'about:blank' tab and change focus to this tab.
-   *
-   * This will also set the active messagemanager for this object
-   *
-   * @param boolean newTab
-   *        If true, create new tab
-   */
-  startSession: function BO_startSession(newTab, win, callback) {
-    if (appName != "Firefox") {
-      callback(win, newTab);
-    }
-    else if (newTab) {
-      this.tab = this.addTab(this.startPage);
-      //if we have a new tab, make it the selected tab
-      this.browser.selectedTab = this.tab;
-      let newTabBrowser = this.browser.getBrowserForTab(this.tab);
-      // wait for tab to be loaded
-      newTabBrowser.addEventListener("load", function onLoad() {
-        newTabBrowser.removeEventListener("load", onLoad, true);
-        callback(win, newTab);
-      }, true);
-    }
-    else {
-      //set this.tab to the currently focused tab
-      if (this.browser != undefined && this.browser.selectedTab != undefined) {
-        this.tab = this.browser.selectedTab;
-      }
-      callback(win, newTab);
-    }
-  },
-
-  /**
-   * Closes current tab
-   */
-  closeTab: function BO_closeTab() {
-    if (this.tab != null && (appName != "B2G")) {
-      this.browser.removeTab(this.tab);
-      this.tab = null;
-    }
-  },
-
-  /**
-   * Opens a tab with given uri
-   *
-   * @param string uri
-   *      URI to open
-   */
-  addTab: function BO_addTab(uri) {
-    return this.browser.addTab(uri, true);
-  },
-
-  /**
-   * Loads content listeners if we don't already have them
-   *
-   * @param string script
-   *        path of script to load
-   * @param nsIDOMWindow frame
-   *        frame to load the script in
-   */
-  loadFrameScript: function BO_loadFrameScript(script, frame) {
-    frame.window.messageManager.loadFrameScript(script, true);
-    Services.prefs.setBoolPref("marionette.contentListener", true);
-  },
-
-  /**
-   * Registers a new frame, and sets its current frame id to this frame
-   * if it is not already assigned, and if a) we already have a session 
-   * or b) we're starting a new session and it is the right start frame.
-   *
-   * @param string uid
-   *        frame uid
-   * @param object frameWindow
-   *        the DOMWindow object of the frame that's being registered
-   */
-  register: function BO_register(uid, frameWindow) {
-    if (this.curFrameId == null) {
-      // If we're setting up a new session on Firefox, we only process the
-      // registration for this frame if it belongs to the tab we've just
-      // created.
-      if ((!this.newSession) ||
-          (this.newSession &&
-            ((appName != "Firefox") ||
-             frameWindow == this.browser.getBrowserForTab(this.tab).contentWindow))) {
-        this.curFrameId = uid;
-        this.mainContentId = uid;
-      }
-    }
-    this.knownFrames.push(uid); //used to delete sessions
-    return uid;
-  },
-}
--- a/testing/marionette/marionette-listener.js
+++ b/testing/marionette/marionette-listener.js
@@ -62,16 +62,21 @@ let nextTouchId = 1000;
 //Keep track of active Touches
 let touchIds = {};
 // last touch for each fingerId
 let multiLast = {};
 let lastCoordinates = null;
 let isTap = false;
 // whether to send mouse event
 let mouseEventsOnly = false;
+
+Cu.import("resource://gre/modules/services-common/log4moz.js");
+let logger = Log4Moz.repository.getLogger("Marionette");
+logger.info("loaded marionette-listener.js");
+
 /**
  * Called when listener is first started up. 
  * The listener sends its unique window ID and its current URI to the actor.
  * If the actor returns an ID, we start the listeners. Otherwise, nothing happens.
  */
 function registerSelf() {
   let msg = {value: winUtil.outerWindowID, href: content.location.href};
   let register = sendSyncMessage("Marionette:register", msg);
--- a/testing/marionette/marionette-log-obj.js
+++ b/testing/marionette/marionette-log-obj.js
@@ -1,13 +1,13 @@
 /* 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/. */
 
-function MarionetteLogObj() {
+this.MarionetteLogObj = function MarionetteLogObj() {
   this.logs = [];
 }
 MarionetteLogObj.prototype = {
   /**
    * Log message. Accepts user defined log-level.
    * @param msg String
    *        The message to be logged
    * @param level String
new file mode 100644
--- /dev/null
+++ b/testing/marionette/marionette-server.js
@@ -0,0 +1,2405 @@
+/* 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/. */
+
+"use strict";
+
+const FRAME_SCRIPT = "chrome://marionette/content/marionette-listener.js";
+
+// import logger
+Cu.import("resource://gre/modules/services-common/log4moz.js");
+let logger = Log4Moz.repository.getLogger("Marionette");
+logger.info('marionette-server.js loaded');
+
+let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
+               .getService(Ci.mozIJSSubScriptLoader);
+loader.loadSubScript("chrome://marionette/content/marionette-simpletest.js");
+loader.loadSubScript("chrome://marionette/content/marionette-log-obj.js");
+Cu.import("chrome://marionette/content/marionette-elements.js");
+let utils = {};
+loader.loadSubScript("chrome://marionette/content/EventUtils.js", utils);
+loader.loadSubScript("chrome://marionette/content/ChromeUtils.js", utils);
+loader.loadSubScript("chrome://marionette/content/atoms.js", utils);
+
+let specialpowers = {};
+loader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserver.js",
+                     specialpowers);
+specialpowers.specialPowersObserver = new specialpowers.SpecialPowersObserver();
+specialpowers.specialPowersObserver.init();
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/FileUtils.jsm");
+Cu.import("resource://gre/modules/NetUtil.jsm");  
+
+Services.prefs.setBoolPref("marionette.contentListener", false);
+let appName = Services.appinfo.name;
+
+// dumpn needed/used by dbg-transport.js
+this.dumpn = function dumpn(str) {
+  logger.trace(str);
+}
+loader.loadSubScript("resource://gre/modules/devtools/DevToolsUtils.js");
+loader.loadSubScript("resource://gre/modules/devtools/server/transport.js");
+
+let bypassOffline = false;
+
+try {
+  XPCOMUtils.defineLazyGetter(this, "libcutils", function () {
+    Cu.import("resource://gre/modules/systemlibs.js");
+    return libcutils;
+  });
+  if (libcutils) {
+    let qemu = libcutils.property_get("ro.kernel.qemu");
+    logger.info("B2G emulator: " + (qemu == "1" ? "yes" : "no"));
+    let platform = libcutils.property_get("ro.product.device");
+    logger.info("Platform detected is " + platform);
+    bypassOffline = (qemu == "1" || platform == "panda");
+  }
+}
+catch(e) {}
+
+if (bypassOffline) {
+  logger.info("Bypassing offline status.");
+  Services.prefs.setBoolPref("network.gonk.manage-offline-status", false);
+  Services.io.manageOfflineStatus = false;
+  Services.io.offline = false;
+}
+
+// This is used to prevent newSession from returning before the telephony
+// API's are ready; see bug 792647.  This assumes that marionette-server.js
+// will be loaded before the 'system-message-listener-ready' message
+// is fired.  If this stops being true, this approach will have to change.
+let systemMessageListenerReady = false;
+Services.obs.addObserver(function() {
+  systemMessageListenerReady = true;
+}, "system-message-listener-ready", false);
+
+/**
+ * An object representing a frame that Marionette has loaded a
+ * frame script in.
+ */
+function MarionetteRemoteFrame(windowId, frameId) {
+  this.windowId = windowId;
+  this.frameId = frameId;
+  this.targetFrameId = null;
+  this.messageManager = null;
+  this.command_id = null;
+}
+// persistent list of remote frames that Marionette has loaded a frame script in
+let remoteFrames = [];
+
+/*
+ * Custom exceptions
+ */
+function FrameSendNotInitializedError(frame) {
+  this.code = 54;
+  this.frame = frame;
+  this.message = "Error sending message to frame (NS_ERROR_NOT_INITIALIZED)";
+  this.toString = function() {
+    return this.message + " " + this.frame + "; frame has closed.";
+  }
+}
+
+function FrameSendFailureError(frame) {
+  this.code = 55;
+  this.frame = frame;
+  this.message = "Error sending message to frame (NS_ERROR_FAILURE)";
+  this.toString = function() {
+    return this.message + " " + this.frame + "; frame not responding.";
+  }
+}
+
+/**
+ * The server connection is responsible for all marionette API calls. It gets created
+ * for each connection and manages all chrome and browser based calls. It
+ * mediates content calls by issuing appropriate messages to the content process.
+ */
+function MarionetteServerConnection(aPrefix, aTransport, aServer)
+{
+  this.uuidGen = Cc["@mozilla.org/uuid-generator;1"]
+                   .getService(Ci.nsIUUIDGenerator);
+
+  this.prefix = aPrefix;
+  this.server = aServer;
+  this.conn = aTransport;
+  this.conn.hooks = this;
+
+  // marionette uses a protocol based on the debugger server, which requires
+  // passing back "actor ids" with responses. unlike the debugger server,
+  // we don't have multiple actors, so just use a dummy value of "0" here
+  this.actorID = "0";
+
+  this.globalMessageManager = Cc["@mozilla.org/globalmessagemanager;1"]
+                             .getService(Ci.nsIMessageBroadcaster);
+  this.messageManager = this.globalMessageManager;
+  this.browsers = {}; //holds list of BrowserObjs
+  this.curBrowser = null; // points to current browser
+  this.context = "content";
+  this.scriptTimeout = null;
+  this.searchTimeout = null;
+  this.pageTimeout = null;
+  this.timer = null;
+  this.marionetteLog = new MarionetteLogObj();
+  this.command_id = null;
+  this.mainFrame = null; //topmost chrome frame
+  this.curFrame = null; //subframe that currently has focus
+  this.importedScripts = FileUtils.getFile('TmpD', ['marionettescriptchrome']);
+  this.currentRemoteFrame = null; // a member of remoteFrames
+  this.testName = null;
+  this.mozBrowserClose = null;
+
+  //register all message listeners
+  this.addMessageManagerListeners(this.messageManager);
+}
+
+MarionetteServerConnection.prototype = {
+
+  /**
+   * Debugger transport callbacks:
+   */
+  onPacket: function MSC_onPacket(aPacket) {
+    // Dispatch the request
+    if (this.requestTypes && this.requestTypes[aPacket.type]) {
+      try {
+        this.requestTypes[aPacket.type].bind(this)(aPacket);
+      } catch(e) {
+        this.conn.send({ error: ("error occurred while processing '" +
+                                 aPacket.type),
+                        message: e });
+      }
+    } else {
+      this.conn.send({ error: "unrecognizedPacketType",
+                       message: ('Marionette does not ' +
+                                 'recognize the packet type "' +
+                                 aPacket.type + '"') });
+    }
+  },
+
+  onClosed: function MSC_onClosed(aStatus) {
+    this.server._connectionClosed(this);
+    this.deleteSession();
+  },
+
+  /**
+   * Helper methods:
+   */
+
+  /**
+   * Switches to the global ChromeMessageBroadcaster, potentially replacing a frame-specific
+   * ChromeMessageSender.  Has no effect if the global ChromeMessageBroadcaster is already
+   * in use.  If this replaces a frame-specific ChromeMessageSender, it removes the message
+   * listeners from that sender, and then puts the corresponding frame script "to sleep",
+   * which removes most of the message listeners from it as well.
+   */
+  switchToGlobalMessageManager: function MDA_switchToGlobalMM() {
+    if (this.currentRemoteFrame !== null) {
+      this.removeMessageManagerListeners(this.messageManager);
+      this.sendAsync("sleepSession", null, null, true);
+    }
+    this.messageManager = this.globalMessageManager;
+    this.currentRemoteFrame = null;
+  },
+
+  /**
+   * Helper method to send async messages to the content listener
+   *
+   * @param string name
+   *        Suffix of the targetted message listener (Marionette:<suffix>)
+   * @param object values
+   *        Object to send to the listener
+   */
+  sendAsync: function MDA_sendAsync(name, values, commandId, ignoreFailure) {
+    let success = true;
+    if (values instanceof Object && commandId) {
+      values.command_id = commandId;
+    }
+    if (this.currentRemoteFrame !== null) {
+      try {
+        this.messageManager.sendAsyncMessage(
+          "Marionette:" + name + this.currentRemoteFrame.targetFrameId, values);
+      }
+      catch(e) {
+        if (!ignoreFailure) {
+          success = false;
+          let error = e;
+          switch(e.result) {
+            case Components.results.NS_ERROR_FAILURE:
+              error = new FrameSendFailureError(this.currentRemoteFrame);
+              break;
+            case Components.results.NS_ERROR_NOT_INITIALIZED:
+              error = new FrameSendNotInitializedError(this.currentRemoteFrame);
+              break;
+            default:
+              break;
+          }
+          let code = error.hasOwnProperty('code') ? e.code : 500;
+          this.sendError(error.toString(), code, error.stack, commandId);
+        }
+      }
+    }
+    else {
+      this.messageManager.broadcastAsyncMessage(
+        "Marionette:" + name + this.curBrowser.curFrameId, values);
+    }
+    return success;
+  },
+
+  /**
+   * Adds listeners for messages from content frame scripts.
+   *
+   * @param object messageManager
+   *        The messageManager object (ChromeMessageBroadcaster or ChromeMessageSender)
+   *        to which the listeners should be added.
+   */
+  addMessageManagerListeners: function MDA_addMessageManagerListeners(messageManager) {
+    messageManager.addMessageListener("Marionette:ok", this);
+    messageManager.addMessageListener("Marionette:done", this);
+    messageManager.addMessageListener("Marionette:error", this);
+    messageManager.addMessageListener("Marionette:log", this);
+    messageManager.addMessageListener("Marionette:shareData", this);
+    messageManager.addMessageListener("Marionette:register", this);
+    messageManager.addMessageListener("Marionette:runEmulatorCmd", this);
+    messageManager.addMessageListener("Marionette:switchToFrame", this);
+  },
+
+  /**
+   * Removes listeners for messages from content frame scripts.
+   *
+   * @param object messageManager
+   *        The messageManager object (ChromeMessageBroadcaster or ChromeMessageSender)
+   *        from which the listeners should be removed.
+   */
+  removeMessageManagerListeners: function MDA_removeMessageManagerListeners(messageManager) {
+    messageManager.removeMessageListener("Marionette:ok", this);
+    messageManager.removeMessageListener("Marionette:done", this);
+    messageManager.removeMessageListener("Marionette:error", this);
+    messageManager.removeMessageListener("Marionette:log", this);
+    messageManager.removeMessageListener("Marionette:shareData", this);
+    messageManager.removeMessageListener("Marionette:register", this);
+    messageManager.removeMessageListener("Marionette:runEmulatorCmd", this);
+    messageManager.removeMessageListener("Marionette:switchToFrame", this);
+  },
+
+  logRequest: function MDA_logRequest(type, data) {
+    logger.debug("Got request: " + type + ", data: " + JSON.stringify(data) + ", id: " + this.command_id);
+  },
+
+  /**
+   * Generic method to pass a response to the client
+   *
+   * @param object msg
+   *        Response to send back to client
+   * @param string command_id
+   *        Unique identifier assigned to the client's request.
+   *        Used to distinguish the asynchronous responses.
+   */
+  sendToClient: function MDA_sendToClient(msg, command_id) {
+    logger.info("sendToClient: " + JSON.stringify(msg) + ", " + command_id +
+                ", " + this.command_id);
+    if (!command_id) {
+      logger.warn("got a response with no command_id");
+      return;
+    }
+    else if (command_id != -1) {
+      // A command_id of -1 is used for emulator callbacks, and those
+      // don't use this.command_id.
+      if (!this.command_id) {
+        // A null value for this.command_id means we've already processed
+        // a message for the previous value, and so the current message is a
+        // duplicate.
+        logger.warn("ignoring duplicate response for command_id " + command_id);
+        return;
+      }
+      else if (this.command_id != command_id) {
+        logger.warn("ignoring out-of-sync response");
+        return;
+      }
+    }
+    this.conn.send(msg);
+    if (command_id != -1) {
+      // Don't unset this.command_id if this message is to process an
+      // emulator callback, since another response for this command_id is
+      // expected, after the containing call to execute_async_script finishes.
+      this.command_id = null;
+    }
+  },
+
+  /**
+   * Send a value to client
+   *
+   * @param object value
+   *        Value to send back to client
+   * @param string command_id
+   *        Unique identifier assigned to the client's request.
+   *        Used to distinguish the asynchronous responses.
+   */
+  sendResponse: function MDA_sendResponse(value, command_id) {
+    if (typeof(value) == 'undefined')
+        value = null;
+    this.sendToClient({from:this.actorID, value: value}, command_id);
+  },
+
+  sayHello: function MDA_sayHello() {
+    this.conn.send({ from: "root",
+                     applicationType: "gecko",
+                     traits: [] });
+  },
+
+  getMarionetteID: function MDA_getMarionette() {
+    this.conn.send({ "from": "root", "id": this.actorID });
+  },
+
+  /**
+   * Send ack to client
+   * 
+   * @param string command_id
+   *        Unique identifier assigned to the client's request.
+   *        Used to distinguish the asynchronous responses.
+   */
+  sendOk: function MDA_sendOk(command_id) {
+    this.sendToClient({from:this.actorID, ok: true}, command_id);
+  },
+
+  /**
+   * Send error message to client
+   *
+   * @param string message
+   *        Error message
+   * @param number status
+   *        Status number
+   * @param string trace
+   *        Stack trace
+   * @param string command_id
+   *        Unique identifier assigned to the client's request.
+   *        Used to distinguish the asynchronous responses.
+   */
+  sendError: function MDA_sendError(message, status, trace, command_id) {
+    let error_msg = {message: message, status: status, stacktrace: trace};
+    this.sendToClient({from:this.actorID, error: error_msg}, command_id);
+  },
+
+  /**
+   * Gets the current active window
+   * 
+   * @return nsIDOMWindow
+   */
+  getCurrentWindow: function MDA_getCurrentWindow() {
+    let type = null;
+    if (this.curFrame == null) {
+      if (this.curBrowser == null) {
+        if (this.context == "content") {
+          type = 'navigator:browser';
+        }
+        return Services.wm.getMostRecentWindow(type);
+      }
+      else {
+        return this.curBrowser.window;
+      }
+    }
+    else {
+      return this.curFrame;
+    }
+  },
+
+  /**
+   * Gets the the window enumerator
+   *
+   * @return nsISimpleEnumerator
+   */
+  getWinEnumerator: function MDA_getWinEnumerator() {
+    let type = null;
+    if (appName != "B2G" && this.context == "content") {
+      type = 'navigator:browser';
+    }
+    return Services.wm.getEnumerator(type);
+  },
+
+  /**
+   * Create a new BrowserObj for window and add to known browsers
+   * 
+   * @param nsIDOMWindow win
+   *        Window for which we will create a BrowserObj
+   *
+   * @return string
+   *        Returns the unique server-assigned ID of the window
+   */
+  addBrowser: function MDA_addBrowser(win) {
+    let browser = new BrowserObj(win);
+    let winId = win.QueryInterface(Ci.nsIInterfaceRequestor).
+                    getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
+    winId = winId + ((appName == "B2G") ? '-b2g' : '');
+    this.browsers[winId] = browser;
+    this.curBrowser = this.browsers[winId];
+    if (this.curBrowser.elementManager.seenItems[winId] == undefined) {
+      //add this to seenItems so we can guarantee the user will get winId as this window's id
+      this.curBrowser.elementManager.seenItems[winId] = Cu.getWeakReference(win);
+    }
+  },
+
+  /**
+   * Start a new session in a new browser. 
+   *
+   * If newSession is true, we will switch focus to the start frame 
+   * when it registers. Also, if it is in desktop, then a new tab 
+   * with the start page uri (about:blank) will be opened.
+   *
+   * @param nsIDOMWindow win
+   *        Window whose browser we need to access
+   * @param boolean newSession
+   *        True if this is the first time we're talking to this browser
+   */
+  startBrowser: function MDA_startBrowser(win, newSession) {
+    this.mainFrame = win;
+    this.curFrame = null;
+    this.addBrowser(win);
+    this.curBrowser.newSession = newSession;
+    this.curBrowser.startSession(newSession, win, this.whenBrowserStarted.bind(this));
+  },
+
+  /**
+   * Callback invoked after a new session has been started in a browser.
+   * Loads the Marionette frame script into the browser if needed.
+   *
+   * @param nsIDOMWindow win
+   *        Window whose browser we need to access
+   * @param boolean newSession
+   *        True if this is the first time we're talking to this browser
+   */
+  whenBrowserStarted: function MDA_whenBrowserStarted(win, newSession) {
+    try {
+      if (!Services.prefs.getBoolPref("marionette.contentListener") || !newSession) {
+        this.curBrowser.loadFrameScript(FRAME_SCRIPT, win);
+      }
+    }
+    catch (e) {
+      //there may not always be a content process
+      logger.info("could not load listener into content for page: " + win.location.href);
+    }
+    utils.window = win;
+  },
+
+  /**
+   * Recursively get all labeled text
+   *
+   * @param nsIDOMElement el
+   *        The parent element
+   * @param array lines
+   *        Array that holds the text lines
+   */
+  getVisibleText: function MDA_getVisibleText(el, lines) {
+    let nodeName = el.nodeName;
+    try {
+      if (utils.isElementDisplayed(el)) {
+        if (el.value) {
+          lines.push(el.value);
+        }
+        for (var child in el.childNodes) {
+          this.getVisibleText(el.childNodes[child], lines);
+        };
+      }
+    }
+    catch (e) {
+      if (nodeName == "#text") {
+        lines.push(el.textContent);
+      }
+    }
+  },
+
+  getCommandId: function MDA_getCommandId() {
+    return this.uuidGen.generateUUID().toString();
+  },
+
+  /**
+   * Marionette API:
+   *
+   * All methods implementing a command from the client should create a
+   * command_id, and then use this command_id in all messages exchanged with
+   * the frame scripts and with responses sent to the client.  This prevents
+   * commands and responses from getting out-of-sync, which can happen in
+   * the case of execute_async calls that timeout and then later send a
+   * response, and other situations.  See bug 779011. See setScriptTimeout()
+   * for a basic example.
+   */
+
+  /**
+   * Create a new session. This creates a BrowserObj.
+   *
+   * In a desktop environment, this opens a new 'about:blank' tab for 
+   * the client to test in.
+   *
+   */
+  newSession: function MDA_newSession() {
+    this.command_id = this.getCommandId();
+    this.newSessionCommandId = this.command_id;
+
+    this.scriptTimeout = 10000;
+
+    function waitForWindow() {
+      let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+      let win = this.getCurrentWindow();
+      if (!win ||
+          (appName == "Firefox" && !win.gBrowser) ||
+          (appName == "Fennec" && !win.BrowserApp)) { 
+        checkTimer.initWithCallback(waitForWindow.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
+      }
+      else {
+        this.startBrowser(win, true);
+      }
+    }
+
+    this.switchToGlobalMessageManager();
+
+    if (!Services.prefs.getBoolPref("marionette.contentListener")) {
+      waitForWindow.call(this);
+    }
+    else if ((appName != "Firefox") && (this.curBrowser == null)) {
+      //if there is a content listener, then we just wake it up
+      this.addBrowser(this.getCurrentWindow());
+      this.curBrowser.startSession(false, this.getCurrentWindow(), this.whenBrowserStarted);
+      this.messageManager.broadcastAsyncMessage("Marionette:restart", {});
+    }
+    else {
+      this.sendError("Session already running", 500, null, this.command_id);
+    }
+  },
+
+  getSessionCapabilities: function MDA_getSessionCapabilities(){
+    this.command_id = this.getCommandId();
+
+    let rotatable = appName == "B2G" ? true : false;
+
+    let value = {
+          'appBuildId' : Services.appinfo.appBuildID,
+          'XULappId' : Services.appinfo.ID,
+          'cssSelectorsEnabled': true,
+          'browserName': appName,
+          'handlesAlerts': false,
+          'javascriptEnabled': true,
+          'nativeEvents': false,
+          'platform': Services.appinfo.OS,
+          'rotatable': rotatable,
+          'takesScreenshot': false,
+          'version': Services.appinfo.version
+    };
+
+    this.sendResponse(value, this.command_id);
+  },
+
+  getStatus: function MDA_getStatus(){
+    this.command_id = this.getCommandId();
+
+    let arch;
+    try {
+      arch = (Services.appinfo.XPCOMABI || 'unknown').split('-')[0]
+    }
+    catch (ignored) {
+      arch = 'unknown'
+    };
+
+    let value = {
+          'os': {
+            'arch': arch,
+            'name': Services.appinfo.OS,
+            'version': 'unknown'
+          },
+          'build': {
+            'revision': 'unknown',
+            'time': Services.appinfo.platformBuildID,
+            'version': Services.appinfo.version
+          }
+    };
+
+    this.sendResponse(value, this.command_id);
+  },
+
+  /**
+   * Log message. Accepts user defined log-level.
+   *
+   * @param object aRequest
+   *        'value' member holds log message
+   *        'level' member hold log level
+   */
+  log: function MDA_log(aRequest) {
+    this.command_id = this.getCommandId();
+    this.marionetteLog.log(aRequest.value, aRequest.level);
+    this.sendOk(this.command_id);
+  },
+
+  /**
+   * Return all logged messages.
+   */
+  getLogs: function MDA_getLogs() {
+    this.command_id = this.getCommandId();
+    this.sendResponse(this.marionetteLog.getLogs(), this.command_id);
+  },
+
+  /**
+   * Sets the context of the subsequent commands to be either 'chrome' or 'content'
+   *
+   * @param object aRequest
+   *        'value' member holds the name of the context to be switched to
+   */
+  setContext: function MDA_setContext(aRequest) {
+    this.command_id = this.getCommandId();
+    this.logRequest("setContext", aRequest);
+    let context = aRequest.value;
+    if (context != "content" && context != "chrome") {
+      this.sendError("invalid context", 500, null, this.command_id);
+    }
+    else {
+      this.context = context;
+      this.sendOk(this.command_id);
+    }
+  },
+
+  /**
+   * Returns a chrome sandbox that can be used by the execute_foo functions.
+   *
+   * @param nsIDOMWindow aWindow
+   *        Window in which we will execute code
+   * @param Marionette marionette
+   *        Marionette test instance
+   * @param object args
+   *        Client given args
+   * @return Sandbox
+   *        Returns the sandbox
+   */
+  createExecuteSandbox: function MDA_createExecuteSandbox(aWindow, marionette, args, specialPowers, command_id) {
+    try {
+      args = this.curBrowser.elementManager.convertWrappedArguments(args, aWindow);
+    }
+    catch(e) {
+      this.sendError(e.message, e.code, e.stack, command_id);
+      return;
+    }
+
+    let _chromeSandbox = new Cu.Sandbox(aWindow,
+       { sandboxPrototype: aWindow, wantXrays: false, sandboxName: ''});
+    _chromeSandbox.__namedArgs = this.curBrowser.elementManager.applyNamedArgs(args);
+    _chromeSandbox.__marionetteParams = args;
+    _chromeSandbox.testUtils = utils;
+
+    marionette.exports.forEach(function(fn) {
+      try {
+        _chromeSandbox[fn] = marionette[fn].bind(marionette);
+      }
+      catch(e) {
+        _chromeSandbox[fn] = marionette[fn];
+      }
+    });
+
+    _chromeSandbox.isSystemMessageListenerReady =
+        function() { return systemMessageListenerReady; }
+
+    if (specialPowers == true) {
+      loader.loadSubScript("chrome://specialpowers/content/specialpowersAPI.js",
+                           _chromeSandbox);
+      loader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserverAPI.js",
+                           _chromeSandbox);
+      loader.loadSubScript("chrome://specialpowers/content/ChromePowers.js",
+                           _chromeSandbox);
+    }
+
+    return _chromeSandbox;
+  },
+
+  /**
+   * Executes a script in the given sandbox.
+   *
+   * @param Sandbox sandbox
+   *        Sandbox in which the script will run
+   * @param string script
+   *        The script to run
+   * @param boolean directInject
+   *        If true, then the script will be run as is,
+   *        and not as a function body (as you would
+   *        do using the WebDriver spec)
+   * @param boolean async
+   *        True if the script is asynchronous
+   */
+  executeScriptInSandbox: function MDA_executeScriptInSandbox(sandbox, script,
+     directInject, async, command_id, timeout) {
+
+    if (directInject && async &&
+        (timeout == null || timeout == 0)) {
+      this.sendError("Please set a timeout", 21, null, command_id);
+      return;
+    }
+
+    if (this.importedScripts.exists()) {
+      let stream = Cc["@mozilla.org/network/file-input-stream;1"].  
+                    createInstance(Ci.nsIFileInputStream);
+      stream.init(this.importedScripts, -1, 0, 0);
+      let data = NetUtil.readInputStreamToString(stream, stream.available());
+      script = data + script;
+    }
+
+    let res = Cu.evalInSandbox(script, sandbox, "1.8");
+
+    if (directInject && !async &&
+        (res == undefined || res.passed == undefined)) {
+      this.sendError("finish() not called", 500, null, command_id);
+      return;
+    }
+
+    if (!async) {
+      this.sendResponse(this.curBrowser.elementManager.wrapValue(res),
+                        command_id);
+    }
+  },
+
+  /**
+   * Execute the given script either as a function body (executeScript)
+   * or directly (for 'mochitest' like JS Marionette tests)
+   *
+   * @param object aRequest
+   *        'value' member is the script to run
+   *        'args' member holds the arguments to the script
+   * @param boolean directInject
+   *        if true, it will be run directly and not as a 
+   *        function body
+   */
+  execute: function MDA_execute(aRequest, directInject) {
+    let timeout = aRequest.scriptTimeout ? aRequest.scriptTimeout : this.scriptTimeout;
+    let command_id = this.command_id = this.getCommandId();
+    this.logRequest("execute", aRequest);
+    if (aRequest.newSandbox == undefined) {
+      //if client does not send a value in newSandbox, 
+      //then they expect the same behaviour as webdriver
+      aRequest.newSandbox = true;
+    }
+    if (this.context == "content") {
+      this.sendAsync("executeScript",
+                     {
+                       value: aRequest.value,
+                       args: aRequest.args,
+                       newSandbox: aRequest.newSandbox,
+                       timeout: timeout,
+                       specialPowers: aRequest.specialPowers
+                     },
+                     command_id);
+      return;
+    }
+
+    let curWindow = this.getCurrentWindow();
+    let marionette = new Marionette(this, curWindow, "chrome",
+                                    this.marionetteLog,
+                                    timeout, this.testName);
+    let _chromeSandbox = this.createExecuteSandbox(curWindow,
+                                                   marionette,
+                                                   aRequest.args,
+                                                   aRequest.specialPowers,
+                                                   command_id);
+    if (!_chromeSandbox)
+      return;
+
+    try {
+      _chromeSandbox.finish = function chromeSandbox_finish() {
+        return marionette.generate_results();
+      };
+
+      let script;
+      if (directInject) {
+        script = aRequest.value;
+      }
+      else {
+        script = "let func = function() {" +
+                       aRequest.value + 
+                     "};" +
+                     "func.apply(null, __marionetteParams);";
+      }
+      this.executeScriptInSandbox(_chromeSandbox, script, directInject,
+                                  false, command_id, timeout);
+    }
+    catch (e) {
+      this.sendError(e.name + ': ' + e.message, 17, e.stack, command_id);
+    }
+  },
+
+  /**
+   * Set the timeout for asynchronous script execution
+   *
+   * @param object aRequest
+   *        'value' member is time in milliseconds to set timeout
+   */
+  setScriptTimeout: function MDA_setScriptTimeout(aRequest) {
+    this.command_id = this.getCommandId();
+    let timeout = parseInt(aRequest.value);
+    if(isNaN(timeout)){
+      this.sendError("Not a Number", 500, null, this.command_id);
+    }
+    else {
+      this.scriptTimeout = timeout;
+      this.sendOk(this.command_id);
+    }
+  },
+
+  /**
+   * execute pure JS script. Used to execute 'mochitest'-style Marionette tests.
+   *
+   * @param object aRequest
+   *        'value' member holds the script to execute
+   *        'args' member holds the arguments to the script
+   *        'timeout' member will be used as the script timeout if it is given
+   */
+  executeJSScript: function MDA_executeJSScript(aRequest) {
+    let timeout = aRequest.scriptTimeout ? aRequest.scriptTimeout : this.scriptTimeout;
+    let command_id = this.command_id = this.getCommandId();
+    //all pure JS scripts will need to call Marionette.finish() to complete the test.
+    if (aRequest.newSandbox == undefined) {
+      //if client does not send a value in newSandbox, 
+      //then they expect the same behaviour as webdriver
+      aRequest.newSandbox = true;
+    }
+    if (this.context == "chrome") {
+      if (aRequest.async) {
+        this.executeWithCallback(aRequest, aRequest.async);
+      }
+      else {
+        this.execute(aRequest, true);
+      }
+    }
+    else {
+      this.sendAsync("executeJSScript",
+                     {
+                       value: aRequest.value,
+                       args: aRequest.args,
+                       newSandbox: aRequest.newSandbox,
+                       async: aRequest.async,
+                       timeout: timeout,
+                       specialPowers: aRequest.specialPowers
+                     },
+                     command_id);
+   }
+  },
+
+  /**
+   * This function is used by executeAsync and executeJSScript to execute a script
+   * in a sandbox. 
+   * 
+   * For executeJSScript, it will return a message only when the finish() method is called.
+   * For executeAsync, it will return a response when marionetteScriptFinished/arguments[arguments.length-1] 
+   * method is called, or if it times out.
+   *
+   * @param object aRequest
+   *        'value' member holds the script to execute
+   *        'args' member holds the arguments for the script
+   * @param boolean directInject
+   *        if true, it will be run directly and not as a 
+   *        function body
+   */
+  executeWithCallback: function MDA_executeWithCallback(aRequest, directInject) {
+    let timeout = aRequest.scriptTimeout ? aRequest.scriptTimeout : this.scriptTimeout;
+    let command_id = this.command_id = this.getCommandId();
+    this.logRequest("executeWithCallback", aRequest);
+    if (aRequest.newSandbox == undefined) {
+      //if client does not send a value in newSandbox, 
+      //then they expect the same behaviour as webdriver
+      aRequest.newSandbox = true;
+    }
+
+    if (this.context == "content") {
+      this.sendAsync("executeAsyncScript",
+                     {
+                       value: aRequest.value,
+                       args: aRequest.args,
+                       id: this.command_id,
+                       newSandbox: aRequest.newSandbox,
+                       timeout: timeout,
+                       specialPowers: aRequest.specialPowers
+                     },
+                     command_id);
+      return;
+    }
+
+    let curWindow = this.getCurrentWindow();
+    let original_onerror = curWindow.onerror;
+    let that = this;
+    that.timeout = timeout;
+    let marionette = new Marionette(this, curWindow, "chrome",
+                                    this.marionetteLog,
+                                    timeout, this.testName);
+    marionette.command_id = this.command_id;
+
+    function chromeAsyncReturnFunc(value, status) {
+      if (that._emu_cbs && Object.keys(that._emu_cbs).length) {
+        value = "Emulator callback still pending when finish() called";
+        status = 500;
+        that._emu_cbs = null;
+      }
+
+      if (value == undefined)
+        value = null;
+      if (that.command_id == marionette.command_id) {
+        if (that.timer != null) {
+          that.timer.cancel();
+          that.timer = null;
+        }
+
+        curWindow.onerror = original_onerror;
+
+        if (status == 0 || status == undefined) {
+          that.sendToClient({from: that.actorID, value: that.curBrowser.elementManager.wrapValue(value), status: status},
+                            marionette.command_id);
+        }
+        else {
+          let error_msg = {message: value, status: status, stacktrace: null};
+          that.sendToClient({from: that.actorID, error: error_msg},
+                            marionette.command_id);
+        }
+      }
+    }
+
+    curWindow.onerror = function (errorMsg, url, lineNumber) {
+      chromeAsyncReturnFunc(errorMsg + " at: " + url + " line: " + lineNumber, 17);
+      return true;
+    };
+
+    function chromeAsyncFinish() {
+      chromeAsyncReturnFunc(marionette.generate_results(), 0);
+    }
+
+    let _chromeSandbox = this.createExecuteSandbox(curWindow,
+                                                   marionette,
+                                                   aRequest.args,
+                                                   aRequest.specialPowers,
+                                                   command_id);
+    if (!_chromeSandbox)
+      return;
+
+    try {
+
+      this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+      if (this.timer != null) {
+        this.timer.initWithCallback(function() {
+          chromeAsyncReturnFunc("timed out", 28);
+        }, that.timeout, Ci.nsITimer.TYPE_ONESHOT);
+      }
+
+      _chromeSandbox.returnFunc = chromeAsyncReturnFunc;
+      _chromeSandbox.finish = chromeAsyncFinish;
+
+      let script;
+      if (directInject) {
+        script = aRequest.value;
+      }
+      else {
+        script =  '__marionetteParams.push(returnFunc);'
+                + 'let marionetteScriptFinished = returnFunc;'
+                + 'let __marionetteFunc = function() {' + aRequest.value + '};'
+                + '__marionetteFunc.apply(null, __marionetteParams);';
+      }
+
+      this.executeScriptInSandbox(_chromeSandbox, script, directInject,
+                                  true, command_id, timeout);
+    } catch (e) {
+      chromeAsyncReturnFunc(e.name + ": " + e.message, 17);
+    }
+  },
+
+  /**
+   * Navigates to given url
+   *
+   * @param object aRequest
+   *        'value' member holds the url to navigate to
+   */
+  goUrl: function MDA_goUrl(aRequest) {
+    let command_id = this.command_id = this.getCommandId();
+    if (this.context != "chrome") {
+      aRequest.command_id = command_id;
+      aRequest.pageTimeout = this.pageTimeout;
+      this.sendAsync("goUrl", aRequest, command_id);
+      return;
+    }
+
+    this.getCurrentWindow().location.href = aRequest.value;
+    let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+    let start = new Date().getTime();
+    let end = null;
+    function checkLoad() { 
+      end = new Date().getTime();
+      let elapse = end - start;
+      if (this.pageTimeout == null || elapse <= this.pageTimeout){
+        if (curWindow.document.readyState == "complete") { 
+          sendOk(command_id);
+          return;
+        }
+        else{ 
+          checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
+        }
+      }
+      else{
+        sendError("Error loading page", 13, null, command_id);
+        return;
+      }
+    }//end
+    checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
+  },
+
+  /**
+   * Gets current url
+   */
+  getUrl: function MDA_getUrl() {
+    this.command_id = this.getCommandId();
+    if (this.context == "chrome") {
+      this.sendResponse(this.getCurrentWindow().location.href, this.command_id);
+    }
+    else {
+      this.sendAsync("getUrl", {}, this.command_id);
+    }
+  },
+
+  /**
+   * Gets the current title of the window
+   */
+  getTitle: function MDA_getTitle() {
+    this.command_id = this.getCommandId();
+    if (this.context == "chrome"){
+      var curWindow = this.getCurrentWindow();
+      var title = curWindow.document.documentElement.getAttribute('title');
+      this.sendResponse(title, this.command_id);
+    }
+    else {
+      this.sendAsync("getTitle", {}, this.command_id);
+    }
+  },
+
+  /**
+   * Gets the current type of the window
+   */
+  getWindowType: function MDA_getWindowType() {
+    this.command_id = this.getCommandId();
+      var curWindow = this.getCurrentWindow();
+      var type = curWindow.document.documentElement.getAttribute('windowtype');
+      this.sendResponse(type, this.command_id);
+  },
+
+  /**
+   * Gets the page source of the content document
+   */
+  getPageSource: function MDA_getPageSource(){
+    this.command_id = this.getCommandId();
+    if (this.context == "chrome"){
+      let curWindow = this.getCurrentWindow();
+      let XMLSerializer = curWindow.XMLSerializer; 
+      let pageSource = new XMLSerializer().serializeToString(curWindow.document);
+      this.sendResponse(pageSource, this.command_id);
+    }
+    else {
+      this.sendAsync("getPageSource", {}, this.command_id);
+    }
+  },
+
+  /**
+   * Go back in history
+   */
+  goBack: function MDA_goBack() {
+    this.command_id = this.getCommandId();
+    this.sendAsync("goBack", {}, this.command_id);
+  },
+
+  /**
+   * Go forward in history
+   */
+  goForward: function MDA_goForward() {
+    this.command_id = this.getCommandId();
+    this.sendAsync("goForward", {}, this.command_id);
+  },
+
+  /**
+   * Refresh the page
+   */
+  refresh: function MDA_refresh() {
+    this.command_id = this.getCommandId();
+    this.sendAsync("refresh", {}, this.command_id);
+  },
+
+  /**
+   * Get the current window's server-assigned ID
+   */
+  getWindow: function MDA_getWindow() {
+    this.command_id = this.getCommandId();
+    for (let i in this.browsers) {
+      if (this.curBrowser == this.browsers[i]) {
+        this.sendResponse(i, this.command_id);
+      }
+    }
+  },
+
+  /**
+   * Get the server-assigned IDs of all available windows
+   */
+  getWindows: function MDA_getWindows() {
+    this.command_id = this.getCommandId();
+    let res = [];
+    let winEn = this.getWinEnumerator(); 
+    while(winEn.hasMoreElements()) {
+      let foundWin = winEn.getNext();
+      let winId = foundWin.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
+      winId = winId + ((appName == "B2G") ? '-b2g' : '');
+      res.push(winId)
+    }
+    this.sendResponse(res, this.command_id);
+  },
+
+  /**
+   * Switch to a window based on name or server-assigned id.
+   * Searches based on name, then id.
+   *
+   * @param object aRequest
+   *        'value' member holds the name or id of the window to switch to
+   */
+  switchToWindow: function MDA_switchToWindow(aRequest) {
+    let command_id = this.command_id = this.getCommandId();
+    let winEn = this.getWinEnumerator(); 
+    while(winEn.hasMoreElements()) {
+      let foundWin = winEn.getNext();
+      let winId = foundWin.QueryInterface(Ci.nsIInterfaceRequestor)
+                          .getInterface(Ci.nsIDOMWindowUtils)
+                          .outerWindowID;
+      winId = winId + ((appName == "B2G") ? '-b2g' : '');
+      if (aRequest.value == foundWin.name || aRequest.value == winId) {
+        if (this.browsers[winId] == undefined) {
+          //enable Marionette in that browser window
+          this.startBrowser(foundWin, false);
+        }
+        else {
+          utils.window = foundWin;
+          this.curBrowser = this.browsers[winId];
+        }
+        this.sendOk(command_id);
+        return;
+      }
+    }
+    this.sendError("Unable to locate window " + aRequest.value, 23, null,
+                   command_id);
+  },
+ 
+  /**
+   * Switch to a given frame within the current window
+   *
+   * @param object aRequest
+   *        'element' is the element to switch to
+   *        'value' if element is not set, then this
+   *                holds either the id, name or index 
+   *                of the frame to switch to
+   */
+  switchToFrame: function MDA_switchToFrame(aRequest) {
+    let command_id = this.command_id = this.getCommandId();
+    this.logRequest("switchToFrame", aRequest);
+    let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+    let curWindow = this.getCurrentWindow();
+    let checkLoad = function() { 
+      let errorRegex = /about:.+(error)|(blocked)\?/;
+      if (curWindow.document.readyState == "complete") { 
+        this.sendOk(command_id);
+        return;
+      } 
+      else if (curWindow.document.readyState == "interactive" && errorRegex.exec(curWindow.document.baseURI)) {
+        this.sendError("Error loading page", 13, null, command_id);
+        return;
+      }
+      
+      checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
+    }
+    if (this.context == "chrome") {
+      let foundFrame = null;
+      if ((aRequest.value == null) && (aRequest.element == null)) {
+        this.curFrame = null;
+        if (aRequest.focus) {
+          this.mainFrame.focus();
+        }
+        checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
+        return;
+      }
+      if (aRequest.element != undefined) {
+        if (this.curBrowser.elementManager.seenItems[aRequest.element] != undefined) {
+          let wantedFrame = this.curBrowser.elementManager.getKnownElement(aRequest.element, curWindow); //HTMLIFrameElement
+          let numFrames = curWindow.frames.length;
+          for (let i = 0; i < numFrames; i++) {
+            if (curWindow.frames[i].frameElement == wantedFrame) {
+              curWindow = curWindow.frames[i]; 
+              this.curFrame = curWindow;
+              if (aRequest.focus) {
+                this.curFrame.focus();
+              }
+              checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
+              return;
+          }
+        }
+      }
+    }
+    switch(typeof(aRequest.value)) {
+      case "string" :
+        let foundById = null;
+        let numFrames = curWindow.frames.length;
+        for (let i = 0; i < numFrames; i++) {
+          //give precedence to name
+          let frame = curWindow.frames[i];
+          let frameElement = frame.frameElement;
+          if (frame.name == aRequest.value) {
+            foundFrame = i;
+            break;
+          } else if ((foundById == null) && (frameElement.id == aRequest.value)) {
+            foundById = i;
+          }
+        }
+        if ((foundFrame == null) && (foundById != null)) {
+          foundFrame = foundById;
+        }
+        break;
+      case "number":
+        if (curWindow.frames[aRequest.value] != undefined) {
+          foundFrame = aRequest.value;
+        }
+        break;
+      }
+      if (foundFrame != null) {
+        curWindow = curWindow.frames[foundFrame];
+        this.curFrame = curWindow;
+        if (aRequest.focus) {
+          this.curFrame.focus();
+        }
+        checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
+      } else {
+        this.sendError("Unable to locate frame: " + aRequest.value, 8, null,
+                       command_id);
+      }
+    }
+    else {
+      if ((!aRequest.value) && (!aRequest.element) &&
+          (this.currentRemoteFrame !== null)) {
+        // We're currently using a ChromeMessageSender for a remote frame, so this
+        // request indicates we need to switch back to the top-level (parent) frame.
+        // We'll first switch to the parent's (global) ChromeMessageBroadcaster, so
+        // we send the message to the right listener.
+        this.switchToGlobalMessageManager();
+      }
+      aRequest.command_id = command_id;
+      this.sendAsync("switchToFrame", aRequest, command_id);
+    }
+  },
+
+  /**
+   * Set timeout for searching for elements
+   *
+   * @param object aRequest
+   *        'value' holds the search timeout in milliseconds
+   */
+  setSearchTimeout: function MDA_setSearchTimeout(aRequest) {
+    this.command_id = this.getCommandId();
+    let timeout = parseInt(aRequest.value);
+    if (isNaN(timeout)) {
+      this.sendError("Not a Number", 500, null, this.command_id);
+    }
+    else {
+      this.searchTimeout = timeout;
+      this.sendOk(this.command_id);
+    }
+  },
+
+  /**
+   * Set timeout for page loading, searching and scripts
+   *
+   * @param object aRequest
+   *        'type' hold the type of timeout
+   *        'ms' holds the timeout in milliseconds
+   */
+  timeouts: function MDA_timeouts(aRequest){
+    /*setTimeout*/
+    this.command_id = this.getCommandId();
+    let timeout_type = aRequest.timeoutType;
+    let timeout = parseInt(aRequest.ms);
+    if (isNaN(timeout)) {
+      this.sendError("Not a Number", 500, null, this.command_id);
+    }
+    else {
+      if (timeout_type == "implicit") {
+        aRequest.value = aRequest.ms;
+        this.setSearchTimeout(aRequest);
+      }
+      else if (timeout_type == "script") {
+        aRequest.value = aRequest.ms;
+        this.setScriptTimeout(aRequest);
+      }
+      else {
+        this.pageTimeout = timeout;
+        this.sendOk(this.command_id);
+      }
+    }
+  },
+
+  /**
+   * Single Tap
+   *
+   * @param object aRequest
+            'element' represents the ID of the element to single tap on
+   */
+  singleTap: function MDA_singleTap(aRequest) {
+    this.command_id = this.getCommandId();
+    let serId = aRequest.element;
+    let x = aRequest.x;
+    let y = aRequest.y;
+    if (this.context == "chrome") {
+      this.sendError("Command 'singleTap' is not available in chrome context", 500, null, this.command_id);
+    }
+    else {
+      this.sendAsync("singleTap",
+                     {
+                       value: serId,
+                       corx: x,
+                       cory: y
+                     },
+                     this.command_id);
+    }
+  },
+
+  /**
+   * actionChain
+   *
+   * @param object aRequest
+   *        'value' represents a nested array: inner array represents each event; outer array represents collection of events
+   */
+  actionChain: function MDA_actionChain(aRequest) {
+    this.command_id = this.getCommandId();
+    if (this.context == "chrome") {
+      this.sendError("Command 'actionChain' is not available in chrome context", 500, null, this.command_id);
+    }
+    else {
+      this.sendAsync("actionChain",
+                     {
+                       chain: aRequest.chain,
+                       nextId: aRequest.nextId
+                     },
+                     this.command_id);
+    }
+  },
+
+  /**
+   * multiAction
+   *
+   * @param object aRequest
+   *        'value' represents a nested array: inner array represents each event;
+   *        middle array represents collection of events for each finger
+   *        outer array represents all the fingers
+   */
+
+  multiAction: function MDA_multiAction(aRequest) {
+    this.command_id = this.getCommandId();
+    if (this.context == "chrome") {
+       this.sendError("Command 'multiAction' is not available in chrome context", 500, null, this.command_id);
+    }
+    else {
+      this.sendAsync("multiAction",
+                     {
+                       value: aRequest.value,
+                       maxlen: aRequest.max_length
+                     },
+                     this.command_id);
+   }
+ },
+
+  /**
+   * Find an element using the indicated search strategy.
+   *
+   * @param object aRequest
+   *        'using' member indicates which search method to use
+   *        'value' member is the value the client is looking for
+   */
+  findElement: function MDA_findElement(aRequest) {
+    let command_id = this.command_id = this.getCommandId();
+    if (this.context == "chrome") {
+      let id;
+      try {
+        let on_success = this.sendResponse.bind(this);
+        let on_error = this.sendError.bind(this);
+        id = this.curBrowser.elementManager.find(
+                              this.getCurrentWindow(),
+                              aRequest,
+                              this.searchTimeout,
+                              on_success,
+                              on_error,
+                              false,
+                              command_id);
+      }
+      catch (e) {
+        this.sendError(e.message, e.code, e.stack, command_id);
+        return;
+      }
+    }
+    else {
+      this.sendAsync("findElementContent",
+                     {
+                       value: aRequest.value,
+                       using: aRequest.using,
+                       element: aRequest.element,
+                       searchTimeout: this.searchTimeout
+                     },
+                     command_id);
+    }
+  },
+
+  /**
+   * Find elements using the indicated search strategy.
+   *
+   * @param object aRequest
+   *        'using' member indicates which search method to use
+   *        'value' member is the value the client is looking for
+   */
+  findElements: function MDA_findElements(aRequest) {
+    let command_id = this.command_id = this.getCommandId();
+    if (this.context == "chrome") {
+      let id;
+      try {
+        let on_success = this.sendResponse.bind(this);
+        let on_error = this.sendError.bind(this);
+        id = this.curBrowser.elementManager.find(this.getCurrentWindow(),
+                                                 aRequest,
+                                                 this.searchTimeout,
+                                                 on_success,
+                                                 on_error,
+                                                 true,
+                                                 command_id);
+      }
+      catch (e) {
+        this.sendError(e.message, e.code, e.stack, command_id);
+        return;
+      }
+    }
+    else {
+      this.sendAsync("findElementsContent",
+                     {
+                       value: aRequest.value,
+                       using: aRequest.using,
+                       element: aRequest.element,
+                       searchTimeout: this.searchTimeout
+                     },
+                     command_id);
+    }
+  },
+
+  /**
+   * Return the active element on the page
+   */
+  getActiveElement: function MDA_getActiveElement(){
+    let command_id = this.command_id = this.getCommandId();
+    this.sendAsync("getActiveElement", {}, command_id);
+  },
+
+  /**
+   * Send click event to element
+   *
+   * @param object aRequest
+   *        'element' member holds the reference id to
+   *        the element that will be clicked
+   */
+  clickElement: function MDA_clickElement(aRequest) {
+    let command_id = this.command_id = this.getCommandId();
+    if (this.context == "chrome") {
+      try {
+        //NOTE: click atom fails, fall back to click() action
+        let el = this.curBrowser.elementManager.getKnownElement(
+            aRequest.element, this.getCurrentWindow());
+        el.click();
+        this.sendOk(command_id);
+      }
+      catch (e) {
+        this.sendError(e.message, e.code, e.stack, command_id);
+      }
+    }
+    else {
+      // We need to protect against the click causing an OOP frame to close. 
+      // This fires the mozbrowserclose event when it closes so we need to 
+      // listen for it and then just send an error back. The person making the
+      // call should be aware something isnt right and handle accordingly
+      let curWindow = this.getCurrentWindow();
+      let self = this;
+      this.mozBrowserClose = function() { 
+        curWindow.removeEventListener('mozbrowserclose', self.mozBrowserClose, true);
+        self.switchToGlobalMessageManager();
+        self.sendError("The frame closed during the click, recovering to allow further communications", 500, null, command_id);
+      };
+      curWindow.addEventListener('mozbrowserclose', this.mozBrowserClose, true);
+      this.sendAsync("clickElement",
+                     { element: aRequest.element },
+                     command_id);
+    }
+  },
+
+  /**
+   * Get a given attribute of an element
+   *
+   * @param object aRequest
+   *        'element' member holds the reference id to
+   *        the element that will be inspected
+   *        'name' member holds the name of the attribute to retrieve
+   */
+  getElementAttribute: function MDA_getElementAttribute(aRequest) {
+    let command_id = this.command_id = this.getCommandId();
+    if (this.context == "chrome") {
+      try {
+        let el = this.curBrowser.elementManager.getKnownElement(
+            aRequest.element, this.getCurrentWindow());
+        this.sendResponse(utils.getElementAttribute(el, aRequest.name),
+                          command_id);
+      }
+      catch (e) {
+        this.sendError(e.message, e.code, e.stack, command_id);
+      }
+    }
+    else {
+      this.sendAsync("getElementAttribute",
+                     {
+                       element: aRequest.element,
+                       name: aRequest.name
+                     },
+                     command_id);
+    }
+  },
+
+  /**
+   * Get the text of an element, if any. Includes the text of all child elements.
+   *
+   * @param object aRequest
+   *        'element' member holds the reference id to
+   *        the element that will be inspected 
+   */
+  getElementText: function MDA_getElementText(aRequest) {
+    let command_id = this.command_id = this.getCommandId();
+    if (this.context == "chrome") {
+      //Note: for chrome, we look at text nodes, and any node with a "label" field
+      try {
+        let el = this.curBrowser.elementManager.getKnownElement(
+            aRequest.element, this.getCurrentWindow());
+        let lines = [];
+        this.getVisibleText(el, lines);
+        lines = lines.join("\n");
+        this.sendResponse(lines, command_id);
+      }
+      catch (e) {
+        this.sendError(e.message, e.code, e.stack, command_id);
+      }
+    }
+    else {
+      this.sendAsync("getElementText",
+                     { element: aRequest.element },
+                     command_id);
+    }
+  },
+
+  /**
+   * Get the tag name of the element.
+   *
+   * @param object aRequest
+   *        'element' member holds the reference id to
+   *        the element that will be inspected 
+   */
+  getElementTagName: function MDA_getElementTagName(aRequest) {
+    let command_id = this.command_id = this.getCommandId();
+    if (this.context == "chrome") {
+      try {
+        let el = this.curBrowser.elementManager.getKnownElement(
+            aRequest.element, this.getCurrentWindow());
+        this.sendResponse(el.tagName.toLowerCase(), command_id);
+      }
+      catch (e) {
+        this.sendError(e.message, e.code, e.stack, command_id);
+      }
+    }
+    else {
+      this.sendAsync("getElementTagName",
+                     { element: aRequest.element },
+                     command_id);
+    }
+  },
+
+  /**
+   * Check if element is displayed
+   *
+   * @param object aRequest
+   *        'element' member holds the reference id to
+   *        the element that will be checked 
+   */
+  isElementDisplayed: function MDA_isElementDisplayed(aRequest) {
+    let command_id = this.command_id = this.getCommandId();
+    if (this.context == "chrome") {
+      try {
+        let el = this.curBrowser.elementManager.getKnownElement(
+            aRequest.element, this.getCurrentWindow());
+        this.sendResponse(utils.isElementDisplayed(el), command_id);
+      }
+      catch (e) {
+        this.sendError(e.message, e.code, e.stack, command_id);
+      }
+    }
+    else {
+      this.sendAsync("isElementDisplayed",
+                     { element:aRequest.element },
+                     command_id);
+    }
+  },
+
+  /**
+   * Return the property of the computed style of an element
+   *
+   * @param object aRequest
+   *               'element' member holds the reference id to
+   *               the element that will be checked
+   *               'propertyName' is the CSS rule that is being requested
+   */
+  getElementValueOfCssProperty: function MDA_getElementValueOfCssProperty(aRequest){
+    let command_id = this.command_id = this.getCommandId();
+    this.sendAsync("getElementValueOfCssProperty",
+                   {element: aRequest.element, propertyName: aRequest.propertyName},
+                   command_id);
+  },
+
+  /**
+   * Check if element is enabled
+   *
+   * @param object aRequest
+   *        'element' member holds the reference id to
+   *        the element that will be checked
+   */
+  isElementEnabled: function MDA_isElementEnabled(aRequest) {
+    let command_id = this.command_id = this.getCommandId();
+    if (this.context == "chrome") {
+      try {
+        //Selenium atom doesn't quite work here
+        let el = this.curBrowser.elementManager.getKnownElement(
+            aRequest.element, this.getCurrentWindow());
+        if (el.disabled != undefined) {
+          this.sendResponse(!!!el.disabled, command_id);
+        }
+        else {
+        this.sendResponse(true, command_id);
+        }
+      }
+      catch (e) {
+        this.sendError(e.message, e.code, e.stack, command_id);
+      }
+    }
+    else {
+      this.sendAsync("isElementEnabled",
+                     { element:aRequest.element },
+                     command_id);
+    }
+  },
+
+  /**
+   * Check if element is selected
+   *
+   * @param object aRequest
+   *        'element' member holds the reference id to
+   *        the element that will be checked
+   */
+  isElementSelected: function MDA_isElementSelected(aRequest) {
+    let command_id = this.command_id = this.getCommandId();
+    if (this.context == "chrome") {
+      try {
+        //Selenium atom doesn't quite work here
+        let el = this.curBrowser.elementManager.getKnownElement(
+            aRequest.element, this.getCurrentWindow());
+        if (el.checked != undefined) {
+          this.sendResponse(!!el.checked, command_id);
+        }
+        else if (el.selected != undefined) {
+          this.sendResponse(!!el.selected, command_id);
+        }
+        else {
+          this.sendResponse(true, command_id);
+        }
+      }
+      catch (e) {
+        this.sendError(e.message, e.code, e.stack, command_id);
+      }
+    }
+    else {
+      this.sendAsync("isElementSelected",
+                     { element:aRequest.element },
+                     command_id);
+    }
+  },
+
+  getElementSize: function MDA_getElementSize(aRequest) {
+    let command_id = this.command_id = this.getCommandId();
+    if (this.context == "chrome") {
+      try {
+        let el = this.curBrowser.elementManager.getKnownElement(
+            aRequest.element, this.getCurrentWindow());
+        let clientRect = el.getBoundingClientRect();  
+        this.sendResponse({width: clientRect.width, height: clientRect.height},
+                          command_id);
+      }
+      catch (e) {
+        this.sendError(e.message, e.code, e.stack, command_id);
+      }
+    }
+    else {
+      this.sendAsync("getElementSize",
+                     { element:aRequest.element },
+                     command_id);
+    }
+  },
+
+  /**
+   * Send key presses to element after focusing on it
+   *
+   * @param object aRequest
+   *        'element' member holds the reference id to
+   *        the element that will be checked
+   *        'value' member holds the value to send to the element
+   */
+  sendKeysToElement: function MDA_sendKeysToElement(aRequest) {
+    let command_id = this.command_id = this.getCommandId();
+    if (this.context == "chrome") {
+      try {
+        let el = this.curBrowser.elementManager.getKnownElement(
+            aRequest.element, this.getCurrentWindow());
+        el.focus();
+        utils.sendString(aRequest.value.join(""), utils.window);
+        this.sendOk(command_id);
+      }
+      catch (e) {
+        this.sendError(e.message, e.code, e.stack, command_id);
+      }
+    }
+    else {
+      this.sendAsync("sendKeysToElement",
+                     {
+                       element:aRequest.element,
+                       value: aRequest.value
+                     },
+                     command_id);
+    }
+  },
+
+  /**
+   * Sets the test name
+   *
+   * The test name is used in logging messages.
+   */
+  setTestName: function MDA_setTestName(aRequest) {
+    this.command_id = this.getCommandId();
+    this.logRequest("setTestName", aRequest);
+    this.testName = aRequest.value;
+    this.sendAsync("setTestName",
+                   { value: aRequest.value },
+                   this.command_id);
+  },
+
+  /**
+   * Clear the text of an element
+   *
+   * @param object aRequest
+   *        'element' member holds the reference id to
+   *        the element that will be cleared 
+   */
+  clearElement: function MDA_clearElement(aRequest) {
+    let command_id = this.command_id = this.getCommandId();
+    if (this.context == "chrome") {
+      //the selenium atom doesn't work here
+      try {
+        let el = this.curBrowser.elementManager.getKnownElement(
+            aRequest.element, this.getCurrentWindow());
+        if (el.nodeName == "textbox") {
+          el.value = "";
+        }
+        else if (el.nodeName == "checkbox") {
+          el.checked = false;
+        }
+        this.sendOk(command_id);
+      }
+      catch (e) {
+        this.sendError(e.message, e.code, e.stack, command_id);
+      }
+    }
+    else {
+      this.sendAsync("clearElement",
+                     { element:aRequest.element },
+                     command_id);
+    }
+  },
+
+  getElementPosition: function MDA_getElementPosition(aRequest) {
+    this.command_id = this.getCommandId();
+    this.sendAsync("getElementPosition",
+                   { element:aRequest.element },
+                   this.command_id);
+  },
+
+  /**
+   * Add a cookie to the document.
+   */
+  addCookie: function MDA_addCookie(aRequest) {
+    this.command_id = this.getCommandId();
+    this.sendAsync("addCookie",
+                   { cookie:aRequest.cookie },
+                   this.command_id);
+  },
+
+  /**
+   * Get all visible cookies for a document
+   */
+  getAllCookies: function MDA_getAllCookies() {
+    this.command_id = this.getCommandId();
+    this.sendAsync("getAllCookies", {}, this.command_id);
+  },
+
+  /**
+   * Delete all cookies that are visible to a document
+   */
+  deleteAllCookies: function MDA_deleteAllCookies() {
+    this.command_id = this.getCommandId();
+    this.sendAsync("deleteAllCookies", {}, this.command_id);
+  },
+
+  /**
+   * Delete a cookie by name
+   */
+  deleteCookie: function MDA_deleteCookie(aRequest) {
+    this.command_id = this.getCommandId();
+    this.sendAsync("deleteCookie",
+                   { name:aRequest.name },
+                   this.command_id);
+  },
+
+  /**
+   * Closes the Browser Window.
+   *
+   * If it is B2G it returns straight away and does not do anything
+   *
+   * If is desktop it calculates how many windows are open and if there is only 
+   * 1 then it deletes the session otherwise it closes the window
+   */
+  closeWindow: function MDA_closeWindow() {
+    let command_id = this.command_id = this.getCommandId();
+    if (appName == "B2G") {
+      // We can't close windows so just return
+      this.sendOk(command_id);
+    }
+    else {
+      // Get the total number of windows
+      let numOpenWindows = 0;
+      let winEnum = this.getWinEnumerator();
+      while (winEnum.hasMoreElements()) {
+        numOpenWindows += 1;
+        winEnum.getNext(); 
+      }
+
+      // if there is only 1 window left, delete the session
+      if (numOpenWindows === 1){
+        this.deleteSession();
+        return;
+      }
+
+      try{
+        this.messageManager.removeDelayedFrameScript(FRAME_SCRIPT); 
+        this.getCurrentWindow().close();
+        this.sendOk(command_id);
+      }
+      catch (e) {
+        this.sendError("Could not close window: " + e.message, 13, e.stack,
+                       command_id);
+      }
+    }
+  }, 
+
+  /**
+   * Deletes the session.
+   * 
+   * If it is a desktop environment, it will close the session's tab and close all listeners
+   *
+   * If it is a B2G environment, it will make the main content listener sleep, and close
+   * all other listeners. The main content listener persists after disconnect (it's the homescreen),
+   * and can safely be reused.
+   */
+  deleteSession: function MDA_deleteSession() {
+    let command_id = this.command_id = this.getCommandId();
+    if (this.curBrowser != null) {
+      if (appName == "B2G") {
+        this.globalMessageManager.broadcastAsyncMessage(
+            "Marionette:sleepSession" + this.curBrowser.mainContentId, {});
+        this.curBrowser.knownFrames.splice(
+            this.curBrowser.knownFrames.indexOf(this.curBrowser.mainContentId), 1);
+      }
+      else {
+        //don't set this pref for B2G since the framescript can be safely reused
+        Services.prefs.setBoolPref("marionette.contentListener", false);
+      }
+      this.curBrowser.closeTab();
+      //delete session in each frame in each browser
+      for (let win in this.browsers) {
+        for (let i in this.browsers[win].knownFrames) {
+          this.globalMessageManager.broadcastAsyncMessage("Marionette:deleteSession" + this.browsers[win].knownFrames[i], {});
+        }
+      }
+      let winEnum = this.getWinEnumerator();
+      while (winEnum.hasMoreElements()) {
+        winEnum.getNext().messageManager.removeDelayedFrameScript(FRAME_SCRIPT); 
+      }
+    }
+    this.sendOk(command_id);
+    this.removeMessageManagerListeners(this.globalMessageManager);
+    this.switchToGlobalMessageManager();
+    // reset frame to the top-most frame
+    this.curFrame = null;
+    if (this.mainFrame) {
+      this.mainFrame.focus();
+    }
+    this.curBrowser = null;
+    try {
+      this.importedScripts.remove(false);
+    }
+    catch (e) {
+    }
+  },
+
+  /**
+   * Returns the current status of the Application Cache
+   */
+  getAppCacheStatus: function MDA_getAppCacheStatus(aRequest) {
+    this.command_id = this.getCommandId();
+    this.sendAsync("getAppCacheStatus", {}, this.command_id);
+  },
+
+  _emu_cb_id: 0,
+  _emu_cbs: null,
+  runEmulatorCmd: function runEmulatorCmd(cmd, callback) {
+    if (callback) {
+      if (!this._emu_cbs) {
+        this._emu_cbs = {};
+      }
+      this._emu_cbs[this._emu_cb_id] = callback;
+    }
+    this.sendToClient({emulator_cmd: cmd, id: this._emu_cb_id}, -1);
+    this._emu_cb_id += 1;
+  },
+
+  emulatorCmdResult: function emulatorCmdResult(message) {
+    if (this.context != "chrome") {
+      this.sendAsync("emulatorCmdResult", message, -1);
+      return;
+    }
+
+    if (!this._emu_cbs) {
+      return;
+    }
+
+    let cb = this._emu_cbs[message.id];
+    delete this._emu_cbs[message.id];
+    if (!cb) {
+      return;
+    }
+    try {
+      cb(message.result);
+    }
+    catch(e) {
+      this.sendError(e.message, e.code, e.stack, -1);
+      return;
+    }
+  },
+  
+  importScript: function MDA_importScript(aRequest) {
+    let command_id = this.command_id = this.getCommandId();
+    if (this.context == "chrome") {
+      let file;
+      if (this.importedScripts.exists()) {
+        file = FileUtils.openFileOutputStream(this.importedScripts,
+            FileUtils.MODE_APPEND | FileUtils.MODE_WRONLY);
+      }
+      else {
+        //Note: The permission bits here don't actually get set (bug 804563)
+        this.importedScripts.createUnique(
+            Components.interfaces.nsIFile.NORMAL_FILE_TYPE, parseInt("0666", 8));
+        file = FileUtils.openFileOutputStream(this.importedScripts,
+            FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE);
+        this.importedScripts.permissions = parseInt("0666", 8); //actually set permissions
+      }
+      file.write(aRequest.script, aRequest.script.length);
+      file.close();
+      this.sendOk(command_id);
+    }
+    else {
+      this.sendAsync("importScript",
+                     { script: aRequest.script },
+                     command_id);
+    }
+  },
+
+  /**
+   * Takes a screenshot of a DOM node. If there is no node given a screenshot
+   * of the window will be taken.
+   */
+  screenShot: function MDA_saveScreenshot(aRequest) {
+    this.command_id = this.getCommandId();
+    this.sendAsync("screenShot",
+                   {
+                     element: aRequest.element,
+                     highlights: aRequest.highlights
+                   },
+                   this.command_id);
+  },
+
+  /**
+   * Helper function to convert an outerWindowID into a UID t