Merge the last PGO-green inbound changeset to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 21 Feb 2013 08:05:14 -0500
changeset 122527 702d2814efbf33eea652d5bfcc658aba75331014
parent 122426 d57a813c77a48307fa76532884dcc8a91aef79ea (current diff)
parent 122526 5b3cf801e0e0434f08ca6cef61e8f5c8f3fbbfad (diff)
child 122528 7f95f7e035424a43bbffd9390edadcf92f05306d
child 122577 31466fd86eb7280c0d1a6f96b62999f41126bf74
child 127335 608fd0acb23aadc35bf65a4226abafda54961038
push id24342
push userryanvm@gmail.com
push dateThu, 21 Feb 2013 13:05:06 +0000
treeherdermozilla-central@702d2814efbf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone22.0a1
first release with
nightly linux32
702d2814efbf / 22.0a1 / 20130221072044 / files
nightly linux64
702d2814efbf / 22.0a1 / 20130221072044 / files
nightly mac
702d2814efbf / 22.0a1 / 20130221072044 / files
nightly win32
702d2814efbf / 22.0a1 / 20130221072044 / files
nightly win64
702d2814efbf / 22.0a1 / 20130221072044 / 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 the last PGO-green inbound changeset to m-c.
content/base/test/chrome/browser_bug822367.js
content/base/test/file_bug822367_1.html
content/base/test/file_bug822367_1.js
content/base/test/file_bug822367_2.html
content/base/test/file_bug822367_3.html
content/base/test/file_bug822367_4.html
content/base/test/file_bug822367_4.js
content/base/test/file_bug822367_4B.html
content/base/test/file_bug822367_5.html
content/base/test/file_bug822367_6.html
mobile/android/base/resources/drawable/menu_item_checkmark.xml
--- a/accessible/src/msaa/AccessibleWrap.cpp
+++ b/accessible/src/msaa/AccessibleWrap.cpp
@@ -10,22 +10,22 @@
 #include "DocAccessible-inl.h"
 #include "EnumVariant.h"
 #include "ia2AccessibleRelation.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 #include "nsIAccessibleEvent.h"
 #include "nsIAccessibleRelation.h"
 #include "nsWinUtils.h"
+#include "ServiceProvider.h"
 #include "Relation.h"
 #include "Role.h"
 #include "RootAccessible.h"
 #include "sdnAccessible.h"
 #include "States.h"
-#include "uiaRawElmProvider.h"
 
 #ifdef A11Y_LOG
 #include "Logging.h"
 #endif
 
 #include "nsIMutableArray.h"
 #include "nsIFrame.h"
 #include "nsIScrollableFrame.h"
@@ -85,17 +85,17 @@ AccessibleWrap::QueryInterface(REFIID ii
     *ppv = static_cast<IAccessible*>(this);
   else if (IID_IEnumVARIANT == iid) {
     // Don't support this interface for leaf elements.
     if (!HasChildren() || nsAccUtils::MustPrune(this))
       return E_NOINTERFACE;
 
     *ppv = static_cast<IEnumVARIANT*>(new ChildrenEnumVariant(this));
   } else if (IID_IServiceProvider == iid)
-    *ppv = static_cast<IServiceProvider*>(this);
+    *ppv = new ServiceProvider(this);
   else if (IID_IAccessible2 == iid && !Compatibility::IsIA2Off())
     *ppv = static_cast<IAccessible2*>(this);
   else if (IID_ISimpleDOMNode == iid) {
     if (IsDefunct() || (!HasOwnContent() && !IsDoc()))
       return E_NOINTERFACE;
 
     *ppv = new sdnAccessible(GetNode());
   }
@@ -122,42 +122,16 @@ AccessibleWrap::QueryInterface(REFIID ii
     return E_NOINTERFACE;
 
   (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
   return S_OK;
 
   A11Y_TRYBLOCK_END
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// IServiceProvider
-
-STDMETHODIMP
-AccessibleWrap::QueryService(REFGUID aGuidService, REFIID aIID,
-                             void** aInstancePtr)
-{
-  if (!aInstancePtr)
-    return E_INVALIDARG;
-
-  *aInstancePtr = NULL;
-
-  // UIA IAccessibleEx
-  if (aGuidService == IID_IAccessibleEx &&
-      Preferences::GetBool("accessibility.uia.enable")) {
-    uiaRawElmProvider* accEx = new uiaRawElmProvider(this);
-    HRESULT hr = accEx->QueryInterface(aIID, aInstancePtr);
-    if (FAILED(hr))
-      delete accEx;
-
-    return hr;
-  }
-
-  return nsAccessNodeWrap::QueryService(aGuidService, aIID, aInstancePtr);
-}
-
 //-----------------------------------------------------
 // IAccessible methods
 //-----------------------------------------------------
 
 STDMETHODIMP
 AccessibleWrap::get_accParent( IDispatch __RPC_FAR *__RPC_FAR *ppdispParent)
 {
   A11Y_TRYBLOCK_BEGIN
--- a/accessible/src/msaa/AccessibleWrap.h
+++ b/accessible/src/msaa/AccessibleWrap.h
@@ -133,21 +133,16 @@ public: // construction, destruction
     NS_DECL_ISUPPORTS_INHERITED
 
   public: // IUnknown methods - see iunknown.h for documentation
     STDMETHODIMP QueryInterface(REFIID, void**);
 
   // Return the registered OLE class ID of this object's CfDataObj.
     CLSID GetClassID() const;
 
-  // IServiceProvider
-  virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID aGuidService,
-                                                 REFIID aIID,
-                                                 void** aInstancePtr);
-
   public: // COM interface IAccessible
     virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accParent( 
         /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispParent);
 
     virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accChildCount( 
         /* [retval][out] */ long __RPC_FAR *pcountChildren);
 
     virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accChild( 
--- a/accessible/src/msaa/Makefile.in
+++ b/accessible/src/msaa/Makefile.in
@@ -24,16 +24,17 @@ CPPSRCS = \
   HTMLWin32ObjectAccessible.cpp \
   HyperTextAccessibleWrap.cpp \
   ImageAccessibleWrap.cpp \
   nsAccessNodeWrap.cpp \
   nsWinUtils.cpp \
   Compatibility.cpp \
   EnumVariant.cpp \
   Platform.cpp \
+  ServiceProvider.cpp \
   RootAccessibleWrap.cpp \
   TextLeafAccessibleWrap.cpp \
   $(NULL)
 
 ifdef MOZ_XUL
 CPPSRCS += \
   XULListboxAccessibleWrap.cpp \
   XULMenuAccessibleWrap.cpp \
new file mode 100644
--- /dev/null
+++ b/accessible/src/msaa/ServiceProvider.cpp
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ServiceProvider.h"
+
+#include "ApplicationAccessibleWrap.h"
+#include "Compatibility.h"
+#include "DocAccessible.h"
+#include "nsAccUtils.h"
+#include "nsCoreUtils.h"
+#include "uiaRawElmProvider.h"
+
+#include "mozilla/Preferences.h"
+#include "nsIDocShell.h"
+
+#include "ISimpleDOMNode_i.c"
+
+namespace mozilla {
+namespace a11y {
+
+IMPL_IUNKNOWN_QUERY_HEAD(ServiceProvider)
+  IMPL_IUNKNOWN_QUERY_IFACE(IServiceProvider)
+  return mAccessible->QueryInterface(aIID, aInstancePtr);
+A11Y_TRYBLOCK_END
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+// IServiceProvider
+
+STDMETHODIMP
+ServiceProvider::QueryService(REFGUID aGuidService, REFIID aIID,
+                              void** aInstancePtr)
+{
+  if (!aInstancePtr)
+    return E_INVALIDARG;
+
+  *aInstancePtr = NULL;
+
+  // UIA IAccessibleEx
+  if (aGuidService == IID_IAccessibleEx &&
+      Preferences::GetBool("accessibility.uia.enable")) {
+    uiaRawElmProvider* accEx = new uiaRawElmProvider(mAccessible);
+    HRESULT hr = accEx->QueryInterface(aIID, aInstancePtr);
+    if (FAILED(hr))
+      delete accEx;
+
+    return hr;
+  }
+
+  // Provide a special service ID for getting the accessible for the browser tab
+  // document that contains this accessible object. If this accessible object
+  // is not inside a browser tab then the service fails with E_NOINTERFACE.
+  // A use case for this is for screen readers that need to switch context or
+  // 'virtual buffer' when focus moves from one browser tab area to another.
+  static const GUID SID_IAccessibleContentDocument =
+    { 0xa5d8e1f3,0x3571,0x4d8f,{0x95,0x21,0x07,0xed,0x28,0xfb,0x07,0x2e} };
+  if (aGuidService == SID_IAccessibleContentDocument) {
+    if (aIID != IID_IAccessible)
+      return E_NOINTERFACE;
+
+    nsCOMPtr<nsIDocShell> docShell =
+      nsCoreUtils::GetDocShellFor(mAccessible->GetNode());
+    if (!docShell)
+      return E_UNEXPECTED;
+
+    // Walk up the parent chain without crossing the boundary at which item
+    // types change, preventing us from walking up out of tab content.
+    nsCOMPtr<nsIDocShellTreeItem> root;
+    docShell->GetSameTypeRootTreeItem(getter_AddRefs(root));
+    if (!root)
+      return E_UNEXPECTED;
+
+
+    // If the item type is typeContent, we assume we are in browser tab content.
+    // Note this includes content such as about:addons, for consistency.
+    int32_t itemType;
+    root->GetItemType(&itemType);
+    if (itemType != nsIDocShellTreeItem::typeContent)
+      return E_NOINTERFACE;
+
+    // Make sure this is a document.
+    DocAccessible* docAcc = nsAccUtils::GetDocAccessibleFor(root);
+    if (!docAcc)
+      return E_UNEXPECTED;
+
+    *aInstancePtr = static_cast<IAccessible*>(docAcc);
+
+    (reinterpret_cast<IUnknown*>(*aInstancePtr))->AddRef();
+    return S_OK;
+  }
+
+  // Can get to IAccessibleApplication from any node via QS
+  if (aGuidService == IID_IAccessibleApplication ||
+      (Compatibility::IsJAWS() && aIID == IID_IAccessibleApplication)) {
+    ApplicationAccessibleWrap* applicationAcc =
+      static_cast<ApplicationAccessibleWrap*>(ApplicationAcc());
+    if (!applicationAcc)
+      return E_NOINTERFACE;
+
+    return applicationAcc->QueryInterface(aIID, aInstancePtr);
+  }
+
+  static const GUID IID_SimpleDOMDeprecated =
+    { 0x0c539790,0x12e4,0x11cf,{0xb6,0x61,0x00,0xaa,0x00,0x4c,0xd6,0xd8} };
+  if (aGuidService == IID_ISimpleDOMNode ||
+      aGuidService == IID_SimpleDOMDeprecated ||
+      aGuidService == IID_IAccessible ||  aGuidService == IID_IAccessible2)
+    return mAccessible->QueryInterface(aIID, aInstancePtr);
+
+  return E_INVALIDARG;
+}
+
+} // namespace a11y
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/accessible/src/msaa/ServiceProvider.h
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_ServiceProvider_h_
+#define mozilla_a11y_ServiceProvider_h_
+
+#include <servprov.h>
+
+#include "AccessibleWrap.h"
+
+namespace mozilla {
+namespace a11y {
+
+class ServiceProvider MOZ_FINAL : public IServiceProvider
+{
+public:
+  ServiceProvider(AccessibleWrap* aAcc) : mRefCnt(0), mAccessible(aAcc) {}
+  ~ServiceProvider() {}
+
+  DECL_IUNKNOWN
+
+  // IServiceProvider
+  virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID aGuidService,
+                                                 REFIID aIID,
+                                                 void** aInstancePtr);
+
+private:
+  nsRefPtr<AccessibleWrap> mAccessible;
+};
+
+}
+}
+
+#endif
--- a/accessible/src/msaa/nsAccessNodeWrap.cpp
+++ b/accessible/src/msaa/nsAccessNodeWrap.cpp
@@ -1,31 +1,18 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsAccessNodeWrap.h"
 
-#include "AccessibleApplication.h"
-#include "ApplicationAccessibleWrap.h"
-#include "sdnAccessible.h"
+#include "DocAccessible.h"
+#include "nsWinUtils.h"
 
-#include "Compatibility.h"
-#include "nsAccessibilityService.h"
-#include "nsAccUtils.h"
-#include "nsCoreUtils.h"
-#include "nsWinUtils.h"
-#include "RootAccessible.h"
-#include "Statistics.h"
-
-#include "nsAttrName.h"
-#include "nsIDOMNodeList.h"
-#include "nsIDOMHTMLElement.h"
-#include "nsINameSpaceManager.h"
 #include "nsPIDOMWindow.h"
 #include "nsIServiceManager.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessNodeWrap
@@ -42,111 +29,16 @@ nsAccessNodeWrap::~nsAccessNodeWrap()
 }
 
 //-----------------------------------------------------
 // nsISupports methods
 //-----------------------------------------------------
 
 NS_IMPL_ISUPPORTS_INHERITED0(nsAccessNodeWrap, nsAccessNode)
 
-STDMETHODIMP nsAccessNodeWrap::QueryInterface(REFIID iid, void** ppv)
-{
-  *ppv = nullptr;
-
-  if (IID_IUnknown == iid) {
-    *ppv = static_cast<IUnknown*>(this);
-  } else {
-    return E_NOINTERFACE; //iid not supported.
-  }
-
-  (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
-  return S_OK;
-}
-
-STDMETHODIMP
-nsAccessNodeWrap::QueryService(REFGUID guidService, REFIID iid, void** ppv)
-{
-  *ppv = nullptr;
-
-  // Provide a special service ID for getting the accessible for the browser tab
-  // document that contains this accessible object. If this accessible object
-  // is not inside a browser tab then the service fails with E_NOINTERFACE.
-  // A use case for this is for screen readers that need to switch context or
-  // 'virtual buffer' when focus moves from one browser tab area to another.
-  static const GUID SID_IAccessibleContentDocument =
-    { 0xa5d8e1f3,0x3571,0x4d8f,{0x95,0x21,0x07,0xed,0x28,0xfb,0x07,0x2e} };
-  if (guidService == SID_IAccessibleContentDocument) {
-    if (iid != IID_IAccessible)
-      return E_NOINTERFACE;
-
-    nsCOMPtr<nsIDocShell> docShell = nsCoreUtils::GetDocShellFor(mContent);
-    if (!docShell)
-      return E_UNEXPECTED;
-
-    // Walk up the parent chain without crossing the boundary at which item
-    // types change, preventing us from walking up out of tab content.
-    nsCOMPtr<nsIDocShellTreeItem> root;
-    docShell->GetSameTypeRootTreeItem(getter_AddRefs(root));
-    if (!root)
-      return E_UNEXPECTED;
-
-
-    // If the item type is typeContent, we assume we are in browser tab content.
-    // Note this includes content such as about:addons, for consistency.
-    int32_t itemType;
-    root->GetItemType(&itemType);
-    if (itemType != nsIDocShellTreeItem::typeContent)
-      return E_NOINTERFACE;
-
-    // Make sure this is a document.
-    DocAccessible* docAcc = nsAccUtils::GetDocAccessibleFor(root);
-    if (!docAcc)
-      return E_UNEXPECTED;
-
-    *ppv = static_cast<IAccessible*>(docAcc);
-
-    (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
-    return S_OK;
-  }
-
-  // Can get to IAccessibleApplication from any node via QS
-  if (guidService == IID_IAccessibleApplication ||
-      (Compatibility::IsJAWS() && iid == IID_IAccessibleApplication)) {
-    ApplicationAccessibleWrap* applicationAcc =
-      static_cast<ApplicationAccessibleWrap*>(ApplicationAcc());
-    if (!applicationAcc)
-      return E_NOINTERFACE;
-
-    return applicationAcc->QueryInterface(iid, ppv);
-  }
-
-  /**
-   * To get an ISimpleDOMNode, ISimpleDOMDocument, ISimpleDOMText
-   * or any IAccessible2 interface on should use IServiceProvider like this:
-   * -----------------------------------------------------------------------
-   * ISimpleDOMDocument *pAccDoc = NULL;
-   * IServiceProvider *pServProv = NULL;
-   * pAcc->QueryInterface(IID_IServiceProvider, (void**)&pServProv);
-   * if (pServProv) {
-   *   const GUID unused;
-   *   pServProv->QueryService(unused, IID_ISimpleDOMDocument, (void**)&pAccDoc);
-   *   pServProv->Release();
-   * }
-   */
-
-  static const GUID IID_SimpleDOMDeprecated =
-    { 0x0c539790,0x12e4,0x11cf,{0xb6,0x61,0x00,0xaa,0x00,0x4c,0xd6,0xd8} };
-  if (guidService == IID_ISimpleDOMNode ||
-      guidService == IID_SimpleDOMDeprecated ||
-      guidService == IID_IAccessible ||  guidService == IID_IAccessible2)
-    return QueryInterface(iid, ppv);
-
-  return E_INVALIDARG;
-}
- 
 int nsAccessNodeWrap::FilterA11yExceptions(unsigned int aCode, EXCEPTION_POINTERS *aExceptionInfo)
 {
   if (aCode == EXCEPTION_ACCESS_VIOLATION) {
 #ifdef MOZ_CRASHREPORTER
     // MSAA swallows crashes (because it is COM-based)
     // but we still need to learn about those crashes so we can fix them
     // Make sure to pass them to the crash reporter
     nsCOMPtr<nsICrashReporter> crashReporter =
--- a/accessible/src/msaa/nsAccessNodeWrap.h
+++ b/accessible/src/msaa/nsAccessNodeWrap.h
@@ -48,35 +48,25 @@ namespace a11y {
 
 #ifdef __GNUC__
 // Inheriting from both XPCOM and MSCOM interfaces causes a lot of warnings
 // about virtual functions being hidden by each other. This is done by
 // design, so silence the warning.
 #pragma GCC diagnostic ignored "-Woverloaded-virtual"
 #endif
 
-class nsAccessNodeWrap : public nsAccessNode,
-                         public IServiceProvider
+class nsAccessNodeWrap : public nsAccessNode
 {
   public:
     NS_DECL_ISUPPORTS_INHERITED
 
 public: // construction, destruction
   nsAccessNodeWrap(nsIContent* aContent, DocAccessible* aDoc);
   virtual ~nsAccessNodeWrap();
 
-  // IUnknown
-  virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID aIID,
-                                                   void** aInstancePtr);
-
-  // IServiceProvider
-  virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID aGuidService,
-                                                 REFIID aIID,
-                                                 void** aInstancePtr);
-
     static int FilterA11yExceptions(unsigned int aCode, EXCEPTION_POINTERS *aExceptionInfo);
 
   static LRESULT CALLBACK WindowProc(HWND hWnd, UINT Msg,
                                      WPARAM WParam, LPARAM lParam);
 
   static nsRefPtrHashtable<nsPtrHashKey<void>, DocAccessible> sHWNDCache;
 };
 
--- a/b2g/chrome/content/dbg-browser-actors.js
+++ b/b2g/chrome/content/dbg-browser-actors.js
@@ -49,17 +49,26 @@ DeviceRootActor.prototype.disconnect = f
  * Handles the listTabs request.  Builds a list of actors for the single
  * tab (window) running in the process. The actors will survive
  * until at least the next listTabs request.
  */
 DeviceRootActor.prototype.onListTabs = function DRA_onListTabs() {
   let actorPool = new ActorPool(this.conn);
 
 #ifndef MOZ_WIDGET_GONK
-  let actor = this._tabActors.get(this.browser);
+  // Get the chrome debugger actor.
+  let actor = this._chromeDebugger;
+  if (!actor) {
+    actor = new ChromeDebuggerActor(this);
+    actor.parentID = this.actorID;
+    this._chromeDebugger = actor;
+    actorPool.addActor(actor);
+  }
+
+  actor = this._tabActors.get(this.browser);
   if (!actor) {
     actor = new DeviceTabActor(this.conn, this.browser);
     // this.actorID is set by ActorPool when an actor is put into one.
     actor.parentID = this.actorID;
     this._tabActors.set(this.browser, actor);
   }
   actorPool.addActor(actor);
 #endif
@@ -73,17 +82,18 @@ DeviceRootActor.prototype.onListTabs = f
   }
   this._tabActorPool = actorPool;
   this.conn.addActorPool(this._tabActorPool);
 
   let response = {
     'from': 'root',
     'selected': 0,
 #ifndef MOZ_WIDGET_GONK
-    'tabs': [actor.grip()]
+    'tabs': [actor.grip()],
+    "chromeDebugger": this._chromeDebugger.actorID
 #else
     'tabs': []
 #endif
   };
   this._appendExtraActors(response);
   return response;
 };
 
--- a/b2g/test/emulator.manifest
+++ b/b2g/test/emulator.manifest
@@ -1,6 +1,6 @@
 [{
-"size": 608318343,
-"digest": "9ab6487eccf44b0781cc96c2af9ba497f720a8d289bde40e29417f9db82788d6c8653c7dafa7443069f5898635eef45fa048ee99c03a9d0113c019a2f80f5aa8",
+"size": 606070399,
+"digest": "3d3899e2537bee5e3f969bb6d0e90fed93345512123e3133b1de793d59a8993d8174d9456cb92d86a880f6813d6049933de924cd522a433ef26c4bfa997777a7",
 "algorithm": "sha512",
 "filename": "emulator.zip"
 }]
--- a/browser/app/nsBrowserApp.cpp
+++ b/browser/app/nsBrowserApp.cpp
@@ -307,17 +307,18 @@ static int do_main(int argc, char* argv[
           *ptr = '\0';
           ptr++;
           newArgv[newArgc] = ptr;
           newArgc++;
           continue;
         }
         ptr++;
       }
-      newArgc--;
+      if (ptr == newArgv[newArgc-1])
+        newArgc--;
       int result = XRE_main(newArgc, newArgv, appData, mainFlags);
       XRE_FreeAppData(appData);
       return result;
     }
   }
 #endif
 
   int result = XRE_main(argc, argv, appData, mainFlags);
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -872,19 +872,22 @@ pref("browser.zoom.full", true);
 pref("browser.zoom.siteSpecific", true);
 
 // Whether or not to update background tabs to the current zoom level.
 pref("browser.zoom.updateBackgroundTabs", true);
 
 // The breakpad report server to link to in about:crashes
 pref("breakpad.reportURL", "http://crash-stats.mozilla.com/report/index/");
 
+#ifndef RELEASE_BUILD
 // Override submission of plugin hang reports to a different processing server
+// for the smaller-volume nightly/aurora populations.
 pref("toolkit.crashreporter.pluginHangSubmitURL",
      "https://hang-reports.mozilla.org/submit");
+#endif
 
 // URL for "Learn More" for Crash Reporter
 pref("toolkit.crashreporter.infoURL",
      "http://www.mozilla.com/legal/privacy/firefox.html#crash-reporter");
 
 // base URL for web-based support pages
 pref("app.support.baseURL", "http://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/");
 
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -4369,17 +4369,17 @@ var XULBrowserWindow = {
             elt.removeAttribute("disabled");
         }
       }
 
       var onContentRSChange = function onContentRSChange(e) {
         if (e.target.readyState != "interactive" && e.target.readyState != "complete")
           return;
 
-        e.target.removeEventListener("readystate", onContentRSChange);
+        e.target.removeEventListener("readystatechange", onContentRSChange);
         disableFindCommands(shouldDisableFind(e.target));
       }
 
       // Disable find commands in documents that ask for them to be disabled.
       if (aLocationURI &&
           (aLocationURI.schemeIs("about") || aLocationURI.schemeIs("chrome"))) {
         // Don't need to re-enable/disable find commands for same-document location changes
         // (e.g. the replaceStates in about:addons)
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -11,17 +11,17 @@ relativesrcdir  = @relativesrcdir@
 DIRS += \
 		newtab \
 		social \
 		$(NULL)
 
 include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_FILES = \
-		head.js \
+		head_plain.js \
 		test_feed_discovery.html \
 		feed_discovery.html \
 		test_bug395533.html \
 		bug395533-data.txt \
 		ctxmenu-image.png \
 		video.ogg \
 		test_offlineNotification.html \
 		offlineChild.html \
@@ -156,16 +156,17 @@ endif
                  browser_bug735471.js \
                  browser_bug743421.js \
                  browser_bug749738.js \
                  browser_bug763468_perwindowpb.js \
                  browser_bug767836_perwindowpb.js \
                  browser_bug783614.js \
                  browser_bug797677.js \
                  browser_bug816527.js \
+                 browser_bug822367.js \
                  browser_bug832435.js \
                  browser_canonizeURL.js \
                  browser_customize.js \
                  browser_findbarClose.js \
                  browser_homeDrop.js \
                  browser_keywordBookmarklets.js \
                  browser_contextSearchTabPosition.js \
                  browser_ctrlTab.js \
@@ -232,16 +233,25 @@ endif
                  browser_visibleTabs_contextMenu.js \
                  browser_visibleTabs_bookmarkAllPages.js \
                  browser_visibleTabs_bookmarkAllTabs.js \
                  browser_visibleTabs_tabPreview.js \
                  bug592338.html \
                  disablechrome.html \
                  discovery.html \
                  domplate_test.js \
+                 file_bug822367_1.html \
+                 file_bug822367_1.js \
+                 file_bug822367_2.html \
+                 file_bug822367_3.html \
+                 file_bug822367_4.html \
+                 file_bug822367_4.js \
+                 file_bug822367_4B.html \
+                 file_bug822367_5.html \
+                 file_bug822367_6.html \
                  moz.png \
                  video.ogg \
                  test_bug435035.html \
                  test_bug462673.html \
                  page_style_sample.html \
                  plugin_unknown.html \
                  plugin_test.html \
                  plugin_test2.html \
rename from content/base/test/chrome/browser_bug822367.js
rename to browser/base/content/test/browser_bug822367.js
--- a/content/base/test/chrome/browser_bug822367.js
+++ b/browser/base/content/test/browser_bug822367.js
@@ -1,16 +1,16 @@
 /*
  * User Override Mixed Content Block - Tests for Bug 822367
  */
 
 
 const PREF_DISPLAY = "security.mixed_content.block_display_content";
 const PREF_ACTIVE = "security.mixed_content.block_active_content";
-const gHttpTestRoot = "https://example.com/tests/content/base/test/";
+const gHttpTestRoot = "https://example.com/browser/browser/base/content/test/";
 var origBlockDisplay;
 var origBlockActive;
 var gTestBrowser = null;
 
 registerCleanupFunction(function() {
   // Set preferences back to their original values
   Services.prefs.setBoolPref(PREF_DISPLAY, origBlockDisplay);
   Services.prefs.setBoolPref(PREF_ACTIVE, origBlockActive);
rename from content/base/test/file_bug822367_1.html
rename to browser/base/content/test/file_bug822367_1.html
--- a/content/base/test/file_bug822367_1.html
+++ b/browser/base/content/test/file_bug822367_1.html
@@ -7,12 +7,12 @@ https://bugzilla.mozilla.org/show_bug.cg
 <head>
   <meta charset="utf-8">
   <title>Test 1 for Bug 822367</title>
 </head>
 <body>
   <div id="testContent">
     <p id="p1"></p>
   </div>
-  <script src="http://example.com/tests/content/base/test/file_bug822367_1.js">
+  <script src="http://example.com/browser/browser/base/content/test/file_bug822367_1.js">
   </script>
 </body>
 </html>
rename from content/base/test/file_bug822367_1.js
rename to browser/base/content/test/file_bug822367_1.js
rename from content/base/test/file_bug822367_2.html
rename to browser/base/content/test/file_bug822367_2.html
rename from content/base/test/file_bug822367_3.html
rename to browser/base/content/test/file_bug822367_3.html
--- a/content/base/test/file_bug822367_3.html
+++ b/browser/base/content/test/file_bug822367_3.html
@@ -16,12 +16,12 @@ https://bugzilla.mozilla.org/show_bug.cg
   }
   </script>
 </head>
 <body>
   <div id="testContent">
     <p id="p1"></p>
     <img src="http://example.com/tests/image/test/mochitest/blue.png" onload="foo()">
   </div>
-  <script src="http://example.com/tests/content/base/test/file_bug822367_1.js">
+  <script src="http://example.com/browser/browser/base/content/test/file_bug822367_1.js">
   </script>
 </body>
 </html>
rename from content/base/test/file_bug822367_4.html
rename to browser/base/content/test/file_bug822367_4.html
--- a/content/base/test/file_bug822367_4.html
+++ b/browser/base/content/test/file_bug822367_4.html
@@ -7,12 +7,12 @@ https://bugzilla.mozilla.org/show_bug.cg
 <head>
   <meta charset="utf-8">
   <title>Test 4 for Bug 822367</title>
 </head>
 <body>
   <div id="testContent">
     <p id="p1"></p>
   </div>
-  <script src="http://example.com/tests/content/base/test/file_bug822367_4.js">
+  <script src="http://example.com/browser/browser/base/content/test/file_bug822367_4.js">
   </script>
 </body>
 </html>
rename from content/base/test/file_bug822367_4.js
rename to browser/base/content/test/file_bug822367_4.js
--- a/content/base/test/file_bug822367_4.js
+++ b/browser/base/content/test/file_bug822367_4.js
@@ -1,1 +1,1 @@
-document.location = "https://example.com/tests/content/base/test/file_bug822367_4B.html";
+document.location = "https://example.com/browser/browser/base/content/test/file_bug822367_4B.html";
rename from content/base/test/file_bug822367_4B.html
rename to browser/base/content/test/file_bug822367_4B.html
--- a/content/base/test/file_bug822367_4B.html
+++ b/browser/base/content/test/file_bug822367_4B.html
@@ -7,12 +7,12 @@ https://bugzilla.mozilla.org/show_bug.cg
 <head>
   <meta charset="utf-8">
   <title>Test 4B Location Change for Bug 822367</title>
 </head>
 <body>
   <div id="testContent">
     <p id="p1"></p>
   </div>
-  <script src="http://example.com/tests/content/base/test/file_bug822367_1.js">
+  <script src="http://example.com/browser/browser/base/content/test/file_bug822367_1.js">
   </script>
 </body>
 </html>
rename from content/base/test/file_bug822367_5.html
rename to browser/base/content/test/file_bug822367_5.html
--- a/content/base/test/file_bug822367_5.html
+++ b/browser/base/content/test/file_bug822367_5.html
@@ -6,17 +6,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 -->
 <head>
   <meta charset="utf-8">
   <title>Test 5 for Bug 822367</title>
   <script>
     function createDoc()
     {
       var doc=document.open("text/html","replace");
-      doc.write('<!DOCTYPE html><html><body><p id="p1">This is some content</p><script src="http://example.com/tests/content/base/test/file_bug822367_1.js">\<\/script\>\<\/body>\<\/html>');
+      doc.write('<!DOCTYPE html><html><body><p id="p1">This is some content</p><script src="http://example.com/browser/browser/base/content/test/file_bug822367_1.js">\<\/script\>\<\/body>\<\/html>');
       doc.close();
     }
   </script>
 </head>
 <body>
   <div id="testContent">
     <img src="https://example.com/tests/image/test/mochitest/blue.png" onload="createDoc()">
   </div>
rename from content/base/test/file_bug822367_6.html
rename to browser/base/content/test/file_bug822367_6.html
--- a/content/base/test/file_bug822367_6.html
+++ b/browser/base/content/test/file_bug822367_6.html
@@ -5,12 +5,12 @@ Test 6 for Mixed Content Blocker User Ov
 https://bugzilla.mozilla.org/show_bug.cgi?id=822367
 -->
 <head>
   <meta charset="utf-8">
   <title>Test 6 for Bug 822367</title>
 </head>
 <body>
   <div id="testContent">
-    <iframe name="f1" id="f1" src="https://example.com/tests/content/base/test/file_bug822367_5.html"></iframe>
+    <iframe name="f1" id="f1" src="https://example.com/browser/browser/base/content/test/file_bug822367_5.html"></iframe>
   </div>
 </body>
 </html>
--- a/browser/base/content/test/head.js
+++ b/browser/base/content/test/head.js
@@ -1,9 +1,8 @@
-netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
   "resource://gre/modules/commonjs/sdk/core/promise.js");
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
   "resource://gre/modules/Task.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
   "resource://gre/modules/PlacesUtils.jsm");
copy from browser/base/content/test/head.js
copy to browser/base/content/test/head_plain.js
--- a/browser/base/content/test/head.js
+++ b/browser/base/content/test/head_plain.js
@@ -1,264 +1,15 @@
-netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
-Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "Promise",
-  "resource://gre/modules/commonjs/sdk/core/promise.js");
-XPCOMUtils.defineLazyModuleGetter(this, "Task",
-  "resource://gre/modules/Task.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
-  "resource://gre/modules/PlacesUtils.jsm");
-
-function whenDelayedStartupFinished(aWindow, aCallback) {
-  Services.obs.addObserver(function observer(aSubject, aTopic) {
-    if (aWindow == aSubject) {
-      Services.obs.removeObserver(observer, aTopic);
-      executeSoon(aCallback);
-    }
-  }, "browser-delayed-startup-finished", false);
-}
-
-function findChromeWindowByURI(aURI) {
-  let windows = Services.wm.getEnumerator(null);
-  while (windows.hasMoreElements()) {
-    let win = windows.getNext();
-    if (win.location.href == aURI)
-      return win;
-  }
-  return null;
-}
-
-function updateTabContextMenu(tab) {
-  let menu = document.getElementById("tabContextMenu");
-  if (!tab)
-    tab = gBrowser.selectedTab;
-  var evt = new Event("");
-  tab.dispatchEvent(evt);
-  menu.openPopup(tab, "end_after", 0, 0, true, false, evt);
-  is(TabContextMenu.contextTab, tab, "TabContextMenu context is the expected tab");
-  menu.hidePopup();
-}
-
-function findToolbarCustomizationWindow(aBrowserWin) {
-  if (!aBrowserWin)
-    aBrowserWin = window;
-
-  let iframe = aBrowserWin.document.getElementById("customizeToolbarSheetIFrame");
-  let win = iframe && iframe.contentWindow;
-  if (win)
-    return win;
-
-  win = findChromeWindowByURI("chrome://global/content/customizeToolbar.xul");
-  if (win && win.opener == aBrowserWin)
-    return win;
-
-  throw Error("Failed to find the customization window");
-}
-
-function openToolbarCustomizationUI(aCallback, aBrowserWin) {
-  if (!aBrowserWin)
-    aBrowserWin = window;
-
-  aBrowserWin.document.getElementById("cmd_CustomizeToolbars").doCommand();
-
-  aBrowserWin.gNavToolbox.addEventListener("beforecustomization", function UI_loaded() {
-    aBrowserWin.gNavToolbox.removeEventListener("beforecustomization", UI_loaded);
-
-    let win = findToolbarCustomizationWindow(aBrowserWin);
-    waitForFocus(function () {
-      aCallback(win);
-    }, win);
-  });
-}
-
-function closeToolbarCustomizationUI(aCallback, aBrowserWin) {
-  let win = findToolbarCustomizationWindow(aBrowserWin);
-
-  win.addEventListener("unload", function unloaded() {
-    win.removeEventListener("unload", unloaded);
-    executeSoon(aCallback);
-  });
-
-  let button = win.document.getElementById("donebutton");
-  button.focus();
-  button.doCommand();
-}
 
 function waitForCondition(condition, nextTest, errorMsg) {
   var tries = 0;
   var interval = setInterval(function() {
     if (tries >= 30) {
       ok(false, errorMsg);
       moveOn();
     }
     if (condition()) {
       moveOn();
     }
     tries++;
   }, 100);
   var moveOn = function() { clearInterval(interval); nextTest(); };
 }
-
-function getTestPlugin() {
-  var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
-  var tags = ph.getPluginTags();
-
-  // Find the test plugin
-  for (var i = 0; i < tags.length; i++) {
-    if (tags[i].name == "Test Plug-in")
-      return tags[i];
-  }
-  ok(false, "Unable to find plugin");
-  return null;
-}
-
-function updateBlocklist(aCallback) {
-  var blocklistNotifier = Cc["@mozilla.org/extensions/blocklist;1"]
-                          .getService(Ci.nsITimerCallback);
-  var observer = function() {
-    aCallback();
-    Services.obs.removeObserver(observer, "blocklist-updated");
-  };
-  Services.obs.addObserver(observer, "blocklist-updated", false);
-  blocklistNotifier.notify(null);
-}
-
-var _originalTestBlocklistURL = null;
-function setAndUpdateBlocklist(aURL, aCallback) {
-  if (!_originalTestBlocklistURL)
-    _originalTestBlocklistURL = Services.prefs.getCharPref("extensions.blocklist.url");
-  Services.prefs.setCharPref("extensions.blocklist.url", aURL);
-  updateBlocklist(aCallback);
-}
-
-function resetBlocklist() {
-  Services.prefs.setCharPref("extensions.blocklist.url", _originalTestBlocklistURL);
-}
-
-function whenNewWindowLoaded(aOptions, aCallback) {
-  let win = OpenBrowserWindow(aOptions);
-  win.addEventListener("load", function onLoad() {
-    win.removeEventListener("load", onLoad, false);
-    aCallback(win);
-  }, false);
-}
-
-/**
- * Waits for all pending async statements on the default connection, before
- * proceeding with aCallback.
- *
- * @param aCallback
- *        Function to be called when done.
- * @param aScope
- *        Scope for the callback.
- * @param aArguments
- *        Arguments array for the callback.
- *
- * @note The result is achieved by asynchronously executing a query requiring
- *       a write lock.  Since all statements on the same connection are
- *       serialized, the end of this write operation means that all writes are
- *       complete.  Note that WAL makes so that writers don't block readers, but
- *       this is a problem only across different connections.
- */
-function waitForAsyncUpdates(aCallback, aScope, aArguments) {
-  let scope = aScope || this;
-  let args = aArguments || [];
-  let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
-                              .DBConnection;
-  let begin = db.createAsyncStatement("BEGIN EXCLUSIVE");
-  begin.executeAsync();
-  begin.finalize();
-
-  let commit = db.createAsyncStatement("COMMIT");
-  commit.executeAsync({
-    handleResult: function() {},
-    handleError: function() {},
-    handleCompletion: function(aReason) {
-      aCallback.apply(scope, args);
-    }
-  });
-  commit.finalize();
-}
-
-/**
- * Asynchronously check a url is visited.
-
- * @param aURI The URI.
- * @param aExpectedValue The expected value.
- * @return {Promise}
- * @resolves When the check has been added successfully.
- * @rejects JavaScript exception.
- */
-function promiseIsURIVisited(aURI, aExpectedValue) {
-  let deferred = Promise.defer();
-  PlacesUtils.asyncHistory.isURIVisited(aURI, function(aURI, aIsVisited) {
-    deferred.resolve(aIsVisited);
-  });
-
-  return deferred.promise;
-}
-
-function addVisits(aPlaceInfo, aCallback) {
-  let places = [];
-  if (aPlaceInfo instanceof Ci.nsIURI) {
-    places.push({ uri: aPlaceInfo });
-  } else if (Array.isArray(aPlaceInfo)) {
-    places = places.concat(aPlaceInfo);
-  } else {
-    places.push(aPlaceInfo);
-   }
-
-  // Create mozIVisitInfo for each entry.
-  let now = Date.now();
-  for (let i = 0; i < places.length; i++) {
-    if (!places[i].title) {
-      places[i].title = "test visit for " + places[i].uri.spec;
-    }
-    places[i].visits = [{
-      transitionType: places[i].transition === undefined ? Ci.nsINavHistoryService.TRANSITION_LINK
-                                                         : places[i].transition,
-      visitDate: places[i].visitDate || (now++) * 1000,
-      referrerURI: places[i].referrer
-    }];
-  }
-
-  PlacesUtils.asyncHistory.updatePlaces(
-    places,
-    {
-      handleError: function AAV_handleError() {
-        throw("Unexpected error in adding visit.");
-      },
-      handleResult: function () {},
-      handleCompletion: function UP_handleCompletion() {
-        if (aCallback)
-          aCallback();
-      }
-    }
-  );
-}
-
-/**
- * Ensures that the specified URIs are either cleared or not.
- *
- * @param aURIs
- *        Array of page URIs
- * @param aShouldBeCleared
- *        True if each visit to the URI should be cleared, false otherwise
- */
-function promiseHistoryClearedState(aURIs, aShouldBeCleared) {
-  let deferred = Promise.defer();
-  let callbackCount = 0;
-  let niceStr = aShouldBeCleared ? "no longer" : "still";
-  function callbackDone() {
-    if (++callbackCount == aURIs.length)
-      deferred.resolve();
-  }
-  aURIs.forEach(function (aURI) {
-    PlacesUtils.asyncHistory.isURIVisited(aURI, function(aURI, aIsVisited) {
-      is(aIsVisited, !aShouldBeCleared,
-         "history visit " + aURI.spec + " should " + niceStr + " exist");
-      callbackDone();
-    });
-  });
-
-  return deferred.promise;
-}
--- a/browser/base/content/test/test_bug787619.html
+++ b/browser/base/content/test/test_bug787619.html
@@ -1,15 +1,15 @@
 <html>
 <head>
   <title>Test for Bug 787619</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
-  <script type="application/javascript;version=1.7" src="head.js"></script>
+  <script type="application/javascript;version=1.7" src="head_plain.js"></script>
   <script>
     SpecialPowers.setBoolPref('plugins.click_to_play', true);
   </script>
 </head>
 <body>
 
   <a id="wrapper">
     <embed id="plugin" style="width: 200px; height: 200px" type="application/x-test">
--- a/browser/extensions/pdfjs/content/web/viewer.html
+++ b/browser/extensions/pdfjs/content/web/viewer.html
@@ -9,17 +9,17 @@ You may obtain a copy of the License at
     http://www.apache.org/licenses/LICENSE-2.0
 
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 -->
-<html dir="ltr" mozdisallowselectionprint>
+<html dir="ltr" mozdisallowselectionprint moznomarginboxes>
   <head>
     <meta charset="utf-8">
     <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
     <title>PDF.js viewer</title>
 
 <!-- This snippet is used in firefox extension, see Makefile -->
 <base href="resource://pdf.js/web/" />
 <script type="text/javascript" src="l10n.js"></script>
--- a/browser/metro/base/content/ContextCommands.js
+++ b/browser/metro/base/content/ContextCommands.js
@@ -18,74 +18,215 @@ var ContextCommands = {
   get docRef() {
     return Browser.selectedBrowser.contentWindow.document;
   },
 
   /*
    * Context menu handlers
    */
 
+  // Text specific
+
   copy: function cc_copy() {
     let target = ContextMenuUI.popupState.target;
     if (target.localName == "browser") {
+      // content
       if (ContextMenuUI.popupState.string != "undefined") {
         this.clipboard.copyString(ContextMenuUI.popupState.string,
                                   this.docRef);
+        this.showToast(Strings.browser.GetStringFromName("selectionHelper.textCopied"));
       } else {
         let x = ContextMenuUI.popupState.x;
         let y = ContextMenuUI.popupState.y;
         let json = {x: x, y: y, command: "copy" };
         target.messageManager.sendAsyncMessage("Browser:ContextCommand", json);
       }
     } else {
+      // chrome
       target.editor.copy();
+      this.showToast(Strings.browser.GetStringFromName("selectionHelper.textCopied"));
     }
 
     if (target)
       target.focus();
   },
 
   paste: function cc_paste() {
     let target = ContextMenuUI.popupState.target;
     if (target.localName == "browser") {
+      // content
       let x = ContextMenuUI.popupState.x;
       let y = ContextMenuUI.popupState.y;
       let json = {x: x, y: y, command: "paste" };
       target.messageManager.sendAsyncMessage("Browser:ContextCommand", json);
     } else {
+      // chrome
       target.editor.paste(Ci.nsIClipboard.kGlobalClipboard);
       target.focus();
     }
   },
 
   pasteAndGo: function cc_pasteAndGo() {
     let target = ContextMenuUI.popupState.target;
     target.editor.selectAll();
     target.editor.paste(Ci.nsIClipboard.kGlobalClipboard);
     BrowserUI.goToURI();
   },
 
+  select: function cc_select() {
+    let contextInfo = { name: "",
+                        json: ContextMenuUI.popupState,
+                        target: ContextMenuUI.popupState.target };
+    SelectionHelperUI.openEditSession(contextInfo);
+  },
+
   selectAll: function cc_selectAll() {
     let target = ContextMenuUI.popupState.target;
     if (target.localName == "browser") {
+      // content
       let x = ContextMenuUI.popupState.x;
       let y = ContextMenuUI.popupState.y;
       let json = {x: x, y: y, command: "select-all" };
       target.messageManager.sendAsyncMessage("Browser:ContextCommand", json);
+      let contextInfo = { name: "",
+                          json: ContextMenuUI.popupState,
+                          target: ContextMenuUI.popupState.target };
+      SelectionHelperUI.attachEditSession(contextInfo);
     } else {
+      // chrome
       target.editor.selectAll();
       target.focus();
     }
   },
 
-  openInNewTab: function cc_openInNewTab() {
-    Browser.addTab(ContextMenuUI.popupState.linkURL, false, Browser.selectedTab);
-    ContextUI.peekTabs();
+  // called on display of the search text menu item
+  searchTextSetup: function cc_searchTextSetup(aRichListItem, aSearchString) {
+    let defaultURI;
+    let defaultName;
+    try {
+      let defaultPB = Services.prefs.getDefaultBranch(null);
+      const nsIPLS = Ci.nsIPrefLocalizedString;
+      defaultName = defaultPB.getComplexValue("browser.search.defaultenginename", nsIPLS).data;
+      let defaultEngine = Services.search.getEngineByName(defaultName);
+      defaultURI = defaultEngine.getSubmission(aSearchString).uri.spec;
+    } catch (ex) {
+      Cu.reportError(ex);
+      return false;
+    }
+    // label child node
+    let label = Services.strings
+                        .createBundle("chrome://browser/locale/browser.properties")
+                        .formatStringFromName("browser.search.contextTextSearchLabel",
+                                              [defaultName], 1);
+    aRichListItem.childNodes[0].setAttribute("value", label);
+    aRichListItem.setAttribute("searchString", defaultURI);
+    return true;
+  },
+
+  searchText: function cc_searchText(aRichListItem) {
+    let defaultURI = aRichListItem.getAttribute("searchString");
+    aRichListItem.childNodes[0].setAttribute("value", "");
+    aRichListItem.setAttribute("searchString", "");
+    BrowserUI.newTab(defaultURI, Browser.selectedTab);
+  },
+
+  // Link specific
+
+  openLinkInNewTab: function cc_openLinkInNewTab() {
+    BrowserUI.newTab(ContextMenuUI.popupState.linkURL, Browser.selectedTab);
+  },
+
+  copyLink: function cc_copyLink() {
+    this.clipboard.copyString(ContextMenuUI.popupState.linkURL,
+                              this.docRef);
+    this.showToast(Strings.browser.GetStringFromName("selectionHelper.linkCopied"));
+  },
+
+  bookmarkLink: function cc_bookmarkLink() {
+    let state = ContextMenuUI.popupState;
+    let uri = Util.makeURI(state.linkURL);
+    let title = state.linkTitle || state.linkURL;
+
+    try {
+      Bookmarks.addForURI(uri, title);
+    } catch (e) {
+      return;
+    }
+
+    this.showToast(Strings.browser.GetStringFromName("alertLinkBookmarked"));
+  },
+
+  // Image specific
+
+  saveImageToLib: function cc_saveImageToLib() {
+    this.saveToWinLibrary("Pict");
   },
 
+  copyImage: function cc_copyImage() {
+    // copy to clibboard
+    this.sendCommand("copy-image-contents");
+  },
+
+  copyImageSrc: function cc_copyImageSrc() {
+    this.clipboard.copyString(ContextMenuUI.popupState.mediaURL,
+                              this.docRef);
+    this.showToast(Strings.browser.GetStringFromName("selectionHelper.linkCopied"));
+  },
+
+  openImageInNewTab: function cc_openImageInNewTab() {
+    BrowserUI.newTab(ContextMenuUI.popupState.mediaURL, Browser.selectedTab);
+  },
+
+  // Video specific
+
+  saveVideoToLib: function cc_saveVideoToLib() {
+    this.saveToWinLibrary("Vids");
+  },
+
+  copyVideoSrc: function cc_copyVideoSrc() {
+    this.clipboard.copyString(ContextMenuUI.popupState.mediaURL,
+                              this.docRef);
+    this.showToast(Strings.browser.GetStringFromName("selectionHelper.linkCopied"));
+  },
+
+  openVideoInNewTab: function cc_openVideoInNewTab() {
+    BrowserUI.newTab(ContextMenuUI.popupState.mediaURL, Browser.selectedTab);
+  },
+
+  openVideoInFullscreen: function cc_openVideoInFullscreen() {
+    // XXX currently isn't working.
+    this.sendCommand('videotab');
+  },
+
+  // Bookmarks
+
+  editBookmark: function cc_editBookmark() {
+    let target = ContextMenuUI.popupState.target;
+    target.startEditing();
+  },
+
+  removeBookmark: function cc_removeBookmark() {
+    let target = ContextMenuUI.popupState.target;
+    target.remove();
+  },
+
+  // App bar
+
+  findInPage: function cc_findInPage() {
+    FindHelperUI.show();
+  },
+
+  viewOnDesktop: function cc_viewOnDesktop() {
+    Appbar.onViewOnDesktop();
+  },
+
+  /*
+   * Utilities
+   */
+
   saveToWinLibrary: function cc_saveToWinLibrary(aType) {
     let popupState = ContextMenuUI.popupState;
     let browser = popupState.target;
 
     // ContentAreaUtils internalSave relies on various desktop related prefs,
     // values, and functionality. We want to be more direct by saving the
     // image to the users Windows Library. If users want to specify the
     // save location they can use the context menu option 'Save (type) To'.
@@ -111,95 +252,27 @@ var ContextCommands = {
       targetFile        : saveLocationPath,
       sourceCacheKey    : null,
       sourcePostData    : null,
       bypassCache       : false,
       initiatingWindow  : this.docRef.defaultView
     });
   },
 
-  saveVideo: function cc_saveVideo() {
-    this.saveToWinLibrary("Vids");
-  },
-
-  saveVideoTo: function cc_saveVideoTo() {
-    this.saveFileAs(ContextMenuUI.popupState);
-  },
-
-  saveImage: function cc_saveImage() {
-    this.saveToWinLibrary("Pict");
-  },
-
-  saveImageTo: function cc_saveImageTo() {
-    this.saveFileAs(ContextMenuUI.popupState);
-  },
-
-  copyLink: function cc_copyLink() {
-    this.clipboard.copyString(ContextMenuUI.popupState.linkURL,
-                              this.docRef);
-  },
-
-  copyEmail: function cc_copyEmail() {
-    this.clipboard.copyString(ContextMenuUI.popupState.linkURL.substr(ContextMenuUI.popupState.linkURL.indexOf(':')+1),
-                              this.docRef);
-  },
-
-  copyPhone: function cc_copyPhone() {
-    this.clipboard.copyString(ContextMenuUI.popupState.linkURL.substr(ContextMenuUI.popupState.linkURL.indexOf(':')+1),
-                              this.docRef);
-  },
-
-  copyImage: function cc_copyImage() {
-    this.sendCommand("copy-image-contents");
-  },
-
-  bookmarkLink: function cc_bookmarkLink() {
-    let state = ContextMenuUI.popupState;
-    let uri = Util.makeURI(state.linkURL);
-    let title = state.linkTitle || state.linkURL;
-
-    try {
-      Bookmarks.addForURI(uri, title);
-    } catch (e) {
-      return;
-    }
-
-    let message = Strings.browser.GetStringFromName("alertLinkBookmarked");
+  showToast: function showToast(aString) {
     let toaster = Cc["@mozilla.org/toaster-alerts-service;1"].getService(Ci.nsIAlertsService);
-    toaster.showAlertNotification(null, message, "", false, "", null);
+    toaster.showAlertNotification(null, aString, "", false, "", null);
   },
 
   sendCommand: function cc_playVideo(aCommand) {
     // Send via message manager over to ContextMenuHandler
     let browser = ContextMenuUI.popupState.target;
     browser.messageManager.sendAsyncMessage("Browser:ContextCommand", { command: aCommand });
   },
 
-  editBookmark: function cc_editBookmark() {
-    let target = ContextMenuUI.popupState.target;
-    target.startEditing();
-  },
-
-  removeBookmark: function cc_removeBookmark() {
-    let target = ContextMenuUI.popupState.target;
-    target.remove();
-  },
-
-  findInPage: function cc_findInPage() {
-    FindHelperUI.show();
-  },
-
-  viewOnDesktop: function cc_viewOnDesktop() {
-    Appbar.onViewOnDesktop();
-  },
-
-  /*
-   * Utilities
-   */
-
   /*
    * isAccessibleDirectory
    *
    * Test to see if the directory exists and is writable.
    */
   isAccessibleDirectory: function isAccessibleDirectory(aDirectory) {
     return aDirectory && aDirectory.exists() && aDirectory.isDirectory() &&
            aDirectory.isWritable();
--- a/browser/metro/base/content/browser.xul
+++ b/browser/metro/base/content/browser.xul
@@ -52,31 +52,31 @@
   </broadcasterset>
 
   <observerset id="observerset">
     <observes id="observe_contentShowing" element="bcast_contentShowing" attribute="disabled" onbroadcast="BrowserUI.updateUIFocus();"/>
   </observerset>
 
   <commandset id="mainCommandSet">
     <!-- basic navigation -->
-    <command id="cmd_back" label="&back.label;" disabled="true" oncommand="CommandUpdater.doCommand(this.id);"/>
-    <command id="cmd_forward" label="&forward.label;" disabled="true" oncommand="CommandUpdater.doCommand(this.id);" observes="bcast_urlbarState"/>
+    <command id="cmd_back" disabled="true" oncommand="CommandUpdater.doCommand(this.id);"/>
+    <command id="cmd_forward" disabled="true" oncommand="CommandUpdater.doCommand(this.id);" observes="bcast_urlbarState"/>
     <command id="cmd_handleBackspace" oncommand="BrowserUI.handleBackspace();" />
     <command id="cmd_handleShiftBackspace" oncommand="BrowserUI.handleShiftBackspace();" />
-    <command id="cmd_reload" label="&reload.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
+    <command id="cmd_reload" oncommand="CommandUpdater.doCommand(this.id);"/>
     <command id="cmd_forceReload" oncommand="CommandUpdater.doCommand(this.id);"/>
-    <command id="cmd_stop" label="&stop.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
-    <command id="cmd_go" label="&go.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
+    <command id="cmd_stop" oncommand="CommandUpdater.doCommand(this.id);"/>
+    <command id="cmd_go" oncommand="CommandUpdater.doCommand(this.id);"/>
     <command id="cmd_openLocation" oncommand="CommandUpdater.doCommand(this.id);"/>
     <command id="cmd_home" oncommand="CommandUpdater.doCommand(this.id);"/>
 
     <!-- tabs -->
-    <command id="cmd_newTab" label="&newtab.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
-    <command id="cmd_closeTab" label="&closetab.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
-    <command id="cmd_undoCloseTab" label="&undoclosetab.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
+    <command id="cmd_newTab" oncommand="CommandUpdater.doCommand(this.id);"/>
+    <command id="cmd_closeTab" oncommand="CommandUpdater.doCommand(this.id);"/>
+    <command id="cmd_undoCloseTab" oncommand="CommandUpdater.doCommand(this.id);"/>
 #ifdef MOZ_SERVICES_SYNC
     <command id="cmd_remoteTabs" oncommand="CommandUpdater.doCommand(this.id);"/>
 #endif
 
     <!-- misc -->
     <command id="cmd_close" oncommand="CommandUpdater.doCommand(this.id);"/>
     <command id="cmd_quit" oncommand="CommandUpdater.doCommand(this.id);"/>
     <command id="cmd_actions" oncommand="CommandUpdater.doCommand(this.id);"/>
@@ -96,22 +96,22 @@
     <command id="cmd_volumeLeft" observes="bcast_contentShowing" oncommand="CommandUpdater.doCommand(this.id);"/>
     <command id="cmd_volumeRight" observes="bcast_contentShowing" oncommand="CommandUpdater.doCommand(this.id);"/>
 
     <!-- scrolling -->
     <command id="cmd_scrollPageUp" oncommand="CommandUpdater.doCommand(this.id);"/>
     <command id="cmd_scrollPageDown" oncommand="CommandUpdater.doCommand(this.id);"/>
 
     <!-- editing -->
-    <command id="cmd_cut" label="&cut.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
-    <command id="cmd_copy" label="&copy.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
-    <command id="cmd_copylink" label="&copylink.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
-    <command id="cmd_paste" label="&paste.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
-    <command id="cmd_delete" label="&delete.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
-    <command id="cmd_selectAll" label="&selectAll.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
+    <command id="cmd_cut" oncommand="CommandUpdater.doCommand(this.id);"/>
+    <command id="cmd_copy" oncommand="CommandUpdater.doCommand(this.id);"/>
+    <command id="cmd_copylink" oncommand="CommandUpdater.doCommand(this.id);"/>
+    <command id="cmd_paste" oncommand="CommandUpdater.doCommand(this.id);"/>
+    <command id="cmd_delete" oncommand="CommandUpdater.doCommand(this.id);"/>
+    <command id="cmd_selectAll" oncommand="CommandUpdater.doCommand(this.id);"/>
 
     <!-- forms navigation -->
     <command id="cmd_formPrevious" oncommand="FormHelperUI.goToPrevious();"/>
     <command id="cmd_formNext" oncommand="FormHelperUI.goToNext();"/>
     <command id="cmd_formClose" oncommand="FormHelperUI.hide();"/>
 
     <!-- find navigation -->
     <command id="cmd_findPrevious" oncommand="FindHelperUI.goToPrevious();"/>
@@ -190,20 +190,20 @@
             <observes element="bcast_windowState" attribute="*"/>
             <observes element="bcast_urlbarState" attribute="*"/>
             <hbox id="unified-back-forward-button" class="chromeclass-toolbar-additional"
                observes="bcast_windowState"
                context="backForwardMenu" removable="true"
                forwarddisabled="true"
                title="Back/Forward">
               <toolbarbutton id="back-button" class="toolbarbutton"
-                             label="Back"
+                             label="&back.label;"
                              command="cmd_back"/>
               <toolbarbutton id="forward-button" class="toolbarbutton"
-                             label="Forward"
+                             label="&forward.label;"
                              command="cmd_forward"/>
               <dummyobservertarget hidden="true"
                                    onbroadcast="if (this.getAttribute('disabled') == 'true')
                                                   this.parentNode.setAttribute('forwarddisabled', 'true');
                                                 else
                                                   this.parentNode.removeAttribute('forwarddisabled');">
                 <observes element="cmd_forward" attribute="disabled"/>
               </dummyobservertarget>
@@ -240,17 +240,17 @@
 
             <hbox id="urlbar-icons" observes="bcast_urlbarState">
               <toolbarbutton id="tool-reload" oncommand="CommandUpdater.doCommand(event.shiftKey ? 'cmd_forceReload' : 'cmd_reload');"/>
               <toolbarbutton id="tool-stop" command="cmd_stop"/>
             </hbox>
           </toolbar>
 
           <box id="toolbar-transition" observes="bcast_windowState" >
-            <toolbarbutton id="tool-new-tab" command="cmd_newTab"/>
+            <toolbarbutton id="tool-new-tab" command="cmd_newTab" label="&newtab.label;"/>
           </box>
         </hbox>
 
         <hbox id="progress-control" layer="true"></hbox>
 
         <!-- Start UI -->
         <hbox id="start-container" flex="1" observes="bcast_windowState" class="meta content-height content-width" onclick="false;">
           <!-- portrait/landscape/filled view -->
@@ -554,88 +554,93 @@
         </vbox>
       </dialog>
     </box>
 #endif
 
     <box id="context-container" class="menu-container" hidden="true">
       <vbox id="context-popup" class="menu-popup">
         <richlistbox id="context-commands" bindingType="contextmenu" flex="1">
+          <!-- priority="low" items are hidden by default when a context is being displayed
+               for two or more media types. (e.g. a linked image) -->
+          <!-- Note the order of richlistitem here is important as it is reflected in the
+               menu itself. -->
+          <!-- ux spec: https://bug782810.bugzilla.mozilla.org/attachment.cgi?id=714804 -->
+
           <!-- Text related -->
-          <richlistitem id="context-copy" type="copy" onclick="ContextCommands.copy();">
-            <label value="&copy.label;"/>
+          <!-- for text inputs, this will copy selected text, or if no text is selected, copy all -->
+          <richlistitem id="context-copy" type="copy,selectable" onclick="ContextCommands.copy();">
+            <label value="&contextTextCopy.label;"/>
           </richlistitem>
-          <richlistitem id="context-copy-all" type="copy-all" onclick="ContextCommands.copy();">
-            <label value="&copyAll.label;"/>
-          </richlistitem>
+          <!-- only displayed if there is text on the clipboard -->
           <richlistitem id="context-paste" type="paste" onclick="ContextCommands.paste();">
-            <label value="&paste.label;"/>
+            <label value="&contextTextPaste.label;"/>
           </richlistitem>
+          <!-- Search Bing for "..." -->
+          <richlistitem id="context-search" type="copy,selected-text" onclick="ContextCommands.searchText(this);">
+            <label id="context-search-label" value=""/>
+          </richlistitem>
+          <!-- only display if there is text on the clipboard and the target is the urlbar -->
           <richlistitem id="context-paste-n-go" type="paste-url" onclick="ContextCommands.pasteAndGo();">
-            <label value="&pasteAndGo.label;"/>
+            <label value="&contextTextPasteAndGo.label;"/>
           </richlistitem>
-          <richlistitem id="context-select-all" type="select-all" onclick="ContextCommands.selectAll();">
-            <label value="&selectAll.label;"/>
+          <!-- only displayed in inputs with text that do not have selection -->
+          <richlistitem id="context-select" type="selectable" onclick="ContextCommands.select();">
+            <label value="&contextTextSelect.label;"/>
+          </richlistitem>
+          <!-- only displayed in inputs with text that do not have selection -->
+          <richlistitem id="context-select-all" type="selectable" onclick="ContextCommands.selectAll();">
+            <label value="&contextTextSelectAll.label;"/>
           </richlistitem>
 
           <!-- Image related -->
-          <richlistitem id="context-viewinnewtab" type="image" onclick="ContextCommands.openInNewTab();">
-            <label value="&contextViewInNewTab.label;"/>
+          <!-- save image to user pictures library -->
+          <richlistitem id="context-save-image-lib" type="image" onclick="ContextCommands.saveImageToLib();">
+            <label value="&contextSaveImageLib.label;"/>
           </richlistitem>
-          <richlistitem id="context-copy-image" type="image-loaded" onclick="ContextCommands.copyImage();">
+          <!-- copy image data to clipboard -->
+          <richlistitem id="context-copy-image" type="image" onclick="ContextCommands.copyImage();">
             <label value="&contextCopyImage.label;"/>
           </richlistitem>
-          <richlistitem id="context-save-image" type="image-loaded" onclick="ContextCommands.saveImage();">
-            <label value="&contextSaveImage.label;"/>
+          <!-- copy the uri of the image src -->
+          <richlistitem id="context-copy-image-loc" type="image" onclick="ContextCommands.copyImageSrc();">
+            <label value="&contextCopyImageLocation.label;"/>
+          </richlistitem>
+          <!-- open the uri of the image src in a new tab -->
+          <richlistitem id="context-open-image-tab" type="image" priority="low" onclick="ContextCommands.openImageInNewTab();">
+            <label value="&contextOpenImageTab.label;"/>
           </richlistitem>
-          <richlistitem id="context-save-image-to" type="image-loaded" onclick="ContextCommands.saveImageTo();">
-            <label value="&contextSaveImageTo.label;"/>
+
+          <!-- Video related -->
+          <!-- save video to user videos library -->
+          <richlistitem id="context-save-video-lib" type="video" onclick="ContextCommands.saveVideoToLib();">
+            <label value="&contextSaveVideoLib.label;"/>
+          </richlistitem>
+          <!-- copy the uri of the video src -->
+          <richlistitem id="context-copy-video-loc" type="video" onclick="ContextCommands.copyVideoSrc();">
+            <label value="&contextCopyVideoLocation.label;"/>
+          </richlistitem>
+          <!-- open the uri of the video src in a new tab -->
+          <richlistitem id="context-open-video-tab" type="video" priority="low" onclick="ContextCommands.openVideoInNewTab();">
+            <label value="&contextOpenVideoTab.label;"/>
           </richlistitem>
 
           <!-- Link related -->
-          <richlistitem id="context-openinnewtab" type="link-openable" onclick="ContextCommands.openInNewTab();">
-            <label value="&contextOpenInNewTab.label;"/>
-          </richlistitem>
-          <richlistitem id="context-bookmark-link" type="link" onclick="ContextCommands.bookmarkLink();">
-            <label value="&contextBookmarkLink.label;"/>
+          <!-- all of these apply to underlying link href values -->
+          <richlistitem id="context-open-in-new-tab" type="link" onclick="ContextCommands.openLinkInNewTab();">
+            <label value="&contextOpenLinkTab.label;"/>
           </richlistitem>
           <richlistitem id="context-copy-link" type="link" onclick="ContextCommands.copyLink();">
-            <label value="&contextCopyLink.label;"/>
+            <label value="&contextCopyLinkHref.label;"/>
           </richlistitem>
-          <richlistitem id="context-copy-email" type="mailto" onclick="ContextCommands.copyEmail();">
-            <label value="&contextCopyEmail.label;"/>
-          </richlistitem>
-          <richlistitem id="context-copy-phone" type="callto" onclick="ContextCommands.copyPhone();">
-            <label value="&contextCopyPhone.label;"/>
+          <richlistitem id="context-bookmark-link" type="link" priority="low" onclick="ContextCommands.bookmarkLink();">
+            <label value="&contextBookmarkLinkHref.label;"/>
           </richlistitem>
 
-          <!-- Video related -->
-          <richlistitem id="context-play-media" type="media-paused" onclick="ContextCommands.sendCommand('play');">
-            <label value="&contextPlayMedia.label;"/>
-          </richlistitem>
-          <richlistitem id="context-pause-video" type="media-playing" onclick="ContextCommands.sendCommand('pause');">
-            <label value="&contextPauseMedia.label;"/>
-          </richlistitem>
-          <richlistitem id="context-videotab" type="video" onclick="ContextCommands.sendCommand('videotab');">
-            <label value="&contextVideoTab.label;"/>
-          </richlistitem>
-          <richlistitem id="context-save-video" type="video" onclick="ContextCommands.saveVideo();">
-            <label value="&contextSaveVideo.label;"/>
-          </richlistitem>
-          <richlistitem id="context-save-video-to" type="video" onclick="ContextCommands.saveVideoTo();">
-            <label value="&contextSaveVideoTo.label;"/>
-          </richlistitem>
-
-          <!-- Misc. related -->
-          <richlistitem id="context-editbookmark" type="edit-bookmark" onclick="ContextCommands.editBookmark();">
-            <label value="&contextEditBookmark.label;"/>
-          </richlistitem>
-          <richlistitem id="context-removebookmark" type="edit-bookmark" onclick="ContextCommands.removeBookmark();">
-            <label value="&contextRemoveBookmark.label;"/>
-          </richlistitem>
+          <!-- App bar: 'more' button context menu -->
           <richlistitem id="context-findinpage" type="find-in-page" onclick="ContextCommands.findInPage();">
           <label value="&appbarFindInPage.label;"/>
           </richlistitem>
           <richlistitem id="context-viewondesktop" type="view-on-desktop" onclick="ContextCommands.viewOnDesktop();">
           <label value="&appbarViewOnDesktop.label;"/>
           </richlistitem>
         </richlistbox>
       </vbox>
--- a/browser/metro/base/content/contenthandlers/ContextMenuHandler.js
+++ b/browser/metro/base/content/contenthandlers/ContextMenuHandler.js
@@ -170,39 +170,38 @@ var ContextMenuHandler = {
             continue;
           }
 
           state.types.push("link");
           state.label = state.linkURL = this._getLinkURL(elem);
           linkUrl = state.linkURL;
           state.linkTitle = popupNode.textContent || popupNode.title;
           state.linkProtocol = this._getProtocol(this._getURI(state.linkURL));
+          // mark as text so we can pickup on selection below
+          isText = true;
           break;
         } else if (this._isTextInput(elem)) {
           let selectionStart = elem.selectionStart;
           let selectionEnd = elem.selectionEnd;
 
           state.types.push("input-text");
           this._target = elem;
 
           // Don't include "copy" for password fields.
           if (!(elem instanceof Ci.nsIDOMHTMLInputElement) || elem.mozIsTextField(true)) {
             if (selectionStart != selectionEnd) {
               state.types.push("copy");
               state.string = elem.value.slice(selectionStart, selectionEnd);
-            } else if (elem.value) {
-              state.types.push("copy-all");
+            }
+            if (elem.value && (selectionStart > 0 || selectionEnd < elem.textLength)) {
+              state.types.push("selectable");
               state.string = elem.value;
             }
           }
 
-          if (selectionStart > 0 || selectionEnd < elem.textLength) {
-            state.types.push("select-all");
-          }
-
           if (!elem.textLength) {
             state.types.push("input-empty");
           }
 
           let flavors = ["text/unicode"];
           let cb = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
           let hasData = cb.hasDataMatchingFlavors(flavors,
                                                   flavors.length,
@@ -222,16 +221,17 @@ var ContextMenuHandler = {
             state.types.push("video");
           }
         }
       }
 
       elem = elem.parentNode;
     }
 
+    // Over arching text tests
     if (isText) {
       // If this is text and has a selection, we want to bring
       // up the copy option on the context menu.
       if (content && content.getSelection() &&
           content.getSelection().toString().length > 0) {
         state.string = content.getSelection().toString();
         state.types.push("copy");
         state.types.push("selected-text");
@@ -329,41 +329,8 @@ var ContextMenuHandler = {
 
   /** Remove all handlers registered for a given type. */
   unregisterType: function unregisterType(aName) {
     this._types = this._types.filter(function(type) type.name != aName);
   }
 };
 
 ContextMenuHandler.init();
-
-ContextMenuHandler.registerType("mailto", function(aState, aElement) {
-  return aState.linkProtocol == "mailto";
-});
-
-ContextMenuHandler.registerType("callto", function(aState, aElement) {
-  let protocol = aState.linkProtocol;
-  return protocol == "tel" || protocol == "callto" || protocol == "sip" || protocol == "voipto";
-});
-
-ContextMenuHandler.registerType("link-openable", function(aState, aElement) {
-  return Util.isOpenableScheme(aState.linkProtocol);
-});
-
-["image", "video"].forEach(function(aType) {
-  ContextMenuHandler.registerType(aType+"-shareable", function(aState, aElement) {
-    if (aState.types.indexOf(aType) == -1)
-      return false;
-
-    let protocol = ContextMenuHandler._getProtocol(ContextMenuHandler._getURI(aState.mediaURL));
-    return Util.isShareableScheme(protocol);
-  });
-});
-
-ContextMenuHandler.registerType("image-loaded", function(aState, aElement) {
-  if (aState.types.indexOf("image") != -1) {
-    let request = aElement.getRequest(Ci.nsIImageLoadingContent.CURRENT_REQUEST);
-    if (request && (request.imageStatus & request.STATUS_SIZE_AVAILABLE))
-      return true;
-  }
-  return false;
-});
-
--- a/browser/metro/base/content/contenthandlers/SelectionHandler.js
+++ b/browser/metro/base/content/contenthandlers/SelectionHandler.js
@@ -50,29 +50,31 @@ var SelectionHandler = {
   _frameOffset: { x:0, y:0 },
   _domWinUtils: null,
   _selectionMoveActive: false,
   _lastMarker: "",
   _debugOptions: { dumpRanges: false, displayRanges: false },
 
   init: function init() {
     addMessageListener("Browser:SelectionStart", this);
+    addMessageListener("Browser:SelectionAttach", this);
     addMessageListener("Browser:SelectionEnd", this);
     addMessageListener("Browser:SelectionMoveStart", this);
     addMessageListener("Browser:SelectionMove", this);
     addMessageListener("Browser:SelectionMoveEnd", this);
     addMessageListener("Browser:SelectionUpdate", this);
     addMessageListener("Browser:SelectionClose", this);
     addMessageListener("Browser:SelectionClear", this);
     addMessageListener("Browser:SelectionCopy", this);
     addMessageListener("Browser:SelectionDebug", this);
   },
 
   shutdown: function shutdown() {
     removeMessageListener("Browser:SelectionStart", this);
+    removeMessageListener("Browser:SelectionAttach", this);
     removeMessageListener("Browser:SelectionEnd", this);
     removeMessageListener("Browser:SelectionMoveStart", this);
     removeMessageListener("Browser:SelectionMove", this);
     removeMessageListener("Browser:SelectionMoveEnd", this);
     removeMessageListener("Browser:SelectionUpdate", this);
     removeMessageListener("Browser:SelectionClose", this);
     removeMessageListener("Browser:SelectionClear", this);
     removeMessageListener("Browser:SelectionCopy", this);
@@ -109,16 +111,27 @@ var SelectionHandler = {
       this._onFail("failed to set selection at point");
       return;
     }
 
     // Update the position of our selection monocles
     this._updateSelectionUI(true, true);
   },
 
+  _onSelectionAttach: function _onSelectionAttach(aX, aY) {
+    // Init content window information
+    if (!this._initTargetInfo(aX, aY)) {
+      this._onFail("failed to get frame offset");
+      return;
+    }
+
+    // Update the position of our selection monocles
+    this._updateSelectionUI(true, true);
+  },
+
   /*
    * Selection monocle start move event handler
    */
   _onSelectionMoveStart: function _onSelectionMoveStart(aMsg) {
     if (!this._contentWindow) {
       this._onFail("_onSelectionMoveStart was called without proper view set up");
       return;
     }
@@ -889,16 +902,20 @@ var SelectionHandler = {
       Util.dumpLn("SelectionHandler:", aMessage.name);
     }
     let json = aMessage.json;
     switch (aMessage.name) {
       case "Browser:SelectionStart":
         this._onSelectionStart(json.xPos, json.yPos);
         break;
 
+      case "Browser:SelectionAttach":
+        this._onSelectionAttach(json.xPos, json.yPos);
+      break;
+
       case "Browser:SelectionClose":
         this._onSelectionClose();
         break;
 
       case "Browser:SelectionMoveStart":
         this._onSelectionMoveStart(json);
         break;
 
--- a/browser/metro/base/content/helperui/MenuUI.js
+++ b/browser/metro/base/content/helperui/MenuUI.js
@@ -113,44 +113,77 @@ var ContextMenuUI = {
    *
    * json: TBD
    */
   showContextMenu: function ch_showContextMenu(aMessage) {
     this._popupState = aMessage.json;
     this._popupState.target = aMessage.target;
     let contentTypes = this._popupState.types;
 
+    /*
+     * Types in ContextMenuHandler:
+     * image
+     * link
+     * input-text     - generic form input control
+     * copy           - form input that has some selected text
+     * selectable     - form input with text that can be selected
+     * input-empty    - form input (empty)
+     * paste          - form input and there's text on the clipboard
+     * selected-text  - generic content text that is selected
+     * content-text   - generic content text
+     * video
+     * media-paused, media-playing
+     * paste-url      - url bar w/text on the clipboard
+     */
+
+    Util.dumpLn("contentTypes:", contentTypes);
+
+    // Defines whether or not low priority items in images, text, and
+    // links are displayed.
+    let multipleMediaTypes = false;
+    if (contentTypes.indexOf("link") != -1 &&
+        (contentTypes.indexOf("image") != -1  ||
+         contentTypes.indexOf("video") != -1 ||
+         contentTypes.indexOf("selected-text") != -1))
+      multipleMediaTypes = true;
+
+    for (let command of Array.slice(this._commands.childNodes)) {
+      command.hidden = true;
+    }
+
     let optionsAvailable = false;
-    for (let i = 0; i < this._commands.childElementCount; i++) {
-      let command = this._commands.childNodes[i];
-      command.hidden = true;
+    for (let command of Array.slice(this._commands.childNodes)) {
+      let types = command.getAttribute("type").split(",");
+      let lowPriority = (command.hasAttribute("priority") &&
+        command.getAttribute("priority") == "low");
+      let searchTextItem = (command.id == "context-search");
 
-      let types = command.getAttribute("type").split(/\s+/);
+      // filter low priority items if we have more than one media type.
+      if (multipleMediaTypes && lowPriority)
+        continue;
+
       for (let i = 0; i < types.length; i++) {
         if (contentTypes.indexOf(types[i]) != -1) {
+          // If this is the special search text item, we need to set its label dynamically.
+          if (searchTextItem && !ContextCommands.searchTextSetup(command, this._popupState.string)) {
+            break;
+          }
           optionsAvailable = true;
           command.hidden = false;
           break;
         }
       }
     }
 
     if (!optionsAvailable) {
       this._popupState = null;
       return false;
     }
 
-
     this._menuPopup.show(this._popupState);
-
-    let event = document.createEvent("Events");
-    event.initEvent("CancelTouchSequence", true, false);
-    if (this._popupState.target) {
-      this._popupState.target.dispatchEvent(event);
-    }
     return true;
   },
 
   hide: function hide () {
     this._menuPopup.hide();
     this._popupState = null;
   },
 
@@ -298,16 +331,20 @@ MenuPopup.prototype = {
 
     this._panel.hidden = false;
     this._position(aPositionOptions || {});
 
     let self = this;
     this._panel.addEventListener("transitionend", function () {
       self._panel.removeEventListener("transitionend", arguments.callee);
       self._panel.removeAttribute("showingfrom");
+
+      let event = document.createEvent("Events");
+      event.initEvent("popupshown", true, false);
+      document.dispatchEvent(event);
     });
 
     let popupFrom = (aPositionOptions.forcePosition && !aPositionOptions.bottomAligned) ? "above" : "below";
     this._panel.setAttribute("showingfrom", popupFrom);
 
     // Ensure the panel actually gets shifted before getting animated
     setTimeout(function () {
       self._panel.setAttribute("showing", "true");
@@ -321,16 +358,19 @@ MenuPopup.prototype = {
     window.removeEventListener("keypress", this, true);
     window.removeEventListener("mousedown", this, true);
 
     let self = this;
     this._panel.addEventListener("transitionend", function () {
       self._panel.removeEventListener("transitionend", arguments.callee);
       self._panel.hidden = true;
       self._popupState = null;
+      let event = document.createEvent("Events");
+      event.initEvent("popuphidden", true, false);
+      document.dispatchEvent(event);
     });
 
     this._panel.removeAttribute("showing");
   },
 
   _position: function _position(aPositionOptions) {
     let aX = aPositionOptions.xPos;
     let aY = aPositionOptions.yPos;
--- a/browser/metro/base/content/helperui/SelectionHelperUI.js
+++ b/browser/metro/base/content/helperui/SelectionHelperUI.js
@@ -221,19 +221,16 @@ var SelectionHelperUI = {
 
   /*
    * openEditSession
    * 
    * Attempts to select underlying text at a point and begins editing
    * the section.
    */
   openEditSession: function openEditSession(aMessage) {
-    if (!this.canHandle(aMessage))
-      return;
-
      /*
      * aMessage - from _onContentContextMenu in ContextMenuHandler
      *  name: aMessage.name,
      *  target: aMessage.target
      *  json:
      *   types: [],
      *   label: "",
      *   linkURL: "",
@@ -261,31 +258,51 @@ var SelectionHelperUI = {
       "Browser:SelectionStart",
       { xPos: this._popupState.xPos,
         yPos: this._popupState.yPos });
 
     this._setupDebugOptions();
   },
 
   /*
+   * attachEditSession
+   * 
+   * Attaches to existing selection and begins editing.
+   */
+  attachEditSession: function attachEditSession(aMessage) {
+    this._popupState = aMessage.json;
+    this._popupState._target = aMessage.target;
+
+    this._init();
+
+    Util.dumpLn("enableSelection target:", this._popupState._target);
+
+    // Set the track bounds for each marker NIY
+    this.startMark.setTrackBounds(this._popupState.xPos, this._popupState.yPos);
+    this.endMark.setTrackBounds(this._popupState.xPos, this._popupState.yPos);
+
+    // Send this over to SelectionHandler in content, they'll message us
+    // back with information on the current selection.
+    this._popupState._target.messageManager.sendAsyncMessage(
+      "Browser:SelectionAttach",
+      { xPos: this._popupState.xPos,
+        yPos: this._popupState.yPos });
+
+    this._setupDebugOptions();
+  },
+
+  /*
    * canHandle
    *
    * Determines if we can handle a ContextMenuHandler message.
    */
   canHandle: function canHandle(aMessage) {
-    // Reject empty text inputs, nothing to do here
-    if (aMessage.json.types.indexOf("input-empty") != -1) {
-      return false;
-    }
-    // Input with text or general text in a page
-    if (aMessage.json.types.indexOf("content-text") == -1 &&
-        aMessage.json.types.indexOf("input-text") == -1) {
-      return false;
-    }
-    return true;
+    if (aMessage.json.types.indexOf("content-text") != -1)
+      return true;
+    return false;
   },
 
   /*
    * isActive
    *
    * Determines if an edit session is currently active.
    */
   isActive: function isActive() {
--- a/browser/metro/base/content/input.js
+++ b/browser/metro/base/content/input.js
@@ -160,18 +160,16 @@ var TouchModule = {
     this._doDragStop();
 
     // Kinetic panning may have already been active or drag stop above may have
     // made kinetic panning active.
     this._kinetic.end();
 
     this._targetScrollbox = null;
     this._targetScrollInterface = null;
-
-    this._cleanClickBuffer();
   },
 
   _onContextMenu: function _onContextMenu(aEvent) {
     // Special case when running on the desktop, fire off
     // a edge ui event when we get the contextmenu event.
     if (this._treatMouseAsTouch) {
       let event = document.createEvent("Events");
       event.initEvent("MozEdgeUIGesture", true, false);
--- a/browser/metro/base/tests/Makefile.in
+++ b/browser/metro/base/tests/Makefile.in
@@ -6,24 +6,34 @@ DEPTH     = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 relativesrcdir  = @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
-_BROWSER_FILES = \
+BROWSER_TESTS = \
   head.js \
   browser_test.js \
   browser_canonizeURL.js \
   browser_context_ui.js \
   browser_onscreen_keyboard.js \
   browser_onscreen_keyboard.html \
   browser_remotetabs.js \
   browser_downloads.js \
   browser_plugin_input.html \
   browser_plugin_input_mouse.js \
   browser_plugin_input_keyboard.js \
+  browser_context_menu_tests.js \
+  browser_context_menu_tests_01.html \
+  browser_context_menu_tests_02.html \
   $(NULL)
 
-libs:: $(_BROWSER_FILES)
+BROWSER_TEST_RESOURCES = \
+  res\image01.png \
+  $(NULL)
+
+libs:: $(BROWSER_TESTS)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/metro/
+
+libs:: $(BROWSER_TEST_RESOURCES)
+	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/metro/res
new file mode 100644
--- /dev/null
+++ b/browser/metro/base/tests/browser_context_menu_tests.js
@@ -0,0 +1,402 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+function debugClipFlavors(aClip)
+{
+  let xfer = Cc["@mozilla.org/widget/transferable;1"].
+             createInstance(Ci.nsITransferable);
+  xfer.init(null);
+  aClip.getData(xfer, Ci.nsIClipboard.kGlobalClipboard);
+  let array = xfer.flavorsTransferableCanExport();
+  let count = array.Count();
+  info("flavors:" + count);
+  for (let idx = 0; idx < count; idx++) {
+    let string = array.GetElementAt(idx).QueryInterface(Ci.nsISupportsString);
+    info("[" + idx + "] " + string);
+  }
+}
+
+// XXX won't work with out of process content
+function emptyClipboard() {
+  Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard)
+                                       .emptyClipboard(Ci.nsIClipboard.kGlobalClipboard);
+}
+
+// Image context menu tests
+gTests.push({
+  desc: "text context menu",
+  run: function test() {
+    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+    info(chromeRoot + "browser_context_menu_tests_02.html");
+    yield addTab(chromeRoot + "browser_context_menu_tests_02.html");
+
+    purgeEventQueue();
+
+    let win = Browser.selectedTab.browser.contentWindow;
+
+    yield hideContextUI();
+
+    ////////////////////////////////////////////////////////////
+    // Context menu in content on selected text
+
+    // select some text
+    let span = win.document.getElementById("text1");
+    win.getSelection().selectAllChildren(span);
+
+    // invoke selection context menu
+    let promise = waitForEvent(document, "popupshown");
+    sendContextMenuClickToElement(win, span, 85, 10);
+    yield promise;
+    ok(promise && !(promise instanceof Error), "promise error");
+
+    // should be visible
+    ok(ContextMenuUI._menuPopup._visible, "is visible");
+
+    // selected text context:
+    checkContextUIMenuItemVisibility(["context-copy",
+                                      "context-search"]);
+
+    promise = waitForEvent(document, "popuphidden");
+    ContextMenuUI.hide();
+    yield promise;
+    ok(promise && !(promise instanceof Error), "promise error");
+    win.getSelection().removeAllRanges();
+
+    ////////////////////////////////////////////////////////////
+    // Context menu in content on selected text that includes a link
+
+    // invoke selection with link context menu
+    let link = win.document.getElementById("text2-link");
+    win.getSelection().selectAllChildren(link);
+    promise = waitForEvent(document, "popupshown");
+    sendContextMenuClickToElement(win, link, 40, 10);
+    yield promise;
+    ok(promise && !(promise instanceof Error), "promise error");
+
+    // should be visible
+    ok(ContextMenuUI._menuPopup._visible, "is visible");
+
+    // selected text context:
+    checkContextUIMenuItemVisibility(["context-copy",
+                                      "context-search",
+                                      "context-open-in-new-tab",
+                                      "context-copy-link"]);
+
+    promise = waitForEvent(document, "popuphidden");
+    ContextMenuUI.hide();
+    yield promise;
+    ok(promise && !(promise instanceof Error), "promise error");
+    win.getSelection().removeAllRanges();
+
+    ////////////////////////////////////////////////////////////
+    // Context menu in content on a link
+
+    link = win.document.getElementById("text2-link");
+    promise = waitForEvent(document, "popupshown");
+    sendContextMenuClickToElement(win, link, 40, 10);
+    yield promise;
+    ok(promise && !(promise instanceof Error), "promise error");
+
+    // should be visible
+    ok(ContextMenuUI._menuPopup._visible, "is visible");
+
+    // selected text context:
+    checkContextUIMenuItemVisibility(["context-open-in-new-tab",
+                                      "context-copy-link",
+                                      "context-bookmark-link"]);
+
+    promise = waitForEvent(document, "popuphidden");
+    ContextMenuUI.hide();
+    yield promise;
+    ok(promise && !(promise instanceof Error), "promise error");
+
+    ////////////////////////////////////////////////////////////
+    // context in input with no selection, no data on clipboard
+
+    emptyClipboard();
+
+    let input = win.document.getElementById("text3-input");
+    promise = waitForEvent(document, "popupshown");
+    sendContextMenuClickToElement(win, input, 20, 10);
+    yield promise;
+    ok(promise && !(promise instanceof Error), "promise error");
+
+    // should be visible
+    ok(ContextMenuUI._menuPopup._visible, "is visible");
+
+    checkContextUIMenuItemVisibility(["context-copy",
+                                      "context-select",
+                                      "context-select-all"]);
+
+    // copy menu item should copy all text
+    let menuItem = document.getElementById("context-copy");
+    ok(menuItem, "menu item exists");
+    ok(!menuItem.hidden, "menu item visible");
+
+    let popupPromise = waitForEvent(document, "popuphidden");
+    EventUtils.synthesizeMouse(menuItem, 10, 10, {}, win);
+    yield popupPromise;
+    ok(popupPromise && !(popupPromise instanceof Error), "promise error");
+    let string = SpecialPowers.getClipboardData("text/unicode");
+    ok(string, "hello, I'm sorry but I must be going.", "copy all");
+
+    emptyClipboard();
+
+    ////////////////////////////////////////////////////////////
+    // context in input with text selection, no data on clipboard
+
+    input = win.document.getElementById("text3-input");
+    input.select();
+    promise = waitForEvent(document, "popupshown");
+    sendContextMenuClickToElement(win, input, 20, 10);
+    yield promise;
+    ok(promise && !(promise instanceof Error), "promise error");
+
+    // should be visible
+    ok(ContextMenuUI._menuPopup._visible, "is visible");
+
+    // selected text context:
+    checkContextUIMenuItemVisibility(["context-copy",
+                                      "context-search"]);
+
+    promise = waitForEvent(document, "popuphidden");
+    ContextMenuUI.hide();
+    yield promise;
+    ok(promise && !(promise instanceof Error), "promise error");
+
+    ////////////////////////////////////////////////////////////
+    // context in input with no selection, data on clipboard
+
+    SpecialPowers.clipboardCopyString("foo");
+    input = win.document.getElementById("text3-input");
+    input.select();
+    promise = waitForEvent(document, "popupshown");
+    sendContextMenuClickToElement(win, input, 20, 10);
+    yield promise;
+    ok(promise && !(promise instanceof Error), "promise error");
+
+    // should be visible
+    ok(ContextMenuUI._menuPopup._visible, "is visible");
+
+    // selected text context:
+    checkContextUIMenuItemVisibility(["context-copy",
+                                      "context-search",
+                                      "context-paste"]);
+
+    promise = waitForEvent(document, "popuphidden");
+    ContextMenuUI.hide();
+    yield promise;
+    ok(promise && !(promise instanceof Error), "promise error");
+
+    ////////////////////////////////////////////////////////////
+    // context in empty input, data on clipboard (paste operation)
+
+    SpecialPowers.clipboardCopyString("foo");
+    input = win.document.getElementById("text3-input");
+    input.value = "";
+
+    promise = waitForEvent(document, "popupshown");
+    sendContextMenuClickToElement(win, input, 20, 10);
+    yield promise;
+    ok(promise && !(promise instanceof Error), "promise error");
+
+    // should be visible
+    ok(ContextMenuUI._menuPopup._visible, "is visible");
+
+    // selected text context:
+    checkContextUIMenuItemVisibility(["context-paste"]);
+
+    promise = waitForEvent(document, "popuphidden");
+    ContextMenuUI.hide();
+    yield promise;
+    ok(promise && !(promise instanceof Error), "promise error");
+
+    ////////////////////////////////////////////////////////////
+    // context in empty input, no data on clipboard (??)
+
+    emptyClipboard();
+
+    input = win.document.getElementById("text3-input");
+    input.value = "";
+
+    promise = waitForEvent(Elements.tray, "transitionend");
+    sendContextMenuClickToElement(win, input, 20, 10);
+    yield promise;
+    ok(promise && !(promise instanceof Error), "promise error");
+
+    // should *not* be visible
+    ok(!ContextMenuUI._menuPopup._visible, "is visible");
+
+    // the test above will invoke the app bar
+    yield hideContextUI();
+
+    Browser.closeTab(Browser.selectedTab);
+    purgeEventQueue();
+  }
+});
+
+// Image context menu tests
+gTests.push({
+  desc: "image context menu",
+  run: function test() {
+    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+    info(chromeRoot + "browser_context_menu_tests_01.html");
+    yield addTab(chromeRoot + "browser_context_menu_tests_01.html");
+
+    let win = Browser.selectedTab.browser.contentWindow;
+
+    purgeEventQueue();
+
+    yield hideContextUI();
+
+    // If we don't do this, sometimes the first sendContextMenuClick
+    // will trigger the app bar.
+    yield waitForImageLoad(win, "image01");
+
+    ////////////////////////////////////////////////////////////
+    // Context menu options
+
+    // image01 - 1x1x100x100
+    let promise = waitForEvent(document, "popupshown");
+    sendContextMenuClick(win, 10, 10);
+    yield promise;
+    ok(promise && !(promise instanceof Error), "promise error");
+
+    purgeEventQueue();
+
+    ok(ContextMenuUI._menuPopup._visible, "is visible");
+
+    checkContextUIMenuItemVisibility(["context-save-image-lib",
+                                      "context-copy-image",
+                                      "context-copy-image-loc",
+                                      "context-open-image-tab"]);
+
+    ////////////////////////////////////////////////////////////
+    // Save to image library
+
+    let dirSvc = Components.classes["@mozilla.org/file/directory_service;1"]
+                           .getService(Components.interfaces.nsIProperties);
+    let saveLocationPath = dirSvc.get("Pict", Components.interfaces.nsIFile);
+    saveLocationPath.append("image01.png");
+
+    registerCleanupFunction(function () {
+      saveLocationPath.remove(false);
+    });
+
+    if (saveLocationPath.exists()) {
+      info("had to remove old image!");
+      saveLocationPath.remove(false);
+    }
+
+    let menuItem = document.getElementById("context-save-image-lib");
+    ok(menuItem, "menu item exists");
+    ok(!menuItem.hidden, "menu item visible");
+
+    let downloadPromise = waitForObserver("dl-done");
+    let popupPromise = waitForEvent(document, "popuphidden");
+    EventUtils.synthesizeMouse(menuItem, 10, 10, {}, win);
+    yield popupPromise;
+    ok(popupPromise && !(popupPromise instanceof Error), "promise error");
+    yield downloadPromise;
+    ok(downloadPromise && !(downloadPromise instanceof Error), "promise error");
+
+    purgeEventQueue();
+
+    ok(saveLocationPath.exists(), "image saved");
+
+    ////////////////////////////////////////////////////////////
+    // Copy image
+
+    let promise = waitForEvent(document, "popupshown");
+    sendContextMenuClick(win, 20, 20);
+    yield promise;
+    ok(promise && !(promise instanceof Error), "promise error");
+    ok(ContextMenuUI._menuPopup._visible, "is visible");
+
+    menuItem = document.getElementById("context-copy-image");
+    ok(menuItem, "menu item exists");
+    ok(!menuItem.hidden, "menu item visible");
+    popupPromise = waitForEvent(document, "popuphidden");
+    EventUtils.synthesizeMouse(menuItem, 10, 10, {}, win);
+    yield popupPromise;
+    ok(popupPromise && !(popupPromise instanceof Error), "promise error");
+
+    purgeEventQueue();
+
+    let clip = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
+    let flavors = ["image/png"];
+    ok(clip.hasDataMatchingFlavors(flavors, flavors.length, Ci.nsIClipboard.kGlobalClipboard), "clip has my png flavor");
+
+    ////////////////////////////////////////////////////////////
+    // Copy image location
+
+    promise = waitForEvent(document, "popupshown");
+    sendContextMenuClick(win, 30, 30);
+    yield promise;
+    ok(promise && !(promise instanceof Error), "promise error");
+    ok(ContextMenuUI._menuPopup._visible, "is visible");
+
+    menuItem = document.getElementById("context-copy-image-loc");
+    ok(menuItem, "menu item exists");
+    ok(!menuItem.hidden, "menu item visible");
+    popupPromise = waitForEvent(document, "popuphidden");
+    EventUtils.synthesizeMouse(menuItem, 10, 10, {}, win);
+    yield popupPromise;
+    ok(popupPromise && !(popupPromise instanceof Error), "promise error");
+
+    purgeEventQueue();
+
+    let clip = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
+    let flavors = ["text/unicode"];
+    ok(clip.hasDataMatchingFlavors(flavors, flavors.length, Ci.nsIClipboard.kGlobalClipboard), "clip has my text flavor");
+
+    let xfer = Cc["@mozilla.org/widget/transferable;1"].
+               createInstance(Ci.nsITransferable);
+    xfer.init(null);
+    xfer.addDataFlavor("text/unicode");
+    clip.getData(xfer, Ci.nsIClipboard.kGlobalClipboard);
+    let str = new Object();
+    let strLength = new Object();
+    xfer.getTransferData("text/unicode", str, strLength);
+    str = str.value.QueryInterface(Components.interfaces.nsISupportsString);
+    ok(str == "chrome://mochitests/content/metro/res/image01.png", "url copied");
+
+    ////////////////////////////////////////////////////////////
+    // Open image in new tab
+
+    promise = waitForEvent(document, "popupshown");
+    sendContextMenuClick(win, 40, 40);
+    yield promise;
+    ok(promise && !(promise instanceof Error), "promise error");
+    ok(ContextMenuUI._menuPopup._visible, "is visible");
+
+    menuItem = document.getElementById("context-open-image-tab");
+    ok(menuItem, "menu item exists");
+    ok(!menuItem.hidden, "menu item visible");
+    let tabPromise = waitForEvent(document, "TabOpen");
+    popupPromise = waitForEvent(document, "popuphidden");
+    EventUtils.synthesizeMouse(menuItem, 10, 10, {}, win);
+    yield popupPromise;
+    let event = yield tabPromise;
+    ok(popupPromise && !(popupPromise instanceof Error), "promise error");
+    ok(tabPromise && !(tabPromise instanceof Error), "promise error");
+
+    purgeEventQueue();
+
+    let imagetab = Browser.getTabFromChrome(event.originalTarget);
+    ok(imagetab != null, "tab created");
+    ok(imagetab.browser.currentURI.spec == "chrome://mochitests/content/metro/res/image01.png", "tab location");
+
+    Browser.closeTab(imagetab);
+  }
+});
+
+function test() {
+  runTests();
+}
new file mode 100644
--- /dev/null
+++ b/browser/metro/base/tests/browser_context_menu_tests_01.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <style>
+    </style>
+  </head>
+<body style="padding: 1px; margin: 1px;">
+<div style="margin: 0; padding: 0;">
+  <span>
+    <img id="image01" width="100" height="100" src="./res/image01.png" />
+  </span>
+</div>
+</body>
+</html>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/metro/base/tests/browser_context_menu_tests_02.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <style>
+    </style>
+  </head>
+<body style="padding: 10px; margin: 10px;">
+  <div style="margin: 0; padding: 5px;">
+    <span id="text1">hello, I'm sorry but I must be going.</span>
+  </div>
+  <div style="margin: 0; padding: 5px;">
+    <span id="text2"><a id="text2-link" href="#test">hello, I'm sorry but</a> I must be going.</span>
+  </div>
+  <div style="margin: 0; padding: 5px;">
+    <span id="text3"><input id="text3-input" value="hello, I'm sorry but I must be going." style="width:200px;"/></span>
+  </div>
+</body>
+</html>
\ No newline at end of file
--- a/browser/metro/base/tests/head.js
+++ b/browser/metro/base/tests/head.js
@@ -14,16 +14,63 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 =============================================================================*/
 const serverRoot = "http://example.com/browser/metro/";
 const baseURI = "http://mochi.test:8888/browser/metro/";
 const chromeRoot = getRootDirectory(gTestPath);
 const kDefaultWait = 10000;
 const kDefaultInterval = 50;
 
 /*=============================================================================
+  Metro ui helpers
+=============================================================================*/
+
+function checkContextUIMenuItemCount(aCount)
+{
+  let visibleCount = 0;
+  for (let idx = 0; idx < ContextMenuUI._commands.childNodes.length; idx++) {
+    if (!ContextMenuUI._commands.childNodes[idx].hidden)
+      visibleCount++;
+  }
+  is(visibleCount, aCount, "command list count");
+}
+
+function checkContextUIMenuItemVisibility(aVisibleList)
+{
+  let errors = 0;
+  for (let idx = 0; idx < ContextMenuUI._commands.childNodes.length; idx++) {
+    let item = ContextMenuUI._commands.childNodes[idx];
+    if (aVisibleList.indexOf(item.id) != -1 && item.hidden) {
+      // item should be visible
+      errors++;
+      info("should be visible:" + item.id);
+    } else if (aVisibleList.indexOf(item.id) == -1 && !item.hidden) {
+      // item should be hidden
+      errors++;
+      info("should be hidden:" + item.id);
+    }
+  }
+  is(errors, 0, "context menu item list visibility");
+}
+
+/*=============================================================================
+  Asynchronous Metro ui helpers
+=============================================================================*/
+
+function hideContextUI()
+{
+  purgeEventQueue();
+  if (ContextUI.isVisible) {
+    info("is visible, waiting...");
+    let promise = waitForEvent(Elements.tray, "transitionend");
+    ContextUI.dismiss();
+    return promise;
+  }
+}
+
+/*=============================================================================
   Asynchronous test helpers
 =============================================================================*/
 /**
  *  Loads a URL in a new tab asynchronously.
  *
  * Usage:
  *    Task.spawn(function() {
  *      let tab = yield addTab("http://example.com/");
@@ -61,16 +108,17 @@ function addTab(aUrl) {
  *    }
  *
  * @param aSubject the element that should receive the event
  * @param aEventName the event to wait for
  * @param aTimeoutMs the number of miliseconds to wait before giving up
  * @returns a Promise that resolves to the received event, or to an Error
  */
 function waitForEvent(aSubject, aEventName, aTimeoutMs) {
+  info("waitForEvent: on " + aSubject + " event: " + aEventName);
   let eventDeferred = Promise.defer();
   let timeoutMs = aTimeoutMs || kDefaultWait;
   let timerID = setTimeout(function wfe_canceller() {
     aSubject.removeEventListener(aEventName, onEvent);
     eventDeferred.reject( new Error(aEventName+" event timeout") );
   }, timeoutMs);
 
   function onEvent(aEvent) {
@@ -157,16 +205,88 @@ function waitForCondition(aCondition, aT
       setTimeout(testCondition, intervalMs);
     }
   }
 
   setTimeout(testCondition, 0);
   return deferred.promise;
 }
 
+/*
+ * Waits for an image in a page to load. Wrapper around waitForCondition.
+ *
+ * @param aWindow the tab or window that contains the image.
+ * @param aImageId the id of the image in the page.
+ * @returns a Promise that resolves to true, or to an Error
+ */
+function waitForImageLoad(aWindow, aImageId) {
+  let elem = aWindow.document.getElementById(aImageId);
+  return waitForCondition(function () {
+    let request = elem.getRequest(Ci.nsIImageLoadingContent.CURRENT_REQUEST);
+    if (request && (request.imageStatus & request.STATUS_SIZE_AVAILABLE))
+      return true;
+    return false;
+  }, 5000, 100);
+}
+
+/**
+ * Waits a specified number of miliseconds for an observer event.
+ *
+ * @param aObsEvent the observer event to wait for
+ * @param aTimeoutMs the number of miliseconds to wait before giving up
+ * @returns a Promise that resolves to true, or to an Error
+ */
+function waitForObserver(aObsEvent, aTimeoutMs) {
+  try {
+  
+  let deferred = Promise.defer();
+  let timeoutMs = aTimeoutMs || kDefaultWait;
+  let timerID = 0;
+
+  var observeWatcher = {
+    onEvent: function () {
+      clearTimeout(timerID);
+      Services.obs.removeObserver(this, aObsEvent);
+      deferred.resolve();
+    },
+
+    onError: function () {
+      clearTimeout(timerID);
+      Services.obs.removeObserver(this, aObsEvent);
+      deferred.reject(new Error(aObsEvent + " event timeout"));
+    },
+
+    observe: function (aSubject, aTopic, aData) {
+      if (aTopic == aObsEvent) {
+        this.onEvent();
+      }
+    },
+
+    QueryInterface: function (aIID) {
+      if (!aIID.equals(Ci.nsIObserver) &&
+          !aIID.equals(Ci.nsISupportsWeakReference) &&
+          !aIID.equals(Ci.nsISupports)) {
+        throw Components.results.NS_ERROR_NO_INTERFACE;
+      }
+      return this;
+    },
+  }
+
+  timerID = setTimeout(function wfo_canceller() {
+    observeWatcher.onError();
+  }, timeoutMs);
+
+  Services.obs.addObserver(observeWatcher, aObsEvent, true);
+  return deferred.promise;
+  
+  } catch (ex) {
+    info(ex.message);
+  }
+}
+
 /*=============================================================================
   Native input synthesis helpers
 =============================================================================*/
 // Keyboard layouts for use with synthesizeNativeKey
 const usEnglish = 0x409;
 const arSpanish = 0x2C0A;
 
 // Modifiers for use with synthesizeNativeKey
@@ -241,16 +361,51 @@ function synthesizeNativeMouseMDown(aEle
 
 function synthesizeNativeMouseMUp(aElement, aOffsetX, aOffsetY) {
   synthesizeNativeMouse(aElement,
                         aOffsetX,
                         aOffsetY,
                         0x0040);  // MOUSEEVENTF_MIDDLEUP
 }
 
+/*
+ * sendContextMenuClick - simulates a press-hold touch input event.
+ */
+function sendContextMenuClick(aWindow, aX, aY) {
+  let utils = aWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                      .getInterface(Components.interfaces.nsIDOMWindowUtils);
+
+  utils.sendMouseEventToWindow("contextmenu", aX, aY, 2, 1, 0, true,
+                                1, Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH);
+}
+
+function sendContextMenuClickToElement(aWindow, aElement, aX, aY) {
+  let utils = aWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                      .getInterface(Components.interfaces.nsIDOMWindowUtils);
+  let rect = aElement.getBoundingClientRect();
+  utils.sendMouseEventToWindow("contextmenu", rect.left + aX, rect.top + aY, 2, 1, 0, true,
+                                1, Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH);
+}
+
+/*=============================================================================
+  System utilities
+=============================================================================*/
+
+/*
+ * purgeEventQueue - purges the event queue on the calling thread.
+ * Pumps latent in-process message manager events awaiting delivery.
+ */
+function purgeEventQueue() {
+  let thread = Services.tm.currentThread;
+  while (thread.hasPendingEvents()) {
+    if (!thread.processNextEvent(true))
+      break;
+  }
+}
+
 /*=============================================================================
   Test-running helpers
 =============================================================================*/
 let gCurrentTest = null;
 let gTests = [];
 
 function runTests() {
   waitForExplicitFinish();
new file mode 100644
index 0000000000000000000000000000000000000000..45429fab6a22b316952b00d67bbd83a9a01cbe1b
GIT binary patch
literal 22083
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
--- a/browser/metro/locales/en-US/chrome/browser.dtd
+++ b/browser/metro/locales/en-US/chrome/browser.dtd
@@ -2,49 +2,33 @@
    - 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/. -->
 
 <!ENTITY urlbar.emptytext      "Enter Search or Address">
 <!ENTITY urlbar.accesskey      "d">
 
 <!ENTITY back.label            "Back">
 <!ENTITY forward.label         "Forward">
-<!ENTITY reload.label          "Reload">
-<!ENTITY stop.label            "Stop">
-<!ENTITY go.label              "Go">
-<!ENTITY star.label            "Star">
-
 <!ENTITY toggleTabsOnly.label  "Always show tabs">
 <!ENTITY showTabs.label        "Show Tabs">
 <!ENTITY newtab.label          "New Tab">
 <!ENTITY closetab.label        "Close Tab">
 <!ENTITY undoclosetab.label    "Undo Close Tab">
 
-<!ENTITY cut.label             "Cut">
-<!ENTITY copy.label            "Copy">
-<!ENTITY copyAll.label         "Copy All">
-<!ENTITY copylink.label        "Copy Link Location">
-<!ENTITY paste.label           "Paste">
-<!ENTITY pasteAndGo.label      "Paste &amp; Go">
-<!ENTITY delete.label          "Delete">
-<!ENTITY selectAll.label       "Select All">
-
 <!ENTITY appbarFindInPage.label    "Find in Page">
 <!ENTITY appbarViewOnDesktop.label "View on Desktop">
 
 <!ENTITY startTopSitesHeader.label        "Top Sites">
 <!ENTITY startBookmarksHeader.label       "Bookmarks">
 <!ENTITY startHistoryHeader.label         "Recent History">
 <!ENTITY startRemoteTabsHeader.label      "Tabs from Other Devices">
 
 <!ENTITY autocompleteResultsHeader.label  "Your Results">
 <!ENTITY autocompleteSearchesHeader.label "Internet Searches"> 
 
-<!ENTITY selectHelper.done         "Done">
-
 <!ENTITY downloadsHeader.label     "Downloads">
 <!ENTITY downloadShowPage.label    "Go to Page">
 <!ENTITY downloadShow2.label       "Find">
 <!ENTITY downloadOpen2.label       "Open">
 <!ENTITY downloadCancel.label      "Cancel">
 <!ENTITY downloadPause.label       "Pause">
 <!ENTITY downloadResume.label      "Resume">
 <!ENTITY downloadRetry.label       "Retry">
@@ -71,32 +55,37 @@
 <!ENTITY consoleMessages.label     "Messages">
 <!ENTITY consoleCodeEval.label     "Code:">
 <!ENTITY consoleClear.label        "Clear">
 <!ENTITY consoleEvaluate.label     "…">
 <!ENTITY consoleErrFile.label      "Source File:">
 <!ENTITY consoleErrLine.label      "Line:">
 <!ENTITY consoleErrColumn.label    "Column:">
 
-<!ENTITY contextOpenInNewTab.label    "Open Link in New Tab">
-<!ENTITY contextViewInNewTab.label    "View in New Tab">
-<!ENTITY contextSaveImage.label       "Save Image">
-<!ENTITY contextSaveImageTo.label     "Save Image To">
-<!ENTITY contextCopyLink.label        "Copy Link">
-<!ENTITY contextCopyEmail.label       "Copy Email Address">
-<!ENTITY contextCopyPhone.label       "Copy Phone Number">
-<!ENTITY contextCopyImage.label       "Copy Image">
-<!ENTITY contextShareLink.label       "Share Link">
-<!ENTITY contextShareImage.label      "Share Image">
-<!ENTITY contextBookmarkLink.label    "Bookmark Link">
-<!ENTITY contextSaveVideo.label       "Save Video">
-<!ENTITY contextSaveVideoTo.label       "Save Video To">
-<!ENTITY contextShareVideo.label      "Share Video">
-<!ENTITY contextPlayMedia.label       "Play">
-<!ENTITY contextPauseMedia.label      "Pause">
-<!ENTITY contextVideoTab.label        "Open In New Tab">
-<!ENTITY contextEditBookmark.label    "Edit">
-<!ENTITY contextRemoveBookmark.label  "Remove">
-<!ENTITY contextShortcutBookmark.label "Add to Home Screen">
+<!--  TEXT CONTEXT MENU -->
+<!ENTITY contextTextCopy.label             "Copy">
+<!ENTITY contextTextPaste.label            "Paste">
+<!-- unique item that is only added to the url bar context menu -->
+<!ENTITY contextTextPasteAndGo.label       "Paste &amp; go">
+<!ENTITY contextTextSelect.label           "Select">
+<!ENTITY contextTextSelectAll.label        "Select all">
+
+<!-- LINK CONTEXT MENU -->
+<!ENTITY contextOpenLinkTab.label          "Open link in new tab">
+<!ENTITY contextCopyLinkHref.label         "Copy link">
+<!ENTITY contextBookmarkLinkHref.label     "Bookmark link">
+
+<!-- IMAGE CONTEXT MENU -->
+<!-- l10n: contextSaveImageLib saves an image to the users "pictures library"
+     (Explorer -> left hand side navigation ppane -> Libraries -> Pictures) -->
+<!ENTITY contextSaveImageLib.label         "Save to picture library">
+<!ENTITY contextCopyImage.label            "Copy image">
+<!ENTITY contextCopyImageLocation.label    "Copy image location">
+<!ENTITY contextOpenImageTab.label         "Open image in new tab">
+
+<!-- VIDEO CONTEXT MENU -->
+<!ENTITY contextSaveVideoLib.label         "Save to video library">
+<!ENTITY contextCopyVideoLocation.label    "Copy video location">
+<!ENTITY contextOpenVideoTab.label         "Open video in new tab">
 
 <!ENTITY pageactions.password.forget "Forget Password">
 <!ENTITY pageactions.reset           "Clear Site Preferences">
 <!ENTITY pageactions.charEncoding    "Character Encoding">
--- a/browser/metro/locales/en-US/chrome/browser.properties
+++ b/browser/metro/locales/en-US/chrome/browser.properties
@@ -5,16 +5,19 @@
 # Default search engine
 browser.search.defaultenginename=Bing
 
 # Search engine order (order displayed in the search bar dropdown)s
 browser.search.order.1=Bing
 browser.search.order.2=Google
 browser.search.order.3=Yahoo
 
+# l10n: search context menu item text will be: |Search (browser.search.defaultenginename) for ".."
+browser.search.contextTextSearchLabel=Search %S for ".."
+
 # Settings Charms
 aboutCharm1=About
 optionsCharm=Options
 helpOnlineCharm=Help (online)
 
 # General
 browserForSaveLocation=Save Location
 
@@ -130,10 +133,11 @@ clearPrivateData.message=Delete your bro
 # This is not a string to translate. If users frequently use the "Character Encoding"
 # menu, set this to "true". Otherwise, you can leave it as "false".
 browser.menu.showCharacterEncoding=false
 
 # LOCALIZATION NOTE (intl.charsetmenu.browser.static): Set to a series of comma separated
 # values for charsets that the user can select from in the Character Encoding menu.
 intl.charsetmenu.browser.static=iso-8859-1,utf-8,x-gbk,big5,iso-2022-jp,shift_jis,euc-jp
 
-#Text Selection
+# Selection alerts
 selectionHelper.textCopied=Text copied to clipboard
+selectionHelper.linkCopied=Link copied to clipboard
--- a/browser/metro/profile/metro.js
+++ b/browser/metro/profile/metro.js
@@ -17,17 +17,17 @@ pref("app.reportCrashes", true);
 // Debug prefs, see input.js
 pref("metro.debug.treatmouseastouch", false);
 pref("metro.debug.colorizeInputOverlay", false);
 pref("metro.debug.selection.displayRanges", false);
 pref("metro.debug.selection.dumpRanges", false);
 pref("metro.debug.selection.dumpEvents", false);
 
 // Form helper options: 0 = disabled, 1 = enabled, 2 = dynamic depending on screen size
-pref("formhelper.mode", 1);
+pref("formhelper.mode", 0);
 // Auto zoom to form elements when they take focus 
 pref("formhelper.autozoom", true);
 // Auto zoom to the caret
 pref("formhelper.autozoom.caret", false);
 
 // form autocomplete service
 pref("browser.formfill.enable", true);
 
--- a/browser/metro/shell/commandexecutehandler/CommandExecuteHandler.cpp
+++ b/browser/metro/shell/commandexecutehandler/CommandExecuteHandler.cpp
@@ -15,16 +15,17 @@
 #include <shlwapi.h>
 #include <propkey.h>
 #include <propvarutil.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <strsafe.h>
 #include <io.h>
 #include <shellapi.h>
+#include <wininet.h>
 
 #ifdef SHOW_CONSOLE
 #define DEBUG_DELAY_SHUTDOWN 1
 #endif
 
 // Heartbeat timer duration used while waiting for an incoming request.
 #define HEARTBEAT_MSEC 1000
 // Total number of heartbeats we wait before giving up and shutting down.
@@ -433,34 +434,101 @@ bool CExecuteCommandVerb::IsTargetBrowse
   checkPath.Append(L"\\");
   checkPath.Append(kFirefoxExe);
   if (tmpTarget == checkPath) {
     return true;
   }
   return false;
 }
 
+namespace {
+  const FORMATETC kPlainTextFormat =
+    {CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
+  const FORMATETC kPlainTextWFormat =
+    {CF_UNICODETEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
+}
+
+bool HasPlainText(IDataObject* aDataObj) {
+  return SUCCEEDED(aDataObj->QueryGetData((FORMATETC*)&kPlainTextWFormat)) ||
+      SUCCEEDED(aDataObj->QueryGetData((FORMATETC*)&kPlainTextFormat));
+}
+
+bool GetPlainText(IDataObject* aDataObj, CStringW& cstrText)
+{
+  if (!HasPlainText(aDataObj))
+    return false;
+
+  STGMEDIUM store;
+
+  // unicode text
+  if (SUCCEEDED(aDataObj->GetData((FORMATETC*)&kPlainTextWFormat, &store))) {
+    // makes a copy
+    cstrText = static_cast<LPCWSTR>(GlobalLock(store.hGlobal));
+    GlobalUnlock(store.hGlobal);
+    ReleaseStgMedium(&store);
+    return true;
+  }
+
+  // ascii text
+  if (SUCCEEDED(aDataObj->GetData((FORMATETC*)&kPlainTextFormat, &store))) {
+    // makes a copy
+    cstrText = static_cast<char*>(GlobalLock(store.hGlobal));
+    GlobalUnlock(store.hGlobal);
+    ReleaseStgMedium(&store);
+    return true;
+  }
+
+  return false;
+}
+
 /*
  * Updates the current target based on the contents of
  * a shell item.
  */
 bool CExecuteCommandVerb::SetTargetPath(IShellItem* aItem)
 {
   if (!aItem)
     return false;
 
+  CString cstrText;
+  CComPtr<IDataObject> object;
+  // Check the underlying data object first to insure we get
+  // absolute uri. See chromium bug 157184.
+  if (SUCCEEDED(aItem->BindToHandler(NULL, BHID_DataObject,
+                                     IID_IDataObject,
+                                     reinterpret_cast<void**>(&object))) &&
+      GetPlainText(object, cstrText)) {
+    wchar_t scheme[16];
+    URL_COMPONENTS components = {0};
+    components.lpszScheme = scheme;
+    components.dwSchemeLength = sizeof(scheme)/sizeof(scheme[0]);
+    components.dwStructSize = sizeof(components);
+    // note, more advanced use may have issues with paths with spaces.
+    if (!InternetCrackUrlW(cstrText, 0, 0, &components)) {
+      Log(L"Failed to identify object text '%s'", cstrText);
+      return false;
+    }
+
+    mTargetIsFileSystemLink = (components.nScheme == INTERNET_SCHEME_FILE);
+    mTarget = cstrText;
+    return true;
+  }
+
+  Log(L"No data object or data object has no text.");
+
+  // Use the shell item display name
   LPWSTR str = NULL;
   mTargetIsFileSystemLink = true;
   if (FAILED(aItem->GetDisplayName(SIGDN_FILESYSPATH, &str))) {
+    mTargetIsFileSystemLink = false;
     if (FAILED(aItem->GetDisplayName(SIGDN_URL, &str))) {
+      Log(L"Failed to get parameter string.");
       return false;
     }
-    mTargetIsFileSystemLink = false;
   }
-
   mTarget = str;
   CoTaskMemFree(str);
   return true;
 }
 
 /*
  * Desktop launch - Launch the destop browser to display the current
  * target using shellexecute.
@@ -472,17 +540,19 @@ void CExecuteCommandVerb::LaunchDesktopB
     return;
   }
 
   // If a taskbar shortcut, link or local file is clicked, the target will
   // be the browser exe or file.
   CStringW params;
   if (!IsTargetBrowser()) {
     params += "-url ";
+    params += "\"";
     params += mTarget;
+    params += "\"";
   }
 
   Log(L"Desktop Launch: verb:%s exe:%s params:%s", mVerb, browserPath, params); 
 
   SHELLEXECUTEINFOW seinfo;
   memset(&seinfo, 0, sizeof(seinfo));
   seinfo.cbSize = sizeof(SHELLEXECUTEINFOW);
   seinfo.fMask  = NULL;
--- a/browser/metro/shell/commandexecutehandler/Makefile.in
+++ b/browser/metro/shell/commandexecutehandler/Makefile.in
@@ -30,13 +30,14 @@ CPPSRCS	= \
 
 OS_LIBS = \
 	kernel32.lib \
 	user32.lib \
 	ole32.lib \
 	shlwapi.lib \
 	propsys.lib \
 	advapi32.lib \
+	wininet.lib \
 	$(NULL)
 
 DEFINES += -DUNICODE -D_UNICODE -DNS_NO_XPCOM
 
 include $(topsrcdir)/config/rules.mk
--- a/browser/metro/theme/content.css
+++ b/browser/metro/theme/content.css
@@ -120,17 +120,17 @@ select[size][multiple],
   border-style: solid;
   border-color: #7d7d7d;
   color: #414141;
   /*background: white -moz-linear-gradient(top, rgba(115,115,115,0.5) 0, rgba(215,215,215,0.5) 3px, rgba(255,255,255,0.2) 16px);*/
 }
 
 /* For both mouse and touch, single-selects are handled by the SelectHelper popup.
  * Suppress mouse events on the popup itself. See also ../base/content/cursor.css */
-select[size=1] :-moz-any(option, optgroup),
+select[size="1"] :-moz-any(option, optgroup),
 select:not([size]):not([multiple]) :-moz-any(option, optgroup) {
   pointer-events: none;
 }
 
 input:-moz-placeholder {
   color: GrayText;
 }
 
--- a/build/pgo/profileserver.py
+++ b/build/pgo/profileserver.py
@@ -15,17 +15,17 @@ from datetime import datetime
 
 SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
 sys.path.insert(0, SCRIPT_DIR)
 from automation import Automation
 from automationutils import getDebuggerInfo, addCommonOptions
 
 PORT = 8888
 PROFILE_DIRECTORY = os.path.abspath(os.path.join(SCRIPT_DIR, "./pgoprofile"))
-MOZ_JAR_LOG_DIR = os.path.abspath(os.getenv("JARLOG_DIR"))
+MOZ_JAR_LOG_FILE = os.path.abspath(os.getenv("JARLOG_FILE"))
 os.chdir(SCRIPT_DIR)
 
 class EasyServer(SocketServer.TCPServer):
   allow_reuse_address = True
 
 if __name__ == '__main__':
   from optparse import OptionParser
   automation = Automation()
@@ -42,17 +42,17 @@ if __name__ == '__main__':
   t = threading.Thread(target=httpd.serve_forever)
   t.setDaemon(True) # don't hang on exit
   t.start()
   
   automation.setServerInfo("localhost", PORT)
   automation.initializeProfile(PROFILE_DIRECTORY)
   browserEnv = automation.environment()
   browserEnv["XPCOM_DEBUG_BREAK"] = "warn"
-  browserEnv["MOZ_JAR_LOG_DIR"] = MOZ_JAR_LOG_DIR
+  browserEnv["MOZ_JAR_LOG_FILE"] = MOZ_JAR_LOG_FILE
 
   url = "http://localhost:%d/index.html" % PORT
   appPath = os.path.join(SCRIPT_DIR, automation.DEFAULT_APP)
   status = automation.runApp(url, browserEnv, appPath, PROFILE_DIRECTORY, {},
                              debuggerInfo=debuggerInfo,
                              # the profiling HTML doesn't output anything,
                              # so let's just run this without a timeout
                              timeout = None)
--- a/client.mk
+++ b/client.mk
@@ -198,17 +198,18 @@ ifdef MOZ_OBJDIR
   PGO_OBJDIR = $(MOZ_OBJDIR)
 else
   PGO_OBJDIR := $(TOPSRCDIR)
 endif
 
 profiledbuild::
 	$(MAKE) -f $(TOPSRCDIR)/client.mk realbuild MOZ_PROFILE_GENERATE=1 MOZ_PGO_INSTRUMENTED=1
 	$(MAKE) -C $(PGO_OBJDIR) package MOZ_PGO_INSTRUMENTED=1 MOZ_INTERNAL_SIGNING_FORMAT= MOZ_EXTERNAL_SIGNING_FORMAT=
-	MOZ_PGO_INSTRUMENTED=1 OBJDIR=${PGO_OBJDIR} JARLOG_DIR=${PGO_OBJDIR}/jarlog/en-US $(PROFILE_GEN_SCRIPT)
+	rm -f ${PGO_OBJDIR}/jarlog/en-US.log
+	MOZ_PGO_INSTRUMENTED=1 OBJDIR=${PGO_OBJDIR} JARLOG_FILE=${PGO_OBJDIR}/jarlog/en-US.log $(PROFILE_GEN_SCRIPT)
 	$(MAKE) -f $(TOPSRCDIR)/client.mk maybe_clobber_profiledbuild
 	$(MAKE) -f $(TOPSRCDIR)/client.mk realbuild MOZ_PROFILE_USE=1
 
 #####################################################
 # Build date unification
 
 ifdef MOZ_UNIFY_BDATE
 ifndef MOZ_BUILD_DATE
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -1202,35 +1202,35 @@ PREF_DIR = defaults/pref
 
 # If DIST_SUBDIR is defined it indicates that app and gre dirs are
 # different and that we are building app related resources. Hence,
 # PREF_DIR should point to the app prefs location.
 ifneq (,$(DIST_SUBDIR)$(XPI_NAME)$(LIBXUL_SDK))
 PREF_DIR = defaults/preferences
 endif
 
-ifneq ($(PREF_JS_EXPORTS),)
 # on win32, pref files need CRLF line endings... see bug 206029
 ifeq (WINNT,$(OS_ARCH))
-PREF_PPFLAGS = --line-endings=crlf
-endif
-
-ifndef NO_DIST_INSTALL
-PREF_JS_EXPORTS_PATH := $(FINAL_TARGET)/$(PREF_DIR)
-PREF_JS_EXPORTS_FLAGS := $(PREF_PPFLAGS)
-PP_TARGETS += PREF_JS_EXPORTS
-endif
+PREF_PPFLAGS += --line-endings=crlf
 endif
 
 # Set a flag that can be used in pref files to disable features if
 # we are not building for Aurora or Nightly.
 ifeq (,$(findstring a,$(GRE_MILESTONE)))
 PREF_PPFLAGS += -DRELEASE_BUILD
 endif
 
+ifneq ($(PREF_JS_EXPORTS),)
+ifndef NO_DIST_INSTALL
+PREF_JS_EXPORTS_PATH := $(FINAL_TARGET)/$(PREF_DIR)
+PREF_JS_EXPORTS_FLAGS := $(PREF_PPFLAGS)
+PP_TARGETS += PREF_JS_EXPORTS
+endif
+endif
+
 ################################################################################
 # Copy each element of AUTOCFG_JS_EXPORTS to $(FINAL_TARGET)/defaults/autoconfig
 
 ifneq ($(AUTOCFG_JS_EXPORTS),)
 ifndef NO_DIST_INSTALL
 AUTOCFG_JS_EXPORTS_FILES := $(AUTOCFG_JS_EXPORTS)
 AUTOCFG_JS_EXPORTS_DEST := $(FINAL_TARGET)/defaults/autoconfig
 AUTOCFG_JS_EXPORTS_TARGET := export
--- a/content/base/public/nsIXMLHttpRequest.idl
+++ b/content/base/public/nsIXMLHttpRequest.idl
@@ -16,37 +16,16 @@ interface nsPIDOMWindow;
 interface nsIInputStream;
 interface nsIDOMBlob;
 
 %{C++
 // for jsval
 #include "jsapi.h"
 %}
 
-/**
- * Parameters for instantiating an XMLHttpRequest. They are passed as an
- * optional argument to the constructor:
- *
- *  new XMLHttpRequest({anon: true, system: true});
- *
- */
-dictionary XMLHttpRequestParameters
-{
-  /**
-   * If true, the request will be sent without cookie and authentication
-   * headers.
-   */
-  boolean mozAnon;
-
-  /**
-   * If true, the same origin policy will not be enforced on the request.
-   */
-  boolean mozSystem;
-};
-
 [scriptable, builtinclass, uuid(a137d5e6-81e2-4fa3-a791-26459df723ff)]
 interface nsIXMLHttpRequestEventTarget : nsIDOMEventTarget {
   // event handler attributes
   [implicit_jscontext] attribute jsval onabort;
   [implicit_jscontext] attribute jsval onerror;
   [implicit_jscontext] attribute jsval onload;
   [implicit_jscontext] attribute jsval onloadstart;
   [implicit_jscontext] attribute jsval onprogress;
--- a/content/base/src/DirectionalityUtils.cpp
+++ b/content/base/src/DirectionalityUtils.cpp
@@ -233,23 +233,28 @@ typedef mozilla::dom::Element Element;
  */
 static bool
 DoesNotParticipateInAutoDirection(const Element* aElement)
 {
   nsINodeInfo* nodeInfo = aElement->NodeInfo();
   return (!aElement->IsHTML() ||
           nodeInfo->Equals(nsGkAtoms::script) ||
           nodeInfo->Equals(nsGkAtoms::style) ||
-          nodeInfo->Equals(nsGkAtoms::textarea));
+          nodeInfo->Equals(nsGkAtoms::textarea) ||
+          aElement->IsInAnonymousSubtree());
 }
 
 static inline bool
 IsBdiWithoutDirAuto(const Element* aElement)
 {
-  return aElement->IsHTML(nsGkAtoms::bdi) && !aElement->HasDirAuto();
+  // We are testing for bdi elements without explicit dir="auto", so we can't
+  // use the HasDirAuto() flag, since that will return true for bdi element with
+  // no dir attribute or an invalid dir attribute
+  return (aElement->IsHTML(nsGkAtoms::bdi) &&
+          (!aElement->HasValidDir() || aElement->HasFixedDir()));
 }
 
 /**
  * Returns true if aElement is one of the element whose text content should not
  * affect the direction of ancestors with dir=auto (though it may affect its own
  * direction, e.g. <bdi>)
  */
 static bool
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -1106,17 +1106,18 @@ nsFrameScriptExecutor::TryCacheLoadAndCo
       }
     } 
     JSContext* unused;
     nsContentUtils::ThreadJSContextStack()->Pop(&unused);
   }
 }
 
 bool
-nsFrameScriptExecutor::InitTabChildGlobalInternal(nsISupports* aScope)
+nsFrameScriptExecutor::InitTabChildGlobalInternal(nsISupports* aScope,
+                                                  const nsACString& aID)
 {
   
   nsCOMPtr<nsIJSRuntimeService> runtimeSvc = 
     do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
   NS_ENSURE_TRUE(runtimeSvc, false);
 
   JSRuntime* rt = nullptr;
   runtimeSvc->GetRuntime(&rt);
@@ -1146,16 +1147,21 @@ nsFrameScriptExecutor::InitTabChildGloba
   NS_ENSURE_SUCCESS(rv, false);
 
     
   JSObject* global = nullptr;
   rv = mGlobal->GetJSObject(&global);
   NS_ENSURE_SUCCESS(rv, false);
 
   JS_SetGlobalObject(cx, global);
+
+  // Set the location information for the new global, so that tools like
+  // about:memory may use that information.
+  xpc::SetLocationForGlobal(global, aID);
+
   DidCreateCx();
   return true;
 }
 
 // static
 void
 nsFrameScriptExecutor::Traverse(nsFrameScriptExecutor *tmp,
                                 nsCycleCollectionTraversalCallback &cb)
--- a/content/base/src/nsFrameMessageManager.h
+++ b/content/base/src/nsFrameMessageManager.h
@@ -289,17 +289,17 @@ protected:
   { MOZ_COUNT_DTOR(nsFrameScriptExecutor); }
   void DidCreateCx();
   // Call this when you want to destroy mCx.
   void DestroyCx();
   void LoadFrameScriptInternal(const nsAString& aURL);
   enum CacheFailedBehavior { EXECUTE_IF_CANT_CACHE, DONT_EXECUTE };
   void TryCacheLoadAndCompileScript(const nsAString& aURL,
                                     CacheFailedBehavior aBehavior = DONT_EXECUTE);
-  bool InitTabChildGlobalInternal(nsISupports* aScope);
+  bool InitTabChildGlobalInternal(nsISupports* aScope, const nsACString& aID);
   static void Traverse(nsFrameScriptExecutor *tmp,
                        nsCycleCollectionTraversalCallback &cb);
   static void Unlink(nsFrameScriptExecutor* aTmp);
   nsCOMPtr<nsIXPConnectJSObjectHolder> mGlobal;
   JSContext* mCx;
   uint32_t mCxStackRefCnt;
   bool mDelayedCxDestroy;
   nsCOMPtr<nsIPrincipal> mPrincipal;
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -33,16 +33,17 @@
 
 GK_ATOM(_empty, "")
 GK_ATOM(moz, "_moz")
 GK_ATOM(mozframetype, "mozframetype")
 GK_ATOM(mozallowfullscreen, "mozallowfullscreen")
 GK_ATOM(moztype, "_moz-type")
 GK_ATOM(mozdirty, "_moz_dirty")
 GK_ATOM(mozdisallowselectionprint, "mozdisallowselectionprint")
+GK_ATOM(moznomarginboxes, "moznomarginboxes")
 GK_ATOM(mozdonotsend, "moz-do-not-send")
 GK_ATOM(mozeditorbogusnode, "_moz_editor_bogus_node")
 GK_ATOM(mozgeneratedcontentbefore, "_moz_generated_content_before")
 GK_ATOM(mozgeneratedcontentafter, "_moz_generated_content_after")
 GK_ATOM(mozgeneratedcontentimage, "_moz_generated_content_image")
 GK_ATOM(mozquote, "_moz_quote")
 GK_ATOM(_moz_is_glyph, "-moz-is-glyph")
 GK_ATOM(_moz_original_size, "_moz_original_size")
--- a/content/base/src/nsInProcessTabChildGlobal.cpp
+++ b/content/base/src/nsInProcessTabChildGlobal.cpp
@@ -138,25 +138,16 @@ nsInProcessTabChildGlobal::Init()
 #endif
   InitTabChildGlobal();
   NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
                    "Couldn't initialize nsInProcessTabChildGlobal");
   mMessageManager = new nsFrameMessageManager(this,
                                               nullptr,
                                               mCx,
                                               mozilla::dom::ipc::MM_CHILD);
-
-  // Set the location information for the new global, so that tools like
-  // about:memory may use that information.
-  JSObject *global;
-  nsIURI* docURI = mOwner->OwnerDoc()->GetDocumentURI();
-  if (mGlobal && NS_SUCCEEDED(mGlobal->GetJSObject(&global)) && docURI) {
-    xpc::SetLocationForGlobal(global, docURI);
-  }
-
   return NS_OK;
 }
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsInProcessTabChildGlobal,
                                                 nsDOMEventTargetHelper)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal)
   nsFrameScriptExecutor::Unlink(tmp);
@@ -302,20 +293,28 @@ nsInProcessTabChildGlobal::PreHandleEven
 #endif
 
   return NS_OK;
 }
 
 nsresult
 nsInProcessTabChildGlobal::InitTabChildGlobal()
 {
-
+  nsAutoCString id;
+  id.AssignLiteral("inProcessTabChildGlobal");
+  nsIURI* uri = mOwner->OwnerDoc()->GetDocumentURI();
+  if (uri) {
+    nsAutoCString u;
+    uri->GetSpec(u);
+    id.AppendLiteral("?ownedBy=");
+    id.Append(u);
+  }
   nsISupports* scopeSupports =
     NS_ISUPPORTS_CAST(nsIDOMEventTarget*, this);
-  NS_ENSURE_STATE(InitTabChildGlobalInternal(scopeSupports));
+  NS_ENSURE_STATE(InitTabChildGlobalInternal(scopeSupports, id));
   return NS_OK;
 }
 
 class nsAsyncScriptLoad : public nsRunnable
 {
 public:
   nsAsyncScriptLoad(nsInProcessTabChildGlobal* aTabChild, const nsAString& aURL)
   : mTabChild(aTabChild), mURL(aURL) {}
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -465,53 +465,16 @@ nsXMLHttpRequest::Init(nsIPrincipal* aPr
                "Expecting an outer window here!");
   NS_ENSURE_ARG_POINTER(aPrincipal);
   Construct(aPrincipal,
             aOwnerWindow ? aOwnerWindow->GetCurrentInnerWindow() : nullptr,
             aBaseURI);
   return NS_OK;
 }
 
-/**
- * This Initialize method is called from XPConnect via nsIJSNativeInitializer.
- */
-NS_IMETHODIMP
-nsXMLHttpRequest::Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj,
-                             uint32_t argc, jsval *argv)
-{
-  nsCOMPtr<nsPIDOMWindow> owner = do_QueryInterface(aOwner);
-  if (!owner) {
-    NS_WARNING("Unexpected nsIJSNativeInitializer owner");
-    return NS_OK;
-  }
-
-  // This XHR object is bound to a |window|,
-  // so re-set principal and script context.
-  nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal = do_QueryInterface(aOwner);
-  NS_ENSURE_STATE(scriptPrincipal);
-
-  Construct(scriptPrincipal->GetPrincipal(), owner);
-  if (argc) {
-    nsresult rv = InitParameters(cx, argv);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  return NS_OK;
-}
-
-nsresult
-nsXMLHttpRequest::InitParameters(JSContext* aCx, const jsval* aParams)
-{
-  mozilla::idl::XMLHttpRequestParameters params;
-  nsresult rv = params.Init(aCx, aParams);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  InitParameters(params.mozAnon, params.mozSystem);
-  return NS_OK;
-}
-
 void
 nsXMLHttpRequest::InitParameters(bool aAnon, bool aSystem)
 {
   if (!aAnon && !aSystem) {
     return;
   }
 
   // Check for permissions.
@@ -633,17 +596,16 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_
   NS_INTERFACE_MAP_ENTRY(nsIXMLHttpRequest)
   NS_INTERFACE_MAP_ENTRY(nsIJSXMLHttpRequest)
   NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
   NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
   NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
   NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)
   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
-  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
   NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
   NS_INTERFACE_MAP_ENTRY(nsISizeOfEventTarget)
 NS_INTERFACE_MAP_END_INHERITING(nsXHREventTarget)
 
 NS_IMPL_ADDREF_INHERITED(nsXMLHttpRequest, nsXHREventTarget)
 NS_IMPL_RELEASE_INHERITED(nsXMLHttpRequest, nsXHREventTarget)
 
 NS_IMPL_EVENT_HANDLER(nsXMLHttpRequest, readystatechange)
--- a/content/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -21,17 +21,16 @@
 #include "nsIChannelEventSink.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIHttpHeaderVisitor.h"
 #include "nsIProgressEventSink.h"
 #include "nsCOMArray.h"
 #include "nsJSUtils.h"
 #include "nsTArray.h"
-#include "nsIJSNativeInitializer.h"
 #include "nsIDOMLSProgressEvent.h"
 #include "nsITimer.h"
 #include "nsIDOMProgressEvent.h"
 #include "nsDOMEventTargetHelper.h"
 #include "nsDOMFile.h"
 #include "nsDOMBlobBuilder.h"
 #include "nsIPrincipal.h"
 #include "nsIScriptObjectPrincipal.h"
@@ -119,17 +118,16 @@ class nsXMLHttpRequestXPCOMifier;
 class nsXMLHttpRequest : public nsXHREventTarget,
                          public nsIXMLHttpRequest,
                          public nsIJSXMLHttpRequest,
                          public nsIStreamListener,
                          public nsIChannelEventSink,
                          public nsIProgressEventSink,
                          public nsIInterfaceRequestor,
                          public nsSupportsWeakReference,
-                         public nsIJSNativeInitializer,
                          public nsITimerCallback,
                          public nsISizeOfEventTarget
 {
   friend class nsXHRParseEndListener;
   friend class nsXMLHttpRequestXPCOMifier;
 
 public:
   nsXMLHttpRequest();
@@ -188,18 +186,16 @@ public:
   {
     MOZ_ASSERT(aPrincipal);
     MOZ_ASSERT_IF(aOwnerWindow, aOwnerWindow->IsInnerWindow());
     mPrincipal = aPrincipal;
     BindToOwner(aOwnerWindow);
     mBaseURI = aBaseURI;
   }
 
-  // Initialize XMLHttpRequestParameter object.
-  nsresult InitParameters(JSContext* aCx, const jsval* aParams);
   void InitParameters(bool aAnon, bool aSystem);
 
   void SetParameters(bool aAnon, bool aSystem)
   {
     mIsAnon = aAnon;
     mIsSystem = aSystem;
   }
 
@@ -223,20 +219,16 @@ public:
   NS_DECL_NSIPROGRESSEVENTSINK
 
   // nsIInterfaceRequestor
   NS_DECL_NSIINTERFACEREQUESTOR
 
   // nsITimerCallback
   NS_DECL_NSITIMERCALLBACK
 
-  // nsIJSNativeInitializer
-  NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj,
-                       uint32_t argc, jsval* argv);
-
   // nsISizeOfEventTarget
   virtual size_t
     SizeOfEventTargetIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
 
   NS_FORWARD_NSIDOMEVENTTARGET(nsXHREventTarget::)
 
 #ifdef DEBUG
   void StaticAssertions();
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -608,25 +608,16 @@ MOCHITEST_FILES_C= \
 		test_XHR_parameters.html \
 		test_ipc_messagemanager_blob.html \
 		test_mixed_content_blocker.html \
 		file_mixed_content_main.html \
 		file_mixed_content_server.sjs \
     test_mixed_content_blocker_bug803225.html \
     file_mixed_content_main_bug803225.html \
     file_mixed_content_main_bug803225_websocket_wsh.py \
-    file_bug822367_1.html \
-    file_bug822367_1.js \
-    file_bug822367_2.html \
-    file_bug822367_3.html \
-    file_bug822367_4.html \
-    file_bug822367_4.js \
-    file_bug822367_4B.html \
-    file_bug822367_5.html \
-    file_bug822367_6.html \
     bug803225_test_mailto.html \
 		test_bug789856.html \
 		file_bug804395.jar \
 		test_bug804395.html \
 		test_bug809003.html \
 		test_bug810494.html \
 		test_bug819051.html \
 		bug819051.sjs \
--- a/content/base/test/chrome/Makefile.in
+++ b/content/base/test/chrome/Makefile.in
@@ -52,12 +52,9 @@ MOCHITEST_CHROME_FILES = \
     test_bug816340.xul \
     file_bug816340.xul \
     test_domparsing.xul \
     test_bug814638.xul \
     host_bug814638.xul \
     frame_bug814638.xul \
     $(NULL)
 
-MOCHITEST_BROWSER_FILES = \
-    browser_bug822367.js \
-
 include $(topsrcdir)/config/rules.mk
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -45,19 +45,20 @@
 #include "mozilla/Services.h"
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ipc/ProcessPriorityManager.h"
 
 #include "Layers.h"
 
 using namespace mozilla;
-using namespace mozilla::gl;
 using namespace mozilla::dom;
 using namespace mozilla::dom::ipc;
+using namespace mozilla::gfx;
+using namespace mozilla::gl;
 using namespace mozilla::layers;
 
 NS_IMETHODIMP
 WebGLMemoryPressureObserver::Observe(nsISupports* aSubject,
                                      const char* aTopic,
                                      const PRUnichar* aSomeData)
 {
     if (strcmp(aTopic, "memory-pressure"))
@@ -104,16 +105,17 @@ WebGLContextOptions::WebGLContextOptions
 
 WebGLContext::WebGLContext()
     : gl(nullptr)
 {
     SetIsDOMBinding();
 
     mGeneration = 0;
     mInvalidated = false;
+    mShouldPresent = true;
     mResetLayer = true;
     mOptionsFrozen = false;
 
     mActiveTexture = 0;
     mWebGLError = LOCAL_GL_NO_ERROR;
     mPixelStoreFlipY = false;
     mPixelStorePremultiplyAlpha = false;
     mPixelStoreColorspaceConversion = BROWSER_DEFAULT_WEBGL;
@@ -151,17 +153,16 @@ WebGLContext::WebGLContext()
     mStencilRefBack = 0;
     mStencilValueMaskFront = 0xffffffff;
     mStencilValueMaskBack  = 0xffffffff;
     mStencilWriteMaskFront = 0xffffffff;
     mStencilWriteMaskBack  = 0xffffffff;
 
     mScissorTestEnabled = 0;
     mDitherEnabled = 1;
-    mBackbufferClearingStatus = BackbufferClearingStatus::NotClearedSinceLastPresented;
     
     // initialize some GL values: we're going to get them from the GL and use them as the sizes of arrays,
     // so in case glGetIntegerv leaves them uninitialized because of a GL bug, we would have very weird crashes.
     mGLMaxVertexAttribs = 0;
     mGLMaxTextureUnits = 0;
     mGLMaxTextureSize = 0;
     mGLMaxCubeMapTextureSize = 0;
     mGLMaxRenderbufferSize = 0;
@@ -188,16 +189,18 @@ WebGLContext::WebGLContext()
 
     mAlreadyGeneratedWarnings = 0;
     mAlreadyWarnedAboutFakeVertexAttrib0 = false;
 
     mLastUseIndex = 0;
 
     mMinInUseAttribArrayLengthCached = false;
     mMinInUseAttribArrayLength = 0;
+
+    mIsScreenCleared = false;
 }
 
 WebGLContext::~WebGLContext()
 {
     DestroyResourcesAndContext();
     WebGLMemoryMultiReporterWrapper::RemoveWebGLContext(this);
     TerminateContextLossTimer();
     mContextRestorer = nullptr;
@@ -377,21 +380,23 @@ WebGLContext::SetDimensions(int32_t widt
     // If we already have a gl context, then we just need to resize it
     if (gl) {
         MakeContextCurrent();
 
         gl->ResizeOffscreen(gfxIntSize(width, height)); // Doesn't matter if it succeeds (soft-fail)
         // It's unlikely that we'll get a proper-sized context if we recreate if we didn't on resize
 
         // everything's good, we're done here
-        mWidth = gl->OffscreenActualSize().width;
-        mHeight = gl->OffscreenActualSize().height;
+        mWidth = gl->OffscreenSize().width;
+        mHeight = gl->OffscreenSize().height;
         mResetLayer = true;
 
+        ScopedBindFramebuffer autoFB(gl, 0);
         gl->ClearSafely();
+        mShouldPresent = true;
 
         return NS_OK;
     }
 
     // End of early return cases.
     // At this point we know that we're not just resizing an existing context,
     // we are initializing a new context.
 
@@ -431,65 +436,40 @@ WebGLContext::SetDimensions(int32_t widt
     // event.
 
     // If incrementing the generation would cause overflow,
     // don't allow it.  Allowing this would allow us to use
     // resource handles created from older context generations.
     if (!(mGeneration + 1).isValid())
         return NS_ERROR_FAILURE; // exit without changing the value of mGeneration
 
-    gl::ContextFormat format(gl::ContextFormat::BasicRGBA32);
-    if (mOptions.depth) {
-        format.depth = 24;
-        format.minDepth = 16;
-    }
+    SurfaceCaps caps;
 
-    if (mOptions.stencil) {
-        format.stencil = 8;
-        format.minStencil = 8;
-    }
-
-    if (!mOptions.alpha) {
-        format.alpha = 0;
-        format.minAlpha = 0;
-    }
+    caps.color = true;
+    caps.alpha = mOptions.alpha;
+    caps.depth = mOptions.depth;
+    caps.stencil = mOptions.stencil;
 
     // we should really have this behind a
     // |gfxPlatform::GetPlatform()->GetScreenDepth() == 16| check, but
     // for now it's just behind a pref for testing/evaluation.
-    if (prefer16bit) {
-        // Select 4444 or 565 on 16-bit displays; we won't/shouldn't
-        // hit this on the desktop, but let mobile know we're ok with
-        // it.  Note that we don't just set this to 4440 if no alpha,
-        // because that might cause us to choose 4444 anyway and we
-        // don't want that.
-        if (mOptions.alpha) {
-            format.red = 4;
-            format.green = 4;
-            format.blue = 4;
-            format.alpha = 4;
-        } else {
-            format.red = 5;
-            format.green = 6;
-            format.blue = 5;
-            format.alpha = 0;
-        }
-    }
+    caps.bpp16 = prefer16bit;
+
+    caps.preserve = mOptions.preserveDrawingBuffer;
 
     bool forceMSAA =
         Preferences::GetBool("webgl.msaa-force", false);
 
     int32_t status;
     nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
     if (mOptions.antialias &&
         gfxInfo &&
         NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBGL_MSAA, &status))) {
         if (status == nsIGfxInfo::FEATURE_NO_INFO || forceMSAA) {
-            uint32_t msaaLevel = Preferences::GetUint("webgl.msaa-level", 2);
-            format.samples = msaaLevel*msaaLevel;
+            caps.antialias = true;
         }
     }
 
 #ifdef XP_WIN
     if (PR_GetEnv("MOZ_WEBGL_PREFER_EGL")) {
         preferEGL = true;
     }
 #endif
@@ -520,34 +500,35 @@ WebGLContext::SetDimensions(int32_t widt
     // allow forcing GL and not EGL/ANGLE
     if (useMesaLlvmPipe || PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL")) {
         preferEGL = false;
         useANGLE = false;
         useOpenGL = true;
     }
 #endif
 
+    gfxIntSize size(width, height);
+
 #ifdef XP_WIN
     // if we want EGL, try it now
     if (!gl && (preferEGL || useANGLE) && !preferOpenGL) {
-        gl = gl::GLContextProviderEGL::CreateOffscreen(gfxIntSize(width, height), format);
+        gl = gl::GLContextProviderEGL::CreateOffscreen(size, caps);
         if (!gl || !InitAndValidateGL()) {
             GenerateWarning("Error during ANGLE OpenGL ES initialization");
             return NS_ERROR_FAILURE;
         }
     }
 #endif
 
     // try the default provider, whatever that is
     if (!gl && useOpenGL) {
         GLContext::ContextFlags flag = useMesaLlvmPipe 
                                        ? GLContext::ContextFlagsMesaLLVMPipe
                                        : GLContext::ContextFlagsNone;
-        gl = gl::GLContextProvider::CreateOffscreen(gfxIntSize(width, height), 
-                                                               format, flag);
+        gl = gl::GLContextProvider::CreateOffscreen(size, caps, flag);
         if (gl && !InitAndValidateGL()) {
             GenerateWarning("Error during %s initialization", 
                             useMesaLlvmPipe ? "Mesa LLVMpipe" : "OpenGL");
             return NS_ERROR_FAILURE;
         }
     }
 
     if (!gl) {
@@ -576,25 +557,34 @@ WebGLContext::SetDimensions(int32_t widt
         // XXX dispatch context lost event
     }
 #endif
 
     MakeContextCurrent();
 
     // Make sure that we clear this out, otherwise
     // we'll end up displaying random memory
-    gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, gl->GetOffscreenFBO());
+    gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
 
     gl->fViewport(0, 0, mWidth, mHeight);
     gl->fClearColor(0.0f, 0.0f, 0.0f, 0.0f);
     gl->fClearDepth(1.0f);
     gl->fClearStencil(0);
 
     gl->ClearSafely();
 
+    mShouldPresent = true;
+
+    MOZ_ASSERT(gl->Caps().color == caps.color);
+    MOZ_ASSERT(gl->Caps().alpha == caps.alpha);
+    MOZ_ASSERT(gl->Caps().depth == caps.depth || !gl->Caps().depth);
+    MOZ_ASSERT(gl->Caps().stencil == caps.stencil || !gl->Caps().stencil);
+    MOZ_ASSERT(gl->Caps().antialias == caps.antialias || !gl->Caps().antialias);
+    MOZ_ASSERT(gl->Caps().preserve == caps.preserve);
+
     reporter.SetSuccessful();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::Render(gfxContext *ctx, gfxPattern::GraphicsFilter f, uint32_t aFlags)
 {
     if (!gl)
@@ -798,35 +788,49 @@ void WebGLContext::UpdateLastUseIndex()
 
 static uint8_t gWebGLLayerUserData;
 
 namespace mozilla {
 
 class WebGLContextUserData : public LayerUserData {
 public:
     WebGLContextUserData(HTMLCanvasElement *aContent)
-    : mContent(aContent) {}
+        : mContent(aContent)
+    {}
+
+    /* PreTransactionCallback gets called by the Layers code every time the
+     * WebGL canvas is going to be composited.
+     */
+    static void PreTransactionCallback(void* data)
+    {
+        WebGLContextUserData* userdata = static_cast<WebGLContextUserData*>(data);
+        HTMLCanvasElement* canvas = userdata->mContent;
+        WebGLContext* context = static_cast<WebGLContext*>(canvas->GetContextAtIndex(0));
 
-  /** DidTransactionCallback gets called by the Layers code everytime the WebGL canvas gets composite,
-    * so it really is the right place to put actions that have to be performed upon compositing
-    */
-  static void DidTransactionCallback(void* aData)
-  {
-    WebGLContextUserData *userdata = static_cast<WebGLContextUserData*>(aData);
-    HTMLCanvasElement *canvas = userdata->mContent;
-    WebGLContext *context = static_cast<WebGLContext*>(canvas->GetContextAtIndex(0));
+        // Present our screenbuffer, if needed.
+        context->PresentScreenBuffer();
+    }
 
-    context->mBackbufferClearingStatus = BackbufferClearingStatus::NotClearedSinceLastPresented;
-    canvas->MarkContextClean();
+    /** DidTransactionCallback gets called by the Layers code everytime the WebGL canvas gets composite,
+      * so it really is the right place to put actions that have to be performed upon compositing
+      */
+    static void DidTransactionCallback(void* aData)
+    {
+        WebGLContextUserData *userdata = static_cast<WebGLContextUserData*>(aData);
+        HTMLCanvasElement *canvas = userdata->mContent;
+        WebGLContext *context = static_cast<WebGLContext*>(canvas->GetContextAtIndex(0));
 
-    context->UpdateLastUseIndex();
-  }
+        // Mark ourselves as no longer invalidated.
+        context->MarkContextClean();
+
+        context->UpdateLastUseIndex();
+    }
 
 private:
-  nsRefPtr<HTMLCanvasElement> mContent;
+    nsRefPtr<HTMLCanvasElement> mContent;
 };
 
 } // end namespace mozilla
 
 already_AddRefed<layers::CanvasLayer>
 WebGLContext::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
                              CanvasLayer *aOldLayer,
                              LayerManager *aManager)
@@ -857,38 +861,28 @@ WebGLContext::GetCanvasLayer(nsDisplayLi
       // The layer will be destroyed when we tear down the presentation
       // (at the latest), at which time this userData will be destroyed,
       // releasing the reference to the element.
       // The userData will receive DidTransactionCallbacks, which flush the
       // the invalidation state to indicate that the canvas is up to date.
       userData = new WebGLContextUserData(mCanvasElement);
       canvasLayer->SetDidTransactionCallback(
               WebGLContextUserData::DidTransactionCallback, userData);
+      canvasLayer->SetPreTransactionCallback(
+              WebGLContextUserData::PreTransactionCallback, userData);
     }
     canvasLayer->SetUserData(&gWebGLLayerUserData, userData);
 
     CanvasLayer::Data data;
-
-    // the gl context may either provide a native PBuffer, in which case we want to initialize
-    // data with the gl context directly, or may provide a surface to which it renders (this is the case
-    // of OSMesa contexts), in which case we want to initialize data with that surface.
-
-    void* native_surface = gl->GetNativeData(gl::GLContext::NativeImageSurface);
-
-    if (native_surface) {
-        data.mSurface = static_cast<gfxASurface*>(native_surface);
-    } else {
-        data.mGLContext = gl.get();
-    }
-
+    data.mGLContext = gl;
     data.mSize = nsIntSize(mWidth, mHeight);
-    data.mGLBufferIsPremultiplied = mOptions.premultipliedAlpha ? true : false;
+    data.mIsGLAlphaPremult = IsPremultAlpha();
 
     canvasLayer->Initialize(data);
-    uint32_t flags = gl->CreationFormat().alpha == 0 ? Layer::CONTENT_OPAQUE : 0;
+    uint32_t flags = gl->Caps().alpha ? 0 : Layer::CONTENT_OPAQUE;
     canvasLayer->SetContentFlags(flags);
     canvasLayer->Updated();
 
     mResetLayer = false;
 
     return canvasLayer.forget().get();
 }
 
@@ -896,21 +890,22 @@ void
 WebGLContext::GetContextAttributes(Nullable<dom::WebGLContextAttributesInitializer> &retval)
 {
     retval.SetNull();
     if (!IsContextStable())
         return;
 
     dom::WebGLContextAttributes& result = retval.SetValue();
 
-    gl::ContextFormat cf = gl->ActualFormat();
-    result.mAlpha = cf.alpha > 0;
-    result.mDepth = cf.depth > 0;
-    result.mStencil = cf.stencil > 0;
-    result.mAntialias = cf.samples > 1;
+    const PixelBufferFormat& format = gl->GetPixelFormat();
+
+    result.mAlpha = format.alpha > 0;
+    result.mDepth = format.depth > 0;
+    result.mStencil = format.stencil > 0;
+    result.mAntialias = format.samples > 1;
     result.mPremultipliedAlpha = mOptions.premultipliedAlpha;
     result.mPreserveDrawingBuffer = mOptions.preserveDrawingBuffer;
 }
 
 bool
 WebGLContext::IsExtensionEnabled(WebGLExtensionID ext) const {
     return mExtensions.SafeElementAt(ext);
 }
@@ -1104,50 +1099,128 @@ WebGLContext::GetExtension(JSContext *cx
         mExtensions.EnsureLengthAtLeast(ext + 1);
         mExtensions[ext] = obj;
     }
 
     return WebGLObjectAsJSObject(cx, mExtensions[ext].get(), rv);
 }
 
 void
-WebGLContext::ForceClearFramebufferWithDefaultValues(uint32_t mask, const nsIntRect& viewportRect)
+WebGLContext::ClearScreen()
+{
+    MakeContextCurrent();
+    ScopedBindFramebuffer autoFB(gl, 0);
+
+    GLbitfield clearMask = LOCAL_GL_COLOR_BUFFER_BIT;
+    if (mOptions.depth)
+        clearMask |= LOCAL_GL_DEPTH_BUFFER_BIT;
+    if (mOptions.stencil)
+        clearMask |= LOCAL_GL_STENCIL_BUFFER_BIT;
+
+    ForceClearFramebufferWithDefaultValues(clearMask);
+    mIsScreenCleared = true;
+}
+
+void
+WebGLContext::ForceClearFramebufferWithDefaultValues(GLbitfield mask)
 {
     MakeContextCurrent();
 
     bool initializeColorBuffer = 0 != (mask & LOCAL_GL_COLOR_BUFFER_BIT);
     bool initializeDepthBuffer = 0 != (mask & LOCAL_GL_DEPTH_BUFFER_BIT);
     bool initializeStencilBuffer = 0 != (mask & LOCAL_GL_STENCIL_BUFFER_BIT);
 
-    // fun GL fact: no need to worry about the viewport here, glViewport is just setting up a coordinates transformation,
-    // it doesn't affect glClear at all
+    // Fun GL fact: No need to worry about the viewport here, glViewport is just
+    // setting up a coordinates transformation, it doesn't affect glClear at all.
+
+#ifdef DEBUG
+    // Scope to hide our variables.
+    {
+        // Sanity-check that all our state is set properly. Otherwise, when we
+        // reset out state to what we *think* it is, we'll get it wrong.
+
+        // Dither shouldn't matter when we're clearing to {0,0,0,0}.
+        MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_SCISSOR_TEST) == mScissorTestEnabled);
+
+        realGLboolean colorWriteMask[4] = {2, 2, 2, 2};
+        GLfloat colorClearValue[4] = {-1.0f, -1.0f, -1.0f, -1.0f};
+
+        gl->fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorWriteMask);
+        gl->fGetFloatv(LOCAL_GL_COLOR_CLEAR_VALUE, colorClearValue);
+
+        MOZ_ASSERT(colorWriteMask[0] == mColorWriteMask[0] &&
+                   colorWriteMask[1] == mColorWriteMask[1] &&
+                   colorWriteMask[2] == mColorWriteMask[2] &&
+                   colorWriteMask[3] == mColorWriteMask[3]);
+        MOZ_ASSERT(colorClearValue[0] == mColorClearValue[0] &&
+                   colorClearValue[1] == mColorClearValue[1] &&
+                   colorClearValue[2] == mColorClearValue[2] &&
+                   colorClearValue[3] == mColorClearValue[3]);
+
+
+        realGLboolean depthWriteMask = 2;
+        GLfloat depthClearValue = -1.0f;
 
-    // prepare GL state for clearing
+        gl->fGetBooleanv(LOCAL_GL_DEPTH_WRITEMASK, &depthWriteMask);
+        gl->fGetFloatv(LOCAL_GL_DEPTH_CLEAR_VALUE, &depthClearValue);
+
+        MOZ_ASSERT(depthWriteMask  == mDepthWriteMask);
+        MOZ_ASSERT(depthClearValue == mDepthClearValue);
+
+
+        GLuint stencilWriteMaskFront = 0xdeadbad1;
+        GLuint stencilWriteMaskBack  = 0xdeadbad1;
+        GLuint stencilClearValue     = 0xdeadbad1;
+
+        gl->GetUIntegerv(LOCAL_GL_STENCIL_WRITEMASK,      &stencilWriteMaskFront);
+        gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_WRITEMASK, &stencilWriteMaskBack);
+        gl->GetUIntegerv(LOCAL_GL_STENCIL_CLEAR_VALUE,    &stencilClearValue);
+
+        GLuint stencilBits = 0;
+        gl->GetUIntegerv(LOCAL_GL_STENCIL_BITS, &stencilBits);
+        GLuint stencilMask = (GLuint(1) << stencilBits) - 1;
+
+        MOZ_ASSERT( ( stencilWriteMaskFront & stencilMask) ==
+                    (mStencilWriteMaskFront & stencilMask) );
+        MOZ_ASSERT( ( stencilWriteMaskBack & stencilMask) ==
+                    (mStencilWriteMaskBack & stencilMask) );
+        MOZ_ASSERT( ( stencilClearValue & stencilMask) ==
+                    (mStencilClearValue & stencilMask) );
+    }
+#endif
+
+    // Prepare GL state for clearing.
     gl->fDisable(LOCAL_GL_SCISSOR_TEST);
-    gl->fDisable(LOCAL_GL_DITHER);
 
     if (initializeColorBuffer) {
         gl->fColorMask(1, 1, 1, 1);
-        gl->fClearColor(0.f, 0.f, 0.f, 0.f);
+        gl->fClearColor(0.0f, 0.0f, 0.0f, 0.0f);
     }
 
     if (initializeDepthBuffer) {
         gl->fDepthMask(1);
         gl->fClearDepth(1.0f);
     }
 
     if (initializeStencilBuffer) {
-        gl->fStencilMask(0xffffffff);
+        // "The clear operation always uses the front stencil write mask
+        //  when clearing the stencil buffer."
+        gl->fStencilMaskSeparate(LOCAL_GL_FRONT, 0xffffffff);
+        gl->fStencilMaskSeparate(LOCAL_GL_BACK,  0xffffffff);
         gl->fClearStencil(0);
     }
 
-    // do clear
+    // Do the clear!
     gl->fClear(mask);
 
-    // restore GL state after clearing
+    // And reset!
+    if (mScissorTestEnabled)
+        gl->fEnable(LOCAL_GL_SCISSOR_TEST);
+
+    // Restore GL state after clearing.
     if (initializeColorBuffer) {
         gl->fColorMask(mColorWriteMask[0],
                        mColorWriteMask[1],
                        mColorWriteMask[2],
                        mColorWriteMask[3]);
         gl->fClearColor(mColorClearValue[0],
                         mColorClearValue[1],
                         mColorClearValue[2],
@@ -1156,51 +1229,43 @@ WebGLContext::ForceClearFramebufferWithD
 
     if (initializeDepthBuffer) {
         gl->fDepthMask(mDepthWriteMask);
         gl->fClearDepth(mDepthClearValue);
     }
 
     if (initializeStencilBuffer) {
         gl->fStencilMaskSeparate(LOCAL_GL_FRONT, mStencilWriteMaskFront);
-        gl->fStencilMaskSeparate(LOCAL_GL_BACK, mStencilWriteMaskBack);
+        gl->fStencilMaskSeparate(LOCAL_GL_BACK,  mStencilWriteMaskBack);
         gl->fClearStencil(mStencilClearValue);
     }
-
-    if (mDitherEnabled)
-        gl->fEnable(LOCAL_GL_DITHER);
-    else
-        gl->fDisable(LOCAL_GL_DITHER);
-
-    if (mScissorTestEnabled)
-        gl->fEnable(LOCAL_GL_SCISSOR_TEST);
-    else
-        gl->fDisable(LOCAL_GL_SCISSOR_TEST);
 }
 
-void
-WebGLContext::EnsureBackbufferClearedAsNeeded()
+// For an overview of how WebGL compositing works, see:
+// https://wiki.mozilla.org/Platform/GFX/WebGL/Compositing
+bool
+WebGLContext::PresentScreenBuffer()
 {
-    if (mOptions.preserveDrawingBuffer)
-        return;
-
-    NS_ABORT_IF_FALSE(!mBoundFramebuffer,
-                      "EnsureBackbufferClearedAsNeeded must not be called when a FBO is bound");
+    if (!mShouldPresent) {
+        return false;
+    }
 
-    if (mBackbufferClearingStatus != BackbufferClearingStatus::NotClearedSinceLastPresented)
-        return;
-
-    mBackbufferClearingStatus = BackbufferClearingStatus::ClearedToDefaultValues;
+    gl->MakeCurrent();
+    if (!gl->PublishFrame()) {
+        this->ForceLoseContext();
+        return false;
+    }
 
-    ForceClearFramebufferWithDefaultValues(LOCAL_GL_COLOR_BUFFER_BIT |
-                                           LOCAL_GL_DEPTH_BUFFER_BIT |
-                                           LOCAL_GL_STENCIL_BUFFER_BIT,
-                                           nsIntRect(0, 0, mWidth, mHeight));
+    if (!mOptions.preserveDrawingBuffer) {
+        ClearScreen();
+    }
 
-    Invalidate();
+    mShouldPresent = false;
+
+    return true;
 }
 
 void
 WebGLContext::DummyFramebufferOperation(const char *info)
 {
     WebGLenum status = CheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
     if (status == LOCAL_GL_FRAMEBUFFER_COMPLETE)
         return;
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -81,20 +81,16 @@ namespace dom {
 struct WebGLContextAttributes;
 struct WebGLContextAttributesInitializer;
 }
 
 struct VertexAttrib0Status {
     enum { Default, EmulatedUninitializedArray, EmulatedInitializedArray };
 };
 
-struct BackbufferClearingStatus {
-    enum { NotClearedSinceLastPresented, ClearedToDefaultValues, HasBeenDrawnTo };
-};
-
 namespace WebGLTexelConversions {
 
 /*
  * The formats that may participate, either as source or destination formats,
  * in WebGL texture conversions. This includes:
  *  - all the formats accepted by WebGL.texImage2D, e.g. RGBA4444
  *  - additional formats provided by extensions, e.g. RGB32F
  *  - additional source formats, depending on browser details, used when uploading
@@ -256,33 +252,45 @@ public:
     WebGLTexture *activeBoundTextureForTarget(WebGLenum target) {
         return target == LOCAL_GL_TEXTURE_2D ? mBound2DTextures[mActiveTexture]
                                              : mBoundCubeMapTextures[mActiveTexture];
     }
 
     already_AddRefed<CanvasLayer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
                                                  CanvasLayer *aOldLayer,
                                                  LayerManager *aManager);
+
+    // Note that 'clean' here refers to its invalidation state, not the
+    // contents of the buffer.
     void MarkContextClean() { mInvalidated = false; }
 
+    gl::GLContext* GL() const {
+        return gl;
+    }
+
+    bool IsPremultAlpha() const {
+        return mOptions.premultipliedAlpha;
+    }
+
+    bool PresentScreenBuffer();
+
     // a number that increments every time we have an event that causes
     // all context resources to be lost.
     uint32_t Generation() { return mGeneration.value(); }
 
     const WebGLRectangleObject *FramebufferRectangleObject() const;
 
-    // this is similar to GLContext::ClearSafely, but is more comprehensive
-    // (takes care of scissor, stencil write mask, dithering, viewport...)
-    // WebGL has more complex needs than GLContext as content controls GL state.
-    void ForceClearFramebufferWithDefaultValues(uint32_t mask, const nsIntRect& viewportRect);
+    // This is similar to GLContext::ClearSafely, but tries to minimize the
+    // amount of work it does.
+    // It only clears the buffers we specify, and can reset its state without
+    // first having to query anything, as WebGL knows its state at all times.
+    void ForceClearFramebufferWithDefaultValues(GLbitfield mask);
 
-    // if the preserveDrawingBuffer context option is false, we need to clear the back buffer
-    // after it's been presented to the compositor. This function does that if needed.
-    // See section 2.2 in the WebGL spec.
-    void EnsureBackbufferClearedAsNeeded();
+    // Calls ForceClearFramebufferWithDefaultValues() for the Context's 'screen'.
+    void ClearScreen();
 
     // checks for GL errors, clears any pending GL error, stores the current GL error in currentGLError,
     // and copies it into mWebGLError if it doesn't already have an error set
     void UpdateWebGLErrorAndClearGLError(GLenum *currentGLError) {
         // get and clear GL error in ALL cases
         *currentGLError = gl->GetAndClearError();
         // only store in mWebGLError if is hasn't already recorded an error
         if (!mWebGLError)
@@ -839,16 +847,18 @@ protected:
     bool mResetLayer;
     bool mOptionsFrozen;
     bool mMinCapability;
     bool mDisableExtensions;
     bool mHasRobustness;
     bool mIsMesa;
     bool mLoseContextOnHeapMinimize;
     bool mCanLoseContextInForeground;
+    bool mShouldPresent;
+    bool mIsScreenCleared;
 
     template<typename WebGLObjectType>
     void DeleteWebGLObjectsArray(nsTArray<WebGLObjectType>& array);
 
     WebGLuint mActiveTexture;
     WebGLenum mWebGLError;
 
     // whether shader validation is supported
@@ -1101,18 +1111,16 @@ protected:
     realGLboolean mColorWriteMask[4];
     realGLboolean mDepthWriteMask;
     realGLboolean mScissorTestEnabled;
     realGLboolean mDitherEnabled;
     WebGLfloat mColorClearValue[4];
     WebGLint mStencilClearValue;
     WebGLfloat mDepthClearValue;
 
-    int mBackbufferClearingStatus;
-
     nsCOMPtr<nsITimer> mContextRestorer;
     bool mAllowRestore;
     bool mContextLossTimerRunning;
     bool mDrawSinceContextLossTimerSet;
     ContextStatus mContextStatus;
     bool mContextLostErrorSet;
 
     int mAlreadyGeneratedWarnings;
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -166,17 +166,17 @@ WebGLContext::BindFramebuffer(WebGLenum 
 
     // silently ignore a deleted frame buffer
     if (wfb && wfb->IsDeleted())
         return;
 
     MakeContextCurrent();
 
     if (!wfb) {
-        gl->fBindFramebuffer(target, gl->GetOffscreenFBO());
+        gl->fBindFramebuffer(target, 0);
     } else {
         WebGLuint framebuffername = wfb->GLName();
         gl->fBindFramebuffer(target, framebuffername);
         wfb->SetHasEverBeenBound(true);
     }
 
     mBoundFramebuffer = wfb;
 }
@@ -570,42 +570,62 @@ WebGLContext::Clear(WebGLbitfield mask)
         return;
 
     MakeContextCurrent();
 
     uint32_t m = mask & (LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT | LOCAL_GL_STENCIL_BUFFER_BIT);
     if (mask != m)
         return ErrorInvalidValue("clear: invalid mask bits");
 
-    bool needClearCallHere = true;
-
     if (mBoundFramebuffer) {
         if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
             return ErrorInvalidFramebufferOperation("clear: incomplete framebuffer");
-    } else {
-        // no FBO is bound, so we are clearing the backbuffer here
-        EnsureBackbufferClearedAsNeeded();
-        bool valuesAreDefault = mColorClearValue[0] == 0.0f &&
-                                  mColorClearValue[1] == 0.0f &&
-                                  mColorClearValue[2] == 0.0f &&
-                                  mColorClearValue[3] == 0.0f &&
-                                  mDepthClearValue    == 1.0f &&
-                                  mStencilClearValue  == 0;
-        if (valuesAreDefault &&
-            mBackbufferClearingStatus == BackbufferClearingStatus::ClearedToDefaultValues)
-        {
-            needClearCallHere = false;
+
+        gl->fClear(mask);
+        return;
+    }
+
+    // Ok, we're clearing the default framebuffer/screen.
+
+    bool needsClear = true;
+    if (mIsScreenCleared) {
+        bool isClearRedundant = true;
+        if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
+            if (mColorClearValue[0] != 0.0f ||
+                mColorClearValue[1] != 0.0f ||
+                mColorClearValue[2] != 0.0f ||
+                mColorClearValue[3] != 0.0f)
+            {
+                isClearRedundant = false;
+            }
         }
-    }
-
-    if (needClearCallHere) {
+
+        if (mask & LOCAL_GL_DEPTH_BUFFER_BIT) {
+            if (mDepthClearValue != 1.0f) {
+                isClearRedundant = false;
+            }
+        }
+
+        if (mask & LOCAL_GL_DEPTH_BUFFER_BIT) {
+            if (mStencilClearValue != 0) {
+                isClearRedundant = false;
+            }
+        }
+
+        if (isClearRedundant)
+            needsClear = false;
+    }
+
+    if (needsClear) {
         gl->fClear(mask);
-        mBackbufferClearingStatus = BackbufferClearingStatus::HasBeenDrawnTo;
-        Invalidate();
-    }
+        mIsScreenCleared = false;
+    }
+
+    Invalidate();
+    mShouldPresent = true;
 }
 
 void
 WebGLContext::ClearColor(WebGLclampf r, WebGLclampf g,
                          WebGLclampf b, WebGLclampf a)
 {
     if (!IsContextStable())
         return;
@@ -810,17 +830,17 @@ WebGLContext::CopyTexImage2D(WebGLenum t
               is_pot_assuming_nonnegative(height)))
             return ErrorInvalidValue("copyTexImage2D: with level > 0, width and height must be powers of two");
     }
 
     bool texFormatRequiresAlpha = internalformat == LOCAL_GL_RGBA ||
                                     internalformat == LOCAL_GL_ALPHA ||
                                     internalformat == LOCAL_GL_LUMINANCE_ALPHA;
     bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment().HasAlpha()
-                                                 : bool(gl->ActualFormat().alpha > 0);
+                                                 : bool(gl->GetPixelFormat().alpha > 0);
     if (texFormatRequiresAlpha && !fboFormatHasAlpha)
         return ErrorInvalidOperation("copyTexImage2D: texture format requires an alpha channel "
                                      "but the framebuffer doesn't have one");
 
     if (internalformat == LOCAL_GL_DEPTH_COMPONENT ||
         internalformat == LOCAL_GL_DEPTH_STENCIL)
         return ErrorInvalidOperation("copyTexImage2D: a base internal format of DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
 
@@ -920,17 +940,17 @@ WebGLContext::CopyTexSubImage2D(WebGLenu
     if (yoffset + height > texHeight || yoffset + height < 0)
       return ErrorInvalidValue("copyTexSubImage2D: yoffset+height is too large");
 
     WebGLenum format = imageInfo.Format();
     bool texFormatRequiresAlpha = format == LOCAL_GL_RGBA ||
                                   format == LOCAL_GL_ALPHA ||
                                   format == LOCAL_GL_LUMINANCE_ALPHA;
     bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment().HasAlpha()
-                                                 : bool(gl->ActualFormat().alpha > 0);
+                                                 : bool(gl->GetPixelFormat().alpha > 0);
 
     if (texFormatRequiresAlpha && !fboFormatHasAlpha)
         return ErrorInvalidOperation("copyTexSubImage2D: texture format requires an alpha channel "
                                      "but the framebuffer doesn't have one");
 
     if (format == LOCAL_GL_DEPTH_COMPONENT ||
         format == LOCAL_GL_DEPTH_STENCIL)
         return ErrorInvalidOperation("copyTexSubImage2D: a base internal format of DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
@@ -1435,32 +1455,33 @@ WebGLContext::DrawArrays(GLenum mode, We
     if (checked_firstPlusCount.value() > maxAllowedCount)
         return ErrorInvalidOperation("drawArrays: bound vertex attribute buffers do not have sufficient size for given first and count");
 
     MakeContextCurrent();
 
     if (mBoundFramebuffer) {
         if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
             return ErrorInvalidFramebufferOperation("drawArrays: incomplete framebuffer");
-    } else {
-        EnsureBackbufferClearedAsNeeded();
     }
 
     BindFakeBlackTextures();
     if (!DoFakeVertexAttrib0(checked_firstPlusCount.value()))
         return;
 
     SetupContextLossTimer();
     gl->fDrawArrays(mode, first, count);
 
     UndoFakeVertexAttrib0();
     UnbindFakeBlackTextures();
 
-    mBackbufferClearingStatus = BackbufferClearingStatus::HasBeenDrawnTo;
-    Invalidate();
+    if (!mBoundFramebuffer) {
+        Invalidate();
+        mShouldPresent = true;
+        mIsScreenCleared = false;
+    }
 }
 
 void
 WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type,
                            WebGLintptr byteOffset)
 {
     if (!IsContextStable())
         return;
@@ -1528,32 +1549,33 @@ WebGLContext::DrawElements(WebGLenum mod
             "size for given indices from the bound element array");
     }
 
     MakeContextCurrent();
 
     if (mBoundFramebuffer) {
         if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
             return ErrorInvalidFramebufferOperation("drawElements: incomplete framebuffer");
-    } else {
-        EnsureBackbufferClearedAsNeeded();
     }
 
     BindFakeBlackTextures();
     if (!DoFakeVertexAttrib0(maxAllowedCount))
         return;
 
     SetupContextLossTimer();
     gl->fDrawElements(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset));
 
     UndoFakeVertexAttrib0();
     UnbindFakeBlackTextures();
 
-    mBackbufferClearingStatus = BackbufferClearingStatus::HasBeenDrawnTo;
-    Invalidate();
+    if (!mBoundFramebuffer) {
+        Invalidate();
+        mShouldPresent = true;
+        mIsScreenCleared = false;
+    }
 }
 
 void
 WebGLContext::Enable(WebGLenum cap)
 {
     if (!IsContextStable())
         return;
 
@@ -3327,17 +3349,17 @@ WebGLContext::ReadPixels(WebGLint x, Web
     // GL_ALPHA to readpixels currently, but we had the code written for it already.
     if (format == LOCAL_GL_ALPHA ||
         format == LOCAL_GL_RGBA)
     {
         bool needAlphaFixup;
         if (mBoundFramebuffer) {
             needAlphaFixup = !mBoundFramebuffer->ColorAttachment().HasAlpha();
         } else {
-            needAlphaFixup = gl->ActualFormat().alpha == 0;
+            needAlphaFixup = gl->GetPixelFormat().alpha == 0;
         }
 
         if (needAlphaFixup) {
             if (format == LOCAL_GL_ALPHA && type == LOCAL_GL_UNSIGNED_BYTE) {
                 // this is easy; it's an 0xff memset per row
                 uint8_t *row = static_cast<uint8_t*>(data);
                 for (GLint j = 0; j < height; ++j) {
                     memset(row, 0xff, checked_plainRowSize.value());
--- a/content/canvas/src/WebGLFramebuffer.cpp
+++ b/content/canvas/src/WebGLFramebuffer.cpp
@@ -347,17 +347,17 @@ WebGLFramebuffer::CheckAndInitializeRend
     }
 
     if (mStencilAttachment.HasUninitializedRenderbuffer() ||
         mDepthStencilAttachment.HasUninitializedRenderbuffer())
     {
         mask |= LOCAL_GL_STENCIL_BUFFER_BIT;
     }
 
-    mContext->ForceClearFramebufferWithDefaultValues(mask, nsIntRect(0, 0, rect->Width(), rect->Height()));
+    mContext->ForceClearFramebufferWithDefaultValues(mask);
 
     if (mColorAttachment.HasUninitializedRenderbuffer())
         mColorAttachment.Renderbuffer()->SetInitialized(true);
 
     if (mDepthAttachment.HasUninitializedRenderbuffer())
         mDepthAttachment.Renderbuffer()->SetInitialized(true);
 
     if (mStencilAttachment.HasUninitializedRenderbuffer())
--- a/content/canvas/test/reftest/reftest.list
+++ b/content/canvas/test/reftest/reftest.list
@@ -6,189 +6,192 @@
 pref(webgl.disabled,true)  == webgl-disable-test.html       wrapper.html?green.png
 
 # Basic WebGL tests:
 # Do we get pixels to the screen at all?
 # Try to just hit the different rendering paths here.
 # Test: {aa, alpha, preserve, readback} = 16
 == webgl-clear-test.html?nogl  wrapper.html?green.png
 
-== webgl-clear-test.html?__&_____&________  wrapper.html?green.png
-== webgl-clear-test.html?aa&_____&________  wrapper.html?green.png
-== webgl-clear-test.html?__&alpha&________  wrapper.html?green.png
-== webgl-clear-test.html?aa&alpha&________  wrapper.html?green.png
-== webgl-clear-test.html?__&_____&preserve  wrapper.html?green.png
-== webgl-clear-test.html?aa&_____&preserve  wrapper.html?green.png
-== webgl-clear-test.html?__&alpha&preserve  wrapper.html?green.png
-== webgl-clear-test.html?aa&alpha&preserve  wrapper.html?green.png
+                      == webgl-clear-test.html?__&_____&________  wrapper.html?green.png
+                      == webgl-clear-test.html?aa&_____&________  wrapper.html?green.png
+fuzzy-if(B2G,256,83)  == webgl-clear-test.html?__&alpha&________  wrapper.html?green.png
+fuzzy-if(B2G,256,83)  == webgl-clear-test.html?aa&alpha&________  wrapper.html?green.png
+                      == webgl-clear-test.html?__&_____&preserve  wrapper.html?green.png
+                      == webgl-clear-test.html?aa&_____&preserve  wrapper.html?green.png
+fuzzy-if(B2G,256,83)  == webgl-clear-test.html?__&alpha&preserve  wrapper.html?green.png
+fuzzy-if(B2G,256,83)  == webgl-clear-test.html?aa&alpha&preserve  wrapper.html?green.png
 
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-clear-test.html?readback&__&_____&________  wrapper.html?green.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-clear-test.html?readback&aa&_____&________  wrapper.html?green.png
-pref(webgl.force-layers-readback,true)                         == webgl-clear-test.html?readback&__&alpha&________  wrapper.html?green.png
-pref(webgl.force-layers-readback,true)                         == webgl-clear-test.html?readback&aa&alpha&________  wrapper.html?green.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-clear-test.html?readback&__&_____&preserve  wrapper.html?green.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-clear-test.html?readback&aa&_____&preserve  wrapper.html?green.png
-pref(webgl.force-layers-readback,true)                         == webgl-clear-test.html?readback&__&alpha&preserve  wrapper.html?green.png
-pref(webgl.force-layers-readback,true)                         == webgl-clear-test.html?readback&aa&alpha&preserve  wrapper.html?green.png
+pref(webgl.force-layers-readback,true)                       == webgl-clear-test.html?readback&__&_____&________  wrapper.html?green.png
+pref(webgl.force-layers-readback,true)                       == webgl-clear-test.html?readback&aa&_____&________  wrapper.html?green.png
+pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83)  == webgl-clear-test.html?readback&__&alpha&________  wrapper.html?green.png
+pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83)  == webgl-clear-test.html?readback&aa&alpha&________  wrapper.html?green.png
+pref(webgl.force-layers-readback,true)                       == webgl-clear-test.html?readback&__&_____&preserve  wrapper.html?green.png
+pref(webgl.force-layers-readback,true)                       == webgl-clear-test.html?readback&aa&_____&preserve  wrapper.html?green.png
+pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83)  == webgl-clear-test.html?readback&__&alpha&preserve  wrapper.html?green.png
+pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83)  == webgl-clear-test.html?readback&aa&alpha&preserve  wrapper.html?green.png
 
 # Check orientation:
 == webgl-orientation-test.html?nogl  wrapper.html?white-top-left.png
 
-== webgl-orientation-test.html?__&_____&________  wrapper.html?white-top-left.png
-== webgl-orientation-test.html?aa&_____&________  wrapper.html?white-top-left.png
-== webgl-orientation-test.html?__&alpha&________  wrapper.html?white-top-left.png
-== webgl-orientation-test.html?aa&alpha&________  wrapper.html?white-top-left.png
-== webgl-orientation-test.html?__&_____&preserve  wrapper.html?white-top-left.png
-== webgl-orientation-test.html?aa&_____&preserve  wrapper.html?white-top-left.png
-== webgl-orientation-test.html?__&alpha&preserve  wrapper.html?white-top-left.png
-== webgl-orientation-test.html?aa&alpha&preserve  wrapper.html?white-top-left.png
+                      == webgl-orientation-test.html?__&_____&________  wrapper.html?white-top-left.png
+                      == webgl-orientation-test.html?aa&_____&________  wrapper.html?white-top-left.png
+fuzzy-if(B2G,256,83)  == webgl-orientation-test.html?__&alpha&________  wrapper.html?white-top-left.png
+fuzzy-if(B2G,256,83)  == webgl-orientation-test.html?aa&alpha&________  wrapper.html?white-top-left.png
+                      == webgl-orientation-test.html?__&_____&preserve  wrapper.html?white-top-left.png
+                      == webgl-orientation-test.html?aa&_____&preserve  wrapper.html?white-top-left.png
+fuzzy-if(B2G,256,83)  == webgl-orientation-test.html?__&alpha&preserve  wrapper.html?white-top-left.png
+fuzzy-if(B2G,256,83)  == webgl-orientation-test.html?aa&alpha&preserve  wrapper.html?white-top-left.png
 
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-orientation-test.html?readback&__&_____&________  wrapper.html?white-top-left.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-orientation-test.html?readback&aa&_____&________  wrapper.html?white-top-left.png
-pref(webgl.force-layers-readback,true)                         == webgl-orientation-test.html?readback&__&alpha&________  wrapper.html?white-top-left.png
-pref(webgl.force-layers-readback,true)                         == webgl-orientation-test.html?readback&aa&alpha&________  wrapper.html?white-top-left.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-orientation-test.html?readback&__&_____&preserve  wrapper.html?white-top-left.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-orientation-test.html?readback&aa&_____&preserve  wrapper.html?white-top-left.png
-pref(webgl.force-layers-readback,true)                         == webgl-orientation-test.html?readback&__&alpha&preserve  wrapper.html?white-top-left.png
-pref(webgl.force-layers-readback,true)                         == webgl-orientation-test.html?readback&aa&alpha&preserve  wrapper.html?white-top-left.png
+pref(webgl.force-layers-readback,true)                       == webgl-orientation-test.html?readback&__&_____&________  wrapper.html?white-top-left.png
+pref(webgl.force-layers-readback,true)                       == webgl-orientation-test.html?readback&aa&_____&________  wrapper.html?white-top-left.png
+pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83)  == webgl-orientation-test.html?readback&__&alpha&________  wrapper.html?white-top-left.png
+pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83)  == webgl-orientation-test.html?readback&aa&alpha&________  wrapper.html?white-top-left.png
+pref(webgl.force-layers-readback,true)                       == webgl-orientation-test.html?readback&__&_____&preserve  wrapper.html?white-top-left.png
+pref(webgl.force-layers-readback,true)                       == webgl-orientation-test.html?readback&aa&_____&preserve  wrapper.html?white-top-left.png
+pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83)  == webgl-orientation-test.html?readback&__&alpha&preserve  wrapper.html?white-top-left.png
+pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83)  == webgl-orientation-test.html?readback&aa&alpha&preserve  wrapper.html?white-top-left.png
 
 # Does we draw the correct color in the correct places with all context creation options?
 # (Note that our context creation option matrix is 2^6 = 64)
 == webgl-color-test.html?nogl  wrapper.html?colors.png
 
-== webgl-color-test.html?__&_____&_____&_______&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&_____&_______&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&_____&_______&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&_____&_______&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&_____&depth&_______&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&depth&_______&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&depth&_______&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&depth&_______&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&_____&_____&premult&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&_____&premult&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&_____&premult&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&_____&premult&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&_____&depth&premult&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&depth&premult&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&depth&premult&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&depth&premult&________&_______  wrapper.html?colors.png
+                      == webgl-color-test.html?__&_____&_____&_______&________&_______  wrapper.html?colors.png
+                      == webgl-color-test.html?aa&_____&_____&_______&________&_______  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?__&alpha&_____&_______&________&_______  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?aa&alpha&_____&_______&________&_______  wrapper.html?colors.png
+                      == webgl-color-test.html?__&_____&depth&_______&________&_______  wrapper.html?colors.png
+                      == webgl-color-test.html?aa&_____&depth&_______&________&_______  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?__&alpha&depth&_______&________&_______  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?aa&alpha&depth&_______&________&_______  wrapper.html?colors.png
+                      == webgl-color-test.html?__&_____&_____&premult&________&_______  wrapper.html?colors.png
+                      == webgl-color-test.html?aa&_____&_____&premult&________&_______  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?__&alpha&_____&premult&________&_______  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?aa&alpha&_____&premult&________&_______  wrapper.html?colors.png
+                      == webgl-color-test.html?__&_____&depth&premult&________&_______  wrapper.html?colors.png
+                      == webgl-color-test.html?aa&_____&depth&premult&________&_______  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?__&alpha&depth&premult&________&_______  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?aa&alpha&depth&premult&________&_______  wrapper.html?colors.png
 
-== webgl-color-test.html?__&_____&_____&_______&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&_____&_______&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&_____&_______&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&_____&_______&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&_____&depth&_______&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&depth&_______&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&depth&_______&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&depth&_______&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&_____&_____&premult&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&_____&premult&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&_____&premult&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&_____&premult&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&_____&depth&premult&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&depth&premult&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&depth&premult&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&depth&premult&preserve&_______  wrapper.html?colors.png
+                      == webgl-color-test.html?__&_____&_____&_______&preserve&_______  wrapper.html?colors.png
+                      == webgl-color-test.html?aa&_____&_____&_______&preserve&_______  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?__&alpha&_____&_______&preserve&_______  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?aa&alpha&_____&_______&preserve&_______  wrapper.html?colors.png
+                      == webgl-color-test.html?__&_____&depth&_______&preserve&_______  wrapper.html?colors.png
+                      == webgl-color-test.html?aa&_____&depth&_______&preserve&_______  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?__&alpha&depth&_______&preserve&_______  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?aa&alpha&depth&_______&preserve&_______  wrapper.html?colors.png
+                      == webgl-color-test.html?__&_____&_____&premult&preserve&_______  wrapper.html?colors.png
+                      == webgl-color-test.html?aa&_____&_____&premult&preserve&_______  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?__&alpha&_____&premult&preserve&_______  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?aa&alpha&_____&premult&preserve&_______  wrapper.html?colors.png
+                      == webgl-color-test.html?__&_____&depth&premult&preserve&_______  wrapper.html?colors.png
+                      == webgl-color-test.html?aa&_____&depth&premult&preserve&_______  wrapper.html?colors.png
+fails-if(B2G)         == webgl-color-test.html?__&alpha&depth&premult&preserve&_______  wrapper.html?colors.png
+fails-if(B2G)         == webgl-color-test.html?aa&alpha&depth&premult&preserve&_______  wrapper.html?colors.png
 
-== webgl-color-test.html?__&_____&_____&_______&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&_____&_______&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&_____&_______&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&_____&_______&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&_____&depth&_______&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&depth&_______&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&depth&_______&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&depth&_______&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&_____&_____&premult&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&_____&premult&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&_____&premult&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&_____&premult&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&_____&depth&premult&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&depth&premult&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&depth&premult&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&depth&premult&________&stencil  wrapper.html?colors.png
+                      == webgl-color-test.html?__&_____&_____&_______&________&stencil  wrapper.html?colors.png
+                      == webgl-color-test.html?aa&_____&_____&_______&________&stencil  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?__&alpha&_____&_______&________&stencil  wrapper.html?colors.png
+fails-if(B2G)         == webgl-color-test.html?aa&alpha&_____&_______&________&stencil  wrapper.html?colors.png
+                      == webgl-color-test.html?__&_____&depth&_______&________&stencil  wrapper.html?colors.png
+                      == webgl-color-test.html?aa&_____&depth&_______&________&stencil  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?__&alpha&depth&_______&________&stencil  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?aa&alpha&depth&_______&________&stencil  wrapper.html?colors.png
+                      == webgl-color-test.html?__&_____&_____&premult&________&stencil  wrapper.html?colors.png
+                      == webgl-color-test.html?aa&_____&_____&premult&________&stencil  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?__&alpha&_____&premult&________&stencil  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?aa&alpha&_____&premult&________&stencil  wrapper.html?colors.png
+                      == webgl-color-test.html?__&_____&depth&premult&________&stencil  wrapper.html?colors.png
+                      == webgl-color-test.html?aa&_____&depth&premult&________&stencil  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?__&alpha&depth&premult&________&stencil  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?aa&alpha&depth&premult&________&stencil  wrapper.html?colors.png
 
-== webgl-color-test.html?__&_____&_____&_______&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&_____&_______&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&_____&_______&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&_____&_______&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&_____&depth&_______&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&depth&_______&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&depth&_______&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&depth&_______&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&_____&_____&premult&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&_____&premult&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&_____&premult&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&_____&premult&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&_____&depth&premult&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&depth&premult&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&depth&premult&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&depth&premult&preserve&stencil  wrapper.html?colors.png
+                      == webgl-color-test.html?__&_____&_____&_______&preserve&stencil  wrapper.html?colors.png
+                      == webgl-color-test.html?aa&_____&_____&_______&preserve&stencil  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?__&alpha&_____&_______&preserve&stencil  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?aa&alpha&_____&_______&preserve&stencil  wrapper.html?colors.png
+                      == webgl-color-test.html?__&_____&depth&_______&preserve&stencil  wrapper.html?colors.png
+                      == webgl-color-test.html?aa&_____&depth&_______&preserve&stencil  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?__&alpha&depth&_______&preserve&stencil  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?aa&alpha&depth&_______&preserve&stencil  wrapper.html?colors.png
+                      == webgl-color-test.html?__&_____&_____&premult&preserve&stencil  wrapper.html?colors.png
+                      == webgl-color-test.html?aa&_____&_____&premult&preserve&stencil  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?__&alpha&_____&premult&preserve&stencil  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?aa&alpha&_____&premult&preserve&stencil  wrapper.html?colors.png
+                      == webgl-color-test.html?__&_____&depth&premult&preserve&stencil  wrapper.html?colors.png
+                      == webgl-color-test.html?aa&_____&depth&premult&preserve&stencil  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?__&alpha&depth&premult&preserve&stencil  wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-test.html?aa&alpha&depth&premult&preserve&stencil  wrapper.html?colors.png
 
 
 # Check a smaller selection for readback:
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-color-test.html?readback&__&_____&________  wrapper.html?colors.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-color-test.html?readback&aa&_____&________  wrapper.html?colors.png
-pref(webgl.force-layers-readback,true)                         == webgl-color-test.html?readback&__&alpha&________  wrapper.html?colors.png
-pref(webgl.force-layers-readback,true)                         == webgl-color-test.html?readback&aa&alpha&________  wrapper.html?colors.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-color-test.html?readback&__&_____&preserve  wrapper.html?colors.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-color-test.html?readback&aa&_____&preserve  wrapper.html?colors.png
-pref(webgl.force-layers-readback,true)                         == webgl-color-test.html?readback&__&alpha&preserve  wrapper.html?colors.png
-pref(webgl.force-layers-readback,true)                         == webgl-color-test.html?readback&aa&alpha&preserve  wrapper.html?colors.png
+pref(webgl.force-layers-readback,true)                       == webgl-color-test.html?readback&__&_____&________  wrapper.html?colors.png
+pref(webgl.force-layers-readback,true)                       == webgl-color-test.html?readback&aa&_____&________  wrapper.html?colors.png
+pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83)  == webgl-color-test.html?readback&__&alpha&________  wrapper.html?colors.png
+pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83)  == webgl-color-test.html?readback&aa&alpha&________  wrapper.html?colors.png
+pref(webgl.force-layers-readback,true)                       == webgl-color-test.html?readback&__&_____&preserve  wrapper.html?colors.png
+pref(webgl.force-layers-readback,true)                       == webgl-color-test.html?readback&aa&_____&preserve  wrapper.html?colors.png
+pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83)  == webgl-color-test.html?readback&__&alpha&preserve  wrapper.html?colors.png
+pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83)  == webgl-color-test.html?readback&aa&alpha&preserve  wrapper.html?colors.png
 
 
 # Check alpha behavior:
-== webgl-color-alpha-test.html?colorVal=1.0&alphaVal=1.0&nogl        wrapper.html?colors.png
-== webgl-color-alpha-test.html?colorVal=1.0&alphaVal=1.0             wrapper.html?colors.png
-== webgl-color-alpha-test.html?colorVal=0.0&alphaVal=1.0&nogl        wrapper.html?black.png
-== webgl-color-alpha-test.html?colorVal=0.0&alphaVal=1.0             wrapper.html?black.png
+fuzzy-if(B2G,256,83)  == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=1.0&nogl        wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=1.0             wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-alpha-test.html?colorVal=0.0&alphaVal=1.0&nogl        wrapper.html?black.png
+fuzzy-if(B2G,256,83)  == webgl-color-alpha-test.html?colorVal=0.0&alphaVal=1.0             wrapper.html?black.png
 
-== webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0&nogl        wrapper.html?colors.png
-== webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0             wrapper.html?colors.png
-== webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0&alpha&nogl  wrapper.html?white.png
-== webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0&alpha       wrapper.html?white.png
+fuzzy-if(B2G,256,83)  == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0&nogl        wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0             wrapper.html?colors.png
+fuzzy-if(B2G,256,83)  == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0&alpha&nogl  wrapper.html?white.png
+fails-if(B2G)         == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0&alpha       wrapper.html?white.png
 
-fuzzy(1,65536) fuzzy-if(Android||B2G,9,65536) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=1.0&nogl  wrapper.html?half-colors.png
-fuzzy(1,65536) fuzzy-if(Android||B2G,9,65536) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=1.0       wrapper.html?half-colors.png
+fuzzy(1,65536) fuzzy-if(B2G,256,83) fuzzy-if(Android||B2G,9,65536)  == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=1.0&nogl  wrapper.html?half-colors.png
+fuzzy(1,65536) fuzzy-if(B2G,256,83) fuzzy-if(Android||B2G,9,65536)  == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=1.0       wrapper.html?half-colors.png
 
 # Test premult:
-fuzzy(1,65536) fuzzy-if(Android||B2G,9,65536)                                == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha&nogl          wrapper.html?colors-half-alpha.png
-fuzzy(1,65536) fuzzy-if(Android||B2G,9,65536)                                == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha               wrapper.html?colors-half-alpha.png
-fuzzy(1,65536) fuzzy-if(Android||B2G,9,65536)                                == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha&nogl          wrapper.html?half-colors-half-alpha.png
-fuzzy(1,65536) fuzzy-if(Android||B2G,9,65536) fails-if(cocoaWidget||Android) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha               wrapper.html?half-colors-half-alpha.png
-fuzzy(1,65536) fuzzy-if(Android||B2G,9,65536)                                == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha&premult&nogl  wrapper.html?colors-half-alpha.png
-fuzzy(1,65536) fuzzy-if(Android||B2G,9,65536)                                == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha&premult       wrapper.html?colors-half-alpha.png
+fuzzy(1,65536) fuzzy-if(B2G,256,83) fuzzy-if(Android||B2G,9,65536)                                 == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha&nogl          wrapper.html?colors-half-alpha.png
+fuzzy(1,65536) fails-if(B2G)        fuzzy-if(Android,9,65536)                                      == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha               wrapper.html?colors-half-alpha.png
+fuzzy(1,65536) fuzzy-if(B2G,256,83) fuzzy-if(Android||B2G,9,65536)                                 == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha&nogl          wrapper.html?half-colors-half-alpha.png
+fuzzy(1,65536) fails-if(B2G)        fuzzy-if(Android,9,65536) fails-if(cocoaWidget||Android)       == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha               wrapper.html?half-colors-half-alpha.png
+fuzzy(1,65536) fuzzy-if(B2G,256,83) fuzzy-if(Android||B2G,9,65536)                                 == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha&premult&nogl  wrapper.html?colors-half-alpha.png
+fuzzy(1,65536) fails-if(B2G)        fuzzy-if(Android,9,65536)                                      == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha&premult       wrapper.html?colors-half-alpha.png
 
 # Test over-bright premult:
-fuzzy(1,65536) fuzzy-if(Android||B2G,9,65536) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha&premult&nogl  wrapper.html?colors-half-alpha.png
-fuzzy(1,65536) fuzzy-if(Android||B2G,9,65536) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha&premult       wrapper.html?colors-half-alpha.png
+fuzzy(1,65536) fuzzy-if(B2G,256,83) fuzzy-if(Android||B2G,9,65536)  == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha&premult&nogl  wrapper.html?colors-half-alpha.png
+fuzzy(1,65536) fails-if(B2G)        fuzzy-if(Android,9,65536)       == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha&premult       wrapper.html?colors-half-alpha.png
 
 
 # Check for hanging framebuffer bindings:
 == webgl-hanging-fb-test.html?nogl  wrapper.html?green.png
 
-== webgl-hanging-fb-test.html       wrapper.html?green.png
-== webgl-hanging-fb-test.html?aa    wrapper.html?green.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-hanging-fb-test.html?readback     wrapper.html?green.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-hanging-fb-test.html?readback&aa  wrapper.html?green.png
+                                        == webgl-hanging-fb-test.html?__&________  wrapper.html?green.png
+                                        == webgl-hanging-fb-test.html?aa&________  wrapper.html?green.png
+pref(webgl.force-layers-readback,true)  == webgl-hanging-fb-test.html?__&readback  wrapper.html?green.png
+pref(webgl.force-layers-readback,true)  == webgl-hanging-fb-test.html?aa&readback  wrapper.html?green.png
 
-== webgl-hanging-scissor-test.html       wrapper.html?green.png
-== webgl-hanging-scissor-test.html?aa    wrapper.html?green.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-hanging-scissor-test.html?readback     wrapper.html?green.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-hanging-scissor-test.html?readback&aa  wrapper.html?green.png
+                                        == webgl-hanging-scissor-test.html?__&________  wrapper.html?green.png
+                                        == webgl-hanging-scissor-test.html?aa&________  wrapper.html?green.png
+pref(webgl.force-layers-readback,true)  == webgl-hanging-scissor-test.html?__&readback  wrapper.html?green.png
+pref(webgl.force-layers-readback,true)  == webgl-hanging-scissor-test.html?aa&readback  wrapper.html?green.png
 
 
 # Check that our experimental prefs still work:
 
 # 16bpp:
-pref(webgl.prefer-16bpp,true)                                                               == webgl-color-test.html?16bpp           wrapper.html?colors.png
-pref(webgl.prefer-16bpp,true) pref(webgl.force-layers-readback,true) fails-if(nativeFennec) == webgl-color-test.html?16bpp&readback  wrapper.html?colors.png
+skip-if(winWidget) pref(webgl.prefer-16bpp,true)                                         == webgl-color-test.html?16bpp           wrapper.html?colors.png
+skip-if(winWidget) pref(webgl.prefer-16bpp,true) pref(webgl.force-layers-readback,true)  == webgl-color-test.html?16bpp&readback  wrapper.html?colors.png
 
 # Force native GL (Windows):
 skip-if(!winWidget) pref(webgl.prefer-native-gl,true)                                == webgl-clear-test.html?native-gl        wrapper.html?green.png
 skip-if(!winWidget) pref(webgl.prefer-native-gl,true)                                == webgl-orientation-test.html?native-gl  wrapper.html?white-top-left.png
 skip-if(!winWidget) pref(webgl.prefer-native-gl,true)                                == webgl-color-test.html?native-gl        wrapper.html?colors.png
 skip-if(!winWidget) pref(webgl.prefer-native-gl,true) pref(webgl.prefer-16bpp,true)  == webgl-color-test.html?native-gl&16bpp  wrapper.html?colors.png
 
+
+# Non-WebGL Reftests!
+
 # Do we correctly handle multiple clip paths?
 != clip-multiple-paths.html clip-multiple-paths-badref.html
 
 # Bug 815648
 == stroketext-shadow.html stroketext-shadow-ref.html
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -818,21 +818,21 @@ nsGenericHTMLElement::AfterSetAttr(int32
           SetDirectionality(dir, aNotify);
           ClearHasDirAuto();
           ClearHasDirAutoSet();
           SetHasFixedDir();
         }
       } else {
         ClearHasValidDir();
         ClearHasFixedDir();
-        ClearHasDirAuto();
-        ClearHasDirAutoSet();
         if (NodeInfo()->Equals(nsGkAtoms::bdi)) {
           SetHasDirAuto();
         } else {
+          ClearHasDirAuto();
+          ClearHasDirAutoSet();
           dir = RecomputeDirectionality(this, aNotify);
         }
       }
       SetDirectionalityOnDescendants(this, dir, aNotify);
     }
   }
 
   return nsGenericHTMLElementBase::AfterSetAttr(aNamespaceID, aName,
--- a/content/media/webrtc/MediaEngineDefault.cpp
+++ b/content/media/webrtc/MediaEngineDefault.cpp
@@ -7,42 +7,42 @@
 #include "nsCOMPtr.h"
 #include "nsDOMFile.h"
 #include "nsILocalFile.h"
 #include "Layers.h"
 #include "ImageContainer.h"
 #include "ImageTypes.h"
 #include "prmem.h"
 
+#include "nsIPrefService.h"
+#include "nsIPrefBranch.h"
+
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidBridge.h"
 #include "nsISupportsUtils.h"
 #endif
 
 #define VIDEO_RATE USECS_PER_S
 #define AUDIO_RATE 16000
 
 namespace mozilla {
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(MediaEngineDefaultVideoSource, nsITimerCallback)
 /**
  * Default video source.
  */
 
-// Cannot be initialized in the class definition
-const MediaEngineVideoOptions MediaEngineDefaultVideoSource::mOpts = {
-  DEFAULT_WIDTH,
-  DEFAULT_HEIGHT,
-  DEFAULT_FPS,
-  kVideoCodecI420
-};
-
-MediaEngineDefaultVideoSource::MediaEngineDefaultVideoSource()
+MediaEngineDefaultVideoSource::MediaEngineDefaultVideoSource(int32_t aWidth,
+                                                             int32_t aHeight,
+                                                             int32_t aFPS)
   : mTimer(nullptr)
 {
+  mOpts.mWidth = aWidth;
+  mOpts.mHeight = aHeight;
+  mOpts.mMaxFPS = aFPS;
   mState = kReleased;
 }
 
 MediaEngineDefaultVideoSource::~MediaEngineDefaultVideoSource()
 {}
 
 void
 MediaEngineDefaultVideoSource::GetName(nsAString& aName)
@@ -138,34 +138,35 @@ MediaEngineDefaultVideoSource::Start(Sou
 
   nsRefPtr<layers::Image> image = mImageContainer->CreateImage(&format, 1);
   mImage = static_cast<layers::PlanarYCbCrImage*>(image.get());
 
   layers::PlanarYCbCrImage::Data data;
   // Allocate a single blank Image
   mCb = 16;
   mCr = 16;
-  AllocateSolidColorFrame(data, DEFAULT_WIDTH, DEFAULT_HEIGHT, 0x80, mCb, mCr);
+  AllocateSolidColorFrame(data, mOpts.mWidth, mOpts.mHeight, 0x80, mCb, mCr);
   // SetData copies data, so we can free the frame
   mImage->SetData(data);
   ReleaseFrame(data);
 
   // AddTrack takes ownership of segment
   VideoSegment *segment = new VideoSegment();
-  segment->AppendFrame(image.forget(), USECS_PER_S / DEFAULT_FPS, gfxIntSize(DEFAULT_WIDTH, DEFAULT_HEIGHT));
+  segment->AppendFrame(image.forget(), USECS_PER_S / mOpts.mMaxFPS,
+                       gfxIntSize(mOpts.mWidth, mOpts.mHeight));
   mSource->AddTrack(aID, VIDEO_RATE, 0, segment);
 
   // We aren't going to add any more tracks
   mSource->AdvanceKnownTracksTime(STREAM_TIME_MAX);
 
   // Remember TrackID so we can end it later
   mTrackID = aID;
 
   // Start timer for subsequent frames
-  mTimer->InitWithCallback(this, 1000 / DEFAULT_FPS, nsITimer::TYPE_REPEATING_SLACK);
+  mTimer->InitWithCallback(this, 1000 / mOpts.mMaxFPS, nsITimer::TYPE_REPEATING_SLACK);
   mState = kStarted;
 
   return NS_OK;
 }
 
 nsresult
 MediaEngineDefaultVideoSource::Stop(SourceMediaStream *aSource, TrackID aID)
 {
@@ -237,24 +238,25 @@ MediaEngineDefaultVideoSource::Notify(ns
   }
 
   // Allocate a single solid color image
   ImageFormat format = PLANAR_YCBCR;
   nsRefPtr<layers::Image> image = mImageContainer->CreateImage(&format, 1);
   nsRefPtr<layers::PlanarYCbCrImage> ycbcr_image =
       static_cast<layers::PlanarYCbCrImage*>(image.get());
   layers::PlanarYCbCrImage::Data data;
-  AllocateSolidColorFrame(data, DEFAULT_WIDTH, DEFAULT_HEIGHT, 0x80, mCb, mCr);
+  AllocateSolidColorFrame(data, mOpts.mWidth, mOpts.mHeight, 0x80, mCb, mCr);
   ycbcr_image->SetData(data);
   // SetData copies data, so we can free the frame
   ReleaseFrame(data);
 
   // AddTrack takes ownership of segment
   VideoSegment segment;
-  segment.AppendFrame(ycbcr_image.forget(), USECS_PER_S / DEFAULT_FPS, gfxIntSize(DEFAULT_WIDTH, DEFAULT_HEIGHT));
+  segment.AppendFrame(ycbcr_image.forget(), USECS_PER_S / mOpts.mMaxFPS,
+                      gfxIntSize(mOpts.mWidth, mOpts.mHeight));
   mSource->AppendToTrack(mTrackID, &segment);
 
   return NS_OK;
 }
 
 void
 MediaEngineDefaultVideoSource::NotifyPull(MediaStreamGraph* aGraph,
                                           StreamTime aDesiredTime)
@@ -339,17 +341,18 @@ MediaEngineDefaultAudioSource::Start(Sou
 
   // We aren't going to add any more tracks
   mSource->AdvanceKnownTracksTime(STREAM_TIME_MAX);
 
   // Remember TrackID so we can finish later
   mTrackID = aID;
 
   // 1 Audio frame per Video frame
-  mTimer->InitWithCallback(this, 1000 / MediaEngineDefaultVideoSource::DEFAULT_FPS, nsITimer::TYPE_REPEATING_SLACK);
+  mTimer->InitWithCallback(this, 1000 / MediaEngineDefaultVideoSource::DEFAULT_VIDEO_FPS,
+                           nsITimer::TYPE_REPEATING_SLACK);
   mState = kStarted;
 
   return NS_OK;
 }
 
 nsresult
 MediaEngineDefaultAudioSource::Stop(SourceMediaStream *aSource, TrackID aID)
 {
@@ -388,28 +391,49 @@ MediaEngineDefaultAudioSource::Notify(ns
 }
 
 void
 MediaEngineDefault::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSource> >* aVSources) {
   MutexAutoLock lock(mMutex);
   int32_t found = false;
   int32_t len = mVSources.Length();
 
+  int32_t width  = MediaEngineDefaultVideoSource::DEFAULT_VIDEO_WIDTH;
+  int32_t height = MediaEngineDefaultVideoSource::DEFAULT_VIDEO_HEIGHT;
+  int32_t fps    = MediaEngineDefaultVideoSource::DEFAULT_VIDEO_FPS;
+
+  // FIX - these should be passed in originating in prefs and/or getUserMedia constraints
+  // Bug 778801
+  nsresult rv;
+  nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
+  if (NS_SUCCEEDED(rv)) {
+    nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
+
+    if (branch) {
+      // these very rarely change
+      branch->GetIntPref("media.navigator.video.default_width", &width);
+      branch->GetIntPref("media.navigator.video.default_height", &height);
+      branch->GetIntPref("media.navigator.video.default_fps", &fps);
+    }
+  }
+
   for (int32_t i = 0; i < len; i++) {
     nsRefPtr<MediaEngineVideoSource> source = mVSources.ElementAt(i);
     aVSources->AppendElement(source);
-    if (source->IsAvailable()) {
+    const MediaEngineVideoOptions *opts = source->GetOptions();
+    if (source->IsAvailable() &&
+        opts->mWidth == width && opts->mHeight == height && opts->mMaxFPS == fps) {
       found = true;
     }
   }
 
-  // All streams are currently busy, just make a new one.
+  // All streams are currently busy (or wrong resolution), just make a new one.
   if (!found) {
     nsRefPtr<MediaEngineVideoSource> newSource =
-      new MediaEngineDefaultVideoSource();
+      new MediaEngineDefaultVideoSource(width, height, fps);
     mVSources.AppendElement(newSource);
     aVSources->AppendElement(newSource);
   }
   return;
 }
 
 void
 MediaEngineDefault::EnumerateAudioDevices(nsTArray<nsRefPtr<MediaEngineAudioSource> >* aASources) {
--- a/content/media/webrtc/MediaEngineDefault.h
+++ b/content/media/webrtc/MediaEngineDefault.h
@@ -20,24 +20,26 @@
 
 namespace mozilla {
 
 namespace layers {
 class ImageContainer;
 class PlanarYCbCrImage;
 }
 
+class MediaEngineDefault;
+
 /**
  * The default implementation of the MediaEngine interface.
  */
 class MediaEngineDefaultVideoSource : public nsITimerCallback,
                                       public MediaEngineVideoSource
 {
 public:
-  MediaEngineDefaultVideoSource();
+  MediaEngineDefaultVideoSource(int aWidth, int aHeight, int aFPS);
   ~MediaEngineDefaultVideoSource();
 
   virtual void GetName(nsAString&);
   virtual void GetUUID(nsAString&);
 
   virtual const MediaEngineVideoOptions *GetOptions();
   virtual nsresult Allocate();
   virtual nsresult Deallocate();
@@ -52,29 +54,31 @@ public:
                           SourceMediaStream *aSource,
                           TrackID aId,
                           StreamTime aDesiredTime,
                           TrackTicks &aLastEndTime) {}
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSITIMERCALLBACK
 
-  // Need something better...
-  static const int DEFAULT_WIDTH=640;
-  static const int DEFAULT_HEIGHT=480;
-  static const int DEFAULT_FPS=30;
+  static const int DEFAULT_VIDEO_FPS = 60;
+  static const int DEFAULT_VIDEO_MIN_FPS = 10;
+  static const int DEFAULT_VIDEO_WIDTH = 640;
+  static const int DEFAULT_VIDEO_HEIGHT = 480;
 
 protected:
+  friend class MediaEngineDefault;
+
   TrackID mTrackID;
   nsCOMPtr<nsITimer> mTimer;
   nsRefPtr<layers::ImageContainer> mImageContainer;
 
   SourceMediaStream* mSource;
   layers::PlanarYCbCrImage* mImage;
-  static const MediaEngineVideoOptions mOpts;
+  MediaEngineVideoOptions mOpts;
   int mCb;
   int mCr;
 };
 
 class MediaEngineDefaultAudioSource : public nsITimerCallback,
                                       public MediaEngineAudioSource
 {
 public:
--- a/content/media/webrtc/MediaEngineWebRTC.cpp
+++ b/content/media/webrtc/MediaEngineWebRTC.cpp
@@ -5,16 +5,19 @@
 #ifdef MOZ_LOGGING
 #define FORCE_PR_LOG
 #endif
 
 #if defined(PR_LOG)
 #error "This file must be #included before any IPDL-generated files or other files that #include prlog.h"
 #endif
 
+#include "nsIPrefService.h"
+#include "nsIPrefBranch.h"
+
 #include "CSFLog.h"
 #include "prenv.h"
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo*
 GetUserMediaLog()
 {
   static PRLogModuleInfo *sLog;
@@ -35,16 +38,46 @@ namespace mozilla {
 void
 MediaEngineWebRTC::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSource> >* aVSources)
 {
   webrtc::ViEBase* ptrViEBase;
   webrtc::ViECapture* ptrViECapture;
   // We spawn threads to handle gUM runnables, so we must protect the member vars
   MutexAutoLock lock(mMutex);
 
+  int32_t width  = MediaEngineWebRTCVideoSource::DEFAULT_VIDEO_WIDTH;
+  int32_t height = MediaEngineWebRTCVideoSource::DEFAULT_VIDEO_HEIGHT;
+  int32_t fps    = MediaEngineWebRTCVideoSource::DEFAULT_VIDEO_FPS;
+  int32_t minfps = MediaEngineWebRTCVideoSource::DEFAULT_VIDEO_MIN_FPS;
+
+  // FIX - these should be passed in originating in prefs and/or getUserMedia constraints
+  // Bug 778801
+  nsresult rv;
+  nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
+  if (NS_SUCCEEDED(rv)) {
+    nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
+
+    if (branch) {
+      branch->GetIntPref("media.navigator.video.default_width", &width);
+      branch->GetIntPref("media.navigator.video.default_height", &height);
+      branch->GetIntPref("media.navigator.video.default_fps", &fps);
+      branch->GetIntPref("media.navigator.video.default_min_fps", &minfps);
+    }
+  }
+  LOG(("%s: %dx%d @%dfps (min %d)", __FUNCTION__, width, height, fps, minfps));
+
+  bool changed = false;
+  if (width != mWidth || height != mHeight || fps != mFPS || minfps != mMinFPS) {
+    changed = true;
+  }
+  mWidth = width;
+  mHeight = height;
+  mFPS = fps;
+  mMinFPS = minfps;
+
   if (!mVideoEngine) {
     if (!(mVideoEngine = webrtc::VideoEngine::Create())) {
       return;
     }
   }
 
   PRLogModuleInfo *logs = GetWebRTCLogInfo();
   if (!gWebrtcTraceLoggingOn && logs && logs->level > 0) {
@@ -129,21 +162,22 @@ MediaEngineWebRTC::EnumerateVideoDevices
     if (uniqueId[0] == '\0') {
       // In case a device doesn't set uniqueId!
       strncpy(uniqueId, deviceName, sizeof(uniqueId));
 	  uniqueId[sizeof(uniqueId)-1] = '\0'; // strncpy isn't safe
     }
 
     nsRefPtr<MediaEngineWebRTCVideoSource> vSource;
     NS_ConvertUTF8toUTF16 uuid(uniqueId);
-    if (mVideoSources.Get(uuid, getter_AddRefs(vSource))) {
+    if (!changed && mVideoSources.Get(uuid, getter_AddRefs(vSource))) {
       // We've already seen this device, just append.
       aVSources->AppendElement(vSource.get());
     } else {
-      vSource = new MediaEngineWebRTCVideoSource(mVideoEngine, i);
+      vSource = new MediaEngineWebRTCVideoSource(mVideoEngine, i,
+                                                 width, height, fps, minfps);
       mVideoSources.Put(uuid, vSource); // Hashtable takes ownership.
       aVSources->AppendElement(vSource);
     }
   }
 
   ptrViEBase->Release();
   ptrViECapture->Release();
 
--- a/content/media/webrtc/MediaEngineWebRTC.h
+++ b/content/media/webrtc/MediaEngineWebRTC.h
@@ -52,32 +52,36 @@ namespace mozilla {
  * The WebRTC implementation of the MediaEngine interface.
  */
 class MediaEngineWebRTCVideoSource : public MediaEngineVideoSource,
                                      public webrtc::ExternalRenderer,
                                      public nsRunnable
 {
 public:
   static const int DEFAULT_VIDEO_FPS = 60;
-  static const int DEFAULT_MIN_VIDEO_FPS = 10;
+  static const int DEFAULT_VIDEO_MIN_FPS = 10;
+  static const int DEFAULT_VIDEO_WIDTH = 640;
+  static const int DEFAULT_VIDEO_HEIGHT = 480;
 
   // ViEExternalRenderer.
   virtual int FrameSizeChange(unsigned int, unsigned int, unsigned int);
   virtual int DeliverFrame(unsigned char*, int, uint32_t, int64_t);
 
   MediaEngineWebRTCVideoSource(webrtc::VideoEngine* aVideoEnginePtr,
-    int aIndex, int aMinFps = DEFAULT_MIN_VIDEO_FPS)
+    int aIndex,
+    int aWidth = DEFAULT_VIDEO_WIDTH, int aHeight = DEFAULT_VIDEO_HEIGHT,
+    int aFps = DEFAULT_VIDEO_FPS, int aMinFps = DEFAULT_VIDEO_MIN_FPS)
     : mVideoEngine(aVideoEnginePtr)
     , mCaptureIndex(aIndex)
     , mCapabilityChosen(false)
-    , mWidth(640)
-    , mHeight(480)
+    , mWidth(aWidth)
+    , mHeight(aHeight)
     , mLastEndTime(0)
     , mMonitor("WebRTCCamera.Monitor")
-    , mFps(DEFAULT_VIDEO_FPS)
+    , mFps(aFps)
     , mMinFps(aMinFps)
     , mInitDone(false)
     , mInSnapshotMode(false)
     , mSnapshotPath(NULL) {
     MOZ_ASSERT(aVideoEnginePtr);
     mState = kReleased;
     Init();
   }
@@ -282,16 +286,19 @@ private:
 
   webrtc::VideoEngine* mVideoEngine;
   webrtc::VoiceEngine* mVoiceEngine;
 
   // Need this to avoid unneccesary WebRTC calls while enumerating.
   bool mVideoEngineInit;
   bool mAudioEngineInit;
 
+  // the last set of selection vars for video sources
+  int mHeight, mWidth, mFPS, mMinFPS;
+
   // Store devices we've already seen in a hashtable for quick return.
   // Maps UUID to MediaEngineSource (one set for audio, one for video).
   nsRefPtrHashtable<nsStringHashKey, MediaEngineWebRTCVideoSource > mVideoSources;
   nsRefPtrHashtable<nsStringHashKey, MediaEngineWebRTCAudioSource > mAudioSources;
 };
 
 }
 
--- a/content/media/webrtc/MediaEngineWebRTCVideo.cpp
+++ b/content/media/webrtc/MediaEngineWebRTCVideo.cpp
@@ -26,16 +26,17 @@ NS_IMPL_THREADSAFE_ISUPPORTS1(MediaEngin
 
 // ViEExternalRenderer Callback.
 int
 MediaEngineWebRTCVideoSource::FrameSizeChange(
    unsigned int w, unsigned int h, unsigned int streams)
 {
   mWidth = w;
   mHeight = h;
+  LOG(("Video FrameSizeChange: %ux%u", w, h));
   return 0;
 }
 
 // ViEExternalRenderer Callback. Process every incoming frame here.
 int
 MediaEngineWebRTCVideoSource::DeliverFrame(
    unsigned char* buffer, int size, uint32_t time_stamp, int64_t render_time)
 {
@@ -77,17 +78,18 @@ MediaEngineWebRTCVideoSource::DeliverFra
   data.mPicY = 0;
   data.mPicSize = gfxIntSize(mWidth, mHeight);
   data.mStereoMode = STEREO_MODE_MONO;
 
   videoImage->SetData(data);
 
 #ifdef DEBUG
   static uint32_t frame_num = 0;
-  LOGFRAME(("frame %d; timestamp %u, render_time %lu", frame_num++, time_stamp, render_time));
+  LOGFRAME(("frame %d (%dx%d); timestamp %u, render_time %lu", frame_num++,
+            mWidth, mHeight, time_stamp, render_time));
 #endif
 
   // we don't touch anything in 'this' until here (except for snapshot,
   // which has it's own lock)
   ReentrantMonitorAutoEnter enter(mMonitor);
 
   // implicitly releases last image
   mImage = image.forget();
@@ -173,16 +175,17 @@ MediaEngineWebRTCVideoSource::ChooseCapa
         mOpts.mWidth = cap.width;
         mOpts.mHeight = cap.height;
         mOpts.mMaxFPS = cap.maxFPS;
         mCapability = cap;
         // FIXME: expose expected capture delay?
       }
     }
   }
+  LOG(("chose cap %dx%d @%dfps", mOpts.mWidth, mOpts.mHeight, mOpts.mMaxFPS));
   mCapabilityChosen = true;
 }
 
 void
 MediaEngineWebRTCVideoSource::GetName(nsAString& aName)
 {
   // mDeviceName is UTF8
   CopyUTF8toUTF16(mDeviceName, aName);
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/crashtests/719779-1.svg
@@ -0,0 +1,19 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="80" y="80" width="300" height="180" viewBox="0 0 200 120">
+
+    <defs>
+        <filter id="MyFilter" filterUnits="userSpaceOnUse" >
+            <feGaussianBlur />
+            <feOffset />
+            <feSpecularLighting >
+                <fePointLight />
+            </feSpecularLighting>
+            <feComposite />
+            <feMerge>
+                <feMergeNode />
+                <feMergeNode />
+            </feMerge>
+        </filter>
+    </defs>
+    <g transform="matrix(100,-2562303,3000,100,300,300) " filter="url(#MyFilter)"/>
+
+</svg>
--- a/content/svg/content/src/crashtests/crashtests.list
+++ b/content/svg/content/src/crashtests/crashtests.list
@@ -53,15 +53,15 @@ load 579356-1.svg
 load 579356-2.svg
 load 595608-1.svg
 load 601251-1.html
 load 601406-1.svg
 load 603145-1.svg
 load 613899-1.svg
 load 613899-2.svg
 load zero-size-image.svg
+load 719779-1.svg
 load 723441-1.html
 load 751515-1.svg
 load 761507-1.svg
 load 831561.html
 load 837450-1.svg
 load 842463-1.html
-
--- a/content/svg/content/src/nsSVGFilters.cpp
+++ b/content/svg/content/src/nsSVGFilters.cpp
@@ -4885,24 +4885,32 @@ nsSVGFELightingElement::ComputeChangeBBo
     float norm = sqrt(DOT(vec, vec)); \
     vec[0] /= norm; \
     vec[1] /= norm; \
     vec[2] /= norm; \
   PR_END_MACRO
 
 static int32_t
 Convolve3x3(const uint8_t *index, int32_t stride,
-            const int8_t kernel[3][3])
+            const int8_t kernel[3][3]
+#ifdef DEBUG
+            , const uint8_t *minData, const uint8_t *maxData
+#endif // DEBUG
+)
 {
   int32_t sum = 0;
   for (int32_t y = 0; y < 3; y++) {
     for (int32_t x = 0; x < 3; x++) {
       int8_t k = kernel[y][x];
-      if (k)
-        sum += k * index[4 * (x - 1) + stride * (y - 1)];
+      if (k) {
+        const uint8_t *valPtr = index + (4 * (x - 1) + stride * (y - 1));
+        NS_ASSERTION(valPtr >= minData, "out of bounds read (before buffer)");
+        NS_ASSERTION(valPtr < maxData,  "out of bounds read (after buffer)");
+        sum += k * (*valPtr);
+      }
     }
   }
   return sum;
 }
 
 static void
 GenerateNormal(float *N, const uint8_t *data, int32_t stride,
                int32_t surfaceWidth, int32_t surfaceHeight,
@@ -4961,20 +4969,40 @@ GenerateNormal(float *N, const uint8_t *
   } else if (y == surfaceHeight - 1) {
     yflag = 2;
   } else {
     yflag = 1;
   }
 
   const uint8_t *index = data + y * stride + 4 * x + GFX_ARGB32_OFFSET_A;
 
+#ifdef DEBUG
+  // For sanity-checking, to be sure we're not reading outside source buffer:
+  const uint8_t* minData = data;
+  const uint8_t* maxData = minData + (surfaceHeight * surfaceWidth * stride);
+
+  // We'll sanity-check each value we read inside of Convolve3x3, but we
+  // might as well ensure we're passing it a valid pointer to start with, too:
+  NS_ASSERTION(index >= minData, "index points before buffer start");
+  NS_ASSERTION(index < maxData, "index points after buffer end");
+#endif // DEBUG
+
   N[0] = -surfaceScale * FACTORx[yflag][xflag] *
-    Convolve3x3(index, stride, Kx[yflag][xflag]);
+    Convolve3x3(index, stride, Kx[yflag][xflag]
+#ifdef DEBUG
+                , minData, maxData
+#endif // DEBUG
+                );
+
   N[1] = -surfaceScale * FACTORy[yflag][xflag] *
-    Convolve3x3(index, stride, Ky[yflag][xflag]);
+    Convolve3x3(index, stride, Ky[yflag][xflag]
+#ifdef DEBUG
+                , minData, maxData
+#endif // DEBUG
+                );
   N[2] = 255;
   NORMALIZE(N);
 }
 
 nsresult
 nsSVGFELightingElement::Filter(nsSVGFilterInstance *instance,
                                const nsTArray<const Image*>& aSources,
                                const Image* aTarget,
--- a/dom/base/nsHistory.cpp
+++ b/dom/base/nsHistory.cpp
@@ -59,16 +59,20 @@ NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(nsHistory)
 NS_IMPL_RELEASE(nsHistory)
 
 
 NS_IMETHODIMP
 nsHistory::GetLength(int32_t* aLength)
 {
+  nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
+  if (!win || !nsContentUtils::CanCallerAccess(win->GetOuterWindow()))
+    return NS_ERROR_DOM_SECURITY_ERR;
+
   nsCOMPtr<nsISHistory>   sHistory;
 
   // Get session History from docshell
   GetSessionHistoryFromDocShell(GetDocShell(), getter_AddRefs(sHistory));
   NS_ENSURE_TRUE(sHistory, NS_ERROR_FAILURE);
   return sHistory->GetCount(aLength);
 }
 
@@ -166,48 +170,60 @@ nsHistory::GetNext(nsAString& aNext)
   CopyUTF8toUTF16(nextURL, aNext);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHistory::Back()
 {
+  nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
+  if (!win || !nsContentUtils::CanCallerAccess(win->GetOuterWindow()))
+    return NS_ERROR_DOM_SECURITY_ERR;
+
   nsCOMPtr<nsISHistory>  sHistory;
 
   GetSessionHistoryFromDocShell(GetDocShell(), getter_AddRefs(sHistory));
   NS_ENSURE_TRUE(sHistory, NS_ERROR_FAILURE);
 
   //QI SHistory to WebNavigation
   nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(sHistory));
   NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
   webNav->GoBack();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHistory::Forward()
 {
+  nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
+  if (!win || !nsContentUtils::CanCallerAccess(win->GetOuterWindow()))
+    return NS_ERROR_DOM_SECURITY_ERR;
+
   nsCOMPtr<nsISHistory>  sHistory;
 
   GetSessionHistoryFromDocShell(GetDocShell(), getter_AddRefs(sHistory));
   NS_ENSURE_TRUE(sHistory, NS_ERROR_FAILURE);
 
   //QI SHistory to WebNavigation
   nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(sHistory));
   NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
   webNav->GoForward();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHistory::Go(int32_t aDelta)
 {
+  nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
+  if (!win || !nsContentUtils::CanCallerAccess(win->GetOuterWindow()))
+    return NS_ERROR_DOM_SECURITY_ERR;
+
   if (aDelta == 0) {
     nsCOMPtr<nsPIDOMWindow> window(do_GetInterface(GetDocShell()));
 
     if (window && window->IsHandlingResizeEvent()) {
       // history.go(0) (aka location.reload()) was called on a window
       // that is handling a resize event. Sites do this since Netscape
       // 4.x needed it, but we don't, and it's a horrible experience
       // for nothing.  In stead of reloading the page, just clear
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -3583,105 +3583,77 @@ nsJSRuntime::Init()
   JS_SetStructuredCloneCallbacks(sRuntime, &cloneCallbacks);
 
   static js::DOMCallbacks DOMcallbacks = {
     InstanceClassHasProtoAtDepth
   };
   SetDOMCallbacks(sRuntime, &DOMcallbacks);
 
   // Set these global xpconnect options...
-  Preferences::RegisterCallback(MaxScriptRunTimePrefChangedCallback,
-                                "dom.max_script_run_time");
-  MaxScriptRunTimePrefChangedCallback("dom.max_script_run_time", nullptr);
-
-  Preferences::RegisterCallback(MaxScriptRunTimePrefChangedCallback,
-                                "dom.max_chrome_script_run_time");
-  MaxScriptRunTimePrefChangedCallback("dom.max_chrome_script_run_time",
-                                      nullptr);
-
-  Preferences::RegisterCallback(ReportAllJSExceptionsPrefChangedCallback,
-                                "dom.report_all_js_exceptions");
-  ReportAllJSExceptionsPrefChangedCallback("dom.report_all_js_exceptions",
-                                           nullptr);
-
-  Preferences::RegisterCallback(SetMemoryHighWaterMarkPrefChangedCallback,
-                                "javascript.options.mem.high_water_mark");
-  SetMemoryHighWaterMarkPrefChangedCallback("javascript.options.mem.high_water_mark",
-                                            nullptr);
-
-  Preferences::RegisterCallback(SetMemoryMaxPrefChangedCallback,
-                                "javascript.options.mem.max");
-  SetMemoryMaxPrefChangedCallback("javascript.options.mem.max",
-                                  nullptr);
-
-  Preferences::RegisterCallback(SetMemoryGCModePrefChangedCallback,
-                                "javascript.options.mem.gc_per_compartment");
-  SetMemoryGCModePrefChangedCallback("javascript.options.mem.gc_per_compartment",
-                                     nullptr);
-
-  Preferences::RegisterCallback(SetMemoryGCModePrefChangedCallback,
-                                "javascript.options.mem.gc_incremental");
-  SetMemoryGCModePrefChangedCallback("javascript.options.mem.gc_incremental",
-                                     nullptr);
-
-  Preferences::RegisterCallback(SetMemoryGCSliceTimePrefChangedCallback,
-                                "javascript.options.mem.gc_incremental_slice_ms");
-  SetMemoryGCSliceTimePrefChangedCallback("javascript.options.mem.gc_incremental_slice_ms",
-                                          nullptr);
-
-  Preferences::RegisterCallback(SetMemoryGCPrefChangedCallback,
-                                "javascript.options.mem.gc_high_frequency_time_limit_ms");
-  SetMemoryGCPrefChangedCallback("javascript.options.mem.gc_high_frequency_time_limit_ms",
-                                 (void *)JSGC_HIGH_FREQUENCY_TIME_LIMIT);
-
-  Preferences::RegisterCallback(SetMemoryGCDynamicMarkSlicePrefChangedCallback,
-                                "javascript.options.mem.gc_dynamic_mark_slice");
-  SetMemoryGCDynamicMarkSlicePrefChangedCallback("javascript.options.mem.gc_dynamic_mark_slice",
-                                                 nullptr);
-
-  Preferences::RegisterCallback(SetMemoryGCDynamicHeapGrowthPrefChangedCallback,
-                                "javascript.options.mem.gc_dynamic_heap_growth");
-  SetMemoryGCDynamicHeapGrowthPrefChangedCallback("javascript.options.mem.gc_dynamic_heap_growth",
-                                                  nullptr);
-
-  Preferences::RegisterCallback(SetMemoryGCPrefChangedCallback,
-                                "javascript.options.mem.gc_low_frequency_heap_growth");
-  SetMemoryGCPrefChangedCallback("javascript.options.mem.gc_low_frequency_heap_growth",
-                                 (void *)JSGC_LOW_FREQUENCY_HEAP_GROWTH);
-
-  Preferences::RegisterCallback(SetMemoryGCPrefChangedCallback,
-                                "javascript.options.mem.gc_high_frequency_heap_growth_min");
-  SetMemoryGCPrefChangedCallback("javascript.options.mem.gc_high_frequency_heap_growth_min",
-                                 (void *)JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN);
-
-  Preferences::RegisterCallback(SetMemoryGCPrefChangedCallback,
-                                "javascript.options.mem.gc_high_frequency_heap_growth_max");
-  SetMemoryGCPrefChangedCallback("javascript.options.mem.gc_high_frequency_heap_growth_max",
-                                 (void *)JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX);
-
-  Preferences::RegisterCallback(SetMemoryGCPrefChangedCallback,
-                                "javascript.options.mem.gc_high_frequency_low_limit_mb");
-  SetMemoryGCPrefChangedCallback("javascript.options.mem.gc_high_frequency_low_limit_mb",
-                                 (void *)JSGC_HIGH_FREQUENCY_LOW_LIMIT);
-
-  Preferences::RegisterCallback(SetMemoryGCPrefChangedCallback,
-                                "javascript.options.mem.gc_high_frequency_high_limit_mb");
-  SetMemoryGCPrefChangedCallback("javascript.options.mem.gc_high_frequency_high_limit_mb",
-                                 (void *)JSGC_HIGH_FREQUENCY_HIGH_LIMIT);
-
-  Preferences::RegisterCallback(SetMemoryGCPrefChangedCallback,
-                                "javascript.options.mem.analysis_purge_mb",
-                                (void *)JSGC_ANALYSIS_PURGE_TRIGGER);
-  SetMemoryGCPrefChangedCallback("javascript.options.mem.analysis_purge_mb",
-                                 (void *)JSGC_ANALYSIS_PURGE_TRIGGER);
-
-  Preferences::RegisterCallback(SetMemoryGCPrefChangedCallback,
-                               "javascript.options.mem.gc_allocation_threshold_mb");
-  SetMemoryGCPrefChangedCallback("javascript.options.mem.gc_allocation_threshold_mb",
-                                (void *)JSGC_ALLOCATION_THRESHOLD);
+  Preferences::RegisterCallbackAndCall(MaxScriptRunTimePrefChangedCallback,
+                                       "dom.max_script_run_time");
+
+  Preferences::RegisterCallbackAndCall(MaxScriptRunTimePrefChangedCallback,
+                                       "dom.max_chrome_script_run_time");
+
+  Preferences::RegisterCallbackAndCall(ReportAllJSExceptionsPrefChangedCallback,
+                                       "dom.report_all_js_exceptions");
+
+  Preferences::RegisterCallbackAndCall(SetMemoryHighWaterMarkPrefChangedCallback,
+                                       "javascript.options.mem.high_water_mark");
+
+  Preferences::RegisterCallbackAndCall(SetMemoryMaxPrefChangedCallback,
+                                       "javascript.options.mem.max");
+
+  Preferences::RegisterCallbackAndCall(SetMemoryGCModePrefChangedCallback,
+                                       "javascript.options.mem.gc_per_compartment");
+
+  Preferences::RegisterCallbackAndCall(SetMemoryGCModePrefChangedCallback,
+                                       "javascript.options.mem.gc_incremental");
+
+  Preferences::RegisterCallbackAndCall(SetMemoryGCSliceTimePrefChangedCallback,
+                                       "javascript.options.mem.gc_incremental_slice_ms");
+
+  Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback,
+                                       "javascript.options.mem.gc_high_frequency_time_limit_ms",
+                                       (void *)JSGC_HIGH_FREQUENCY_TIME_LIMIT);
+
+  Preferences::RegisterCallbackAndCall(SetMemoryGCDynamicMarkSlicePrefChangedCallback,
+                                       "javascript.options.mem.gc_dynamic_mark_slice");
+
+  Preferences::RegisterCallbackAndCall(SetMemoryGCDynamicHeapGrowthPrefChangedCallback,
+                                       "javascript.options.mem.gc_dynamic_heap_growth");
+
+  Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback,
+                                       "javascript.options.mem.gc_low_frequency_heap_growth",
+                                       (void *)JSGC_LOW_FREQUENCY_HEAP_GROWTH);
+
+  Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback,
+                                       "javascript.options.mem.gc_high_frequency_heap_growth_min",
+                                       (void *)JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN);
+
+  Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback,
+                                       "javascript.options.mem.gc_high_frequency_heap_growth_max",
+                                       (void *)JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX);
+
+  Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback,
+                                       "javascript.options.mem.gc_high_frequency_low_limit_mb",
+                                       (void *)JSGC_HIGH_FREQUENCY_LOW_LIMIT);
+
+  Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback,
+                                       "javascript.options.mem.gc_high_frequency_high_limit_mb",
+                                       (void *)JSGC_HIGH_FREQUENCY_HIGH_LIMIT);
+
+  Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback,
+                                       "javascript.options.mem.analysis_purge_mb",
+                                       (void *)JSGC_ANALYSIS_PURGE_TRIGGER);
+
+  Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback,
+                                       "javascript.options.mem.gc_allocation_threshold_mb",
+                                       (void *)JSGC_ALLOCATION_THRESHOLD);
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (!obs)
     return NS_ERROR_FAILURE;
 
   Preferences::AddBoolVarCache(&sGCOnMemoryPressure,
                                "javascript.options.gc_on_memory_pressure",
                                true);
 
--- a/dom/bindings/test/test_integers.html
+++ b/dom/bindings/test/test_integers.html
@@ -18,17 +18,23 @@
     // ints edge cases.
     try {
       var gl = $("c").getContext("experimental-webgl");
     } catch (ex) {
       // No WebGL support on MacOS 10.5.  Just skip this test
       todo(false, "WebGL not supported");
       return;
     }
-    is(gl.getError(), 0, "Should not start in an error state");
+    var error = gl.getError()
+
+    // on the b2g emulator we get GL_INVALID_FRAMEBUFFER_OPERATION
+    if (error == 0x0506) // GL_INVALID_FRAMEBUFFER_OPERATION
+        return;
+
+    is(error, 0, "Should not start in an error state");
 
     var b = gl.createBuffer();
     gl.bindBuffer(gl.ARRAY_BUFFER, b);
 
     var a = new Float32Array(1);
     gl.bufferData(gl.ARRAY_BUFFER, a, gl.STATIC_DRAW);
 
     gl.bufferSubData(gl.ARRAY_BUFFER, arg, a);
--- a/dom/contacts/fallback/ContactService.jsm
+++ b/dom/contacts/fallback/ContactService.jsm
@@ -205,18 +205,20 @@ this.DOMContactManager = {
         }
         if (DEBUG) debug("Register!");
         if (this._children.indexOf(mm) == -1) {
           this._children.push(mm);
         }
         break;
       case "child-process-shutdown":
         if (DEBUG) debug("Unregister");
-        this._db.releaseCursors(this._liveCursors[mm]);
-        delete this._liveCursors[mm];
+        if (this._liveCursors[mm]) {
+          this._db.releaseCursors(this._liveCursors[mm]);
+          delete this._liveCursors[mm];
+        }
         let index = this._children.indexOf(mm);
         if (index != -1) {
           if (DEBUG) debug("Unregister index: " + index);
           this._children.splice(index, 1);
         }
         break;
       default:
         if (DEBUG) debug("WRONG MESSAGE NAME: " + aMessage.name);
--- a/dom/icc/interfaces/SimToolKit.idl
+++ b/dom/icc/interfaces/SimToolKit.idl
@@ -11,16 +11,23 @@ dictionary MozStkTextMessage
   /**
    * Text String.
    *
    * @see TS 11.14, clause 12.15, Text String.
    */
   DOMString text;
 
   /**
+   * The length of time for which the ME shall display the dialog.
+   *
+   * @see MozStkDuration
+   */
+  jsval duration;
+
+  /**
    * Indicate this text message is high priority or normal priority.
    *
    * @see TS 11.14, clause 12.6, Command Qualifier, Display Text, bit 1.
    *
    * High priority text shall be displayed on the screen immediately, except if
    * there is a conflict of priority level of alerting such as incoming calls
    * or a low battery warning. In that situation, the resolution is left to
    * the terminal. If the command is rejected in spite of the high priority,
@@ -244,16 +251,23 @@ dictionary MozStkSetUpCall
 
   /**
    * The text message used in call set up phase.
    *
    * @see MozStkTextMessage for the detail specification of
    *      callMessage.
    */
   jsval callMessage;
+
+  /**
+   * The Optional maximum duration for the redial mechanism.
+   * The time elapsed since the first call set-up attempt has exceeded the duration
+   * requested by the UICC, the redial mechanism is terminated.
+   */
+  jsval duration;
 };
 
 dictionary MozStkSetUpEventList
 {
   /**
    * The list of events that needs to provide details to ICC when they happen.
    * When this valus is null, means an indication to remove the existing list
    * of events in ME.
--- a/dom/icc/tests/marionette/test_stk_proactive_command.js
+++ b/dom/icc/tests/marionette/test_stk_proactive_command.js
@@ -146,16 +146,36 @@ function testSetupCall(cmd) {
   is(cmd.commandQualifier, 0x04);
   is(cmd.options.address, "012340123456,1,2");
   is(cmd.options.confirmMessage, "Disconnect");
   is(cmd.options.callMessage, "Message");
 
   runNextTest();
 }
 
+function testDisplayTextVariableTimeOut(cmd) {
+  log("STK CMD " + JSON.stringify(cmd));
+  is(cmd.typeOfCommand, icc.STK_CMD_DISPLAY_TEXT);
+  is(cmd.commandNumber, 0x01);
+  is(cmd.options.duration.timeUnit, icc.STK_TIME_UNIT_SECOND);
+  is(cmd.options.duration.timeInterval, 0x0A);
+
+  runNextTest();
+}
+
+function testSetUpCallVariableTimeOut(cmd) {
+  log("STK CMD " + JSON.stringify(cmd));
+  is(cmd.typeOfCommand, icc.STK_CMD_SET_UP_CALL);
+  is(cmd.commandNumber, 0x01);
+  is(cmd.options.duration.timeUnit, icc.STK_TIME_UNIT_SECOND);
+  is(cmd.options.duration.timeInterval, 0x0A);
+
+  runNextTest();
+}
+
 let tests = [
   {command: "d0288103012180820281020d1d00d3309bfc06c95c301aa8e80259c3ec34b9ac07c9602f58ed159bb940",
    func: testDisplayTextGsm7BitEncoding},
   {command: "d009810301260082028182",
    func: testLocalInfoLocation},
   {command: "d009810301260182028182",
    func: testLocalInfoImei},
   {command: "d009810301260382028182",
@@ -175,16 +195,20 @@ let tests = [
   {command: "d00c810301270182028182a40104",
    func: testTimerManagementDeactivate},
   {command: "d00c810301270282028182a40108",
    func: testTimerManagementGetCurrentValue},
   {command: "d029810301100482028182050a446973636f6e6e6563748609811032042143651c2c05074d657373616765",
    func: testSetupCall},
   {command: "D0198103012200820281828D0A04456E74657220222B228402010A",
    func: testGetInKeyVariableTimeout},
+  {command: "d0198103012180820281028D0A043130205365636F6E648402010A",
+   func: testDisplayTextVariableTimeOut},
+  {command: "d02281030110008202818385084E6F7420627573798609911032042143651C2C8402010A",
+   func: testSetUpCallVariableTimeOut},
 ];
 
 let pendingEmulatorCmdCount = 0;
 function sendStkPduToEmulator(cmd, func) {
   ++pendingEmulatorCmdCount;
 
   runEmulatorCmd(cmd, function (result) {
     --pendingEmulatorCmdCount;
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -2055,17 +2055,18 @@ TabChild::InitTabChildGlobal(FrameScript
 
     nsRefPtr<TabChildGlobal> scope = new TabChildGlobal(this);
     NS_ENSURE_TRUE(scope, false);
 
     mTabChildGlobal = scope;
 
     nsISupports* scopeSupports = NS_ISUPPORTS_CAST(nsIDOMEventTarget*, scope);
 
-    NS_ENSURE_TRUE(InitTabChildGlobalInternal(scopeSupports), false); 
+    NS_NAMED_LITERAL_CSTRING(globalId, "outOfProcessTabChildGlobal");
+    NS_ENSURE_TRUE(InitTabChildGlobalInternal(scopeSupports, globalId), false);
 
     scope->Init();
 
     nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(chromeHandler);
     NS_ENSURE_TRUE(root, false);
     root->SetParentTarget(scope);
 
     chromeHandler->AddEventListener(NS_LITERAL_STRING("DOMMetaAdded"), this, false);
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -608,24 +608,28 @@ public:
       count = videoSources.Length();
       if (count <= 0) {
         NS_DispatchToMainThread(new ErrorCallbackRunnable(
           mSuccess, mError, NS_LITERAL_STRING("NO_DEVICES_FOUND"), mWindowID
         ));
         return NS_ERROR_FAILURE;
       }
 
+      /**
+       * We're allowing multiple tabs to access the same camera for parity
+       * with Chrome.  See bug 811757 for some of the issues surrounding
+       * this decision.  To disallow, we'd filter by IsAvailable() as we used
+       * to.
+       */
       // Pick the first available device.
       for (uint32_t i = 0; i < count; i++) {
         nsRefPtr<MediaEngineVideoSource> vSource = videoSources[i];
-        if (vSource->IsAvailable()) {
-          found = true;
-          mVideoDevice = new MediaDevice(videoSources[i]);
-          break;
-        }
+        found = true;
+        mVideoDevice = new MediaDevice(videoSources[i]);
+        break;
       }
 
       if (!found) {
         NS_DispatchToMainThread(new ErrorCallbackRunnable(
           mSuccess, mError, NS_LITERAL_STRING("HARDWARE_UNAVAILABLE"), mWindowID
         ));
         return NS_ERROR_FAILURE;
       }
@@ -642,21 +646,19 @@ public:
         NS_DispatchToMainThread(new ErrorCallbackRunnable(
           mSuccess, mError, NS_LITERAL_STRING("NO_DEVICES_FOUND"), mWindowID
         ));
         return NS_ERROR_FAILURE;
       }
 
       for (uint32_t i = 0; i < count; i++) {
         nsRefPtr<MediaEngineAudioSource> aSource = audioSources[i];
-        if (aSource->IsAvailable()) {
-          found = true;
-          mAudioDevice = new MediaDevice(audioSources[i]);
-          break;
-        }
+        found = true;
+        mAudioDevice = new MediaDevice(audioSources[i]);
+        break;
       }
 
       if (!found) {
         NS_DispatchToMainThread(new ErrorCallbackRunnable(
           mSuccess, mError, NS_LITERAL_STRING("HARDWARE_UNAVAILABLE"), mWindowID
         ));
         return NS_ERROR_FAILURE;
       }
--- a/dom/network/interfaces/nsIDOMMobileConnection.idl
+++ b/dom/network/interfaces/nsIDOMMobileConnection.idl
@@ -99,17 +99,18 @@ interface nsIDOMMozMobileConnection : ns
    * 'IllegalSIMorME', or 'GenericFailure'
    */
   nsIDOMDOMRequest selectNetworkAutomatically();
 
   /**
    * Find out about the status of an ICC lock (e.g. the PIN lock).
    *
    * @param lockType
-   *        Identifies the lock type, e.g. "pin" for the PIN lock.
+   *        Identifies the lock type, e.g. "pin" for the PIN lock, "fdn" for
+   *        the FDN lock.
    *
    * @return a DOM Request.
    *         The request's result will be an object containing
    *         information about the specified lock's status,
    *         e.g. {lockType: "pin", enabled: true}.
    */
   nsIDOMDOMRequest getCardLock(in DOMString lockType);
 
@@ -146,72 +147,78 @@ interface nsIDOMMozMobileConnection : ns
    *         information about the unlock operation.
    *
    * Examples:
    *
    * (1) Unlocking failed:
    *
    *     {
    *       lockType:   "pin",
-   *       result:     false,
+   *       success:    false,
    *       retryCount: 2
    *     }
    *
    * (2) Unlocking succeeded:
    *
    *     {
    *       lockType:  "pin",
-   *       result:    true
+   *       success:   true
    *     }
    */
   nsIDOMDOMRequest unlockCardLock(in jsval info);
 
   /**
    * Modify the state of a card lock.
    *
    * @param info
    *        An object containing information about the lock and
    *        how to modify its state. At a minimum, this object
    *        must have a "lockType" attribute which specifies the
    *        type of lock, e.g. "pin" for the PIN lock. Other
    *        attributes are dependent on the lock type.
    *
    * Examples:
    *
-   * (1) Disabling the PIN lock:
+   * (1a) Disabling the PIN lock:
    *
    *   setCardLock({lockType: "pin",
    *                pin: "...",
    *                enabled: false});
    *
+   * (1b) Disabling the FDN lock:
+   *
+   *   setCardLock({lockType: "fdn",
+   *                pin2: "...",
+   *                enabled: false});
+   *
    * (2) Changing the PIN:
    *
    *   setCardLock({lockType: "pin",
    *                pin: "...",
    *                newPin: "..."});
    *
    * @return a nsIDOMDOMRequest.
    *         The request's result will be an object containing
    *         information about the operation.
    *
    * Examples:
    *
    * (1) Enabling/Disabling card lock failed or change card lock failed.
    *
    *     {
    *       lockType: "pin",
-   *       result: false,
+   *       success: false,
    *       retryCount: 2
    *     }
    *
    * (2) Enabling/Disabling card lock succeed or change card lock succeed.
    *
    *     {
    *       lockType: "pin",
-   *       result: true
+   *       success: true
    *     }
    */
   nsIDOMDOMRequest setCardLock(in jsval info);
 
   /**
    * Send a MMI message.
    *
    * @param mmi
--- a/dom/phonenumberutils/PhoneNumber.jsm
+++ b/dom/phonenumberutils/PhoneNumber.jsm
@@ -9,24 +9,107 @@
 this.EXPORTED_SYMBOLS = ["PhoneNumber"];
 
 Components.utils.import("resource://gre/modules/PhoneNumberMetaData.jsm");
 
 this.PhoneNumber = (function (dataBase) {
   // Use strict in our context only - users might not want it
   'use strict';
 
+  // The minimum length of the national significant number.
+  const MIN_LENGTH_FOR_NSN = 2;
+
+  const STAR_SIGN = "*";
   const UNICODE_DIGITS = /[\uFF10-\uFF19\u0660-\u0669\u06F0-\u06F9]/g;
-  const ALPHA_CHARS = /[a-zA-Z]/g;
   const NON_ALPHA_CHARS = /[^a-zA-Z]/g;
   const NON_DIALABLE_CHARS = /[^,#+\*\d]/g;
-  const PLUS_CHARS = /^[+\uFF0B]+/g;
+  const PLUS_CHARS = "+\uFF0B";
   const BACKSLASH = /\\/g;
   const SPLIT_FIRST_GROUP = /^(\d+)(.*)$/;
 
+  /**
+   * Regular expression of acceptable punctuation found in phone numbers. This
+   * excludes punctuation found as a leading character only. This consists of
+   * dash characters, white space characters, full stops, slashes, square
+   * brackets, parentheses and tildes. It also includes the letter 'x' as that
+   * is found as a placeholder for carrier information in some phone numbers.
+   * Full-width variants are also present.
+   */
+  const VALID_PUNCTUATION = "-x\u2010-\u2015\u2212\u30FC\uFF0D-\uFF0F \u00A0"
+                          + "\u200B\u2060\u3000()\uFF08\uFF09\uFF3B\uFF3D."
+                          + "\\[\\]/~\u2053\u223C\uFF5E";
+  const VALID_DIGITS = "0-9\uFF10-\uFF19\u0660-\u0669\u06F0-\u06F9";
+  const VALID_ALPHA = "a-zA-Z";
+
+  /**
+   * Regular expression of viable phone numbers. This is location independent.
+   * Checks we have at least three leading digits, and only valid punctuation,
+   * alpha characters and digits in the phone number. Does not include extension
+   * data. The symbol 'x' is allowed here as valid punctuation since it is often
+   * used as a placeholder for carrier codes, for example in Brazilian phone
+   * numbers. We also allow multiple '+' characters at the start.
+   * Corresponds to the following:
+   * [digits]{minLengthNsn}|
+   * plus_sign*
+   * (([punctuation]|[star])*[digits]){3,}([punctuation]|[star]|[digits]|[alpha])*
+   *
+   * The first reg-ex is to allow short numbers (two digits long) to be parsed
+   * if they are entered as "15" etc, but only if there is no punctuation in
+   * them. The second expression restricts the number of digits to three or
+   * more, but then allows them to be in international form, and to have
+   * alpha-characters and punctuation. We split up the two reg-exes here and
+   * combine them when creating the reg-ex VALID_PHONE_NUMBER_PATTERN itself so
+   * we can prefix it with ^ and append $ to each branch.
+   *
+   * Note VALID_PUNCTUATION starts with a -, so must be the first in the range.
+   */
+  const MIN_LENGTH_PHONE_NUMBER
+    = "[" + VALID_DIGITS + "]{" + MIN_LENGTH_FOR_NSN + "}";
+  const VALID_PHONE_NUMBER
+    = "[" + PLUS_CHARS + "]*"
+    + "(?:[" + VALID_PUNCTUATION + STAR_SIGN + "]*" + "[" + VALID_DIGITS + "]){3,}"
+    + "[" + VALID_PUNCTUATION + STAR_SIGN + VALID_ALPHA + VALID_DIGITS + "]*";
+
+  /**
+   * Pattern to capture digits used in an extension.
+   * Places a maximum length of '7' for an extension.
+   */
+  const CAPTURING_EXTN_DIGITS = "([" + VALID_DIGITS + "]{1,7})";
+
+  /**
+   * Regexp of all possible ways to write extensions, for use when parsing. This
+   * will be run as a case-insensitive regexp match. Wide character versions are
+   * also provided after each ASCII version. There are three regular expressions
+   * here. The first covers RFC 3966 format, where the extension is added using
+   * ';ext='. The second more generic one starts with optional white space and
+   * ends with an optional full stop (.), followed by zero or more spaces/tabs and
+   * then the numbers themselves. The other one covers the special case of
+   * American numbers where the extension is written with a hash at the end, such
+   * as '- 503#'. Note that the only capturing groups should be around the digits
+   * that you want to capture as part of the extension, or else parsing will fail!
+   * We allow two options for representing the accented o - the character itself,
+   * and one in the unicode decomposed form with the combining acute accent.
+   */
+  const EXTN_PATTERNS_FOR_PARSING
+    = ";ext=" + CAPTURING_EXTN_DIGITS + "|" + "[ \u00A0\\t,]*"
+    + "(?:e?xt(?:ensi(?:o\u0301?|\u00F3))?n?|\uFF45?\uFF58\uFF54\uFF4E?|"
+    + "[,x\uFF58#\uFF03~\uFF5E]|int|anexo|\uFF49\uFF4E\uFF54)"
+    + "[:\\.\uFF0E]?[ \u00A0\\t,-]*" + CAPTURING_EXTN_DIGITS + "#?|"
+    + "[- ]+([" + VALID_DIGITS + "]{1,5})#";
+
+  const VALID_ALPHA_PATTERN = new RegExp("[" + VALID_ALPHA + "]", "g");
+  const LEADING_PLUS_CHARS_PATTERN = new RegExp("^[" + PLUS_CHARS + "]+", "g");
+
+  // We append optionally the extension pattern to the end here, as a valid
+  // phone number may have an extension prefix appended, followed by 1 or more
+  // digits.
+  const VALID_PHONE_NUMBER_PATTERN =
+    new RegExp("^" + MIN_LENGTH_PHONE_NUMBER + "$|"
+               + "^" + VALID_PHONE_NUMBER + "(?:" + EXTN_PATTERNS_FOR_PARSING + ")?$", "i");
+
   // Format of the string encoded meta data. If the name contains "^" or "$"
   // we will generate a regular expression from the value, with those special
   // characters as prefix/suffix.
   const META_DATA_ENCODING = ["region",
                               "^internationalPrefix",
                               "nationalPrefix",
                               "^nationalPrefixForParsing",
                               "nationalPrefixTransformRule",
@@ -217,21 +300,21 @@ this.PhoneNumber = (function (dataBase) 
 
   // Normalize a number by converting unicode numbers and symbols to their
   // ASCII equivalents and removing all non-dialable characters.
   function NormalizeNumber(number) {
     number = number.replace(UNICODE_DIGITS,
                             function (ch) {
                               return String.fromCharCode(48 + (ch.charCodeAt(0) & 0xf));
                             });
-    number = number.replace(ALPHA_CHARS,
+    number = number.replace(VALID_ALPHA_PATTERN,
                             function (ch) {
                               return (ch.toLowerCase().charCodeAt(0) - 97)/3+2 | 0;
                             });
-    number = number.replace(PLUS_CHARS, "+");
+    number = number.replace(LEADING_PLUS_CHARS_PATTERN, "+");
     number = number.replace(NON_DIALABLE_CHARS, "");
     return number;
   }
 
   // Check whether the number is valid for the given region.
   function IsValidNumber(number, md) {
     return md.possiblePattern.test(number);
   }
@@ -302,17 +385,17 @@ this.PhoneNumber = (function (dataBase) 
     number = NormalizeNumber(number);
 
     // If there is no defaultRegion, we can't parse international access codes.
     if (!defaultRegion && number[0] !== '+')
       return null;
 
     // Detect and strip leading '+'.
     if (number[0] === '+')
-      return ParseInternationalNumber(number.replace(PLUS_CHARS, ""));
+      return ParseInternationalNumber(number.replace(LEADING_PLUS_CHARS_PATTERN, ""));
 
     // Lookup the meta data for the given region.
     var md = FindMetaDataForRegion(defaultRegion.toUpperCase());
 
     // See if the number starts with an international prefix, and if the
     // number resulting from stripping the code is valid, then remove the
     // prefix and flag the number as international.
     if (md.internationalPrefix.test(number)) {
@@ -355,13 +438,27 @@ this.PhoneNumber = (function (dataBase) 
     ret = ParseInternationalNumber(number)
     if (ret)
       return ret;
 
     // We couldn't parse the number at all.
     return null;
   }
 
+  function IsViablePhoneNumber(number) {
+    if (number == null || number.length < MIN_LENGTH_FOR_NSN) {
+      return false;
+    }
+
+    let matchedGroups = number.match(VALID_PHONE_NUMBER_PATTERN);
+    if (matchedGroups && matchedGroups[0].length == number.length) {
+      return true;
+    }
+
+    return false;
+  }
+
   return {
+    IsViable: IsViablePhoneNumber,
     Parse: ParseNumber,
     Normalize: NormalizeNumber
   };
 })(PHONE_NUMBER_META_DATA);
--- a/dom/phonenumberutils/PhoneNumberUtils.jsm
+++ b/dom/phonenumberutils/PhoneNumberUtils.jsm
@@ -78,10 +78,16 @@ this.PhoneNumberUtils = {
     }
     return result;
   },
 
   parseWithMCC: function(aNumber, aMCC) {
     let countryName = MCC_ISO3166_TABLE[aMCC];
     if (DEBUG) debug("found country name: " + countryName);
     return PhoneNumber.Parse(aNumber, countryName);
+  },
+
+  isViablePhoneNumber: function IsViablePhoneNumber(aNumber) {
+    let viable = PhoneNumber.IsViable(aNumber);
+    if (DEBUG) debug("IsViable(" + aNumber + "): " + viable);
+    return viable;
   }
 };
--- a/dom/phonenumberutils/tests/test_phonenumber.xul
+++ b/dom/phonenumberutils/tests/test_phonenumber.xul
@@ -17,16 +17,25 @@
   </body>
 
 <script type="application/javascript;version=1.8">
 
 "use strict";
 
 Components.utils.import("resource://gre/modules/PhoneNumber.jsm");
 
+function IsViable(dial, expected) {
+  var result = PhoneNumber.IsViable(dial);
+  if (result != expected) {
+    ok(false, dial + " is " + (result ? "" : "not ") + "viable, expects otherwise.");
+  } else {
+    ok(true, dial + " is " + (result ? "" : "not ") + "viable as expected.");
+  }
+}
+
 function CantParse(dial, currentRegion) {
   var result = PhoneNumber.Parse(dial, currentRegion);
   if (result) {
   	ok(false, "Shouldn't parse!\n");
     print("expected: does not parse");
     print("got: " + dial + " " + currentRegion);
   }
 }
@@ -68,16 +77,47 @@ function Format(dial, currentRegion, nat
   if (result.nationalFormat != nationalFormat ||
       result.internationalFormat != internationalFormat) {
     ok(false, "expected: " + nationalFormat + " " + internationalFormat + 
       "got: " + result.nationalFormat + " " + result.internationalFormat);
     return result;
   }
 }
 
+// Test whether could a string be a phone number.
+IsViable(null, false);
+IsViable("", false);
+IsViable("1", false);
+IsViable("12", true); // MIN_LENGTH_PHONE_NUMBER
+IsViable("123", true); // MIN_LENGTH_PHONE_NUMBER
+IsViable("1a2", false);
+IsViable("12a", false);
+IsViable("1234", true); // MIN_LENGTH_PHONE_NUMBER
+IsViable("123a", true);
+IsViable("+", false);
+IsViable("+1", false);
+IsViable("+12", false);
+IsViable("+123", true);
+IsViable("()123", true);
+IsViable("(1)23", true);
+IsViable("(12)3", true);
+IsViable("(123)", true);
+IsViable("(123)4", true);
+IsViable("(123)4", true);
+IsViable("123;ext=", false);
+IsViable("123;ext=1", true);
+IsViable("123;ext=1234567", true);
+IsViable("123;ext=12345678", false);
+IsViable("123 ext:1", true);
+IsViable("123 ext:1#", true);
+IsViable("123-1#", true);
+IsViable("123 1#", true);
+IsViable("123 12345#", true);
+IsViable("123 +123456#", false);
+
 // Test parsing national numbers.
 Parse("033316005", "NZ");
 Parse("03-331 6005", "NZ");
 Parse("03 331 6005", "NZ");
 
 // Always test CA before US because CA has to load all meta-info for US.
 ParseWithIntl("4031234567", "CA");
 Parse("(416) 585-4319", "CA");
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -77,17 +77,19 @@ private:
   bool mCanceled;
 };
 
 static nsRefPtr<GLContext> sPluginContext = nullptr;
 
 static bool EnsureGLContext()
 {
   if (!sPluginContext) {
-    sPluginContext = GLContextProvider::CreateOffscreen(gfxIntSize(16, 16));
+    gfxIntSize dummySize(16, 16);
+    GLContext::SurfaceCaps dummyCaps;
+    sPluginContext = GLContextProvider::CreateOffscreen(dummySize, dummyCaps);
   }
 
   return sPluginContext != nullptr;
 }
 
 class SharedPluginTexture {
 public:
   NS_INLINE_DECL_REFCOUNTING(SharedPluginTexture)
--- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp
+++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp
@@ -121,25 +121,25 @@ nsPluginByteRangeStreamListener::OnStart
   
   uint32_t responseCode = 0;
   rv = httpChannel->GetResponseStatus(&responseCode);
   if (NS_FAILED(rv)) {
     return NS_ERROR_FAILURE;
   }
   
   if (responseCode != 200) {
-    bool bWantsAllNetworkStreams = false;
+    uint32_t wantsAllNetworkStreams = 0;
     rv = pslp->GetPluginInstance()->GetValueFromPlugin(NPPVpluginWantsAllNetworkStreams,
-                                                       &bWantsAllNetworkStreams);
+                                                       &wantsAllNetworkStreams);
     // If the call returned an error code make sure we still use our default value.
     if (NS_FAILED(rv)) {
-      bWantsAllNetworkStreams = false;
+      wantsAllNetworkStreams = 0;
     }
 
-    if (!bWantsAllNetworkStreams){
+    if (!wantsAllNetworkStreams){
       return NS_ERROR_FAILURE;
     }
   }
   
   // if server cannot continue with byte range (206 status) and sending us whole object (200 status)
   // reset this seekable stream & try serve it to plugin instance as a file
   mStreamConverter = finalStreamListener;
   mRemoveMagicNumber = true;
@@ -471,30 +471,30 @@ nsPluginStreamListenerPeer::OnStartReque
       // in nsNPAPIPluginStreamListener::CleanUpStream
       // return error will cancel this request
       // ...and we also need to tell the plugin that
       mRequestFailed = true;
       return NS_ERROR_FAILURE;
     }
 
     if (responseCode > 206) { // not normal
-      bool bWantsAllNetworkStreams = false;
+      uint32_t wantsAllNetworkStreams = 0;
 
       // We don't always have an instance here already, but if we do, check
       // to see if it wants all streams.
       if (mPluginInstance) {
         rv = mPluginInstance->GetValueFromPlugin(NPPVpluginWantsAllNetworkStreams,
-                                                 &bWantsAllNetworkStreams);
+                                                 &wantsAllNetworkStreams);
         // If the call returned an error code make sure we still use our default value.
         if (NS_FAILED(rv)) {
-          bWantsAllNetworkStreams = false;
+          wantsAllNetworkStreams = 0;
         }
       }
 
-      if (!bWantsAllNetworkStreams) {
+      if (!wantsAllNetworkStreams) {
         mRequestFailed = true;
         return NS_ERROR_FAILURE;
       }
     }
   }
 
   // Get the notification callbacks from the channel and save it as
   // week ref we'll use it in nsPluginStreamInfo::RequestRead() when
--- a/dom/plugins/test/testplugin/nptest.cpp
+++ b/dom/plugins/test/testplugin/nptest.cpp
@@ -1506,21 +1506,23 @@ NPP_GetValue(NPP instance, NPPVariable v
   if (variable == NPPVpluginScriptableNPObject) {
     NPObject* object = instanceData->scriptableObject;
     NPN_RetainObject(object);
     *((NPObject**)value) = object;
     return NPERR_NO_ERROR;
   }
   if (variable == NPPVpluginNeedsXEmbed) {
     // Only relevant for X plugins
-    *(NPBool*)value = instanceData->hasWidget;
+    // use 4-byte writes like some plugins may do
+    *(uint32_t*)value = instanceData->hasWidget;
     return NPERR_NO_ERROR;
   }
   if (variable == NPPVpluginWantsAllNetworkStreams) {
-    *(NPBool*)value = instanceData->wantsAllStreams;
+    // use 4-byte writes like some plugins may do
+    *(uint32_t*)value = instanceData->wantsAllStreams;
     return NPERR_NO_ERROR;
   }
 
   return NPERR_GENERIC_ERROR;
 }
 
 NPError
 NPP_SetValue(NPP instance, NPNVariable variable, void* value)
--- a/dom/system/gonk/NetworkManager.js
+++ b/dom/system/gonk/NetworkManager.js
@@ -390,21 +390,22 @@ NetworkManager.prototype = {
       if (this.active != this._overriddenActive) {
         this.active = this._overriddenActive;
         this.setDefaultRouteAndDNS(oldActive);
         Services.obs.notifyObservers(this.active, TOPIC_ACTIVE_CHANGED, null);
       }
       return;
     }
 
-    // If the active network is already of the preferred type, nothing to do.
+    // The active network is already our preferred type.
     if (this.active &&
         this.active.state == Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED &&
         this.active.type == this._preferredNetworkType) {
-      debug("Active network is already our preferred type. Not doing anything.");
+      debug("Active network is already our preferred type.");
+      this.setDefaultRouteAndDNS(oldActive);
       return;
     }
 
     // Find a suitable network interface to activate.
     this.active = null;
     for each (let network in this.networkInterfaces) {
       if (network.state != Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED) {
         continue;
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -147,16 +147,22 @@ XPCOMUtils.defineLazyServiceGetter(this,
                                    "nsISystemWorkerManager");
 
 XPCOMUtils.defineLazyGetter(this, "WAP", function () {
   let WAP = {};
   Cu.import("resource://gre/modules/WapPushManager.js", WAP);
   return WAP;
 });
 
+XPCOMUtils.defineLazyGetter(this, "PhoneNumberUtils", function () {
+  let ns = {};
+  Cu.import("resource://gre/modules/PhoneNumberUtils.jsm", ns);
+  return ns.PhoneNumberUtils;
+});
+
 function convertRILCallState(state) {
   switch (state) {
     case RIL.CALL_STATE_ACTIVE:
       return nsIRadioInterfaceLayer.CALL_STATE_CONNECTED;
     case RIL.CALL_STATE_HOLDING:
       return nsIRadioInterfaceLayer.CALL_STATE_HELD;
     case RIL.CALL_STATE_DIALING:
       return nsIRadioInterfaceLayer.CALL_STATE_DIALING;
@@ -1979,16 +1985,24 @@ RadioInterfaceLayer.prototype = {
   enumerateCalls: function enumerateCalls(message) {
     debug("Requesting enumeration of calls for callback");
     message.rilMessageType = "enumerateCalls";
     this.worker.postMessage(message);
   },
 
   dial: function dial(number) {
     debug("Dialing " + number);
+    if (!PhoneNumberUtils.isViablePhoneNumber(number)) {
+      this.handleCallError({
+        callIndex: -1,
+        error: RIL.RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[RIL.CALL_FAIL_UNOBTAINABLE_NUMBER]
+      });
+      debug("Number '" + number + "' doesn't seem to be a viable number. Drop.");
+      return;
+    }
     this.worker.postMessage({rilMessageType: "dial",
                              number: number,
                              isDialEmergency: false});
   },
 
   dialEmergency: function dialEmergency(number) {
     debug("Dialing emergency " + number);
     this.worker.postMessage({rilMessageType: "dial",
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -509,16 +509,17 @@ this.ICC_STATUS_WITH_SIM_DATA = 0x9e;
 this.ICC_STATUS_WITH_RESPONSE_DATA = 0x9f;
 this.ICC_STATUS_ERROR_WRONG_LENGTH = 0x67;
 this.ICC_STATUS_ERROR_COMMAND_NOT_ALLOWED = 0x69;
 this.ICC_STATUS_ERROR_WRONG_PARAMETERS = 0x6a;
 
 // ICC call barring facility.
 // TS 27.007, clause 7.4, +CLCK
 this.ICC_CB_FACILITY_SIM = "SC";
+this.ICC_CB_FACILITY_FDN = "FD";
 
 // ICC service class
 // TS 27.007, clause 7.4, +CLCK
 this.ICC_SERVICE_CLASS_NONE = 0; // no user input
 this.ICC_SERVICE_CLASS_VOICE = (1 << 0);
 this.ICC_SERVICE_CLASS_DATA = (1 << 1);
 this.ICC_SERVICE_CLASS_FAX = (1 << 2);
 this.ICC_SERVICE_CLASS_SMS = (1 << 3);
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -1005,41 +1005,54 @@ let RIL = {
    */
   enterDepersonalization: function enterDepersonalization(options) {
     Buf.newParcel(REQUEST_ENTER_NETWORK_DEPERSONALIZATION_CODE, options);
     Buf.writeUint32(options.type);
     Buf.writeString(options.pin);
     Buf.sendParcel();
   },
 
-   /**
+  /**
    * Helper function for changing ICC locks.
    */
   iccSetCardLock: function iccSetCardLock(options) {
-    if (options.newPin !== undefined) {
+    if (options.newPin !== undefined) { // Change PIN lock.
       switch (options.lockType) {
         case "pin":
           this.changeICCPIN(options);
           break;
         case "pin2":
           this.changeICCPIN2(options);
           break;
         default:
           options.errorMsg = "Unsupported Card Lock.";
           options.success = false;
           this.sendDOMMessage(options);
       }
-    } else { // Enable/Disable pin lock.
-      if (options.lockType != "pin") {
-        options.errorMsg = "Unsupported Card Lock.";
-        options.success = false;
-        this.sendDOMMessage(options);
-        return;
-      }
-      this.setICCPinLock(options);
+    } else { // Enable/Disable lock.
+      switch (options.lockType) {
+        case "pin":
+          options.facility = ICC_CB_FACILITY_SIM;
+          options.password = options.pin;
+          break;
+        case "fdn":
+          options.facility = ICC_CB_FACILITY_FDN;
+          options.password = options.pin2;
+          break;
+        default:
+          options.errorMsg = "Unsupported Card Lock.";
+          options.success = false;
+          this.sendDOMMessage(options);
+          return;
+      }
+      options.enabled = options.enabled;
+      options.serviceClass = ICC_SERVICE_CLASS_VOICE |
+                             ICC_SERVICE_CLASS_DATA  |
+                             ICC_SERVICE_CLASS_FAX;
+      this.setICCFacilityLock(options);
     }
   },
 
   /**
    * Change the current ICC PIN number.
    *
    * @param pin
    *        String containing the old PIN value
@@ -1122,33 +1135,28 @@ let RIL = {
    },
 
   /**
    * Helper function for fetching the state of ICC locks.
    */
   iccGetCardLock: function iccGetCardLock(options) {
     switch (options.lockType) {
       case "pin":
-        this.getICCPinLock(options);
+        options.facility = ICC_CB_FACILITY_SIM;
+        break;
+      case "fdn":
+        options.facility = ICC_CB_FACILITY_FDN;
         break;
       default:
         options.errorMsg = "Unsupported Card Lock.";
         options.success = false;
         this.sendDOMMessage(options);
-    }
-  },
-
-  /**
-   * Get ICC Pin lock. A wrapper call to queryICCFacilityLock.
-   *
-   * @param requestId
-   *        Request Id from RadioInterfaceLayer.
-   */
-  getICCPinLock: function getICCPinLock(options) {
-    options.facility = ICC_CB_FACILITY_SIM;
+        return;
+    }
+
     options.password = ""; // For query no need to provide pin.
     options.serviceClass = ICC_SERVICE_CLASS_VOICE |
                            ICC_SERVICE_CLASS_DATA  |
                            ICC_SERVICE_CLASS_FAX;
     this.queryICCFacilityLock(options);
   },
 
   /**
@@ -1171,36 +1179,16 @@ let RIL = {
     Buf.writeString(options.serviceClass.toString());
     if (!RILQUIRKS_V5_LEGACY) {
       Buf.writeString(options.aid || this.aid);
     }
     Buf.sendParcel();
   },
 
   /**
-   * Set ICC Pin lock. A wrapper call to setICCFacilityLock.
-   *
-   * @param enabled
-   *        true to enable, false to disable.
-   * @param pin
-   *        Pin code.
-   * @param requestId
-   *        Request Id from RadioInterfaceLayer.
-   */
-  setICCPinLock: function setICCPinLock(options) {
-    options.facility = ICC_CB_FACILITY_SIM;
-    options.enabled = options.enabled;
-    options.password = options.pin;
-    options.serviceClass = ICC_SERVICE_CLASS_VOICE |
-                           ICC_SERVICE_CLASS_DATA  |
-                           ICC_SERVICE_CLASS_FAX;
-    this.setICCFacilityLock(options);
-  },
-
-  /**
    * Set ICC facility lock.
    *
    * @param facility
    *        One of ICC_CB_FACILITY_*.
    * @param enabled
    *        true to enable, false to disable.
    * @param password
    *        Password for the facility, or "" if not required.
@@ -7419,16 +7407,21 @@ let StkCommandParamsFactory = {
     }
     textMsg.text = ctlv.value.textString;
 
     ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_IMMEDIATE_RESPONSE, ctlvs);
     if (ctlv) {
       textMsg.responseNeeded = true;
     }
 
+    ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_DURATION, ctlvs);
+    if (ctlv) {
+      textMsg.duration = ctlv.value;
+    }
+
     // High priority.
     if (cmdDetails.commandQualifier & 0x01) {
       textMsg.isHighPriority = true;
     }
 
     // User clear.
     if (cmdDetails.commandQualifier & 0x80) {
       textMsg.userClear = true;
@@ -7583,16 +7576,22 @@ let StkCommandParamsFactory = {
     if (!ctlv) {
       RIL.sendStkTerminalResponse({
         command: cmdDetails,
         resultCode: STK_RESULT_REQUIRED_VALUES_MISSING});
       throw new Error("Stk Set Up Call: Required value missing : Adress");
     }
     call.address = ctlv.value.number;
 
+    // see 3GPP TS 31.111 section 6.4.13
+    ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_DURATION, ctlvs);
+    if (ctlv) {
+      call.duration = ctlv.value;
+    }
+
     return call;
   },
 
   processLaunchBrowser: function processLaunchBrowser(cmdDetails, ctlvs) {
     let browser = {};
 
     let ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_URL, ctlvs);
     if (!ctlv) {
--- a/dom/system/gonk/tests/test_ril_worker_icc.js
+++ b/dom/system/gonk/tests/test_ril_worker_icc.js
@@ -502,16 +502,54 @@ add_test(function test_send_stk_terminal
     do_check_eq(parseInt(profile.substring(2 * i, 2 * i + 2), 16),
                 STK_SUPPORTED_TERMINAL_PROFILE[i]);
   }
 
   run_next_test();
 });
 
 /**
+ * Verify RIL.iccGetCardLock("fdn")
+ */
+add_test(function test_icc_get_card_lock_fdn() {
+  let worker = newUint8Worker();
+  let ril = worker.RIL;
+  let buf = worker.Buf;
+
+  buf.sendParcel = function () {
+    // Request Type.
+    do_check_eq(this.readUint32(), REQUEST_QUERY_FACILITY_LOCK)
+
+    // Token : we don't care.
+    this.readUint32();
+
+    // String Array Length.
+    do_check_eq(this.readUint32(), 4);
+
+    // Facility.
+    do_check_eq(this.readString(), ICC_CB_FACILITY_FDN);
+
+    // Password.
+    do_check_eq(this.readString(), "");
+
+    // Service class.
+    do_check_eq(this.readString(), (ICC_SERVICE_CLASS_VOICE |
+                                    ICC_SERVICE_CLASS_DATA  |
+                                    ICC_SERVICE_CLASS_FAX).toString());
+
+    // AID. Ignore because it's from modem.
+    this.readUint32();
+
+    run_next_test();
+  };
+
+  ril.iccGetCardLock({lockType: "fdn"});
+});
+
+/**
  * Verify ComprehensionTlvHelper.writeLocationInfoTlv
  */
 add_test(function test_write_location_info_tlv() {
   let worker = newUint8Worker();
   let pduHelper = worker.GsmPDUHelper;
   let tlvHelper = worker.ComprehensionTlvHelper;
 
   // Test with 2-digit mnc, and gsmCellId obtained from UMTS network.
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -188,27 +188,27 @@ struct WorkerStructuredCloneCallbacks
       }
     }
     // See if the object is an ImageData.
     else if (aTag == SCTAG_DOM_IMAGEDATA) {
       JS_ASSERT(!aData);
 
       // Read the information out of the stream.
       uint32_t width, height;
-      jsval dataArray;
+      JS::Value dataArray;
       if (!JS_ReadUint32Pair(aReader, &width, &height) ||
           !JS_ReadTypedArray(aReader, &dataArray))
       {
         return nullptr;
       }
       MOZ_ASSERT(dataArray.isObject());
 
       // Construct the ImageData.
       JSObject* obj = imagedata::Create(aCx, width, height,
-                                        JSVAL_TO_OBJECT(dataArray));
+                                        &dataArray.toObject());
       return obj;
     }
 
     Error(aCx, 0);
     return nullptr;
   }
 
   static JSBool
@@ -301,26 +301,26 @@ struct MainThreadWorkerStructuredCloneCa
           NS_ASSERTION(NS_SUCCEEDED(mutableFile->GetMutable(&isMutable)) &&
                        !isMutable,
                        "Only immutable file should be passed to worker");
         }
 #endif
 
         // nsIDOMFiles should be threadsafe, thus we will use the same instance
         // on the main thread.
-        jsval wrappedFile;
+        JS::Value wrappedFile;
         nsresult rv =
           nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), file,
                                      &NS_GET_IID(nsIDOMFile), &wrappedFile);
         if (NS_FAILED(rv)) {
           Error(aCx, DATA_CLONE_ERR);
           return nullptr;
         }
 
-        return JSVAL_TO_OBJECT(wrappedFile);
+        return &wrappedFile.toObject();
       }
     }
     // See if object is a nsIDOMBlob pointer.
     else if (aTag == DOMWORKER_SCTAG_BLOB) {
       JS_ASSERT(!aData);
 
       nsIDOMBlob* blob;
       if (JS_ReadBytes(aReader, &blob, sizeof(blob))) {
@@ -334,26 +334,26 @@ struct MainThreadWorkerStructuredCloneCa
           NS_ASSERTION(NS_SUCCEEDED(mutableBlob->GetMutable(&isMutable)) &&
                        !isMutable,
                        "Only immutable blob should be passed to worker");
         }
 #endif
 
         // nsIDOMBlobs should be threadsafe, thus we will use the same instance
         // on the main thread.
-        jsval wrappedBlob;
+        JS::Value wrappedBlob;
         nsresult rv =
           nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), blob,
                                      &NS_GET_IID(nsIDOMBlob), &wrappedBlob);
         if (NS_FAILED(rv)) {
           Error(aCx, DATA_CLONE_ERR);
           return nullptr;
         }
 
-        return JSVAL_TO_OBJECT(wrappedBlob);
+        return &wrappedBlob.toObject();
       }
     }
 
     JS_ClearPendingException(aCx);
     return NS_DOMReadStructuredClone(aCx, aReader, aTag, aData, nullptr);
   }
 
   static JSBool
@@ -2151,18 +2151,19 @@ WorkerPrivateParent<Derived>::ForgetMain
   SwapToISupportsArray(mPrincipal, aDoomed);
   SwapToISupportsArray(mCSP, aDoomed);
 
   mMainThreadObjectsForgotten = true;
 }
 
 template <class Derived>
 bool
-WorkerPrivateParent<Derived>::PostMessage(JSContext* aCx, jsval aMessage,
-                                          jsval aTransferable)
+WorkerPrivateParent<Derived>::PostMessage(JSContext* aCx,
+                                          JS::Value aMessage,
+                                          JS::Value aTransferable)
 {
   AssertIsOnParentThread();
 
   {
     MutexAutoLock lock(mMutex);
     if (mParentStatus > Running) {
       return true;
     }
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -344,17 +344,17 @@ public:
 
   bool
   RootJSObject(JSContext* aCx, bool aRoot);
 
   void
   ForgetMainThreadObjects(nsTArray<nsCOMPtr<nsISupports> >& aDoomed);
 
   bool
-  PostMessage(JSContext* aCx, jsval aMessage, jsval aTransferable);
+  PostMessage(JSContext* aCx, JS::Value aMessage, JS::Value aTransferable);
 
   uint64_t
   GetInnerWindowId();
 
   void
   UpdateJSContextOptions(JSContext* aCx, uint32_t aOptions);
 
   void
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -2,50 +2,43 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <algorithm>
 #include <stdio.h>
 #include <string.h>
 
-#include "mozilla/DebugOnly.h"
-
-#include "prlink.h"
-#include "prenv.h"
-
-#include "nsThreadUtils.h"
-
-#include "gfxPlatform.h"
 #include "GLContext.h"
-#include "GLContextProvider.h"
 
 #include "gfxCrashReporterUtils.h"
+#include "gfxPlatform.h"
 #include "gfxUtils.h"
-
+#include "GLContextProvider.h"
+#include "GLTextureImage.h"
+#include "nsIMemoryReporter.h"
+#include "nsThreadUtils.h"
+#include "prenv.h"
+#include "prlink.h"
+#include "SurfaceStream.h"
+
+#include "mozilla/DebugOnly.h"
 #include "mozilla/Preferences.h"
 
-#include "GLTextureImage.h"
-
-#include "nsIMemoryReporter.h"
-
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace gl {
 
 #ifdef DEBUG
 unsigned GLContext::sCurrentGLContextTLS = -1;
 #endif
 
 uint32_t GLContext::sDebugMode = 0;
 
-// define this here since it's global to GLContextProvider, not any
-// specific implementation
-const ContextFormat ContextFormat::BasicRGBA32Format(ContextFormat::BasicRGBA32);
 
 #define MAX_SYMBOL_LENGTH 128
 #define MAX_SYMBOL_NAMES 5
 
 // should match the order of GLExtensions, and be null-terminated.
 static const char *sExtensionNames[] = {
     "GL_EXT_framebuffer_object",
     "GL_ARB_framebuffer_object",
@@ -307,58 +300,66 @@ GLContext::InitWithPrefix(const char *pr
 
             if (!LoadSymbols(&symbols_desktop[0], trygl, prefix)) {
                 NS_ERROR("Desktop symbols failed to load.");
                 mInitialized = false;
             }
         }
     }
 
-    const char *glVendorString;
-    const char *glRendererString;
+    const char *glVendorString = nullptr;
+    const char *glRendererString = nullptr;
 
     if (mInitialized) {
         // The order of these strings must match up with the order of the enum
         // defined in GLContext.h for vendor IDs
         glVendorString = (const char *)fGetString(LOCAL_GL_VENDOR);
+        if (!glVendorString)
+            mInitialized = false;
+
         const char *vendorMatchStrings[VendorOther] = {
                 "Intel",
                 "NVIDIA",
                 "ATI",
                 "Qualcomm",
                 "Imagination",
                 "nouveau"
         };
+
         mVendor = VendorOther;
         for (int i = 0; i < VendorOther; ++i) {
             if (DoesStringMatch(glVendorString, vendorMatchStrings[i])) {
                 mVendor = i;
                 break;
             }
         }
 
         // The order of these strings must match up with the order of the enum
         // defined in GLContext.h for renderer IDs
         glRendererString = (const char *)fGetString(LOCAL_GL_RENDERER);
+        if (!glRendererString)
+            mInitialized = false;
+
         const char *rendererMatchStrings[RendererOther] = {
                 "Adreno 200",
                 "Adreno 205",
                 "PowerVR SGX 530",
-                "PowerVR SGX 540",
-
+                "PowerVR SGX 540"
         };
+
         mRenderer = RendererOther;
         for (int i = 0; i < RendererOther; ++i) {
             if (DoesStringMatch(glRendererString, rendererMatchStrings[i])) {
                 mRenderer = i;
                 break;
             }
         }
     }
 
+
 #ifdef DEBUG
     if (PR_GetEnv("MOZ_GL_DEBUG"))
         sDebugMode |= DebugEnabled;
 
     // enables extra verbose output, informing of the start and finish of every GL call.
     // useful e.g. to record information to investigate graphics system crashes/lockups
     if (PR_GetEnv("MOZ_GL_DEBUG_VERBOSE"))
         sDebugMode |= DebugTrace;
@@ -374,16 +375,17 @@ GLContext::InitWithPrefix(const char *pr
         if (firstRun && DebugMode()) {
             const char *vendors[VendorOther] = {
                 "Intel",
                 "NVIDIA",
                 "ATI",
                 "Qualcomm"
             };
 
+            MOZ_ASSERT(glVendorString);
             if (mVendor < VendorOther) {
                 printf_stderr("OpenGL vendor ('%s') recognized as: %s\n",
                               glVendorString, vendors[mVendor]);
             } else {
                 printf_stderr("OpenGL vendor ('%s') unrecognized\n", glVendorString);
             }
         }
         firstRun = false;
@@ -449,20 +451,19 @@ GLContext::InitWithPrefix(const char *pr
                 NS_ERROR("GL supports framebuffer_blit without supplying glBlitFramebuffer");
 
                 MarkExtensionUnsupported(ANGLE_framebuffer_blit);
                 MarkExtensionUnsupported(EXT_framebuffer_blit);
                 mSymbols.fBlitFramebuffer = nullptr;
             }
         }
 
-        if (SupportsOffscreenSplit() &&
-            ( IsExtensionSupported(GLContext::ANGLE_framebuffer_multisample) ||
-              IsExtensionSupported(GLContext::EXT_framebuffer_multisample) ))
+        if (SupportsFramebufferMultisample())
         {
+            MOZ_ASSERT(SupportsSplitFramebuffer());
             SymLoadStruct auxSymbols[] = {
                 {
                     (PRFuncPtr*) &mSymbols.fRenderbufferStorageMultisample,
                     {
                         "RenderbufferStorageMultisample",
                         "RenderbufferStorageMultisampleEXT",
                         "RenderbufferStorageMultisampleANGLE",
                         nullptr
@@ -503,24 +504,26 @@ GLContext::InitWithPrefix(const char *pr
                 mSymbols.fGetInteger64v = nullptr;
                 mSymbols.fGetSynciv = nullptr;
             }
         }
 
         if (IsExtensionSupported(OES_EGL_image)) {
             SymLoadStruct imageSymbols[] = {
                 { (PRFuncPtr*) &mSymbols.fEGLImageTargetTexture2D, { "EGLImageTargetTexture2DOES", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fEGLImageTargetRenderbufferStorage, { "EGLImageTargetRenderbufferStorageOES", nullptr } },
                 { nullptr, { nullptr } },
             };
 
             if (!LoadSymbols(&imageSymbols[0], trygl, prefix)) {
                 NS_ERROR("GL supports OES_EGL_image without supplying its functions.");
 
                 MarkExtensionUnsupported(OES_EGL_image);
                 mSymbols.fEGLImageTargetTexture2D = nullptr;
+                mSymbols.fEGLImageTargetRenderbufferStorage = nullptr;
             }
         }
        
         // Load developer symbols, don't fail if we can't find them.
         SymLoadStruct auxSymbols[] = {
                 { (PRFuncPtr*) &mSymbols.fGetTexImage, { "GetTexImage", nullptr } },
                 { (PRFuncPtr*) &mSymbols.fGetTexLevelParameteriv, { "GetTexLevelParameteriv", nullptr } },
                 { nullptr, { nullptr } },
@@ -559,17 +562,33 @@ GLContext::InitWithPrefix(const char *pr
             // see bug 814716. Clamp MaxCubeMapTextureSize at 2K for Nouveau.
             mMaxCubeMapTextureSize = std::min(mMaxCubeMapTextureSize, 2048);
             mNeedsTextureSizeChecks = true;
         }
 #endif
 
         mMaxTextureImageSize = mMaxTextureSize;
 
-        UpdateActualFormat();
+        mMaxSamples = 0;
+        if (SupportsFramebufferMultisample()) {
+            fGetIntegerv(LOCAL_GL_MAX_SAMPLES, (GLint*)&mMaxSamples);
+        }
+
+        // We're ready for final setup.
+        InitFramebuffers();
+
+        if (mCaps.any)
+            DetermineCaps();
+
+        UpdatePixelFormat();
+        UpdateGLFormats(mCaps);
+
+        mTexGarbageBin = new TextureGarbageBin(this);
+
+        MOZ_ASSERT(IsCurrent());
     }
 
     if (mInitialized)
         reporter.SetSuccessful();
     else {
         // if initialization fails, ensure all symbols are zero, to avoid hard-to-understand bugs
         mSymbols.Zero();
         NS_WARNING("InitWithPrefix failed!");
@@ -817,148 +836,182 @@ void GLContext::ApplyFilterToBoundTextur
         fTexParameteri(aTarget, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST);
     } else {
         fTexParameteri(aTarget, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
         fTexParameteri(aTarget, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
     }
 }
 
 
-GLContext::GLFormats
-GLContext::ChooseGLFormats(ContextFormat& aCF, ColorByteOrder aByteOrder)
+void
+GLContext::DetermineCaps()
+{
+    PixelBufferFormat format = QueryPixelFormat();
+
+    SurfaceCaps caps;
+    caps.color = !!format.red && !!format.green && !!format.blue;
+    caps.bpp16 = caps.color && format.ColorBits() == 16;
+    caps.alpha = !!format.alpha;
+    caps.depth = !!format.depth;
+    caps.stencil = !!format.stencil;
+    caps.antialias = format.samples > 1;
+    caps.preserve = true;
+
+    mCaps = caps;
+}
+
+PixelBufferFormat
+GLContext::QueryPixelFormat()
+{
+    PixelBufferFormat format;
+
+    ScopedBindFramebuffer autoFB(this, 0);
+
+    fGetIntegerv(LOCAL_GL_RED_BITS  , &format.red  );
+    fGetIntegerv(LOCAL_GL_GREEN_BITS, &format.green);
+    fGetIntegerv(LOCAL_GL_BLUE_BITS , &format.blue );
+    fGetIntegerv(LOCAL_GL_ALPHA_BITS, &format.alpha);
+
+    fGetIntegerv(LOCAL_GL_DEPTH_BITS, &format.depth);
+    fGetIntegerv(LOCAL_GL_STENCIL_BITS, &format.stencil);
+
+    fGetIntegerv(LOCAL_GL_SAMPLES, &format.samples);
+
+    return format;
+}
+
+void
+GLContext::UpdatePixelFormat()
+{
+    PixelBufferFormat format = QueryPixelFormat();
+#ifdef DEBUG
+    const SurfaceCaps& caps = Caps();
+    MOZ_ASSERT(caps.color == !!format.red);
+    MOZ_ASSERT(caps.color == !!format.green);
+    MOZ_ASSERT(caps.color == !!format.blue);
+    MOZ_ASSERT(caps.alpha == !!format.alpha);
+    MOZ_ASSERT(caps.depth == !!format.depth);
+    MOZ_ASSERT(caps.stencil == !!format.stencil);
+    MOZ_ASSERT(caps.antialias == (format.samples > 1));
+#endif
+    mPixelFormat = new PixelBufferFormat(format);
+}
+
+GLFormats
+GLContext::ChooseGLFormats(const SurfaceCaps& caps) const
 {
     GLFormats formats;
 
     // If we're on ES2 hardware and we have an explicit request for 16 bits of color or less
     // OR we don't support full 8-bit color, return a 4444 or 565 format.
-    if (mIsGLES2 && (aCF.colorBits() <= 16 || !IsExtensionSupported(OES_rgb8_rgba8))) {
-        if (aCF.alpha) {
-            formats.texColor = LOCAL_GL_RGBA;
-            formats.texColorType = LOCAL_GL_UNSIGNED_SHORT_4_4_4_4;
-            formats.rbColor = LOCAL_GL_RGBA4;
-
-            aCF.red = aCF.green = aCF.blue = aCF.alpha = 4;
-        } else {
-            formats.texColor = LOCAL_GL_RGB;
-            formats.texColorType = LOCAL_GL_UNSIGNED_SHORT_5_6_5;
-            formats.rbColor = LOCAL_GL_RGB565;
-
-            aCF.red = 5;
-            aCF.green = 6;
-            aCF.blue = 5;
-            aCF.alpha = 0;
-        }   
+    bool bpp16 = caps.bpp16;
+    if (mIsGLES2) {
+        if (!IsExtensionSupported(OES_rgb8_rgba8))
+            bpp16 = true;
     } else {
-        formats.texColorType = LOCAL_GL_UNSIGNED_BYTE;
-
-        if (aCF.alpha) {
-            // Prefer BGRA8888 on ES2 hardware; if the extension is supported, it
-            // should be faster.  There are some cases where we don't want this --
-            // specifically, CopyTex*Image doesn't seem to understand how to deal
-            // with a BGRA source going to a RGB/RGBA destination on some drivers.
-            if (mIsGLES2 &&
-                IsExtensionSupported(EXT_texture_format_BGRA8888) &&
-                aByteOrder != ForceRGBA)
-            {
-                formats.texColor = LOCAL_GL_BGRA;
-            } else {
-                formats.texColor = LOCAL_GL_RGBA;
-            }
-
-            formats.rbColor = LOCAL_GL_RGBA8;
-
-            aCF.red = aCF.green = aCF.blue = aCF.alpha = 8;
+        // RGB565 is uncommon on desktop, requiring ARB_ES2_compatibility.
+        // Since it's also vanishingly useless there, let's not support it.
+        bpp16 = false;
+    }
+
+    if (bpp16) {
+        MOZ_ASSERT(mIsGLES2);
+        if (caps.alpha) {
+            formats.color_texInternalFormat = LOCAL_GL_RGBA;
+            formats.color_texFormat = LOCAL_GL_RGBA;
+            formats.color_texType   = LOCAL_GL_UNSIGNED_SHORT_4_4_4_4;
+            formats.color_rbFormat  = LOCAL_GL_RGBA4;
         } else {
-            formats.texColor = LOCAL_GL_RGB;
-            formats.rbColor = LOCAL_GL_RGB8;
-
-            aCF.red = aCF.green = aCF.blue = 8;
-            aCF.alpha = 0;
+            formats.color_texInternalFormat = LOCAL_GL_RGB;
+            formats.color_texFormat = LOCAL_GL_RGB;
+            formats.color_texType   = LOCAL_GL_UNSIGNED_SHORT_5_6_5;
+            formats.color_rbFormat  = LOCAL_GL_RGB565;
+        }
+    } else {
+        formats.color_texType = LOCAL_GL_UNSIGNED_BYTE;
+
+        if (caps.alpha) {
+            formats.color_texInternalFormat = mIsGLES2 ? LOCAL_GL_RGBA : LOCAL_GL_RGBA8;
+            formats.color_texFormat = LOCAL_GL_RGBA;
+            formats.color_rbFormat  = LOCAL_GL_RGBA8;
+        } else {
+            formats.color_texInternalFormat = mIsGLES2 ? LOCAL_GL_RGB : LOCAL_GL_RGB8;
+            formats.color_texFormat = LOCAL_GL_RGB;
+            formats.color_rbFormat  = LOCAL_GL_RGB8;
         }
     }
 
-    GLsizei samples = aCF.samples;
-
-    GLsizei maxSamples = 0;
-    if (SupportsFramebufferMultisample())
-        fGetIntegerv(LOCAL_GL_MAX_SAMPLES, (GLint*)&maxSamples);
-    samples = std::min(samples, maxSamples);
-
-    // bug 778765
+    uint32_t msaaLevel = Preferences::GetUint("gl.msaa-level", 2);
+    GLsizei samples = msaaLevel * msaaLevel;
+    samples = std::min(samples, mMaxSamples);
+
+    // Bug 778765.
     if (WorkAroundDriverBugs() && samples == 1) {
         samples = 0;
     }
-
     formats.samples = samples;
-    aCF.samples = samples;
-
-
-    const int depth = aCF.depth;
-    const int stencil = aCF.stencil;
-    const bool useDepthStencil =
-        !mIsGLES2 || IsExtensionSupported(OES_packed_depth_stencil);
-
+
+
+    // Be clear that these are 0 if unavailable.
     formats.depthStencil = 0;
+    if (!mIsGLES2 || IsExtensionSupported(OES_packed_depth_stencil)) {
+        formats.depthStencil = LOCAL_GL_DEPTH24_STENCIL8;
+    }
+
     formats.depth = 0;
-    formats.stencil = 0;
-    if (depth && stencil && useDepthStencil) {
-        formats.depthStencil = LOCAL_GL_DEPTH24_STENCIL8;
-        aCF.depth = 24;
-        aCF.stencil = 8;
+    if (mIsGLES2) {
+        if (IsExtensionSupported(OES_depth24)) {
+            formats.depth = LOCAL_GL_DEPTH_COMPONENT24;
+        } else {
+            formats.depth = LOCAL_GL_DEPTH_COMPONENT16;
+        }
     } else {
-        if (depth) {
-            if (mIsGLES2) {
-                if (IsExtensionSupported(OES_depth24)) {
-                    formats.depth = LOCAL_GL_DEPTH_COMPONENT24;
-                    aCF.depth = 24;
-                } else {
-                    formats.depth = LOCAL_GL_DEPTH_COMPONENT16;
-                    aCF.depth = 16;
-                }
-            } else {
-                formats.depth = LOCAL_GL_DEPTH_COMPONENT24;
-                aCF.depth = 24;
-            }
-        }
-
-        if (stencil) {
-            formats.stencil = LOCAL_GL_STENCIL_INDEX8;
-            aCF.stencil = 8;
-        }
+        formats.depth = LOCAL_GL_DEPTH_COMPONENT24;
     }
 
+    formats.stencil = LOCAL_GL_STENCIL_INDEX8;
+
     return formats;
 }
 
-void
-GLContext::CreateTextureForOffscreen(const GLFormats& aFormats, const gfxIntSize& aSize, GLuint& texture)
+GLuint
+GLContext::CreateTextureForOffscreen(const GLFormats& formats, const gfxIntSize& size)
 {
-    GLuint boundTexture = 0;
-    fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, (GLint*)&boundTexture);
-
-    if (texture == 0) {
-        fGenTextures(1, &texture);
-    }
-
-    fBindTexture(LOCAL_GL_TEXTURE_2D, texture);
+    MOZ_ASSERT(formats.color_texInternalFormat);
+    MOZ_ASSERT(formats.color_texFormat);
+    MOZ_ASSERT(formats.color_texType);
+
+    return CreateTexture(formats.color_texInternalFormat,
+                         formats.color_texFormat,
+                         formats.color_texType,
+                         size);
+}
+
+GLuint
+GLContext::CreateTexture(GLenum internalFormat, GLenum format, GLenum type, const gfxIntSize& size)
+{
+    GLuint tex = 0;
+    fGenTextures(1, &tex);
+    ScopedBindTexture autoTex(this, tex);
+
     fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
     fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
     fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
     fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
 
     fTexImage2D(LOCAL_GL_TEXTURE_2D,
                 0,
-                aFormats.texColor,
-                aSize.width, aSize.height,
+                internalFormat,
+                size.width, size.height,
                 0,
-                aFormats.texColor,
-                aFormats.texColorType,
+                format,
+                type,
                 nullptr);
 
-    fBindTexture(LOCAL_GL_TEXTURE_2D, boundTexture);
+    return tex;
 }
 
 static inline void
 RenderbufferStorageBySamples(GLContext* gl, GLsizei samples, GLenum internalFormat, const gfxIntSize& size)
 {
     if (samples) {
         gl->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER,
                                             samples,
@@ -966,100 +1019,167 @@ RenderbufferStorageBySamples(GLContext* 
                                             size.width, size.height);
     } else {
         gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER,
                                  internalFormat,
                                  size.width, size.height);
     }
 }
 
-void
-GLContext::CreateRenderbuffersForOffscreen(const GLContext::GLFormats& aFormats, const gfxIntSize& aSize,
-                                           GLuint& colorMSRB, GLuint& depthRB, GLuint& stencilRB)
+GLuint
+GLContext::CreateRenderbuffer(GLenum format, GLsizei samples, const gfxIntSize& size)
 {
-    GLuint boundRB = 0;
-    fGetIntegerv(LOCAL_GL_RENDERBUFFER_BINDING, (GLint*)&boundRB);
-
-
-    colorMSRB = 0;
-    depthRB = 0;
-    stencilRB = 0;
-
-    if (aFormats.samples > 0) {
-        fGenRenderbuffers(1, &colorMSRB);
-        fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, colorMSRB);
-        RenderbufferStorageBySamples(this, aFormats.samples, aFormats.rbColor, aSize);
+    GLuint rb = 0;
+    fGenRenderbuffers(1, &rb);
+    ScopedBindRenderbuffer autoRB(this, rb);
+
+    RenderbufferStorageBySamples(this, samples, format, size);
+
+    return rb;
+}
+
+void
+GLContext::CreateRenderbuffersForOffscreen(const GLFormats& formats, const gfxIntSize& size,
+                                           bool multisample,
+                                           GLuint* colorMSRB, GLuint* depthRB, GLuint* stencilRB)
+{
+    GLsizei samples = multisample ? formats.samples : 0;
+    if (colorMSRB) {
+        MOZ_ASSERT(formats.samples > 0);
+        MOZ_ASSERT(formats.color_rbFormat);
+
+        *colorMSRB = CreateRenderbuffer(formats.color_rbFormat, samples, size);
     }
 
-    // If depthStencil, disallow depth, stencil
-    MOZ_ASSERT(!aFormats.depthStencil || (!aFormats.depth && !aFormats.stencil));
-
-    if (aFormats.depthStencil) {
-        fGenRenderbuffers(1, &depthRB);
-        stencilRB = depthRB;
-        fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, depthRB);
-        RenderbufferStorageBySamples(this, aFormats.samples, aFormats.depthStencil, aSize);
+    if (depthRB &&
+        stencilRB &&
+        formats.depthStencil)
+    {
+        *depthRB = CreateRenderbuffer(formats.depthStencil, samples, size);
+        *stencilRB = *depthRB;
+    } else {
+        if (depthRB) {
+            MOZ_ASSERT(formats.depth);
+
+            *depthRB = CreateRenderbuffer(formats.depth, samples, size);
+        }
+
+        if (stencilRB) {
+            MOZ_ASSERT(formats.stencil);
+
+            *stencilRB = CreateRenderbuffer(formats.stencil, samples, size);
+        }
     }
-
-    if (aFormats.depth) {
-        fGenRenderbuffers(1, &depthRB);
-        fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, depthRB);
-        RenderbufferStorageBySamples(this, aFormats.samples, aFormats.depth, aSize);
-    }
-
-    if (aFormats.stencil) {
-        fGenRenderbuffers(1, &stencilRB);
-        fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, stencilRB);
-        RenderbufferStorageBySamples(this, aFormats.samples, aFormats.stencil, aSize);
-    }
-
-
-    fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, boundRB);
 }
 
 bool
-GLContext::AssembleOffscreenFBOs(const GLuint colorMSRB,
-                                 const GLuint depthRB,
-                                 const GLuint stencilRB,
-                                 const GLuint texture,
-                                 GLuint& drawFBO,
-                                 GLuint& readFBO)
+GLContext::IsFramebufferComplete(GLuint fb, GLenum* pStatus)
+{
+    MOZ_ASSERT(fb);
+
+    ScopedBindFramebuffer autoFB(this, fb);
+    MOZ_ASSERT(fIsFramebuffer(fb));
+
+    GLenum status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
+    if (pStatus)
+        *pStatus = status;
+
+    return status == LOCAL_GL_FRAMEBUFFER_COMPLETE;
+}
+
+void
+GLContext::AttachBuffersToFB(GLuint colorTex, GLuint colorRB,
+                             GLuint depthRB, GLuint stencilRB,
+                             GLuint fb)
 {
-    drawFBO = 0;
-    readFBO = 0;
-
+    MOZ_ASSERT(fb);
+    MOZ_ASSERT( !(colorTex && colorRB) );
+
+    ScopedBindFramebuffer autoFB(this, fb);
+    MOZ_ASSERT(fIsFramebuffer(fb)); // It only counts after being bound.
+
+    if (colorTex) {
+        MOZ_ASSERT(fIsTexture(colorTex));
+        fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
+                              LOCAL_GL_COLOR_ATTACHMENT0,
+                              LOCAL_GL_TEXTURE_2D,
+                              colorTex,
+                              0);
+    } else if (colorRB) {
+        MOZ_ASSERT(fIsRenderbuffer(colorRB));
+        fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
+                                 LOCAL_GL_COLOR_ATTACHMENT0,
+                                 LOCAL_GL_RENDERBUFFER,
+                                 colorRB);
+    }
+
+    if (depthRB) {
+        MOZ_ASSERT(fIsRenderbuffer(depthRB));
+        fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
+                                 LOCAL_GL_DEPTH_ATTACHMENT,
+                                 LOCAL_GL_RENDERBUFFER,
+                                 depthRB);
+    }
+
+    if (stencilRB) {
+        MOZ_ASSERT(fIsRenderbuffer(stencilRB));
+        fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
+                                 LOCAL_GL_STENCIL_ATTACHMENT,
+                                 LOCAL_GL_RENDERBUFFER,
+                                 stencilRB);
+    }
+}
+
+bool
+GLContext::AssembleOffscreenFBs(const GLuint colorMSRB,
+                                const GLuint depthRB,
+                                const GLuint stencilRB,
+                                const GLuint texture,
+                                GLuint* drawFB_out,
+                                GLuint* readFB_out)
+{
     if (!colorMSRB && !texture) {
         MOZ_ASSERT(!depthRB && !stencilRB);
+
+        if (drawFB_out)
+            *drawFB_out = 0;
+        if (readFB_out)
+            *readFB_out = 0;
+
         return true;
     }
 
-    GLuint boundDrawFBO = GetUserBoundDrawFBO();
-    GLuint boundReadFBO = GetUserBoundReadFBO();
+    ScopedBindFramebuffer autoFB(this);
+
+    GLuint drawFB = 0;
+    GLuint readFB = 0;
 
     if (texture) {
-        fGenFramebuffers(1, &readFBO);
-        BindInternalFBO(readFBO);
+        readFB = 0;
+        fGenFramebuffers(1, &readFB);
+        BindFB(readFB);
         fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
                               LOCAL_GL_COLOR_ATTACHMENT0,
                               LOCAL_GL_TEXTURE_2D,
                               texture,
                               0);
     }
 
     if (colorMSRB) {
-        fGenFramebuffers(1, &drawFBO);
-        BindInternalFBO(drawFBO);
+        drawFB = 0;
+        fGenFramebuffers(1, &drawFB);
+        BindFB(drawFB);
         fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
                                  LOCAL_GL_COLOR_ATTACHMENT0,
                                  LOCAL_GL_RENDERBUFFER,
                                  colorMSRB);
     } else {
-        drawFBO = readFBO;
-        // drawFBO==readFBO is already bound from the 'if (texture)' block.
+        drawFB = readFB;
     }
+    MOZ_ASSERT(GetFB() == drawFB);
 
     if (depthRB) {
         fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
                                  LOCAL_GL_DEPTH_ATTACHMENT,
                                  LOCAL_GL_RENDERBUFFER,
                                  depthRB);
     }
 
@@ -1069,142 +1189,74 @@ GLContext::AssembleOffscreenFBOs(const G
                                  LOCAL_GL_RENDERBUFFER,
                                  stencilRB);
     }
 
     // We should be all resized.  Check for framebuffer completeness.
     GLenum status;
     bool isComplete = true;
 
-    BindInternalFBO(drawFBO);
-    status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
-    if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
+    if (!IsFramebufferComplete(drawFB, &status)) {
         NS_WARNING("DrawFBO: Incomplete");
   #ifdef DEBUG
         if (DebugMode()) {
             printf_stderr("Framebuffer status: %X\n", status);
         }
   #endif
         isComplete = false;
     }
 
-    BindInternalFBO(readFBO);
-    status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
-    if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
+    if (!IsFramebufferComplete(readFB, &status)) {
         NS_WARNING("ReadFBO: Incomplete");
   #ifdef DEBUG
         if (DebugMode()) {
             printf_stderr("Framebuffer status: %X\n", status);
         }
   #endif
         isComplete = false;
     }
 
-    BindUserDrawFBO(boundDrawFBO);
-    BindUserReadFBO(boundReadFBO);
+    if (drawFB_out) {
+        *drawFB_out = drawFB;
+    } else if (drawFB) {
+        NS_RUNTIMEABORT("drawFB created when not requested!");
+    }
+
+    if (readFB_out) {
+        *readFB_out = readFB;
+    } else if (readFB) {
+        NS_RUNTIMEABORT("readFB created when not requested!");
+    }
 
     return isComplete;
 }
 
+
+
 bool
-GLContext::ResizeOffscreenFBOs(const ContextFormat& aCF, const gfxIntSize& aSize, const bool aNeedsReadBuffer)
+GLContext::PublishFrame()
 {
-    // Early out for when we're rendering directly to the context's 'screen'.
-    if (!aNeedsReadBuffer && !aCF.samples)
-        return true;
-
-    MakeCurrent();
-    ContextFormat cf(aCF);
-    GLFormats formats = ChooseGLFormats(cf);
-
-    GLuint texture = 0;
-    if (aNeedsReadBuffer)
-        CreateTextureForOffscreen(formats, aSize, texture);
-
-    GLuint colorMSRB = 0;
-    GLuint depthRB = 0;
-    GLuint stencilRB = 0;
-    CreateRenderbuffersForOffscreen(formats, aSize, colorMSRB, depthRB, stencilRB);
-
-    GLuint drawFBO = 0;
-    GLuint readFBO = 0;
-    if (!AssembleOffscreenFBOs(colorMSRB, depthRB, stencilRB, texture,
-                               drawFBO, readFBO))
-    {
-        fDeleteFramebuffers(1, &drawFBO);
-        fDeleteFramebuffers(1, &readFBO);
-        fDeleteRenderbuffers(1, &colorMSRB);
-        fDeleteRenderbuffers(1, &depthRB);
-        fDeleteRenderbuffers(1, &stencilRB);
-        fDeleteTextures(1, &texture);
-
+    MOZ_ASSERT(mScreen);
+
+    if (!mScreen->PublishFrame(OffscreenSize()))
         return false;
-    }
-
-    // Success, so switch everything out.
-    // Store current user FBO bindings.
-    GLuint boundDrawFBO = GetUserBoundDrawFBO();
-    GLuint boundReadFBO = GetUserBoundReadFBO();
-
-    // Replace with the new hotness
-    std::swap(mOffscreenDrawFBO, drawFBO);
-    std::swap(mOffscreenReadFBO, readFBO);
-    std::swap(mOffscreenColorRB, colorMSRB);
-    std::swap(mOffscreenDepthRB, depthRB);
-    std::swap(mOffscreenStencilRB, stencilRB);
-    std::swap(mOffscreenTexture, texture);
-
-    // Delete the old and busted
-    fDeleteFramebuffers(1, &drawFBO);
-    fDeleteFramebuffers(1, &readFBO);
-    fDeleteRenderbuffers(1, &colorMSRB);
-    fDeleteRenderbuffers(1, &depthRB);
-    fDeleteRenderbuffers(1, &stencilRB);
-    fDeleteTextures(1, &texture);
-
-    // Rebind user FBOs, in case anything changed internally.
-    BindUserDrawFBO(boundDrawFBO);
-    BindUserReadFBO(boundReadFBO);
-
-    // Newly-created buffers are...unlikely to match.
-    ForceDirtyFBOs();
-
-    // Finish up.
-    mOffscreenSize = aSize;
-    mOffscreenActualSize = aSize;
-    mActualFormat = cf;
-
-    if (DebugMode()) {
-        printf_stderr("Resized %dx%d offscreen FBO: r: %d g: %d b: %d a: %d depth: %d stencil: %d samples: %d\n",
-                      mOffscreenActualSize.width, mOffscreenActualSize.height,
-                      mActualFormat.red, mActualFormat.green, mActualFormat.blue, mActualFormat.alpha,
-                      mActualFormat.depth, mActualFormat.stencil, mActualFormat.samples);
-    }
 
     return true;
 }
 
-void
-GLContext::DeleteOffscreenFBOs()
+SharedSurface*
+GLContext::RequestFrame()
 {
-    fDeleteFramebuffers(1, &mOffscreenDrawFBO);
-    fDeleteFramebuffers(1, &mOffscreenReadFBO);
-    fDeleteTextures(1, &mOffscreenTexture);
-    fDeleteRenderbuffers(1, &mOffscreenColorRB);
-    fDeleteRenderbuffers(1, &mOffscreenDepthRB);
-    fDeleteRenderbuffers(1, &mOffscreenStencilRB);
-
-    mOffscreenDrawFBO = 0;
-    mOffscreenReadFBO = 0;
-    mOffscreenTexture = 0;
-    mOffscreenColorRB = 0;
-    mOffscreenDepthRB = 0;
-    mOffscreenStencilRB = 0;
+    MOZ_ASSERT(mScreen);
+
+    return mScreen->Stream()->SwapConsumer();
 }
 
+
+
 void
 GLContext::ClearSafely()
 {
     // bug 659349 --- we must be very careful here: clearing a GL framebuffer is nontrivial, relies on a lot of state,
     // and in the case of the backbuffer of a WebGL context, state is exposed to scripts.
     //
     // The code here is taken from WebGLContext::ForceClearFramebufferWithDefaultValues, but I didn't find a good way of
     // sharing code with it. WebGL's code is somewhat performance-critical as it is typically called on every frame, so
@@ -1230,17 +1282,17 @@ GLContext::ClearSafely()
     fGetIntegerv(LOCAL_GL_STENCIL_BACK_WRITEMASK, &stencilWriteMaskBack);
     fGetFloatv(LOCAL_GL_COLOR_CLEAR_VALUE, colorClearValue);
     fGetFloatv(LOCAL_GL_DEPTH_CLEAR_VALUE, &depthClearValue);
     fGetIntegerv(LOCAL_GL_STENCIL_CLEAR_VALUE, &stencilClearValue);
 
     // prepare GL state for clearing
     fDisable(LOCAL_GL_SCISSOR_TEST);
     fDisable(LOCAL_GL_DITHER);
-    PushViewportRect(nsIntRect(0, 0, mOffscreenSize.width, mOffscreenSize.height));
+    PushViewportRect(nsIntRect(0, 0, OffscreenSize().width, OffscreenSize().height));
 
     fColorMask(1, 1, 1, 1);
     fClearColor(0.f, 0.f, 0.f, 0.f);
 
     fDepthMask(1);
     fClearDepth(1.0f);
 
     fStencilMask(0xffffffff);
@@ -1278,44 +1330,34 @@ GLContext::ClearSafely()
     if (scissorTestEnabled)
         fEnable(LOCAL_GL_SCISSOR_TEST);
     else
         fDisable(LOCAL_GL_SCISSOR_TEST);
 
 }
 
 void
-GLContext::UpdateActualFormat()
-{
-    ContextFormat nf;
-
-    fGetIntegerv(LOCAL_GL_RED_BITS, (GLint*) &nf.red);
-    fGetIntegerv(LOCAL_GL_GREEN_BITS, (GLint*) &nf.green);
-    fGetIntegerv(LOCAL_GL_BLUE_BITS, (GLint*) &nf.blue);
-    fGetIntegerv(LOCAL_GL_ALPHA_BITS, (GLint*) &nf.alpha);
-    fGetIntegerv(LOCAL_GL_DEPTH_BITS, (GLint*) &nf.depth);
-    fGetIntegerv(LOCAL_GL_STENCIL_BITS, (GLint*) &nf.stencil);
-
-    mActualFormat = nf;
-}
-
-void
 GLContext::MarkDestroyed()
 {
     if (IsDestroyed())
         return;
 
     if (MakeCurrent()) {
-        DeleteOffscreenFBOs();
+        DestroyScreenBuffer();
+
+        // This is for Blit{Tex,FB}To{TexFB}.
         DeleteTexBlitProgram();
 
+        // Likely used by OGL Layers.
         fDeleteProgram(mBlitProgram);
         mBlitProgram = 0;
         fDeleteFramebuffers(1, &mBlitFramebuffer);
         mBlitFramebuffer = 0;
+
+        mTexGarbageBin->GLContextTeardown();
     } else {
         NS_WARNING("MakeCurrent() failed during MarkDestroyed! Skipping GL object teardown.");
     }
 
     mSymbols.Zero();
 }
 
 static void SwapRAndBComponents(gfxImageSurface* surf)
@@ -1512,123 +1554,243 @@ GLContext::ReadTextureImage(GLuint aText
     fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, oldfb);
     fUseProgram(oldprog);
 
     PopViewportRect();
 
     return isurf.forget();
 }
 
-static void
-GetOptimalReadFormats(GLContext* gl, GLenum& format, GLenum& type) {
+static bool
+GetActualReadFormats(GLContext* gl, GLenum destFormat, GLenum destType,
+                     GLenum& readFormat, GLenum& readType)
+{
+    if (destFormat == LOCAL_GL_RGBA &&
+        destType == LOCAL_GL_UNSIGNED_BYTE)
+    {
+        readFormat = destFormat;
+        readType = destType;
+        return true;
+    }
+
+    bool fallback = true;
     if (gl->IsGLES2()) {
-        bool has_BGRA_UByte = false;
-        if (gl->IsExtensionSupported(gl::GLContext::EXT_bgra)) {
-          has_BGRA_UByte = true;
-        } else if (gl->IsExtensionSupported(gl::GLContext::EXT_read_format_bgra) ||
-                   gl->IsExtensionSupported(gl::GLContext::IMG_read_format)) {
-            // Note that these extensions are not required to query this value.
-            // However, we should never get back BGRA unless one of these is supported.
-            GLint auxFormat = 0;
-            GLint auxType = 0;
-
-            gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT, &auxFormat);
-            gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE, &auxType);
-
-            if (auxFormat == LOCAL_GL_BGRA && auxType == LOCAL_GL_UNSIGNED_BYTE)
-              has_BGRA_UByte = true;
+        GLenum auxFormat = 0;
+        GLenum auxType = 0;
+
+        gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT, (GLint*)&auxFormat);
+        gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE, (GLint*)&auxType);
+
+        if (destFormat == auxFormat &&
+            destType == auxType)
+        {
+            fallback = false;
         }
-
-        format = has_BGRA_UByte ? LOCAL_GL_BGRA : LOCAL_GL_RGBA;
-        type = LOCAL_GL_UNSIGNED_BYTE;
     } else {
-        // defaults for desktop
-        format = LOCAL_GL_BGRA;
-        type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
+        switch (destFormat) {
+            case LOCAL_GL_RGB: {
+                if (destType == LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV)
+                    fallback = false;
+                break;
+            }
+            case LOCAL_GL_BGRA: {
+                if (destType == LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV)
+                    fallback = false;
+                break;
+            }
+        }
+    }
+
+    if (fallback) {
+        readFormat = LOCAL_GL_RGBA;
+        readType = LOCAL_GL_UNSIGNED_BYTE;
+        return false;
+    } else {
+        readFormat = destFormat;
+        readType = destType;
+        return true;
     }
 }
 
 void
 GLContext::ReadScreenIntoImageSurface(gfxImageSurface* dest)
 {
-    GLuint boundFB = 0;
-    fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*)&boundFB);
-    fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
+    ScopedBindFramebuffer autoFB(this, 0);
 
     ReadPixelsIntoImageSurface(dest);
-
-    fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, boundFB);
 }
 
 void
 GLContext::ReadPixelsIntoImageSurface(gfxImageSurface* dest)
 {
-    MOZ_ASSERT(dest->Format() == gfxASurface::ImageFormatARGB32 ||
-               dest->Format() == gfxASurface::ImageFormatRGB24);
-
-    MOZ_ASSERT(dest->Stride() == dest->Width() * 4);
-    MOZ_ASSERT(dest->Format() == gfxASurface::ImageFormatARGB32 ||
-               dest->Format() == gfxASurface::ImageFormatRGB24);
-
-    MOZ_ASSERT(dest->Stride() == dest->Width() * 4);
-
     MakeCurrent();
+    MOZ_ASSERT(dest->GetSize() != gfxIntSize(0, 0));
+
+    /* ImageFormatARGB32:
+     * RGBA+UByte: be[RGBA], le[ABGR]
+     * RGBA+UInt: le[RGBA]
+     * BGRA+UInt: le[BGRA]
+     * BGRA+UIntRev: le[ARGB]
+     *
+     * ImageFormatRGB16_565:
+     * RGB+UShort: le[rrrrrggg,gggbbbbb]
+     */
+    bool hasAlpha = dest->Format() == gfxASurface::ImageFormatARGB32;
+
+    int destPixelSize;
+    GLenum destFormat;
+    GLenum destType;
+
+    switch (dest->Format()) {
+        case gfxASurface::ImageFormatRGB24: // XRGB
+        case gfxASurface::ImageFormatARGB32:
+            destPixelSize = 4;
+            // Needs host (little) endian ARGB.
+            destFormat = LOCAL_GL_BGRA;
+            destType = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
+            break;
+
+        case gfxASurface::ImageFormatRGB16_565:
+            destPixelSize = 2;
+            destFormat = LOCAL_GL_RGB;
+            destType = LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV;
+            break;
+
+        default:
+            MOZ_NOT_REACHED("Bad format.");
+            return;
+    }
+    MOZ_ASSERT(dest->Stride() == dest->Width() * destPixelSize);
+
+    GLenum readFormat = destFormat;
+    GLenum readType = destType;
+    bool needsTempSurf = !GetActualReadFormats(this,
+                                               destFormat, destType,
+                                               readFormat, readType);
+
+    nsAutoPtr<gfxImageSurface> tempSurf;
+    gfxImageSurface* readSurf = nullptr;
+    int readPixelSize = 0;
+    if (needsTempSurf) {
+        if (DebugMode()) {
+            NS_WARNING("Needing intermediary surface for ReadPixels. This will be slow!");
+        }
+        gfxASurface::gfxImageFormat readFormatGFX;
+
+        switch (readFormat) {
+            case LOCAL_GL_RGBA:
+            case LOCAL_GL_BGRA: {
+                readFormatGFX = hasAlpha ? gfxASurface::ImageFormatARGB32
+                                         : gfxASurface::ImageFormatRGB24;
+                break;
+            }
+            case LOCAL_GL_RGB: {
+                MOZ_ASSERT(readPixelSize == 2);
+                MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV);
+                readFormatGFX = gfxASurface::ImageFormatRGB16_565;
+                break;
+            }
+            default: {
+                MOZ_NOT_REACHED("Bad read format.");
+                return;
+            }
+        }
+
+        switch (readType) {
+            case LOCAL_GL_UNSIGNED_BYTE: {
+                MOZ_ASSERT(readFormat == LOCAL_GL_RGBA);
+                readPixelSize = 4;
+                break;
+            }
+            case LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV: {
+                MOZ_ASSERT(readFormat == LOCAL_GL_BGRA);
+                readPixelSize = 4;
+                break;
+            }
+            case LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV: {
+                MOZ_ASSERT(readFormat == LOCAL_GL_RGB);
+                readPixelSize = 2;
+                break;
+            }
+            default: {
+                MOZ_NOT_REACHED("Bad read type.");
+                return;
+            }
+        }
+
+        tempSurf = new gfxImageSurface(dest->GetSize(), readFormatGFX, false);
+        readSurf = tempSurf;
+    } else {
+        readPixelSize = destPixelSize;
+        readSurf = dest;
+    }
+    MOZ_ASSERT(readPixelSize);
 
     GLint currentPackAlignment = 0;
     fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &currentPackAlignment);
 
-    if (currentPackAlignment != 4)
-        fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4);
-
-    GLenum format;
-    GLenum datatype;
-    GetOptimalReadFormats(this, format, datatype);
+    if (currentPackAlignment != readPixelSize)
+        fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, readPixelSize);
 
     GLsizei width = dest->Width();
     GLsizei height = dest->Height();
 
+    readSurf->Flush();
     fReadPixels(0, 0,
                 width, height,
-                format, datatype,
-                dest->Data());
+                readFormat, readType,
+                readSurf->Data());
+    readSurf->MarkDirty();
+
+    if (currentPackAlignment != readPixelSize)
+        fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment);
+
+    if (readSurf != dest) {
+        MOZ_ASSERT(readFormat == LOCAL_GL_RGBA);
+        MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE);
+        // So we just copied in RGBA in big endian, or le: 0xAABBGGRR.
+        // We want 0xAARRGGBB, so swap R and B:
+        dest->Flush();
+        SwapRAndBComponents(readSurf);
+        dest->MarkDirty();
+
+        gfxContext ctx(dest);
+        ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
+        ctx.SetSource(readSurf);
+        ctx.Paint();
+    }
 
     // Check if GL is giving back 1.0 alpha for
     // RGBA reads to RGBA images from no-alpha buffers.
 #ifdef XP_MACOSX
     if (WorkAroundDriverBugs() &&
         mVendor == VendorNVIDIA &&
         dest->Format() == gfxASurface::ImageFormatARGB32 &&
         width && height)
     {
         GLint alphaBits = 0;
         fGetIntegerv(LOCAL_GL_ALPHA_BITS, &alphaBits);
         if (!alphaBits) {
             const uint32_t alphaMask = gfxPackedPixelNoPreMultiply(0xff,0,0,0);
 
+            dest->Flush();
             uint32_t* itr = (uint32_t*)dest->Data();
             uint32_t testPixel = *itr;
             if ((testPixel & alphaMask) != alphaMask) {
                 // We need to set the alpha channel to 1.0 manually.
                 uint32_t* itrEnd = itr + width*height;  // Stride is guaranteed to be width*4.
 
                 for (; itr != itrEnd; itr++) {
                     *itr |= alphaMask;
                 }
             }
+            dest->MarkDirty();
         }
     }
 #endif
-
-    // Output should be in BGRA, so swap if RGBA.
-    if (format == LOCAL_GL_RGBA) {
-        SwapRAndBComponents(dest);
-    }
-
-    if (currentPackAlignment != 4)
-        fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment);
 }
 
 void
 GLContext::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect,
                             TextureImage *aDst, const nsIntRect& aDstRect)
 {
     NS_ASSERTION(!aSrc->InUpdate(), "Source texture is in update!");
     NS_ASSERTION(!aDst->InUpdate(), "Destination texture is in update!");
@@ -1859,16 +2021,19 @@ GLContext::UploadSurfaceToTexture(gfxASu
         // If a pixel buffer is bound the data pointer parameter is relative
         // to the start of the data block.
         if (!aPixelBuffer) {
               data = imageSurface->Data();
         }
         data += DataOffset(imageSurface, aSrcPoint);
     }
 
+    MOZ_ASSERT(imageSurface);
+    imageSurface->Flush();
+
     GLenum format;
     GLenum type;
     int32_t pixelSize = gfxASurface::BytePerPixelFromFormat(imageSurface->Format());
     ShaderProgramType shader;
 
     switch (imageSurface->Format()) {
         case gfxASurface::ImageFormatARGB32:
             format = LOCAL_GL_RGBA;
@@ -2653,10 +2818,125 @@ GLContext::ReportOutstandingNames()
     ReportArrayContents("Outstanding Programs", mTrackedPrograms);
     ReportArrayContents("Outstanding Shaders", mTrackedShaders);
     ReportArrayContents("Outstanding Framebuffers", mTrackedFramebuffers);
     ReportArrayContents("Outstanding Renderbuffers", mTrackedRenderbuffers);
 }
 
 #endif /* DEBUG */
 
+
+void
+GLContext::GuaranteeResolve()
+{
+   mScreen->AssureBlitted();
+   fFinish();
+}
+
+const gfxIntSize&
+GLContext::OffscreenSize() const
+{
+    MOZ_ASSERT(IsOffscreen());
+    return mScreen->Size();
+}
+
+bool
+GLContext::CreateScreenBufferImpl(const gfxIntSize& size, const SurfaceCaps& caps)
+{
+    GLScreenBuffer* newScreen = GLScreenBuffer::Create(this, size, caps);
+    if (!newScreen)
+        return false;
+
+    if (!newScreen->PublishFrame(size)) {
+        delete newScreen;
+        return false;
+    }
+
+    DestroyScreenBuffer();
+
+    // This will rebind to 0 (Screen) if needed when
+    // it falls out of scope.
+    ScopedBindFramebuffer autoFB(this);
+
+    mScreen = newScreen;
+
+    return true;
+}
+
+bool
+GLContext::ResizeScreenBuffer(const gfxIntSize& size)
+{
+    if (!IsOffscreenSizeAllowed(size))
+        return false;
+
+    return mScreen->PublishFrame(size);
+}
+
+
+void
+GLContext::DestroyScreenBuffer()
+{
+    delete mScreen;
+    mScreen = nullptr;
+}
+
+void
+GLContext::ForceDirtyScreen()
+{
+    ScopedBindFramebuffer autoFB(0);
+
+    BeforeGLDrawCall();
+    // no-op; just pretend we did something
+    AfterGLDrawCall();
+}
+
+void
+GLContext::CleanDirtyScreen()
+{
+    ScopedBindFramebuffer autoFB(0);
+
+    BeforeGLReadCall();
+    // no-op; we just want to make sure the Read FBO is updated if it needs to be
+    AfterGLReadCall();
+}
+
+void
+GLContext::EmptyTexGarbageBin()
+{
+   TexGarbageBin()->EmptyGarbage();
+}
+
+
+void
+TextureGarbageBin::GLContextTeardown()
+{
+    EmptyGarbage();
+
+    MutexAutoLock lock(mMutex);
+    mGL = nullptr;
+}
+
+void
+TextureGarbageBin::Trash(GLuint tex)
+{
+    MutexAutoLock lock(mMutex);
+    if (!mGL)
+        return;
+
+    mGarbageTextures.push(tex);
+}
+
+void
+TextureGarbageBin::EmptyGarbage()
+{
+    MutexAutoLock lock(mMutex);
+    if (!mGL)
+        return;
+
+    while (!mGarbageTextures.empty()) {
+        GLuint tex = mGarbageTextures.top();
+        mGarbageTextures.pop();
+        mGL->fDeleteTextures(1, &tex);
+    }
+}
+
 } /* namespace gl */
 } /* namespace mozilla */
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -8,16 +8,18 @@
 
 #include <stdio.h>
 #include <algorithm>
 #if defined(XP_UNIX)
 #include <stdint.h>
 #endif
 #include <string.h>
 #include <ctype.h>
+#include <set>
+#include <stack>
 
 #ifdef WIN32
 #include <windows.h>
 #endif
 
 #include "GLDefs.h"
 #include "GLLibraryLoader.h"
 #include "gfxASurface.h"
@@ -31,143 +33,90 @@
 
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 #include "nsRegion.h"
 #include "nsAutoPtr.h"
 #include "nsThreadUtils.h"
 #include "GLContextTypes.h"
 #include "GLTextureImage.h"
+#include "SurfaceTypes.h"
+#include "GLScreenBuffer.h"
 
 typedef char realGLboolean;
 
 #include "GLContextSymbols.h"
 
 #include "mozilla/mozalloc.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/StandardInteger.h"
+#include "mozilla/Mutex.h"
 
 namespace android {
-class GraphicBuffer;
+    class GraphicBuffer;
 }
 
 namespace mozilla {
-  namespace layers {
-    class LayerManagerOGL;
-    class ColorTextureLayerProgram;
-  }
-
-namespace gl {
-class GLContext;
-
-typedef uintptr_t SharedTextureHandle;
-
-struct THEBES_API ContextFormat
-{
-    static const ContextFormat BasicRGBA32Format;
-
-    enum StandardContextFormat {
-        Empty,
-        BasicRGBA32,
-        StrictBasicRGBA32,
-        BasicRGB24,
-        StrictBasicRGB24,
-        BasicRGB16_565,
-        StrictBasicRGB16_565
-    };
-
-    ContextFormat() {
-        memset(this, 0, sizeof(ContextFormat));
+    namespace gfx {
+        class SharedSurface;
+        struct SurfaceCaps;
+    }
+
+    namespace gl {
+        class GLContext;
+        class GLLibraryEGL;
+        class GLScreenBuffer;
+        class TextureGarbageBin;
     }
 
-    ContextFormat(const StandardContextFormat cf) {
-        memset(this, 0, sizeof(ContextFormat));
-        switch (cf) {
-        case BasicRGBA32:
-            red = green = blue = alpha = 8;
-            minRed = minGreen = minBlue = minAlpha = 1;
-            break;
-
-        case StrictBasicRGBA32:
-            red = green = blue = alpha = 8;
-            minRed = minGreen = minBlue = minAlpha = 8;
-            break;
-
-        case BasicRGB24:
-            red = green = blue = 8;
-            minRed = minGreen = minBlue = 1;
-            break;
-
-        case StrictBasicRGB24:
-            red = green = blue = 8;
-            minRed = minGreen = minBlue = 8;
-            break;
-
-        case StrictBasicRGB16_565:
-            red = minRed = 5;
-            green = minGreen = 6;
-            blue = minBlue = 5;
-            break;
-
-        default:
-            break;
-        }
+    namespace layers {
+        class ColorTextureLayerProgram;
+        class LayerManagerOGL;
     }
-
-    int depth, minDepth;
-    int stencil, minStencil;
-    int red, minRed;
-    int green, minGreen;
-    int blue, minBlue;
-    int alpha, minAlpha;
-    int samples;
-
-    int colorBits() const { return red + green + blue; }
-};
+}
+
+namespace mozilla {
+namespace gl {
+typedef uintptr_t SharedTextureHandle;
 
 class GLContext
     : public GLLibraryLoader
 {
     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GLContext)
+
+protected:
+    typedef class gfx::SharedSurface SharedSurface;
+    typedef gfx::SharedSurfaceType SharedSurfaceType;
+
 public:
-    GLContext(const ContextFormat& aFormat,
-              bool aIsOffscreen = false,
-              GLContext *aSharedContext = nullptr)
+    typedef struct gfx::SurfaceCaps SurfaceCaps;
+
+    GLContext(const SurfaceCaps& caps,
+              GLContext* sharedContext = nullptr,
+              bool isOffscreen = false)
       : mTexBlit_Buffer(0),
         mTexBlit_VertShader(0),
         mTexBlit_FragShader(0),
         mTexBlit_Program(0),
         mTexBlit_UseDrawNotCopy(false),
-        mUserBoundDrawFBO(0),
-        mUserBoundReadFBO(0),
-        mInternalBoundDrawFBO(0),
-        mInternalBoundReadFBO(0),
-#ifdef DEBUG
-        mInInternalBindingMode_DrawFBO(true),
-        mInInternalBindingMode_ReadFBO(true),
-#endif
-        mOffscreenFBOsDirty(false),
         mInitialized(false),
-        mIsOffscreen(aIsOffscreen),
+        mIsOffscreen(isOffscreen),
         mIsGLES2(false),
         mIsGlobalSharedContext(false),
         mHasRobustness(false),
         mContextLost(false),
         mVendor(-1),
         mRenderer(-1),
-        mCreationFormat(aFormat),
-        mSharedContext(aSharedContext),
-        mOffscreenTexture(0),
+        mSharedContext(sharedContext),
         mFlipped(false),
         mBlitProgram(0),
         mBlitFramebuffer(0),
-        mOffscreenDrawFBO(0),
-        mOffscreenReadFBO(0),
-        mOffscreenColorRB(0),
-        mOffscreenDepthRB(0),
-        mOffscreenStencilRB(0),
+        mCaps(caps),
+        mScreen(nullptr),
+        mLockedSurface(nullptr),
         mMaxTextureSize(0),
         mMaxCubeMapTextureSize(0),
         mMaxTextureImageSize(0),
         mMaxRenderbufferSize(0),
         mNeedsTextureSizeChecks(false),
         mWorkAroundDriverBugs(true)
 #ifdef DEBUG
         , mGLError(LOCAL_GL_NO_ERROR)
@@ -288,23 +237,22 @@ public:
         // (that is, when the main thread is no longer get-able) can cause them
         // to leak. See Bug 741319, and Bug 744115.
         nsCOMPtr<nsIThread> mainThread;
         if (NS_SUCCEEDED(NS_GetMainThread(getter_AddRefs(mainThread)))) {
             mOwningThread->Dispatch(event, NS_DISPATCH_NORMAL);
         }
     }
 
-    const ContextFormat& CreationFormat() { return mCreationFormat; }
-    const ContextFormat& ActualFormat() { return mActualFormat; }
-
-    /**
-     * If this GL context has a D3D texture share handle, returns non-null.
-     */
-    virtual void *GetD3DShareHandle() { return nullptr; }
+    virtual EGLContext GetEGLContext() { return nullptr; }
+    virtual GLLibraryEGL* GetLibraryEGL() { return nullptr; }
+
+    virtual void MakeCurrent_EGLSurface(void* surf) {
+        MOZ_NOT_REACHED("Must be called against a GLContextEGL.");
+    }
 
     /**
      * If this context is double-buffered, returns TRUE.
      */
     virtual bool IsDoubleBuffered() { return false; }
 
     /**
      * If this context is the GLES2 API, returns TRUE.
@@ -406,86 +354,41 @@ public:
 
     virtual bool BindExternalBuffer(GLuint texture, void* buffer) { return false; }
     virtual bool UnbindExternalBuffer(GLuint texture) { return false; }
 
     virtual already_AddRefed<TextureImage>
     CreateDirectTextureImage(android::GraphicBuffer* aBuffer, GLenum aWrapMode)
     { return nullptr; }
 
-    /*
-     * Offscreen support API
-     */
-
-    /*
-     * Bind aOffscreen's color buffer as a texture to the TEXTURE_2D
-     * target.  Returns TRUE on success, otherwise FALSE.  If
-     * aOffscreen is not an offscreen context, returns FALSE.  If
-     * BindOffscreenNeedsTexture() returns TRUE, then you should have
-     * a 2D texture name bound whose image will be replaced by the
-     * contents of the offscreen context.  If it returns FALSE,
-     * the current 2D texture binding will be replaced.
-     *
-     * After a successul call to BindTex2DOffscreen, UnbindTex2DOffscreen
-     * *must* be called once rendering is complete.
-     *
-     * The same texture unit must be active for Bind/Unbind of a given
-     * context.
-     */
-    virtual bool BindOffscreenNeedsTexture(GLContext *aOffscreen) {
-        return aOffscreen->mOffscreenTexture == 0;
-    }
-
-    virtual bool BindTex2DOffscreen(GLContext *aOffscreen) {
-        if (aOffscreen->GetContextType() != GetContextType()) {
-          return false;
-        }
-
-        if (!aOffscreen->mSharedContext ||
-            aOffscreen->mSharedContext != mSharedContext)
-        {
-            return false;
-        }
-
-        if (!aOffscreen->mOffscreenTexture) {
-            return false;
-        }
-
-        fBindTexture(LOCAL_GL_TEXTURE_2D, aOffscreen->mOffscreenTexture);
-
-        return true;
-    }
-
-    virtual void UnbindTex2DOffscreen(GLContext *aOffscreen) { }
-
-    bool IsOffscreen() {
-        return mIsOffscreen;
-    }
-    
     // Before reads from offscreen texture
-    void GuaranteeResolve() {
-        BlitDirtyFBOs();
-        fFinish();
-    }
+    void GuaranteeResolve();
 
 protected:
     GLuint mTexBlit_Buffer;
     GLuint mTexBlit_VertShader;
     GLuint mTexBlit_FragShader;
     GLuint mTexBlit_Program;
 
     bool mTexBlit_UseDrawNotCopy;
 
     bool UseTexQuadProgram();
     void DeleteTexBlitProgram();
 
 public:
+    // If you don't have |srcFormats| for the 2nd definition,
+    // then you'll need the framebuffer_blit extensions to use
+    // the first BlitFramebufferToFramebuffer.
     void BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
                                       const gfxIntSize& srcSize,
                                       const gfxIntSize& destSize);
+    void BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
+                                      const gfxIntSize& srcSize,
+                                      const gfxIntSize& destSize,
+                                      const GLFormats& srcFormats);
     void BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
                                   const gfxIntSize& srcSize,
                                   const gfxIntSize& destSize);
     void BlitFramebufferToTexture(GLuint srcFB, GLuint destTex,
                                   const gfxIntSize& srcSize,
                                   const gfxIntSize& destSize);
     void BlitTextureToTexture(GLuint srcTex, GLuint destTex,
                               const gfxIntSize& srcSize,
@@ -494,63 +397,35 @@ public:
     /*
      * Resize the current offscreen buffer.  Returns true on success.
      * If it returns false, the context should be treated as unusable
      * and should be recreated.  After the resize, the viewport is not
      * changed; glViewport should be called as appropriate.
      *
      * Only valid if IsOffscreen() returns true.
      */
-    virtual bool ResizeOffscreen(const gfxIntSize& aNewSize) {
-        if (mOffscreenDrawFBO || mOffscreenReadFBO)
-            return ResizeOffscreenFBOs(aNewSize, mOffscreenReadFBO != 0);
-        return false;
+    virtual bool ResizeOffscreen(const gfxIntSize& size) {
+        return ResizeScreenBuffer(size);
     }
 
     /*
      * Return size of this offscreen context.
      *
      * Only valid if IsOffscreen() returns true.
      */
-    gfxIntSize OffscreenSize() {
-        return mOffscreenSize;
-    }
-
-    /*
-     * In some cases, we have to allocate a bigger offscreen buffer
-     * than what's requested.  This is the bigger size.
-     *
-     * Only valid if IsOffscreen() returns true.
-     */
-    gfxIntSize OffscreenActualSize() {
-        return mOffscreenActualSize;
+    const gfxIntSize& OffscreenSize() const;
+
+    virtual bool SupportsFramebufferMultisample() const {
+        return IsExtensionSupported(EXT_framebuffer_multisample) ||
+               IsExtensionSupported(ANGLE_framebuffer_multisample);
     }
 
-    /*
-     * If this context is FBO-backed, return the FBO or the color
-     * buffer texture.  If the context is not FBO-backed, 0 is
-     * returned (which is also a valid FBO binding).
-     *
-     * Only valid if IsOffscreen() returns true.
-     */
-    GLuint GetOffscreenFBO() {
-        // 0 is interpreted as (off)screen, whether for read or draw operations
-        return 0;
-    }
-
-    GLuint GetOffscreenTexture() {
-        return mOffscreenTexture;
-    }
-
-    virtual bool SupportsFramebufferMultisample() {
-        return IsExtensionSupported(EXT_framebuffer_multisample) || IsExtensionSupported(ANGLE_framebuffer_multisample);
-    }
-
-    virtual bool SupportsOffscreenSplit() {
-        return IsExtensionSupported(EXT_framebuffer_blit) || IsExtensionSupported(ANGLE_framebuffer_blit);
+    virtual bool SupportsSplitFramebuffer() {
+        return IsExtensionSupported(EXT_framebuffer_blit) ||
+               IsExtensionSupported(ANGLE_framebuffer_blit);
     }
 
 
     enum SharedTextureShareType {
         SameProcess = 0,
         CrossProcess
     };
 
@@ -626,269 +501,121 @@ public:
 
     /**
      * Detach Shared GL Handle from GL_TEXTURE_2D target
      */
     virtual void DetachSharedHandle(SharedTextureShareType shareType,
                                     SharedTextureHandle sharedHandle)
     { }
 
-private:
-    GLuint mUserBoundDrawFBO;
-    GLuint mUserBoundReadFBO;
-    GLuint mInternalBoundDrawFBO;
-    GLuint mInternalBoundReadFBO;
-
-public:
     void fBindFramebuffer(GLenum target, GLuint framebuffer) {
+        if (!mScreen) {
+            raw_fBindFramebuffer(target, framebuffer);
+            return;
+        }
+
         switch (target) {
-          case LOCAL_GL_DRAW_FRAMEBUFFER_EXT:
-            mUserBoundDrawFBO = framebuffer;
-
-            if (framebuffer == 0) {
-                mInternalBoundDrawFBO = mOffscreenDrawFBO;
-            } else {
-                mInternalBoundDrawFBO = mUserBoundDrawFBO;
-            }
-
-            raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT,
-                                 mInternalBoundDrawFBO);
-            break;
-
-          case LOCAL_GL_READ_FRAMEBUFFER_EXT:
-            mUserBoundReadFBO = framebuffer;
-
-            if (framebuffer == 0) {
-                mInternalBoundReadFBO = mOffscreenReadFBO;
-            } else {
-                mInternalBoundReadFBO = mUserBoundReadFBO;
-            }
-
-            raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT,
-                                 mInternalBoundReadFBO);
-            break;
-
-          case LOCAL_GL_FRAMEBUFFER:
-            mUserBoundDrawFBO = mUserBoundReadFBO = framebuffer;
-
-            if (framebuffer == 0) {
-                mInternalBoundDrawFBO = mOffscreenDrawFBO;
-                mInternalBoundReadFBO = mOffscreenReadFBO;
-            } else {
-                mInternalBoundDrawFBO = mUserBoundDrawFBO;
-                mInternalBoundReadFBO = mUserBoundReadFBO;
-            }
-
-            if (SupportsOffscreenSplit()) {
-                raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT,
-                                     mInternalBoundDrawFBO);
-                raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT,
-                                     mInternalBoundReadFBO);
-            } else {
-                raw_fBindFramebuffer(LOCAL_GL_FRAMEBUFFER,
-                                     mInternalBoundDrawFBO);
-            }
-
-            break;
-
-          default:
-            raw_fBindFramebuffer(target, framebuffer);
-            break;
-        }
+            case LOCAL_GL_DRAW_FRAMEBUFFER_EXT:
+                mScreen->BindDrawFB(framebuffer);
+                return;
+
+            case LOCAL_GL_READ_FRAMEBUFFER_EXT:
+                mScreen->BindReadFB(framebuffer);
+                return;
+
+            case LOCAL_GL_FRAMEBUFFER:
+                 mScreen->BindFB(framebuffer);
+                 return;
+
+            default:
+                // Nothing we care about, likely an error.
+                break;
+       }
+
+        raw_fBindFramebuffer(target, framebuffer);
+    }
+
+    void BindFB(GLuint fb) {
+        fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb);
+        MOZ_ASSERT(!fb || fIsFramebuffer(fb));
+    }
+
+    void BindDrawFB(GLuint fb) {
+        fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, fb);
+    }
+
+    void BindReadFB(GLuint fb) {
+        fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, fb);
     }
 
     void fGetIntegerv(GLenum pname, GLint *params) {
+        if (!mScreen) {
+            raw_fGetIntegerv(pname, params);
+            return;
+        }
+
         switch (pname)
         {
             // LOCAL_GL_FRAMEBUFFER_BINDING is equal to
-            // LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, so we don't need two
-            // cases.
-            case LOCAL_GL_FRAMEBUFFER_BINDING:
-                *params = GetUserBoundDrawFBO();
+            // LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT,
+            // so we don't need two cases.
+            case LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT:
+                *params = mScreen->GetDrawFB();
                 break;
 
             case LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT:
-                *params = GetUserBoundReadFBO();
-                break;
-
-            case LOCAL_GL_MAX_TEXTURE_SIZE:
-                *params = mMaxTextureSize;
-                break;
-
-            case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE:
-                *params = mMaxCubeMapTextureSize;
-                break;
-
-            case LOCAL_GL_MAX_RENDERBUFFER_SIZE:
-                *params = mMaxRenderbufferSize;
+                *params = mScreen->GetReadFB();
                 break;
 
             default:
                 raw_fGetIntegerv(pname, params);
                 break;
         }
     }
 
-#ifdef DEBUG
-    // See comment near BindInternalDrawFBO()
-    bool mInInternalBindingMode_DrawFBO;
-    bool mInInternalBindingMode_ReadFBO;
-#endif
-
-    GLuint GetUserBoundDrawFBO() {
-#ifdef DEBUG
-        MOZ_ASSERT(IsCurrent());
-
-        GLint ret = 0;
-        // Don't need a branch here, because:
-        // LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT == LOCAL_GL_FRAMEBUFFER_BINDING == 0x8CA6
-        // We use raw_ here because this is debug code and we need to see what
-        // the driver thinks.
-        raw_fGetIntegerv(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, &ret);
-
-        bool abort = false;
-
-        if (mInInternalBindingMode_DrawFBO) {
-            NS_ERROR("Draw FBO still bound internally!");
-            printf_stderr("Current internal draw FBO: %d, user: %d)\n", ret, mUserBoundDrawFBO);
-            abort = true;
-        }
-
-        if (mInternalBoundDrawFBO != (GLuint)ret) {
-            NS_ERROR("Draw FBO binding misprediction!");
-            printf_stderr("Bound draw FBO was: %d, Expected: %d\n", ret, mInternalBoundDrawFBO);
-            abort = true;
-        }
-
-        if (abort)
-            NS_ABORT();
-#endif
-
-        // We only ever expose the user's bound FBOs
-        return mUserBoundDrawFBO;
+    GLuint GetDrawFB() {
+        if (mScreen)
+            return mScreen->GetDrawFB();
+
+        GLuint ret = 0;
+        GetUIntegerv(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, &ret);
+        return ret;
     }
 
-    GLuint GetUserBoundReadFBO() {
-#ifdef DEBUG
-        MOZ_ASSERT(IsCurrent());
-
-        GLint ret = 0;
-        // We use raw_ here because this is debug code and we need to see what
-        // the driver thinks.
-        if (SupportsOffscreenSplit())
-            raw_fGetIntegerv(LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT, &ret);
-        else
-            raw_fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &ret);
-
-        bool abort = false;
-
-        if (mInInternalBindingMode_ReadFBO) {
-            NS_ERROR("Read FBO still bound internally!");
-            printf_stderr("Current internal read FBO: %d, user: %d)\n", ret, mUserBoundReadFBO);
-            abort = true;
-        }
-
-        if (mInternalBoundReadFBO != (GLuint)ret) {
-            NS_ERROR("Read FBO binding misprediction!");
-            printf_stderr("Bound read FBO was: %d, Expected: %d\n", ret, mInternalBoundReadFBO);
-            abort = true;
+    GLuint GetReadFB() {
+        if (mScreen)
+            return mScreen->GetReadFB();
+
+        GLenum bindEnum = SupportsSplitFramebuffer() ? LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT
+                                                     : LOCAL_GL_FRAMEBUFFER_BINDING;
+
+        GLuint ret = 0;
+        GetUIntegerv(bindEnum, &ret);
+        return ret;
+    }
+
+    GLuint GetFB() {
+        if (mScreen) {
+            // This has a very important extra assert that checks that we're
+            // not accidentally ignoring a situation where the draw and read
+            // FBs differ.
+            return mScreen->GetFB();
         }
 
-        if (abort)
-            NS_ABORT();
-#endif
-
-        // We only ever expose the user's bound FBOs
-        return mUserBoundReadFBO;
-    }
-
-    void BindUserDrawFBO(GLuint name) {
-        if (SupportsOffscreenSplit())
-            fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, name);
-        else
-            fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, name);
-#ifdef DEBUG
-        mInInternalBindingMode_DrawFBO = false;
-#endif
-    }
-
-    void BindUserReadFBO(GLuint name) {
-        if (SupportsOffscreenSplit())
-            fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, name);
-        else
-            fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, name);
-#ifdef DEBUG
-        mInInternalBindingMode_ReadFBO = false;
-#endif
-    }
-
-    GLuint GetUserBoundFBO() {
-        MOZ_ASSERT(GetUserBoundDrawFBO() == GetUserBoundReadFBO());
-        return GetUserBoundReadFBO();
-    }
-
-    void BindUserFBO(GLuint name) {
-        fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, name);
-    }
-
-    // BindInternalDraw/ReadFBO() switch us over into 'internal binding mode'
-    //   for the corresponding Draw or Read binding.
-    // To exit internal binding mode, use BindUserDraw/ReadFBO().
-    // While in internal binding mode for Draw/Read, the corresponding
-    //   GetBoundUserDraw/ReadFBO() is undefined, and will trigger ABORT in DEBUG builds.
-    void BindInternalDrawFBO(GLuint name) {
-#ifdef DEBUG
-        mInInternalBindingMode_DrawFBO = true;
-#endif
-        if (SupportsOffscreenSplit())
-            raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, name);
-        else
-            raw_fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, name);
-
-        mInternalBoundDrawFBO = name;
-    }
-
-    void BindInternalReadFBO(GLuint name) {
-#ifdef DEBUG
-        mInInternalBindingMode_ReadFBO = true;
-#endif
-        if (SupportsOffscreenSplit())
-            raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, name);
-        else
-            raw_fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, name);
-
-        mInternalBoundReadFBO = name;
-    }
-
-    void BindInternalFBO(GLuint name) {
-        BindInternalDrawFBO(name);
-        BindInternalReadFBO(name);
+        GLuint ret = 0;
+        GetUIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &ret);
+        return ret;
     }
 
     void InitFramebuffers() {
         MakeCurrent();
-        BindUserDrawFBO(0);
-        BindUserReadFBO(0);
-    }
-
-    GLuint SwapUserDrawFBO(GLuint name) {
-        GLuint prev = GetUserBoundDrawFBO();
-        BindUserDrawFBO(name);
-        return prev;
-    }
-
-    GLuint SwapUserReadFBO(GLuint name) {
-        GLuint prev = GetUserBoundReadFBO();
-        BindUserReadFBO(name);
-        return prev;
+        BindFB(0);
     }
 
 private:
-    bool mOffscreenFBOsDirty;
-
     void GetShaderPrecisionFormatNonES2(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
         switch (precisiontype) {
             case LOCAL_GL_LOW_FLOAT:
             case LOCAL_GL_MEDIUM_FLOAT:
             case LOCAL_GL_HIGH_FLOAT:
                 // Assume IEEE 754 precision
                 range[0] = 127;
                 range[1] = 127;
@@ -904,73 +631,30 @@ private:
                 *precision = 0;
                 break;
         }
     }
 
     // Do whatever setup is necessary to draw to our offscreen FBO, if it's
     // bound.
     void BeforeGLDrawCall() {
-        if (mInternalBoundDrawFBO != mOffscreenDrawFBO)
-            return;
-
-        if (mOffscreenDrawFBO == mOffscreenReadFBO)
-            return;
-
-        mOffscreenFBOsDirty = true;
     }
 
     // Do whatever tear-down is necessary after drawing to our offscreen FBO,
     // if it's bound.
     void AfterGLDrawCall() {
+        if (mScreen)
+            mScreen->AfterDrawCall();
     }
 
     // Do whatever setup is necessary to read from our offscreen FBO, if it's
     // bound.
     void BeforeGLReadCall() {
-        if (mInternalBoundReadFBO != mOffscreenReadFBO)
-            return;
-
-        if (mOffscreenDrawFBO == mOffscreenReadFBO)
-            return;
-
-        // If we're not dirty, there's no need to blit
-        if (!mOffscreenFBOsDirty)
-            return;
-
-        const bool scissor = fIsEnabled(LOCAL_GL_SCISSOR_TEST);
-        if (scissor)
-            fDisable(LOCAL_GL_SCISSOR_TEST);
-
-        // Store current bindings for restoring later
-        GLuint prevDraw = GetUserBoundDrawFBO();
-        GLuint prevRead = GetUserBoundReadFBO();
-
-        NS_ABORT_IF_FALSE(SupportsOffscreenSplit(), "Doesn't support offscreen split?");
-
-        // Manually setting internal bindings, entering internal mode
-        // Flip read/draw for blitting
-        BindInternalDrawFBO(mOffscreenReadFBO);
-        BindInternalReadFBO(mOffscreenDrawFBO);
-
-        GLint width = mOffscreenActualSize.width;
-        GLint height = mOffscreenActualSize.height;
-        raw_fBlitFramebuffer(0, 0, width, height,
-                             0, 0, width, height,
-                             LOCAL_GL_COLOR_BUFFER_BIT,
-                             LOCAL_GL_NEAREST);
-
-        // Reset to emulated user binding, exiting internal mode
-        BindUserDrawFBO(prevDraw);
-        BindUserReadFBO(prevRead);
-
-        if (scissor)
-            fEnable(LOCAL_GL_SCISSOR_TEST);
-
-        mOffscreenFBOsDirty = false;
+        if (mScreen)
+            mScreen->BeforeReadCall();
     }
 
     // Do whatever tear-down is necessary after reading from our offscreen FBO,
     // if it's bound.
     void AfterGLReadCall() {
     }
 
 public:
@@ -1024,35 +708,18 @@ public:
         y = FixYValue(y, height);
 
         BeforeGLReadCall();
         raw_fCopyTexSubImage2D(target, level, xoffset, yoffset,
                                x, y, width, height);
         AfterGLReadCall();
     }
 
-    void ForceDirtyFBOs() {
-        GLuint draw = SwapUserDrawFBO(0);
-
-        BeforeGLDrawCall();
-        // no-op; just pretend we did something
-        AfterGLDrawCall();
-
-        BindUserDrawFBO(draw);
-    }
-
-    void BlitDirtyFBOs() {
-        GLuint read = SwapUserReadFBO(0);
-
-        BeforeGLReadCall();
-        // no-op; we just want to make sure the Read FBO is updated if it needs to be
-        AfterGLReadCall();
-
-        BindUserReadFBO(read);
-    }
+    void ForceDirtyScreen();
+    void CleanDirtyScreen();
 
     // Draw/Read
     void fBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
         BeforeGLDrawCall();
         BeforeGLReadCall();
         raw_fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
         AfterGLReadCall();
         AfterGLDrawCall();
@@ -1419,16 +1086,21 @@ public:
         CONTEXT_INNOCENT_CONTEXT_RESET_ARB = 0x8254,
         CONTEXT_UNKNOWN_CONTEXT_RESET_ARB = 0x8255
     };
 
     bool HasRobustness() {
         return mHasRobustness;
     }
 
+    bool HasExt_FramebufferBlit() {
+        return IsExtensionSupported(EXT_framebuffer_blit) ||
+               IsExtensionSupported(ANGLE_framebuffer_blit);
+    }
+
 protected:
     bool mInitialized;
     bool mIsOffscreen;
     bool mIsGLES2;
     bool mIsGlobalSharedContext;
     bool mHasRobustness;
     bool mContextLost;
 
@@ -1448,128 +1120,214 @@ public:
 #ifdef DEBUG
         return sDebugMode;
 #else
         return 0;
 #endif
     }
 
 protected:
-
-    ContextFormat mCreationFormat;
     nsRefPtr<GLContext> mSharedContext;
 
     // The thread on which this context was created.
     nsCOMPtr<nsIThread> mOwningThread;
 
     GLContextSymbols mSymbols;
 
 #ifdef DEBUG
     // GLDebugMode will check that we don't send call
     // to a GLContext that isn't current on the current
     // thread.
     // Store the current context when binding to thread local
     // storage to support DebugMode on an arbitrary thread.
     static unsigned sCurrentGLContextTLS;
 #endif
-
-    void UpdateActualFormat();
-    ContextFormat mActualFormat;
-
-    gfxIntSize mOffscreenSize;
-    gfxIntSize mOffscreenActualSize;
-    GLuint mOffscreenTexture;
     bool mFlipped;
 
     // lazy-initialized things
     GLuint mBlitProgram, mBlitFramebuffer;
     void UseBlitProgram();
     void SetBlitFramebufferForDestTexture(GLuint aTexture);
 
-    // Helper to create/resize an offscreen FBO,
-    // for offscreen implementations that use FBOs.
+public:
+    // Assumes shares are created by all sharing with the same global context.
+    bool SharesWith(const GLContext* other) const {
+        MOZ_ASSERT(!this->mSharedContext || !this->mSharedContext->mSharedContext);
+        MOZ_ASSERT(!other->mSharedContext || !other->mSharedContext->mSharedContext);
+        MOZ_ASSERT(!this->mSharedContext ||
+                   !other->mSharedContext ||
+                   this->mSharedContext == other->mSharedContext);
+
+        const GLContext* thisShared = this->mSharedContext ? this->mSharedContext
+                                                           : this;
+        const GLContext* otherShared = other->mSharedContext ? other->mSharedContext
+                                                             : other;
+
+        return thisShared == otherShared;
+    }
+
+    bool InitOffscreen(const gfxIntSize& size, const SurfaceCaps& caps) {
+        if (!CreateScreenBuffer(size, caps))
+            return false;
+
+        InitFramebuffers();
+
+        mCaps = mScreen->Caps();
+        UpdateGLFormats(caps);
+        UpdatePixelFormat();
+
+        return true;
+    }
+
+protected:
     // Note that it does -not- clear the resized buffers.
-    bool ResizeOffscreenFBOs(const ContextFormat& aCF, const gfxIntSize& aSize, const bool aNeedsReadBuffer);
-    bool ResizeOffscreenFBOs(const gfxIntSize& aSize, const bool aNeedsReadBuffer) {
-        if (!IsOffscreenSizeAllowed(aSize))
+    bool CreateScreenBuffer(const gfxIntSize& size, const SurfaceCaps& caps) {
+        if (!IsOffscreenSizeAllowed(size))
             return false;
 
-        ContextFormat format(mCreationFormat);
-
-        if (format.samples) {
+        SurfaceCaps tryCaps = caps;
+        if (tryCaps.antialias) {
             // AA path
-            if (ResizeOffscreenFBOs(format, aSize, aNeedsReadBuffer))
+            if (CreateScreenBufferImpl(size, tryCaps))
                 return true;
 
-            NS_WARNING("ResizeOffscreenFBOs failed to resize an AA context! Falling back to no AA...");
-            format.samples = 0;
+            NS_WARNING("CreateScreenBuffer failed to initialize an AA context! Falling back to no AA...");
+            tryCaps.antialias = false;
         }
-
-        if (ResizeOffscreenFBOs(format, aSize, aNeedsReadBuffer))
+        MOZ_ASSERT(!tryCaps.antialias);
+
+        if (CreateScreenBufferImpl(size, tryCaps))
             return true;
 
-        NS_WARNING("ResizeOffscreenFBOs failed to resize non-AA context!");
+        NS_WARNING("CreateScreenBuffer failed to initialize non-AA context!");
         return false;
     }
 
-    struct GLFormats {
-        GLFormats()
-            : texColor(0)
-            , texColorType(0)
-            , rbColor(0)
-            , depthStencil(0)
-            , depth(0)
-            , stencil(0)
-            , samples(0)
-        {}
-
-        GLenum texColor;
-        GLenum texColorType;
-        GLenum rbColor;
-        GLenum depthStencil;
-        GLenum depth;
-        GLenum stencil;
-        GLsizei samples;
-    };
-
-    enum ColorByteOrder {
-      ForceRGBA,
-      DefaultByteOrder
-    };
-
-    GLFormats ChooseGLFormats(ContextFormat& aCF, GLContext::ColorByteOrder aByteOrder = GLContext::DefaultByteOrder);
-    void CreateTextureForOffscreen(const GLFormats& aFormats, const gfxIntSize& aSize,
-                                   GLuint& texture);
-    void CreateRenderbuffersForOffscreen(const GLContext::GLFormats& aFormats, const gfxIntSize& aSize,
-                                         GLuint& colorMSRB, GLuint& depthRB, GLuint& stencilRB);
-    bool AssembleOffscreenFBOs(const GLuint colorMSRB,
-                               const GLuint depthRB,
-                               const GLuint stencilRB,
-                               const GLuint texture,
-                               GLuint& drawFBO,
-                               GLuint& readFBO);
-
-    void DeleteOffscreenFBOs();
-
-    GLuint mOffscreenDrawFBO;
-    GLuint mOffscreenReadFBO;
-    GLuint mOffscreenColorRB;
-    GLuint mOffscreenDepthRB;
-    GLuint mOffscreenStencilRB;
-
-    // Clear to transparent black, with 0 depth and stencil,
-    // while preserving current ClearColor etc. values.
-    // Useful for resizing offscreen buffers.
+    bool CreateScreenBufferImpl(const gfxIntSize& size,
+                                const SurfaceCaps& caps);
+
+public:
+    bool ResizeScreenBuffer(const gfxIntSize& size);
+
+protected:
+    SurfaceCaps mCaps;
+    nsAutoPtr<GLFormats> mGLFormats;
+    nsAutoPtr<PixelBufferFormat> mPixelFormat;
+
 public:
+    void DetermineCaps();
+    const SurfaceCaps& Caps() const {
+        return mCaps;
+    }
+
+    // Only varies based on bpp16 and alpha.
+    GLFormats ChooseGLFormats(const SurfaceCaps& caps) const;
+    void UpdateGLFormats(const SurfaceCaps& caps) {
+        mGLFormats = new GLFormats(ChooseGLFormats(caps));
+    }
+
+    const GLFormats& GetGLFormats() const {
+        MOZ_ASSERT(mGLFormats);
+        return *mGLFormats;
+    }
+
+    PixelBufferFormat QueryPixelFormat();
+    void UpdatePixelFormat();
+
+    const PixelBufferFormat& GetPixelFormat() const {
+        MOZ_ASSERT(mPixelFormat);
+        return *mPixelFormat;
+    }
+
+
+    GLuint CreateTextureForOffscreen(const GLFormats& formats,
+                                     const gfxIntSize& size);
+    GLuint CreateTexture(GLenum internalFormat,
+                         GLenum format, GLenum type,
+                         const gfxIntSize& size);
+    GLuint CreateRenderbuffer(GLenum format,
+                              GLsizei samples,
+                              const gfxIntSize& size);
+    bool IsFramebufferComplete(GLuint fb, GLenum* status = nullptr);
+
+    // Pass null to an RB arg to disable its creation.
+    void CreateRenderbuffersForOffscreen(const GLFormats& formats,
+                                         const gfxIntSize& size,
+                                         bool multisample,
+                                         GLuint* colorMSRB,
+                                         GLuint* depthRB,
+                                         GLuint* stencilRB);
+
+    // Does not check completeness.
+    void AttachBuffersToFB(GLuint colorTex, GLuint colorRB,
+                           GLuint depthRB, GLuint stencilRB,
+                           GLuint fb);
+
+    // Passing null is fine if the value you'd get is 0.
+    bool AssembleOffscreenFBs(const GLuint colorMSRB,
+                              const GLuint depthRB,
+                              const GLuint stencilRB,
+                              const GLuint texture,
+                              GLuint* drawFB,
+                              GLuint* readFB);
+
+protected:
+    friend class GLScreenBuffer;
+    GLScreenBuffer* mScreen;
+
+    void DestroyScreenBuffer();
+
+    SharedSurface* mLockedSurface;
+
+public:
+    void LockSurface(SharedSurface* surf) {
+        MOZ_ASSERT(!mLockedSurface);
+        mLockedSurface = surf;
+    }
+
+    void UnlockSurface(SharedSurface* surf) {
+        MOZ_ASSERT(mLockedSurface == surf);
+        mLockedSurface = nullptr;
+    }
+
+    SharedSurface* GetLockedSurface() const {
+        return mLockedSurface;
+    }
+
+    bool IsOffscreen() const {
+        return mScreen;
+    }
+
+    GLScreenBuffer* Screen() const {
+        return mScreen;
+    }
+
+    bool PublishFrame();
+    SharedSurface* RequestFrame();
+
+    /* Clear to transparent black, with 0 depth and stencil,
+     * while preserving current ClearColor etc. values.
+     * Useful for resizing offscreen buffers.
+     */
     void ClearSafely();
 
     bool WorkAroundDriverBugs() const { return mWorkAroundDriverBugs; }
 
 protected:
-
+    nsRefPtr<TextureGarbageBin> mTexGarbageBin;
+
+public:
+    TextureGarbageBin* TexGarbageBin() {
+        MOZ_ASSERT(mTexGarbageBin);
+        return mTexGarbageBin;
+    }
+
+    void EmptyTexGarbageBin();
+
+protected:
     nsDataHashtable<nsPtrHashKey<void>, void*> mUserData;
 
     void SetIsGLES2(bool aIsGLES2) {
         NS_ASSERTION(!mInitialized, "SetIsGLES2 can only be called before initialization!");
         mIsGLES2 = aIsGLES2;
     }
 
     bool InitWithPrefix(const char *prefix, bool trygl);
@@ -1592,16 +1350,17 @@ protected:
 
     nsTArray<nsIntRect> mViewportStack;
     nsTArray<nsIntRect> mScissorStack;
 
     GLint mMaxTextureSize;
     GLint mMaxCubeMapTextureSize;
     GLint mMaxTextureImageSize;
     GLint mMaxRenderbufferSize;
+    GLsizei mMaxSamples;
     bool mNeedsTextureSizeChecks;
     bool mWorkAroundDriverBugs;
 
     bool IsTextureSizeSafeToPassToDriver(GLenum target, GLsizei width, GLsizei height) const {
         if (mNeedsTextureSizeChecks) {
             // some drivers incorrectly handle some large texture sizes that are below the
             // max texture size that they report. So we check ourselves against our own values
             // (mMax[CubeMap]TextureSize).
@@ -1648,16 +1407,17 @@ public:
 #endif
 
 protected:
     GLenum mGLError;
 
 public:
 
     void BeforeGLCall(const char* glFunction) {
+        MOZ_ASSERT(IsCurrent());
         if (DebugMode()) {
             GLContext *currentGLContext = NULL;
 
             currentGLContext = (GLContext*)PR_GetThreadPrivate(sCurrentGLContextTLS);
 
             if (DebugMode() & DebugTrace)
                 printf_stderr("[gl:%p] > %s\n", this, glFunction);
             if (this != currentGLContext) {
@@ -2627,17 +2387,17 @@ private:
 
 public:
     void fBindRenderbuffer(GLenum target, GLuint renderbuffer) {
         BEFORE_GL_CALL;
         mSymbols.fBindRenderbuffer(target, renderbuffer);
         AFTER_GL_CALL;
     }
 
-    GLenum fCheckFramebufferStatus (GLenum target) {
+    GLenum fCheckFramebufferStatus(GLenum target) {
         BEFORE_GL_CALL;
         GLenum retval = mSymbols.fCheckFramebufferStatus(target);
         AFTER_GL_CALL;
         return retval;
     }
 
     void fFramebufferRenderbuffer(GLenum target, GLenum attachmentPoint, GLenum renderbufferTarget, GLuint renderbuffer) {
         BEFORE_GL_CALL;
@@ -2904,16 +2664,24 @@ public:
     }
 
     void fDeleteBuffers(GLsizei n, GLuint *names) {
         raw_fDeleteBuffers(n, names);
         TRACKING_CONTEXT(DeletedBuffers(this, n, names));
     }
 
     void fDeleteFramebuffers(GLsizei n, GLuint *names) {
+        if (mScreen) {
+            // Notify mScreen which framebuffers we're deleting.
+            // Otherwise, we will get framebuffer binding mispredictions.
+            for (int i = 0; i < n; i++) {
+                mScreen->DeletingFB(names[i]);
+            }
+        }
+
         if (n == 1 && *names == 0) {
             // Deleting framebuffer 0 causes hangs on the DROID. See bug 623228.
         } else {
             raw_fDeleteFramebuffers(n, names);
         }
         TRACKING_CONTEXT(DeletedFramebuffers(this, n, names));
     }
 
@@ -2993,16 +2761,24 @@ public:
     // OES_EGL_image (GLES)
     void fEGLImageTargetTexture2D(GLenum target, GLeglImage image) {
         BEFORE_GL_CALL;
         ASSERT_SYMBOL_PRESENT(fEGLImageTargetTexture2D);
         mSymbols.fEGLImageTargetTexture2D(target, image);
         AFTER_GL_CALL;
     }
 
+    void fEGLImageTargetRenderbufferStorage(GLenum target, GLeglImage image)
+    {
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fEGLImageTargetRenderbufferStorage);
+        mSymbols.fEGLImageTargetRenderbufferStorage(target, image);
+        AFTER_GL_CALL;
+    }
+
 #undef ASSERT_SYMBOL_PRESENT
 
 #ifdef DEBUG
     void THEBES_API CreatedProgram(GLContext *aOrigin, GLuint aName);
     void THEBES_API CreatedShader(GLContext *aOrigin, GLuint aName);
     void THEBES_API CreatedBuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
     void THEBES_API CreatedTextures(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
     void THEBES_API CreatedFramebuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
@@ -3123,147 +2899,288 @@ public:
 
         Derived* derived = static_cast<Derived*>(this);
         derived->UnwrapImpl();
 
         mIsUnwrapped = true;
     }
 };
 
-struct ScopedFramebufferTexture
-    : public ScopedGLWrapper<ScopedFramebufferTexture>
-{
-    friend struct ScopedGLWrapper<ScopedFramebufferTexture>;
-
-protected:
-    bool mComplete; // True if the framebuffer we create is complete.
-    GLuint mFB;
-
-public:
-    ScopedFramebufferTexture(GLContext* gl, GLuint texture)
-        : ScopedGLWrapper<ScopedFramebufferTexture>(gl)
-        , mComplete(false)
-        , mFB(0)
-    {
-        MOZ_ASSERT(mGL->IsCurrent());
-        GLuint boundFB = mGL->GetUserBoundFBO();
-
-        mGL->fGenFramebuffers(1, &mFB);
-        mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mFB);
-        mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
-                                   LOCAL_GL_COLOR_ATTACHMENT0,
-                                   LOCAL_GL_TEXTURE_2D,
-                                   texture,
-                                   0);
-
-        GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
-        if (status == LOCAL_GL_FRAMEBUFFER_COMPLETE) {
-            mComplete = true;
-        } else {
-            mGL->fDeleteFramebuffers(1, &mFB);
-            mFB = 0;
-        }
-
-        mGL->BindUserFBO(boundFB);
-    }
-
-protected:
-    void UnwrapImpl() {
-        if (!mFB)
-            return;
-
-        MOZ_ASSERT(mGL->IsCurrent());
-        mGL->fDeleteFramebuffers(1, &mFB);
-        mFB = 0;
-    }
-
-public:
-    GLuint FB() const {
-        return mFB;
-    }
-
-    bool IsComplete() const {
-        return mComplete;
-    }
-};
-
 // Wraps glEnable/Disable.
 struct ScopedGLState
     : public ScopedGLWrapper<ScopedGLState>
 {
     friend struct ScopedGLWrapper<ScopedGLState>;
 
 protected:
     const GLenum mCapability;
     bool mOldState;
 
 public:
     // Use |newState = true| to enable, |false| to disable.
     ScopedGLState(GLContext* gl, GLenum capability, bool newState)
         : ScopedGLWrapper<ScopedGLState>(gl)
         , mCapability(capability)
     {
-        MOZ_ASSERT(mGL->IsCurrent());
         mOldState = mGL->fIsEnabled(mCapability);