Merge m-i to m-c
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 05 Aug 2013 11:18:59 +0200
changeset 141726 54434a926c5f2f8ff7506499a400ebb56d7ee2a6
parent 141725 6bc019d8abc824fd2671d9d62324438ab3dde70f (current diff)
parent 141671 d144ffab454362f834974dc1a1c843dee85212c2 (diff)
child 141738 ad0ae007aa9e03cd74e9005cd6652e544139b3b5
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
milestone25.0a1
Merge m-i to m-c
browser/themes/linux/browser.css
browser/themes/osx/browser.css
browser/themes/windows/browser.css
configure.in
dom/interfaces/push/moz.build
dom/interfaces/push/nsIDOMPushManager.idl
dom/workers/ImageData.cpp
dom/workers/ImageData.h
media/webrtc/trunk/webrtc/modules/audio_device/android/audio_device_opensles_android.cc
media/webrtc/trunk/webrtc/modules/audio_device/android/audio_device_opensles_android.h
toolkit/content/license.html
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -190,17 +190,16 @@
 @BINPATH@/components/dom_geolocation.xpt
 @BINPATH@/components/dom_media.xpt
 @BINPATH@/components/dom_network.xpt
 @BINPATH@/components/dom_notification.xpt
 @BINPATH@/components/dom_html.xpt
 @BINPATH@/components/dom_indexeddb.xpt
 @BINPATH@/components/dom_offline.xpt
 @BINPATH@/components/dom_payment.xpt
-@BINPATH@/components/dom_push.xpt
 @BINPATH@/components/dom_json.xpt
 @BINPATH@/components/dom_browserelement.xpt
 @BINPATH@/components/dom_messages.xpt
 @BINPATH@/components/dom_power.xpt
 @BINPATH@/components/dom_quota.xpt
 @BINPATH@/components/dom_range.xpt
 @BINPATH@/components/dom_settings.xpt
 @BINPATH@/components/dom_permissionsettings.xpt
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -4,16 +4,21 @@
    - 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/. -->
 
 <!DOCTYPE bindings [
 <!ENTITY % tabBrowserDTD SYSTEM "chrome://browser/locale/tabbrowser.dtd" >
 %tabBrowserDTD;
 ]>
 
+# MAKE_E10S_WORK surrounds code needed to have the front-end try to be smart
+# about using non-remote browsers for loading certain URIs when remote tabs
+# (browser.tabs.remote) are enabled.
+#define MAKE_E10S_WORK 1
+
 <bindings id="tabBrowserBindings"
           xmlns="http://www.mozilla.org/xbl"
           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
           xmlns:xbl="http://www.mozilla.org/xbl">
 
   <binding id="tabbrowser">
     <resources>
       <stylesheet src="chrome://browser/content/tabbrowser.css"/>
@@ -1295,16 +1300,83 @@
               this.selectedTab = firstTabAdded;
             }
             else
               this.selectedBrowser.focus();
           }
         ]]></body>
       </method>
 
+#ifdef MAKE_E10S_WORK
+      <method name="_updateBrowserRemoteness">
+        <parameter name="aBrowser"/>
+        <parameter name="aRemote"/>
+        <body>
+          <![CDATA[
+            let isRemote = aBrowser.getAttribute("remote") == "true";
+            if (isRemote == aRemote)
+              return;
+
+            // Unhook our progress listener.
+            let tab = this._getTabForBrowser(aBrowser);
+            let index = tab._tPos;
+            let filter = this.mTabFilters[index];
+            aBrowser.webProgress.removeProgressListener(filter);
+
+            // Change the "remote" attribute.
+            let parent = aBrowser.parentNode;
+            parent.removeChild(aBrowser);
+            aBrowser.setAttribute("remote", aRemote ? "true" : "false");
+            parent.appendChild(aBrowser);
+
+            // Restore the progress listener.
+            aBrowser.webProgress.addProgressListener(filter, Ci.nsIWebProgress.NOTIFY_ALL);
+
+            if (aRemote)
+              tab.setAttribute("remote", "true");
+            else
+              tab.removeAttribute("remote");
+          ]]>
+        </body>
+      </method>
+
+      <!--
+        Returns true if we want to load the content for this URL in a
+        remote process. Eventually this should just check whether aURL
+        is unprivileged. Right now, though, we would like to load
+        some unprivileged URLs (like about:neterror) in the main
+        process since they interact with chrome code through
+        BrowserOnClick.
+      -->
+      <method name="_shouldBrowserBeRemote">
+        <parameter name="aURL"/>
+        <body>
+          <![CDATA[
+            if (!gMultiProcessBrowser)
+              return false;
+
+            // loadURI in browser.xml treats null as about:blank
+            if (!aURL)
+              aURL = "about:blank";
+
+            if (aURL.startsWith("about:") &&
+                aURL.toLowerCase() != "about:home" &&
+                aURL.toLowerCase() != "about:blank") {
+              return false;
+            }
+
+            if (aURL.startsWith("chrome:"))
+              return false;
+
+            return true;
+          ]]>
+        </body>
+      </method>
+#endif
+
       <method name="addTab">
         <parameter name="aURI"/>
         <parameter name="aReferrerURI"/>
         <parameter name="aCharset"/>
         <parameter name="aPostData"/>
         <parameter name="aOwner"/>
         <parameter name="aAllowThirdPartyFixup"/>
         <body>
@@ -1339,16 +1411,18 @@
 
             if (!aURI || isBlankPageURL(aURI))
               t.setAttribute("label", this.mStringBundle.getString("tabs.emptyTabTitle"));
             else
               t.setAttribute("label", aURI);
 
             t.setAttribute("crop", "end");
             t.setAttribute("onerror", "this.removeAttribute('image');");
+            if (remote)
+              t.setAttribute("remote", "true");
             t.className = "tabbrowser-tab";
 
             this.tabContainer._unlockTabSizing();
 
             // When overflowing, new tabs are scrolled into view smoothly, which
             // doesn't go well together with the width transition. So we skip the
             // transition in that case.
             let animate = !aSkipAnimation &&
@@ -1374,20 +1448,23 @@
             var b = document.createElementNS(
               "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
                                              "browser");
             b.setAttribute("type", "content-targetable");
             b.setAttribute("message", "true");
             b.setAttribute("contextmenu", this.getAttribute("contentcontextmenu"));
             b.setAttribute("tooltip", this.getAttribute("contenttooltip"));
 
-            if (Services.prefs.getPrefType("browser.tabs.remote") == Services.prefs.PREF_BOOL &&
-                Services.prefs.getBoolPref("browser.tabs.remote")) {
+#ifdef MAKE_E10S_WORK
+            let remote = this._shouldBrowserBeRemote(aURI);
+#else
+            let remote = gMultiProcessBrowser;
+#endif
+            if (remote)
               b.setAttribute("remote", "true");
-            }
 
             if (window.gShowPageResizers && document.getElementById("addon-bar").collapsed &&
                 window.windowState == window.STATE_NORMAL) {
               b.setAttribute("showresizer", "true");
             }
 
             if (this.hasAttribute("autocompletepopup"))
               b.setAttribute("autocompletepopup", this.getAttribute("autocompletepopup"));
@@ -2549,31 +2626,51 @@
 
       <!-- throws exception for unknown schemes -->
       <method name="loadURI">
         <parameter name="aURI"/>
         <parameter name="aReferrerURI"/>
         <parameter name="aCharset"/>
         <body>
           <![CDATA[
+#ifdef MAKE_E10S_WORK
+            this._updateBrowserRemoteness(this.mCurrentBrowser, this._shouldBrowserBeRemote(aURI));
+            try {
+#endif
             return this.mCurrentBrowser.loadURI(aURI, aReferrerURI, aCharset);
+#ifdef MAKE_E10S_WORK
+            } catch (e) {
+              let url = this.mCurrentBrowser.currentURI.spec;
+              this._updateBrowserRemoteness(this.mCurrentBrowser, this._shouldBrowserBeRemote(url));
+            }
+#endif
           ]]>
         </body>
       </method>
 
       <!-- throws exception for unknown schemes -->
       <method name="loadURIWithFlags">
         <parameter name="aURI"/>
         <parameter name="aFlags"/>
         <parameter name="aReferrerURI"/>
         <parameter name="aCharset"/>
         <parameter name="aPostData"/>
         <body>
           <![CDATA[
+#ifdef MAKE_E10S_WORK
+            this._updateBrowserRemoteness(this.mCurrentBrowser, this._shouldBrowserBeRemote(aURI));
+            try {
+#endif
             return this.mCurrentBrowser.loadURIWithFlags(aURI, aFlags, aReferrerURI, aCharset, aPostData);
+#ifdef MAKE_E10S_WORK
+            } catch (e) {
+              let url = this.mCurrentBrowser.currentURI.spec;
+              this._updateBrowserRemoteness(this.mCurrentBrowser, this._shouldBrowserBeRemote(url));
+            }
+#endif
           ]]>
         </body>
       </method>
 
       <method name="goHome">
         <body>
           <![CDATA[
             return this.mCurrentBrowser.goHome();
@@ -2813,16 +2910,17 @@
       <constructor>
         <![CDATA[
           let browserStack = document.getAnonymousElementByAttribute(this, "anonid", "browserStack");
           this.mCurrentBrowser = document.getAnonymousElementByAttribute(this, "anonid", "initialBrowser");
           if (Services.prefs.getBoolPref("browser.tabs.remote")) {
             browserStack.removeChild(this.mCurrentBrowser);
             this.mCurrentBrowser.setAttribute("remote", true);
             browserStack.appendChild(this.mCurrentBrowser);
+            this.tabContainer.firstChild.setAttribute("remote", "true");
           }
 
           this.mCurrentTab = this.tabContainer.firstChild;
           document.addEventListener("keypress", this, false);
           window.addEventListener("sizemodechange", this, false);
 
           var uniqueId = "panel" + Date.now();
           this.mPanelContainer.childNodes[0].id = uniqueId;
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -185,17 +185,16 @@
 #endif
 #ifdef MOZ_B2G_BT
 @BINPATH@/components/dom_bluetooth.xpt
 #endif
 @BINPATH@/components/dom_camera.xpt
 @BINPATH@/components/dom_canvas.xpt
 @BINPATH@/components/dom_contacts.xpt
 @BINPATH@/components/dom_alarm.xpt
-@BINPATH@/components/dom_push.xpt
 @BINPATH@/components/dom_core.xpt
 @BINPATH@/components/dom_css.xpt
 @BINPATH@/components/dom_devicestorage.xpt
 @BINPATH@/components/dom_events.xpt
 @BINPATH@/components/dom_file.xpt
 @BINPATH@/components/dom_geolocation.xpt
 @BINPATH@/components/dom_media.xpt
 @BINPATH@/components/dom_network.xpt
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -1657,16 +1657,20 @@ richlistitem[type~="action"][actiontype=
 }
 
 .tabbrowser-tab[selected="true"] {
   background-image: linear-gradient(@selectedTabHighlight@, @toolbarHighlight@ 32%),
                     linear-gradient(-moz-dialog, -moz-dialog);
   color: -moz-dialogtext;
 }
 
+.tabbrowser-tab[remote] {
+  text-decoration: underline;
+}
+
 #main-window[tabsontop=false]:not([disablechrome]) .tabbrowser-tab[selected=true]:not(:-moz-lwtheme) {
   background-image: linear-gradient(to top, rgba(0,0,0,.3) 1px, transparent 1px),
                     linear-gradient(@selectedTabHighlight@, @toolbarHighlight@ 32%),
                     linear-gradient(-moz-dialog, -moz-dialog);
 }
 
 .tabbrowser-tab[selected="true"]:-moz-lwtheme {
   background-image: linear-gradient(@selectedTabHighlight@, @toolbarHighlight@ 32%);
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -2252,16 +2252,20 @@ toolbarbutton.chevron > .toolbarbutton-m
   text-shadow: @loweredShadow@;
   margin: 0;
   padding: 0;
   border: none;
   text-align: center;
   -moz-box-align: stretch;
 }
 
+.tabbrowser-tab[remote] {
+  text-decoration: underline;
+}
+
 %define TABSONTOP_TAB #tabbrowser-tabs[tabsontop="true"] > .tabbrowser-tab
 %define TABSONBOTTOM_TAB #tabbrowser-tabs[tabsontop="false"] > .tabbrowser-tab
 %define TABSONTOP_TAB_STACK #tabbrowser-tabs[tabsontop="true"] > .tabbrowser-tab > .tab-stack
 %define TABSONBOTTOM_TAB_STACK #tabbrowser-tabs[tabsontop="false"] > .tabbrowser-tab > .tab-stack
 %define TABSONTOP_NEWTAB_BUTTON #tabbrowser-tabs[tabsontop="true"] > .tabbrowser-arrowscrollbox > .tabs-newtab-button
 %define TABSONBOTTOM_NEWTAB_BUTTON #tabbrowser-tabs[tabsontop="false"] > .tabbrowser-arrowscrollbox > .tabs-newtab-button
 
 @TABSONTOP_TAB_STACK@ > .tab-background {
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -1966,16 +1966,20 @@ richlistitem[type~="action"][actiontype=
   margin: 0;
   padding: 2px 0 4px;
   border-width: 4px 3px 0;
   border-style: solid;
   border-image: url(tabbrowser/tab.png) 4 3 0 fill repeat stretch;
   border-radius: 0;
 }
 
+.tabbrowser-tab[remote] {
+  text-decoration: underline;
+}
+
 .tabbrowser-tab:hover,
 .tabs-newtab-button:hover {
   background-image: @toolbarShadowOnTab@, @bgTabTextureHover@,
                     linear-gradient(-moz-dialog, -moz-dialog);
 }
 
 %ifndef WINDOWS_AERO
 @media (-moz-windows-theme: luna-blue) {
--- a/build/mobile/sutagent/android/CmdWorkerThread.java
+++ b/build/mobile/sutagent/android/CmdWorkerThread.java
@@ -134,16 +134,20 @@ public class CmdWorkerThread extends Thr
 
                 if ((inputLine += readLine(in)) != null)
                     {
                     String message = String.format("%s : %s",
                                      socket.getInetAddress().getHostAddress(), inputLine);
                     SUTAgentAndroid.log(dc, message);
 
                     outputLine = dc.processCommand(inputLine, out, in, cmdOut);
+                    if (outputLine == null)
+                        {
+                        outputLine = "";
+                        }
                     if (outputLine.length() > 0)
                         {
                         out.print(outputLine + "\n" + prompt);
                         }
                     else
                         out.print(prompt);
                     out.flush();
                     if (outputLine.equals("exit"))
--- a/build/mobile/sutagent/android/DataWorkerThread.java
+++ b/build/mobile/sutagent/android/DataWorkerThread.java
@@ -165,16 +165,20 @@ public class DataWorkerThread extends Th
                             }
                         }
                     else
                         inputLine = "";
 
                     if ((inputLine += readLine(in)) != null)
                         {
                         outputLine = dc.processCommand(inputLine, out, in, cmdOut);
+                        if (outputLine == null)
+                            {
+                            outputLine = "";
+                            }
                         out.print(outputLine + "\n");
                         out.flush();
                         if (outputLine.equals("exit"))
                             {
                             theParent.StopListening();
                             bListening = false;
                             }
                         if (outputLine.equals("quit"))
--- a/build/mobile/sutagent/android/DoCommand.java
+++ b/build/mobile/sutagent/android/DoCommand.java
@@ -102,17 +102,17 @@ public class DoCommand {
 
     String    currentDir = "/";
     String    sErrorPrefix = "##AGENT-WARNING## ";
     boolean bTraceOn = false;
 
     String ffxProvider = "org.mozilla.ffxcp";
     String fenProvider = "org.mozilla.fencp";
 
-    private final String prgVersion = "SUTAgentAndroid Version 1.18";
+    private final String prgVersion = "SUTAgentAndroid Version 1.19";
 
     public enum Command
         {
         RUN ("run"),
         EXEC ("exec"),
         EXECSU ("execsu"),
         EXECCWD ("execcwd"),
         EXECCWDSU ("execcwdsu"),
@@ -1391,17 +1391,17 @@ private void CancelNotification()
         }
         if (tmpFile.exists())
             {
             tmpFile.delete();
             return("/data/local");
             }
         Log.e("SUTAgentAndroid", "ERROR: Cannot access world writeable test root");
 
-        return(null);
+        return sErrorPrefix + " unable to determine test root";
         }
 
     public String GetAppRoot(String AppName)
         {
         String sRet = sErrorPrefix + " internal error [no context]";
         Context ctx = contextWrapper.getApplicationContext();
 
         if (ctx != null)
new file mode 100644
--- /dev/null
+++ b/config/check_spidermonkey_style.py
@@ -0,0 +1,396 @@
+# vim: set ts=8 sts=4 et sw=4 tw=99:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#----------------------------------------------------------------------------
+# This script checks various aspects of SpiderMonkey code style.  The current checks are as
+# follows.
+#
+# We check the following things in headers.
+#
+# - No cyclic dependencies.
+# 
+# - No normal header should #include a inlines.h/-inl.h file.
+# 
+# - #ifndef wrappers should have the right form. (XXX: not yet implemented)
+#   - Every header file should have one.
+#   - It should be in the vanilla form and have no tokens before/after it so
+#     that GCC and clang can avoid multiple-inclusion.
+#   - The guard name used should be appropriate for the filename.
+# 
+# We check the following things in all files.
+#
+# - #includes should have full paths, e.g. "ion/Ion.h", not "Ion.h". 
+#
+# - #includes should use the appropriate form for system headers (<...>) and
+#   local headers ("...").
+#
+# - #includes should be ordered correctly. (XXX: not yet implemented;  see bug
+#   888088)
+#   - Each one should be in the correct section.
+#   - Alphabetical order should be used within sections.
+#   - Sections should be in the right order.
+#----------------------------------------------------------------------------
+
+from __future__ import print_function
+
+import difflib
+import os
+import re
+import subprocess
+import sys
+import traceback
+
+# We don't bother checking files in these directories, because they're (a) auxiliary or (b)
+# imported code that doesn't follow our coding style.
+ignored_js_src_dirs = [
+   'js/src/config/',            # auxiliary stuff
+   'js/src/ctypes/libffi/',     # imported code
+   'js/src/devtools/',          # auxiliary stuff
+   'js/src/editline/',          # imported code
+   'js/src/gdb/',               # auxiliary stuff
+   'js/src/vtune/'              # imported code
+]
+
+# We ignore #includes of these files, because they don't follow the usual rules.
+included_inclnames_to_ignore = set([
+    'ffi.h',                    # generated in ctypes/libffi/
+    'devtools/sharkctl.h',      # we ignore devtools/ in general
+    'devtools/Instruments.h',   # we ignore devtools/ in general
+    'double-conversion.h',      # strange MFBT case
+    'javascript-trace.h',       # generated in $OBJDIR if HAVE_DTRACE is defined
+    'jsautokw.h',               # generated in $OBJDIR
+    'jsautooplen.h',            # generated in $OBJDIR
+    'jscustomallocator.h',      # provided by embedders;  allowed to be missing
+    'js-config.h',              # generated in $OBJDIR
+    'pratom.h',                 # NSPR
+    'prcvar.h',                 # NSPR
+    'prinit.h',                 # NSPR
+    'prlink.h',                 # NSPR
+    'prlock.h',                 # NSPR
+    'prprf.h',                  # NSPR
+    'prthread.h',               # NSPR
+    'prtypes.h',                # NSPR
+    'selfhosted.out.h',         # generated in $OBJDIR
+    'unicode/locid.h',          # ICU
+    'unicode/numsys.h',         # ICU
+    'unicode/ucal.h',           # ICU
+    'unicode/uclean.h',         # ICU
+    'unicode/ucol.h',           # ICU
+    'unicode/udat.h',           # ICU
+    'unicode/udatpg.h',         # ICU
+    'unicode/uenum.h',          # ICU
+    'unicode/unum.h',           # ICU
+    'unicode/ustring.h',        # ICU
+    'unicode/utypes.h',         # ICU
+    'vtune/VTuneWrapper.h'      # VTune
+])
+
+# The files in tests/style/ contain code that fails this checking in various
+# ways.  Here is the output we expect.  If the actual output differs from
+# this, one of the following must have happened.
+# - New SpiderMonkey code violates one of the checked rules.
+# - The tests/style/ files have changed without expected_output being changed
+#   accordingly.
+# - This script has been broken somehow.
+#
+expected_output = '''\
+js/src/tests/style/BadIncludes2.h:1: error:
+    vanilla header includes an inline-header file "tests/style/BadIncludes2-inl.h"
+
+js/src/tests/style/BadIncludes.h:1: error:
+    the file includes itself
+
+js/src/tests/style/BadIncludes.h:3: error:
+    "BadIncludes2.h" is included using the wrong path;
+    did you forget a prefix, or is the file not yet committed?
+
+js/src/tests/style/BadIncludes.h:4: error:
+    <tests/style/BadIncludes2.h> should be included using
+    the #include "..." form
+
+js/src/tests/style/BadIncludes.h:5: error:
+    "stdio.h" is included using the wrong path;
+    did you forget a prefix, or is the file not yet committed?
+
+(multiple files): error:
+    header files form one or more cycles
+
+   tests/style/HeaderCycleA1.h
+   -> tests/style/HeaderCycleA2.h
+      -> tests/style/HeaderCycleA3.h
+         -> tests/style/HeaderCycleA1.h
+
+   tests/style/HeaderCycleB1-inl.h
+   -> tests/style/HeaderCycleB2-inl.h
+      -> tests/style/HeaderCycleB3-inl.h
+         -> tests/style/HeaderCycleB4-inl.h
+            -> tests/style/HeaderCycleB1-inl.h
+            -> tests/style/jsheadercycleB5inlines.h
+               -> tests/style/HeaderCycleB1-inl.h
+      -> tests/style/HeaderCycleB4-inl.h
+
+'''.splitlines(True)
+
+actual_output = []
+
+
+def out(*lines):
+    for line in lines:
+        actual_output.append(line + '\n')
+
+
+def error(filename, linenum, *lines):
+    location = filename
+    if linenum != None:
+        location += ":" + str(linenum)
+    out(location + ': error:')
+    for line in (lines):
+        out('    ' + line)
+    out('')
+
+
+class FileKind(object):
+    C = 1
+    CPP = 2
+    INL_H = 3
+    H = 4
+    TBL = 5
+    MSG = 6
+
+    @staticmethod
+    def get(filename):
+        if filename.endswith('.c'):
+            return FileKind.C
+       
+        if filename.endswith('.cpp'):
+            return FileKind.CPP
+       
+        if filename.endswith(('inlines.h', '-inl.h')):
+            return FileKind.INL_H
+
+        if filename.endswith('.h'):
+            return FileKind.H
+
+        if filename.endswith('.tbl'):
+            return FileKind.TBL
+
+        if filename.endswith('.msg'):
+            return FileKind.MSG
+
+        error(filename, None, 'unknown file kind')
+
+
+def get_all_filenames():
+    """Get a list of all the files in the (Mercurial or Git) repository."""
+    cmds = [['hg', 'manifest'], ['git', 'ls-files']]
+    for cmd in cmds:
+        try:
+            all_filenames = subprocess.check_output(cmd, universal_newlines=True,
+                                                    stderr=subprocess.PIPE).split('\n')
+            return all_filenames
+        except:
+            continue
+    else:
+        raise Exception('failed to run any of the repo manifest commands', cmds)
+
+
+def check_style():
+    # We deal with two kinds of name.
+    # - A "filename" is a full path to a file from the repository root.
+    # - An "inclname" is how a file is referred to in a #include statement.
+    #
+    # Examples (filename -> inclname)
+    # - "mfbt/Attributes.h"  -> "mozilla/Attributes.h"
+    # - "js/public/Vector.h" -> "js/Vector.h"
+    # - "js/src/vm/String.h" -> "vm/String.h"
+
+    mfbt_inclnames = set()      # type: set(inclname)
+    js_names = dict()           # type: dict(filename, inclname)
+
+    # Select the appropriate files.
+    for filename in get_all_filenames():
+        if filename.startswith('mfbt/') and filename.endswith('.h'):
+            inclname = 'mozilla/' + filename[len('mfbt/'):]
+            mfbt_inclnames.add(inclname)
+
+        if filename.startswith('js/public/') and filename.endswith('.h'):
+            inclname = 'js/' + filename[len('js/public/'):]
+            js_names[filename] = inclname
+
+        if filename.startswith('js/src/') and \
+           not filename.startswith(tuple(ignored_js_src_dirs)) and \
+           filename.endswith(('.c', '.cpp', '.h', '.tbl', '.msg')):
+            inclname = filename[len('js/src/'):]
+            js_names[filename] = inclname
+
+    all_inclnames = mfbt_inclnames | set(js_names.values())
+
+    edges = dict()      # type: dict(inclname, set(inclname))
+
+    # We don't care what's inside the MFBT files, but because they are
+    # #included from JS files we have to add them to the inclusion graph.
+    for inclname in mfbt_inclnames:
+        edges[inclname] = set()
+
+    # Process all the JS files.
+    for filename in js_names.keys():
+        inclname = js_names[filename]
+        file_kind = FileKind.get(filename)
+        if file_kind == FileKind.C or file_kind == FileKind.CPP or \
+           file_kind == FileKind.H or file_kind == FileKind.INL_H:
+            included_h_inclnames = set()    # type: set(inclname)
+
+            # This script is run in js/src/, so prepend '../../' to get to the root of the Mozilla
+            # source tree.
+            with open(os.path.join('../..', filename)) as f:
+                do_file(filename, inclname, file_kind, f, all_inclnames, included_h_inclnames)
+
+        edges[inclname] = included_h_inclnames
+
+    find_cycles(all_inclnames, edges)
+
+    # Compare expected and actual output.
+    difflines = difflib.unified_diff(expected_output, actual_output,
+                                     fromfile='check_spider_monkey_style.py expected output',
+                                       tofile='check_spider_monkey_style.py actual output')
+    ok = True
+    for diffline in difflines:
+        ok = False
+        print(diffline, end='')
+
+    return ok
+
+
+def do_file(filename, inclname, file_kind, f, all_inclnames, included_h_inclnames):
+    for linenum, line in enumerate(f, start=1):
+        # Look for a |#include "..."| line.
+        m = re.match(r'\s*#\s*include\s+"([^"]*)"', line)
+        if m is not None:
+            included_inclname = m.group(1)
+
+            if included_inclname not in included_inclnames_to_ignore:
+                included_kind = FileKind.get(included_inclname)
+
+                # Check the #include path has the correct form.
+                if included_inclname not in all_inclnames:
+                    error(filename, linenum,
+                          '"' + included_inclname + '" is included ' + 'using the wrong path;',
+                          'did you forget a prefix, or is the file not yet committed?')
+
+                # Record inclusions of .h files for cycle detection later.
+                # (Exclude .tbl and .msg files.)
+                elif included_kind == FileKind.H or included_kind == FileKind.INL_H:
+                    included_h_inclnames.add(included_inclname)
+
+                # Check a H file doesn't #include an INL_H file.
+                if file_kind == FileKind.H and included_kind == FileKind.INL_H:
+                    error(filename, linenum,
+                          'vanilla header includes an inline-header file "' + included_inclname + '"')
+
+                # Check a file doesn't #include itself.  (We do this here because the
+                # cycle detection below doesn't detect this case.)
+                if inclname == included_inclname:
+                    error(filename, linenum, 'the file includes itself')
+
+        # Look for a |#include <...>| line.
+        m = re.match(r'\s*#\s*include\s+<([^>]*)>', line)
+        if m is not None:
+            included_inclname = m.group(1)
+
+            # Check it is not a known local file (in which case it's
+            # probably a system header).
+            if included_inclname in included_inclnames_to_ignore or \
+               included_inclname in all_inclnames:
+                error(filename, linenum,
+                      '<' + included_inclname + '> should be included using',
+                      'the #include "..." form')
+
+
+def find_cycles(all_inclnames, edges):
+    """Find and draw any cycles."""
+    
+    SCCs = tarjan(all_inclnames, edges)
+
+    # The various sorted() calls below ensure the output is deterministic.
+
+    def draw_SCC(c):
+        cset = set(c)
+        drawn = set()
+        def draw(v, indent):
+            out('   ' * indent + ('-> ' if indent else '   ') + v)
+            if v in drawn:
+                return
+            drawn.add(v)
+            for succ in sorted(edges[v]):
+                if succ in cset:
+                    draw(succ, indent + 1)
+        draw(sorted(c)[0], 0)
+        out('')
+
+    have_drawn_an_SCC = False
+    for scc in sorted(SCCs):
+        if len(scc) != 1:
+            if not have_drawn_an_SCC:
+                error('(multiple files)', None, 'header files form one or more cycles')
+                have_drawn_an_SCC = True
+
+            draw_SCC(scc)
+
+
+# Tarjan's algorithm for finding the strongly connected components (SCCs) of a graph.
+# https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
+def tarjan(V, E):
+    vertex_index = {}
+    vertex_lowlink = {}
+    index = 0
+    S = []
+    all_SCCs = []
+
+    def strongconnect(v, index):
+        # Set the depth index for v to the smallest unused index
+        vertex_index[v] = index
+        vertex_lowlink[v] = index
+        index += 1
+        S.append(v)
+
+        # Consider successors of v
+        for w in E[v]:
+            if w not in vertex_index:
+                # Successor w has not yet been visited; recurse on it
+                index = strongconnect(w, index)
+                vertex_lowlink[v] = min(vertex_lowlink[v], vertex_lowlink[w])
+            elif w in S:
+                # Successor w is in stack S and hence in the current SCC
+                vertex_lowlink[v] = min(vertex_lowlink[v], vertex_index[w])
+
+        # If v is a root node, pop the stack and generate an SCC
+        if vertex_lowlink[v] == vertex_index[v]:
+            i = S.index(v)
+            scc = S[i:]
+            del S[i:]
+            all_SCCs.append(scc)
+
+        return index
+
+    for v in V:
+        if v not in vertex_index:
+            index = strongconnect(v, index)
+
+    return all_SCCs
+
+
+def main():
+    ok = check_style()
+
+    if ok:
+        print('TEST-PASS | check_spidermonkey_style.py | ok')
+    else:
+        print('TEST-UNEXPECTED-FAIL | check_spidermonkey_style.py | actual output does not match expected output;  diff is above')
+
+    sys.exit(0 if ok else 1)
+
+
+if __name__ == "__main__":
+    main()
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -437,17 +437,17 @@ endif
 # directories.
 define SUBMAKE # $(call SUBMAKE,target,directory,static)
 +@$(UPDATE_TITLE)
 +$(if $(3), MOZBUILD_BACKEND_CHECKED=,) $(MAKE) $(if $(2),-C $(2)) $(1)
 
 endef # The extra line is important here! don't delete it
 
 define TIER_DIR_SUBMAKE
-@echo "BUILDSTATUS TIERDIR_START $(2)"
+@echo "BUILDSTATUS TIERDIR_START  $(2)"
 $(call SUBMAKE,$(1),$(2),$(3))
 @echo "BUILDSTATUS TIERDIR_FINISH $(2)"
 
 endef # Ths empty line is important.
 
 
 ifneq (,$(strip $(DIRS)))
 LOOP_OVER_DIRS = \
--- a/configure.in
+++ b/configure.in
@@ -9120,17 +9120,17 @@ if test -n "$INTEL_ARCHITECTURE"; then
     EXTRA_GYP_DEFINES="$EXTRA_GYP_DEFINES -D yuv_disable_asm=1"
   fi
 fi
 
 if test -n "$MOZ_WEBRTC"; then
    AC_MSG_RESULT("generating WebRTC Makefiles...")
 
    if test "${MOZ_WIDGET_TOOLKIT}" = "gonk"; then
-      EXTRA_GYP_DEFINES="${EXTRA_GYP_DEFINES} -D build_with_gonk=1 -D include_internal_audio_device=0"
+      EXTRA_GYP_DEFINES="${EXTRA_GYP_DEFINES} -D build_with_gonk=1"
    fi
 
 dnl Any --include files must also appear in -D FORCED_INCLUDE_FILE= entries
 dnl so that regeneration via dependencies works correctly
    WEBRTC_CONFIG="-D build_with_mozilla=1 -D build_with_chromium=0 --include ${srcdir}/media/webrtc/webrtc_config.gypi -D FORCED_INCLUDE_FILE=${srcdir}/media/webrtc/webrtc_config.gypi"
 
    if test -n HAVE_CLOCK_MONOTONIC; then
       WEBRTC_CONFIG="${WEBRTC_CONFIG} -D have_clock_monotonic=1"
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -6699,16 +6699,24 @@ nsIDocument::AdoptNode(nsINode& aAdopted
       } while ((doc = doc->GetParentDocument()));
 
       // Remove from parent.
       nsCOMPtr<nsINode> parent = adoptedNode->GetParentNode();
       if (parent) {
         int32_t idx = parent->IndexOf(adoptedNode);
         MOZ_ASSERT(idx >= 0);
         parent->RemoveChildAt(idx, true);
+      } else {
+        MOZ_ASSERT(!adoptedNode->IsInDoc());
+
+        // If we're adopting a node that's not in a document, it might still
+        // have a binding applied. Remove the binding from the element now
+        // that it's getting adopted into a new document.
+        // TODO Fully tear down the binding.
+        adoptedNode->AsContent()->SetXBLBinding(nullptr);
       }
 
       break;
     }
     case nsIDOMNode::DOCUMENT_NODE:
     {
       rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
       return nullptr;
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -3384,16 +3384,29 @@ nsObjectLoadingContent::DoNewResolve(JSC
   nsRefPtr<nsNPAPIPluginInstance> pi;
   nsresult rv = ScriptRequestPluginInstance(aCx, getter_AddRefs(pi));
   if (NS_FAILED(rv)) {
     return mozilla::dom::Throw<true>(aCx, rv);
   }
   return true;
 }
 
+void
+nsObjectLoadingContent::GetOwnPropertyNames(JSContext* aCx,
+                                            nsTArray<nsString>& /* unused */,
+                                            ErrorResult& aRv)
+{
+  // Just like DoNewResolve, just make sure we're instantiated.  That will do
+  // the work our Enumerate hook needs to do, and we don't want to return these
+  // property names from Xrays anyway.
+  nsRefPtr<nsNPAPIPluginInstance> pi;
+  aRv = ScriptRequestPluginInstance(aCx, getter_AddRefs(pi));
+}
+
+
 // SetupProtoChainRunner implementation
 nsObjectLoadingContent::SetupProtoChainRunner::SetupProtoChainRunner(
     nsIScriptContext* scriptContext,
     nsObjectLoadingContent* aContent)
   : mContext(scriptContext)
   , mContent(aContent)
 {
 }
--- a/content/base/src/nsObjectLoadingContent.h
+++ b/content/base/src/nsObjectLoadingContent.h
@@ -146,16 +146,19 @@ class nsObjectLoadingContent : public ns
 
     // Remove plugin from protochain
     void TeardownProtoChain();
 
     // Helper for WebIDL newResolve
     bool DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
                       JS::Handle<jsid> aId,
                       JS::MutableHandle<JS::Value> aValue);
+    // Helper for WebIDL enumeration
+    void GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& /* unused */,
+                             mozilla::ErrorResult& aRv);
 
     // WebIDL API
     nsIDocument* GetContentDocument();
     void GetActualType(nsAString& aType) const
     {
       CopyUTF8toUTF16(mContentType, aType);
     }
     uint32_t DisplayedType() const
--- a/content/canvas/src/WebGLExtensionDrawBuffers.cpp
+++ b/content/canvas/src/WebGLExtensionDrawBuffers.cpp
@@ -50,18 +50,17 @@ void WebGLExtensionDrawBuffers::DrawBuff
 {
     mContext->DrawBuffers(buffers);
 }
 
 bool WebGLExtensionDrawBuffers::IsSupported(const WebGLContext* context)
 {
     gl::GLContext * gl = context->GL();
 
-    if (!gl->IsExtensionSupported(gl->IsGLES2() ? GLContext::EXT_draw_buffers
-                                                : GLContext::ARB_draw_buffers)) {
+    if (!gl->IsExtensionSupported(GLContext::XXX_draw_buffers)) {
         return false;
     }
 
     GLint supportedColorAttachments = 0;
     GLint supportedDrawBuffers = 0;
 
     context->MakeContextCurrent();
 
--- a/content/canvas/src/WebGLExtensionVertexArray.cpp
+++ b/content/canvas/src/WebGLExtensionVertexArray.cpp
@@ -41,17 +41,12 @@ void WebGLExtensionVertexArray::BindVert
 {
     mContext->BindVertexArray(array);
 }
 
 bool WebGLExtensionVertexArray::IsSupported(const WebGLContext* context)
 {
     gl::GLContext* gl = context->GL();
 
-    if (gl->IsGLES2()) {
-        return gl->IsExtensionSupported(gl::GLContext::OES_vertex_array_object);
-    }
-
-    return gl->IsExtensionSupported(gl::GLContext::ARB_vertex_array_object) ||
-           gl->IsExtensionSupported(gl::GLContext::APPLE_vertex_array_object);
+    return gl->IsExtensionSupported(gl::GLContext::XXX_vertex_array_object);
 }
 
 IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionVertexArray)
--- a/content/media/webrtc/Makefile.in
+++ b/content/media/webrtc/Makefile.in
@@ -16,15 +16,16 @@ ifeq ($(OS_ARCH),WINNT)
 OS_CXXFLAGS += -DNOMINMAX
 endif
 
 include $(topsrcdir)/config/rules.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 
 ifdef MOZ_WEBRTC
 LOCAL_INCLUDES += \
+  -I$(topsrcdir)/media/webrtc/trunk \
   -I$(topsrcdir)/media/webrtc/trunk/webrtc \
   -I$(topsrcdir)/media/webrtc/signaling/src/common \
   -I$(topsrcdir)/media/webrtc/signaling/src/common/browser_logging \
   -I$(topsrcdir)/dom/base \
   -I$(topsrcdir)/dom/camera \
   $(NULL)
 endif
--- a/dom/alarm/AlarmsManager.js
+++ b/dom/alarm/AlarmsManager.js
@@ -83,28 +83,28 @@ AlarmsManager.prototype = {
         manifestURL: this._manifestURL }
     );
     return request;
   },
 
   remove: function remove(aId) {
     debug("remove()");
 
-    return this._cpmm.sendSyncMessage(
-      "AlarmsManager:Remove", 
+    this._cpmm.sendAsyncMessage(
+      "AlarmsManager:Remove",
       { id: aId, manifestURL: this._manifestURL }
     );
   },
 
   getAll: function getAll() {
     debug("getAll()");
 
     let request = this.createRequest();
     this._cpmm.sendAsyncMessage(
-      "AlarmsManager:GetAll", 
+      "AlarmsManager:GetAll",
       { requestId: this.getRequestId(request), manifestURL: this._manifestURL }
     );
     return request;
   },
 
   receiveMessage: function receiveMessage(aMessage) {
     debug("receiveMessage(): " + aMessage.name);
 
@@ -123,17 +123,17 @@ AlarmsManager.prototype = {
 
       case "AlarmsManager:GetAll:Return:OK":
         // We don't need to expose everything to the web content.
         let alarms = [];
         json.alarms.forEach(function trimAlarmInfo(aAlarm) {
           let alarm = { "id":              aAlarm.id,
                         "date":            aAlarm.date,
                         "respectTimezone": aAlarm.ignoreTimezone ?
-                                             "ignoreTimezone" : "honorTimezone", 
+                                             "ignoreTimezone" : "honorTimezone",
                         "data":            aAlarm.data };
           alarms.push(alarm);
         });
         Services.DOMRequest.fireSuccess(request,
                                         ObjectWrapper.wrap(alarms, this._window));
         break;
 
       case "AlarmsManager:Add:Return:KO":
@@ -151,30 +151,36 @@ AlarmsManager.prototype = {
     this.removeRequest(json.requestId);
    },
 
   // nsIDOMGlobalPropertyInitializer implementation
   init: function init(aWindow) {
     debug("init()");
 
     // Set navigator.mozAlarms to null.
-    if (!Services.prefs.getBoolPref("dom.mozAlarms.enabled"))
+    if (!Services.prefs.getBoolPref("dom.mozAlarms.enabled")) {
       return null;
+    }
 
     // Only pages with perm set can use the alarms.
     let principal = aWindow.document.nodePrincipal;
-    let perm = Services.perms.testExactPermissionFromPrincipal(principal, "alarms");
-    if (perm != Ci.nsIPermissionManager.ALLOW_ACTION)
+    let perm =
+      Services.perms.testExactPermissionFromPrincipal(principal, "alarms");
+    if (perm != Ci.nsIPermissionManager.ALLOW_ACTION) {
       return null;
+    }
 
-    this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsISyncMessageSender);
+    this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
+                   .getService(Ci.nsISyncMessageSender);
 
     // Add the valid messages to be listened.
-    this.initDOMRequestHelper(aWindow, ["AlarmsManager:Add:Return:OK", "AlarmsManager:Add:Return:KO",
-                              "AlarmsManager:GetAll:Return:OK", "AlarmsManager:GetAll:Return:KO"]);
+    this.initDOMRequestHelper(aWindow, ["AlarmsManager:Add:Return:OK",
+                                        "AlarmsManager:Add:Return:KO",
+                                        "AlarmsManager:GetAll:Return:OK",
+                                        "AlarmsManager:GetAll:Return:KO"]);
 
     // Get the manifest URL if this is an installed app
     let appsService = Cc["@mozilla.org/AppsService;1"]
                         .getService(Ci.nsIAppsService);
     this._pageURL = principal.URI.spec;
     this._manifestURL = appsService.getManifestURLByLocalId(principal.appId);
     this._window = aWindow;
   },
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1451,17 +1451,17 @@ bool
 Navigator::DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
                         JS::Handle<jsid> aId,
                         JS::MutableHandle<JS::Value> aValue)
 {
   if (!JSID_IS_STRING(aId)) {
     return true;
   }
 
-  nsScriptNameSpaceManager *nameSpaceManager =
+  nsScriptNameSpaceManager* nameSpaceManager =
     nsJSRuntime::GetNameSpaceManager();
   if (!nameSpaceManager) {
     return Throw<true>(aCx, NS_ERROR_NOT_INITIALIZED);
   }
 
   nsDependentJSString name(aId);
 
   const nsGlobalNameStruct* name_struct =
@@ -1545,16 +1545,39 @@ Navigator::DoNewResolve(JSContext* aCx, 
   if (!JS_WrapValue(aCx, prop_val.address())) {
     return Throw<true>(aCx, NS_ERROR_UNEXPECTED);
   }
 
   aValue.set(prop_val);
   return true;
 }
 
+static PLDHashOperator
+SaveNavigatorName(const nsAString& aName, void* aClosure)
+{
+  nsTArray<nsString>* arr = static_cast<nsTArray<nsString>*>(aClosure);
+  arr->AppendElement(aName);
+  return PL_DHASH_NEXT;
+}
+
+void
+Navigator::GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames,
+                               ErrorResult& aRv)
+{
+  nsScriptNameSpaceManager *nameSpaceManager =
+    nsJSRuntime::GetNameSpaceManager();
+  if (!nameSpaceManager) {
+    NS_ERROR("Can't get namespace manager.");
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return;
+  }
+
+  nameSpaceManager->EnumerateNavigatorNames(SaveNavigatorName, &aNames);
+}
+
 JSObject*
 Navigator::WrapObject(JSContext* cx, JS::Handle<JSObject*> scope)
 {
   return NavigatorBinding::Wrap(cx, scope, this);
 }
 
 /* static */
 bool
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -238,16 +238,18 @@ public:
                        MozDOMGetUserMediaErrorCallback* aOnError,
                        ErrorResult& aRv);
   void MozGetUserMediaDevices(MozGetUserMediaDevicesSuccessCallback* aOnSuccess,
                               MozDOMGetUserMediaErrorCallback* aOnError,
                               ErrorResult& aRv);
 #endif // MOZ_MEDIA_NAVIGATOR
   bool DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
                     JS::Handle<jsid> aId, JS::MutableHandle<JS::Value> aValue);
+  void GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames,
+                           ErrorResult& aRv);
 
   // WebIDL helper methods
   static bool HasBatterySupport(JSContext* /* unused*/, JSObject* /*unused */);
   static bool HasPowerSupport(JSContext* /* unused */, JSObject* aGlobal);
   static bool HasIdleSupport(JSContext* /* unused */, JSObject* aGlobal);
   static bool HasWakeLockSupport(JSContext* /* unused*/, JSObject* /*unused */);
   static bool HasDesktopNotificationSupport(JSContext* /* unused*/,
                                             JSObject* /*unused */)
--- a/dom/base/nsScriptNameSpaceManager.cpp
+++ b/dom/base/nsScriptNameSpaceManager.cpp
@@ -782,37 +782,44 @@ nsScriptNameSpaceManager::RegisterNaviga
     if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
       s->mType = nsGlobalNameStruct::eTypeNewDOMBinding;
     }
     s->mConstructNavigatorProperty = aNavConstructor;
     s->mConstructorEnabled = aConstructorEnabled;
   }
 }
 
-struct GlobalNameClosure
+struct NameClosure
 {
-  nsScriptNameSpaceManager::GlobalNameEnumerator enumerator;
+  nsScriptNameSpaceManager::NameEnumerator enumerator;
   void* closure;
 };
 
 static PLDHashOperator
-EnumerateGlobalName(PLDHashTable*, PLDHashEntryHdr *hdr, uint32_t,
-                    void* aClosure)
+EnumerateName(PLDHashTable*, PLDHashEntryHdr *hdr, uint32_t, void* aClosure)
 {
   GlobalNameMapEntry *entry = static_cast<GlobalNameMapEntry *>(hdr);
-  GlobalNameClosure* closure = static_cast<GlobalNameClosure*>(aClosure);
+  NameClosure* closure = static_cast<NameClosure*>(aClosure);
   return closure->enumerator(entry->mKey, closure->closure);
 }
 
 void
-nsScriptNameSpaceManager::EnumerateGlobalNames(GlobalNameEnumerator aEnumerator,
+nsScriptNameSpaceManager::EnumerateGlobalNames(NameEnumerator aEnumerator,
                                                void* aClosure)
 {
-  GlobalNameClosure closure = { aEnumerator, aClosure };
-  PL_DHashTableEnumerate(&mGlobalNames, EnumerateGlobalName, &closure);
+  NameClosure closure = { aEnumerator, aClosure };
+  PL_DHashTableEnumerate(&mGlobalNames, EnumerateName, &closure);
+}
+
+void
+nsScriptNameSpaceManager::EnumerateNavigatorNames(NameEnumerator aEnumerator,
+                                                  void* aClosure)
+{
+  NameClosure closure = { aEnumerator, aClosure };
+  PL_DHashTableEnumerate(&mNavigatorNames, EnumerateName, &closure);
 }
 
 static size_t
 SizeOfEntryExcludingThis(PLDHashEntryHdr *aHdr, MallocSizeOf aMallocSizeOf,
                          void *aArg)
 {
     GlobalNameMapEntry* entry = static_cast<GlobalNameMapEntry*>(aHdr);
     return entry->SizeOfExcludingThis(aMallocSizeOf);
--- a/dom/base/nsScriptNameSpaceManager.h
+++ b/dom/base/nsScriptNameSpaceManager.h
@@ -147,20 +147,22 @@ public:
     mozilla::dom::DefineInterface aDefineDOMInterface,
     mozilla::dom::ConstructorEnabled* aConstructorEnabled);
 
   void RegisterNavigatorDOMConstructor(const nsAFlatString& aName,
     mozilla::dom::ConstructNavigatorProperty aNavConstructor,
     mozilla::dom::ConstructorEnabled* aConstructorEnabled);
 
   typedef PLDHashOperator
-  (* GlobalNameEnumerator)(const nsAString& aGlobalName, void* aClosure);
+  (* NameEnumerator)(const nsAString& aGlobalName, void* aClosure);
 
-  void EnumerateGlobalNames(GlobalNameEnumerator aEnumerator,
+  void EnumerateGlobalNames(NameEnumerator aEnumerator,
                             void* aClosure);
+  void EnumerateNavigatorNames(NameEnumerator aEnumerator,
+                               void* aClosure);
 
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
 
 private:
   // Adds a new entry to the hash and returns the nsGlobalNameStruct
   // that aKey will be mapped to. If mType in the returned
   // nsGlobalNameStruct is != eTypeNotInitialized, an entry for aKey
   // already existed.
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -2,16 +2,18 @@
 /* vim: set ts=2 sw=2 et tw=79: */
 /* 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 <stdarg.h>
 
+#include "JavaScriptParent.h"
+
 #include "prprf.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/Assertions.h"
 
 #include "BindingUtils.h"
 
 #include "AccessCheck.h"
@@ -1741,16 +1743,27 @@ InterfaceHasInstance(JSContext* cx, JS::
              "ID?");
 
   if (domClass &&
       domClass->mInterfaceChain[clasp->mDepth] == clasp->mPrototypeID) {
     *bp = true;
     return true;
   }
 
+  JS::Rooted<JSObject*> unwrapped(cx, js::CheckedUnwrap(instance, true));
+  if (unwrapped && jsipc::JavaScriptParent::IsCPOW(unwrapped)) {
+    bool boolp = false;
+    if (!jsipc::JavaScriptParent::DOMInstanceOf(unwrapped, clasp->mPrototypeID,
+                                                clasp->mDepth, &boolp)) {
+      return false;
+    }
+    *bp = boolp;
+    return true;
+  }
+
   JS::Rooted<JS::Value> protov(cx);
   DebugOnly<bool> ok = JS_GetProperty(cx, obj, "prototype", &protov);
   MOZ_ASSERT(ok, "Someone messed with our prototype property?");
 
   JS::Rooted<JSObject*> interfacePrototype(cx, &protov.toObject());
   MOZ_ASSERT(IsDOMIfaceAndProtoClass(js::GetObjectClass(interfacePrototype)),
              "Someone messed with our prototype property?");
 
@@ -1782,16 +1795,31 @@ InterfaceHasInstance(JSContext* cx, JS::
     *bp = false;
     return true;
   }
 
   JS::Rooted<JSObject*> instanceObject(cx, &vp.toObject());
   return InterfaceHasInstance(cx, obj, instanceObject, bp);
 }
 
+JSBool
+InterfaceHasInstance(JSContext* cx, int prototypeID, int depth,
+                     JS::Handle<JSObject*> instance,
+                     JSBool* bp)
+{
+  const DOMClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance));
+
+  MOZ_ASSERT(!domClass || prototypeID != prototypes::id::_ID_Count,
+             "Why do we have a hasInstance hook if we don't have a prototype "
+             "ID?");
+
+  *bp = (domClass && domClass->mInterfaceChain[depth] == prototypeID);
+  return true;
+}
+
 bool
 ReportLenientThisUnwrappingFailure(JSContext* cx, JS::Handle<JSObject*> obj)
 {
   GlobalObject global(cx, obj);
   if (global.Failed()) {
     return false;
   }
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(global.Get());
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -2069,16 +2069,20 @@ ReparentWrapper(JSContext* aCx, JS::Hand
  */
 JSBool
 InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj,
                      JS::Handle<JSObject*> instance,
                      JSBool* bp);
 JSBool
 InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj, JS::MutableHandle<JS::Value> vp,
                      JSBool* bp);
+JSBool
+InterfaceHasInstance(JSContext* cx, int prototypeID, int depth,
+                     JS::Handle<JSObject*> instance,
+                     JSBool* bp);
 
 // Helper for lenient getters/setters to report to console.  If this
 // returns false, we couldn't even get a global.
 bool
 ReportLenientThisUnwrappingFailure(JSContext* cx, JS::Handle<JSObject*> obj);
 
 inline JSObject*
 GetUnforgeableHolder(JSObject* aGlobal, prototypes::ID aId)
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -24,16 +24,18 @@
 #                their primary interface.  Always False for callback interfaces.
 #                defaults to True otherwise.
 #   * workers - Indicates whether the descriptor is intended to be used for
 #               worker threads (defaults to false).
 #   * customTrace - The native class will use a custom trace hook (defaults to
 #                   true for workers, false otherwise).
 #   * customFinalize - The native class will use a custom finalize hook
 #                      (defaults to true for workers, false otherwise).
+#   * wantsQI - Indicates whether the interface should have a QueryInterface
+#               method available to chrome.
 #   * notflattened - The native type does not have nsIClassInfo, so when
 #                    wrapping it the right IID needs to be passed in.
 #   * register - True if this binding should be registered.  Defaults to true.
 #   * binaryNames - Dict for mapping method and attribute names to different
 #                   names when calling the native methods (defaults to an empty
 #                   dict). The keys are the property names as they appear in the
 #                   .webidl file and the values are the names as they should be
 #                   in the WebIDL.
@@ -600,19 +602,21 @@ DOMInterfaces = {
 {
     'nativeType': 'nsIJSID',
     'headerFile': 'xpcjsid.h',
 },
 {
     'workers': True,
 }],
 
-'ImageData': {
-   'wrapperCache': False
-},
+'ImageData': [
+{
+   'wrapperCache': False,
+   'wantsQI': False,
+}],
 
 'InputStream': [
 {
     'nativeType': 'nsIInputStream',
     'notflattened': True
 },
 {
     'workers': True,
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -18,16 +18,17 @@ AUTOGENERATED_WARNING_COMMENT = \
     "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
 ADDPROPERTY_HOOK_NAME = '_addProperty'
 FINALIZE_HOOK_NAME = '_finalize'
 TRACE_HOOK_NAME = '_trace'
 CONSTRUCT_HOOK_NAME = '_constructor'
 LEGACYCALLER_HOOK_NAME = '_legacycaller'
 HASINSTANCE_HOOK_NAME = '_hasInstance'
 NEWRESOLVE_HOOK_NAME = '_newResolve'
+ENUMERATE_HOOK_NAME= '_enumerate'
 ENUM_ENTRY_VARIABLE_NAME = 'strings'
 
 def replaceFileIfChanged(filename, newContents):
     """
     Read a copy of the old file, so that we don't touch it if it hasn't changed.
     Returns True if the file was updated, false otherwise.
     """
     oldFileContents = ""
@@ -83,17 +84,17 @@ class CGNativePropertyHooks(CGThing):
     def define(self):
         if self.descriptor.workers:
             return ""
         if self.descriptor.concrete and self.descriptor.proxy:
             resolveOwnProperty = "ResolveOwnProperty"
             enumerateOwnProperties = "EnumerateOwnProperties"
         elif self.descriptor.interface.getExtendedAttribute("NeedNewResolve"):
             resolveOwnProperty = "ResolveOwnPropertyViaNewresolve"
-            enumerateOwnProperties = "nullptr"
+            enumerateOwnProperties = "EnumerateOwnPropertiesViaGetOwnPropertyNames"
         else:
             resolveOwnProperty = "nullptr"
             enumerateOwnProperties = "nullptr"
         if self.properties.hasNonChromeOnly():
             regular = "&sNativeProperties"
         else:
             regular = "nullptr"
         if self.properties.hasChromeOnly():
@@ -168,43 +169,45 @@ class CGDOMJSClass(CGThing):
         return "extern DOMJSClass Class;\n"
     def define(self):
         traceHook = TRACE_HOOK_NAME if self.descriptor.customTrace else 'nullptr'
         callHook = LEGACYCALLER_HOOK_NAME if self.descriptor.operations["LegacyCaller"] else 'nullptr'
         classFlags = "JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(3)"
         if self.descriptor.interface.getExtendedAttribute("NeedNewResolve"):
             newResolveHook = "(JSResolveOp)" + NEWRESOLVE_HOOK_NAME
             classFlags += " | JSCLASS_NEW_RESOLVE"
+            enumerateHook = ENUMERATE_HOOK_NAME
         else:
             newResolveHook = "JS_ResolveStub"
+            enumerateHook = "JS_EnumerateStub"
         return """
 DOMJSClass Class = {
   { "%s",
     %s,
     %s, /* addProperty */
     JS_DeletePropertyStub, /* delProperty */
     JS_PropertyStub,       /* getProperty */
     JS_StrictPropertyStub, /* setProperty */
-    JS_EnumerateStub,
-    %s,
+    %s, /* enumerate */
+    %s, /* resolve */
     JS_ConvertStub,
     %s, /* finalize */
     nullptr,               /* checkAccess */
     %s, /* call */
     nullptr,               /* hasInstance */
     nullptr,               /* construct */
     %s, /* trace */
     JSCLASS_NO_INTERNAL_MEMBERS
   },
 %s
 };
 """ % (self.descriptor.interface.identifier.name,
        classFlags,
        ADDPROPERTY_HOOK_NAME if self.descriptor.concrete and not self.descriptor.workers and self.descriptor.wrapperCache else 'JS_PropertyStub',
-       newResolveHook, FINALIZE_HOOK_NAME, callHook, traceHook,
+       enumerateHook, newResolveHook, FINALIZE_HOOK_NAME, callHook, traceHook,
        CGIndenter(CGGeneric(DOMClass(self.descriptor))).define())
 
 def PrototypeIDAndDepth(descriptor):
     prototypeID = "prototypes::id::"
     if descriptor.interface.hasInterfacePrototypeObject():
         prototypeID += descriptor.interface.identifier.name
         if descriptor.workers:
             prototypeID += "_workers"
@@ -642,23 +645,25 @@ class CGHeaders(CGWrapper):
         callForEachType(descriptors + callbackDescriptors, dictionaries,
                         callbacks, addHeadersForType)
 
         # Now for non-callback descriptors make sure we include any
         # headers needed by Func declarations.
         for desc in descriptors:
             if desc.interface.isExternal():
                 continue
-            for m in desc.interface.members:
-                func = PropertyDefiner.getStringAttr(m, "Func")
+            def addHeaderForFunc(func):
                 # Include the right class header, which we can only do
                 # if this is a class member function.
                 if func is not None and "::" in func:
                     # Strip out the function name and convert "::" to "/"
                     bindingHeaders.add("/".join(func.split("::")[:-1]) + ".h")
+            for m in desc.interface.members:
+                addHeaderForFunc(PropertyDefiner.getStringAttr(m, "Func"))
+            addHeaderForFunc(desc.interface.getExtendedAttribute("Func"))
 
         for d in dictionaries:
             if d.parent:
                 declareIncludes.add(self.getDeclarationFilename(d.parent))
             bindingHeaders.add(self.getDeclarationFilename(d))
 
         for c in callbacks:
             bindingHeaders.add(self.getDeclarationFilename(c))
@@ -1364,31 +1369,16 @@ class PropertyDefiner:
 def overloadLength(arguments):
     i = len(arguments)
     while i > 0 and arguments[i - 1].optional:
         i -= 1
     return i
 def methodLength(method):
     signatures = method.signatures()
     return min(overloadLength(arguments) for (retType, arguments) in signatures)
-def requiresQueryInterfaceMethod(descriptor):
-    # Make sure to not stick QueryInterface on abstract interfaces that
-    # have hasXPConnectImpls (like EventTarget).  So only put it on
-    # interfaces that are concrete and all of whose ancestors are abstract.
-    def allAncestorsAbstract(iface):
-        if not iface.parent:
-            return True
-        desc = descriptor.getDescriptor(iface.parent.identifier.name)
-        if desc.concrete:
-            return False
-        return allAncestorsAbstract(iface.parent)
-    return (not descriptor.workers and
-            descriptor.interface.hasInterfacePrototypeObject() and
-            descriptor.concrete and
-            allAncestorsAbstract(descriptor.interface))
 
 class MethodDefiner(PropertyDefiner):
     """
     A class for defining methods on a prototype object.
     """
     def __init__(self, descriptor, name, static):
         PropertyDefiner.__init__(self, descriptor, name)
 
@@ -1420,17 +1410,17 @@ class MethodDefiner(PropertyDefiner):
         if any(m.isGetter() and m.isIndexed() for m in methods):
             self.regular.append({"name": 'iterator',
                                  "methodInfo": False,
                                  "nativeName": "JS_ArrayIterator",
                                  "length": 0,
                                  "flags": "JSPROP_ENUMERATE",
                                  "condition": MemberCondition(None, None) })
 
-        if not static and requiresQueryInterfaceMethod(descriptor):
+        if not static and descriptor.wantsQI():
             condition = "WantsQueryInterface<%s>::Enabled" % descriptor.nativeType
             self.regular.append({"name": 'QueryInterface',
                                  "methodInfo": False,
                                  "length": 1,
                                  "flags": "0",
                                  "condition": MemberCondition(None, condition) })
 
         if not static:
@@ -1715,17 +1705,19 @@ class CGCreateInterfaceObjectsMethod(CGA
                     idsToInit.append(props.variableName(False))
         if len(idsToInit) > 0:
             initIds = CGList(
                 [CGGeneric("!InitIds(aCx, %s, %s_ids)" % (varname, varname)) for
                  varname in idsToInit], ' ||\n')
             if len(idsToInit) > 1:
                 initIds = CGWrapper(initIds, pre="(", post=")", reindent=True)
             initIds = CGList(
-                [CGGeneric("%s_ids[0] == JSID_VOID &&" % idsToInit[0]), initIds],
+                [CGGeneric("%s_ids[0] == JSID_VOID &&" % idsToInit[0]),
+                 CGGeneric("NS_IsMainThread() &&"),
+                 initIds],
                 "\n")
             initIds = CGWrapper(initIds, pre="if (", post=") {", reindent=True)
             initIds = CGList(
                 [initIds,
                  CGGeneric(("  %s_ids[0] = JSID_VOID;\n"
                             "  return;") % idsToInit[0]),
                  CGGeneric("}")],
                 "\n")
@@ -1945,34 +1937,34 @@ class CGDefineDOMInterfaceMethod(CGAbstr
   }
   return interfaceObject;"""
         else:
             getConstructor = "  return GetConstructorObject(aCx, aGlobal);"
         return ("""  *aEnabled = true;
 
 """ + getConstructor)
 
-class CGPrefEnabledNative(CGAbstractMethod):
+class CGConstructorEnabledViaPrefEnabled(CGAbstractMethod):
     """
     A method for testing whether the preference controlling this
     interface is enabled. This delegates to PrefEnabled() on the
     wrapped class. The interface should only be visible on the global
     if the method returns true.
     """
     def __init__(self, descriptor):
         CGAbstractMethod.__init__(self, descriptor,
                                   'ConstructorEnabled', 'bool',
                                   [Argument("JSContext*", "/* unused */"),
                                    Argument("JS::Handle<JSObject*>",
                                             "/* unused */")])
 
     def definition_body(self):
         return "  return %s::PrefEnabled();" % self.descriptor.nativeType
 
-class CGPrefEnabled(CGAbstractMethod):
+class CGConstructorEnabledViaPref(CGAbstractMethod):
     """
     A method for testing whether the preference controlling this
     interface is enabled. This generates code in the binding to
     check the given preference. The interface should only be visible
     on the global if the pref is true.
     """
     def __init__(self, descriptor):
         CGAbstractMethod.__init__(self, descriptor,
@@ -1997,16 +1989,32 @@ class CGConstructorEnabledChromeOnly(CGA
         CGAbstractMethod.__init__(self, descriptor,
                                   'ConstructorEnabled', 'bool',
                                   [Argument("JSContext*", "aCx"),
                                    Argument("JS::Handle<JSObject*>", "aObj")])
 
     def definition_body(self):
         return "  return %s;" % GetAccessCheck(self.descriptor, "aObj")
 
+class CGConstructorEnabledViaFunc(CGAbstractMethod):
+    """
+    A method for testing whether the interface object should be exposed on a
+    given global based on whatever the callee wants to consider.
+    """
+    def __init__(self, descriptor):
+        CGAbstractMethod.__init__(self, descriptor,
+                                  'ConstructorEnabled', 'bool',
+                                  [Argument("JSContext*", "cx"),
+                                   Argument("JS::Handle<JSObject*>", "obj")])
+
+    def definition_body(self):
+        func = self.descriptor.interface.getExtendedAttribute("Func")
+        assert isinstance(func, list) and len(func) == 1
+        return "  return %s(cx, obj);" % func[0]
+
 class CGIsMethod(CGAbstractMethod):
     def __init__(self, descriptor):
         args = [Argument('JSObject*', 'obj')]
         CGAbstractMethod.__init__(self, descriptor, 'Is', 'bool', args)
 
     def definition_body(self):
         # Non-proxy implementation would check
         #   js::GetObjectJSClass(obj) == &Class.mBase
@@ -2143,17 +2151,17 @@ class CGWrapWithCacheMethod(CGAbstractMe
         args = [Argument('JSContext*', 'aCx'),
                 Argument('JS::Handle<JSObject*>', 'aScope'),
                 Argument(descriptor.nativeType + '*', 'aObject'),
                 Argument('nsWrapperCache*', 'aCache')]
         CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
         self.properties = properties
 
     def definition_body(self):
-        if self.descriptor.workers:
+        if self.descriptor.nativeOwnership == 'worker':
             return """  return aObject->GetJSObject();"""
 
         assertISupportsInheritance = (
             '  MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),\n'
             '             "nsISupports must be on our primary inheritance chain");\n')
         return """%s
 %s
   JS::Rooted<JSObject*> parent(aCx,
@@ -5331,45 +5339,70 @@ class CGLegacyCallHook(CGAbstractBinding
         return CGMethodCall(nativeName, False, self.descriptor,
                             self._legacycaller)
 
 class CGNewResolveHook(CGAbstractBindingMethod):
     """
     NewResolve hook for our object
     """
     def __init__(self, descriptor):
-        self._needNewResolve = descriptor.interface.getExtendedAttribute("NeedNewResolve")
+        assert descriptor.interface.getExtendedAttribute("NeedNewResolve")
         args = [Argument('JSContext*', 'cx'), Argument('JS::Handle<JSObject*>', 'obj'),
                 Argument('JS::Handle<jsid>', 'id'), Argument('unsigned', 'flags'),
                 Argument('JS::MutableHandle<JSObject*>', 'objp')]
-        # Our "self" is actually the callee in this case, not the thisval.
+        # Our "self" is actually the "obj" argument in this case, not the thisval.
         CGAbstractBindingMethod.__init__(
             self, descriptor, NEWRESOLVE_HOOK_NAME,
             args, getThisObj="", callArgs="")
 
-    def define(self):
-        if not self._needNewResolve:
-            return ""
-        return CGAbstractBindingMethod.define(self)
-
     def generate_code(self):
         return CGIndenter(CGGeneric(
                 "JS::Rooted<JS::Value> value(cx);\n"
                 "if (!self->DoNewResolve(cx, obj, id, &value)) {\n"
                 "  return false;\n"
                 "}\n"
                 "if (value.isUndefined()) {\n"
                 "  return true;\n"
                 "}\n"
                 "if (!JS_DefinePropertyById(cx, obj, id, value, nullptr, nullptr, JSPROP_ENUMERATE)) {\n"
                 "  return false;\n"
                 "}\n"
                 "objp.set(obj);\n"
                 "return true;"))
 
+class CGEnumerateHook(CGAbstractBindingMethod):
+    """
+    Enumerate hook for our object
+    """
+    def __init__(self, descriptor):
+        assert descriptor.interface.getExtendedAttribute("NeedNewResolve")
+        args = [Argument('JSContext*', 'cx'),
+                Argument('JS::Handle<JSObject*>', 'obj')]
+        # Our "self" is actually the "obj" argument in this case, not the thisval.
+        CGAbstractBindingMethod.__init__(
+            self, descriptor, ENUMERATE_HOOK_NAME,
+            args, getThisObj="", callArgs="")
+
+    def generate_code(self):
+        return CGIndenter(CGGeneric(
+                "nsAutoTArray<nsString, 8> names;\n"
+                "ErrorResult rv;\n"
+                "self->GetOwnPropertyNames(cx, names, rv);\n"
+                "rv.WouldReportJSException();\n"
+                "if (rv.Failed()) {\n"
+                '  return ThrowMethodFailedWithDetails<true>(cx, rv, "%s", "enumerate");\n'
+                "}\n"
+                "JS::Rooted<JS::Value> dummy(cx);\n"
+                "for (uint32_t i = 0; i < names.Length(); ++i) {\n"
+                "  if (!JS_LookupUCProperty(cx, obj, names[i].get(), names[i].Length(), &dummy)) {\n"
+                "    return false;\n"
+                "  }\n"
+                "}\n"
+                "return true;"))
+
 class CppKeywords():
     """
     A class for checking if method names declared in webidl
     are not in conflict with C++ keywords.
     """
     keywords = frozenset(['alignas', 'alignof', 'and', 'and_eq', 'asm', 'auto', 'bitand', 'bitor', 'bool',
     'break', 'case', 'catch', 'char', 'char16_t', 'char32_t', 'class', 'compl', 'const', 'constexpr',
     'const_cast', 'continue', 'decltype', 'default', 'delete', 'do', 'double', 'dynamic_cast', 'else', 'enum',
@@ -6915,16 +6948,43 @@ class CGEnumerateOwnProperties(CGAbstrac
                 Argument('JS::Handle<JSObject*>', 'obj'),
                 Argument('JS::AutoIdVector&', 'props')]
         CGAbstractStaticMethod.__init__(self, descriptor,
                                         "EnumerateOwnProperties", "bool", args)
     def definition_body(self):
         return """  return js::GetProxyHandler(obj)->getOwnPropertyNames(cx, wrapper, props);
 """
 
+class CGEnumerateOwnPropertiesViaGetOwnPropertyNames(CGAbstractBindingMethod):
+    """
+    An implementation of Xray EnumerateOwnProperties stuff for things
+    that have a newresolve hook.
+    """
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'),
+                Argument('JS::Handle<JSObject*>', 'wrapper'),
+                Argument('JS::Handle<JSObject*>', 'obj'),
+                Argument('JS::AutoIdVector&', 'props')]
+        CGAbstractBindingMethod.__init__(self, descriptor,
+                                         "EnumerateOwnPropertiesViaGetOwnPropertyNames",
+                                         args, getThisObj="",
+                                         callArgs="", returnType="bool")
+    def generate_code(self):
+        return CGIndenter(CGGeneric(
+                "nsAutoTArray<nsString, 8> names;\n"
+                "ErrorResult rv;\n"
+                "self->GetOwnPropertyNames(cx, names, rv);\n"
+                "rv.WouldReportJSException();\n"
+                "if (rv.Failed()) {\n"
+                '  return ThrowMethodFailedWithDetails<true>(cx, rv, "%s", "enumerate");\n'
+                "}\n"
+                '// OK to pass null as "proxy" because it\'s ignored if\n'
+                "// shadowPrototypeProperties is true\n"
+                "return DOMProxyHandler::AppendNamedPropertyIds(cx, JS::NullPtr(), names, true, nullptr, props);"))
+
 class CGPrototypeTraitsClass(CGClass):
     def __init__(self, descriptor, indent=''):
         templateArgs = [Argument('prototypes::ID', 'PrototypeID')]
         templateSpecialization = ['prototypes::id::' + descriptor.name]
         enums = [ClassEnum('', ['Depth'],
                            [descriptor.interface.inheritanceDepth()])]
         typedefs = [ClassTypedef('NativeType', descriptor.nativeType)]
         CGClass.__init__(self, 'PrototypeTraits', indent=indent,
@@ -7483,17 +7543,17 @@ for (int32_t i = 0; i < int32_t(length);
         if self.descriptor.supportsNamedProperties():
             if self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
                 shadow = "!isXray"
             else:
                 shadow = "false"
             addNames = """
 nsTArray<nsString> names;
 UnwrapProxy(proxy)->GetSupportedNames(names);
-if (!AppendNamedPropertyIds(cx, proxy, names, %s, props)) {
+if (!AppendNamedPropertyIds(cx, proxy, names, %s, this, props)) {
   return false;
 }
 """ % shadow
         else:
             addNames = ""
 
         if UseHolderForUnforgeable(self.descriptor):
             addUnforgeable = (
@@ -7877,32 +7937,35 @@ class CGDescriptor(CGThing):
 
         # Set up our Xray callbacks as needed.  Note that we don't need to do
         # it in workers.
         if not descriptor.workers and descriptor.concrete and descriptor.proxy:
             cgThings.append(CGResolveOwnProperty(descriptor))
             cgThings.append(CGEnumerateOwnProperties(descriptor))
         elif descriptor.interface.getExtendedAttribute("NeedNewResolve"):
             cgThings.append(CGResolveOwnPropertyViaNewresolve(descriptor))
+            cgThings.append(CGEnumerateOwnPropertiesViaGetOwnPropertyNames(descriptor))
 
         # Now that we have our ResolveOwnProperty/EnumerateOwnProperties stuff
         # done, set up our NativePropertyHooks.
         cgThings.append(CGNativePropertyHooks(descriptor, properties))
 
         if descriptor.interface.hasInterfaceObject():
             cgThings.append(CGClassConstructor(descriptor,
                                                descriptor.interface.ctor()))
             cgThings.append(CGClassHasInstanceHook(descriptor))
             cgThings.append(CGInterfaceObjectJSClass(descriptor, properties))
             if descriptor.needsConstructHookHolder():
                 cgThings.append(CGClassConstructHookHolder(descriptor))
             cgThings.append(CGNamedConstructors(descriptor))
 
         cgThings.append(CGLegacyCallHook(descriptor))
-        cgThings.append(CGNewResolveHook(descriptor))
+        if descriptor.interface.getExtendedAttribute("NeedNewResolve"):
+            cgThings.append(CGNewResolveHook(descriptor))
+            cgThings.append(CGEnumerateHook(descriptor))
 
         if descriptor.interface.hasInterfacePrototypeObject():
             cgThings.append(CGPrototypeJSClass(descriptor, properties))
 
         cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties))
         if descriptor.interface.hasInterfacePrototypeObject():
             cgThings.append(CGGetProtoObjectMethod(descriptor))
         if descriptor.interface.hasInterfaceObject():
@@ -7913,27 +7976,31 @@ class CGDescriptor(CGThing):
 
         if ((descriptor.interface.hasInterfaceObject() or descriptor.interface.getNavigatorProperty()) and
             not descriptor.interface.isExternal() and
             # Workers stuff is never pref-controlled
             not descriptor.workers):
             prefControlled = descriptor.interface.getExtendedAttribute("PrefControlled")
             havePref = descriptor.interface.getExtendedAttribute("Pref")
             haveChromeOnly = descriptor.interface.getExtendedAttribute("ChromeOnly")
+            haveFunc = descriptor.interface.getExtendedAttribute("Func")
             # Make sure at most one of those is set
-            if bool(prefControlled) + bool(havePref) + bool(haveChromeOnly) > 1:
+            if (bool(prefControlled) + bool(havePref) +
+                bool(haveChromeOnly) + bool(haveFunc) > 1):
                 raise TypeError("Interface %s has more than one of "
-                                "'PrefControlled', 'Pref', and 'ChomeOnly' "
-                                "specified", descriptor.name)
+                                "'PrefControlled', 'Pref', 'Func', and "
+                                "'ChomeOnly' specified", descriptor.name)
             if prefControlled is not None:
-                cgThings.append(CGPrefEnabledNative(descriptor))
+                cgThings.append(CGConstructorEnabledViaPrefEnabled(descriptor))
             elif havePref is not None:
-                cgThings.append(CGPrefEnabled(descriptor))
+                cgThings.append(CGConstructorEnabledViaPref(descriptor))
             elif haveChromeOnly is not None:
                 cgThings.append(CGConstructorEnabledChromeOnly(descriptor))
+            elif haveFunc is not None:
+                cgThings.append(CGConstructorEnabledViaFunc(descriptor))
 
         if descriptor.concrete:
             if descriptor.proxy:
                 cgThings.append(CGGeneric("""static_assert(IsBaseOf<nsISupports, %s >::value,
                   "We don't support non-nsISupports native classes for "
                   "proxy-based bindings yet");
 
 """ % descriptor.nativeType))
@@ -8449,17 +8516,18 @@ class CGRegisterProtos(CGAbstractMethod)
         return """
 #undef REGISTER_CONSTRUCTOR
 #undef REGISTER_PROTO
 #undef REGISTER_NAVIGATOR_CONSTRUCTOR"""
     def _registerProtos(self):
         def getCheck(desc):
             if (desc.interface.getExtendedAttribute("PrefControlled") is None and
                 desc.interface.getExtendedAttribute("Pref") is None and
-                desc.interface.getExtendedAttribute("ChromeOnly") is None):
+                desc.interface.getExtendedAttribute("ChromeOnly") is None and
+                desc.interface.getExtendedAttribute("Func") is None):
                 return "nullptr"
             return "%sBinding::ConstructorEnabled" % desc.name
         lines = []
         for desc in self.config.getDescriptors(hasInterfaceObject=True,
                                                isExternal=False,
                                                workers=False,
                                                register=True):
             lines.append("REGISTER_PROTO(%s, %s);" % (desc.name, getCheck(desc)))
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -353,32 +353,30 @@ class Descriptor(DescriptorProvider):
                                       "we don't support that yet.\n%s" %
                                       (self.interface, self.interface.location))
                 iface = self.interface
                 while iface:
                     iface.setUserData('hasProxyDescendant', True)
                     iface = iface.parent
         self.operations = operations
 
-        if self.workers:
-            if desc.get('nativeOwnership', 'worker') != 'worker':
-                raise TypeError("Worker descriptor for %s should have 'worker' "
-                                "as value for nativeOwnership" %
-                                self.interface.identifier.name)
+        if self.workers and desc.get('nativeOwnership', 'worker') == 'worker':
             self.nativeOwnership = "worker"
         else:
             self.nativeOwnership = desc.get('nativeOwnership', 'refcounted')
             if not self.nativeOwnership in ['owned', 'refcounted']:
                 raise TypeError("Descriptor for %s has unrecognized value (%s) "
                                 "for nativeOwnership" %
                                 (self.interface.identifier.name, self.nativeOwnership))
         self.customTrace = desc.get('customTrace', self.workers)
         self.customFinalize = desc.get('customFinalize', self.workers)
+        if desc.get('wantsQI', None) != None:
+            self._wantsQI = desc.get('wantsQI', None)
         self.wrapperCache = (not self.interface.isCallback() and
-                             (self.workers or
+                             (self.nativeOwnership == 'worker' or
                               (self.nativeOwnership != 'owned' and
                                desc.get('wrapperCache', True))))
 
         def make_name(name):
             return name + "_workers" if self.workers else name
         self.name = make_name(interface.identifier.name)
 
         # self.extendedAttributes is a dict of dicts, keyed on
@@ -483,16 +481,36 @@ class Descriptor(DescriptorProvider):
         """
         An interface doesn't need a header file if it is not concrete,
         not pref-controlled, and has only consts.
         """
         return (self.interface.isExternal() or self.concrete or
             self.interface.getExtendedAttribute("PrefControlled") or
             self.interface.hasInterfacePrototypeObject())
 
+    def wantsQI(self):
+        # If it was specified explicitly use that.
+        if hasattr(self, '_wantsQI'):
+            return self._wantsQI
+
+        # Make sure to not stick QueryInterface on abstract interfaces that
+        # have hasXPConnectImpls (like EventTarget).  So only put it on
+        # interfaces that are concrete and all of whose ancestors are abstract.
+        def allAncestorsAbstract(iface):
+            if not iface.parent:
+                return True
+            desc = self.getDescriptor(iface.parent.identifier.name)
+            if desc.concrete:
+                return False
+            return allAncestorsAbstract(iface.parent)
+        return (not self.workers and
+                self.interface.hasInterfacePrototypeObject() and
+                self.concrete and
+                allAncestorsAbstract(self.interface))
+
 # Some utility methods
 def getTypesFromDescriptor(descriptor):
     """
     Get all argument and return types for all members of the descriptor
     """
     members = [m for m in descriptor.interface.members]
     if descriptor.interface.ctor():
         members.append(descriptor.interface.ctor())
--- a/dom/bindings/DOMJSProxyHandler.cpp
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -261,36 +261,38 @@ DOMProxyHandler::has(JSContext* cx, JS::
   JSBool protoHasProp;
   bool ok = JS_HasPropertyById(cx, proto, id, &protoHasProp);
   if (ok) {
     *bp = protoHasProp;
   }
   return ok;
 }
 
+/* static */
 bool
 DOMProxyHandler::AppendNamedPropertyIds(JSContext* cx,
                                         JS::Handle<JSObject*> proxy,
                                         nsTArray<nsString>& names,
                                         bool shadowPrototypeProperties,
+                                        DOMProxyHandler* handler,
                                         JS::AutoIdVector& props)
 {
   for (uint32_t i = 0; i < names.Length(); ++i) {
     JS::Rooted<JS::Value> v(cx);
     if (!xpc::NonVoidStringToJsval(cx, names[i], v.address())) {
       return false;
     }
 
     JS::Rooted<jsid> id(cx);
     if (!JS_ValueToId(cx, v, id.address())) {
       return false;
     }
 
     if (shadowPrototypeProperties ||
-        !HasPropertyOnPrototype(cx, proxy, this, id)) {
+        !HasPropertyOnPrototype(cx, proxy, handler, id)) {
       if (!props.append(id)) {
         return false;
       }
     }
   }
 
   return true;
 }
--- a/dom/bindings/DOMJSProxyHandler.h
+++ b/dom/bindings/DOMJSProxyHandler.h
@@ -72,24 +72,25 @@ public:
   }
   /* GetAndClearExpandoObject does not DROP or clear the preserving wrapper flag. */
   static JSObject* GetAndClearExpandoObject(JSObject* obj);
   static JSObject* EnsureExpandoObject(JSContext* cx,
                                        JS::Handle<JSObject*> obj);
 
   const DOMClass& mClass;
 
-protected:
   // Append the property names in "names" to "props". If
   // shadowPrototypeProperties is false then skip properties that are also
-  // present on our proto chain.
-  bool AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
-                              nsTArray<nsString>& names,
-                              bool shadowPrototypeProperties,
-                              JS::AutoIdVector& props);
+  // present on our proto chain.  If shadowPrototypeProperties is true,
+  // then the "proxy" and "handler" arguments are ignored.
+  static bool AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
+                                     nsTArray<nsString>& names,
+                                     bool shadowPrototypeProperties,
+                                     DOMProxyHandler* handler,
+                                     JS::AutoIdVector& props);
 };
 
 extern jsid s_length_id;
 
 int32_t IdToInt32(JSContext* cx, JS::Handle<jsid> id);
 
 // XXXbz this should really return uint32_t, with the maximum value
 // meaning "not an index"...
--- a/dom/bindings/Makefile.in
+++ b/dom/bindings/Makefile.in
@@ -69,16 +69,17 @@ CPPSRCS = \
   CallbackInterface.cpp \
   CallbackObject.cpp \
   DOMJSProxyHandler.cpp \
   $(NULL)
 endif
 
 LOCAL_INCLUDES += -I$(topsrcdir)/js/xpconnect/src \
   -I$(topsrcdir)/js/xpconnect/wrappers \
+  -I$(topsrcdir)/js/ipc \
   -I$(topsrcdir)/content/canvas/src \
   -I$(topsrcdir)/content/html/content/src \
   -I$(topsrcdir)/media/webrtc/signaling/src/peerconnection \
   -I$(topsrcdir)/dom/base \
   -I$(topsrcdir)/dom/battery \
   -I$(topsrcdir)/dom/indexedDB \
   -I$(topsrcdir)/content/xslt/src/base \
   -I$(topsrcdir)/content/xslt/src/xpath \
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -927,17 +927,18 @@ class IDLInterface(IDLObjectWithScope):
                   identifier == "ChromeOnly"):
                 # Known extended attributes that do not take values
                 if not attr.noArguments():
                     raise WebIDLError("[%s] must take no arguments" % identifier,
                                       [attr.location])
             elif (identifier == "Pref" or
                   identifier == "JSImplementation" or
                   identifier == "HeaderFile" or
-                  identifier == "NavigatorProperty"):
+                  identifier == "NavigatorProperty" or
+                  identifier == "Func"):
                 # Known extended attributes that take a string value
                 if not attr.hasValue():
                     raise WebIDLError("[%s] must have a value" % identifier,
                                       [attr.location])
             else:
                 raise WebIDLError("Unknown extended attribute %s on interface" % identifier,
                                   [attr.location])
 
--- a/dom/bindings/test/Makefile.in
+++ b/dom/bindings/test/Makefile.in
@@ -58,32 +58,35 @@ MOCHITEST_FILES := \
   test_lookupGetter.html \
   test_InstanceOf.html \
   file_InstanceOf.html \
   test_traceProtos.html \
   test_forOf.html \
   forOf_iframe.html \
   test_sequence_wrapping.html \
   file_bug775543.html \
+  file_bug707564.html \
   test_bug788369.html \
   test_bug742191.html \
   test_namedNoIndexed.html \
   test_bug759621.html \
   test_queryInterface.html \
   test_exceptionThrowing.html \
   test_bug852846.html \
   test_bug862092.html \
   test_bug560072.html \
   test_lenientThis.html \
   test_ByteString.html \
   test_exception_messages.html \
+  test_bug707564.html \
   $(NULL)
 
 MOCHITEST_CHROME_FILES = \
   test_bug775543.html \
+  test_bug707564-chrome.html \
   $(NULL)
 
 ifdef GNU_CC
 CXXFLAGS += -Wno-uninitialized
 endif
 
 # Include rules.mk before any of our targets so our first target is coming from
 # rules.mk and running make with no target in this dir does the right thing.
new file mode 100644
--- /dev/null
+++ b/dom/bindings/test/file_bug707564.html
@@ -0,0 +1,5 @@
+<body>
+<script>
+  navigator.foopy = 5;
+</script>
+</body>
new file mode 100644
--- /dev/null
+++ b/dom/bindings/test/test_bug707564-chrome.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=707564
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 707564</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=707564">Mozilla Bug 707564</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe id="t1" src="http://example.org/tests/dom/bindings/test/file_bug707564.html"></iframe>
+<iframe id="t2" src="http://example.org/tests/dom/bindings/test/file_bug707564.html"></iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 775543 **/
+function test()
+{
+  var nav = document.getElementById("t1").contentWindow.navigator;
+  ise(nav.foopy, undefined, "We should have an Xray now");
+  is(nav.wrappedJSObject.foopy, 5, "We should have the right navigator object");
+  var props = Object.getOwnPropertyNames(nav);
+  isnot(props.indexOf("mozApps"), -1,
+        "Should enumerate a mozApps property on navigator xray");
+
+  var nav = document.getElementById("t2").contentWindow.navigator;
+  ise(nav.foopy, undefined, "We should have an Xray now again");
+  is(nav.wrappedJSObject.foopy, 5, "We should have the right navigator object again");
+  var found = false;
+  for (var name in nav) {
+    if (name == "mozApps") {
+      found = true;
+    }
+  }
+  ok(found, "Should enumerate a mozApps property on navigator xray via for...in");
+
+  SimpleTest.finish();
+}
+
+addLoadEvent(test);
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/bindings/test/test_bug707564.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=707564
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 707564</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  /** Test for Bug 707564 **/
+  SimpleTest.waitForExplicitFinish();
+
+  addLoadEvent(function() {
+    var props = Object.getOwnPropertyNames(frames[0].navigator);
+    isnot(props.indexOf("mozApps"), -1,
+          "Should enumerate a mozApps property on navigator");
+
+    // Now enumerate a different navigator object
+    var found = false;
+    for (var name in frames[1].navigator) {
+      if (name == "mozApps") {
+        found = true;
+      }
+    }
+    ok(found, "Should enumerate a mozApps property on navigator via for...in");
+    SimpleTest.finish();
+  });
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=707564">Mozilla Bug 707564</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe></iframe>
+<iframe></iframe>
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
deleted file mode 100644
--- a/dom/interfaces/push/moz.build
+++ /dev/null
@@ -1,9 +0,0 @@
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-MODULE        = 'dom'
-XPIDL_MODULE  = 'dom_push'
-XPIDL_SOURCES += ['nsIDOMPushManager.idl']
-XPIDL_FLAGS += ['-I$(topsrcdir)/dom/interfaces/base']
deleted file mode 100644
--- a/dom/interfaces/push/nsIDOMPushManager.idl
+++ /dev/null
@@ -1,45 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "domstubs.idl"
-interface nsIDOMDOMRequest;
-
-/**
- * Client API for SimplePush.
- *
- * The SimplePush API allows web applications to use push notifications and be
- * woken up when something of interest has changed. This frees web applications
- * from implementing polling, giving better responsiveness and conserving the
- * device's battery life.
- */
-[scriptable,uuid(c7ad4f42-faae-4e8b-9879-780a72349945)]
-interface nsIDOMPushManager : nsISupports
-{
-  /**
-   * Register for a new push endpoint.
-   *
-   * On success, the DOMRequest's result field will be a string URL.  This URL
-   * is the endpoint that can be contacted to wake up the application.
-   */
-  nsIDOMDOMRequest register();
-  
-  /**
-   * Unregister a push endpoint.
-   *
-   * On success, the DOMRequest's result field will be the endpoint that was
-   * passed in.
-   *
-   * Stops watching for changes to this URL.
-   */
-  nsIDOMDOMRequest unregister(in ACString endpoint);
-
-  /**
-   * Get a list of active registrations for this web app.
-   *
-   * On success, the DOMRequest's result field is an array of endpoints.
-   * For example:
-   *   ["https://example.com/notify/1", "https://example.com/notify/2"]
-   */
-  nsIDOMDOMRequest registrations();
-};
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -186,16 +186,22 @@ parent:
      * Return native data of root widget
      */
     sync GetWidgetNativeData() returns (WindowsHandle value);
 
     SetCursor(uint32_t value);
     SetBackgroundColor(nscolor color);
 
     /**
+     * Used to set the current text of the status tooltip.
+     * Nowadays this is mainly used for link locations on hover.
+     */
+    SetStatus(uint32_t type, nsString status);
+
+    /**
      * Initiates an asynchronous request for permission for the
      * provided principal.
      *
      * @param aType
      *   The type of permission to request.
      * @param aAccess
      *   Access type. "read" for example.
      * @param aPrincipal
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -739,18 +739,20 @@ NS_INTERFACE_MAP_BEGIN(TabChild)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(TabChild)
 NS_IMPL_RELEASE(TabChild)
 
 NS_IMETHODIMP
 TabChild::SetStatus(uint32_t aStatusType, const PRUnichar* aStatus)
 {
-  // FIXME/bug 617804: should the platform support this?
-  return NS_OK;
+  return SetStatusWithContext(aStatusType,
+      aStatus ? static_cast<const nsString &>(nsDependentString(aStatus))
+              : EmptyString(),
+      nullptr);
 }
 
 NS_IMETHODIMP
 TabChild::GetWebBrowser(nsIWebBrowser** aWebBrowser)
 {
   NS_NOTREACHED("TabChild::GetWebBrowser not supported in TabChild");
 
   return NS_ERROR_NOT_IMPLEMENTED;
@@ -815,20 +817,23 @@ TabChild::ExitModalEventLoop(nsresult aS
 {
   NS_NOTREACHED("TabChild::ExitModalEventLoop not supported in TabChild");
 
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 TabChild::SetStatusWithContext(uint32_t aStatusType,
-                                    const nsAString& aStatusText,
-                                    nsISupports* aStatusContext)
+                               const nsAString& aStatusText,
+                               nsISupports* aStatusContext)
 {
-  // FIXME/bug 617804: should the platform support this?
+  // We can only send the status after the ipc machinery is set up,
+  // mRemoteFrame is a good indicator.
+  if (mRemoteFrame)
+    SendSetStatus(aStatusType, nsString(aStatusText));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TabChild::SetDimensions(uint32_t aFlags, int32_t aX, int32_t aY,
                              int32_t aCx, int32_t aCy)
 {
   NS_NOTREACHED("TabChild::SetDimensions not supported in TabChild");
@@ -2203,24 +2208,29 @@ TabChild::InitRenderingState()
       NS_WARNING("failed to construct RenderFrame");
       return false;
     }
 
     PLayerTransactionChild* shadowManager = nullptr;
     if (id != 0) {
         // Pushing layers transactions directly to a separate
         // compositor context.
-		PCompositorChild* compositorChild = CompositorChild::Get();
+        PCompositorChild* compositorChild = CompositorChild::Get();
         if (!compositorChild) {
           NS_WARNING("failed to get CompositorChild instance");
           return false;
         }
+        bool success;
         shadowManager =
             compositorChild->SendPLayerTransactionConstructor(mTextureFactoryIdentifier.mParentBackend,
-                                                              id, &mTextureFactoryIdentifier);
+                                                              id, &mTextureFactoryIdentifier, &success);
+        if (!success) {
+          NS_WARNING("failed to properly allocate layer transaction");
+          return false;
+        }
     } else {
         // Pushing transactions to the parent content.
         shadowManager = remoteFrame->SendPLayerTransactionConstructor();
     }
 
     if (!shadowManager) {
       NS_WARNING("failed to construct LayersChild");
       // This results in |remoteFrame| being deleted.
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -36,16 +36,19 @@
 #include "nsIDOMEvent.h"
 #include "nsIDOMHTMLFrameElement.h"
 #include "nsIDOMWindow.h"
 #include "nsIDialogCreator.h"
 #include "nsIPromptFactory.h"
 #include "nsIURI.h"
 #include "nsIMozBrowserFrame.h"
 #include "nsIScriptSecurityManager.h"
+#include "nsIWebBrowserChrome.h"
+#include "nsIXULBrowserWindow.h"
+#include "nsIXULWindow.h"
 #include "nsViewManager.h"
 #include "nsIWidget.h"
 #include "nsIWindowWatcher.h"
 #include "nsNetUtil.h"
 #include "nsPIDOMWindow.h"
 #include "nsPrintfCString.h"
 #include "nsSerializationHelper.h"
 #include "nsServiceManagerUtils.h"
@@ -744,16 +747,52 @@ TabParent::RecvSetBackgroundColor(const 
 {
   if (RenderFrameParent* frame = GetRenderFrame()) {
     frame->SetBackgroundColor(aColor);
   }
   return true;
 }
 
 bool
+TabParent::RecvSetStatus(const uint32_t& aType, const nsString& aStatus)
+{
+  nsCOMPtr<nsIContent> frame = do_QueryInterface(mFrameElement);
+  if (frame) {
+    nsCOMPtr<nsISupports> container = frame->OwnerDoc()->GetContainer();
+    if (!container)
+      return true;
+    nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
+    if (!docShell)
+      return true;
+    nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
+    docShell->GetTreeOwner(getter_AddRefs(treeOwner));
+    if (!treeOwner)
+      return true;
+
+    nsCOMPtr<nsIXULWindow> window = do_GetInterface(treeOwner);
+    if (window) {
+      nsCOMPtr<nsIXULBrowserWindow> xulBrowserWindow;
+      window->GetXULBrowserWindow(getter_AddRefs(xulBrowserWindow));
+      if (xulBrowserWindow) {
+        switch (aType)
+        {
+        case nsIWebBrowserChrome::STATUS_SCRIPT:
+          xulBrowserWindow->SetJSStatus(aStatus);
+          break;
+        case nsIWebBrowserChrome::STATUS_LINK:
+          xulBrowserWindow->SetOverLink(aStatus, nullptr);
+          break;
+        }
+      }
+    }
+  }
+  return true;
+}
+
+bool
 TabParent::RecvNotifyIMEFocus(const bool& aFocus,
                               nsIMEUpdatePreference* aPreference,
                               uint32_t* aSeqno)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     aPreference->mWantUpdates = nsIMEUpdatePreference::NOTIFY_NOTHING;
     aPreference->mWantHints = false;
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -148,16 +148,17 @@ public:
                                      const int32_t& aIMEOpen,
                                      const nsString& aType,
                                      const nsString& aInputmode,
                                      const nsString& aActionHint,
                                      const int32_t& aCause,
                                      const int32_t& aFocusChange);
     virtual bool RecvSetCursor(const uint32_t& aValue);
     virtual bool RecvSetBackgroundColor(const nscolor& aValue);
+    virtual bool RecvSetStatus(const uint32_t& aType, const nsString& aStatus);
     virtual bool RecvGetDPI(float* aValue);
     virtual bool RecvGetDefaultScale(double* aValue);
     virtual bool RecvGetWidgetNativeData(WindowsHandle* aValue);
     virtual bool RecvZoomToRect(const CSSRect& aRect);
     virtual bool RecvUpdateZoomConstraints(const bool& aAllowZoom,
                                            const float& aMinZoom,
                                            const float& aMaxZoom);
     virtual bool RecvContentReceivedTouch(const bool& aPreventDefault);
--- a/dom/moz.build
+++ b/dom/moz.build
@@ -22,17 +22,16 @@ interfaces = [
     'xpath',
     'xul',
     'storage',
     'json',
     'offline',
     'geolocation',
     'notification',
     'permission',
-    'push',
     'svg',
     'smil',
     'apps',
     'gamepad',
 ]
 
 PARALLEL_DIRS += ['interfaces/' + i for i in interfaces]
 
--- a/dom/network/src/TCPSocket.js
+++ b/dom/network/src/TCPSocket.js
@@ -345,17 +345,22 @@ TCPSocket.prototype = {
     that._socketBridge = socketChild;
 
     return that;
   },
 
   /* end nsITCPSocketInternal methods */
 
   initWindowless: function ts_initWindowless() {
-    return Services.prefs.getBoolPref("dom.mozTCPSocket.enabled");
+    try {
+      return Services.prefs.getBoolPref("dom.mozTCPSocket.enabled");
+    } catch (e) {
+      // no pref means return false
+      return false;
+    }
   },
 
   init: function ts_init(aWindow) {
     if (!this.initWindowless())
       return null;
 
     let principal = aWindow.document.nodePrincipal;
     let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"]
--- a/dom/push/src/Push.js
+++ b/dom/push/src/Push.js
@@ -12,81 +12,73 @@ const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
 Cu.import("resource://gre/modules/AppsUtils.jsm");
 
-const PUSH_CID = Components.ID("{c7ad4f42-faae-4e8b-9879-780a72349945}");
+const PUSH_CID = Components.ID("{cde1d019-fad8-4044-b141-65fb4fb7a245}");
 
 /**
  * The Push component runs in the child process and exposes the SimplePush API
  * to the web application. The PushService running in the parent process is the
  * one actually performing all operations.
  */
-function Push()
-{
+function Push() {
   debug("Push Constructor");
 }
 
 Push.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
 
+  contractID: "@mozilla.org/push/PushManager;1",
+
   classID : PUSH_CID,
 
   QueryInterface : XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
                                           Ci.nsISupportsWeakReference]),
 
   init: function(aWindow) {
     debug("init()");
 
-    if (!Services.prefs.getBoolPref("services.push.enabled"))
-      return null;
-
     let principal = aWindow.document.nodePrincipal;
 
     this._pageURL = principal.URI;
 
     let appsService = Cc["@mozilla.org/AppsService;1"]
                         .getService(Ci.nsIAppsService);
     this._app = appsService.getAppByLocalId(principal.appId);
     this._manifestURL = appsService.getManifestURLByLocalId(principal.appId);
-    if (!this._manifestURL)
-      return null;
+    if (!this._manifestURL) {
+	// Now what?  XXXbz should this be tested in a Func for this
+	// interface so it wouldn't appear at all?
+	return;
+    }
 
     let perm = Services.perms.testExactPermissionFromPrincipal(principal,
                                                                "push");
-    if (perm != Ci.nsIPermissionManager.ALLOW_ACTION)
-      return null;
+    if (perm != Ci.nsIPermissionManager.ALLOW_ACTION) {
+	// Now what?  XXXbz should this be tested in a Func for this
+	// interface so it wouldn't appear at all?
+	return;
+    }
 
     this.initDOMRequestHelper(aWindow, [
       "PushService:Register:OK",
       "PushService:Register:KO",
       "PushService:Unregister:OK",
       "PushService:Unregister:KO",
       "PushService:Registrations:OK",
       "PushService:Registrations:KO"
     ]);
 
     this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
                    .getService(Ci.nsISyncMessageSender);
-
-    var self = this;
-    return {
-      register: self.register.bind(self),
-      unregister: self.unregister.bind(self),
-      registrations: self.registrations.bind(self),
-      __exposedProps__: {
-        register: "r",
-        unregister: "r",
-        registrations: "r"
-      }
-    };
   },
 
   receiveMessage: function(aMessage) {
     debug("receiveMessage()");
     let request = this.getRequest(aMessage.data.requestID);
     let json = aMessage.data;
     if (!request) {
       debug("No request " + json.requestID);
--- a/dom/push/src/Push.manifest
+++ b/dom/push/src/Push.manifest
@@ -1,9 +1,8 @@
 # DOM API
-component {c7ad4f42-faae-4e8b-9879-780a72349945} Push.js
-contract @mozilla.org/Push;1 {c7ad4f42-faae-4e8b-9879-780a72349945}
-category JavaScript-navigator-property push @mozilla.org/Push;1
+component {cde1d019-fad8-4044-b141-65fb4fb7a245} Push.js
+contract @mozilla.org/push/PushManager;1 {cde1d019-fad8-4044-b141-65fb4fb7a245}
 
 # Component to initialize PushService on startup.
 component {4b8caa3b-3c58-4f3c-a7f5-7bd9cb24c11d} PushServiceLauncher.js
-contract @mozilla.org/dom/push/service;1 {4b8caa3b-3c58-4f3c-a7f5-7bd9cb24c11d}
-category app-startup PushServiceLauncher @mozilla.org/dom/push/service;1
+contract @mozilla.org/push/ServiceLauncher;1 {4b8caa3b-3c58-4f3c-a7f5-7bd9cb24c11d}
+category app-startup PushServiceLauncher @mozilla.org/push/ServiceLauncher;1
--- a/dom/push/src/PushServiceLauncher.js
+++ b/dom/push/src/PushServiceLauncher.js
@@ -13,16 +13,18 @@ Cu.import("resource://gre/modules/XPCOMU
 Cu.import("resource://gre/modules/Services.jsm");
 
 function PushServiceLauncher() {
 };
 
 PushServiceLauncher.prototype = {
   classID: Components.ID("{4b8caa3b-3c58-4f3c-a7f5-7bd9cb24c11d}"),
 
+  contractID: "@mozilla.org/push/ServiceLauncher;1",
+
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
                                          Ci.nsISupportsWeakReference]),
 
   observe: function observe(subject, topic, data) {
     switch (topic) {
       case "app-startup":
         Services.obs.addObserver(this, "final-ui-startup", true);
         break;
--- a/dom/system/gonk/NetworkManager.js
+++ b/dom/system/gonk/NetworkManager.js
@@ -429,16 +429,37 @@ NetworkManager.prototype = {
     this.controlMessage(params, function(result) {
       let success = result.resultCode >= NETD_COMMAND_OKAY &&
                     result.resultCode < NETD_COMMAND_ERROR;
       callback.networkStatsAvailable(success, result.rxBytes,
                                      result.txBytes, result.date);
     });
   },
 
+  setWifiOperationMode: function setWifiOperationMode(interfaceName, mode, callback) {
+    debug("setWifiOperationMode on " + interfaceName + " to " + mode);
+
+    let params = {
+      cmd: "setWifiOperationMode",
+      ifname: interfaceName,
+      mode: mode
+    };
+
+    params.report = true;
+    params.isAsync = true;
+
+    this.controlMessage(params, function(result) {
+      if (isError(result.resultCode)) {
+        callback.wifiOperationModeResult("netd command error");
+      } else {
+        callback.wifiOperationModeResult(null);
+      }
+    });
+  },
+
   // Helpers
 
   controlMessage: function controlMessage(params, callback) {
     if (callback) {
       let id = callback.name;
       params.id = id;
       this.controlCallbacks[id] = callback;
     }
--- a/dom/system/gonk/net_worker.js
+++ b/dom/system/gonk/net_worker.js
@@ -161,16 +161,28 @@ function updateUpStreamSuccess(params) {
 }
 
 function updateUpStreamFail(params) {
   // Notify the main thread.
   postMessage(params);
   return true;
 }
 
+function wifiOperationModeFail(params) {
+  // Notify the main thread.
+  postMessage(params);
+  return true;
+}
+
+function wifiOperationModeSuccess(params) {
+  // Notify the main thread.
+  postMessage(params);
+  return true;
+}
+
 /**
  * Get network interface properties from the system property table.
  *
  * @param ifname
  *        Name of the network interface.
  */
 function getIFProperties(ifname) {
   return {
@@ -796,16 +808,28 @@ function getNetworkInterfaceStats(params
   params.rxBytes = -1;
   params.txBytes = -1;
   params.date = new Date();
 
   chain(params, gNetworkInterfaceStatsChain, networkInterfaceStatsFail);
   return true;
 }
 
+let gWifiOperationModeChain = [wifiFirmwareReload,
+                               wifiOperationModeSuccess];
+
+/**
+ * handling main thread's reload Wifi firmware request
+ */
+function setWifiOperationMode(params) {
+  debug("setWifiOperationMode: " + params.ifname + " " + params.mode);
+  chain(params, gWifiOperationModeChain, wifiOperationModeFail);
+  return true;
+}
+
 let debug;
 if (DEBUG) {
   debug = function (s) {
     dump("Network Worker: " + s + "\n");
   };
 } else {
   debug = function (s) {};
 }
--- a/dom/system/gonk/nsINetworkManager.idl
+++ b/dom/system/gonk/nsINetworkManager.idl
@@ -103,20 +103,33 @@ interface nsIWifiTetheringCallback : nsI
 interface nsINetworkStatsCallback : nsISupports
 {
   void networkStatsAvailable(in boolean success,
                              in unsigned long rxBytes,
                              in unsigned long txBytes,
                              in jsval date);
 };
 
+[scriptable, function, uuid(9ede8720-f8bc-11e2-b778-0800200c9a66)]
+interface nsIWifiOperationModeCallback : nsISupports
+{
+  /**
+   * Callback function used to report result to WifiManager.
+   *
+   * @param error
+   *        An error message if the operation wasn't successful,
+   *        or `null` if it was.
+   */
+  void wifiOperationModeResult(in jsval error);
+};
+
 /**
  * Manage network interfaces.
  */
-[scriptable, uuid(f39a0fb6-2752-47d2-943e-a0cdd3e43494)]
+[scriptable, uuid(5b22c620-f8b9-11e2-b778-0800200c9a66)]
 interface nsINetworkManager : nsISupports
 {
   /**
    * Register the given network interface with the network manager.
    *
    * Consumers will be notified with the 'network-interface-registered'
    * observer notification.
    *
@@ -203,9 +216,24 @@ interface nsINetworkManager : nsISupport
    *        Select the Network interface to request estats.
    *
    * @param callback
    *        Callback to notify result and provide stats, connectionType
    *        and the date when stats are retrieved
    */
   void getNetworkInterfaceStats(in DOMString networkName, in nsINetworkStatsCallback callback);
 
+  /**
+   * Reload Wifi firmware to specific operation mode.
+   *
+   * @param interfaceName
+   *        Wifi Network interface name.
+   *
+   * @param mode
+   *        AP  - Access pointer mode.
+   *        P2P - Peer to peer connection mode.
+   *        STA - Station mode.
+   *
+   * @param callback
+   *        Callback to notify Wifi firmware reload result.
+   */
+  void setWifiOperationMode(in DOMString interfaceName, in DOMString mode, in nsIWifiOperationModeCallback callback);
 };
new file mode 100644
--- /dev/null
+++ b/dom/webidl/PushManager.webidl
@@ -0,0 +1,12 @@
+/* -*- Mode: IDL; 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/.
+*/
+
+[NoInterfaceObject, NavigatorProperty="push", JSImplementation="@mozilla.org/push/PushManager;1", Pref="services.push.enabled"]
+interface PushManager {
+    DOMRequest register();
+    DOMRequest unregister(DOMString pushEndpoint);
+    DOMRequest registrations();
+};
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -221,16 +221,17 @@ webidl_files = \
   PerformanceTiming.webidl \
   PeriodicWave.webidl \
   Plugin.webidl \
   PluginArray.webidl \
   Position.webidl \
   PositionError.webidl \
   ProcessingInstruction.webidl \
   Promise.webidl \
+  PushManager.webidl \
   Range.webidl \
   Rect.webidl \
   RGBColor.webidl \
   RTCConfiguration.webidl \
   RTCDataChannelEvent.webidl \
   RTCIceCandidate.webidl \
   RTCPeerConnection.webidl \
   RTCPeerConnectionIceEvent.webidl \
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -1219,46 +1219,56 @@ var WifiManager = (function() {
         WifiNetworkInterface.gateway = null;
         WifiNetworkInterface.dns1 = null;
         WifiNetworkInterface.dns2 = null;
         Services.obs.notifyObservers(WifiNetworkInterface,
                                      kNetworkInterfaceStateChangedTopic,
                                      null);
 
         prepareForStartup(function() {
-          loadDriver(function (status) {
-            if (status < 0) {
+          gNetworkManager.setWifiOperationMode(ifname,
+                                               WIFI_FIRMWARE_STATION,
+                                               function (status) {
+            if (status) {
               callback(status);
               manager.state = "UNINITIALIZED";
               return;
             }
 
-            function doStartSupplicant() {
-              cancelWaitForDriverReadyTimer();
-              startSupplicant(function (status) {
-                if (status < 0) {
-                  unloadDriver(function() {
-                    callback(status);
+            loadDriver(function (status) {
+              if (status < 0) {
+                callback(status);
+                manager.state = "UNINITIALIZED";
+                return;
+              }
+
+              function doStartSupplicant() {
+                cancelWaitForDriverReadyTimer();
+                startSupplicant(function (status) {
+                  if (status < 0) {
+                    unloadDriver(function() {
+                      callback(status);
+                    });
+                    manager.state = "UNINITIALIZED";
+                    return;
+                  }
+
+                  manager.supplicantStarted = true;
+                  enableInterface(ifname, function (ok) {
+                    callback(ok ? 0 : -1);
                   });
-                  manager.state = "UNINITIALIZED";
-                  return;
-                }
-
-                manager.supplicantStarted = true;
-                enableInterface(ifname, function (ok) {
-                  callback(ok ? 0 : -1);
                 });
-              });
-            }
-
-            // Driver startup on certain platforms takes longer than it takes for us
-            // to return from loadDriver, so wait 2 seconds before starting
-            // the supplicant to give it a chance to start.
-            createWaitForDriverReadyTimer(doStartSupplicant);
-         });
+              }
+
+              // Driver startup on certain platforms takes longer than it takes for us
+              // to return from loadDriver, so wait 2 seconds before starting
+              // the supplicant to give it a chance to start.
+              createWaitForDriverReadyTimer(doStartSupplicant);
+           });
+          });
         });
       });
     } else {
       // Note these following calls ignore errors. If we fail to kill the
       // supplicant gracefully, then we need to continue telling it to die
       // until it does.
       terminateSupplicant(function (ok) {
         manager.connectionDropped(function () {
deleted file mode 100644
--- a/dom/workers/ImageData.cpp
+++ /dev/null
@@ -1,205 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "ImageData.h"
-
-#include "jsfriendapi.h"
-
-#include "nsTraceRefcnt.h"
-
-#define PROPERTY_FLAGS \
-  (JSPROP_ENUMERATE | JSPROP_SHARED)
-
-USING_WORKERS_NAMESPACE
-
-namespace {
-
-class ImageData
-{
-  static JSClass sClass;
-  static const JSPropertySpec sProperties[];
-
-  enum SLOT {
-    SLOT_width = 0,
-    SLOT_height,
-    SLOT_data,
-
-    SLOT_COUNT
-  };
-
-public:
-  static JSObject*
-  InitClass(JSContext* aCx, JSObject* aObj)
-  {
-    return JS_InitClass(aCx, aObj, NULL, &sClass, Construct, 0, sProperties,
-                        NULL, NULL, NULL);
-  }
-
-  static JSObject*
-  Create(JSContext* aCx, uint32_t aWidth,
-         uint32_t aHeight, JS::Handle<JSObject*> aData)
-  {
-    MOZ_ASSERT(aData);
-    MOZ_ASSERT(JS_IsTypedArrayObject(aData));
-    MOZ_ASSERT(JS_IsUint8ClampedArray(aData));
-
-    JSObject* obj = JS_NewObject(aCx, &sClass, NULL, NULL);
-    if (!obj) {
-      return NULL;
-    }
-
-    JS_SetReservedSlot(obj, SLOT_width, UINT_TO_JSVAL(aWidth));
-    JS_SetReservedSlot(obj, SLOT_height, UINT_TO_JSVAL(aHeight));
-    JS_SetReservedSlot(obj, SLOT_data, OBJECT_TO_JSVAL(aData));
-
-    // This is an empty object. The point is just to differentiate instances
-    // from the interface object.
-    ImageData* priv = new ImageData();
-    JS_SetPrivate(obj, priv);
-
-    return obj;
-  }
-
-  static bool
-  IsInstance(JSObject* aObj)
-  {
-    return JS_GetClass(aObj) == &sClass;
-  }
-
-  static uint32_t
-  GetWidth(JSObject* aObj)
-  {
-    MOZ_ASSERT(IsInstance(aObj));
-    return JS_DoubleToUint32(JS_GetReservedSlot(aObj, SLOT_width).toNumber());
-  }
-
-  static uint32_t
-  GetHeight(JSObject* aObj)
-  {
-    MOZ_ASSERT(IsInstance(aObj));
-    return JS_DoubleToUint32(JS_GetReservedSlot(aObj, SLOT_height).toNumber());
-  }
-
-  static
-  JSObject* GetData(JSObject* aObj)
-  {
-    MOZ_ASSERT(IsInstance(aObj));
-    return &JS_GetReservedSlot(aObj, SLOT_data).toObject();
-  }
-
-private:
-  ImageData()
-  {
-    MOZ_COUNT_CTOR(mozilla::dom::workers::ImageData);
-  }
-
-  ~ImageData()
-  {
-    MOZ_COUNT_DTOR(mozilla::dom::workers::ImageData);
-  }
-
-  static JSBool
-  Construct(JSContext* aCx, unsigned aArgc, jsval* aVp)
-  {
-    JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_WRONG_CONSTRUCTOR,
-                         sClass.name);
-    return false;
-  }
-
-  static void
-  Finalize(JSFreeOp* aFop, JSObject* aObj)
-  {
-    MOZ_ASSERT(JS_GetClass(aObj) == &sClass);
-    delete static_cast<ImageData*>(JS_GetPrivate(aObj));
-  }
-
-  static JSBool
-  GetProperty(JSContext* aCx, JS::Handle<JSObject*> aObj, JS::Handle<jsid> aIdval,
-              JS::MutableHandle<JS::Value> aVp)
-  {
-    JSClass* classPtr = JS_GetClass(aObj);
-    if (classPtr != &sClass) {
-      JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
-                           JSMSG_INCOMPATIBLE_PROTO, sClass.name, "GetProperty",
-                           classPtr->name);
-      return false;
-    }
-
-    MOZ_ASSERT(JSID_IS_INT(aIdval));
-    MOZ_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < SLOT_COUNT);
-
-    aVp.set(JS_GetReservedSlot(aObj, JSID_TO_INT(aIdval)));
-    return true;
-  }
-};
-
-JSClass ImageData::sClass = {
-  "ImageData",
-  JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT),
-  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize
-};
-
-const JSPropertySpec ImageData::sProperties[] = {
-  // These properties are read-only per spec, which means that sets must throw
-  // in strict mode and silently fail otherwise. This is a problem for workers
-  // in general (because js_GetterOnlyPropertyStub throws unconditionally). The
-  // general plan for fixing this involves the new DOM bindings. But Peace
-  // Keeper breaks if we throw when setting these properties, so we need to do
-  // something about it in the mean time. So we use NULL, which defaults to the
-  // class setter (JS_StrictPropertyStub), which is always a silent no-op,
-  // regardless of strict mode. Not ideal, but good enough for now.
-  { "width", SLOT_width, PROPERTY_FLAGS, JSOP_WRAPPER(GetProperty), JSOP_NULLWRAPPER },
-  { "height", SLOT_height, PROPERTY_FLAGS, JSOP_WRAPPER(GetProperty), JSOP_NULLWRAPPER },
-  { "data", SLOT_data, PROPERTY_FLAGS, JSOP_WRAPPER(GetProperty), JSOP_NULLWRAPPER },
-  { 0, 0, 0, JSOP_NULLWRAPPER, JSOP_NULLWRAPPER }
-};
-
-} // anonymous namespace
-
-BEGIN_WORKERS_NAMESPACE
-
-namespace imagedata {
-
-bool
-InitClass(JSContext* aCx, JSObject* aGlobal)
-{
-  return !!ImageData::InitClass(aCx, aGlobal);
-}
-
-JSObject*
-Create(JSContext* aCx, uint32_t aWidth,
-       uint32_t aHeight, JS::Handle<JSObject*> aData)
-{
-  return ImageData::Create(aCx, aWidth, aHeight, aData);
-}
-
-bool
-IsImageData(JSObject* aObj)
-{
-  return ImageData::IsInstance(aObj);
-}
-
-uint32_t
-GetWidth(JSObject* aObj)
-{
-  return ImageData::GetWidth(aObj);
-}
-
-uint32_t
-GetHeight(JSObject* aObj)
-{
-  return ImageData::GetHeight(aObj);
-}
-
-JSObject*
-GetData(JSObject* aObj)
-{
-  return ImageData::GetData(aObj);
-}
-
-
-} // namespace imagedata
-
-END_WORKERS_NAMESPACE
deleted file mode 100644
--- a/dom/workers/ImageData.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_workers_imagedata_h__
-#define mozilla_dom_workers_imagedata_h__
-
-#include "Workers.h"
-
-BEGIN_WORKERS_NAMESPACE
-
-namespace imagedata {
-
-bool
-InitClass(JSContext* aCx, JSObject* aGlobal);
-
-JSObject*
-Create(JSContext* aCx, uint32_t aWidth,
-       uint32_t aHeight, JS::Handle<JSObject*> aData);
-
-/*
- * All data members live in private slots on the JS Object. Callers must
- * first check IsImageData, after which they may call the data accessors.
- */
-
-bool
-IsImageData(JSObject* aObj);
-
-uint32_t
-GetWidth(JSObject* aObj);
-
-uint32_t
-GetHeight(JSObject* aObj);
-
-JSObject*
-GetData(JSObject* aObj);
-
-} // namespace imagedata
-
-END_WORKERS_NAMESPACE
-
-#endif // mozilla_dom_workers_imagedata_h__
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -16,23 +16,25 @@
 #include "nsISupportsPriority.h"
 #include "nsITimer.h"
 #include "nsPIDOMWindow.h"
 
 #include <algorithm>
 #include "GeckoProfiler.h"
 #include "jsdbgapi.h"
 #include "jsfriendapi.h"
+#include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/EventTargetBinding.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Util.h"
 #include <Navigator.h>
 #include "nsContentUtils.h"
+#include "nsCycleCollector.h"
 #include "nsDOMJSUtils.h"
 #include "nsLayoutStatics.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOM.h"
 #include "nsXPCOMPrivate.h"
 #include "OSFileConstants.h"
@@ -743,30 +745,21 @@ CTypesActivityCallback(JSContext* aCx,
       break;
 
     default:
       MOZ_CRASH("Unknown type flag!");
   }
 }
 
 JSContext*
-CreateJSContextForWorker(WorkerPrivate* aWorkerPrivate)
+CreateJSContextForWorker(WorkerPrivate* aWorkerPrivate, JSRuntime* aRuntime)
 {
   aWorkerPrivate->AssertIsOnWorkerThread();
   NS_ASSERTION(!aWorkerPrivate->GetJSContext(), "Already has a context!");
 
-  // The number passed here doesn't matter, we're about to change it in the call
-  // to JS_SetGCParameter.
-  JSRuntime* runtime =
-    JS_NewRuntime(WORKER_DEFAULT_RUNTIME_HEAPSIZE, JS_NO_HELPER_THREADS);
-  if (!runtime) {
-    NS_WARNING("Could not create new runtime!");
-    return nullptr;
-  }
-
   JSSettings settings;
   aWorkerPrivate->CopyJSSettings(settings);
 
   NS_ASSERTION((settings.chrome.options & kRequiredJSContextOptions) ==
                kRequiredJSContextOptions,
                "Somehow we lost our required chrome options!");
   NS_ASSERTION((settings.content.options & kRequiredJSContextOptions) ==
                kRequiredJSContextOptions,
@@ -774,63 +767,114 @@ CreateJSContextForWorker(WorkerPrivate* 
 
   JSSettings::JSGCSettingsArray& gcSettings = settings.gcSettings;
 
   // This is the real place where we set the max memory for the runtime.
   for (uint32_t index = 0; index < ArrayLength(gcSettings); index++) {
     const JSSettings::JSGCSetting& setting = gcSettings[index];
     if (setting.IsSet()) {
       NS_ASSERTION(setting.value, "Can't handle 0 values!");
-      JS_SetGCParameter(runtime, setting.key, setting.value);
+      JS_SetGCParameter(aRuntime, setting.key, setting.value);
     }
   }
 
-  JS_SetNativeStackQuota(runtime, WORKER_CONTEXT_NATIVE_STACK_LIMIT);
+  JS_SetNativeStackQuota(aRuntime, WORKER_CONTEXT_NATIVE_STACK_LIMIT);
 
   // Security policy:
   static JSSecurityCallbacks securityCallbacks = {
     NULL,
     ContentSecurityPolicyAllows
   };
-  JS_SetSecurityCallbacks(runtime, &securityCallbacks);
+  JS_SetSecurityCallbacks(aRuntime, &securityCallbacks);
 
   // DOM helpers:
   static js::DOMCallbacks DOMCallbacks = {
     InstanceClassHasProtoAtDepth
   };
-  SetDOMCallbacks(runtime, &DOMCallbacks);
+  SetDOMCallbacks(aRuntime, &DOMCallbacks);
 
-  JSContext* workerCx = JS_NewContext(runtime, 0);
+  JSContext* workerCx = JS_NewContext(aRuntime, 0);
   if (!workerCx) {
-    JS_DestroyRuntime(runtime);
     NS_WARNING("Could not create new context!");
     return nullptr;
   }
 
-  JS_SetRuntimePrivate(runtime, aWorkerPrivate);
+  JS_SetRuntimePrivate(aRuntime, aWorkerPrivate);
 
   JS_SetErrorReporter(workerCx, ErrorReporter);
 
   JS_SetOperationCallback(workerCx, OperationCallback);
 
-  js::SetCTypesActivityCallback(runtime, CTypesActivityCallback);
+  js::SetCTypesActivityCallback(aRuntime, CTypesActivityCallback);
 
   JS_SetOptions(workerCx,
                 aWorkerPrivate->IsChromeWorker() ? settings.chrome.options :
                                                    settings.content.options);
 
-  JS_SetJitHardening(runtime, settings.jitHardening);
+  JS_SetJitHardening(aRuntime, settings.jitHardening);
 
 #ifdef JS_GC_ZEAL
   JS_SetGCZeal(workerCx, settings.gcZeal, settings.gcZealFrequency);
 #endif
 
   return workerCx;
 }
 
+class WorkerJSRuntime : public mozilla::CycleCollectedJSRuntime
+{
+public:
+  // The heap size passed here doesn't matter, we will change it later in the
+  // call to JS_SetGCParameter inside CreateJSContextForWorker.
+  WorkerJSRuntime(WorkerPrivate* aWorkerPrivate)
+  : CycleCollectedJSRuntime(WORKER_DEFAULT_RUNTIME_HEAPSIZE,
+                            JS_NO_HELPER_THREADS,
+                            false)
+  {
+    // We need to ensure that a JSContext outlives the cycle collector, and
+    // that the internal JSContext created by ctypes is not the last JSContext
+    // to die.  So we create an unused JSContext here and destroy it after
+    // the cycle collector shuts down.  Thus all cycles will be broken before
+    // the last GC and all finalizers will be run.
+    mLastJSContext = JS_NewContext(Runtime(), 0);
+    MOZ_ASSERT(mLastJSContext);
+  }
+
+  ~WorkerJSRuntime()
+  {
+    // All JSContexts except mLastJSContext should be destroyed now.  The
+    // worker global will be unrooted and the shutdown cycle collection
+    // should break all remaining cycles.  Destroying mLastJSContext will run
+    // the GC the final time and finalize any JSObjects that were participating
+    // in cycles that were broken during CC shutdown.
+    nsCycleCollector_shutdownThreads();
+    nsCycleCollector_shutdown();
+    JS_DestroyContext(mLastJSContext);
+    mLastJSContext = nullptr;
+  }
+
+  // Make this public for now.  Ideally we'd hide the JSRuntime inside.
+  JSRuntime*
+  Runtime() const
+  {
+    return mozilla::CycleCollectedJSRuntime::Runtime();
+  }
+
+  void
+  DispatchDeferredDeletion(bool aContinuation) MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(!aContinuation);
+
+    // Do it immediately, no need for asynchronous behavior here.
+    nsCycleCollector_doDeferredDeletion();
+  }
+
+private:
+  JSContext* mLastJSContext;
+};
+
 class WorkerThreadRunnable : public nsRunnable
 {
   WorkerPrivate* mWorkerPrivate;
 
 public:
   WorkerThreadRunnable(WorkerPrivate* aWorkerPrivate)
   : mWorkerPrivate(aWorkerPrivate)
   {
@@ -840,60 +884,55 @@ public:
   NS_IMETHOD
   Run()
   {
     WorkerPrivate* workerPrivate = mWorkerPrivate;
     mWorkerPrivate = nullptr;
 
     workerPrivate->AssertIsOnWorkerThread();
 
-    JSContext* cx = CreateJSContextForWorker(workerPrivate);
-    if (!cx) {
-      // XXX need to fire an error at parent.
-      NS_ERROR("Failed to create runtime and context!");
-      return NS_ERROR_FAILURE;
-    }
+    {
+      nsCycleCollector_startup(CCSingleThread);
 
-    JSRuntime* rt = JS_GetRuntime(cx);
-
-    char aLocal;
-    profiler_register_thread("WebWorker", &aLocal);
-#ifdef MOZ_ENABLE_PROFILER_SPS
-    if (PseudoStack* stack = mozilla_get_pseudo_stack())
-      stack->sampleRuntime(rt);
-#endif
+      WorkerJSRuntime runtime(workerPrivate);
+      JSRuntime* rt = runtime.Runtime();
+      JSContext* cx = CreateJSContextForWorker(workerPrivate, rt);
+      if (!cx) {
+        // XXX need to fire an error at parent.
+        NS_ERROR("Failed to create runtime and context!");
+        return NS_ERROR_FAILURE;
+      }
 
-    {
-      JSAutoRequest ar(cx);
-      workerPrivate->DoRunLoop(cx);
-    }
+      char aLocal;
+      profiler_register_thread("WebWorker", &aLocal);
+  #ifdef MOZ_ENABLE_PROFILER_SPS
+      if (PseudoStack* stack = mozilla_get_pseudo_stack())
+        stack->sampleRuntime(rt);
+  #endif
 
-    // XXX Bug 666963 - CTypes can create another JSContext for use with
-    // closures, and then it holds that context in a reserved slot on the CType
-    // prototype object. We have to destroy that context before we can destroy
-    // the runtime, and we also have to make sure that it isn't the last context
-    // to be destroyed (otherwise it will assert). To accomplish this we create
-    // an unused dummy context, destroy our real context, and then destroy the
-    // dummy. Once this bug is resolved we can remove this nastiness and simply
-    // call JS_DestroyContextNoGC on our context.
-    JSContext* dummyCx = JS_NewContext(rt, 0);
-    if (dummyCx) {
+      {
+        JSAutoRequest ar(cx);
+        workerPrivate->DoRunLoop(cx);
+      }
+
+      // Destroy the main context.  This will unroot the main worker global and
+      // GC.  This is not the last JSContext (WorkerJSRuntime maintains an
+      // internal JSContext).
       JS_DestroyContext(cx);
-      JS_DestroyContext(dummyCx);
-    }
-    else {
-      NS_WARNING("Failed to create dummy context!");
-      JS_DestroyContext(cx);
+
+      // Now WorkerJSRuntime goes out of scope and its destructor will shut
+      // down the cycle collector and destroy the final JSContext.  This
+      // breaks any remaining cycles and collects the C++ and JS objects
+      // participating.
     }
 
 #ifdef MOZ_ENABLE_PROFILER_SPS
     if (PseudoStack* stack = mozilla_get_pseudo_stack())
       stack->sampleRuntime(nullptr);
 #endif
-    JS_DestroyRuntime(rt);
 
     workerPrivate->ScheduleDeletion(false);
     profiler_unregister_thread();
     return NS_OK;
   }
 };
 
 } /* anonymous namespace */
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -31,16 +31,19 @@
 #include <algorithm>
 #include "jsfriendapi.h"
 #include "jsdbgapi.h"
 #include "jsfriendapi.h"
 #include "jsprf.h"
 #include "js/MemoryMetrics.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Likely.h"
+#include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/ImageData.h"
+#include "mozilla/dom/ImageDataBinding.h"
 #include "nsAlgorithm.h"
 #include "nsContentUtils.h"
 #include "nsCxPusher.h"
 #include "nsError.h"
 #include "nsDOMJSUtils.h"
 #include "nsGUIEvent.h"
 #include "nsJSEnvironment.h"
 #include "nsJSUtils.h"
@@ -52,17 +55,16 @@
 
 #ifdef ANDROID
 #include <android/log.h>
 #endif
 
 #include "Events.h"
 #include "Exceptions.h"
 #include "File.h"
-#include "ImageData.h"
 #include "Principal.h"
 #include "RuntimeService.h"
 #include "ScriptLoader.h"
 #include "Worker.h"
 #include "WorkerFeature.h"
 #include "WorkerScope.h"
 
 // GC will run once every thirty seconds during normal execution.
@@ -199,19 +201,24 @@ struct WorkerStructuredCloneCallbacks
       if (!JS_ReadUint32Pair(aReader, &width, &height) ||
           !JS_ReadTypedArray(aReader, dataArray.address()))
       {
         return nullptr;
       }
       MOZ_ASSERT(dataArray.isObject());
 
       // Construct the ImageData.
-      JS::Rooted<JSObject*> dataObj(aCx, &dataArray.toObject());
-      JSObject* obj = imagedata::Create(aCx, width, height, dataObj);
-      return obj;
+      nsRefPtr<ImageData> imageData = new ImageData(width, height,
+                                                    dataArray.toObject());
+      // Wrap it in a JS::Value.
+      JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
+      if (!global) {
+        return nullptr;
+      }
+      return imageData->WrapObject(aCx, global);
     }
 
     Error(aCx, 0);
     return nullptr;
   }
 
   static JSBool
   Write(JSContext* aCx, JSStructuredCloneWriter* aWriter,
@@ -245,26 +252,30 @@ struct WorkerStructuredCloneCallbacks
             JS_WriteBytes(aWriter, &blob, sizeof(blob))) {
           clonedObjects->AppendElement(blob);
           return true;
         }
       }
     }
 
     // See if this is an ImageData object.
-    if (imagedata::IsImageData(aObj)) {
-      // Pull the properties off the object.
-      uint32_t width = imagedata::GetWidth(aObj);
-      uint32_t height = imagedata::GetHeight(aObj);
-      JSObject* data = imagedata::GetData(aObj);
-
-      // Write the structured clone.
-      return JS_WriteUint32Pair(aWriter, SCTAG_DOM_IMAGEDATA, 0) &&
-             JS_WriteUint32Pair(aWriter, width, height) &&
-             JS_WriteTypedArray(aWriter, OBJECT_TO_JSVAL(data));
+    {
+      ImageData* imageData = nullptr;
+      if (NS_SUCCEEDED(UnwrapObject<ImageData>(aCx, aObj, imageData))) {
+        // Prepare the ImageData internals.
+        uint32_t width = imageData->Width();
+        uint32_t height = imageData->Height();
+        JS::Rooted<JSObject*> dataArray(aCx, imageData->GetDataObject());
+
+        // Write the internals to the stream.
+        JSAutoCompartment ac(aCx, dataArray);
+        return JS_WriteUint32Pair(aWriter, SCTAG_DOM_IMAGEDATA, 0) &&
+               JS_WriteUint32Pair(aWriter, width, height) &&
+               JS_WriteTypedArray(aWriter, JS::ObjectValue(*dataArray));
+      }
     }
 
     Error(aCx, 0);
     return false;
   }
 
   static void
   Error(JSContext* aCx, uint32_t /* aErrorId */)
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -8,16 +8,18 @@
 
 #include "jsapi.h"
 #include "jsdbgapi.h"
 #include "mozilla/Util.h"
 #include "mozilla/dom/DOMJSClass.h"
 #include "mozilla/dom/EventTargetBinding.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/FileReaderSyncBinding.h"
+#include "mozilla/dom/ImageData.h"
+#include "mozilla/dom/ImageDataBinding.h"
 #include "mozilla/dom/TextDecoderBinding.h"
 #include "mozilla/dom/TextEncoderBinding.h"
 #include "mozilla/dom/XMLHttpRequestBinding.h"
 #include "mozilla/dom/XMLHttpRequestUploadBinding.h"
 #include "mozilla/dom/URLBinding.h"
 #include "mozilla/dom/WorkerLocationBinding.h"
 #include "mozilla/dom/WorkerNavigatorBinding.h"
 #include "mozilla/OSFileConstants.h"
@@ -31,17 +33,16 @@
 #include "ChromeWorkerScope.h"
 #include "Events.h"
 #include "EventListenerManager.h"
 #include "EventTarget.h"
 #include "Exceptions.h"
 #include "File.h"
 #include "FileReaderSync.h"
 #include "Location.h"
-#include "ImageData.h"
 #include "Navigator.h"
 #include "Principal.h"
 #include "ScriptLoader.h"
 #include "Worker.h"
 #include "WorkerPrivate.h"
 #include "XMLHttpRequest.h"
 
 #include "WorkerInlines.h"
@@ -1007,23 +1008,23 @@ CreateDedicatedWorkerGlobalScope(JSConte
         !DefineOSFileConstants(aCx, global)) {
       return NULL;
     }
   }
 
   // Init other classes we care about.
   if (!events::InitClasses(aCx, global, false) ||
       !file::InitClasses(aCx, global) ||
-      !exceptions::InitClasses(aCx, global) ||
-      !imagedata::InitClass(aCx, global)) {
+      !exceptions::InitClasses(aCx, global)) {
     return NULL;
   }
 
   // Init other paris-bindings.
   if (!FileReaderSyncBinding_workers::GetConstructorObject(aCx, global) ||
+      !ImageDataBinding::GetConstructorObject(aCx, global) ||
       !TextDecoderBinding_workers::GetConstructorObject(aCx, global) ||
       !TextEncoderBinding_workers::GetConstructorObject(aCx, global) ||
       !XMLHttpRequestBinding_workers::GetConstructorObject(aCx, global) ||
       !XMLHttpRequestUploadBinding_workers::GetConstructorObject(aCx, global) ||
       !URLBinding_workers::GetConstructorObject(aCx, global) ||
       !WorkerLocationBinding_workers::GetConstructorObject(aCx, global) ||
       !WorkerNavigatorBinding_workers::GetConstructorObject(aCx, global)) {
     return NULL;
--- a/dom/workers/moz.build
+++ b/dom/workers/moz.build
@@ -34,17 +34,16 @@ CPP_SOURCES += [
     'ChromeWorkerScope.cpp',
     'DOMBindingBase.cpp',
     'EventListenerManager.cpp',
     'EventTarget.cpp',
     'Events.cpp',
     'Exceptions.cpp',
     'File.cpp',
     'FileReaderSync.cpp',
-    'ImageData.cpp',
     'Location.cpp',
     'Navigator.cpp',
     'Principal.cpp',
     'RuntimeService.cpp',
     'ScriptLoader.cpp',
     'TextDecoder.cpp',
     'TextEncoder.cpp',
     'URL.cpp',
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -71,39 +71,41 @@ public:
 
   std::vector<SkColor> mColors;
   std::vector<SkScalar> mPositions;
   int mCount;
   ExtendMode mExtendMode;
 };
 
 DrawTargetSkia::DrawTargetSkia()
+  : mSnapshot(nullptr)
 {
 #ifdef ANDROID
   mSoftClipping = false;
 #else
   mSoftClipping = true;
 #endif
 }
 
 DrawTargetSkia::~DrawTargetSkia()
 {
-  MOZ_ASSERT(mSnapshots.size() == 0);
 }
 
 TemporaryRef<SourceSurface>
 DrawTargetSkia::Snapshot()
 {
-  RefPtr<SourceSurfaceSkia> source = new SourceSurfaceSkia();
+  RefPtr<SourceSurfaceSkia> snapshot = mSnapshot;
+  if (!snapshot) {
+    snapshot = new SourceSurfaceSkia();
+    mSnapshot = snapshot;
+    if (!snapshot->InitFromCanvas(mCanvas.get(), mFormat, this))
+      return nullptr;
+  }
 
-  if (!source->InitFromCanvas(mCanvas.get(), mFormat, this))
-    return nullptr;
-
-  AppendSnapshot(source);
-  return source;
+  return snapshot;
 }
 
 void SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1.0)
 {
   switch (aPattern.GetType()) {
     case PATTERN_COLOR: {
       Color color = static_cast<const ColorPattern&>(aPattern).mColor;
       aPaint.setColor(ColorToSkColor(color, aAlpha));
@@ -768,37 +770,24 @@ DrawTargetSkia::CreateGradientStops(Grad
     stops[i] = aStops[i];
   }
   std::stable_sort(stops.begin(), stops.end());
   
   return new GradientStopsSkia(stops, aNumStops, aExtendMode);
 }
 
 void
-DrawTargetSkia::AppendSnapshot(SourceSurfaceSkia* aSnapshot)
+DrawTargetSkia::MarkChanged()
 {
-  mSnapshots.push_back(aSnapshot);
-}
-
-void
-DrawTargetSkia::RemoveSnapshot(SourceSurfaceSkia* aSnapshot)
-{
-  std::vector<SourceSurfaceSkia*>::iterator iter = std::find(mSnapshots.begin(), mSnapshots.end(), aSnapshot);
-  if (iter != mSnapshots.end()) {
-    mSnapshots.erase(iter);
+  if (mSnapshot) {
+    mSnapshot->DrawTargetWillChange();
+    mSnapshot = nullptr;
   }
 }
 
 void
-DrawTargetSkia::MarkChanged()
+DrawTargetSkia::SnapshotDestroyed()
 {
-  if (mSnapshots.size()) {
-    for (std::vector<SourceSurfaceSkia*>::iterator iter = mSnapshots.begin();
-         iter != mSnapshots.end(); iter++) {
-      (*iter)->DrawTargetWillChange();
-    }
-    // All snapshots will now have copied data.
-    mSnapshots.clear();
-  }
+  mSnapshot = nullptr;
 }
 
 }
 }
--- a/gfx/2d/DrawTargetSkia.h
+++ b/gfx/2d/DrawTargetSkia.h
@@ -109,18 +109,17 @@ public:
   operator std::string() const {
     std::stringstream stream;
     stream << "DrawTargetSkia(" << this << ")";
     return stream.str();
   }
 
 private:
   friend class SourceSurfaceSkia;
-  void AppendSnapshot(SourceSurfaceSkia* aSnapshot);
-  void RemoveSnapshot(SourceSurfaceSkia* aSnapshot);
+  void SnapshotDestroyed();
 
   void MarkChanged();
 
 #ifdef USE_SKIA_GPU
   /*
    * These members have inter-dependencies, but do not keep each other alive, so
    * destruction order is very important here: mGrContext uses mGrGLInterface, and
    * through it, uses mGLContext, so it is important that they be declared in the
@@ -128,14 +127,14 @@ private:
    */
   RefPtr<GenericRefCountedBase> mGLContext;
   SkRefPtr<GrGLInterface> mGrGLInterface;
   SkRefPtr<GrContext> mGrContext;
 #endif
 
   IntSize mSize;
   SkRefPtr<SkCanvas> mCanvas;
-  std::vector<SourceSurfaceSkia*> mSnapshots;
+  SourceSurfaceSkia* mSnapshot;
   bool mSoftClipping;
 };
 
 }
 }
--- a/gfx/2d/SourceSurfaceSkia.cpp
+++ b/gfx/2d/SourceSurfaceSkia.cpp
@@ -17,17 +17,20 @@ namespace gfx {
 SourceSurfaceSkia::SourceSurfaceSkia()
   : mDrawTarget(nullptr), mLocked(false)
 {
 }
 
 SourceSurfaceSkia::~SourceSurfaceSkia()
 {
   MaybeUnlock();
-  MarkIndependent();
+  if (mDrawTarget) {
+    mDrawTarget->SnapshotDestroyed();
+    mDrawTarget = nullptr;
+  }
 }
 
 IntSize
 SourceSurfaceSkia::GetSize() const
 {
   return mSize;
 }
 
@@ -104,25 +107,16 @@ SourceSurfaceSkia::DrawTargetWillChange(
     mDrawTarget = nullptr;
     SkBitmap temp = mBitmap;
     mBitmap.reset();
     temp.copyTo(&mBitmap, temp.getConfig());
   }
 }
 
 void
-SourceSurfaceSkia::MarkIndependent()
-{
-  if (mDrawTarget) {
-    mDrawTarget->RemoveSnapshot(this);
-    mDrawTarget = nullptr;
-  }
-}
-
-void
 SourceSurfaceSkia::MaybeUnlock()
 {
   if (mLocked) {
     mBitmap.unlockPixels();
     mLocked = false;
   }
 }
 
--- a/gfx/2d/SourceSurfaceSkia.h
+++ b/gfx/2d/SourceSurfaceSkia.h
@@ -40,18 +40,16 @@ public:
   virtual unsigned char *GetData();
 
   virtual int32_t Stride() { return mStride; }
 
 private:
   friend class DrawTargetSkia;
 
   void DrawTargetWillChange();
-  void DrawTargetDestroyed();
-  void MarkIndependent();
   void MaybeUnlock();
 
   SkBitmap mBitmap;
   SurfaceFormat mFormat;
   IntSize mSize;
   int32_t mStride;
   RefPtr<DrawTargetSkia> mDrawTarget;
   bool mLocked;
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -10,16 +10,17 @@
 #include "GLContext.h"
 
 #include "gfxCrashReporterUtils.h"
 #include "gfxPlatform.h"
 #include "gfxUtils.h"
 #include "GLContextProvider.h"
 #include "GLTextureImage.h"
 #include "nsIMemoryReporter.h"
+#include "nsPrintfCString.h"
 #include "nsThreadUtils.h"
 #include "prenv.h"
 #include "prlink.h"
 #include "SurfaceStream.h"
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Preferences.h"
 
@@ -464,60 +465,56 @@ GLContext::InitWithPrefix(const char *pr
                     mSymbols.fGetGraphicsResetStatus = nullptr;
                 } else {
                     mHasRobustness = true;
                 }
             }
         }
 
         // Check for aux symbols based on extensions
-        if (IsExtensionSupported(GLContext::ANGLE_framebuffer_blit) ||
-            IsExtensionSupported(GLContext::EXT_framebuffer_blit))
+        if (IsExtensionSupported(XXX_framebuffer_blit))
         {
             SymLoadStruct auxSymbols[] = {
                 {
                     (PRFuncPtr*) &mSymbols.fBlitFramebuffer,
                     {
                         "BlitFramebuffer",
                         "BlitFramebufferEXT",
                         "BlitFramebufferANGLE",
                         nullptr
                     }
                 },
                 { nullptr, { nullptr } },
             };
             if (!LoadSymbols(&auxSymbols[0], trygl, prefix)) {
                 NS_ERROR("GL supports framebuffer_blit without supplying glBlitFramebuffer");
 
-                MarkExtensionUnsupported(ANGLE_framebuffer_blit);
-                MarkExtensionUnsupported(EXT_framebuffer_blit);
+                MarkExtensionGroupUnsupported(XXX_framebuffer_blit);
                 mSymbols.fBlitFramebuffer = nullptr;
             }
         }
 
-        if (SupportsFramebufferMultisample())
+        if (IsExtensionSupported(XXX_framebuffer_multisample))
         {
-            MOZ_ASSERT(SupportsSplitFramebuffer());
             SymLoadStruct auxSymbols[] = {
                 {
                     (PRFuncPtr*) &mSymbols.fRenderbufferStorageMultisample,
                     {
                         "RenderbufferStorageMultisample",
                         "RenderbufferStorageMultisampleEXT",
                         "RenderbufferStorageMultisampleANGLE",
                         nullptr
                     }
                 },
                 { nullptr, { nullptr } },
             };
             if (!LoadSymbols(&auxSymbols[0], trygl, prefix)) {
                 NS_ERROR("GL supports framebuffer_multisample without supplying glRenderbufferStorageMultisample");
 
-                MarkExtensionUnsupported(ANGLE_framebuffer_multisample);
-                MarkExtensionUnsupported(EXT_framebuffer_multisample);
+                MarkExtensionGroupUnsupported(XXX_framebuffer_multisample);
                 mSymbols.fRenderbufferStorageMultisample = nullptr;
             }
         }
 
         if (IsExtensionSupported(ARB_sync)) {
             SymLoadStruct syncSymbols[] = {
                 { (PRFuncPtr*) &mSymbols.fFenceSync,      { "FenceSync",      nullptr } },
                 { (PRFuncPtr*) &mSymbols.fIsSync,         { "IsSync",         nullptr } },
@@ -567,19 +564,17 @@ GLContext::InitWithPrefix(const char *pr
                 { (PRFuncPtr*) &mSymbols.fBindVertexArray, { "BindVertexArray", "BindVertexArrayOES", nullptr } },
                 { (PRFuncPtr*) &mSymbols.fDeleteVertexArrays, { "DeleteVertexArrays", "DeleteVertexArraysOES", nullptr } },
                 { nullptr, { nullptr } },
             };
 
             if (!LoadSymbols(&vaoSymbols[0], trygl, prefix)) {
                 NS_ERROR("GL supports Vertex Array Object without supplying its functions.");
 
-                MarkExtensionUnsupported(ARB_vertex_array_object);
-                MarkExtensionUnsupported(OES_vertex_array_object);
-                MarkExtensionUnsupported(APPLE_vertex_array_object);
+                MarkExtensionGroupUnsupported(XXX_vertex_array_object);
                 mSymbols.fIsVertexArray = nullptr;
                 mSymbols.fGenVertexArrays = nullptr;
                 mSymbols.fBindVertexArray = nullptr;
                 mSymbols.fDeleteVertexArrays = nullptr;
             }
         }
         else if (IsExtensionSupported(APPLE_vertex_array_object)) {
             /*
@@ -592,17 +587,17 @@ GLContext::InitWithPrefix(const char *pr
                 { (PRFuncPtr*) &mSymbols.fBindVertexArray, { "BindVertexArrayAPPLE", nullptr } },
                 { (PRFuncPtr*) &mSymbols.fDeleteVertexArrays, { "DeleteVertexArraysAPPLE", nullptr } },
                 { nullptr, { nullptr } },
             };
 
             if (!LoadSymbols(&vaoSymbols[0], trygl, prefix)) {
                 NS_ERROR("GL supports Vertex Array Object without supplying its functions.");
 
-                MarkExtensionUnsupported(APPLE_vertex_array_object);
+                MarkExtensionGroupUnsupported(XXX_vertex_array_object);
                 mSymbols.fIsVertexArray = nullptr;
                 mSymbols.fGenVertexArrays = nullptr;
                 mSymbols.fBindVertexArray = nullptr;
                 mSymbols.fDeleteVertexArrays = nullptr;
             }
         }
 
         if (IsExtensionSupported(XXX_draw_instanced)) {
@@ -626,20 +621,17 @@ GLContext::InitWithPrefix(const char *pr
                   }
                 },
                 { nullptr, { nullptr } },
             };
 
             if (!LoadSymbols(drawInstancedSymbols, trygl, prefix)) {
                 NS_ERROR("GL supports instanced draws without supplying its functions.");
 
-                MarkExtensionUnsupported(ARB_draw_instanced);
-                MarkExtensionUnsupported(EXT_draw_instanced);
-                MarkExtensionUnsupported(NV_draw_instanced);
-                MarkExtensionUnsupported(ANGLE_instanced_array);
+                MarkExtensionGroupUnsupported(XXX_draw_instanced);
                 mSymbols.fDrawArraysInstanced = nullptr;
                 mSymbols.fDrawElementsInstanced = nullptr;
             }
         }
 
         // Load developer symbols, don't fail if we can't find them.
         SymLoadStruct auxSymbols[] = {
                 { (PRFuncPtr*) &mSymbols.fGetTexImage, { "GetTexImage", nullptr } },
@@ -700,17 +692,17 @@ GLContext::InitWithPrefix(const char *pr
             mMaxCubeMapTextureSize = std::min(mMaxCubeMapTextureSize, 2048);
             mNeedsTextureSizeChecks = true;
         }
 #endif
 
         mMaxTextureImageSize = mMaxTextureSize;
 
         mMaxSamples = 0;
-        if (SupportsFramebufferMultisample()) {
+        if (IsExtensionSupported(XXX_framebuffer_multisample)) {
             fGetIntegerv(LOCAL_GL_MAX_SAMPLES, (GLint*)&mMaxSamples);
         }
 
         // We're ready for final setup.
         fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
 
         if (mCaps.any)
             DetermineCaps();
@@ -726,16 +718,18 @@ GLContext::InitWithPrefix(const char *pr
     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!");
     }
 
+    mVersionString = nsPrintfCString("%u.%u.%u", mVersion / 100, (mVersion / 10) % 10, mVersion % 10);
+
     return mInitialized;
 }
 
 void
 GLContext::InitExtensions()
 {
     MakeCurrent();
     const char* extensions = (const char*)fGetString(LOCAL_GL_EXTENSIONS);
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -193,16 +193,23 @@ public:
                 break;
         }
 
         MOZ_ASSERT(profile != ContextProfile::Unknown, "unknown context profile");
         return "OpenGL unknown profile";
     }
 
     /**
+     * Return true if we are running on a OpenGL core profile context
+     */
+    const char* ProfileString() const {
+        return GetProfileName(mProfile);
+    }
+
+    /**
      * Return true if the context is compatible with given parameters
      *
      * IsAtLeast(ContextProfile::OpenGL, N) is exactly same as
      * IsAtLeast(ContextProfile::OpenGLCore, N) || IsAtLeast(ContextProfile::OpenGLCompatibility, N)
      */
     inline bool IsAtLeast(ContextProfile profile, unsigned int version) const
     {
         MOZ_ASSERT(profile != ContextProfile::Unknown, "IsAtLeast: bad <profile> parameter");
@@ -223,16 +230,20 @@ public:
      * Return the version of the context.
      * Example :
      *   If this a OpenGL 2.1, that will return 210
      */
     inline unsigned int Version() const {
         return mVersion;
     }
 
+    const char* VersionString() const {
+        return mVersionString.get();
+    }
+
     int Vendor() const {
         return mVendor;
     }
 
     int Renderer() const {
         return mRenderer;
     }
 
@@ -278,16 +289,17 @@ protected:
     bool mIsGlobalSharedContext;
     bool mContextLost;
 
     /**
      * mVersion store the OpenGL's version, multiplied by 100. For example, if
      * the context is an OpenGL 2.1 context, mVersion value will be 210.
      */
     unsigned int mVersion;
+    nsCString mVersionString;
     ContextProfile mProfile;
 
     int32_t mVendor;
     int32_t mRenderer;
 
     inline void SetProfileVersion(ContextProfile profile, unsigned int version) {
         MOZ_ASSERT(!mInitialized, "SetProfileVersion can only be called before initialization!");
         MOZ_ASSERT(profile != ContextProfile::Unknown && profile != ContextProfile::OpenGL, "Invalid `profile` for SetProfileVersion");
@@ -364,17 +376,18 @@ public:
         ARB_draw_buffers,
         EXT_draw_buffers,
         EXT_gpu_shader4,
         EXT_blend_minmax,
         ARB_draw_instanced,
         EXT_draw_instanced,
         NV_draw_instanced,
         ANGLE_instanced_array,
-        Extensions_Max
+        Extensions_Max,
+        Extensions_End
     };
 
     bool IsExtensionSupported(GLExtensions aKnownExtension) const {
         return mAvailableExtensions[aKnownExtension];
     }
 
     void MarkExtensionUnsupported(GLExtensions aKnownExtension) {
         mAvailableExtensions[aKnownExtension] = 0;
@@ -455,96 +468,43 @@ protected:
  * This mecahnism introduces a new way to check if an extension is supported,
  * regardless if it is an ARB, EXT, OES, etc.
  */
 public:
 
     /**
      * This enum should be sorted by name.
      */
-    enum GLExtensionPackages {
+    enum GLExtensionGroup {
         XXX_draw_buffers,
         XXX_draw_instanced,
         XXX_framebuffer_blit,
         XXX_framebuffer_multisample,
         XXX_framebuffer_object,
+        XXX_robustness,
         XXX_texture_float,
         XXX_texture_non_power_of_two,
-        XXX_robustness,
         XXX_vertex_array_object,
-        ExtensionPackages_Max
+        ExtensionGroup_Max
     };
 
-    bool IsExtensionSupported(GLExtensionPackages aKnownExtensionPackage) const
-    {
-        switch (aKnownExtensionPackage)
-        {
-            case XXX_draw_buffers:
-                return IsExtensionSupported(ARB_draw_buffers) ||
-                       IsExtensionSupported(EXT_draw_buffers);
-
-            case XXX_draw_instanced:
-                return IsExtensionSupported(ARB_draw_instanced) ||
-                       IsExtensionSupported(EXT_draw_instanced) ||
-                       IsExtensionSupported(NV_draw_instanced) ||
-                       IsExtensionSupported(ANGLE_instanced_array);
-
-            case XXX_framebuffer_blit:
-                return IsExtensionSupported(EXT_framebuffer_blit) ||
-                       IsExtensionSupported(ANGLE_framebuffer_blit);
-
-            case XXX_framebuffer_multisample:
-                return IsExtensionSupported(EXT_framebuffer_multisample) ||
-                       IsExtensionSupported(ANGLE_framebuffer_multisample);
-
-            case XXX_framebuffer_object:
-                return IsExtensionSupported(ARB_framebuffer_object) ||
-                       IsExtensionSupported(EXT_framebuffer_object);
-
-            case XXX_texture_float:
-                return IsExtensionSupported(ARB_texture_float) ||
-                       IsExtensionSupported(OES_texture_float);
-
-            case XXX_robustness:
-                return IsExtensionSupported(ARB_robustness) ||
-                       IsExtensionSupported(EXT_robustness);
-
-            case XXX_texture_non_power_of_two:
-                return IsExtensionSupported(ARB_texture_non_power_of_two) ||
-                       IsExtensionSupported(OES_texture_npot);
-
-            case XXX_vertex_array_object:
-                return IsExtensionSupported(ARB_vertex_array_object) ||
-                       IsExtensionSupported(OES_vertex_array_object) ||
-                       IsExtensionSupported(APPLE_vertex_array_object);
-
-            default:
-                break;
-        }
-
-        MOZ_ASSERT(false, "GLContext::IsExtensionSupported : unknown <aKnownExtensionPackage>");
-        return false;
-    }
-
-
-// -----------------------------------------------------------------------------
-// Deprecated extension group queries (use XXX_* instead)
-public:
-
-    bool SupportsFramebufferMultisample() const {
-        return IsExtensionSupported(XXX_framebuffer_multisample);
-    }
-
-    bool HasExt_FramebufferBlit() const {
-        return IsExtensionSupported(XXX_framebuffer_blit);
-    }
-
-    bool SupportsSplitFramebuffer() const {
-        return IsExtensionSupported(XXX_framebuffer_blit);
-    }
+    bool IsExtensionSupported(GLExtensionGroup extensionGroup) const;
+
+    static const char* GetExtensionGroupName(GLExtensionGroup extensionGroup);
+
+
+private:
+
+    /**
+     * Mark all extensions of this group as unsupported.
+     *
+     * Returns false if marking this extension group as unsupported contradicts
+     * the OpenGL version and profile. Returns true otherwise.
+     */
+    bool MarkExtensionGroupUnsupported(GLExtensionGroup extensionGroup);
 
 
 // -----------------------------------------------------------------------------
 // Robustness handling
 public:
 
     bool HasRobustness() {
         return mHasRobustness;
@@ -560,18 +520,17 @@ public:
 private:
     bool mHasRobustness;
 
 
 // -----------------------------------------------------------------------------
 // Error handling
 public:
 
-    // TODO: this function should be a static
-    const char* GLErrorToString(GLenum aError) const
+    static const char* GLErrorToString(GLenum aError)
     {
         switch (aError) {
             case LOCAL_GL_INVALID_ENUM:
                 return "GL_INVALID_ENUM";
             case LOCAL_GL_INVALID_VALUE:
                 return "GL_INVALID_VALUE";
             case LOCAL_GL_INVALID_OPERATION:
                 return "GL_INVALID_OPERATION";
@@ -2587,18 +2546,19 @@ public:
         GetUIntegerv(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, &ret);
         return ret;
     }
 
     GLuint GetReadFB() {
         if (mScreen)
             return mScreen->GetReadFB();
 
-        GLenum bindEnum = SupportsSplitFramebuffer() ? LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT
-                                                     : LOCAL_GL_FRAMEBUFFER_BINDING;
+        GLenum bindEnum = IsExtensionSupported(XXX_framebuffer_blit)
+                            ? LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT
+                            : LOCAL_GL_FRAMEBUFFER_BINDING;
 
         GLuint ret = 0;
         GetUIntegerv(bindEnum, &ret);
         return ret;
     }
 
     GLuint GetFB() {
         if (mScreen) {
new file mode 100644
--- /dev/null
+++ b/gfx/gl/GLContextExtensionGroupQueries.cpp
@@ -0,0 +1,220 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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 "GLContext.h"
+#include "nsPrintfCString.h"
+
+namespace mozilla {
+namespace gl {
+
+const size_t kMAX_EXTENSION_GROUP_SIZE = 5;
+
+struct ExtensionGroupInfo
+{
+    const char* mName;
+    unsigned int mOpenGLVersion;
+    unsigned int mOpenGLESVersion;
+    GLContext::GLExtensions mExtensions[kMAX_EXTENSION_GROUP_SIZE];
+};
+
+static const ExtensionGroupInfo sExtensionGroupInfoArr[] = {
+    {
+        "XXX_draw_buffers",
+        200, // OpenGL version
+        300, // OpenGL ES version
+        {
+            GLContext::ARB_draw_buffers,
+            GLContext::EXT_draw_buffers,
+            GLContext::Extensions_End
+        }
+    },
+    {
+        "XXX_draw_instanced",
+        310, // OpenGL version
+        300, // OpenGL ES version
+        {
+            GLContext::ARB_draw_instanced,
+            GLContext::EXT_draw_instanced,
+            GLContext::NV_draw_instanced,
+            GLContext::ANGLE_instanced_array,
+            GLContext::Extensions_End
+        }
+    },
+    {
+        "XXX_framebuffer_blit",
+        300, // OpenGL version
+        300, // OpenGL ES version
+        {
+            GLContext::EXT_framebuffer_blit,
+            GLContext::ANGLE_framebuffer_blit,
+            GLContext::Extensions_End
+        }
+    },
+    {
+        "XXX_framebuffer_multisample",
+        300, // OpenGL version
+        300, // OpenGL ES version
+        {
+            GLContext::EXT_framebuffer_multisample,
+            GLContext::ANGLE_framebuffer_multisample,
+            GLContext::Extensions_End
+        }
+    },
+    {
+        "XXX_framebuffer_object",
+        300, // OpenGL version
+        200, // OpenGL ES version
+        {
+            GLContext::ARB_framebuffer_object,
+            GLContext::EXT_framebuffer_object,
+            GLContext::Extensions_End
+        }
+    },
+    {
+        "XXX_robustness",
+        0,   // OpenGL version
+        0,   // OpenGL ES version
+        {
+            GLContext::ARB_robustness,
+            GLContext::EXT_robustness,
+            GLContext::Extensions_End
+        }
+    },
+    {
+        "XXX_texture_float",
+        310, // OpenGL version
+        300, // OpenGL ES version
+        {
+            GLContext::ARB_texture_float,
+            GLContext::OES_texture_float,
+            GLContext::Extensions_End
+        }
+    },
+    {
+        "XXX_texture_non_power_of_two",
+        200, // OpenGL version
+        300, // OpenGL ES version
+        {
+            GLContext::ARB_texture_non_power_of_two,
+            GLContext::OES_texture_npot,
+            GLContext::Extensions_End
+        }
+    },
+    {
+        "XXX_vertex_array_object",
+        300, // OpenGL version
+        300, // OpenGL ES version
+        {
+            GLContext::ARB_vertex_array_object,
+            GLContext::OES_vertex_array_object,
+            GLContext::APPLE_vertex_array_object,
+            GLContext::Extensions_End
+        }
+    }
+};
+
+static inline const ExtensionGroupInfo&
+GetExtensionGroupInfo(GLContext::GLExtensionGroup extensionGroup)
+{
+    static_assert(MOZ_ARRAY_LENGTH(sExtensionGroupInfoArr) == size_t(GLContext::ExtensionGroup_Max),
+                  "Mismatched lengths for sExtensionGroupInfos and ExtensionGroup enums");
+
+    MOZ_ASSERT(extensionGroup < GLContext::ExtensionGroup_Max,
+               "GLContext::GetExtensionGroupInfo : unknown <extensionGroup>");
+
+    return sExtensionGroupInfoArr[extensionGroup];
+}
+
+static inline uint32_t
+ProfileVersionForExtensionGroup(GLContext::GLExtensionGroup extensionGroup, ContextProfile profile)
+{
+    MOZ_ASSERT(profile != ContextProfile::Unknown,
+               "GLContext::ProfileVersionForExtensionGroup : unknown <profile>");
+
+    const ExtensionGroupInfo& groupInfo = GetExtensionGroupInfo(extensionGroup);
+
+    if (profile == ContextProfile::OpenGLES) {
+        return groupInfo.mOpenGLESVersion;
+    }
+
+    return groupInfo.mOpenGLVersion;
+}
+
+static inline bool
+IsExtensionGroupIsPartOfProfileVersion(GLContext::GLExtensionGroup extensionGroup,
+                                       ContextProfile profile, unsigned int version)
+{
+    unsigned int profileVersion = ProfileVersionForExtensionGroup(extensionGroup, profile);
+
+    return profileVersion && version >= profileVersion;
+}
+
+const char*
+GLContext::GetExtensionGroupName(GLExtensionGroup extensionGroup)
+{
+    return GetExtensionGroupInfo(extensionGroup).mName;
+}
+
+bool
+GLContext::IsExtensionSupported(GLExtensionGroup extensionGroup) const
+{
+    if (IsExtensionGroupIsPartOfProfileVersion(extensionGroup, mProfile, mVersion)) {
+        return true;
+    }
+
+    const ExtensionGroupInfo& groupInfo = GetExtensionGroupInfo(extensionGroup);
+
+    for (size_t i = 0; true; i++)
+    {
+        MOZ_ASSERT(i < kMAX_EXTENSION_GROUP_SIZE, "kMAX_EXTENSION_GROUP_SIZE too small");
+
+        if (groupInfo.mExtensions[i] == GLContext::Extensions_End) {
+            break;
+        }
+
+        if (IsExtensionSupported(groupInfo.mExtensions[i])) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+bool
+GLContext::MarkExtensionGroupUnsupported(GLExtensionGroup extensionGroup)
+{
+    MOZ_ASSERT(IsExtensionSupported(extensionGroup), "extension group is already unsupported!");
+
+    if (IsExtensionGroupIsPartOfProfileVersion(extensionGroup, mProfile, mVersion)) {
+        NS_WARNING(nsPrintfCString("%s marked as unsupported, but it's supposed to be supported by %s %s",
+                                   GetExtensionGroupName(extensionGroup),
+                                   ProfileString(),
+                                   VersionString()).get());
+        return false;
+    }
+
+    const ExtensionGroupInfo& groupInfo = GetExtensionGroupInfo(extensionGroup);
+
+    for (size_t i = 0; true; i++)
+    {
+        MOZ_ASSERT(i < kMAX_EXTENSION_GROUP_SIZE, "kMAX_EXTENSION_GROUP_SIZE too small");
+
+        if (groupInfo.mExtensions[i] == GLContext::Extensions_End) {
+            break;
+        }
+
+        MarkExtensionUnsupported(groupInfo.mExtensions[i]);
+    }
+
+    MOZ_ASSERT(!IsExtensionSupported(extensionGroup), "GLContext::MarkExtensionGroupUnsupported has failed!");
+
+    NS_WARNING(nsPrintfCString("%s marked as unsupported", GetExtensionGroupName(extensionGroup)).get());
+
+    return true;
+}
+
+} /* namespace gl */
+} /* namespace mozilla */
--- a/gfx/gl/GLContextProviderCGL.mm
+++ b/gfx/gl/GLContextProviderCGL.mm
@@ -133,22 +133,23 @@ public:
     bool MakeCurrentImpl(bool aForce = false)
     {
         if (!aForce && [NSOpenGLContext currentContext] == mContext) {
             return true;
         }
 
         if (mContext) {
             [mContext makeCurrentContext];
-            // Use blocking swap only with the default frame rate.
+            // Use non-blocking swap in "ASAP mode".
+            // ASAP mode means that rendering is iterated as fast as possible.
+            // ASAP mode is entered when layout.frame_rate=0 (requires restart).
             // If swapInt is 1, then glSwapBuffers will block and wait for a vblank signal.
-            // While this is fine for the default refresh rate, if the user chooses some
-            // other rate, and specifically if this rate is higher than the screen refresh rate,
-            // then we want a non-blocking glSwapBuffers, which will happen when swapInt==0.
-            GLint swapInt = gfxPlatform::GetPrefLayoutFrameRate() == -1 ? 1 : 0;
+            // When we're iterating as fast as possible, however, we want a non-blocking
+            // glSwapBuffers, which will happen when swapInt==0.
+            GLint swapInt = gfxPlatform::GetPrefLayoutFrameRate() == 0 ? 0 : 1;
             [mContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
         }
         return true;
     }
 
     virtual bool IsCurrent() {
         return [NSOpenGLContext currentContext] == mContext;
     }
--- a/gfx/gl/GLScreenBuffer.cpp
+++ b/gfx/gl/GLScreenBuffer.cpp
@@ -24,17 +24,17 @@ namespace mozilla {
 namespace gl {
 
 GLScreenBuffer*
 GLScreenBuffer::Create(GLContext* gl,
                      const gfxIntSize& size,
                      const SurfaceCaps& caps)
 {
     if (caps.antialias &&
-        !gl->SupportsFramebufferMultisample())
+        !gl->IsExtensionSupported(GLContext::XXX_framebuffer_multisample))
     {
         return nullptr;
     }
 
     SurfaceFactory_GL* factory = nullptr;
 
 #ifdef MOZ_WIDGET_GONK
     /* On B2G, we want a Gralloc factory, and we want one right at the start */
@@ -74,37 +74,37 @@ GLScreenBuffer::~GLScreenBuffer()
 
 
 void
 GLScreenBuffer::BindAsFramebuffer(GLContext* const gl, GLenum target) const
 {
     GLuint drawFB = DrawFB();
     GLuint readFB = ReadFB();
 
-    if (!gl->HasExt_FramebufferBlit()) {
+    if (!gl->IsExtensionSupported(GLContext::XXX_framebuffer_blit)) {
         MOZ_ASSERT(drawFB == readFB);
         gl->raw_fBindFramebuffer(target, readFB);
         return;
     }
 
     switch (target) {
     case LOCAL_GL_FRAMEBUFFER:
         gl->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, drawFB);
         gl->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, readFB);
         break;
 
     case LOCAL_GL_DRAW_FRAMEBUFFER_EXT:
-        if (!gl->HasExt_FramebufferBlit())
+        if (!gl->IsExtensionSupported(GLContext::XXX_framebuffer_blit))
             NS_WARNING("DRAW_FRAMEBUFFER requested but unavailable.");
 
         gl->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, drawFB);
         break;
 
     case LOCAL_GL_READ_FRAMEBUFFER_EXT:
-        if (!gl->HasExt_FramebufferBlit())
+        if (!gl->IsExtensionSupported(GLContext::XXX_framebuffer_blit))
             NS_WARNING("READ_FRAMEBUFFER requested but unavailable.");
 
         gl->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, readFB);
         break;
 
     default:
         MOZ_CRASH("Bad `target` for BindFramebuffer.");
     }
@@ -119,31 +119,31 @@ GLScreenBuffer::BindFB(GLuint fb)
     mUserDrawFB = fb;
     mUserReadFB = fb;
     mInternalDrawFB = (fb == 0) ? drawFB : fb;
     mInternalReadFB = (fb == 0) ? readFB : fb;
 
     if (mInternalDrawFB == mInternalReadFB) {
         mGL->raw_fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mInternalDrawFB);
     } else {
-        MOZ_ASSERT(mGL->SupportsSplitFramebuffer());
+        MOZ_ASSERT(mGL->IsExtensionSupported(GLContext::XXX_framebuffer_blit));
         mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB);
         mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB);
     }
 
 #ifdef DEBUG
     mInInternalMode_DrawFB = false;
     mInInternalMode_ReadFB = false;
 #endif
 }
 
 void
 GLScreenBuffer::BindDrawFB(GLuint fb)
 {
-    if (!mGL->SupportsSplitFramebuffer()) {
+    if (!mGL->IsExtensionSupported(GLContext::XXX_framebuffer_blit)) {
         NS_WARNING("DRAW_FRAMEBUFFER requested, but unsupported.");
 
         mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, fb);
     } else {
         GLuint drawFB = DrawFB();
         mUserDrawFB = fb;
         mInternalDrawFB = (fb == 0) ? drawFB : fb;
 
@@ -153,17 +153,17 @@ GLScreenBuffer::BindDrawFB(GLuint fb)
 #ifdef DEBUG
     mInInternalMode_DrawFB = false;
 #endif
 }
 
 void
 GLScreenBuffer::BindReadFB(GLuint fb)
 {
-    if (!mGL->SupportsSplitFramebuffer()) {
+    if (!mGL->IsExtensionSupported(GLContext::XXX_framebuffer_blit)) {
         NS_WARNING("READ_FRAMEBUFFER requested, but unsupported.");
 
         mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, fb);
     } else {
         GLuint readFB = ReadFB();
         mUserReadFB = fb;
         mInternalReadFB = (fb == 0) ? readFB : fb;
 
@@ -228,17 +228,17 @@ GLScreenBuffer::GetReadFB() const
 {
 #ifdef DEBUG
     MOZ_ASSERT(mGL->IsCurrent());
     MOZ_ASSERT(!mInInternalMode_ReadFB);
 
     // We use raw_ here because this is debug code and we need to see what
     // the driver thinks.
     GLuint actual = 0;
-    if (mGL->SupportsSplitFramebuffer())
+    if (mGL->IsExtensionSupported(GLContext::XXX_framebuffer_blit))
         mGL->raw_fGetIntegerv(LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT, (GLint*)&actual);
     else
         mGL->raw_fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*)&actual);
 
     GLuint predicted = mInternalReadFB;
     if (predicted != actual) {
         printf_stderr("Misprediction: Bound read FB predicted: %d. Was: %d.\n",
                       predicted, actual);
--- a/gfx/gl/moz.build
+++ b/gfx/gl/moz.build
@@ -96,16 +96,17 @@ else:
 
 if gl_provider == 'EGL':
     CPP_SOURCES += [
         'GLLibraryEGL.cpp',
     ]
 
 CPP_SOURCES += [
     'GLContext.cpp',
+    'GLContextExtensionGroupQueries.cpp',
     'GLContextTypes.cpp',
     'GLContextUtils.cpp',
     'GLLibraryLoader.cpp',
     'GLScreenBuffer.cpp',
     'GLTextureImage.cpp',
     'SharedSurface.cpp',
     'SharedSurfaceEGL.cpp',
     'SharedSurfaceGL.cpp',
--- a/gfx/layers/CompositorTypes.h
+++ b/gfx/layers/CompositorTypes.h
@@ -2,16 +2,18 @@
 * 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_LAYERS_COMPOSITORTYPES_H
 #define MOZILLA_LAYERS_COMPOSITORTYPES_H
 
 #include "LayersTypes.h"
+#include "nsXULAppAPI.h"
+
 
 namespace mozilla {
 namespace layers {
 
 typedef int32_t SurfaceDescriptorType;
 const SurfaceDescriptorType SURFACEDESCRIPTOR_UNKNOWN = 0;
 
 /**
@@ -62,21 +64,40 @@ const TextureFlags TEXTURE_COPY_PREVIOUS
 // be a choice from another part of gecko that wants to keep the data alive
 // for some reason. The default behaviour is to deallocate on the host side.
 const TextureFlags TEXTURE_DEALLOCATE_CLIENT  = 1 << 25;
 const TextureFlags TEXTURE_DEALLOCATE_HOST    = 1 << 26;
 // After being shared ith the compositor side, an immutable texture is never
 // modified, it can only be read. It is safe to not Lock/Unlock immutable
 // textures.
 const TextureFlags TEXTURE_IMMUTABLE          = 1 << 27;
+// The contents of the texture must be uploaded or copied immediately
+// during the transaction, because the producer may want to write
+// to it again.
+const TextureFlags TEXTURE_IMMEDIATE_UPLOAD   = 1 << 28;
+// The texture is going to be used as part of a double
+// buffered pair, and so we can guarantee that the producer/consumer
+// won't be racing to access its contents.
+const TextureFlags TEXTURE_DOUBLE_BUFFERED    = 1 << 29;
 
 // the default flags
 const TextureFlags TEXTURE_FLAGS_DEFAULT = TEXTURE_DEALLOCATE_HOST
                                          | TEXTURE_FRONT;
 
+static inline bool
+TextureRequiresLocking(TextureFlags aFlags)
+{
+  // If we're not double buffered, or uploading
+  // within a transaction, then we need to support
+  // locking correctly.
+  return !(aFlags & (TEXTURE_IMMEDIATE_UPLOAD |
+                     TEXTURE_DOUBLE_BUFFERED |
+                     TEXTURE_IMMUTABLE));
+}
+
 /**
  * See gfx/layers/Effects.h
  */
 enum EffectTypes
 {
   EFFECT_MASK,
   EFFECT_MAX_SECONDARY, // sentinel for the count of secondary effect types
   EFFECT_BGRX,
@@ -99,17 +120,18 @@ enum DeprecatedTextureClientType
 {
   TEXTURE_CONTENT,            // dynamically drawn content
   TEXTURE_SHMEM,              // shared memory
   TEXTURE_YCBCR,              // Deprecated YCbCr texture
   TEXTURE_SHARED_GL,          // GLContext::SharedTextureHandle
   TEXTURE_SHARED_GL_EXTERNAL, // GLContext::SharedTextureHandle, the ownership of
                               // the SurfaceDescriptor passed to the texture
                               // remains with whoever passed it.
-  TEXTURE_STREAM_GL           // WebGL streaming buffer
+  TEXTURE_STREAM_GL,          // WebGL streaming buffer
+  TEXTURE_FALLBACK            // A fallback path appropriate for the platform
 };
 
 /**
  * How the Compositable should manage textures.
  */
 enum CompositableType
 {
   BUFFER_UNKNOWN,
@@ -142,25 +164,28 @@ enum DeprecatedTextureHostFlags
 /**
  * Sent from the compositor to the content-side LayerManager, includes properties
  * of the compositor and should (in the future) include information about what
  * kinds of buffer and texture clients to create.
  */
 struct TextureFactoryIdentifier
 {
   LayersBackend mParentBackend;
+  GeckoProcessType mParentProcessId;
   int32_t mMaxTextureSize;
   bool mSupportsTextureBlitting;
   bool mSupportsPartialUploads;
 
   TextureFactoryIdentifier(LayersBackend aLayersBackend = LAYERS_NONE,
+                           GeckoProcessType aParentProcessId = GeckoProcessType_Default,
                            int32_t aMaxTextureSize = 0,
                            bool aSupportsTextureBlitting = false,
                            bool aSupportsPartialUploads = false)
     : mParentBackend(aLayersBackend)
+    , mParentProcessId(aParentProcessId)
     , mMaxTextureSize(aMaxTextureSize)
     , mSupportsTextureBlitting(aSupportsTextureBlitting)
     , mSupportsPartialUploads(aSupportsPartialUploads)
   {}
 };
 
 /**
  * Identify a texture to a compositable. Many textures can have the same id, but
--- a/gfx/layers/ThebesLayerBuffer.cpp
+++ b/gfx/layers/ThebesLayerBuffer.cpp
@@ -441,17 +441,18 @@ ComputeBufferRect(const nsIntRect& aRequ
 
 ThebesLayerBuffer::PaintState
 ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
                               uint32_t aFlags)
 {
   PaintState result;
   // We need to disable rotation if we're going to be resampled when
   // drawing, because we might sample across the rotation boundary.
-  bool canHaveRotation = !(aFlags & (PAINT_WILL_RESAMPLE | PAINT_NO_ROTATION));
+  bool canHaveRotation = gfxPlatform::BufferRotationEnabled() &&
+                         !(aFlags & (PAINT_WILL_RESAMPLE | PAINT_NO_ROTATION));
 
   nsIntRegion validRegion = aLayer->GetValidRegion();
 
   Layer::SurfaceMode mode;
   ContentType contentType;
   nsIntRegion neededRegion;
   bool canReuseBuffer;
   nsIntRect destBufferRect;
--- a/gfx/layers/YCbCrImageDataSerializer.cpp
+++ b/gfx/layers/YCbCrImageDataSerializer.cpp
@@ -35,16 +35,17 @@ struct YCbCrBufferInfo
 {
   uint32_t mYOffset;
   uint32_t mCbOffset;
   uint32_t mCrOffset;
   uint32_t mYWidth;
   uint32_t mYHeight;
   uint32_t mCbCrWidth;
   uint32_t mCbCrHeight;
+  StereoMode mStereoMode;
 };
 
 static YCbCrBufferInfo* GetYCbCrBufferInfo(uint8_t* aData)
 {
   return reinterpret_cast<YCbCrBufferInfo*>(aData);
 }
 
 bool YCbCrImageDataDeserializerBase::IsValid()
@@ -98,16 +99,22 @@ gfxIntSize YCbCrImageDataDeserializerBas
 }
 
 gfxIntSize YCbCrImageDataDeserializerBase::GetCbCrSize()
 {
   YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData);
   return gfxIntSize(info->mCbCrWidth, info->mCbCrHeight);
 }
 
+StereoMode YCbCrImageDataDeserializerBase::GetStereoMode()
+{
+  YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData);
+  return info->mStereoMode;
+}
+
 // Offset in bytes
 static size_t ComputeOffset(uint32_t aHeight, uint32_t aStride)
 {
   return MOZ_ALIGN_WORD(aHeight * aStride);
 }
 
 // Minimum required shmem size in bytes
 size_t
@@ -139,37 +146,41 @@ static size_t ComputeOffset(uint32_t aSi
 size_t
 YCbCrImageDataSerializer::ComputeMinBufferSize(uint32_t aSize)
 {
   return ComputeOffset(aSize) + MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
 }
 
 void
 YCbCrImageDataSerializer::InitializeBufferInfo(const gfx::IntSize& aYSize,
-                                               const gfx::IntSize& aCbCrSize)
+                                               const gfx::IntSize& aCbCrSize,
+                                               StereoMode aStereoMode)
 {
   YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData);
   info->mYOffset = MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
   info->mCbOffset = info->mYOffset
                   + MOZ_ALIGN_WORD(aYSize.width * aYSize.height);
   info->mCrOffset = info->mCbOffset
                   + MOZ_ALIGN_WORD(aCbCrSize.width * aCbCrSize.height);
 
   info->mYWidth = aYSize.width;
   info->mYHeight = aYSize.height;
   info->mCbCrWidth = aCbCrSize.width;
   info->mCbCrHeight = aCbCrSize.height;
+  info->mStereoMode = aStereoMode;
 }
 
 void
 YCbCrImageDataSerializer::InitializeBufferInfo(const gfxIntSize& aYSize,
-                                               const gfxIntSize& aCbCrSize)
+                                               const gfxIntSize& aCbCrSize,
+                                               StereoMode aStereoMode)
 {
   InitializeBufferInfo(gfx::IntSize(aYSize.width, aYSize.height),
-                       gfx::IntSize(aCbCrSize.width, aCbCrSize.height));
+                       gfx::IntSize(aCbCrSize.width, aCbCrSize.height),
+                       aStereoMode);
 }
 
 static void CopyLineWithSkip(const uint8_t* src, uint8_t* dst, uint32_t len, uint32_t skip) {
   for (uint32_t i = 0; i < len; ++i) {
     *dst = *src;
     src += 1 + skip;
     ++dst;
   }
--- a/gfx/layers/YCbCrImageDataSerializer.h
+++ b/gfx/layers/YCbCrImageDataSerializer.h
@@ -62,16 +62,21 @@ public:
   gfxIntSize GetYSize();
 
   /**
    * Returns the dimensions of the Cb and Cr Channel.
    */
   gfxIntSize GetCbCrSize();
 
   /**
+   * Stereo mode for the image.
+   */
+  StereoMode GetStereoMode();
+
+  /**
    * Return a pointer to the begining of the data buffer.
    */
   uint8_t* GetData();
 protected:
   YCbCrImageDataDeserializerBase(uint8_t* aData)
   : mData (aData) {}
 
   uint8_t* mData;
@@ -106,19 +111,21 @@ public:
   static size_t ComputeMinBufferSize(uint32_t aSize);
 
   /**
    * Write the image informations in the buffer for given dimensions.
    * The provided pointer should point to the beginning of the (chunk of)
    * buffer on which we want to store the image.
    */
   void InitializeBufferInfo(const gfx::IntSize& aYSize,
-                            const gfx::IntSize& aCbCrSize);
+                            const gfx::IntSize& aCbCrSize,
+                            StereoMode aStereoMode);
   void InitializeBufferInfo(const gfxIntSize& aYSize,
-                            const gfxIntSize& aCbCrSize);
+                            const gfxIntSize& aCbCrSize,
+                            StereoMode aStereoMode);
 
   bool CopyData(const uint8_t* aYData,
                 const uint8_t* aCbData, const uint8_t* aCrData,
                 gfxIntSize aYSize, uint32_t aYStride,
                 gfxIntSize aCbCrSize, uint32_t aCbCrStride,
                 uint32_t aYSkip, uint32_t aCbCrSkip);
 };
 
--- a/gfx/layers/basic/BasicCompositor.h
+++ b/gfx/layers/basic/BasicCompositor.h
@@ -38,17 +38,19 @@ public:
 
   virtual void Destroy() MOZ_OVERRIDE;
 
   virtual TemporaryRef<DataTextureSource>
   CreateDataTextureSource(TextureFlags aFlags = 0) MOZ_OVERRIDE { return nullptr; }
 
   virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() MOZ_OVERRIDE
   {
-    return TextureFactoryIdentifier(LAYERS_BASIC, GetMaxTextureSize());
+    return TextureFactoryIdentifier(LAYERS_BASIC,
+                                    XRE_GetProcessType(),
+                                    GetMaxTextureSize());
   }
 
   virtual TemporaryRef<CompositingRenderTarget>
   CreateRenderTarget(const gfx::IntRect &aRect, SurfaceInitMode aInit) MOZ_OVERRIDE;
 
   virtual TemporaryRef<CompositingRenderTarget>
   CreateRenderTargetFromSource(const gfx::IntRect &aRect,
                                const CompositingRenderTarget *aSource) MOZ_OVERRIDE;
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -23,37 +23,87 @@ namespace layers {
 
 /* static */ TemporaryRef<CanvasClient>
 CanvasClient::CreateCanvasClient(CanvasClientType aType,
                                  CompositableForwarder* aForwarder,
                                  TextureFlags aFlags)
 {
   if (aType == CanvasClientGLContext &&
       aForwarder->GetCompositorBackendType() == LAYERS_OPENGL) {
-    return new CanvasClientSurfaceStream(aForwarder, aFlags);
+    return new DeprecatedCanvasClientSurfaceStream(aForwarder, aFlags);
+  }
+  if (gfxPlatform::GetPlatform()->UseDeprecatedTextures()) {
+    return new DeprecatedCanvasClient2D(aForwarder, aFlags);
   }
   return new CanvasClient2D(aForwarder, aFlags);
 }
 
 void
-CanvasClient::Updated()
+CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
+{
+  if (mBuffer &&
+      (mBuffer->IsImmutable() || mBuffer->GetSize() != aSize)) {
+    RemoveTextureClient(mBuffer);
+    mBuffer = nullptr;
+  }
+
+  if (!mBuffer) {
+    bool isOpaque = (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE);
+    gfxASurface::gfxContentType contentType = isOpaque
+                                                ? gfxASurface::CONTENT_COLOR
+                                                : gfxASurface::CONTENT_COLOR_ALPHA;
+    gfxASurface::gfxImageFormat format
+      = gfxPlatform::GetPlatform()->OptimalFormatForContent(contentType);
+    mBuffer = CreateBufferTextureClient(gfx::ImageFormatToSurfaceFormat(format));
+    MOZ_ASSERT(mBuffer->AsTextureClientSurface());
+    mBuffer->AsTextureClientSurface()->AllocateForSurface(aSize);
+
+    AddTextureClient(mBuffer);
+  }
+
+  if (!mBuffer->Lock(OPEN_READ_WRITE)) {
+    return;
+  }
+
+  nsRefPtr<gfxASurface> surface = mBuffer->AsTextureClientSurface()->GetAsSurface();
+  if (surface) {
+    aLayer->UpdateSurface(surface);
+  }
+
+  mBuffer->Unlock();
+
+  if (surface) {
+    GetForwarder()->UpdatedTexture(this, mBuffer, nullptr);
+    GetForwarder()->UseTexture(this, mBuffer);
+  }
+}
+
+TemporaryRef<BufferTextureClient>
+CanvasClient2D::CreateBufferTextureClient(gfx::SurfaceFormat aFormat)
+{
+  return CompositableClient::CreateBufferTextureClient(aFormat,
+                                                       mTextureInfo.mTextureFlags);
+}
+
+void
+DeprecatedCanvasClient2D::Updated()
 {
   mForwarder->UpdateTexture(this, 1, mDeprecatedTextureClient->GetDescriptor());
 }
 
 
-CanvasClient2D::CanvasClient2D(CompositableForwarder* aFwd,
-                               TextureFlags aFlags)
+DeprecatedCanvasClient2D::DeprecatedCanvasClient2D(CompositableForwarder* aFwd,
+                                                   TextureFlags aFlags)
 : CanvasClient(aFwd, aFlags)
 {
   mTextureInfo.mCompositableType = BUFFER_IMAGE_SINGLE;
 }
 
 void
-CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
+DeprecatedCanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
 {
   if (!mDeprecatedTextureClient) {
     mDeprecatedTextureClient = CreateDeprecatedTextureClient(TEXTURE_CONTENT);
     MOZ_ASSERT(mDeprecatedTextureClient, "Failed to create texture client");
   }
 
   bool isOpaque = (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE);
   gfxASurface::gfxContentType contentType = isOpaque
@@ -62,35 +112,35 @@ CanvasClient2D::Update(gfx::IntSize aSiz
   mDeprecatedTextureClient->EnsureAllocated(aSize, contentType);
 
   gfxASurface* surface = mDeprecatedTextureClient->LockSurface();
   aLayer->UpdateSurface(surface);
   mDeprecatedTextureClient->Unlock();
 }
 
 void
-CanvasClientSurfaceStream::Updated()
+DeprecatedCanvasClientSurfaceStream::Updated()
 {
   if (mNeedsUpdate) {
     mForwarder->UpdateTextureNoSwap(this, 1, mDeprecatedTextureClient->GetDescriptor());
     mNeedsUpdate = false;
   }
 }
 
 
-CanvasClientSurfaceStream::CanvasClientSurfaceStream(CompositableForwarder* aFwd,
-                                                     TextureFlags aFlags)
+DeprecatedCanvasClientSurfaceStream::DeprecatedCanvasClientSurfaceStream(CompositableForwarder* aFwd,
+                                                                         TextureFlags aFlags)
 : CanvasClient(aFwd, aFlags)
 , mNeedsUpdate(false)
 {
   mTextureInfo.mCompositableType = BUFFER_IMAGE_SINGLE;
 }
 
 void
-CanvasClientSurfaceStream::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
+DeprecatedCanvasClientSurfaceStream::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
 {
   if (!mDeprecatedTextureClient) {
     mDeprecatedTextureClient = CreateDeprecatedTextureClient(TEXTURE_STREAM_GL);
     MOZ_ASSERT(mDeprecatedTextureClient, "Failed to create texture client");
   }
 
   NS_ASSERTION(aLayer->mGLContext, "CanvasClientSurfaceStream should only be used with GL canvases");
 
--- a/gfx/layers/client/CanvasClient.h
+++ b/gfx/layers/client/CanvasClient.h
@@ -39,59 +39,103 @@ public:
   {
     mTextureInfo.mTextureFlags = aFlags;
   }
 
   virtual ~CanvasClient() {}
 
   virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) = 0;
 
-  virtual void Updated();
+  virtual void Updated() { }
 
-  virtual void SetDescriptorFromReply(TextureIdentifier aTextureId,
-                                      const SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE
-  {
-    mDeprecatedTextureClient->SetDescriptorFromReply(aDescriptor);
-  }
 protected:
-  RefPtr<DeprecatedTextureClient> mDeprecatedTextureClient;
   TextureInfo mTextureInfo;
 };
 
 // Used for 2D canvases and WebGL canvas on non-GL systems where readback is requried.
 class CanvasClient2D : public CanvasClient
 {
 public:
   CanvasClient2D(CompositableForwarder* aLayerForwarder,
-                 TextureFlags aFlags);
+                 TextureFlags aFlags)
+    : CanvasClient(aLayerForwarder, aFlags)
+  {
+  }
 
-  TextureInfo GetTextureInfo() const MOZ_OVERRIDE
+  TextureInfo GetTextureInfo() const
   {
-    return mTextureInfo;
+    return TextureInfo(COMPOSITABLE_IMAGE);
   }
 
-  virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer);
-};
+  virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) MOZ_OVERRIDE;
+
+  virtual void AddTextureClient(TextureClient* aTexture) MOZ_OVERRIDE
+  {
+    MOZ_ASSERT((mTextureInfo.mTextureFlags & aTexture->GetFlags()) == mTextureInfo.mTextureFlags);
+    CompositableClient::AddTextureClient(aTexture);
+  }
 
-// Used for GL canvases where we don't need to do any readback, i.e., with a
-// GL backend.
-class CanvasClientSurfaceStream : public CanvasClient
+  virtual TemporaryRef<BufferTextureClient>
+  CreateBufferTextureClient(gfx::SurfaceFormat aFormat) MOZ_OVERRIDE;
+
+  virtual void Detach() MOZ_OVERRIDE
+  {
+    mBuffer = nullptr;
+  }
+
+private:
+  RefPtr<TextureClient> mBuffer;
+};
+class DeprecatedCanvasClient2D : public CanvasClient
 {
 public:
-  CanvasClientSurfaceStream(CompositableForwarder* aFwd,
-                            TextureFlags aFlags);
+  DeprecatedCanvasClient2D(CompositableForwarder* aLayerForwarder,
+                           TextureFlags aFlags);
 
   TextureInfo GetTextureInfo() const MOZ_OVERRIDE
   {
     return mTextureInfo;
   }
 
   virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer);
   virtual void Updated() MOZ_OVERRIDE;
 
+  virtual void SetDescriptorFromReply(TextureIdentifier aTextureId,
+                                      const SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE
+  {
+    mDeprecatedTextureClient->SetDescriptorFromReply(aDescriptor);
+  }
+
 private:
+  RefPtr<DeprecatedTextureClient> mDeprecatedTextureClient;
+};
+
+// Used for GL canvases where we don't need to do any readback, i.e., with a
+// GL backend.
+class DeprecatedCanvasClientSurfaceStream : public CanvasClient
+{
+public:
+  DeprecatedCanvasClientSurfaceStream(CompositableForwarder* aFwd,
+                                      TextureFlags aFlags);
+
+  TextureInfo GetTextureInfo() const MOZ_OVERRIDE
+  {
+    return mTextureInfo;
+  }
+
+  virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer);
+  virtual void Updated() MOZ_OVERRIDE;
+
+  virtual void SetDescriptorFromReply(TextureIdentifier aTextureId,
+                                      const SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE
+  {
+    mDeprecatedTextureClient->SetDescriptorFromReply(aDescriptor);
+  }
+
+private:
+  RefPtr<DeprecatedTextureClient> mDeprecatedTextureClient;
   bool mNeedsUpdate;
 };
 
 }
 }
 
 #endif
--- a/gfx/layers/client/ClientCanvasLayer.cpp
+++ b/gfx/layers/client/ClientCanvasLayer.cpp
@@ -76,17 +76,17 @@ ClientCanvasLayer::RenderLayer()
     return;
   }
 
   if (GetMaskLayer()) {
     ToClientLayer(GetMaskLayer())->RenderLayer();
   }
   
   if (!mCanvasClient) {
-    TextureFlags flags = 0;
+    TextureFlags flags = TEXTURE_IMMEDIATE_UPLOAD;
     if (mNeedsYFlip) {
       flags |= NeedsYFlip;
     }
 
     bool isCrossProcess = !(XRE_GetProcessType() == GeckoProcessType_Default);
     //Append TEXTURE_DEALLOCATE_CLIENT flag for streaming buffer under OOPC case
     if (isCrossProcess && mGLContext) {
       GLScreenBuffer* screen = mGLContext->Screen();
@@ -107,16 +107,17 @@ ClientCanvasLayer::RenderLayer()
   
   FirePreTransactionCallback();
   mCanvasClient->Update(gfx::IntSize(mBounds.width, mBounds.height), this);
 
   FireDidTransactionCallback();
 
   ClientManager()->Hold(this);
   mCanvasClient->Updated();
+  mCanvasClient->OnTransaction();
 }
 
 already_AddRefed<CanvasLayer>
 ClientLayerManager::CreateCanvasLayer()
 {
   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
   nsRefPtr<ClientCanvasLayer> layer =
     new ClientCanvasLayer(this);
--- a/gfx/layers/client/ClientCanvasLayer.h
+++ b/gfx/layers/client/ClientCanvasLayer.h
@@ -81,15 +81,16 @@ protected:
     if (mGLContext) {
       return CanvasClient::CanvasClientGLContext;
     }
     return CanvasClient::CanvasClientSurface;
   }
 
   RefPtr<CanvasClient> mCanvasClient;
 
+  friend class DeprecatedCanvasClient2D;
   friend class CanvasClient2D;
-  friend class CanvasClientSurfaceStream;
+  friend class DeprecatedCanvasClientSurfaceStream;
 };
 }
 }
 
 #endif
--- a/gfx/layers/client/ClientImageLayer.cpp
+++ b/gfx/layers/client/ClientImageLayer.cpp
@@ -140,16 +140,19 @@ ClientImageLayer::RenderLayer()
     if (HasShadow() && !mContainer->IsAsync()) {
       mImageClient->Connect();
       ClientManager()->Attach(mImageClient, this);
     }
     if (!mImageClient->UpdateImage(mContainer, GetContentFlags())) {
       return;
     }
   }
+  if (mImageClient) {
+    mImageClient->OnTransaction();
+  }
   ClientManager()->Hold(this);
 }
 
 already_AddRefed<ImageLayer>
 ClientLayerManager::CreateImageLayer()
 {
   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
   nsRefPtr<ClientImageLayer> layer =
--- a/gfx/layers/client/CompositableClient.cpp
+++ b/gfx/layers/client/CompositableClient.cpp
@@ -5,16 +5,17 @@
 
 #include "mozilla/layers/CompositableClient.h"
 #include "mozilla/layers/TextureClient.h"
 #include "mozilla/layers/TextureClientOGL.h"
 #include "mozilla/layers/LayerTransactionChild.h"
 #include "mozilla/layers/CompositableForwarder.h"
 #include "gfxPlatform.h"
 #ifdef XP_WIN
+#include "mozilla/layers/TextureD3D9.h"
 #include "mozilla/layers/TextureD3D11.h"
 #include "gfxWindowsPlatform.h"
 #endif
 
 namespace mozilla {
 namespace layers {
 
 CompositableClient::CompositableClient(CompositableForwarder* aForwarder)
@@ -107,32 +108,45 @@ CompositableClient::CreateDeprecatedText
     break;
   case TEXTURE_STREAM_GL:
     if (parentBackend == LAYERS_OPENGL) {
       result = new DeprecatedTextureClientStreamOGL(GetForwarder(), GetTextureInfo());
     }
     break;
   case TEXTURE_YCBCR:
     if (parentBackend == LAYERS_OPENGL ||
+        parentBackend == LAYERS_D3D9 ||
         parentBackend == LAYERS_D3D11 ||
         parentBackend == LAYERS_BASIC) {
       result = new DeprecatedTextureClientShmemYCbCr(GetForwarder(), GetTextureInfo());
     }
     break;
   case TEXTURE_CONTENT:
 #ifdef XP_WIN
     if (parentBackend == LAYERS_D3D11 && gfxWindowsPlatform::GetPlatform()->GetD2DDevice()) {
       result = new DeprecatedTextureClientD3D11(GetForwarder(), GetTextureInfo());
       break;
     }
+    if (parentBackend == LAYERS_D3D9 &&
+        !GetForwarder()->ForwardsToDifferentProcess()) {
+      result = new DeprecatedTextureClientD3D9(GetForwarder(), GetTextureInfo());
+      break;
+    }
 #endif
      // fall through to TEXTURE_SHMEM
   case TEXTURE_SHMEM:
     result = new DeprecatedTextureClientShmem(GetForwarder(), GetTextureInfo());
     break;
+  case TEXTURE_FALLBACK:
+#ifdef XP_WIN
+    if (parentBackend == LAYERS_D3D9) {
+      result = new DeprecatedTextureClientShmem(GetForwarder(), GetTextureInfo());
+    }
+#endif
+    break;
   default:
     MOZ_ASSERT(false, "Unhandled texture client type");
   }
 
   // If we couldn't create an appropriate texture client,
   // then return nullptr so the caller can chose another
   // type.
   if (!result) {
@@ -142,26 +156,32 @@ CompositableClient::CreateDeprecatedText
   MOZ_ASSERT(result->SupportsType(aDeprecatedTextureClientType),
              "Created the wrong texture client?");
   result->SetFlags(GetTextureInfo().mTextureFlags);
 
   return result.forget();
 }
 
 TemporaryRef<BufferTextureClient>
-CompositableClient::CreateBufferTextureClient(gfx::SurfaceFormat aFormat)
+CompositableClient::CreateBufferTextureClient(gfx::SurfaceFormat aFormat,
+                                              uint32_t aTextureFlags)
 {
   if (gfxPlatform::GetPlatform()->PreferMemoryOverShmem()) {
-    RefPtr<BufferTextureClient> result = new MemoryTextureClient(this, aFormat);
+    RefPtr<BufferTextureClient> result = new MemoryTextureClient(this, aFormat, aTextureFlags);
     return result.forget();
   }
-  RefPtr<BufferTextureClient> result = new ShmemTextureClient(this, aFormat);
+  RefPtr<BufferTextureClient> result = new ShmemTextureClient(this, aFormat, aTextureFlags);
   return result.forget();
 }
 
+TemporaryRef<BufferTextureClient>
+CompositableClient::CreateBufferTextureClient(gfx::SurfaceFormat aFormat)
+{
+  return CreateBufferTextureClient(aFormat, TEXTURE_FLAGS_DEFAULT);
+}
 
 void
 CompositableClient::AddTextureClient(TextureClient* aClient)
 {
   ++mNextTextureID;
   // 0 is always an invalid ID
   if (mNextTextureID == 0) {
     ++mNextTextureID;
--- a/gfx/layers/client/CompositableClient.h
+++ b/gfx/layers/client/CompositableClient.h
@@ -72,16 +72,19 @@ public:
   virtual TextureInfo GetTextureInfo() const = 0;
 
   LayersBackend GetCompositorBackendType() const;
 
   TemporaryRef<DeprecatedTextureClient>
   CreateDeprecatedTextureClient(DeprecatedTextureClientType aDeprecatedTextureClientType);
 
   TemporaryRef<BufferTextureClient>
+  CreateBufferTextureClient(gfx::SurfaceFormat aFormat, TextureFlags aFlags);
+
+  virtual TemporaryRef<BufferTextureClient>
   CreateBufferTextureClient(gfx::SurfaceFormat aFormat);
 
   virtual void SetDescriptorFromReply(TextureIdentifier aTextureId,
                                       const SurfaceDescriptor& aDescriptor)
   {
     MOZ_CRASH("If you want to call this, you should have implemented it");
   }
 
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -21,19 +21,20 @@ using namespace gfx;
 
 namespace layers {
 
 /* static */ TemporaryRef<ContentClient>
 ContentClient::CreateContentClient(CompositableForwarder* aForwarder)
 {
   LayersBackend backend = aForwarder->GetCompositorBackendType();
   if (backend != LAYERS_OPENGL &&
+      backend != LAYERS_D3D9 &&
       backend != LAYERS_D3D11 &&
       backend != LAYERS_BASIC) {
-        return nullptr;
+    return nullptr;
   }
 
   bool useDoubleBuffering = false;
 
 #ifdef XP_WIN
   if (backend == LAYERS_D3D11) {
     useDoubleBuffering = !!gfxWindowsPlatform::GetPlatform()->GetD2DDevice();
   } else
@@ -133,16 +134,35 @@ ContentClientRemoteBuffer::EndPaint()
   if (mDeprecatedTextureClient) {
     mDeprecatedTextureClient->Unlock();
   }
   if (mDeprecatedTextureClientOnWhite) {
     mDeprecatedTextureClientOnWhite->Unlock();
   }
 }
 
+bool
+ContentClientRemoteBuffer::CreateAndAllocateDeprecatedTextureClient(RefPtr<DeprecatedTextureClient>& aClient)
+{
+  aClient = CreateDeprecatedTextureClient(TEXTURE_CONTENT);
+  MOZ_ASSERT(aClient, "Failed to create texture client");
+
+  if (!aClient->EnsureAllocated(mSize, mContentType)) {
+    aClient = CreateDeprecatedTextureClient(TEXTURE_FALLBACK);
+    MOZ_ASSERT(aClient, "Failed to create texture client");
+    if (!aClient->EnsureAllocated(mSize, mContentType)) {
+      NS_WARNING("Could not allocate texture client");
+      return false;
+    }
+  }
+
+  MOZ_ASSERT(IsSurfaceDescriptorValid(*aClient->GetDescriptor()));
+  return true;
+}
+
 void
 ContentClientRemoteBuffer::BuildDeprecatedTextureClients(ContentType aType,
                                                const nsIntRect& aRect,
                                                uint32_t aFlags)
 {
   NS_ABORT_IF_FALSE(!mIsNewBuffer,
                     "Bad! Did we create a buffer twice without painting?");
 
@@ -150,32 +170,30 @@ ContentClientRemoteBuffer::BuildDeprecat
 
   if (mDeprecatedTextureClient) {
     mOldTextures.AppendElement(mDeprecatedTextureClient);
     if (mDeprecatedTextureClientOnWhite) {
       mOldTextures.AppendElement(mDeprecatedTextureClientOnWhite);
     }
     DestroyBuffers();
   }
-  mTextureInfo.mTextureFlags = aFlags | TEXTURE_DEALLOCATE_HOST;
-  mDeprecatedTextureClient = CreateDeprecatedTextureClient(TEXTURE_CONTENT);
-  MOZ_ASSERT(mDeprecatedTextureClient, "Failed to create texture client");
-  if (aFlags & BUFFER_COMPONENT_ALPHA) {
-    mDeprecatedTextureClientOnWhite = CreateDeprecatedTextureClient(TEXTURE_CONTENT);
-    MOZ_ASSERT(mDeprecatedTextureClientOnWhite, "Failed to create texture client");
-    mTextureInfo.mTextureFlags |= ComponentAlpha;
-  }
 
   mContentType = aType;
   mSize = gfx::IntSize(aRect.width, aRect.height);
-  mDeprecatedTextureClient->EnsureAllocated(mSize, mContentType);
-  MOZ_ASSERT(IsSurfaceDescriptorValid(*mDeprecatedTextureClient->GetDescriptor()));
-  if (mDeprecatedTextureClientOnWhite) {
-    mDeprecatedTextureClientOnWhite->EnsureAllocated(mSize, mContentType);
-    MOZ_ASSERT(IsSurfaceDescriptorValid(*mDeprecatedTextureClientOnWhite->GetDescriptor()));
+  mTextureInfo.mTextureFlags = aFlags | TEXTURE_DEALLOCATE_HOST;
+
+  if (!CreateAndAllocateDeprecatedTextureClient(mDeprecatedTextureClient)) {
+    return;
+  }
+  
+  if (aFlags & BUFFER_COMPONENT_ALPHA) {
+    if (!CreateAndAllocateDeprecatedTextureClient(mDeprecatedTextureClientOnWhite)) {
+      return;
+    }
+    mTextureInfo.mTextureFlags |= ComponentAlpha;
   }
 
   CreateFrontBufferAndNotify(aRect);
 }
 
 TemporaryRef<DrawTarget>
 ContentClientRemoteBuffer::CreateDTBuffer(ContentType aType,
                                           const nsIntRect& aRect,
@@ -278,28 +296,28 @@ ContentClientDoubleBuffered::~ContentCli
     mDeprecatedTextureClientOnWhite->SetDescriptor(SurfaceDescriptor());
     mFrontClientOnWhite->SetDescriptor(SurfaceDescriptor());
   }
 }
 
 void
 ContentClientDoubleBuffered::CreateFrontBufferAndNotify(const nsIntRect& aBufferRect)
 {
-  mFrontClient = CreateDeprecatedTextureClient(TEXTURE_CONTENT);
-  MOZ_ASSERT(mFrontClient, "Failed to create texture client");
-  mFrontClient->EnsureAllocated(mSize, mContentType);
+  if (!CreateAndAllocateDeprecatedTextureClient(mFrontClient)) {
+    return;
+  }
+
+  if (mTextureInfo.mTextureFlags & ComponentAlpha) {
+    if (!CreateAndAllocateDeprecatedTextureClient(mFrontClientOnWhite)) {
+      return;
+    }
+  }
 
   mFrontBufferRect = aBufferRect;
   mFrontBufferRotation = nsIntPoint();
-
-  if (mTextureInfo.mTextureFlags & ComponentAlpha) {
-    mFrontClientOnWhite = CreateDeprecatedTextureClient(TEXTURE_CONTENT);
-    MOZ_ASSERT(mFrontClientOnWhite, "Failed to create texture client");
-    mFrontClientOnWhite->EnsureAllocated(mSize, mContentType);
-  }
   
   mForwarder->CreatedDoubleBuffer(this,
                                   *mFrontClient->GetDescriptor(),
                                   *mDeprecatedTextureClient->GetDescriptor(),
                                   mTextureInfo,
                                   mFrontClientOnWhite ? mFrontClientOnWhite->GetDescriptor() : nullptr,
                                   mDeprecatedTextureClientOnWhite ? mDeprecatedTextureClientOnWhite->GetDescriptor() : nullptr);
 }
--- a/gfx/layers/client/ContentClient.h
+++ b/gfx/layers/client/ContentClient.h
@@ -248,16 +248,18 @@ protected:
   // Create the front buffer for the ContentClient/Host pair if necessary
   // and notify the compositor that we have created the buffer(s).
   virtual void CreateFrontBufferAndNotify(const nsIntRect& aBufferRect) = 0;
   virtual void DestroyFrontBuffer() {}
   // We're about to hand off to the compositor, if you've got a back buffer,
   // lock it now.
   virtual void LockFrontBuffer() {}
 
+  bool CreateAndAllocateDeprecatedTextureClient(RefPtr<DeprecatedTextureClient>& aClient);
+
   RefPtr<DeprecatedTextureClient> mDeprecatedTextureClient;
   RefPtr<DeprecatedTextureClient> mDeprecatedTextureClientOnWhite;
   // keep a record of texture clients we have created and need to keep
   // around, then unlock when we are done painting
   nsTArray<RefPtr<DeprecatedTextureClient> > mOldTextures;
 
   TextureInfo mTextureInfo;
   bool mIsNewBuffer;
--- a/gfx/layers/client/ImageClient.cpp
+++ b/gfx/layers/client/ImageClient.cpp
@@ -116,17 +116,17 @@ ImageClientSingle::UpdateImage(ImageCont
       RemoveTextureClient(mFrontBuffer);
       mFrontBuffer = nullptr;
     }
 
     if (!mFrontBuffer) {
       mFrontBuffer = CreateBufferTextureClient(gfx::FORMAT_YUV);
       gfx::IntSize ySize(data->mYSize.width, data->mYSize.height);
       gfx::IntSize cbCrSize(data->mCbCrSize.width, data->mCbCrSize.height);
-      if (!mFrontBuffer->AsTextureClientYCbCr()->AllocateForYCbCr(ySize, cbCrSize)) {
+      if (!mFrontBuffer->AsTextureClientYCbCr()->AllocateForYCbCr(ySize, cbCrSize, data->mStereoMode)) {
         mFrontBuffer = nullptr;
         return false;
       }
       AddTextureClient(mFrontBuffer);
     }
 
     if (!mFrontBuffer->Lock(OPEN_READ_WRITE)) {
       return false;
@@ -141,26 +141,28 @@ ImageClientSingle::UpdateImage(ImageCont
       MOZ_ASSERT(false);
       return false;
     }
 
   } else {
     nsRefPtr<gfxASurface> surface = image->GetAsSurface();
     MOZ_ASSERT(surface);
 
-    if (mFrontBuffer && mFrontBuffer->IsImmutable()) {
+    gfx::IntSize size = gfx::IntSize(image->GetSize().width, image->GetSize().height);
+
+    if (mFrontBuffer &&
+        (mFrontBuffer->IsImmutable() || mFrontBuffer->GetSize() != size)) {
       RemoveTextureClient(mFrontBuffer);
       mFrontBuffer = nullptr;
     }
 
     if (!mFrontBuffer) {
       gfxASurface::gfxImageFormat format
         = gfxPlatform::GetPlatform()->OptimalFormatForContent(surface->GetContentType());
       mFrontBuffer = CreateBufferTextureClient(gfx::ImageFormatToSurfaceFormat(format));
-      gfx::IntSize size = gfx::IntSize(image->GetSize().width, image->GetSize().height);
       MOZ_ASSERT(mFrontBuffer->AsTextureClientSurface());
       mFrontBuffer->AsTextureClientSurface()->AllocateForSurface(size);
 
       AddTextureClient(mFrontBuffer);
     }
 
     if (!mFrontBuffer->Lock(OPEN_READ_WRITE)) {
       return false;
@@ -190,20 +192,26 @@ ImageClientBuffered::UpdateImage(ImageCo
   mFrontBuffer = mBackBuffer;
   mBackBuffer = temp;
   return ImageClientSingle::UpdateImage(aContainer, aContentFlags);
 }
 
 void
 ImageClientSingle::AddTextureClient(TextureClient* aTexture)
 {
-  aTexture->AddFlags(mTextureFlags);
+  MOZ_ASSERT((mTextureFlags & aTexture->GetFlags()) == mTextureFlags);
   CompositableClient::AddTextureClient(aTexture);
 }
 
+TemporaryRef<BufferTextureClient>
+ImageClientSingle::CreateBufferTextureClient(gfx::SurfaceFormat aFormat)
+{
+  return CompositableClient::CreateBufferTextureClient(aFormat, mTextureFlags);
+}
+
 void
 ImageClientSingle::Detach()
 {
   mFrontBuffer = nullptr;
 }
 
 void
 ImageClientBuffered::Detach()
--- a/gfx/layers/client/ImageClient.h
+++ b/gfx/layers/client/ImageClient.h
@@ -72,16 +72,19 @@ public:
                     CompositableType aType);
 
   virtual bool UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags);
 
   virtual void Detach() MOZ_OVERRIDE;
 
   virtual void AddTextureClient(TextureClient* aTexture) MOZ_OVERRIDE;
 
+  virtual TemporaryRef<BufferTextureClient>
+  CreateBufferTextureClient(gfx::SurfaceFormat aFormat) MOZ_OVERRIDE;
+
   virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE;
 protected:
   RefPtr<TextureClient> mFrontBuffer;
   // Some layers may want to enforce some flags to all their textures
   // (like disallowing tiling)
   TextureFlags mTextureFlags;
 };
 
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -83,18 +83,19 @@ ShmemTextureClient::GetBuffer() const
 
 size_t
 ShmemTextureClient::GetBufferSize() const
 {
   return mShmem.Size<uint8_t>();
 }
 
 ShmemTextureClient::ShmemTextureClient(CompositableClient* aCompositable,
-                                       gfx::SurfaceFormat aFormat)
-  : BufferTextureClient(aCompositable, aFormat)
+                                       gfx::SurfaceFormat aFormat,
+                                       TextureFlags aFlags)
+  : BufferTextureClient(aCompositable, aFormat, aFlags)
   , mAllocated(false)
 {
   MOZ_COUNT_CTOR(ShmemTextureClient);
 }
 
 ShmemTextureClient::~ShmemTextureClient()
 {
   MOZ_COUNT_DTOR(ShmemTextureClient);
@@ -120,18 +121,20 @@ bool
 MemoryTextureClient::Allocate(uint32_t aSize)
 {
   MOZ_ASSERT(!mBuffer);
   mBuffer = new uint8_t[aSize];
   mBufSize = aSize;
   return true;
 }
 
-MemoryTextureClient::MemoryTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat)
-  : BufferTextureClient(aCompositable, aFormat)
+MemoryTextureClient::MemoryTextureClient(CompositableClient* aCompositable,
+                                         gfx::SurfaceFormat aFormat,
+                                         TextureFlags aFlags)
+  : BufferTextureClient(aCompositable, aFormat, aFlags)
   , mBuffer(nullptr)
   , mBufSize(0)
 {
   MOZ_COUNT_CTOR(MemoryTextureClient);
 }
 
 MemoryTextureClient::~MemoryTextureClient()
 {
@@ -139,18 +142,19 @@ MemoryTextureClient::~MemoryTextureClien
   if (ShouldDeallocateInDestructor()) {
     // if the buffer has never been shared we must deallocate it or ir would
     // leak.
     delete mBuffer;
   }
 }
 
 BufferTextureClient::BufferTextureClient(CompositableClient* aCompositable,
-                                         gfx::SurfaceFormat aFormat)
-  : TextureClient()
+                                         gfx::SurfaceFormat aFormat,
+                                         TextureFlags aFlags)
+  : TextureClient(aFlags)
   , mCompositable(aCompositable)
   , mFormat(aFormat)
 {}
 
 BufferTextureClient::~BufferTextureClient()
 {}
 
 bool
@@ -167,31 +171,51 @@ BufferTextureClient::UpdateSurface(gfxAS
   if (!surf) {
     return false;
   }
 
   nsRefPtr<gfxContext> tmpCtx = new gfxContext(surf.get());
   tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
   tmpCtx->DrawSurface(aSurface, gfxSize(serializer.GetSize().width,
                                         serializer.GetSize().height));
+
+  if (TextureRequiresLocking(mFlags)) {
+    // We don't have support for proper locking yet, so we'll
+    // have to be immutable instead.
+    MarkImmutable();
+  }
   return true;
 }
 
+already_AddRefed<gfxASurface>
+BufferTextureClient::GetAsSurface()
+{
+  ImageDataSerializer serializer(GetBuffer());
+  if (!serializer.IsValid()) {
+    return nullptr;
+  }
+
+  RefPtr<gfxImageSurface> surf = serializer.GetAsThebesSurface();
+  nsRefPtr<gfxASurface> result = surf.get();
+  return result.forget();
+}
+
 bool
 BufferTextureClient::AllocateForSurface(gfx::IntSize aSize)
 {
   MOZ_ASSERT(mFormat != gfx::FORMAT_YUV, "This textureClient cannot use YCbCr data");
 
   int bufSize
     = ImageDataSerializer::ComputeMinBufferSize(aSize, mFormat);
   if (!Allocate(bufSize)) {
     return false;
   }
   ImageDataSerializer serializer(GetBuffer());
   serializer.InitializeBufferInfo(aSize, mFormat);
+  mSize = aSize;
   return true;
 }
 
 bool
 BufferTextureClient::UpdateYCbCr(const PlanarYCbCrImage::Data& aData)
 {
   MOZ_ASSERT(mFormat == gfx::FORMAT_YUV, "This textureClient can only use YCbCr data");
   MOZ_ASSERT(!IsImmutable());
@@ -201,30 +225,40 @@ BufferTextureClient::UpdateYCbCr(const P
   MOZ_ASSERT(serializer.IsValid());
   if (!serializer.CopyData(aData.mYChannel, aData.mCbChannel, aData.mCrChannel,
                            aData.mYSize, aData.mYStride,
                            aData.mCbCrSize, aData.mCbCrStride,
                            aData.mYSkip, aData.mCbSkip)) {
     NS_WARNING("Failed to copy image data!");
     return false;
   }
+
+  if (TextureRequiresLocking(mFlags)) {
+    // We don't have support for proper locking yet, so we'll
+    // have to be immutable instead.
+    MarkImmutable();
+  }
   return true;
 }
 
 bool
-BufferTextureClient::AllocateForYCbCr(gfx::IntSize aYSize, gfx::IntSize aCbCrSize)
+BufferTextureClient::AllocateForYCbCr(gfx::IntSize aYSize,
+                                      gfx::IntSize aCbCrSize,
+                                      StereoMode aStereoMode)
 {
   size_t bufSize = YCbCrImageDataSerializer::ComputeMinBufferSize(aYSize,
                                                                   aCbCrSize);
   if (!Allocate(bufSize)) {
     return false;
   }
   YCbCrImageDataSerializer serializer(GetBuffer());
   serializer.InitializeBufferInfo(aYSize,
-                                  aCbCrSize);
+                                  aCbCrSize,
+                                  aStereoMode);
+  mSize = aYSize;
   return true;
 }
 
 
 
 
 
 
@@ -268,33 +302,34 @@ DeprecatedTextureClientShmem::ReleaseRes
   }
 
   if (IsSurfaceDescriptorValid(mDescriptor)) {
     mForwarder->DestroySharedSurface(&mDescriptor);
     mDescriptor = SurfaceDescriptor();
   }
 }
 
-void
+bool
 DeprecatedTextureClientShmem::EnsureAllocated(gfx::IntSize aSize,
                                     gfxASurface::gfxContentType aContentType)
 {
   if (aSize != mSize ||
       aContentType != mContentType ||
       !IsSurfaceDescriptorValid(mDescriptor)) {
     ReleaseResources();
 
     mContentType = aContentType;
     mSize = aSize;
 
     if (!mForwarder->AllocSurfaceDescriptor(gfxIntSize(mSize.width, mSize.height),
                                             mContentType, &mDescriptor)) {
       NS_WARNING("creating SurfaceDescriptor failed!");
     }
   }
+  return true;
 }
 
 void
 DeprecatedTextureClientShmem::SetDescriptor(const SurfaceDescriptor& aDescriptor)
 {
   if (IsSurfaceDescriptorValid(aDescriptor)) {
     ReleaseResources();
     mDescriptor = aDescriptor;
@@ -396,43 +431,45 @@ DeprecatedTextureClientShmemYCbCr::SetDe
   if (shYCbCr) {
     shYCbCr->Release();
     mDescriptor = SurfaceDescriptor();
   } else {
     SetDescriptor(aDescriptor);
   }
 }
 
-void
+bool
 DeprecatedTextureClientShmemYCbCr::EnsureAllocated(gfx::IntSize aSize,
                                          gfxASurface::gfxContentType aType)
 {
   NS_RUNTIMEABORT("not enough arguments to do this (need both Y and CbCr sizes)");
+  return false;
 }
 
 
 DeprecatedTextureClientTile::DeprecatedTextureClientTile(CompositableForwarder* aForwarder,
                                      const TextureInfo& aTextureInfo)
   : DeprecatedTextureClient(aForwarder, aTextureInfo)
   , mSurface(nullptr)
 {
   mTextureInfo.mDeprecatedTextureHostFlags = TEXTURE_HOST_TILED;
 }
 
-void
+bool
 DeprecatedTextureClientTile::EnsureAllocated(gfx::IntSize aSize, gfxASurface::gfxContentType aType)
 {
   if (!mSurface ||
       mSurface->Format() != gfxPlatform::GetPlatform()->OptimalFormatForContent(aType)) {
     gfxImageSurface* tmpTile = new gfxImageSurface(gfxIntSize(aSize.width, aSize.height),
                                                    gfxPlatform::GetPlatform()->OptimalFormatForContent(aType),
                                                    aType != gfxASurface::CONTENT_COLOR);
     mSurface = new gfxReusableSurfaceWrapper(tmpTile);
     mContentType = aType;
   }
+  return true;
 }
 
 gfxImageSurface*
 DeprecatedTextureClientTile::LockImageSurface()
 {
   // Use the gfxReusableSurfaceWrapper, which will reuse the surface
   // if the compositor no longer has a read lock, otherwise the surface
   // will be copied into a new writable surface.
@@ -544,17 +581,18 @@ bool AutoLockYCbCrClient::EnsureDeprecat
                                                                data->mCbCrSize);
   ipc::Shmem shmem;
   if (!mDeprecatedTextureClient->GetForwarder()->AllocUnsafeShmem(size, shmType, &shmem)) {
     return false;
   }
 
   YCbCrImageDataSerializer serializer(shmem.get<uint8_t>());
   serializer.InitializeBufferInfo(data->mYSize,
-                                  data->mCbCrSize);
+                                  data->mCbCrSize,
+                                  data->mStereoMode);
 
   *mDescriptor = YCbCrImage(shmem, 0);
 
   return true;
 }
 
 
 }
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -39,27 +39,30 @@ class CompositableClient;
 
 /**
  * Interface for TextureClients that can be updated using a gfxASurface.
  */
 class TextureClientSurface
 {
 public:
   virtual bool UpdateSurface(gfxASurface* aSurface) = 0;
+  virtual already_AddRefed<gfxASurface> GetAsSurface() = 0;
   virtual bool AllocateForSurface(gfx::IntSize aSize) = 0;
 };
 
 /**
  * Interface for TextureClients that can be updated using YCbCr data.
  */
 class TextureClientYCbCr
 {
 public:
   virtual bool UpdateYCbCr(const PlanarYCbCrImage::Data& aData) = 0;
-  virtual bool AllocateForYCbCr(gfx::IntSize aYSize, gfx::IntSize aCbCrSize) = 0;
+  virtual bool AllocateForYCbCr(gfx::IntSize aYSize,
+                                gfx::IntSize aCbCrSize,
+                                StereoMode aStereoMode) = 0;
 };
 
 
 /**
  * TextureClient is a thin abstraction over texture data that need to be shared
  * between the content process and the compositor process. It is the
  * content-side half of a TextureClient/TextureHost pair. A corresponding
  * TextureHost lives on the compositor-side.
@@ -119,116 +122,115 @@ public:
   {
     return mNextSibling;
   }
 
   virtual bool IsAllocated() const = 0;
 
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) = 0;
 
-  void SetFlags(TextureFlags aFlags)
-  {
-    MOZ_ASSERT(!IsSharedWithCompositor());
-    mFlags = aFlags;
-  }
-
-  void AddFlags(TextureFlags  aFlags)
-  {
-    MOZ_ASSERT(!IsSharedWithCompositor());
-    // make sure we don't deallocate on both client and host;
-    MOZ_ASSERT(!(aFlags & TEXTURE_DEALLOCATE_CLIENT && aFlags & TEXTURE_DEALLOCATE_HOST));
-    if (aFlags & TEXTURE_DEALLOCATE_CLIENT) {
-      mFlags &= ~TEXTURE_DEALLOCATE_HOST;
-    } else if (aFlags & TEXTURE_DEALLOCATE_HOST) {
-      mFlags &= ~TEXTURE_DEALLOCATE_CLIENT;
-    }
-    mFlags |= aFlags;
-  }
-
-  void RemoveFlags(TextureFlags  aFlags)
-  {
-    MOZ_ASSERT(!IsSharedWithCompositor());
-    mFlags &= (~aFlags);
-  }
+  virtual gfx::IntSize GetSize() const = 0;
 
   TextureFlags GetFlags() const { return mFlags; }
 
   /**
    * After being shared ith the compositor side, an immutable texture is never
    * modified, it can only be read. It is safe to not Lock/Unlock immutable
    * textures.
    */
   bool IsImmutable() const { return mFlags & TEXTURE_IMMUTABLE; }
 
   void MarkImmutable() { AddFlags(TEXTURE_IMMUTABLE); }
 
   bool IsSharedWithCompositor() const { return GetID() != 0; }
 
   bool ShouldDeallocateInDestructor() const;
 protected:
+  void AddFlags(TextureFlags  aFlags)
+  {
+    MOZ_ASSERT(!IsSharedWithCompositor());
+    // make sure we don't deallocate on both client and host;
+    MOZ_ASSERT(!(aFlags & TEXTURE_DEALLOCATE_CLIENT && aFlags & TEXTURE_DEALLOCATE_HOST));
+    if (aFlags & TEXTURE_DEALLOCATE_CLIENT) {
+      mFlags &= ~TEXTURE_DEALLOCATE_HOST;
+    } else if (aFlags & TEXTURE_DEALLOCATE_HOST) {
+      mFlags &= ~TEXTURE_DEALLOCATE_CLIENT;
+    }
+    mFlags |= aFlags;
+  }
+
   uint64_t mID;
   RefPtr<TextureClient> mNextSibling;
   TextureFlags mFlags;
 };
 
 /**
  * TextureClient that wraps a random access buffer such as a Shmem or raw memory.
  * This class must be inherited to implement the memory allocation and access bits.
  * (see ShmemTextureClient and MemoryTextureClient)
  */
 class BufferTextureClient : public TextureClient
                           , public TextureClientSurface
                           , TextureClientYCbCr
 {
 public:
-  BufferTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat);
+  BufferTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat,
+                      TextureFlags aFlags);
 
   virtual ~BufferTextureClient();
 
   virtual bool IsAllocated() const = 0;
 
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) = 0;
 
   virtual bool Allocate(uint32_t aSize) = 0;
 
   virtual uint8_t* GetBuffer() const = 0;
 
   virtual size_t GetBufferSize() const = 0;
 
+  virtual gfx::IntSize GetSize() const { return mSize; }
+
   // TextureClientSurface
 
   virtual TextureClientSurface* AsTextureClientSurface() MOZ_OVERRIDE { return this; }
 
   virtual bool UpdateSurface(gfxASurface* aSurface) MOZ_OVERRIDE;
 
+  virtual already_AddRefed<gfxASurface> GetAsSurface() MOZ_OVERRIDE;
+
   virtual bool AllocateForSurface(gfx::IntSize aSize) MOZ_OVERRIDE;
 
   // TextureClientYCbCr
 
   virtual TextureClientYCbCr* AsTextureClientYCbCr() MOZ_OVERRIDE { return this; }
 
   virtual bool UpdateYCbCr(const PlanarYCbCrImage::Data& aData) MOZ_OVERRIDE;
 
-  virtual bool AllocateForYCbCr(gfx::IntSize aYSize, gfx::IntSize aCbCrSize) MOZ_OVERRIDE;
+  virtual bool AllocateForYCbCr(gfx::IntSize aYSize,
+                                gfx::IntSize aCbCrSize,
+                                StereoMode aStereoMode) MOZ_OVERRIDE;
 
   gfx::SurfaceFormat GetFormat() const { return mFormat; }
 
 protected:
   CompositableClient* mCompositable;
   gfx::SurfaceFormat mFormat;
+  gfx::IntSize mSize;
 };
 
 /**
  * TextureClient that wraps shared memory.
  * the corresponding texture on the host side is ShmemTextureHost.
  */
 class ShmemTextureClient : public BufferTextureClient
 {
 public:
-  ShmemTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat);
+  ShmemTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat,
+                     TextureFlags aFlags);
 
   ~ShmemTextureClient();
 
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE;
 
   virtual bool Allocate(uint32_t aSize) MOZ_OVERRIDE;
 
   virtual uint8_t* GetBuffer() const MOZ_OVERRIDE;
@@ -250,17 +252,18 @@ protected:
 /**
  * TextureClient that wraps raw memory.
  * The corresponding texture on the host side is MemoryTextureHost.
  * Can obviously not be used in a cross process setup.
  */
 class MemoryTextureClient : public BufferTextureClient
 {
 public:
-  MemoryTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat);
+  MemoryTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat,
+                      TextureFlags aFlags);
 
   ~MemoryTextureClient();
 
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE;
 
   virtual bool Allocate(uint32_t aSize) MOZ_OVERRIDE;
 
   virtual uint8_t* GetBuffer() const MOZ_OVERRIDE { return mBuffer; }
@@ -350,18 +353,19 @@ public:
    * This unlocks the current DrawableTexture and allows the host to composite
    * it directly.
    */
   virtual void Unlock() {}
 
   /**
    * Ensure that the texture client is suitable for the given size and content
    * type and that any initialisation has taken place.
+   * Returns true if succeeded, false if failed.
    */
-  virtual void EnsureAllocated(gfx::IntSize aSize,
+  virtual bool EnsureAllocated(gfx::IntSize aSize,
                                gfxASurface::gfxContentType aType) = 0;
 
   /**
    * _Only_ used at the end of the layer transaction when receiving a reply from
    *  the compositor.
    */
   virtual void SetDescriptorFromReply(const SurfaceDescriptor& aDescriptor)
   {
@@ -418,23 +422,23 @@ protected:
 class DeprecatedTextureClientShmem : public DeprecatedTextureClient
 {
 public:
   DeprecatedTextureClientShmem(CompositableForwarder* aForwarder, const TextureInfo& aTextureInfo);
   ~DeprecatedTextureClientShmem() { ReleaseResources(); }
 
   virtual bool SupportsType(DeprecatedTextureClientType aType) MOZ_OVERRIDE
   {
-    return aType == TEXTURE_SHMEM || aType == TEXTURE_CONTENT;
+    return aType == TEXTURE_SHMEM || aType == TEXTURE_CONTENT || aType == TEXTURE_FALLBACK;
   }
   virtual gfxImageSurface* LockImageSurface() MOZ_OVERRIDE;
   virtual gfxASurface* LockSurface() MOZ_OVERRIDE { return GetSurface(); }
   virtual gfx::DrawTarget* LockDrawTarget();
   virtual void Unlock() MOZ_OVERRIDE;
-  virtual void EnsureAllocated(gfx::IntSize aSize, gfxASurface::gfxContentType aType) MOZ_OVERRIDE;
+  virtual bool EnsureAllocated(gfx::IntSize aSize, gfxASurface::gfxContentType aType) MOZ_OVERRIDE;
 
   virtual void ReleaseResources() MOZ_OVERRIDE;
   virtual void SetDescriptor(const SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE;
   virtual gfxASurface::gfxContentType GetContentType() MOZ_OVERRIDE { return mContentType; }
 private:
   gfxASurface* GetSurface();
 
   nsRefPtr<gfxASurface> mSurface;
@@ -452,32 +456,32 @@ class DeprecatedTextureClientShmemYCbCr 
 {
 public:
   DeprecatedTextureClientShmemYCbCr(CompositableForwarder* aForwarder, const TextureInfo& aTextureInfo)
     : DeprecatedTextureClient(aForwarder, aTextureInfo)
   { }
   ~DeprecatedTextureClientShmemYCbCr() { ReleaseResources(); }
 
   virtual bool SupportsType(DeprecatedTextureClientType aType) MOZ_OVERRIDE { return aType == TEXTURE_YCBCR; }
-  void EnsureAllocated(gfx::IntSize aSize, gfxASurface::gfxContentType aType) MOZ_OVERRIDE;
+  bool EnsureAllocated(gfx::IntSize aSize, gfxASurface::gfxContentType aType) MOZ_OVERRIDE;
   virtual void SetDescriptorFromReply(const SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE;
   virtual void SetDescriptor(const SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE;
   virtual void ReleaseResources();
   virtual gfxASurface::gfxContentType GetContentType() MOZ_OVERRIDE { return gfxASurface::CONTENT_COLOR_ALPHA; }
 };
 
 class DeprecatedTextureClientTile : public DeprecatedTextureClient
 {
 public:
   DeprecatedTextureClientTile(const DeprecatedTextureClientTile& aOther);
   DeprecatedTextureClientTile(CompositableForwarder* aForwarder,
                     const TextureInfo& aTextureInfo);
   ~DeprecatedTextureClientTile();
 
-  virtual void EnsureAllocated(gfx::IntSize aSize,
+  virtual bool EnsureAllocated(gfx::IntSize aSize,
                                gfxASurface::gfxContentType aType) MOZ_OVERRIDE;
 
   virtual gfxImageSurface* LockImageSurface() MOZ_OVERRIDE;
 
   gfxReusableSurfaceWrapper* GetReusableSurfaceWrapper()
   {
     return mSurface;
   }
--- a/gfx/layers/composite/CanvasLayerComposite.cpp
+++ b/gfx/layers/composite/CanvasLayerComposite.cpp
@@ -28,40 +28,41 @@ CanvasLayerComposite::CanvasLayerComposi
 
 CanvasLayerComposite::~CanvasLayerComposite()
 {
   MOZ_COUNT_DTOR(CanvasLayerComposite);
 
   CleanupResources();
 }
 
-void CanvasLayerComposite::SetCompositableHost(CompositableHost* aHost) {
+void
+CanvasLayerComposite::SetCompositableHost(CompositableHost* aHost) {
   mImageHost = aHost;
 }
 
 Layer*
 CanvasLayerComposite::GetLayer()
 {
   return this;
 }
 
 LayerRenderState
 CanvasLayerComposite::GetRenderState()
 {
-  if (mDestroyed || !mImageHost) {
+  if (mDestroyed || !mImageHost || !mImageHost->IsAttached()) {
     return LayerRenderState();
   }
   return mImageHost->GetRenderState();
 }
 
 void
 CanvasLayerComposite::RenderLayer(const nsIntPoint& aOffset,
                                   const nsIntRect& aClipRect)
 {
-  if (!mImageHost) {
+  if (!mImageHost || !mImageHost->IsAttached()) {
     return;
   }
 
   mCompositor->MakeCurrent();
 
 #ifdef MOZ_DUMP_PAINTING
   if (gfxUtils::sDumpPainting) {
     nsRefPtr<gfxImageSurface> surf = mImageHost->GetAsSurface();
@@ -93,18 +94,23 @@ CanvasLayerComposite::RenderLayer(const 
                         gfx::Point(aOffset.x, aOffset.y),
                         gfx::ToFilter(filter),
                         clipRect);
 
   LayerManagerComposite::RemoveMaskEffect(mMaskLayer);
 }
 
 CompositableHost*
-CanvasLayerComposite::GetCompositableHost() {
-  return mImageHost.get();
+CanvasLayerComposite::GetCompositableHost()
+{
+  if (mImageHost->IsAttached()) {
+    return mImageHost.get();
+  }
+
+  return nullptr;
 }
 
 void
 CanvasLayerComposite::CleanupResources()
 {
   if (mImageHost) {
     mImageHost->Detach();
   }
@@ -112,17 +118,17 @@ CanvasLayerComposite::CleanupResources()
 }
 
 #ifdef MOZ_LAYERS_HAVE_LOG
 nsACString&
 CanvasLayerComposite::PrintInfo(nsACString& aTo, const char* aPrefix)
 {
   CanvasLayer::PrintInfo(aTo, aPrefix);
   aTo += "\n";
-  if (mImageHost) {
+  if (mImageHost && mImageHost->IsAttached()) {
     nsAutoCString pfx(aPrefix);
     pfx += "  ";
     mImageHost->PrintInfo(aTo, pfx.get());
   }
   return aTo;
 }
 #endif
 
--- a/gfx/layers/composite/CompositableHost.cpp
+++ b/gfx/layers/composite/CompositableHost.cpp
@@ -13,16 +13,17 @@
 
 namespace mozilla {
 namespace layers {
 
 CompositableHost::CompositableHost(const TextureInfo& aTextureInfo)
   : mTextureInfo(aTextureInfo)
   , mCompositor(nullptr)
   , mLayer(nullptr)
+  , mAttached(false)
 {
   MOZ_COUNT_CTOR(CompositableHost);
 }
 
 CompositableHost::~CompositableHost()
 {
   MOZ_COUNT_DTOR(CompositableHost);
 
--- a/gfx/layers/composite/CompositableHost.h
+++ b/gfx/layers/composite/CompositableHost.h
@@ -182,23 +182,28 @@ public:
   Layer* GetLayer() const { return mLayer; }
   void SetLayer(Layer* aLayer) { mLayer = aLayer; }
 
   virtual TiledLayerComposer* AsTiledLayerComposer() { return nullptr; }
 
   virtual void Attach(Layer* aLayer, Compositor* aCompositor)
   {
     MOZ_ASSERT(aCompositor, "Compositor is required");
+    MOZ_ASSERT(!IsAttached());
     SetCompositor(aCompositor);
     SetLayer(aLayer);
+    mAttached = true;
   }
-  void Detach() {
+  void Detach()
+  {
     SetLayer(nullptr);
     SetCompositor(nullptr);
+    mAttached = false;
   }
+  bool IsAttached() { return mAttached; }
 
   virtual void Dump(FILE* aFile=nullptr,
                     const char* aPrefix="",
                     bool aDumpHtml=false) { }
   static void DumpDeprecatedTextureHost(FILE* aFile, DeprecatedTextureHost* aTexture);
   static void DumpTextureHost(FILE* aFile, TextureHost* aTexture);
 
 #ifdef MOZ_DUMP_PAINTING
@@ -214,16 +219,17 @@ public:
   void RemoveTextureHost(uint64_t aTextureID);
   TextureHost* GetTextureHost(uint64_t aTextureID);
 
 protected:
   TextureInfo mTextureInfo;
   Compositor* mCompositor;
   Layer* mLayer;
   RefPtr<TextureHost> mFirstTexture;
+  bool mAttached;
 };
 
 class CompositableParentManager;
 
 class CompositableParent : public PCompositableParent
 {
 public:
   CompositableParent(CompositableParentManager* aMgr,
--- a/gfx/layers/composite/ImageLayerComposite.cpp
+++ b/gfx/layers/composite/ImageLayerComposite.cpp
@@ -49,33 +49,33 @@ void
 ImageLayerComposite::Disconnect()
 {
   Destroy();
 }
 
 LayerRenderState
 ImageLayerComposite::GetRenderState()
 {
-  if (mImageHost) {
+  if (mImageHost && mImageHost->IsAttached()) {
     return mImageHost->GetRenderState();
   }
   return LayerRenderState();
 }
 
 Layer*
 ImageLayerComposite::GetLayer()
 {
   return this;
 }
 
 void
 ImageLayerComposite::RenderLayer(const nsIntPoint& aOffset,
                                  const nsIntRect& aClipRect)
 {
-  if (!mImageHost) {
+  if (!mImageHost || !mImageHost->IsAttached()) {
     return;
   }
 
 #ifdef MOZ_DUMP_PAINTING
   if (gfxUtils::sDumpPainting) {
     nsRefPtr<gfxImageSurface> surf = mImageHost->GetAsSurface();
     WriteSnapshotToDumpFile(this, surf);
   }
@@ -103,17 +103,18 @@ ImageLayerComposite::RenderLayer(const n
 void 
 ImageLayerComposite::ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
 {
   gfx3DMatrix local = GetLocalTransform();
 
   // Snap image edges to pixel boundaries
   gfxRect sourceRect(0, 0, 0, 0);
   if (mImageHost &&
-    (mImageHost->GetDeprecatedTextureHost() || mImageHost->GetTextureHost())) {
+      mImageHost->IsAttached() &&
+      (mImageHost->GetDeprecatedTextureHost() || mImageHost->GetTextureHost())) {
     IntSize size =
       mImageHost->GetTextureHost() ? mImageHost->GetTextureHost()->GetSize()
                                    : mImageHost->GetDeprecatedTextureHost()->GetSize();
     sourceRect.SizeTo(size.width, size.height);
     if (mScaleMode != SCALE_NONE &&
         sourceRect.width != 0.0 && sourceRect.height != 0.0) {
       NS_ASSERTION(mScaleMode == SCALE_STRETCH,
                    "No other scalemodes than stretch and none supported yet.");
@@ -127,18 +128,22 @@ ImageLayerComposite::ComputeEffectiveTra
   // transform, then we'd snap again when compositing the ThebesLayer).
   mEffectiveTransform =
       SnapTransform(local, sourceRect, nullptr) *
       SnapTransformTranslation(aTransformToSurface, nullptr);
   ComputeEffectiveTransformForMaskLayer(aTransformToSurface);
 }
 
 CompositableHost*
-ImageLayerComposite::GetCompositableHost() {
-  return mImageHost.get();
+ImageLayerComposite::GetCompositableHost()
+{
+  if (mImageHost->IsAttached())
+    return mImageHost.get();
+
+  return nullptr;
 }
 
 void
 ImageLayerComposite::CleanupResources()
 {
   if (mImageHost) {
     mImageHost->Detach();
   }
@@ -146,17 +151,17 @@ ImageLayerComposite::CleanupResources()
 }
 
 #ifdef MOZ_LAYERS_HAVE_LOG
 nsACString&
 ImageLayerComposite::PrintInfo(nsACString& aTo, const char* aPrefix)
 {
   ImageLayer::PrintInfo(aTo, aPrefix);
   aTo += "\n";
-  if (mImageHost) {
+  if (mImageHost && mImageHost->IsAttached()) {
     nsAutoCString pfx(aPrefix);
     pfx += "  ";
     mImageHost->PrintInfo(aTo, pfx.get());
   }
   return aTo;
 }
 #endif
 
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -81,16 +81,17 @@ LayerManagerComposite::ClearCachedResour
 }
 
 /**
  * LayerManagerComposite
  */
 LayerManagerComposite::LayerManagerComposite(Compositor* aCompositor)
 : mCompositor(aCompositor)
 {
+  MOZ_ASSERT(aCompositor);
 }
 
 LayerManagerComposite::~LayerManagerComposite()
 {
   Destroy();
 }
 
 
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -22,45 +22,41 @@ namespace layers {
 TemporaryRef<DeprecatedTextureHost> CreateDeprecatedTextureHostOGL(SurfaceDescriptorType aDescriptorType,
                                                            uint32_t aDeprecatedTextureHostFlags,
                                                            uint32_t aTextureFlags);
 // implemented in BasicCompositor.cpp
 TemporaryRef<DeprecatedTextureHost> CreateBasicDeprecatedTextureHost(SurfaceDescriptorType aDescriptorType,
                                                              uint32_t aDeprecatedTextureHostFlags,
                                                              uint32_t aTextureFlags);
 
+#ifdef XP_WIN
 TemporaryRef<DeprecatedTextureHost> CreateDeprecatedTextureHostD3D9(SurfaceDescriptorType aDescriptorType,
                                                             uint32_t aDeprecatedTextureHostFlags,
-                                                            uint32_t aTextureFlags)
-{
-  NS_RUNTIMEABORT("not implemented");
-  return nullptr;
-}
+                                                            uint32_t aTextureFlags);
 
-#ifdef XP_WIN
 TemporaryRef<DeprecatedTextureHost> CreateDeprecatedTextureHostD3D11(SurfaceDescriptorType aDescriptorType,
                                                              uint32_t aDeprecatedTextureHostFlags,
                                                              uint32_t aTextureFlags);
 #endif
 
 /* static */ TemporaryRef<DeprecatedTextureHost>
 DeprecatedTextureHost::CreateDeprecatedTextureHost(SurfaceDescriptorType aDescriptorType,
                                            uint32_t aDeprecatedTextureHostFlags,
                                            uint32_t aTextureFlags)
 {
   switch (Compositor::GetBackend()) {
     case LAYERS_OPENGL:
       return CreateDeprecatedTextureHostOGL(aDescriptorType,
                                         aDeprecatedTextureHostFlags,
                                         aTextureFlags);
+#ifdef XP_WIN
     case LAYERS_D3D9:
       return CreateDeprecatedTextureHostD3D9(aDescriptorType,
                                          aDeprecatedTextureHostFlags,
                                          aTextureFlags);
-#ifdef XP_WIN
     case LAYERS_D3D11:
       return CreateDeprecatedTextureHostD3D11(aDescriptorType,
                                           aDeprecatedTextureHostFlags,
                                           aTextureFlags);
 #endif
     case LAYERS_BASIC:
       return CreateBasicDeprecatedTextureHost(aDescriptorType,
                                           aDeprecatedTextureHostFlags,
@@ -224,16 +220,19 @@ BufferTextureHost::Updated(const nsIntRe
 {
   ++mUpdateSerial;
   if (aRegion) {
     mPartialUpdate = true;
     mMaybeUpdatedRegion = *aRegion;
   } else {
     mPartialUpdate = false;
   }
+  if (GetFlags() & TEXTURE_IMMEDIATE_UPLOAD) {
+    MaybeUpload(mPartialUpdate ? &mMaybeUpdatedRegion : nullptr);
+  }
 }
 
 void
 BufferTextureHost::SetCompositor(Compositor* aCompositor)
 {
   if (mCompositor == aCompositor) {
     return;
   }
@@ -263,21 +262,18 @@ BufferTextureHost::Unlock()
 {
   mLocked = false;
 }
 
 NewTextureSource*
 BufferTextureHost::GetTextureSources()
 {
   MOZ_ASSERT(mLocked, "should never be called while not locked");
-  if (!mFirstSource || mUpdateSerial != mFirstSource->GetUpdateSerial()) {
-    if (!Upload(mPartialUpdate ? &mMaybeUpdatedRegion : nullptr)) {
+  if (!MaybeUpload(mPartialUpdate ? &mMaybeUpdatedRegion : nullptr)) {
       return nullptr;
-    }
-    mFirstSource->SetUpdateSerial(mUpdateSerial);
   }
   return mFirstSource;
 }
 
 gfx::SurfaceFormat
 BufferTextureHost::GetFormat() const
 {
   // mFormat is the format of the data that we share with the content process.
@@ -289,16 +285,29 @@ BufferTextureHost::GetFormat() const
     mCompositor &&
     !mCompositor->SupportsEffect(EFFECT_YCBCR)) {
     return gfx::FORMAT_R8G8B8X8;
   }
   return mFormat;
 }
 
 bool
+BufferTextureHost::MaybeUpload(nsIntRegion *aRegion)
+{
+  if (mFirstSource && mFirstSource->GetUpdateSerial() == mUpdateSerial) {
+    return true;
+  }
+  if (!Upload(aRegion)) {
+    return false;
+  }
+  mFirstSource->SetUpdateSerial(mUpdateSerial);
+  return true;
+}
+
+bool
 BufferTextureHost::Upload(nsIntRegion *aRegion)
 {
   if (mFormat == gfx::FORMAT_UNKNOWN) {
     NS_WARNING("BufferTextureHost: unsupported format!");
     return false;
   } else if (mFormat == gfx::FORMAT_YUV) {
     YCbCrImageDataDeserializer yuvDeserializer(GetBuffer());
     MOZ_ASSERT(yuvDeserializer.IsValid());
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -26,16 +26,17 @@ class DataSourceSurface;
 
 namespace mozilla {
 namespace layers {
 
 class Compositor;
 class SurfaceDescriptor;
 class ISurfaceAllocator;
 class TextureSourceOGL;
+class TextureSourceD3D9;
 class TextureSourceD3D11;
 class TextureSourceBasic;
 class TextureParent;
 class DataTextureSource;
 
 /**
  * A view on a TextureHost where the texture is internally represented as tiles
  * (contrast with a tiled buffer, where each texture is a tile). For iteration by
@@ -82,28 +83,21 @@ public:
   virtual gfx::IntSize GetSize() const = 0;
 
   /**
    * Return the pixel format of this texture
    */
   virtual gfx::SurfaceFormat GetFormat() const { return gfx::FORMAT_UNKNOWN; }
 
   /**
-   * Cast to a TextureSource for the OpenGL backend.
+   * Cast to a TextureSource for for each backend..
    */
   virtual TextureSourceOGL* AsSourceOGL() { return nullptr; }
-
-  /**
-   * Cast to a TextureSource for the D3D11 backend.
-   */
+  virtual TextureSourceD3D9* AsSourceD3D9() { return nullptr; }
   virtual TextureSourceD3D11* AsSourceD3D11() { return nullptr; }
-
-  /**
-   * Cast to a TextureSource for the software backend.
-   */
   virtual TextureSourceBasic* AsSourceBasic() { return nullptr; }
 
   /**
    * Cast to a DataTextureSurce.
    */
   virtual DataTextureSource* AsDataTextureSource() { return nullptr; }
 
   /**
@@ -444,16 +438,17 @@ public:
   virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE;
 
   virtual already_AddRefed<gfxImageSurface> GetAsSurface() MOZ_OVERRIDE;
 
   virtual gfx::IntSize GetSize() const MOZ_OVERRIDE { return mSize; }
 
 protected:
   bool Upload(nsIntRegion *aRegion = nullptr);
+  bool MaybeUpload(nsIntRegion *aRegion = nullptr);
 
   Compositor* mCompositor;
   RefPtr<DataTextureSource> mFirstSource;
   nsIntRegion mMaybeUpdatedRegion;
   gfx::IntSize mSize;
   // format of the data that is shared with the content process.
   gfx::SurfaceFormat mFormat;
   uint32_t mUpdateSerial;
--- a/gfx/layers/composite/ThebesLayerComposite.cpp
+++ b/gfx/layers/composite/ThebesLayerComposite.cpp
@@ -24,82 +24,83 @@
 
 namespace mozilla {
 namespace layers {
 
 ThebesLayerComposite::ThebesLayerComposite(LayerManagerComposite *aManager)
   : ThebesLayer(aManager, nullptr)
   , LayerComposite(aManager)
   , mBuffer(nullptr)
+  , mRequiresTiledProperties(false)
 {
   MOZ_COUNT_CTOR(ThebesLayerComposite);
   mImplData = static_cast<LayerComposite*>(this);
 }
 
 ThebesLayerComposite::~ThebesLayerComposite()
 {
   MOZ_COUNT_DTOR(ThebesLayerComposite);
-  if (mBuffer) {
-    mBuffer->Detach();
-  }
+  CleanupResources();
 }
 
 void
 ThebesLayerComposite::SetCompositableHost(CompositableHost* aHost)
 {
-  mBuffer= static_cast<ContentHost*>(aHost);
+  mBuffer = static_cast<ContentHost*>(aHost);
 }
 
 void
 ThebesLayerComposite::Disconnect()
 {
   Destroy();
 }
 
 void
 ThebesLayerComposite::Destroy()
 {
   if (!mDestroyed) {
-    if (mBuffer) {
-      mBuffer->Detach();
-    }
-    mBuffer = nullptr;
+    CleanupResources();
     mDestroyed = true;
   }
 }
 
 Layer*
 ThebesLayerComposite::GetLayer()
 {
   return this;
 }
 
 TiledLayerComposer*
 ThebesLayerComposite::GetTiledLayerComposer()
 {
+  MOZ_ASSERT(mBuffer && mBuffer->IsAttached());
   return mBuffer->AsTiledLayerComposer();
 }
 
 LayerRenderState
 ThebesLayerComposite::GetRenderState()
 {
-  if (!mBuffer || mDestroyed) {
+  if (!mBuffer || !mBuffer->IsAttached() || mDestroyed) {
     return LayerRenderState();
   }
   return mBuffer->GetRenderState();
 }
 
 void
 ThebesLayerComposite::RenderLayer(const nsIntPoint& aOffset,
                                   const nsIntRect& aClipRect)
 {
-  if (!mBuffer) {
+  if (!mBuffer || !mBuffer->IsAttached()) {
     return;
   }
 
+  MOZ_ASSERT(mBuffer->GetCompositor() == mCompositeManager->GetCompositor() &&
+             mBuffer->GetLayer() == this,
+             "buffer is corrupted");
+
   gfx::Matrix4x4 transform;
   ToMatrix4x4(GetEffectiveTransform(), transform);
   gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
 
 #ifdef MOZ_DUMP_PAINTING
   if (gfxUtils::sDumpPainting) {
     nsRefPtr<gfxImageSurface> surf = mBuffer->GetAsSurface();
     WriteSnapshotToDumpFile(this, surf);
@@ -140,24 +141,29 @@ ThebesLayerComposite::RenderLayer(const 
     mValidRegion = tiledLayerProps.mValidRegion;
   }
 
   LayerManagerComposite::RemoveMaskEffect(mMaskLayer);
   mCompositeManager->GetCompositor()->MakeCurrent();
 }
 
 CompositableHost*
-ThebesLayerComposite::GetCompositableHost() {
-  return mBuffer.get();
+ThebesLayerComposite::GetCompositableHost()
+{
+  if (mBuffer->IsAttached()) {
+    return mBuffer.get();
+  }
+
+  return nullptr;
 }
 
 void
 ThebesLayerComposite::CleanupResources()
 {
-  if (mBuffer)  {
+  if (mBuffer) {
     mBuffer->Detach();
   }
   mBuffer = nullptr;
 }
 
 gfxSize
 ThebesLayerComposite::GetEffectiveResolution()
 {
@@ -278,17 +284,17 @@ ThebesLayerComposite::GetCompositionBoun
 }
 
 #ifdef MOZ_LAYERS_HAVE_LOG
 nsACString&
 ThebesLayerComposite::PrintInfo(nsACString& aTo, const char* aPrefix)
 {
   ThebesLayer::PrintInfo(aTo, aPrefix);
   aTo += "\n";
-  if (mBuffer) {
+  if (mBuffer && mBuffer->IsAttached()) {
     nsAutoCString pfx(aPrefix);
     pfx += "  ";
     mBuffer->PrintInfo(aTo, pfx.get());
   }
   return aTo;
 }
 #endif
 
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -314,16 +314,17 @@ CompositorD3D11::Initialize()
   return true;
 }
 
 TextureFactoryIdentifier
 CompositorD3D11::GetTextureFactoryIdentifier()
 {
   TextureFactoryIdentifier ident;
   ident.mMaxTextureSize = GetMaxTextureSize();
+  ident.mParentProcessId = XRE_GetProcessType();
   ident.mParentBackend = LAYERS_D3D11;
   return ident;
 }
 
 bool
 CompositorD3D11::CanUseCanvasLayerForSize(const gfxIntSize& aSize)
 {
   int32_t maxTextureSize = GetMaxTextureSize();
@@ -561,49 +562,57 @@ CompositorD3D11::DrawQuad(const gfx::Rec
 
 void
 CompositorD3D11::BeginFrame(const Rect* aClipRectIn,
                             const gfxMatrix& aTransform,
                             const Rect& aRenderBounds,
                             Rect* aClipRectOut,
                             Rect* aRenderBoundsOut)
 {
-  VerifyBufferSize();
   UpdateRenderTarget();
 
-  nsIntRect rect;
-  mWidget->GetClientBounds(rect);
-
-  if (rect.IsEmpty()) {
+  if (mSize.width == 0 || mSize.height == 0) {
     *aRenderBoundsOut = Rect();
     return;
   }
 
-  mDefaultRT->SetSize(IntSize(rect.width, rect.height));
-
   mContext->IASetInputLayout(mAttachments->mInputLayout);
 
   ID3D11Buffer* buffer = mAttachments->mVertexBuffer;
   UINT size = sizeof(Vertex);
   UINT offset = 0;
   mContext->IASetVertexBuffers(0, 1, &buffer, &size, &offset);
-  SetRenderTarget(mDefaultRT);
 
   if (aClipRectOut) {
-    *aClipRectOut = Rect(0, 0, rect.width, rect.height);
+    *aClipRectOut = Rect(0, 0, mSize.width, mSize.height);
   }
   if (aRenderBoundsOut) {
-    *aRenderBoundsOut = Rect(0, 0, rect.width, rect.height);
+    *aRenderBoundsOut = Rect(0, 0, mSize.width, mSize.height);
   }
 
+  D3D11_RECT scissor;
+  if (aClipRectIn) {
+    scissor.left = aClipRectIn->x;
+    scissor.right = aClipRectIn->XMost();
+    scissor.top = aClipRectIn->y;
+    scissor.bottom = aClipRectIn->YMost();
+  } else {
+    scissor.left = scissor.top = 0;
+    scissor.right = mSize.width;
+    scissor.bottom = mSize.height;
+  }
+  mContext->RSSetScissorRects(1, &scissor);
+
   FLOAT black[] = { 0, 0, 0, 0 };
   mContext->ClearRenderTargetView(mDefaultRT->mRTView, black);
 
   mContext->OMSetBlendState(mAttachments->mPremulBlendState, sBlendFactor, 0xFFFFFFFF);
   mContext->RSSetState(mAttachments->mRasterizerState);
+
+  SetRenderTarget(mDefaultRT);
 }
 
 void
 CompositorD3D11::EndFrame()
 {
   mContext->Flush();
   mSwapChain->Present(0, 0);
 
@@ -635,83 +644,84 @@ CompositorD3D11::PrepareViewport(const g
   viewMatrix = aWorldTransform * viewMatrix;
 
   gfx3DMatrix projection = gfx3DMatrix::From2D(viewMatrix);
   projection._33 = 0.0f;
 
   memcpy(&mVSConstants.projection, &projection, sizeof(mVSConstants.projection));
 }
 
-const nsIntSize&
-CompositorD3D11::GetWidgetSize()
+void
+CompositorD3D11::EnsureSize()
 {
   nsIntRect rect;
   mWidget->GetClientBounds(rect);
 
   mSize = rect.Size();
-
-  return mSize;
 }
 
 void
 CompositorD3D11::VerifyBufferSize()
 {
-  nsIntRect rect;
-  mWidget->GetClientBounds(rect);
-
   DXGI_SWAP_CHAIN_DESC swapDesc;
   mSwapChain->GetDesc(&swapDesc);
 
-  if ((swapDesc.BufferDesc.Width == rect.width &&
-      swapDesc.BufferDesc.Height == rect.height) || rect.IsEmpty()) {
+  if ((swapDesc.BufferDesc.Width == mSize.width &&
+       swapDesc.BufferDesc.Height == mSize.height) ||
+      mSize.width == 0 || mSize.height == 0) {
     return;
   }
 
   mDefaultRT = nullptr;
 
   if (gfxWindowsPlatform::IsOptimus()) {
-    mSwapChain->ResizeBuffers(1, rect.width, rect.height,
+    mSwapChain->ResizeBuffers(1, mSize.width, mSize.height,
                               DXGI_FORMAT_B8G8R8A8_UNORM,
                               0);
+#ifdef MOZ_METRO
   } else if (IsRunningInWindowsMetro()) {
-    mSwapChain->ResizeBuffers(2, rect.width, rect.height,
+    mSwapChain->ResizeBuffers(2, mSize.width, mSize.height,
                               DXGI_FORMAT_B8G8R8A8_UNORM,
                               0);
+#endif
   } else {
-    mSwapChain->ResizeBuffers(1, rect.width, rect.height,
+    mSwapChain->ResizeBuffers(1, mSize.width, mSize.height,
                               DXGI_FORMAT_B8G8R8A8_UNORM,
                               DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE);
   }
 }
 
 void
 CompositorD3D11::UpdateRenderTarget()
 {
+  EnsureSize();
+  VerifyBufferSize();
+
   if (mDefaultRT) {
     return;
   }
 
   HRESULT hr;
 
   nsRefPtr<ID3D11Texture2D> backBuf;
 
   hr = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)backBuf.StartAssignment());
   if (FAILED(hr)) {
     return;
   }
 
   mDefaultRT = new CompositingRenderTargetD3D11(backBuf);
+  mDefaultRT->SetSize(mSize);
 }
 
 bool
 CompositorD3D11::CreateShaders()
 {
   HRESULT hr;
 
-
   hr = mDevice->CreateVertexShader(LayerQuadVS,
                                    sizeof(LayerQuadVS),
                                    nullptr,
                                    byRef(mAttachments->mVSQuadShader[MaskNone]));
   if (FAILED(hr)) {
     return false;
   }
 
@@ -819,16 +829,16 @@ CompositorD3D11::PaintToTarget()
 
   nsRefPtr<gfxImageSurface> tmpSurface =
     new gfxImageSurface((unsigned char*)map.pData,
                         gfxIntSize(bbDesc.Width, bbDesc.Height),
                         map.RowPitch,
                         gfxASurface::ImageFormatARGB32);
 
   mTarget->SetSource(tmpSurface);
-  mTarget->SetOperator(gfxContext::OPERATOR_OVER);
+  mTarget->SetOperator(gfxContext::OPERATOR_SOURCE);
   mTarget->Paint();
 
   mContext->Unmap(readTexture, 0);
 }
 
 }
 }
--- a/gfx/layers/d3d11/CompositorD3D11.h
+++ b/gfx/layers/d3d11/CompositorD3D11.h
@@ -132,21 +132,30 @@ public:
 
 #ifdef MOZ_DUMP_PAINTING
   virtual const char* Name() const MOZ_OVERRIDE { return "Direct3D 11"; }
 #endif
 
   virtual void NotifyLayersTransaction() MOZ_OVERRIDE { }
 
   virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; }
-  virtual const nsIntSize& GetWidgetSize() MOZ_OVERRIDE;
+  virtual const nsIntSize& GetWidgetSize() MOZ_OVERRIDE
+  {
+    NS_ASSERTION(false, "Getting the widget size on windows causes some kind of resizing of buffers. "
+                        "You should not do that outside of BeginFrame, so the best we can do is return "
+                        "the last size we got, that might not be up to date. So you probably shouldn't "
+                        "use this method.");
+    return mSize;
+  }
 
   ID3D11Device* GetDevice() { return mDevice; }
 
 private:
+  // ensure mSize is up to date with respect to mWidget
+  void EnsureSize();
   void VerifyBufferSize();
   void UpdateRenderTarget();
   bool CreateShaders();
   void UpdateConstantBuffers();
   void SetSamplerForFilter(gfx::Filter aFilter);
   void SetPSForEffect(Effect *aEffect, MaskType aMaskType);
   void PaintToTarget();
 
@@ -156,19 +165,17 @@ private:
   RefPtr<CompositingRenderTargetD3D11> mDefaultRT;
   RefPtr<CompositingRenderTargetD3D11> mCurrentRT;
 
   DeviceAttachmentsD3D11* mAttachments;
 
   nsRefPtr<gfxContext> mTarget;
 
   nsIWidget* mWidget;
-  // GetWidgetSize requires us to return a reference to an nsIntSize. Since we
-  // don't otherwise keep this value around, we need mSize to avoid a dangling
-  // reference problem.
+
   nsIntSize mSize;
 
   HWND mHwnd;
 
   D3D_FEATURE_LEVEL mFeatureLevel;
 
   VertexShaderConstants mVSConstants;
   PixelShaderConstants mPSConstants;
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -72,27 +72,27 @@ DeprecatedTextureClientD3D11::Deprecated
 
 DeprecatedTextureClientD3D11::~DeprecatedTextureClientD3D11()
 {
   mDescriptor = SurfaceDescriptor();
 
   ClearDT();
 }
 
-void
+bool
 DeprecatedTextureClientD3D11::EnsureAllocated(gfx::IntSize aSize,
                                               gfxASurface::gfxContentType aType)
 {
   D3D10_TEXTURE2D_DESC desc;
 
   if (mTexture) {
     mTexture->GetDesc(&desc);
 
     if (desc.Width == aSize.width && desc.Height == aSize.height) {
-      return;
+      return true;
     }
 
     mTexture = nullptr;
     mSurface = nullptr;
     ClearDT();
   }
 
   mSize = aSize;
@@ -104,33 +104,34 @@ DeprecatedTextureClientD3D11::EnsureAllo
                                 D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE);
 
   newDesc.MiscFlags = D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX;
 
   HRESULT hr = device->CreateTexture2D(&newDesc, nullptr, byRef(mTexture));
 
   if (FAILED(hr)) {
     LOGD3D11("Error creating texture for client!");
-    return;
+    return false;
   }
 
   RefPtr<IDXGIResource> resource;
   mTexture->QueryInterface((IDXGIResource**)byRef(resource));
 
   HANDLE sharedHandle;
   hr = resource->GetSharedHandle(&sharedHandle);
 
   if (FAILED(hr)) {
     LOGD3D11("Error getting shared handle for texture.");
   }
 
   mDescriptor = SurfaceDescriptorD3D10((WindowsHandle)sharedHandle,
                                        aType == gfxASurface::CONTENT_COLOR_ALPHA);
 
   mContentType = aType;
+  return true;
 }
 
 gfxASurface*
 DeprecatedTextureClientD3D11::LockSurface()
 {
   EnsureSurface();
 
   LockTexture();
--- a/gfx/layers/d3d11/TextureD3D11.h
+++ b/gfx/layers/d3d11/TextureD3D11.h
@@ -72,17 +72,17 @@ public:
                                const TextureInfo& aTextureInfo);
   virtual ~DeprecatedTextureClientD3D11();
 
   virtual bool SupportsType(DeprecatedTextureClientType aType) MOZ_OVERRIDE
   {
     return aType == TEXTURE_CONTENT;
   }
 
-  virtual void EnsureAllocated(gfx::IntSize aSize,
+  virtual bool EnsureAllocated(gfx::IntSize aSize,
                                gfxASurface::gfxContentType aType) MOZ_OVERRIDE;
 
   virtual gfxASurface* LockSurface() MOZ_OVERRIDE;
   virtual gfx::DrawTarget* LockDrawTarget() MOZ_OVERRIDE;
   virtual void Unlock() MOZ_OVERRIDE;
 
   virtual void SetDescriptor(const SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE;
   virtual gfxASurface::gfxContentType GetContentType() MOZ_OVERRIDE
--- a/gfx/layers/d3d9/ColorLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ColorLayerD3D9.cpp
@@ -41,17 +41,17 @@ RenderColorLayerD3D9(ColorLayer* aLayer,
   float opacity = aLayer->GetEffectiveOpacity() * layerColor.a;
   // output color is premultiplied, so we need to adjust all channels.
   // mColor is not premultiplied.
   color[0] = (float)(layerColor.r * opacity);
   color[1] = (float)(layerColor.g * opacity);
   color[2] = (float)(layerColor.b * opacity);
   color[3] = (float)(opacity);
 
-  aManager->device()->SetPixelShaderConstantF(0, color, 1);
+  aManager->device()->SetPixelShaderConstantF(CBvColor, color, 1);
 
   aManager->SetShaderMode(DeviceManagerD3D9::SOLIDCOLORLAYER,
                           aLayer->GetMaskLayer());
 
   aManager->device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
 }
 
 void
new file mode 100644
--- /dev/null
+++ b/gfx/layers/d3d9/CompositorD3D9.cpp
@@ -0,0 +1,592 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * 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 "CompositorD3D9.h"
+#include "LayerManagerD3D9Shaders.h"
+#include "gfxWindowsPlatform.h"
+#include "nsIWidget.h"
+#include "mozilla/layers/ImageHost.h"
+#include "mozilla/layers/ContentHost.h"
+#include "mozilla/layers/Effects.h"
+#include "nsWindowsHelpers.h"
+#include "Nv3DVUtils.h"
+#include "gfxFailure.h"
+
+using namespace mozilla::gfx;
+
+namespace mozilla {
+namespace layers {
+
+CompositorD3D9::CompositorD3D9(nsIWidget *aWidget)
+  : mWidget(aWidget)
+{
+  sBackend = LAYERS_D3D9;
+}
+
+CompositorD3D9::~CompositorD3D9()
+{
+  mSwapChain = nullptr;
+  mDeviceManager = nullptr;
+}
+
+bool
+CompositorD3D9::Initialize()
+{
+  if (!gfxPlatform::CanUseDirect3D9()) {
+    NS_WARNING("Direct3D 9-accelerated layers are not supported on this system.");
+    return false;
+  }
+
+  mDeviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager();
+  if (!mDeviceManager) {
+    return false;
+  }
+
+  mSwapChain = mDeviceManager->
+    CreateSwapChain((HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW));
+
+  if (!mSwapChain) {
+    return false;
+  }
+
+  return true;
+}
+
+TextureFactoryIdentifier
+CompositorD3D9::GetTextureFactoryIdentifier()
+{
+  TextureFactoryIdentifier ident;
+  ident.mMaxTextureSize = GetMaxTextureSize();
+  ident.mParentBackend = LAYERS_D3D9;
+  ident.mParentProcessId = XRE_GetProcessType();
+  return ident;
+}
+
+bool
+CompositorD3D9::CanUseCanvasLayerForSize(const gfxIntSize &aSize)
+{
+  int32_t maxTextureSize = GetMaxTextureSize();
+
+  if (aSize.width > maxTextureSize || aSize.height > maxTextureSize) {
+    return false;
+  }
+
+  return true;
+}
+
+int32_t
+CompositorD3D9::GetMaxTextureSize() const
+{
+  return mDeviceManager->GetMaxTextureSize();
+}
+
+TemporaryRef<CompositingRenderTarget>
+CompositorD3D9::CreateRenderTarget(const gfx::IntRect &aRect,
+                                   SurfaceInitMode aInit)
+{
+  RefPtr<IDirect3DTexture9> texture;
+  HRESULT hr = device()->CreateTexture(aRect.width, aRect.height, 1,
+                                       D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
+                                       D3DPOOL_DEFAULT, byRef(texture),
+                                       NULL);
+  if (FAILED(hr)) {
+    ReportFailure(NS_LITERAL_CSTRING("CompositorD3D9::CreateRenderTarget: Failed to create texture"),
+                  hr);
+    return nullptr;
+  }
+
+  RefPtr<CompositingRenderTargetD3D9> rt =
+    new CompositingRenderTargetD3D9(texture, aInit, IntSize(aRect.width, aRect.height));
+
+  return rt;
+}
+
+TemporaryRef<CompositingRenderTarget>
+CompositorD3D9::CreateRenderTargetFromSource(const gfx::IntRect &aRect,
+                                             const CompositingRenderTarget *aSource)
+{
+  RefPtr<IDirect3DTexture9> texture;
+  HRESULT hr = device()->CreateTexture(aRect.width, aRect.height, 1,
+                                       D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
+                                       D3DPOOL_DEFAULT, byRef(texture),
+                                       NULL);
+  if (FAILED(hr)) {
+    ReportFailure(NS_LITERAL_CSTRING("CompositorD3D9::CreateRenderTargetFromSource: Failed to create texture"),
+                  hr);
+    return nullptr;
+  }
+
+  if (aSource) {
+    nsRefPtr<IDirect3DSurface9> sourceSurface =
+      static_cast<const CompositingRenderTargetD3D9*>(aSource)->GetD3D9Surface();
+
+    nsRefPtr<IDirect3DSurface9> destSurface;
+    hr = texture->GetSurfaceLevel(0, getter_AddRefs(destSurface));
+    if (FAILED(hr)) {
+      NS_WARNING("Failed to get texture surface level for dest.");
+    }
+
+    if (sourceSurface && destSurface) {
+      RECT sourceRect;
+      sourceRect.left = aRect.x;
+      sourceRect.right = aRect.XMost();
+      sourceRect.top = aRect.y;
+      sourceRect.bottom = aRect.YMost();
+      RECT destRect;
+      destRect.left = 0;
+      destRect.right = aRect.width;
+      destRect.top = 0;
+      destRect.bottom = aRect.height;
+
+      // copy the source to the dest
+      hr = device()->StretchRect(sourceSurface,
+                                 &sourceRect,
+                                 destSurface,
+                                 &destRect,
+                                 D3DTEXF_NONE);
+      if (FAILED(hr)) {
+        ReportFailure(NS_LITERAL_CSTRING("CompositorD3D9::CreateRenderTargetFromSource: Failed to update texture"),
+                      hr);
+      }
+    }
+  }
+
+  RefPtr<CompositingRenderTargetD3D9> rt =
+    new CompositingRenderTargetD3D9(texture,
+                                    INIT_MODE_NONE,
+                                    IntSize(aRect.width, aRect.height));
+
+  return rt;
+}
+
+void
+CompositorD3D9::SetRenderTarget(CompositingRenderTarget *aRenderTarget)
+{
+  MOZ_ASSERT(aRenderTarget);
+  RefPtr<CompositingRenderTargetD3D9> oldRT = mCurrentRT;
+  mCurrentRT = static_cast<CompositingRenderTargetD3D9*>(aRenderTarget);
+  mCurrentRT->BindRenderTarget(device());
+  PrepareViewport(mCurrentRT->GetSize(), gfxMatrix());
+}
+
+static DeviceManagerD3D9::ShaderMode
+ShaderModeForEffectType(EffectTypes aEffectType)
+{
+  switch (aEffectType) {
+  case EFFECT_SOLID_COLOR:
+    return DeviceManagerD3D9::SOLIDCOLORLAYER;
+  case EFFECT_BGRA:
+  case EFFECT_RENDER_TARGET:
+    return DeviceManagerD3D9::RGBALAYER;
+  case EFFECT_BGRX:
+    return DeviceManagerD3D9::RGBLAYER;
+  case EFFECT_YCBCR:
+    return DeviceManagerD3D9::YCBCRLAYER;
+  }
+
+  MOZ_CRASH("Bad effect type");
+}
+
+void
+CompositorD3D9::DrawQuad(const gfx::Rect &aRect, const gfx::Rect &aClipRect,
+                         const EffectChain &aEffectChain,
+                         gfx::Float aOpacity, const gfx::Matrix4x4 &aTransform,
+                         const gfx::Point &aOffset)
+{
+  MOZ_ASSERT(mCurrentRT, "No render target");
+  device()->SetVertexShaderConstantF(CBmLayerTransform, &aTransform._11, 4);
+
+  float renderTargetOffset[] = { aOffset.x, aOffset.y, 0, 0 };
+  device()->SetVertexShaderConstantF(CBvRenderTargetOffset,
+                                     renderTargetOffset,
+                                     1);
+  device()->SetVertexShaderConstantF(CBvLayerQuad,
+                                     ShaderConstantRect(aRect.x,
+                                                        aRect.y,
+                                                        aRect.width,
+                                                        aRect.height),
+                                     1);
+  bool target = false;
+
+  if (aEffectChain.mPrimaryEffect->mType != EFFECT_SOLID_COLOR) {
+    float opacity[4];
+    /*
+     * We always upload a 4 component float, but the shader will use only the
+     * first component since it's declared as a 'float'.
+     */
+    opacity[0] = aOpacity;
+    device()->SetPixelShaderConstantF(CBfLayerOpacity, opacity, 1);
+  }
+
+  bool isPremultiplied = true;
+
+  MaskType maskType = MaskNone;
+
+  if (aEffectChain.mSecondaryEffects[EFFECT_MASK]) {
+    if (aTransform.Is2D()) {
+      maskType = Mask2d;
+    } else {
+      maskType = Mask3d;
+    }
+  }
+
+  RECT scissor;
+  scissor.left = aClipRect.x;
+  scissor.right = aClipRect.XMost();
+  scissor.top = aClipRect.y;
+  scissor.bottom = aClipRect.YMost();
+  device()->SetScissorRect(&scissor);
+
+  uint32_t maskTexture = 0;
+  switch (aEffectChain.mPrimaryEffect->mType) {
+  case EFFECT_SOLID_COLOR:
+    {
+      // output color is premultiplied, so we need to adjust all channels.
+      Color layerColor =
+        static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get())->mColor;
+      float color[4];
+      color[0] = layerColor.r * layerColor.a * aOpacity;
+      color[1] = layerColor.g * layerColor.a * aOpacity;
+      color[2] = layerColor.b * layerColor.a * aOpacity;
+      color[3] = layerColor.a * aOpacity;
+
+      device()->SetPixelShaderConstantF(CBvColor, color, 1);
+
+      maskTexture = mDeviceManager
+        ->SetShaderMode(DeviceManagerD3D9::SOLIDCOLORLAYER, maskType);
+    }
+    break;
+  case EFFECT_RENDER_TARGET:
+  case EFFECT_BGRX:
+  case EFFECT_BGRA:
+    {
+      TexturedEffect* texturedEffect =
+        static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
+
+      Rect textureCoords = texturedEffect->mTextureCoords;
+      device()->SetVertexShaderConstantF(CBvTextureCoords,
+                                         ShaderConstantRect(
+                                           textureCoords.x,
+                                           textureCoords.y,
+                                           textureCoords.width,
+                                           textureCoords.height),
+                                         1);
+
+      SetSamplerForFilter(texturedEffect->mFilter);
+
+      TextureSourceD3D9* source = texturedEffect->mTexture->AsSourceD3D9();
+      device()->SetTexture(0, source->GetD3D9Texture());
+
+      maskTexture = mDeviceManager
+        ->SetShaderMode(ShaderModeForEffectType(aEffectChain.mPrimaryEffect->mType),
+                        maskType);
+
+      isPremultiplied = texturedEffect->mPremultiplied;
+    }
+    break;
+  case EFFECT_YCBCR:
+    {
+      EffectYCbCr* ycbcrEffect =
+        static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get());
+
+      SetSamplerForFilter(FILTER_LINEAR);
+
+      Rect textureCoords = ycbcrEffect->mTextureCoords;
+      device()->SetVertexShaderConstantF(CBvTextureCoords,
+                                         ShaderConstantRect(
+                                           textureCoords.x,
+                                           textureCoords.y,
+                                           textureCoords.width,
+                                           textureCoords.height),
+                                         1);
+                                    
+      TextureSourceD3D9* source = ycbcrEffect->mTexture->AsSourceD3D9();
+      TextureSourceD3D9::YCbCrTextures textures = source->GetYCbCrTextures();
+
+      /*
+       * Send 3d control data and metadata
+       */
+      if (mDeviceManager->GetNv3DVUtils()) {
+        Nv_Stereo_Mode mode;
+        switch (textures.mStereoMode) {
+        case STEREO_MODE_LEFT_RIGHT:
+          mode = NV_STEREO_MODE_LEFT_RIGHT;
+          break;
+        case STEREO_MODE_RIGHT_LEFT:
+          mode = NV_STEREO_MODE_RIGHT_LEFT;
+          break;
+        case STEREO_MODE_BOTTOM_TOP:
+          mode = NV_STEREO_MODE_BOTTOM_TOP;
+          break;
+        case STEREO_MODE_TOP_BOTTOM:
+          mode = NV_STEREO_MODE_TOP_BOTTOM;
+          break;
+        case STEREO_MODE_MONO:
+          mode = NV_STEREO_MODE_MONO;
+          break;
+        }
+
+        // Send control data even in mono case so driver knows to leave stereo mode.
+        mDeviceManager->GetNv3DVUtils()->SendNv3DVControl(mode, true, FIREFOX_3DV_APP_HANDLE);
+
+        if (textures.mStereoMode != STEREO_MODE_MONO) {
+          mDeviceManager->GetNv3DVUtils()->SendNv3DVControl(mode, true, FIREFOX_3DV_APP_HANDLE);
+
+          nsRefPtr<IDirect3DSurface9> renderTarget;
+          device()->GetRenderTarget(0, getter_AddRefs(renderTarget));
+          mDeviceManager->GetNv3DVUtils()->SendNv3DVMetaData((unsigned int)aRect.width,
+                                                             (unsigned int)aRect.height,
+                                                             (HANDLE)(textures.mY),
+                                                             (HANDLE)(renderTarget));
+        }
+      }
+
+      // Linear scaling is default here, adhering to mFilter is difficult since
+      // presumably even with point filtering we'll still want chroma upsampling
+      // to be linear. In the current approach we can't.
+      device()->SetTexture(0, textures.mY);
+      device()->SetTexture(1, textures.mCb);
+      device()->SetTexture(2, textures.mCr);
+      maskTexture = mDeviceManager->SetShaderMode(DeviceManagerD3D9::YCBCRLAYER, maskType);
+    }
+    break;
+  case EFFECT_COMPONENT_ALPHA:
+    {
+      EffectComponentAlpha* effectComponentAlpha =
+        static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
+      TextureSourceD3D9* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceD3D9();
+      TextureSourceD3D9* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceD3D9();
+
+      Rect textureCoords = effectComponentAlpha->mTextureCoords;
+      device()->SetVertexShaderConstantF(CBvTextureCoords,
+                                         ShaderConstantRect(
+                                           textureCoords.x,
+                                           textureCoords.y,
+                                           textureCoords.width,
+                                           textureCoords.height),
+                                          1);
+
+      SetSamplerForFilter(effectComponentAlpha->mFilter);
+      SetMask(aEffectChain, maskTexture);
+
+      maskTexture = mDeviceManager->SetShaderMode(DeviceManagerD3D9::COMPONENTLAYERPASS1, maskType);
+      device()->SetTexture(0, sourceOnBlack->GetD3D9Texture());
+      device()->SetTexture(1, sourceOnWhite->GetD3D9Texture());
+      device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
+      device()->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCCOLOR);
+      device()->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
+      device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
+
+      maskTexture = mDeviceManager->SetShaderMode(DeviceManagerD3D9::COMPONENTLAYERPASS2, maskType);
+      device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
+      device()->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
+      device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
+
+      // Restore defaults
+      device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
+      device()->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
+      device()->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
+      device()->SetTexture(1, NULL);
+    }
+    return;
+  default:
+    NS_WARNING("Unknown shader type");
+    return;
+  }
+
+  SetMask(aEffectChain, maskTexture);
+
+  if (!isPremultiplied) {
+    device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
+    device()->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
+  }
+
+  HRESULT hr = device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
+
+  if (!isPremultiplied) {
+    device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
+    device()->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
+  }
+}
+
+void
+CompositorD3D9::SetMask(const EffectChain &aEffectChain, uint32_t aMaskTexture)
+{
+  EffectMask *maskEffect =
+    static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EFFECT_MASK].get());
+  if (!maskEffect) {
+    return;
+  }
+
+  TextureSourceD3D9 *source = maskEffect->mMaskTexture->AsSourceD3D9();
+
+  MOZ_ASSERT(aMaskTexture >= 0);
+  device()->SetTexture(aMaskTexture, source->GetD3D9Texture());
+
+  const gfx::Matrix4x4& maskTransform = maskEffect->mMaskTransform;
+  NS_ASSERTION(maskTransform.Is2D(), "How did we end up with a 3D transform here?!");
+  Rect bounds = Rect(Point(), Size(maskEffect->mSize));
+  bounds = maskTransform.As2D().TransformBounds(bounds);
+
+  device()->SetVertexShaderConstantF(DeviceManagerD3D9::sMaskQuadRegister, 
+                                     ShaderConstantRect(bounds.x,
+                                                        bounds.y,
+                                                        bounds.width,
+                                                        bounds.height),
+                                     1);
+}
+
+void
+CompositorD3D9::BeginFrame(const Rect *aClipRectIn,
+                           const gfxMatrix& aTransform,
+                           const Rect& aRenderBounds,
+                           Rect *aClipRectOut,
+                           Rect *aRenderBoundsOut)
+{
+  if (!mSwapChain->PrepareForRendering()) {
+    return;
+  }
+  mDeviceManager->SetupRenderState();
+
+  EnsureSize();
+
+  device()->Clear(0, NULL, D3DCLEAR_TARGET, 0x00000000, 0, 0);
+  device()->BeginScene();
+
+  if (aClipRectOut) {
+    *aClipRectOut = Rect(0, 0, mSize.width, mSize.height);
+  }
+  if (aRenderBoundsOut) {
+    *aRenderBoundsOut = Rect(0, 0, mSize.width, mSize.height);
+  }
+
+  RECT r;
+  if (aClipRectIn) {
+    r.left = (LONG)aClipRectIn->x;
+    r.top = (LONG)aClipRectIn->y;
+    r.right = (LONG)(aClipRectIn->x + aClipRectIn->width);
+    r.bottom = (LONG)(aClipRectIn->y + aClipRectIn->height);
+  } else {
+    r.left = r.top = 0;
+    r.right = mSize.width;
+    r.bottom = mSize.height;
+  }
+  device()->SetScissorRect(&r);
+
+  nsRefPtr<IDirect3DSurface9> backBuffer = mSwapChain->GetBackBuffer();
+  mDefaultRT = new CompositingRenderTargetD3D9(backBuffer,
+                                               INIT_MODE_CLEAR,
+                                               IntSize(mSize.width, mSize.height));
+  SetRenderTarget(mDefaultRT);
+}
+
+void
+CompositorD3D9::EndFrame()
+{
+  device()->EndScene();
+
+  if (!!mTarget) {
+    PaintToTarget();
+  } else {
+    mSwapChain->Present();
+  }
+
+  mCurrentRT = nullptr;
+}
+
+void
+CompositorD3D9::PrepareViewport(const gfx::IntSize& aSize,
+                                const gfxMatrix &aWorldTransform)
+{
+  gfx3DMatrix viewMatrix;
+  /*
+   * Matrix to transform to viewport space ( <-1.0, 1.0> topleft,
+   * <1.0, -1.0> bottomright)
+   */
+  viewMatrix._11 = 2.0f / aSize.width;
+  viewMatrix._22 = -2.0f / aSize.height;
+  viewMatrix._41 = -1.0f;
+  viewMatrix._42 = 1.0f;
+
+  viewMatrix = gfx3DMatrix::From2D(aWorldTransform) * viewMatrix;
+
+  HRESULT hr = device()->SetVertexShaderConstantF(CBmProjection, &viewMatrix._11, 4);
+
+  if (FAILED(hr)) {
+    NS_WARNING("Failed to set projection matrix");
+  }
+}
+
+void
+CompositorD3D9::EnsureSize()
+{
+  nsIntRect rect;
+  mWidget->GetClientBounds(rect);
+
+  mSize = rect.Size();
+}
+
+void
+CompositorD3D9::SetSamplerForFilter(Filter aFilter)
+{
+  switch (aFilter) {
+  case FILTER_LINEAR:
+    device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
+    device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
+    return;
+  case FILTER_POINT:
+    device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
+    device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
+    return;
+  default:
+    device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
+    device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
+  }
+}
+
+void
+CompositorD3D9::PaintToTarget()
+{
+  nsRefPtr<IDirect3DSurface9> backBuff;
+  nsRefPtr<IDirect3DSurface9> destSurf;
+  device()->GetRenderTarget(0, getter_AddRefs(backBuff));
+
+  D3DSURFACE_DESC desc;
+  backBuff->GetDesc(&desc);
+
+  device()->CreateOffscreenPlainSurface(desc.Width, desc.Height,
+                                        D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM,
+                                        getter_AddRefs(destSurf), NULL);
+
+  device()->GetRenderTargetData(backBuff, destSurf);
+
+  D3DLOCKED_RECT rect;
+  destSurf->LockRect(&rect, NULL, D3DLOCK_READONLY);
+  mTarget->SetOperator(gfxContext::OPERATOR_SOURCE);
+  nsRefPtr<gfxImageSurface> imageSurface =
+    new gfxImageSurface((unsigned char*)rect.pBits,
+                        gfxIntSize(desc.Width, desc.Height),
+                        rect.Pitch,
+                        gfxASurface::ImageFormatARGB32);
+  mTarget->SetSource(imageSurface);
+  mTarget->Paint();
+  destSurf->UnlockRect();
+}
+
+void
+CompositorD3D9::ReportFailure(const nsACString &aMsg, HRESULT aCode)
+{
+  // We could choose to abort here when hr == E_OUTOFMEMORY.
+  nsCString msg;
+  msg.Append(aMsg);
+  msg.AppendLiteral(" Error code: ");
+  msg.AppendInt(uint32_t(aCode));
+  NS_WARNING(msg.BeginReading());
+
+  gfx::LogFailure(msg);
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/gfx/layers/d3d9/CompositorD3D9.h
@@ -0,0 +1,142 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZILLA_GFX_COMPOSITORD3D9_H
+#define MOZILLA_GFX_COMPOSITORD3D9_H
+
+#include "mozilla/layers/Compositor.h"
+#include "mozilla/layers/TextureD3D9.h"
+#include "DeviceManagerD3D9.h"
+
+class nsWidget;
+
+namespace mozilla {
+namespace layers {
+
+class CompositorD3D9 : public Compositor
+{
+public:
+  CompositorD3D9(nsIWidget *aWidget);
+  ~CompositorD3D9();
+
+  virtual bool Initialize() MOZ_OVERRIDE;
+  virtual void Destroy() MOZ_OVERRIDE {}
+
+  virtual TextureFactoryIdentifier
+    GetTextureFactoryIdentifier() MOZ_OVERRIDE;
+
+  virtual bool CanUseCanvasLayerForSize(const gfxIntSize &aSize) MOZ_OVERRIDE;
+  virtual int32_t GetMaxTextureSize() const MOZ_FINAL;
+
+  virtual void SetTargetContext(gfxContext *aTarget) MOZ_OVERRIDE
+  {
+    mTarget = aTarget;
+  }
+
+  virtual void MakeCurrent(MakeCurrentFlags aFlags = 0) MOZ_OVERRIDE {}
+
+  virtual TemporaryRef<CompositingRenderTarget>
+    CreateRenderTarget(const gfx::IntRect &aRect,
+                       SurfaceInitMode aInit) MOZ_OVERRIDE;
+
+  virtual TemporaryRef<CompositingRenderTarget>
+    CreateRenderTargetFromSource(const gfx::IntRect &aRect,
+                                 const CompositingRenderTarget *aSource) MOZ_OVERRIDE;
+
+  virtual void SetRenderTarget(CompositingRenderTarget *aSurface);
+  virtual CompositingRenderTarget* GetCurrentRenderTarget() MOZ_OVERRIDE
+  {
+    return mCurrentRT;
+  }
+
+  virtual void SetDestinationSurfaceSize(const gfx::IntSize& aSize) MOZ_OVERRIDE {}
+
+  virtual void DrawQuad(const gfx::Rect &aRect, const gfx::Rect &aClipRect,
+                        const EffectChain &aEffectChain,
+                        gfx::Float aOpacity, const gfx::Matrix4x4 &aTransform,
+                        const gfx::Point &aOffset) MOZ_OVERRIDE;
+
+  virtual void BeginFrame(const gfx::Rect *aClipRectIn,
+                          const gfxMatrix& aTransform,
+                          const gfx::Rect& aRenderBounds,
+                          gfx::Rect *aClipRectOut = nullptr,
+                          gfx::Rect *aRenderBoundsOut = nullptr) MOZ_OVERRIDE;
+
+  virtual void EndFrame() MOZ_OVERRIDE;
+
+  virtual void EndFrameForExternalComposition(const gfxMatrix& aTransform) MOZ_OVERRIDE {}
+
+  virtual void AbortFrame() MOZ_OVERRIDE {}
+
+  virtual void PrepareViewport(const gfx::IntSize& aSize,
+                               const gfxMatrix& aWorldTransform) MOZ_OVERRIDE;
+
+  virtual bool SupportsPartialTextureUpdate() MOZ_OVERRIDE{ return true; }
+
+#ifdef MOZ_DUMP_PAINTING
+  virtual const char* Name() const MOZ_OVERRIDE { return "Direct3D9"; }
+#endif
+
+  virtual void NotifyLayersTransaction() MOZ_OVERRIDE {}
+
+  virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; }
+  virtual const nsIntSize& GetWidgetSize() MOZ_OVERRIDE
+  {
+    NS_ASSERTION(false, "Getting the widget size on windows causes some kind of resizing of buffers. "
+                        "You should not do that outside of BeginFrame, so the best we can do is return "
+                        "the last size we got, that might not be up to date. So you probably shouldn't "
+                        "use this method.");
+    return mSize;
+  }
+
+  IDirect3DDevice9* device() const { return mDeviceManager->device(); }
+
+  /**
+   * Declare an offset to use when rendering layers. This will be ignored when
+   * rendering to a target instead of the screen.
+   */
+  virtual void SetScreenRenderOffset(const ScreenPoint& aOffset) MOZ_OVERRIDE
+  {
+    if (aOffset.x || aOffset.y) {
+      NS_RUNTIMEABORT("SetScreenRenderOffset not supported by CompositorD3D9.");
+    }
+    // If the offset is 0, 0 that's okay.
+  }
+
+   virtual TemporaryRef<DataTextureSource>
+     CreateDataTextureSource(TextureFlags aFlags = 0) MOZ_OVERRIDE { return nullptr; } 
+private:
+  // ensure mSize is up to date with respect to mWidget
+  void EnsureSize();
+  void SetSamplerForFilter(gfx::Filter aFilter);
+  void PaintToTarget();
+  void SetMask(const EffectChain &aEffectChain, uint32_t aMaskTexture);
+
+  void ReportFailure(const nsACString &aMsg, HRESULT aCode);
+
+  /* Device manager instance for this compositor */
+  nsRefPtr<DeviceManagerD3D9> mDeviceManager;
+
+  /* Swap chain associated with this compositor */
+  nsRefPtr<SwapChainD3D9> mSwapChain;
+
+  /* Widget associated with this layer manager */
+  nsIWidget *mWidget;
+
+  /*
+   * Context target, NULL when drawing directly to our swap chain.
+   */
+  nsRefPtr<gfxContext> mTarget;
+
+  RefPtr<CompositingRenderTargetD3D9> mDefaultRT;
+  RefPtr<CompositingRenderTargetD3D9> mCurrentRT;
+
+  nsIntSize mSize;
+};
+
+}
+}
+
+#endif
--- a/gfx/layers/d3d9/DeviceManagerD3D9.cpp
+++ b/gfx/layers/d3d9/DeviceManagerD3D9.cpp
@@ -7,16 +7,17 @@
 #include "LayerManagerD3D9Shaders.h"
 #include "ThebesLayerD3D9.h"
 #include "nsIServiceManager.h"
 #include "nsIConsoleService.h"
 #include "nsPrintfCString.h"
 #include "Nv3DVUtils.h"
 #include "plstr.h"
 #include <algorithm>
+#include "gfxPlatform.h"
 
 namespace mozilla {
 namespace layers {
 
 const LPCWSTR kClassName       = L"D3D9WindowClass";
 
 #define USE_D3D9EX
 
@@ -73,16 +74,26 @@ SwapChainD3D9::Init(HWND hWnd)
   if (FAILED(hr)) {
     NS_WARNING("Failed to create swap chain for window.");
     return false;
   }
 
   return true;
 }
 
+already_AddRefed<IDirect3DSurface9>
+SwapChainD3D9::GetBackBuffer()
+{
+  nsRefPtr<IDirect3DSurface9> backBuffer;
+    mSwapChain->GetBackBuffer(0,
+                              D3DBACKBUFFER_TYPE_MONO,
+                              getter_AddRefs(backBuffer));
+  return backBuffer.forget();
+}
+
 bool
 SwapChainD3D9::PrepareForRendering()
 {
   RECT r;
   if (!::GetClientRect(mWnd, &r)) {
     return false;
   }
 
@@ -90,20 +101,17 @@ SwapChainD3D9::PrepareForRendering()
     return false;
   }
 
   if (!mSwapChain) {
     Init(mWnd);
   }
 
   if (mSwapChain) {
-    nsRefPtr<IDirect3DSurface9> backBuffer;
-    mSwapChain->GetBackBuffer(0,
-                              D3DBACKBUFFER_TYPE_MONO,
-                              getter_AddRefs(backBuffer));
+    nsRefPtr<IDirect3DSurface9> backBuffer = GetBackBuffer();
 
     D3DSURFACE_DESC desc;
     backBuffer->GetDesc(&desc);
 
     if (desc.Width == r.right - r.left && desc.Height == r.bottom - r.top) {
       mDeviceManager->device()->SetRenderTarget(0, backBuffer);
       return true;
     }
@@ -111,20 +119,17 @@ SwapChainD3D9::PrepareForRendering()
     mSwapChain = nullptr;
     
     Init(mWnd);
     
     if (!mSwapChain) {
       return false;
     }
     
-    mSwapChain->GetBackBuffer(0,
-                              D3DBACKBUFFER_TYPE_MONO,
-                              getter_AddRefs(backBuffer));
-
+    backBuffer = GetBackBuffer();
     mDeviceManager->device()->SetRenderTarget(0, backBuffer);
     
     return true;
   }
   return false;
 }
 
 void
@@ -135,40 +140,46 @@ SwapChainD3D9::Present(const nsIntRect &
   r.top = aRect.y;
   r.right = aRect.XMost();
   r.bottom = aRect.YMost();
 
   mSwapChain->Present(&r, &r, 0, 0, 0);
 }
 
 void
+SwapChainD3D9::Present()
+{
+  mSwapChain->Present(NULL, NULL, 0, 0, 0);
+}
+
+void
 SwapChainD3D9::Reset()
 {
   mSwapChain = nullptr;
 }
 
 #define HAS_CAP(a, b) (((a) & (b)) == (b))
 #define LACKS_CAP(a, b) !(((a) & (b)) == (b))
 
+uint32_t DeviceManagerD3D9::sMaskQuadRegister = 11;
+
 DeviceManagerD3D9::DeviceManagerD3D9()
   : mDeviceResetCount(0)
   , mMaxTextureSize(0)
+  , mTextureAddressingMode(D3DTADDRESS_CLAMP)
   , mHasDynamicTextures(false)
   , mDeviceWasRemoved(false)
 {
 }
 
 DeviceManagerD3D9::~DeviceManagerD3D9()
 {
   LayerManagerD3D9::OnDeviceManagerDestroy(this);
 }
 
-NS_IMPL_ADDREF(DeviceManagerD3D9)
-NS_IMPL_RELEASE(DeviceManagerD3D9)
-
 bool
 DeviceManagerD3D9::Init()
 {
   WNDCLASSW wc;
   HRESULT hr;
 
   if (!GetClassInfoW(GetModuleHandle(nullptr), kClassName, &wc)) {
       ZeroMemory(&wc, sizeof(WNDCLASSW));
@@ -491,22 +502,22 @@ DeviceManagerD3D9::SetupRenderState()
   mDevice->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA);
   mDevice->SetRenderState(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD);
   mDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
   mDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
   mDevice->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
   mDevice->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
   mDevice->SetSamplerState(2, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
   mDevice->SetSamplerState(2, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
-  mDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
-  mDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
-  mDevice->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
-  mDevice->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
-  mDevice->SetSamplerState(2, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
-  mDevice->SetSamplerState(2, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
+  mDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, mTextureAddressingMode);
+  mDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, mTextureAddressingMode);
+  mDevice->SetSamplerState(1, D3DSAMP_ADDRESSU, mTextureAddressingMode);
+  mDevice->SetSamplerState(1, D3DSAMP_ADDRESSV, mTextureAddressingMode);
+  mDevice->SetSamplerState(2, D3DSAMP_ADDRESSU, mTextureAddressingMode);
+  mDevice->SetSamplerState(2, D3DSAMP_ADDRESSV, mTextureAddressingMode);
 }
 
 already_AddRefed<SwapChainD3D9>
 DeviceManagerD3D9::CreateSwapChain(HWND hWnd)
 {
   nsRefPtr<SwapChainD3D9> swapChain = new SwapChainD3D9(this);
   
   // See bug 604647. This line means that if we create a window while the
@@ -528,94 +539,47 @@ DeviceManagerD3D9::CreateSwapChain(HWND 
 /*
   * Finds a texture for the mask layer and sets it as an
   * input to the shaders.
   * Returns true if a texture is loaded, false if 
   * a texture for the mask layer could not be loaded.
   */
 bool
 LoadMaskTexture(Layer* aMask, IDirect3DDevice9* aDevice,
-                uint32_t aMaskQuadTexture, uint32_t aMaskTexRegister)
+                uint32_t aMaskTexRegister)
 {
   gfxIntSize size;
   nsRefPtr<IDirect3DTexture9> texture =
     static_cast<LayerD3D9*>(aMask->ImplData())->GetAsTexture(&size);
   
   if (!texture) {
     return false;
   }
   
   gfxMatrix maskTransform;
   bool maskIs2D = aMask->GetEffectiveTransform().CanDraw2D(&maskTransform);
   NS_ASSERTION(maskIs2D, "How did we end up with a 3D transform here?!");
   gfxRect bounds = gfxRect(gfxPoint(), size);
   bounds = maskTransform.TransformBounds(bounds);
 
-  aDevice->SetVertexShaderConstantF(aMaskQuadTexture, 
+  aDevice->SetVertexShaderConstantF(DeviceManagerD3D9::sMaskQuadRegister, 
                                     ShaderConstantRect((float)bounds.x,
                                                        (float)bounds.y,
                                                        (float)bounds.width,
                                                        (float)bounds.height),
                                     1);
 
   aDevice->SetTexture(aMaskTexRegister, texture);
   return true;
 }
 
-void
-DeviceManagerD3D9::SetShaderMode(ShaderMode aMode, Layer* aMask, bool aIs2D)
+uint32_t
+DeviceManagerD3D9::SetShaderMode(ShaderMode aMode, MaskType aMaskType)
 {
-  if (aMask) {
-    // register allocations are taken from LayerManagerD3D9Shaders.h after
-    // the shaders are compiled (genshaders.sh)
-    const uint32_t maskQuadRegister = 11;
-    uint32_t maskTexRegister;
-    switch (aMode) {
-      case RGBLAYER:
-        mDevice->SetVertexShader(mLayerVSMask);
-        mDevice->SetPixelShader(mRGBPSMask);
-        maskTexRegister = 1;
-        break;
-      case RGBALAYER:
-        if (aIs2D) {
-          mDevice->SetVertexShader(mLayerVSMask);
-          mDevice->SetPixelShader(mRGBAPSMask);
-        } else {
-          mDevice->SetVertexShader(mLayerVSMask3D);
-          mDevice->SetPixelShader(mRGBAPSMask3D);
-        }
-        maskTexRegister = 1;
-        break;
-      case COMPONENTLAYERPASS1:
-        mDevice->SetVertexShader(mLayerVSMask);
-        mDevice->SetPixelShader(mComponentPass1PSMask);
-        maskTexRegister = 2;
-        break;
-      case COMPONENTLAYERPASS2:
-        mDevice->SetVertexShader(mLayerVSMask);
-        mDevice->SetPixelShader(mComponentPass2PSMask);
-        maskTexRegister = 2;
-        break;
-      case YCBCRLAYER:
-        mDevice->SetVertexShader(mLayerVSMask);
-        mDevice->SetPixelShader(mYCbCrPSMask);
-        maskTexRegister = 3;
-        break;
-      case SOLIDCOLORLAYER:
-        mDevice->SetVertexShader(mLayerVSMask);
-        mDevice->SetPixelShader(mSolidColorPSMask);
-        maskTexRegister = 0;
-        break;
-    }
-    if (!LoadMaskTexture(aMask, mDevice, maskQuadRegister, maskTexRegister)) {
-      // if we can't load the mask, fall back to unmasked rendering
-      NS_WARNING("Could not load texture for mask layer.");
-      SetShaderMode(aMode, nullptr, true);
-    }
-  } else {
+  if (aMaskType == MaskNone) {
     switch (aMode) {
       case RGBLAYER:
         mDevice->SetVertexShader(mLayerVS);
         mDevice->SetPixelShader(mRGBPS);
         break;
       case RGBALAYER:
         mDevice->SetVertexShader(mLayerVS);
         mDevice->SetPixelShader(mRGBAPS);
@@ -632,16 +596,76 @@ DeviceManagerD3D9::SetShaderMode(ShaderM
         mDevice->SetVertexShader(mLayerVS);
         mDevice->SetPixelShader(mYCbCrPS);
         break;
       case SOLIDCOLORLAYER:
         mDevice->SetVertexShader(mLayerVS);
         mDevice->SetPixelShader(mSolidColorPS);
         break;
     }
+    return 0;
+  }
+
+  uint32_t maskTexRegister;
+  switch (aMode) {
+    case RGBLAYER:
+      mDevice->SetVertexShader(mLayerVSMask);
+      mDevice->SetPixelShader(mRGBPSMask);
+      maskTexRegister = 1;
+      break;
+    case RGBALAYER:
+      if (aMaskType == Mask2d) {
+        mDevice->SetVertexShader(mLayerVSMask);
+        mDevice->SetPixelShader(mRGBAPSMask);
+      } else {
+        mDevice->SetVertexShader(mLayerVSMask3D);
+        mDevice->SetPixelShader(mRGBAPSMask3D);
+      }
+      maskTexRegister = 1;
+      break;
+    case COMPONENTLAYERPASS1:
+      mDevice->SetVertexShader(mLayerVSMask);
+      mDevice->SetPixelShader(mComponentPass1PSMask);
+      maskTexRegister = 2;
+      break;
+    case COMPONENTLAYERPASS2:
+      mDevice->SetVertexShader(mLayerVSMask);
+      mDevice->SetPixelShader(mComponentPass2PSMask);
+      maskTexRegister = 2;
+      break;
+    case YCBCRLAYER:
+      mDevice->SetVertexShader(mLayerVSMask);
+      mDevice->SetPixelShader(mYCbCrPSMask);
+      maskTexRegister = 3;
+      break;
+    case SOLIDCOLORLAYER:
+      mDevice->SetVertexShader(mLayerVSMask);
+      mDevice->SetPixelShader(mSolidColorPSMask);
+      maskTexRegister = 0;
+      break;
+  }
+  return maskTexRegister;
+}
+
+void
+DeviceManagerD3D9::SetShaderMode(ShaderMode aMode, Layer* aMask, bool aIs2D)
+{
+  MaskType maskType = MaskNone;
+  if (aMask) {
+    maskType = aIs2D ? Mask2d : Mask3d;
+  }
+  uint32_t maskTexRegister = SetShaderMode(aMode, maskType);
+  if (aMask) {
+    // register allocations are taken from LayerManagerD3D9Shaders.h after
+    // the shaders are compiled (genshaders.sh)
+    if (!LoadMaskTexture(aMask, mDevice, maskTexRegister)) {
+      // if we can't load the mask, fall back to unmasked rendering
+      NS_WARNING("Could not load texture for mask layer.");
+      SetShaderMode(aMode, MaskNone);
+    }
   }
 }
 
 bool
 DeviceManagerD3D9::VerifyReadyForRendering()
 {
   HRESULT hr = mDevice->TestCooperativeLevel();
 
@@ -768,16 +792,23 @@ DeviceManagerD3D9::VerifyCaps()
       (caps.VertexShaderVersion & 0xffff) < 0x200) {
     return false;
   }
 
   if (HAS_CAP(caps.Caps2, D3DCAPS2_DYNAMICTEXTURES)) {
     mHasDynamicTextures = true;
   }
 
+  if (HAS_CAP(caps.TextureAddressCaps, D3DPTADDRESSCAPS_WRAP) &&
+      LACKS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_NONPOW2CONDITIONAL)) {
+    mTextureAddressingMode = D3DTADDRESS_WRAP;
+  } else {
+    gfxPlatform::DisableBufferRotation();
+  }
+
   return true;
 }
 
 bool
 DeviceManagerD3D9::CreateVertexBuffer()
 {
   HRESULT hr;
 
--- a/gfx/layers/d3d9/DeviceManagerD3D9.h
+++ b/gfx/layers/d3d9/DeviceManagerD3D9.h
@@ -6,32 +6,65 @@
 #ifndef GFX_DEVICEMANAGERD3D9_H
 #define GFX_DEVICEMANAGERD3D9_H
 
 #include "gfxTypes.h"
 #include "nsRect.h"
 #include "nsAutoPtr.h"
 #include "d3d9.h"
 #include "nsTArray.h"
+#include "mozilla/layers/CompositorTypes.h"
 
 namespace mozilla {
 namespace layers {
 
 class DeviceManagerD3D9;
 class LayerD3D9;
 class Nv3DVUtils;
 class Layer;
 
 // Shader Constant locations
 const int CBmLayerTransform = 0;
 const int CBmProjection = 4;
 const int CBvRenderTargetOffset = 8;
 const int CBvTextureCoords = 9;
 const int CBvLayerQuad = 10;
+// we don't use opacity with solid color shaders
 const int CBfLayerOpacity = 0;
+const int CBvColor = 0;
+
+/**
+ * This structure is used to pass rectangles to our shader constant. We can use
+ * this for passing rectangular areas to SetVertexShaderConstant. In the format
+ * of a 4 component float(x,y,width,height). Our vertex shader can then use
+ * this to construct rectangular positions from the 0,0-1,1 quad that we source
+ * it with.
+ */
+struct ShaderConstantRect
+{
+  float mX, mY, mWidth, mHeight;
+
+  // Provide all the commonly used argument types to prevent all the local
+  // casts in the code.
+  ShaderConstantRect(float aX, float aY, float aWidth, float aHeight)
+    : mX(aX), mY(aY), mWidth(aWidth), mHeight(aHeight)
+  { }
+
+  ShaderConstantRect(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight)
+    : mX((float)aX), mY((float)aY)
+    , mWidth((float)aWidth), mHeight((float)aHeight)
+  { }
+
+  ShaderConstantRect(int32_t aX, int32_t aY, float aWidth, float aHeight)
+    : mX((float)aX), mY((float)aY), mWidth(aWidth), mHeight(aHeight)
+  { }
+
+  // For easy passing to SetVertexShaderConstantF.
+  operator float* () { return &mX; }
+};
 
 /**
  * SwapChain class, this class manages the swap chain belonging to a
  * LayerManagerD3D9.
  */
 class SwapChainD3D9
 {
   NS_INLINE_DECL_REFCOUNTING(SwapChainD3D9)
@@ -45,21 +78,24 @@ public:
    * swap chain belonging to this device will the device draw to it. Passed in
    * is the size of the swap chain. If the window size differs from the size
    * during the last call to this function the swap chain will resize. Note that
    * in no case does this function guarantee the backbuffer to still have its
    * old content.
    */
   bool PrepareForRendering();
 
+  already_AddRefed<IDirect3DSurface9> GetBackBuffer();
+
   /**
    * This function will present the selected rectangle of the swap chain to
    * its associated window.
    */
   void Present(const nsIntRect &aRect);
+  void Present();
 
 private:
   friend class DeviceManagerD3D9;
 
   SwapChainD3D9(DeviceManagerD3D9 *aDeviceManager);
   
   bool Init(HWND hWnd);
 
@@ -78,23 +114,18 @@ private:
  * Device manager, this class is used by the layer managers to share the D3D9
  * device and create swap chains for the individual windows the layer managers
  * belong to.
  */
 class DeviceManagerD3D9 MOZ_FINAL
 {
 public:
   DeviceManagerD3D9();
-  NS_IMETHOD_(nsrefcnt) AddRef(void);
-  NS_IMETHOD_(nsrefcnt) Release(void);
-protected:
-  nsAutoRefCnt mRefCnt;
-  NS_DECL_OWNINGTHREAD
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DeviceManagerD3D9)
 
-public:
   bool Init();
 
   /**
    * Sets up the render state for the device for layer rendering.
    */
   void SetupRenderState();
 
   /**
@@ -113,16 +144,18 @@ public:
     RGBALAYER,
     COMPONENTLAYERPASS1,
     COMPONENTLAYERPASS2,
     YCBCRLAYER,
     SOLIDCOLORLAYER
   };
 
   void SetShaderMode(ShaderMode aMode, Layer* aMask, bool aIs2D);
+  // returns the register to be used for the mask texture, if appropriate
+  uint32_t SetShaderMode(ShaderMode aMode, MaskType aMaskType);
 
   /** 
    * Return pointer to the Nv3DVUtils instance 
    */ 
   Nv3DVUtils *GetNv3DVUtils()  { return mNv3DVUtils; }
 
   /**
    * Returns true if this device was removed.
@@ -134,16 +167,18 @@ public:
   /**
    * We keep a list of all layers here that may have hardware resource allocated
    * so we can clean their resources on reset.
    */
   nsTArray<LayerD3D9*> mLayersWithResources;
 
   int32_t GetMaxTextureSize() { return mMaxTextureSize; }
 
+  static uint32_t sMaskQuadRegister;
+
 private:
   friend class SwapChainD3D9;
 
   ~DeviceManagerD3D9();
 
   /**
    * This function verifies the device is ready for rendering, internally this
    * will test the cooperative level of the device and reset the device if
@@ -217,16 +252,22 @@ private:
 
   /* we use this to help track if our device temporarily or permanently lost */
   HMONITOR mDeviceMonitor;
 
   uint32_t mDeviceResetCount;
 
   uint32_t mMaxTextureSize;
 
+  /**
+   * Wrap (repeat) or clamp textures. We prefer the former so we can do buffer
+   * rotation, but some older hardware doesn't support it.
+   */
+  D3DTEXTUREADDRESS mTextureAddressingMode;
+
   /* If this device supports dynamic textures */
   bool mHasDynamicTextures;
 
   /* If this device was removed */
   bool mDeviceWasRemoved;
 
   /* Nv3DVUtils instance */ 
   nsAutoPtr<Nv3DVUtils> mNv3DVUtils; 
--- a/gfx/layers/d3d9/LayerManagerD3D9.h
+++ b/gfx/layers/d3d9/LayerManagerD3D9.h
@@ -17,46 +17,16 @@
 #include "DeviceManagerD3D9.h"
 
 namespace mozilla {
 namespace layers {
 
 class LayerD3D9;
 class ThebesLayerD3D9;
 
-/**
- * This structure is used to pass rectangles to our shader constant. We can use
- * this for passing rectangular areas to SetVertexShaderConstant. In the format
- * of a 4 component float(x,y,width,height). Our vertex shader can then use
- * this to construct rectangular positions from the 0,0-1,1 quad that we source
- * it with.
- */
-struct ShaderConstantRect
-{
-  float mX, mY, mWidth, mHeight;
-
-  // Provide all the commonly used argument types to prevent all the local
-  // casts in the code.
-  ShaderConstantRect(float aX, float aY, float aWidth, float aHeight)
-    : mX(aX), mY(aY), mWidth(aWidth), mHeight(aHeight)
-  { }
-
-  ShaderConstantRect(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight)
-    : mX((float)aX), mY((float)aY)
-    , mWidth((float)aWidth), mHeight((float)aHeight)
-  { }
-
-  ShaderConstantRect(int32_t aX, int32_t aY, float aWidth, float aHeight)
-    : mX((float)aX), mY((float)aY), mWidth(aWidth), mHeight(aHeight)
-  { }
-
-  // For easy passing to SetVertexShaderConstantF.
-  operator float* () { return &mX; }
-};
-
 /*
  * This is the LayerManager used for Direct3D 9. For now this will render on
  * the main thread.
  */
 class LayerManagerD3D9 : public LayerManager {
 public:
   LayerManagerD3D9(nsIWidget *aWidget);
   virtual ~LayerManagerD3D9();
new file mode 100644
--- /dev/null
+++ b/gfx/layers/d3d9/TextureD3D9.cpp
@@ -0,0 +1,628 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * 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 "TextureD3D9.h"
+#include "CompositorD3D9.h"
+#include "gfxContext.h"
+#include "gfxImageSurface.h"
+#include "Effects.h"
+#include "ipc/AutoOpenSurface.h"
+#include "mozilla/layers/YCbCrImageDataSerializer.h"
+#include "gfxWindowsPlatform.h"
+
+using namespace mozilla::gfx;
+
+namespace mozilla {
+namespace layers {
+
+TemporaryRef<DeprecatedTextureHost>
+CreateDeprecatedTextureHostD3D9(SurfaceDescriptorType aDescriptorType,
+                      uint32_t aDeprecatedTextureHostFlags,
+                      uint32_t aTextureFlags)
+{
+  RefPtr<DeprecatedTextureHost> result;
+  if (aDescriptorType == SurfaceDescriptor::TYCbCrImage) {
+    result = new DeprecatedTextureHostYCbCrD3D9();
+  } else if (aDescriptorType == SurfaceDescriptor::TSurfaceDescriptorD3D9) {
+    result = new DeprecatedTextureHostSystemMemD3D9();
+  } else {
+    result = new DeprecatedTextureHostShmemD3D9();
+  }
+
+  result->SetFlags(aTextureFlags);
+
+  return result.forget();
+}
+
+
+CompositingRenderTargetD3D9::CompositingRenderTargetD3D9(IDirect3DTexture9* aTexture,
+                                                         SurfaceInitMode aInit,
+                                                         const gfx::IntSize& aSize)
+  : mInitMode(aInit)
+  , mInitialized(false)
+{
+  MOZ_COUNT_CTOR(CompositingRenderTargetD3D9);
+  MOZ_ASSERT(aTexture);
+
+  mTextures[0] = aTexture;
+  HRESULT hr = mTextures[0]->GetSurfaceLevel(0, getter_AddRefs(mSurface));
+  NS_ASSERTION(mSurface, "Couldn't create surface for texture");
+  TextureSourceD3D9::SetSize(aSize);
+}
+
+CompositingRenderTargetD3D9::CompositingRenderTargetD3D9(IDirect3DSurface9* aSurface,
+                                                         SurfaceInitMode aInit,
+                                                         const gfx::IntSize& aSize)
+  : mSurface(aSurface)
+  , mInitMode(aInit)
+  , mInitialized(false)
+{
+  MOZ_COUNT_CTOR(CompositingRenderTargetD3D9);
+  MOZ_ASSERT(mSurface);
+  TextureSourceD3D9::SetSize(aSize);
+}
+
+CompositingRenderTargetD3D9::~CompositingRenderTargetD3D9()
+{
+  MOZ_COUNT_DTOR(CompositingRenderTargetD3D9);
+}
+
+void
+CompositingRenderTargetD3D9::BindRenderTarget(IDirect3DDevice9* aDevice)
+{
+  aDevice->SetRenderTarget(0, mSurface);
+  if (!mInitialized &&
+      mInitMode == INIT_MODE_CLEAR) {
+    mInitialized = true;
+    aDevice->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 0), 0, 0);
+  }
+}
+
+IntSize
+CompositingRenderTargetD3D9::GetSize() const
+{
+  return TextureSourceD3D9::GetSize();
+}
+
+DeprecatedTextureHostD3D9::DeprecatedTextureHostD3D9()
+  : mIsTiled(false)
+  , mCurrentTile(0)
+  , mIterating(false)
+{
+  MOZ_COUNT_CTOR(DeprecatedTextureHostD3D9);
+}
+
+DeprecatedTextureHostD3D9::~DeprecatedTextureHostD3D9()
+{
+  MOZ_COUNT_DTOR(DeprecatedTextureHostD3D9);
+}
+
+IntSize
+DeprecatedTextureHostD3D9::GetSize() const
+{
+  if (mIterating) {
+    gfx::IntRect rect = GetTileRect(mCurrentTile);
+    return gfx::IntSize(rect.width, rect.height);
+  }
+  return TextureSourceD3D9::GetSize();
+}
+
+nsIntRect
+DeprecatedTextureHostD3D9::GetTileRect()
+{
+  IntRect rect = GetTileRect(mCurrentTile);
+  return nsIntRect(rect.x, rect.y, rect.width, rect.height);
+}
+
+static uint32_t GetRequiredTiles(uint32_t aSize, uint32_t aMaxSize)
+{
+  uint32_t requiredTiles = aSize / aMaxSize;
+  if (aSize % aMaxSize) {
+    requiredTiles++;
+  }
+  return requiredTiles;
+}
+
+void
+DeprecatedTextureHostD3D9::SetCompositor(Compositor* aCompositor)
+{
+  mCompositor = static_cast<CompositorD3D9*>(aCompositor);
+  mDevice = mCompositor ? mCompositor->device() : nullptr;
+}
+
+static TemporaryRef<IDirect3DTexture9>
+DataToTexture(IDirect3DDevice9 *aDevice,
+              unsigned char *aData,
+              int aStride,
+              const gfxIntSize &aSize,
+              _D3DFORMAT aFormat,
+              uint32_t aBPP)
+{
+  RefPtr<IDirect3DTexture9> texture;
+  nsRefPtr<IDirect3DDevice9Ex> deviceEx;
+  aDevice->QueryInterface(IID_IDirect3DDevice9Ex,
+                          (void**)getter_AddRefs(deviceEx));
+
+  RefPtr<IDirect3DSurface9> surface;
+  D3DLOCKED_RECT lockedRect;
+  if (deviceEx) {
+    // D3D9Ex doesn't support managed textures. We could use dynamic textures
+    // here but since Images are immutable that probably isn't such a great
+    // idea.
+    if (FAILED(aDevice->
+               CreateTexture(aSize.width, aSize.height,
+                             1, 0, aFormat, D3DPOOL_DEFAULT,
+                             byRef(texture), nullptr)))
+    {
+      return nullptr;
+    }
+
+    RefPtr<IDirect3DTexture9> tmpTexture;
+    if (FAILED(aDevice->
+               CreateTexture(aSize.width, aSize.height,
+                             1, 0, aFormat, D3DPOOL_SYSTEMMEM,
+                             byRef(tmpTexture), nullptr)))
+    {
+      return nullptr;
+    }
+
+    tmpTexture->GetSurfaceLevel(0, byRef(surface));
+    surface->LockRect(&lockedRect, NULL, 0);
+    NS_ASSERTION(lockedRect.pBits, "Could not lock surface");
+  } else {
+    if (FAILED(aDevice->
+               CreateTexture(aSize.width, aSize.height,
+                             1, 0, aFormat, D3DPOOL_MANAGED,
+                             byRef(texture), nullptr))) {
+      return nullptr;
+    }
+
+    /* lock the entire texture */
+    texture->LockRect(0, &lockedRect, nullptr, 0);
+  }
+
+  uint32_t width = aSize.width * aBPP;
+
+  for (int y = 0; y < aSize.height; y++) {
+    memcpy((char*)lockedRect.pBits + lockedRect.Pitch * y,
+            aData + aStride * y,
+            width);
+  }
+
+  if (deviceEx) {
+    surface->UnlockRect();
+    nsRefPtr<IDirect3DSurface9> dstSurface;
+    texture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
+    aDevice->UpdateSurface(surface, NULL, dstSurface, NULL);
+  } else {
+    texture->UnlockRect(0);
+  }
+
+  return texture.forget();
+}
+
+void
+DeprecatedTextureHostShmemD3D9::UpdateImpl(const SurfaceDescriptor& aImage,
+                                 nsIntRegion *aRegion,
+                                 nsIntPoint *aOffset)
+{
+  MOZ_ASSERT(aImage.type() == SurfaceDescriptor::TShmem ||
+             aImage.type() == SurfaceDescriptor::TMemoryImage);
+  MOZ_ASSERT(mCompositor, "Must have compositor to update.");
+
+  AutoOpenSurface openSurf(OPEN_READ_ONLY, aImage);
+
+  nsRefPtr<gfxImageSurface> surf = openSurf.GetAsImage();
+
+  gfxIntSize size = surf->GetSize();
+  mSize = IntSize(size.width, size.height);
+
+  uint32_t bpp = 0;
+
+  _D3DFORMAT format = D3DFMT_A8R8G8B8;
+  switch (surf->Format()) {
+  case gfxImageSurface::ImageFormatRGB24:
+    mFormat = FORMAT_B8G8R8X8;
+    format = D3DFMT_X8R8G8B8;
+    bpp = 4;
+    break;
+  case gfxImageSurface::ImageFormatARGB32:
+    mFormat = FORMAT_B8G8R8A8;
+    format = D3DFMT_A8R8G8B8;
+    bpp = 4;
+    break;
+  case gfxImageSurface::ImageFormatA8:
+    mFormat = FORMAT_A8;
+    format = D3DFMT_A8;
+    bpp = 1;
+    break;
+  default:
+    NS_ERROR("Bad image format");
+  }
+
+  int32_t maxSize = mCompositor->GetMaxTextureSize();
+  if (size.width <= maxSize && size.height <= maxSize) {
+    mTextures[0] = DataToTexture(mDevice,
+                                 surf->Data(), surf->Stride(),
+                                 size, format, bpp);
+    NS_ASSERTION(mTextures[0], "Could not upload texture");
+    mIsTiled = false;
+  } else {
+    mIsTiled = true;
+    uint32_t tileCount = GetRequiredTiles(size.width, maxSize) *
+                         GetRequiredTiles(size.height, maxSize);
+    mTileTextures.resize(tileCount);
+
+    for (uint32_t i = 0; i < tileCount; i++) {
+      IntRect tileRect = GetTileRect(i);
+      unsigned char* data = surf->Data() +
+                            tileRect.y * surf->Stride() +
+                            tileRect.x * bpp;
+      mTileTextures[i] = DataToTexture(mDevice,
+                                       data,
+                                       surf->Stride(),
+                                       gfxIntSize(tileRect.width, tileRect.height),
+                                       format,
+                                       bpp);
+    }
+  }
+}
+
+IntRect
+DeprecatedTextureHostD3D9::GetTileRect(uint32_t aID) const
+{
+  uint32_t maxSize = mCompositor->GetMaxTextureSize();
+  uint32_t horizontalTiles = GetRequiredTiles(mSize.width, maxSize);
+  uint32_t verticalTiles = GetRequiredTiles(mSize.height, maxSize);
+
+  uint32_t verticalTile = aID / horizontalTiles;
+  uint32_t horizontalTile = aID % horizontalTiles;
+
+  return IntRect(horizontalTile * maxSize,
+                 verticalTile * maxSize,
+                 horizontalTile < (horizontalTiles - 1) ? maxSize : mSize.width % maxSize,
+                 verticalTile < (verticalTiles - 1) ? maxSize : mSize.height % maxSize);
+}
+
+void
+DeprecatedTextureHostYCbCrD3D9::SetCompositor(Compositor* aCompositor)
+{
+  CompositorD3D9 *d3dCompositor = static_cast<CompositorD3D9*>(aCompositor);
+  mDevice = d3dCompositor ? d3dCompositor->device() : nullptr;
+}
+
+IntSize
+DeprecatedTextureHostYCbCrD3D9::GetSize() const
+{
+  return TextureSourceD3D9::GetSize();
+}
+
+void
+DeprecatedTextureHostYCbCrD3D9::UpdateImpl(const SurfaceDescriptor& aImage,
+                                 nsIntRegion *aRegion,
+                                 nsIntPoint *aOffset)
+{
+  MOZ_ASSERT(aImage.type() == SurfaceDescriptor::TYCbCrImage);
+
+  YCbCrImageDataDeserializer yuvDeserializer(aImage.get_YCbCrImage().data().get<uint8_t>());
+
+  gfxIntSize gfxCbCrSize = yuvDeserializer.GetCbCrSize();
+  gfxIntSize size = yuvDeserializer.GetYSize();
+  mSize = IntSize(size.width, size.height);
+  mStereoMode = yuvDeserializer.GetStereoMode();
+
+  mTextures[0] = DataToTexture(mDevice,
+                               yuvDeserializer.GetYData(),
+                               yuvDeserializer.GetYStride(),
+                               size,
+                               D3DFMT_L8, 1);
+  mTextures[1] = DataToTexture(mDevice,
+                               yuvDeserializer.GetCbData(),
+                               yuvDeserializer.GetCbCrStride(),
+                               gfxCbCrSize,
+                               D3DFMT_L8, 1);
+  mTextures[2] = DataToTexture(mDevice,
+                               yuvDeserializer.GetCrData(),
+                               yuvDeserializer.GetCbCrStride(),
+                               gfxCbCrSize,
+                               D3DFMT_L8, 1);
+}
+
+// aTexture should be in SYSTEMMEM, returns a texture in the default
+// pool (that is, in video memory).
+static TemporaryRef<IDirect3DTexture9>
+TextureToTexture(IDirect3DDevice9* aDevice,
+                 IDirect3DTexture9* aTexture,
+                 const IntSize& aSize,
+                 _D3DFORMAT aFormat)
+{
+  RefPtr<IDirect3DTexture9> texture;
+  if (FAILED(aDevice->
+              CreateTexture(aSize.width, aSize.height,
+                            1, 0, aFormat, D3DPOOL_DEFAULT,
+                            byRef(texture), nullptr))) {
+    return nullptr;
+  }
+
+  HRESULT hr = aDevice->UpdateTexture(aTexture, texture);
+  if (FAILED(hr)) {
+    return nullptr;
+  }
+
+  return texture.forget();
+}
+
+void
+DeprecatedTextureHostSystemMemD3D9::UpdateImpl(const SurfaceDescriptor& aImage,
+                                     nsIntRegion *aRegion,
+                                     nsIntPoint *aOffset)
+{
+  MOZ_ASSERT(aImage.type() == SurfaceDescriptor::TSurfaceDescriptorD3D9);
+  MOZ_ASSERT(mCompositor, "Must have compositor to update.");
+
+  IDirect3DTexture9* texture =
+    reinterpret_cast<IDirect3DTexture9*>(aImage.get_SurfaceDescriptorD3D9().texture());
+
+  if (!texture) {
+    mTextures[0] = nullptr;
+    return;
+  }
+
+  D3DSURFACE_DESC desc;
+  texture->GetLevelDesc(0, &desc);
+  mSize.width = desc.Width;
+  mSize.height = desc.Height;
+
+  _D3DFORMAT format = desc.Format;
+  uint32_t bpp = 0;
+  switch (format) {
+  case D3DFMT_X8R8G8B8:
+    mFormat = FORMAT_B8G8R8X8;
+    bpp = 4;
+    break;
+  case D3DFMT_A8R8G8B8:
+    mFormat = FORMAT_B8G8R8A8;
+    bpp = 4;
+    break;
+  case D3DFMT_A8:
+    mFormat = FORMAT_A8;
+    bpp = 1;
+    break;
+  default:
+    NS_ERROR("Bad image format");
+  }
+
+  int32_t maxSize = mCompositor->GetMaxTextureSize();
+  if (mSize.width <= maxSize && mSize.height <= maxSize) {
+    mIsTiled = false;
+
+    mTextures[0] = TextureToTexture(mDevice, texture, mSize, format);
+    NS_ASSERTION(mTextures[0], "Could not upload texture");
+  } else {
+    mIsTiled = true;
+
+    uint32_t tileCount = GetRequiredTiles(mSize.width, maxSize) *
+                         GetRequiredTiles(mSize.height, maxSize);
+    mTileTextures.resize(tileCount);
+
+    for (uint32_t i = 0; i < tileCount; i++) {
+      IntRect tileRect = GetTileRect(i);
+      RECT d3dTileRect;
+      d3dTileRect.left = tileRect.x;
+      d3dTileRect.top = tileRect.y;
+      d3dTileRect.right = tileRect.XMost();
+      d3dTileRect.bottom = tileRect.YMost();
+      D3DLOCKED_RECT lockedRect;
+      texture->LockRect(0, &lockedRect, &d3dTileRect, 0);
+      mTileTextures[i] = DataToTexture(mDevice,
+                                       reinterpret_cast<unsigned char*>(lockedRect.pBits),
+                                       lockedRect.Pitch,
+                                       gfxIntSize(tileRect.width, tileRect.height),
+                                       format,
+                                       bpp);
+      texture->UnlockRect(0);
+    }
+  }
+}
+
+DeprecatedTextureClientD3D9::DeprecatedTextureClientD3D9(CompositableForwarder* aCompositableForwarder,
+                                     const TextureInfo& aTextureInfo)
+  : DeprecatedTextureClient(aCompositableForwarder, aTextureInfo)
+  , mDC(nullptr)
+  , mTextureLocked(false)
+{
+  MOZ_COUNT_CTOR(DeprecatedTextureClientD3D9);
+}
+
+DeprecatedTextureClientD3D9::~DeprecatedTextureClientD3D9()
+{
+  MOZ_COUNT_DTOR(DeprecatedTextureClientD3D9);
+  Unlock();
+  mDescriptor = SurfaceDescriptor();
+
+  ClearDT();
+}
+
+bool
+DeprecatedTextureClientD3D9::EnsureAllocated(gfx::IntSize aSize,
+                                   gfxASurface::gfxContentType aType)
+{
+  if (mTexture) {
+    D3DSURFACE_DESC desc;
+    mTexture->GetLevelDesc(0, &desc);
+
+    if (desc.Width == aSize.width &&
+        desc.Height == aSize.height) {
+      return true;
+    }
+
+    Unlock();
+    mD3D9Surface = nullptr;
+    mTexture = nullptr;
+  }
+
+  mSize = aSize;
+
+  _D3DFORMAT format = D3DFMT_A8R8G8B8;
+  switch (aType) {
+  case gfxASurface::CONTENT_COLOR:
+    format = D3DFMT_X8R8G8B8;
+    mIsOpaque = true;
+    break;
+  case gfxASurface::CONTENT_COLOR_ALPHA:
+    format = D3DFMT_A8R8G8B8;
+    mIsOpaque = false;
+    break;
+  case gfxASurface::CONTENT_ALPHA:
+    format = D3DFMT_A8;
+    mIsOpaque = true;
+    break;
+  default:
+    NS_ERROR("Bad image type");
+  }
+
+  IDirect3DDevice9 *device = gfxWindowsPlatform::GetPlatform()->GetD3D9Device();
+  if (!device ||
+      FAILED(device->
+               CreateTexture(aSize.width, aSize.height,
+                             1, 0, format, D3DPOOL_SYSTEMMEM,
+                             getter_AddRefs(mTexture), nullptr)))
+  {
+    NS_WARNING("Could not create texture");
+    return false;
+  }
+
+  MOZ_ASSERT(mTexture);
+  mDescriptor = SurfaceDescriptorD3D9(reinterpret_cast<uintptr_t>(mTexture.get()));
+
+  if (!mIsOpaque) {
+    nsRefPtr<gfxASurface> surface = LockSurface();
+    nsRefPtr<gfxContext> ctx = new gfxContext(surface);
+    ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
+    ctx->SetColor(gfxRGBA(0.0, 0.0, 0.0, 0.0));
+    ctx->Paint();
+    Unlock();
+  }
+
+  mContentType = aType;
+  return true;
+}
+
+gfxASurface*
+DeprecatedTextureClientD3D9::LockSurface()
+{
+  if (mSurface) {
+    return mSurface.get();
+  }
+
+  MOZ_ASSERT(mTexture, "Cannot lock surface without a texture to lock");
+
+  if (mIsOpaque) {
+    MOZ_ASSERT(!mTextureLocked, "Shouldn't lock texture and have a surface");
+    if (!mD3D9Surface) {
+      HRESULT hr = mTexture->GetSurfaceLevel(0, getter_AddRefs(mD3D9Surface));
+      if (FAILED(hr)) {
+        NS_WARNING("Failed to get texture surface level.");
+        return nullptr;
+      }
+    }
+
+    if (!mDC) {
+      HRESULT hr = mD3D9Surface->GetDC(&mDC);
+      if (FAILED(hr)) {
+        NS_WARNING("Failed to get device context for texture surface.");
+        return nullptr;
+      }
+    }
+    NS_ASSERTION(mDC, "We need a DC here");
+    mSurface = new gfxWindowsSurface(mDC);
+  } else {
+    // d3d9 SYSTEMMEM surfaces do not support GDI with an alpha channel
+    MOZ_ASSERT(!mD3D9Surface && !mDC, "Shouldn't lock texture and have a surface");
+    if (!mTextureLocked) {
+      D3DLOCKED_RECT lockedRect;
+      mTexture->LockRect(0, &lockedRect, nullptr, 0);
+      mTextureLocked = true;
+
+      mSurface = new gfxImageSurface(reinterpret_cast<unsigned char*>(lockedRect.pBits),
+                                     gfxIntSize(mSize.width, mSize.height),
+                                     lockedRect.Pitch,
+                                     gfxASurface::ImageFormatARGB32);
+    }
+  }
+
+  NS_ASSERTION(mSurface, "should have a surface one way or the other");
+  return mSurface.get();
+}
+
+DrawTarget*
+DeprecatedTextureClientD3D9::LockDrawTarget()
+{
+  if (!mDrawTarget) {
+    mDrawTarget =
+      gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(LockSurface(), mSize);
+  }
+
+  return mDrawTarget.get();
+}
+
+void
+DeprecatedTextureClientD3D9::Unlock()
+{
+  if (mDrawTarget) {
+    mDrawTarget->Flush();
+    mDrawTarget = nullptr;
+  }
+
+  if (mTextureLocked) {
+    MOZ_ASSERT(!mD3D9Surface && !mDC, "Shouldn't lock texture and have a surface");
+    mTexture->UnlockRect(0);
+    mTextureLocked = false;
+  } else if (mDC) {
+    MOZ_ASSERT(mD3D9Surface, "we need a D3D9Surface to release our DC");
+    MOZ_ASSERT(!mTextureLocked, "Shouldn't lock texture and have a surface");
+    mD3D9Surface->ReleaseDC(mDC);
+    mDC = nullptr;
+  }
+
+  if (mSurface) {
+    mSurface = nullptr;
+  }
+}
+
+void
+DeprecatedTextureClientD3D9::SetDescriptor(const SurfaceDescriptor& aDescriptor)
+{
+  if (aDescriptor.type() == SurfaceDescriptor::Tnull_t) {
+    EnsureAllocated(mSize, mContentType);
+    return;
+  }
+
+  mDescriptor = aDescriptor;
+  mSurface = nullptr;
+  ClearDT();
+
+  if (aDescriptor.type() == SurfaceDescriptor::T__None) {
+    return;
+  }
+
+  MOZ_ASSERT(aDescriptor.type() == SurfaceDescriptor::TSurfaceDescriptorD3D9);
+  Unlock();
+  mD3D9Surface = nullptr;
+  mTexture = reinterpret_cast<IDirect3DTexture9*>(
+               mDescriptor.get_SurfaceDescriptorD3D9().texture());
+}
+
+void
+DeprecatedTextureClientD3D9::ClearDT()
+{
+  // Perhaps this should be debug only.
+  if (mDrawTarget) {
+    mDrawTarget = nullptr;
+  }
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/gfx/layers/d3d9/TextureD3D9.h
@@ -0,0 +1,260 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * 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_GFX_TEXTURED3D9_H
+#define MOZILLA_GFX_TEXTURED3D9_H
+
+#include "mozilla/layers/Compositor.h"
+#include "mozilla/layers/TextureClient.h"
+#include "mozilla/layers/TextureHost.h"
+#include "gfxWindowsPlatform.h"
+#include "d3d9.h"
+#include <vector>
+
+namespace mozilla {
+namespace layers {
+
+class CompositorD3D9;
+
+class TextureSourceD3D9
+{
+public:
+  virtual IDirect3DTexture9* GetD3D9Texture() { return mTextures[0]; }
+  virtual bool IsYCbCrSource() const { return false; }
+
+  struct YCbCrTextures
+  {
+    IDirect3DTexture9 *mY;
+    IDirect3DTexture9 *mCb;
+    IDirect3DTexture9 *mCr;
+    StereoMode mStereoMode;
+  };
+
+  virtual YCbCrTextures GetYCbCrTextures() {
+    YCbCrTextures textures = { mTextures[0],
+                               mTextures[1],
+                               mTextures[2],
+                               mStereoMode };
+    return textures;
+  }
+
+protected:
+  virtual gfx::IntSize GetSize() const { return mSize; }
+  void SetSize(const gfx::IntSize& aSize) { mSize = aSize; }
+
+  gfx::IntSize mSize;
+  StereoMode mStereoMode;
+  RefPtr<IDirect3DTexture9> mTextures[3];
+};
+
+class CompositingRenderTargetD3D9 : public CompositingRenderTarget,
+                                    public TextureSourceD3D9
+{
+public:
+  CompositingRenderTargetD3D9(IDirect3DTexture9* aTexture,
+                              SurfaceInitMode aInit,
+                              const gfx::IntSize& aSize);
+  // use for rendering to the main window, cannot be rendered as a texture
+  CompositingRenderTargetD3D9(IDirect3DSurface9* aSurface,
+                              SurfaceInitMode aInit,
+                              const gfx::IntSize& aSize);
+  ~CompositingRenderTargetD3D9();
+
+  virtual TextureSourceD3D9* AsSourceD3D9() MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(mTextures[0],
+               "No texture, can't be indirectly rendered. Is this the screen backbuffer?");
+    return this;
+  }
+
+  virtual gfx::IntSize GetSize() const MOZ_OVERRIDE;
+
+  void BindRenderTarget(IDirect3DDevice9* aDevice);
+
+  IDirect3DSurface9* GetD3D9Surface() const { return mSurface; }
+
+private:
+  friend class CompositorD3D9;
+
+  nsRefPtr<IDirect3DSurface9> mSurface;
+  SurfaceInitMode mInitMode;
+  bool mInitialized;
+};
+
+// Shared functionality for non-YCbCr texture hosts
+class DeprecatedTextureHostD3D9 : public DeprecatedTextureHost
+                      , public TextureSourceD3D9
+                      , public TileIterator
+{
+public:
+  DeprecatedTextureHostD3D9();
+  virtual ~DeprecatedTextureHostD3D9();
+
+  virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE;
+
+  virtual TextureSourceD3D9* AsSourceD3D9() MOZ_OVERRIDE { return this; }
+
+  virtual IDirect3DTexture9 *GetD3D9Texture() MOZ_OVERRIDE {
+    return mIsTiled ? mTileTextures[mCurrentTile].get()
+                    : TextureSourceD3D9::GetD3D9Texture();
+  }
+
+  virtual gfx::IntSize GetSize() const MOZ_OVERRIDE;
+
+  virtual LayerRenderState GetRenderState() { return LayerRenderState(); }
+
+  virtual bool Lock() MOZ_OVERRIDE { return true; }
+
+  virtual already_AddRefed<gfxImageSurface> GetAsSurface() MOZ_OVERRIDE
+  {
+    return nullptr; // TODO: cf bug 872568
+  }
+
+  virtual void BeginTileIteration() MOZ_OVERRIDE
+  {
+    mIterating = true;
+    mCurrentTile = 0;
+  }
+  virtual void EndTileIteration() MOZ_OVERRIDE
+  {
+    mIterating = false;
+  }
+  virtual nsIntRect GetTileRect() MOZ_OVERRIDE;
+  virtual size_t GetTileCount() MOZ_OVERRIDE { return mTileTextures.size(); }
+  virtual bool NextTile() MOZ_OVERRIDE
+  {
+    return (++mCurrentTile < mTileTextures.size());
+  }
+
+  virtual TileIterator* AsTileIterator() MOZ_OVERRIDE
+  {
+    return mIsTiled ? this : nullptr;
+  }
+
+protected:
+  gfx::IntRect GetTileRect(uint32_t aID) const;
+
+  RefPtr<IDirect3DDevice9> mDevice;
+  RefPtr<CompositorD3D9> mCompositor;
+  bool mIsTiled;
+  std::vector< RefPtr<IDirect3DTexture9> > mTileTextures;
+  uint32_t mCurrentTile;
+  bool mIterating;
+};
+
+class DeprecatedTextureHostShmemD3D9 : public DeprecatedTextureHostD3D9
+{
+public:
+#ifdef MOZ_LAYERS_HAVE_LOG
+  virtual const char* Name() { return "DeprecatedTextureHostShmemD3D9"; }
+#endif
+
+protected:
+  virtual void UpdateImpl(const SurfaceDescriptor& aSurface,
+                          nsIntRegion* aRegion,
+                          nsIntPoint *aOffset = nullptr) MOZ_OVERRIDE;
+};
+
+class DeprecatedTextureHostSystemMemD3D9 : public DeprecatedTextureHostD3D9
+{
+public:
+#ifdef MOZ_LAYERS_HAVE_LOG
+  virtual const char* Name() { return "DeprecatedTextureHostSystemMemD3D9"; }
+#endif
+
+protected:
+  virtual void UpdateImpl(const SurfaceDescriptor& aSurface,
+                          nsIntRegion* aRegion,
+                          nsIntPoint *aOffset = nullptr) MOZ_OVERRIDE;
+
+  nsRefPtr<IDirect3DTexture9> mTexture;
+};
+
+class DeprecatedTextureHostYCbCrD3D9 : public DeprecatedTextureHost
+                           , public TextureSourceD3D9
+{
+public:
+  DeprecatedTextureHostYCbCrD3D9()
+    : mDevice(nullptr)
+  {
+    mFormat = gfx::FORMAT_YUV;
+  }
+
+  virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE;
+
+  virtual TextureSourceD3D9* AsSourceD3D9() MOZ_OVERRIDE { return this; }
+
+  virtual gfx::IntSize GetSize() const MOZ_OVERRIDE;
+
+  virtual bool IsYCbCrSource() const MOZ_OVERRIDE { return true; }
+
+  virtual already_AddRefed<gfxImageSurface> GetAsSurface() MOZ_OVERRIDE
+  {
+    return nullptr; // TODO: cf bug 872568
+  }
+
+#ifdef MOZ_LAYERS_HAVE_LOG
+  virtual const char* Name() MOZ_OVERRIDE
+  {
+    return "TextureImageDeprecatedTextureHostD3D11";
+  }
+#endif
+
+protected:
+  virtual void UpdateImpl(const SurfaceDescriptor& aSurface,
+                          nsIntRegion* aRegion,
+                          nsIntPoint* aOffset = nullptr) MOZ_OVERRIDE;
+
+private:
+  RefPtr<IDirect3DDevice9> mDevice;
+};
+
+// If we want to use d3d9 textures for transport, use this class.
+// If we are using shmem, then use DeprecatedTextureClientShmem with DeprecatedTextureHostShmemD3D9
+// Since we pass a raw pointer, you should not use this texture client for
+// multi-process compositing.
+class DeprecatedTextureClientD3D9 : public DeprecatedTextureClient
+{
+public:
+  DeprecatedTextureClientD3D9(CompositableForwarder* aCompositableForwarder,
+                    const TextureInfo& aTextureInfo);
+  virtual ~DeprecatedTextureClientD3D9();
+
+  virtual bool SupportsType(DeprecatedTextureClientType aType) MOZ_OVERRIDE
+  {
+    return aType == TEXTURE_CONTENT;
+  }
+
+  virtual bool EnsureAllocated(gfx::IntSize aSize,
+                               gfxASurface::gfxContentType aType) MOZ_OVERRIDE;
+
+  virtual gfxASurface* LockSurface() MOZ_OVERRIDE;
+  virtual gfx::DrawTarget* LockDrawTarget() MOZ_OVERRIDE;
+  virtual void Unlock() MOZ_OVERRIDE;
+
+  virtual void SetDescriptor(const SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE;
+  virtual gfxASurface::gfxContentType GetContentType() MOZ_OVERRIDE
+  {
+    return mContentType;
+  }
+
+private:
+  void ClearDT();
+
+  nsRefPtr<IDirect3DTexture9> mTexture;
+  nsRefPtr<gfxASurface> mSurface;
+  nsRefPtr<IDirect3DSurface9> mD3D9Surface;
+  HDC mDC;
+  RefPtr<gfx::DrawTarget> mDrawTarget;
+  gfx::IntSize mSize;
+  gfxContentType mContentType;
+  bool mTextureLocked;
+  bool mIsOpaque;
+};
+
+}
+}
+
+#endif /* MOZILLA_GFX_TEXTURED3D9_H */
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -1164,16 +1164,17 @@ ViewTransform AsyncPanZoomController::Ge
   return ViewTransform(-translation, localScale / mLastContentPaintMetrics.mDevPixelsPerCSSPixel);
 }
 
 void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetrics, bool aIsFirstPaint) {
   ReentrantMonitorAutoEnter lock(mMonitor);
 
   mLastContentPaintMetrics = aLayerMetrics;
 
+  bool isDefault = mFrameMetrics.IsDefault();
   mFrameMetrics.mMayHaveTouchListeners = aLayerMetrics.mMayHaveTouchListeners;
 
   // TODO: Once a mechanism for calling UpdateScrollOffset() when content does
   //       a scrollTo() is implemented for B2G (bug 895905), this block can be removed.
 #ifndef MOZ_WIDGET_ANDROID
   if (!mPaintThrottler.IsOutstanding()) {
     // No paint was requested, but we got one anyways. One possible cause of this
     // is that content could have fired a scrollTo(). In this case, we should take
@@ -1202,27 +1203,27 @@ void AsyncPanZoomController::NotifyLayer
     // Remote content has sync'd up to the composition geometry
     // change, so we can accept the viewport it's calculated.
     CSSToScreenScale previousResolution = mFrameMetrics.CalculateResolution();
     mFrameMetrics.mViewport = aLayerMetrics.mViewport;
     CSSToScreenScale newResolution = mFrameMetrics.CalculateResolution();
     needContentRepaint |= (previousResolution != newResolution);
   }
 
-  if (aIsFirstPaint || mFrameMetrics.IsDefault()) {
+  if (aIsFirstPaint || isDefault) {
     mPaintThrottler.ClearHistory();
     mPaintThrottler.SetMaxDurations(gNumPaintDurationSamples);
 
     mX.CancelTouch();
     mY.CancelTouch();
 
     // XXX If this is the very first time we're getting a layers update we need to
     // trigger another repaint, or the B2G browser shows stale content. This needs
     // to be investigated and fixed.
-    needContentRepaint |= (mFrameMetrics.IsDefault() && !aLayerMetrics.IsDefault());
+    needContentRepaint |= (isDefault && !aLayerMetrics.IsDefault());
 
     mFrameMetrics = aLayerMetrics;
     mState = NOTHING;
   } else if (!mFrameMetrics.mScrollableRect.IsEqualEdges(aLayerMetrics.mScrollableRect)) {
     mFrameMetrics.mScrollableRect = aLayerMetrics.mScrollableRect;
   }
 
   if (needContentRepaint) {
--- a/gfx/layers/ipc/CompositableForwarder.h
+++ b/gfx/layers/ipc/CompositableForwarder.h
@@ -36,16 +36,17 @@ class BasicTiledLayerBuffer;
 class CompositableForwarder : public ISurfaceAllocator
 {
   friend class AutoOpenSurface;
   friend class DeprecatedTextureClientShmem;
 public:
   typedef gfxASurface::gfxContentType gfxContentType;
 
   CompositableForwarder()
+    : mMultiProcess(false)
   {}
 
   /**
    * Setup the IPDL actor for aCompositable to be part of layers
    * transactions.
    */
   virtual void Connect(CompositableClient* aCompositable) = 0;
 
@@ -202,16 +203,22 @@ public:
     return mTextureFactoryIdentifier.mSupportsTextureBlitting;
   }
 
   bool SupportsPartialUploads() const
   {
     return mTextureFactoryIdentifier.mSupportsPartialUploads;
   }
 
+  bool ForwardsToDifferentProcess() const
+  {
+    return mMultiProcess;
+  }
+
 protected:
   TextureFactoryIdentifier mTextureFactoryIdentifier;
+  bool mMultiProcess;
 };
 
 } // namespace
 } // namespace
 
 #endif
--- a/gfx/layers/ipc/CompositorChild.cpp
+++ b/gfx/layers/ipc/CompositorChild.cpp
@@ -68,17 +68,18 @@ CompositorChild::Get()
   // This is only expected to be used in child processes.
   MOZ_ASSERT(XRE_GetProcessType() != GeckoProcessType_Default);
   return sCompositor;
 }
 
 PLayerTransactionChild*
 CompositorChild::AllocPLayerTransactionChild(const LayersBackend& aBackendHint,
                                              const uint64_t& aId,
-                                             TextureFactoryIdentifier*)
+                                             TextureFactoryIdentifier*,
+                                             bool*)
 {
   return new LayerTransactionChild();
 }
 
 bool
 CompositorChild::DeallocPLayerTransactionChild(PLayerTransactionChild* actor)
 {
   delete actor;
--- a/gfx/layers/ipc/CompositorChild.h
+++ b/gfx/layers/ipc/CompositorChild.h
@@ -36,17 +36,18 @@ public:
 
   static PCompositorChild* Get();
 
   static bool ChildProcessHasCompositor() { return sCompositor != nullptr; }
 protected:
   virtual PLayerTransactionChild*
     AllocPLayerTransactionChild(const LayersBackend& aBackendHint,
                                 const uint64_t& aId,
-                                TextureFactoryIdentifier* aTextureFactoryIdentifier) MOZ_OVERRIDE;
+                                TextureFactoryIdentifier* aTextureFactoryIdentifier,
+                                bool* aSuccess) MOZ_OVERRIDE;
 
   virtual bool DeallocPLayerTransactionChild(PLayerTransactionChild *aChild) MOZ_OVERRIDE;
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
 
 private:
   nsRefPtr<LayerManager> mLayerManager;
   nsCOMPtr<nsIObserver> mMemoryPressureObserver;
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -9,16 +9,17 @@
 #include "mozilla/DebugOnly.h"
 
 #include "AutoOpenSurface.h"
 #include "CompositorParent.h"
 #include "mozilla/layers/CompositorOGL.h"
 #include "mozilla/layers/BasicCompositor.h"
 #ifdef XP_WIN
 #include "mozilla/layers/CompositorD3D11.h"
+#include "mozilla/layers/CompositorD3D9.h"
 #endif
 #include "LayerTransactionParent.h"
 #include "nsIWidget.h"
 #include "nsGkAtoms.h"
 #include "RenderTrace.h"
 #include "gfxPlatform.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/layers/AsyncCompositionManager.h"
@@ -418,26 +419,23 @@ CompositorParent::ScheduleTask(Cancelabl
   } else {
     MessageLoop::current()->PostDelayedTask(FROM_HERE, task, time);
   }
 }
 
 void
 CompositorParent::NotifyShadowTreeTransaction(uint64_t aId, bool aIsFirstPaint)
 {
-  if (mApzcTreeManager) {
+  if (mApzcTreeManager &&
+      mLayerManager &&
+      mLayerManager->GetRoot()) {
     AutoResolveRefLayers resolve(mCompositionManager);
     mApzcTreeManager->UpdatePanZoomControllerTree(this, mLayerManager->GetRoot(), aIsFirstPaint, aId);
-  }
 
-  if (mLayerManager) {
-    LayerManagerComposite* managerComposite = mLayerManager->AsLayerManagerComposite();
-    if (managerComposite) {
-      managerComposite->NotifyShadowTreeTransaction();
-    }
+    mLayerManager->AsLayerManagerComposite()->NotifyShadowTreeTransaction();
   }
   ScheduleComposition();
 }
 
 void
 CompositorParent::ScheduleComposition()
 {
   if (mCurrentCompositeTask) {
@@ -598,17 +596,18 @@ CompositorParent::ShadowLayersUpdated(La
   if (layerComposite) {
     layerComposite->NotifyShadowTreeTransaction();
   }
 }
 
 PLayerTransactionParent*
 CompositorParent::AllocPLayerTransactionParent(const LayersBackend& aBackendHint,
                                                const uint64_t& aId,
-                                               TextureFactoryIdentifier* aTextureFactoryIdentifier)
+                                               TextureFactoryIdentifier* aTextureFactoryIdentifier,
+                                               bool *aSuccess)
 {
   MOZ_ASSERT(aId == 0);
 
   // mWidget doesn't belong to the compositor thread, so it should be set to
   // nullptr before returning from this method, to avoid accessing it elsewhere.
   nsIntRect rect;
   mWidget->GetClientBounds(rect);
 
@@ -620,33 +619,39 @@ CompositorParent::AllocPLayerTransaction
                                                   mUseExternalSurfaceSize));
   } else if (aBackendHint == mozilla::layers::LAYERS_BASIC) {
     mLayerManager =
       new LayerManagerComposite(new BasicCompositor(mWidget));
 #ifdef XP_WIN
   } else if (aBackendHint == mozilla::layers::LAYERS_D3D11) {
     mLayerManager =
       new LayerManagerComposite(new CompositorD3D11(mWidget));
+  } else if (aBackendHint == mozilla::layers::LAYERS_D3D9) {
+    mLayerManager =
+      new LayerManagerComposite(new CompositorD3D9(mWidget));
 #endif
   } else {
-    NS_ERROR("Unsupported backend selected for Async Compositor");
-    return nullptr;
+    NS_WARNING("Unsupported backend selected for Async Compositor");
+    *aSuccess = false;
+    return new LayerTransactionParent(nullptr, this, 0);
   }
 
   mWidget = nullptr;
   mLayerManager->SetCompositorID(mCompositorID);
 
   if (!mLayerManager->Initialize()) {
-    NS_ERROR("Failed to init Compositor");
-    return nullptr;
+    NS_WARNING("Failed to init Compositor");
+    *aSuccess = false;
+    return new LayerTransactionParent(nullptr, this, 0);
   }
 
   mCompositionManager = new AsyncCompositionManager(mLayerManager);
 
   *aTextureFactoryIdentifier = mLayerManager->GetTextureFactoryIdentifier();
+  *aSuccess = true;
   return new LayerTransactionParent(mLayerManager, this, 0);
 }
 
 bool
 CompositorParent::DeallocPLayerTransactionParent(PLayerTransactionParent* actor)
 {
   delete actor;
   return true;
@@ -826,17 +831,18 @@ public:
   virtual bool RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
                                 SurfaceDescriptor* aOutSnapshot)
   { return true; }
   virtual bool RecvFlushRendering() MOZ_OVERRIDE { return true; }
 
   virtual PLayerTransactionParent*
     AllocPLayerTransactionParent(const LayersBackend& aBackendType,
                                  const uint64_t& aId,
-                                 TextureFactoryIdentifier* aTextureFactoryIdentifier) MOZ_OVERRIDE;
+                                 TextureFactoryIdentifier* aTextureFactoryIdentifier,
+                                 bool *aSuccess) MOZ_OVERRIDE;
 
   virtual bool DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers) MOZ_OVERRIDE;
 
   virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
                                    const TargetConfig& aTargetConfig,
                                    bool isFirstPaint) MOZ_OVERRIDE;
 
 private:
@@ -907,27 +913,32 @@ CrossProcessCompositorParent::ActorDestr
   MessageLoop::current()->PostTask(
     FROM_HERE,
     NewRunnableMethod(this, &CrossProcessCompositorParent::DeferredDestroy));
 }
 
 PLayerTransactionParent*
 CrossProcessCompositorParent::AllocPLayerTransactionParent(const LayersBackend& aBackendType,
                                                            const uint64_t& aId,
-                                                           TextureFactoryIdentifier* aTextureFactoryIdentifier)
+                                                           TextureFactoryIdentifier* aTextureFactoryIdentifier,
+                                                           bool *aSuccess)
 {
   MOZ_ASSERT(aId != 0);
 
   if (sIndirectLayerTrees[aId].mParent) {
     LayerManagerComposite* lm = sIndirectLayerTrees[aId].mParent->GetLayerManager();
     *aTextureFactoryIdentifier = lm->GetTextureFactoryIdentifier();
+    *aSuccess = true;
     return new LayerTransactionParent(lm, this, aId);
   }
 
   NS_WARNING("Created child without a matching parent?");
+  // XXX: should be false, but that causes us to fail some tests on Mac w/ OMTC.
+  // Bug 900745. change *aSuccess to false to see test failures.
+  *aSuccess = true;
   return new LayerTransactionParent(nullptr, this, aId);
 }
 
 bool
 CrossProcessCompositorParent::DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers)
 {
   LayerTransactionParent* slp = static_cast<LayerTransactionParent*>(aLayers);
   RemoveIndirectTree(slp->GetId());
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -203,17 +203,18 @@ public:
   /**
    * Returns true if the calling thrad is the compositor thread.
    */
   static bool IsInCompositorThread();
 protected:
   virtual PLayerTransactionParent*
     AllocPLayerTransactionParent(const LayersBackend& aBackendHint,
                                  const uint64_t& aId,
-                                 TextureFactoryIdentifier* aTextureFactoryIdentifier);
+                                 TextureFactoryIdentifier* aTextureFactoryIdentifier,
+                                 bool* aSuccess);
   virtual bool DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers);
   virtual void ScheduleTask(CancelableTask*, int);
   virtual void Composite();
   virtual void ComposeToTarget(gfxContext* aTarget);
 
   void SetEGLSurfaceSize(int width, int height);
 
 private:
--- a/gfx/layers/ipc/ISurfaceAllocator.cpp
+++ b/gfx/layers/ipc/ISurfaceAllocator.cpp
@@ -85,17 +85,20 @@ ISurfaceAllocator::AllocSurfaceDescripto
       PlatformAllocSurfaceDescriptor(aSize, aContent, aCaps, aBuffer)) {
     return true;
   }
 
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
     gfxImageFormat format =
       gfxPlatform::GetPlatform()->OptimalFormatForContent(aContent);
     int32_t stride = gfxASurface::FormatStrideForWidth(format, aSize.width);
-    uint8_t *data = new uint8_t[stride * aSize.height];
+    uint8_t *data = new (std::nothrow) uint8_t[stride * aSize.height];
+    if (!data) {
+      return false;
+    }
 #ifdef XP_MACOSX
     // Workaround a bug in Quartz where drawing an a8 surface to another a8
     // surface with OPERATOR_SOURCE still requires the destination to be clear.
     if (format == gfxASurface::ImageFormatA8) {
       memset(data, 0, stride * aSize.height);
     }
 #endif
     *aBuffer = MemoryImage((uintptr_t)data, aSize, stride, format);
@@ -128,16 +131,17 @@ ISurfaceAllocator::DestroySharedSurface(
       DeallocShmem(aSurface->get_Shmem());
       break;
     case SurfaceDescriptor::TYCbCrImage:
       DeallocShmem(aSurface->get_YCbCrImage().data());
       break;
     case SurfaceDescriptor::TRGBImage:
       DeallocShmem(aSurface->get_RGBImage().data());
       break;
+    case SurfaceDescriptor::TSurfaceDescriptorD3D9:
     case SurfaceDescriptor::TSurfaceDescriptorD3D10:
       break;
     case SurfaceDescriptor::TMemoryImage:
       delete [] (unsigned char *)aSurface->get_MemoryImage().data();
       break;
     case SurfaceDescriptor::Tnull_t:
     case SurfaceDescriptor::T__None:
       break;
--- a/gfx/layers/ipc/LayersSurfaces.ipdlh
+++ b/gfx/layers/ipc/LayersSurfaces.ipdlh
@@ -31,16 +31,21 @@ using mozilla::gfx::IntSize;
 namespace mozilla {
 namespace layers {
 
 union MaybeMagicGrallocBufferHandle {
   MagicGrallocBufferHandle;
   null_t;
 };
 
+struct SurfaceDescriptorD3D9 {
+  // IDirect3DTexture9*
+  uintptr_t texture;
+};
+
 struct SurfaceDescriptorD3D10 {
   WindowsHandle handle;
   bool hasAlpha;
 };
 
 struct SharedTextureDescriptor {
   SharedTextureShareType shareType;
   SharedTextureHandle handle;
@@ -119,16 +124,17 @@ struct SurfaceDescriptorShmem {
  struct SurfaceDescriptorMemory {
   uintptr_t data;
   SurfaceFormat format;
 };
 
 union SurfaceDescriptor {
   SurfaceDescriptorShmem;
   SurfaceDescriptorMemory;
+  SurfaceDescriptorD3D9;
   SurfaceDescriptorD3D10;
   SurfaceDescriptorX11;
   SharedTextureDescriptor;
   SurfaceStreamDescriptor;
   YCbCrImage;                 // XXX - deprecated
   SurfaceDescriptorGralloc;   // XXX - deprecated
   Shmem;                      // XXX - deprecated
   RGBImage;                   // XXX - deprecated
--- a/gfx/layers/ipc/PCompositor.ipdl
+++ b/gfx/layers/ipc/PCompositor.ipdl
@@ -55,13 +55,13 @@ parent:
   sync MakeSnapshot(SurfaceDescriptor inSnapshot)
     returns (SurfaceDescriptor outSnapshot);
 
   // Make sure any pending composites are started immediately and
   // block until they are completed.
   sync FlushRendering();
 
   sync PLayerTransaction(LayersBackend layersBackendHint, uint64_t id)
-    returns (TextureFactoryIdentifier textureFactoryIdentifier);
+    returns (TextureFactoryIdentifier textureFactoryIdentifier, bool success);
 };
 
 } // layers
 } // mozilla
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -156,16 +156,17 @@ struct AutoTxnEnd {
   ~AutoTxnEnd() { mTxn->End(); }
   Transaction* mTxn;
 };
 
 void
 CompositableForwarder::IdentifyTextureHost(const TextureFactoryIdentifier& aIdentifier)
 {
   mTextureFactoryIdentifier = aIdentifier;
+  mMultiProcess = aIdentifier.mParentProcessId != XRE_GetProcessType();
 }
 
 ShadowLayerForwarder::ShadowLayerForwarder()
  : mShadowManager(nullptr)
  , mIsFirstPaint(false)
  , mDrawColoredBorders(false)
  , mWindowOverlayChanged(false)
 {
@@ -402,19 +403,26 @@ ShadowLayerForwarder::RemoveTexture(Comp
 
 void
 ShadowLayerForwarder::UpdatedTexture(CompositableClient* aCompositable,
                                      TextureClient* aTexture,
                                      nsIntRegion* aRegion)
 {
   MaybeRegion region = aRegion ? MaybeRegion(*aRegion)
                                : MaybeRegion(null_t());
-  mTxn->AddEdit(OpUpdateTexture(nullptr, aCompositable->GetIPDLActor(),
-                                aTexture->GetID(),
-                                region));
+  if (aTexture->GetFlags() & TEXTURE_IMMEDIATE_UPLOAD) {
+    mTxn->AddPaint(OpUpdateTexture(nullptr, aCompositable->GetIPDLActor(),
+                                   aTexture->GetID(),
+                                   region));
+  } else {
+    mTxn->AddNoSwapPaint(OpUpdateTexture(nullptr, aCompositable->GetIPDLActor(),
+                                         aTexture->GetID(),
+                                         region));
+
+  }
 }
 
 void
 ShadowLayerForwarder::UseTexture(CompositableClient* aCompositable,
                                  TextureClient* aTexture)
 {
   mTxn->AddEdit(OpUseTexture(nullptr, aCompositable->GetIPDLActor(),
                              aTexture->GetID()));
--- a/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
+++ b/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
@@ -114,17 +114,18 @@ SharedPlanarYCbCrImage::AllocateAndGetNe
 
 void
 SharedPlanarYCbCrImage::SetDataNoCopy(const Data &aData)
 {
   mData = aData;
   mSize = aData.mPicSize;
   YCbCrImageDataSerializer serializer(mTextureClient->GetBuffer());
   serializer.InitializeBufferInfo(aData.mYSize,
-                                  aData.mCbCrSize);
+                                  aData.mCbCrSize,
+                                  aData.mStereoMode);
 }
 
 uint8_t*
 SharedPlanarYCbCrImage::AllocateBuffer(uint32_t aSize)
 {
   NS_ABORT_IF_FALSE(!mTextureClient->IsAllocated(),
                     "This image already has allocated data");
   if (!mTextureClient->Allocate(aSize)) {
@@ -148,17 +149,18 @@ SharedPlanarYCbCrImage::Allocate(PlanarY
                                                                aData.mCbCrSize);
 
   if (AllocateBuffer(static_cast<uint32_t>(size)) == nullptr) {
     return false;
   }
 
   YCbCrImageDataSerializer serializer(mTextureClient->GetBuffer());
   serializer.InitializeBufferInfo(aData.mYSize,
-                                  aData.mCbCrSize);
+                                  aData.mCbCrSize,
+                                  aData.mStereoMode);
   MOZ_ASSERT(serializer.IsValid());
 
   aData.mYChannel = serializer.GetYData();
   aData.mCbChannel = serializer.GetCbData();
   aData.mCrChannel = serializer.GetCrData();
 
   // copy some of aData's values in mData (most of them)
   mData.mYChannel = aData.mYChannel;
@@ -234,17 +236,18 @@ DeprecatedSharedPlanarYCbCrImage::Alloca
 
 void
 DeprecatedSharedPlanarYCbCrImage::SetDataNoCopy(const Data &aData)
 {
   mData = aData;
   mSize = aData.mPicSize;
   YCbCrImageDataSerializer serializer(mShmem.get<uint8_t>());
   serializer.InitializeBufferInfo(aData.mYSize,
-                                  aData.mCbCrSize);
+                                  aData.mCbCrSize,
+                                  aData.mStereoMode);
 }
 
 uint8_t* 
 DeprecatedSharedPlanarYCbCrImage::AllocateBuffer(uint32_t aSize)
 {
   NS_ABORT_IF_FALSE(!mAllocated, "This image already has allocated data");
   SharedMemory::SharedMemoryType shmType = OptimalShmemType();
   if (!mSurfaceAllocator->AllocUnsafeShmem(aSize, shmType, &mShmem)) {
@@ -264,17 +267,18 @@ DeprecatedSharedPlanarYCbCrImage::Alloca
                                                                aData.mCbCrSize);
 
   if (AllocateBuffer(static_cast<uint32_t>(size)) == nullptr) {
     return false;
   }
 
   YCbCrImageDataSerializer serializer(mShmem.get<uint8_t>());
   serializer.InitializeBufferInfo(aData.mYSize,
-                                  aData.mCbCrSize);
+                                  aData.mCbCrSize,
+                                  aData.mStereoMode);
   if (!serializer.IsValid() || mShmem.Size<uint8_t>() < size) {
     mSurfaceAllocator->DeallocShmem(mShmem);
     return false;
   }
 
   aData.mYChannel = serializer.GetYData();
   aData.mCbChannel = serializer.GetCbData();
   aData.mCrChannel = serializer.GetCrData();
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -47,17 +47,23 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'wind
     CPP_SOURCES += [
         'D3D9SurfaceImage.cpp',
     ]
     if CONFIG['MOZ_ENABLE_D3D9_LAYER']:
         EXPORTS += [
             'd3d9/DeviceManagerD3D9.h',
             'd3d9/LayerManagerD3D9.h',
         ]
+        EXPORTS.mozilla.layers += [
+            'CompositorD3D9.h',
+            'TextureD3D9.h',
+        ]
         CPP_SOURCES += [
+            'CompositorD3D9.cpp',
+            'TextureD3D9.cpp',
             'LayerManagerD3D9.cpp',
             'ThebesLayerD3D9.cpp',
             'ContainerLayerD3D9.cpp',
             'ImageLayerD3D9.cpp',
             'ColorLayerD3D9.cpp',
             'CanvasLayerD3D9.cpp',
             'DeviceManagerD3D9.cpp',
             'Nv3DVUtils.cpp',
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -39,16 +39,17 @@ public:
 
   virtual bool Initialize() MOZ_OVERRIDE;
 
   virtual void Destroy() MOZ_OVERRIDE;
 
   virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() MOZ_OVERRIDE
   {
     return TextureFactoryIdentifier(LAYERS_OPENGL,
+                                    XRE_GetProcessType(),
                                     GetMaxTextureSize(),
                                     mFBOTextureTarget == LOCAL_GL_TEXTURE_2D,
                                     SupportsPartialTextureUpdate());
   }
 
   virtual TemporaryRef<CompositingRenderTarget> 
   CreateRenderTarget(const gfx::IntRect &aRect, SurfaceInitMode aInit) MOZ_OVERRIDE;
 
--- a/gfx/layers/opengl/TextureClientOGL.cpp
+++ b/gfx/layers/opengl/TextureClientOGL.cpp
@@ -73,18 +73,19 @@ DeprecatedTextureClientSharedOGL::Releas
     return;
   }
   MOZ_ASSERT(mDescriptor.type() == SurfaceDescriptor::TSharedTextureDescriptor);
   mDescriptor = SurfaceDescriptor();
   // It's important our handle gets released! SharedDeprecatedTextureHostOGL will take
   // care of this for us though.
 }
 
-void
+bool
 DeprecatedTextureClientSharedOGL::EnsureAllocated(gfx::IntSize aSize,
                                         gfxASurface::gfxContentType aContentType)
 {
   mSize = aSize;
+  return true;
 }
 
 
 } // namespace
 } // namespace
--- a/gfx/layers/opengl/TextureClientOGL.h
+++ b/gfx/layers/opengl/TextureClientOGL.h
@@ -34,34 +34,34 @@ public:
 
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
 
   void InitWith(gl::SharedTextureHandle aHandle,
                 gfx::IntSize aSize,
                 bool aIsCrossProcess = false,
                 bool aInverted = false);
 
-  gfx::IntSize GetSize() const { return mSize; }
+  virtual gfx::IntSize GetSize() const { return mSize; }
 
 protected:
   gfx::IntSize mSize;
   gl::SharedTextureHandle mHandle;
   bool mIsCrossProcess;
   bool mInverted;
 };
 
 
 class DeprecatedTextureClientSharedOGL : public DeprecatedTextureClient
 {
 public:
   DeprecatedTextureClientSharedOGL(CompositableForwarder* aForwarder, const TextureInfo& aTextureInfo);
   ~DeprecatedTextureClientSharedOGL() { ReleaseResources(); }
 
   virtual bool SupportsType(DeprecatedTextureClientType aType) MOZ_OVERRIDE { return aType == TEXTURE_SHARED_GL; }
-  virtual void EnsureAllocated(gfx::IntSize aSize, gfxASurface::gfxContentType aType);
+  virtual bool EnsureAllocated(gfx::IntSize aSize, gfxASurface::gfxContentType aType);
   virtual void ReleaseResources();
   virtual gfxASurface::gfxContentType GetContentType() MOZ_OVERRIDE { return gfxASurface::CONTENT_COLOR_ALPHA; }
 
 protected:
   gl::GLContext* mGL;
   gfx::IntSize mSize;
 
   friend class CompositingFactory;
@@ -83,17 +83,17 @@ class DeprecatedTextureClientStreamOGL :
 {
 public:
   DeprecatedTextureClientStreamOGL(CompositableForwarder* aForwarder, const TextureInfo& aTextureInfo)
     : DeprecatedTextureClient(aForwarder, aTextureInfo)
   {}
   ~DeprecatedTextureClientStreamOGL() { ReleaseResources(); }
 
   virtual bool SupportsType(DeprecatedTextureClientType aType) MOZ_OVERRIDE { return aType == TEXTURE_STREAM_GL; }
-  virtual void EnsureAllocated(gfx::IntSize aSize, gfxASurface::gfxContentType aType) { }
+  virtual bool EnsureAllocated(gfx::IntSize aSize, gfxASurface::gfxContentType aType) { return true; }
   virtual void ReleaseResources() { mDescriptor = SurfaceDescriptor(); }
   virtual gfxASurface::gfxContentType GetContentType() MOZ_OVERRIDE { return gfxASurface::CONTENT_COLOR_ALPHA; }
 };
 
 } // namespace
 } // namespace
 
 #endif
--- a/gfx/src/nsFont.cpp
+++ b/gfx/src/nsFont.cpp
@@ -110,28 +110,28 @@ bool nsFont::BaseEquals(const nsFont& aO
       (languageOverride == aOther.languageOverride) &&
       (variantAlternates == aOther.variantAlternates) &&
       (variantCaps == aOther.variantCaps) &&
       (variantEastAsian == aOther.variantEastAsian) &&
       (variantLigatures == aOther.variantLigatures) &&
       (variantNumeric == aOther.variantNumeric) &&
       (variantPosition == aOther.variantPosition) &&
       (alternateValues == aOther.alternateValues) &&
-      (featureValueLookup == aOther.featureValueLookup)) {
+      (featureValueLookup == aOther.featureValueLookup) &&
+      (smoothing == aOther.smoothing)) {
     return true;
   }
   return false;
 }
 
 bool nsFont::Equals(const nsFont& aOther) const
 {
   if (BaseEquals(aOther) &&
       (variant == aOther.variant) &&
-      (decorations == aOther.decorations) &&
-      (smoothing == aOther.smoothing)) {
+      (decorations == aOther.decorations)) {
     return true;
   }
   return false;
 }
 
 nsFont& nsFont::operator=(const nsFont& aOther)
 {
   name = aOther.name;
--- a/gfx/thebes/gfxCachedTempSurface.cpp
+++ b/gfx/thebes/gfxCachedTempSurface.cpp
@@ -68,35 +68,31 @@ gfxCachedTempSurface::~gfxCachedTempSurf
 already_AddRefed<gfxContext>
 gfxCachedTempSurface::Get(gfxASurface::gfxContentType aContentType,
                           const gfxRect& aRect,
                           gfxASurface* aSimilarTo)
 {
   if (mSurface) {
     /* Verify the current buffer is valid for this purpose */
     if (mSize.width < aRect.width || mSize.height < aRect.height
-        || mSurface->GetContentType() != aContentType) {
+        || mSurface->GetContentType() != aContentType
+        || mType != aSimilarTo->GetType()) {
       mSurface = nullptr;
-    } else {
-      NS_ASSERTION(mType == aSimilarTo->GetType(),
-                   "Unexpected surface type change");
     }
   }
 
   bool cleared = false;
   if (!mSurface) {
     mSize = gfxIntSize(int32_t(ceil(aRect.width)), int32_t(ceil(aRect.height)));
     mSurface = aSimilarTo->CreateSimilarSurface(aContentType, mSize);
     if (!mSurface)
       return nullptr;
 
     cleared = true;
-#ifdef DEBUG
     mType = aSimilarTo->GetType();
-#endif
   }
   mSurface->SetDeviceOffset(-aRect.TopLeft());
 
   nsRefPtr<gfxContext> ctx = new gfxContext(mSurface);
   ctx->Rectangle(aRect);
   ctx->Clip();
   if (!cleared && aContentType != gfxASurface::CONTENT_COLOR) {
     ctx->SetOperator(gfxContext::OPERATOR_CLEAR);
--- a/gfx/thebes/gfxCachedTempSurface.h
+++ b/gfx/thebes/gfxCachedTempSurface.h
@@ -28,33 +28,30 @@ public:
    * Returns a context for a surface that can be efficiently copied to
    * |aSimilarTo|.
    *
    * When |aContentType| has an alpha component, the surface will be cleared.
    * For opaque surfaces, the initial surface contents are undefined.
    * When |aContentType| differs in different invocations this is handled
    * appropriately, creating a new surface if necessary.
    * 
-   * |aSimilarTo| should be of the same gfxSurfaceType in each invocation.
    * Because the cached surface may have been created during a previous
    * invocation, this will not be efficient if the new |aSimilarTo| has a
-   * different format.
+   * different format, size, or gfxSurfaceType.
    */
   already_AddRefed<gfxContext> Get(gfxASurface::gfxContentType aContentType,
                                    const gfxRect& aRect,
                                    gfxASurface* aSimilarTo);
 
   void Expire() { mSurface = nullptr; }
   nsExpirationState* GetExpirationState() { return &mExpirationState; }
   ~gfxCachedTempSurface();
 
   bool IsSurface(gfxASurface* aSurface) { return mSurface == aSurface; }
 
 private:
   nsRefPtr<gfxASurface> mSurface;
   gfxIntSize mSize;
   nsExpirationState mExpirationState;
-#ifdef DEBUG
   gfxASurface::gfxSurfaceType mType;
-#endif 
 };
 
 #endif /* GFX_CACHED_TEMP_SURFACE_H */
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -72,25 +72,28 @@
 #include "skia/GrContext.h"
 #include "skia/GrGLInterface.h"
 #include "GLContextSkia.h"
 #endif
 
 #include "mozilla/Preferences.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/Mutex.h"
 
 #include "nsIGfxInfo.h"
 
 using namespace mozilla;
 using namespace mozilla::layers;
 
 gfxPlatform *gPlatform = nullptr;
 static bool gEverInitialized = false;
 
+static Mutex* gGfxPlatformPrefsLock = nullptr;
+
 // These two may point to the same profile
 static qcms_profile *gCMSOutputProfile = nullptr;
 static qcms_profile *gCMSsRGBProfile = nullptr;
 
 static qcms_transform *gCMSRGBTransform = nullptr;
 static qcms_transform *gCMSInverseRGBTransform = nullptr;
 static qcms_transform *gCMSRGBATransform = nullptr;
 
@@ -308,16 +311,18 @@ gfxPlatform::Init()
 #ifdef PR_LOGGING
     sFontlistLog = PR_NewLogModule("fontlist");;
     sFontInitLog = PR_NewLogModule("fontinit");;
     sTextrunLog = PR_NewLogModule("textrun");;
     sTextrunuiLog = PR_NewLogModule("textrunui");;
     sCmapDataLog = PR_NewLogModule("cmapdata");;
 #endif
 
+    gGfxPlatformPrefsLock = new Mutex("gfxPlatform::gGfxPlatformPrefsLock");
+
     /* Initialize the GfxInfo service.
      * Note: we can't call functions on GfxInfo that depend
      * on gPlatform until after it has been initialized
      * below. GfxInfo initialization annotates our
      * crash reports so we want to do it before
      * we try to load any drivers and do device detection
      * incase that code crashes. See bug #591561. */
     nsCOMPtr<nsIGfxInfo> gfxInfo;
@@ -470,16 +475,18 @@ gfxPlatform::Shutdown()
 #endif
 
     // This will block this thread untill the ImageBridge protocol is completely
     // deleted.
     ImageBridgeChild::ShutDown();
 
     CompositorParent::ShutDown();
 
+    delete gGfxPlatformPrefsLock;
+
     delete gPlatform;
     gPlatform = nullptr;
 }
 
 gfxPlatform::~gfxPlatform()
 {
     mScreenReferenceSurface = nullptr;
 
@@ -1851,72 +1858,119 @@ gfxPlatform::GetOrientationSyncMillis() 
  */
 static bool sPrefLayersOffMainThreadCompositionEnabled = false;
 static bool sPrefLayersOffMainThreadCompositionTestingEnabled = false;
 static bool sPrefLayersOffMainThreadCompositionForceEnabled = false;
 static bool sPrefLayersAccelerationForceEnabled = false;
 static bool sPrefLayersAccelerationDisabled = false;
 static bool sPrefLayersPreferOpenGL = false;
 static bool sPrefLayersPreferD3D9 = false;
+static bool sLayersSupportsD3D9 = true;
 static int  sPrefLayoutFrameRate = -1;
+static bool sBufferRotationEnabled = false;
 
-void InitLayersAccelerationPrefs()
+static bool sLayersAccelerationPrefsInitialized = false;
+
+void
+InitLayersAccelerationPrefs()
 {
-  static bool sLayersAccelerationPrefsInitialized = false;
   if (!sLayersAccelerationPrefsInitialized)
   {
     sPrefLayersOffMainThreadCompositionEnabled = Preferences::GetBool("layers.offmainthreadcomposition.enabled", false);
     sPrefLayersOffMainThreadCompositionTestingEnabled = Preferences::GetBool("layers.offmainthreadcomposition.testing.enabled", false);
     sPrefLayersOffMainThreadCompositionForceEnabled = Preferences::GetBool("layers.offmainthreadcomposition.force-enabled", false);
     sPrefLayersAccelerationForceEnabled = Preferences::GetBool("layers.acceleration.force-enabled", false);
     sPrefLayersAccelerationDisabled = Preferences::GetBool("layers.acceleration.disabled", false);
     sPrefLayersPreferOpenGL = Preferences::GetBool("layers.prefer-opengl", false);
     sPrefLayersPreferD3D9 = Preferences::GetBool("layers.prefer-d3d9", false);
     sPrefLayoutFrameRate = Preferences::GetInt("layout.frame_rate", -1);
+    sBufferRotationEnabled = Preferences::GetBool("layers.bufferrotation.enabled", true);
+
+    nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
+    if (gfxInfo) {
+      int32_t status;
+      if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, &status))) {
+        if (status != nsIGfxInfo::FEATURE_NO_INFO && !sPrefLayersAccelerationForceEnabled) {
+          sLayersSupportsD3D9 = false;
+        }
+      }
+    }
 
     sLayersAccelerationPrefsInitialized = true;
   }
 }
 
-bool gfxPlatform::GetPrefLayersOffMainThreadCompositionEnabled()
+bool
+gfxPlatform::GetPrefLayersOffMainThreadCompositionEnabled()
 {
   InitLayersAccelerationPrefs();
   return sPrefLayersOffMainThreadCompositionEnabled ||
          sPrefLayersOffMainThreadCompositionForceEnabled ||
          sPrefLayersOffMainThreadCompositionTestingEnabled;
 }
 
-bool gfxPlatform::GetPrefLayersOffMainThreadCompositionForceEnabled()
+bool
+gfxPlatform::GetPrefLayersOffMainThreadCompositionForceEnabled()
 {
   InitLayersAccelerationPrefs();
   return sPrefLayersOffMainThreadCompositionForceEnabled;
 }
 
-bool gfxPlatform::GetPrefLayersAccelerationForceEnabled()
+bool
+gfxPlatform::GetPrefLayersAccelerationForceEnabled()
 {
   InitLayersAccelerationPrefs();
   return sPrefLayersAccelerationForceEnabled;
 }
 
 bool
 gfxPlatform::GetPrefLayersAccelerationDisabled()
 {
   InitLayersAccelerationPrefs();
   return sPrefLayersAccelerationDisabled;
 }
 
-bool gfxPlatform::GetPrefLayersPreferOpenGL()
+bool
+gfxPlatform::GetPrefLayersPreferOpenGL()
 {
   InitLayersAccelerationPrefs();
   return sPrefLayersPreferOpenGL;
 }
 
-bool gfxPlatform::GetPrefLayersPreferD3D9()
+bool
+gfxPlatform::GetPrefLayersPreferD3D9()
 {
   InitLayersAccelerationPrefs();
   return sPrefLayersPreferD3D9;
 }
 
-int gfxPlatform::GetPrefLayoutFrameRate()
+bool
+gfxPlatform::CanUseDirect3D9()
+{
+  // this function is called from the compositor thread, so it is not
+  // safe to init the prefs etc. from here.
+  MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
+  return sLayersSupportsD3D9;
+}
+
+int
+gfxPlatform::GetPrefLayoutFrameRate()
 {
   InitLayersAccelerationPrefs();
   return sPrefLayoutFrameRate;
 }
+
+bool
+gfxPlatform::BufferRotationEnabled()
+{
+  MutexAutoLock autoLock(*gGfxPlatformPrefsLock);
+
+  InitLayersAccelerationPrefs();
+  return sBufferRotationEnabled;
+}
+
+void
+gfxPlatform::DisableBufferRotation()
+{
+  MutexAutoLock autoLock(*gGfxPlatformPrefsLock);
+
+  sBufferRotationEnabled = false;
+}
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -466,19 +466,25 @@ public:
      * only once, and remain the same until restart.
      */
     static bool GetPrefLayersOffMainThreadCompositionEnabled();
     static bool GetPrefLayersOffMainThreadCompositionForceEnabled();
     static bool GetPrefLayersAccelerationForceEnabled();
     static bool GetPrefLayersAccelerationDisabled();
     static bool GetPrefLayersPreferOpenGL();
     static bool GetPrefLayersPreferD3D9();
+    static bool CanUseDirect3D9();
     static int  GetPrefLayoutFrameRate();
 
     /**
+     * Is it possible to use buffer rotation
+     */
+    static bool BufferRotationEnabled();
+    static void DisableBufferRotation();
+    /**
      * Are we going to try color management?
      */
     static eCMSMode GetCMSMode();
 
     /**
      * Determines the rendering intent for color management.
      *
      * If the value in the pref gfx.color_management.rendering_intent is a
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -23,30 +23,33 @@
 
 #include "nsIGfxInfo.h"
 
 #include "gfxCrashReporterUtils.h"
 
 #include "gfxGDIFontList.h"
 #include "gfxGDIFont.h"
 
+#include "DeviceManagerD3D9.h"
+
 #ifdef CAIRO_HAS_DWRITE_FONT
 #include "gfxDWriteFontList.h"
 #include "gfxDWriteFonts.h"
 #include "gfxDWriteCommon.h"
 #include <dwrite.h>
 #endif
 
 #include "gfxUserFontSet.h"
 #include "nsWindowsHelpers.h"
 
 #include <string>
 
 using namespace mozilla;
 using namespace mozilla::gfx;
+using namespace mozilla::layers;
 
 #ifdef CAIRO_HAS_D2D_SURFACE
 #include "gfxD2DSurface.h"
 
 #include <d3d10_1.h>
 
 #include "mozilla/gfx/2D.h"
 
@@ -345,17 +348,18 @@ static __inline void
 BuildKeyNameFromFontName(nsAString &aName)
 {
     if (aName.Length() >= LF_FACESIZE)
         aName.Truncate(LF_FACESIZE - 1);
     ToLowerCase(aName);
 }
 
 gfxWindowsPlatform::gfxWindowsPlatform()
-  : mD3D11DeviceInitialized(false)
+  : mD3D9DeviceInitialized(false)
+  , mD3D11DeviceInitialized(false)
 {
     mPrefFonts.Init(50);
 
     mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE;
     mUseClearTypeAlways = UNINITIALIZED_VALUE;
 
     mUsingGDIFonts = false;
 
@@ -379,16 +383,18 @@ gfxWindowsPlatform::gfxWindowsPlatform()
     mGPUAdapterMultiReporter = new GPUAdapterMultiReporter();
     NS_RegisterMemoryMultiReporter(mGPUAdapterMultiReporter);
 }
 
 gfxWindowsPlatform::~gfxWindowsPlatform()
 {
     NS_UnregisterMemoryMultiReporter(mGPUAdapterMultiReporter);
     
+     mDeviceManager = nullptr;
+     
     ::ReleaseDC(nullptr, mScreenDC);
     // not calling FT_Done_FreeType because cairo may still hold references to
     // these FT_Faces.  See bug 458169.
 #ifdef CAIRO_HAS_D2D_SURFACE
     if (mD2DDevice) {
         cairo_release_device(mD2DDevice);
     }
 #endif
@@ -1442,16 +1448,39 @@ gfxWindowsPlatform::SetupClearTypeParams
 
         GetDWriteFactory()->CreateCustomRenderingParams(gamma, contrast, level,
 	    dwriteGeometry, DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC,
             getter_AddRefs(mRenderingParams[TEXT_RENDERING_GDI_CLASSIC]));
     }
 #endif
 }
 
+IDirect3DDevice9*
+gfxWindowsPlatform::GetD3D9Device()
+{
+  DeviceManagerD3D9* manager = GetD3D9DeviceManager();
+  return manager ? manager->device() : nullptr;
+}
+
+DeviceManagerD3D9*
+gfxWindowsPlatform::GetD3D9DeviceManager()
+{
+  if (!mD3D9DeviceInitialized) {
+    mD3D9DeviceInitialized = true;
+
+    mDeviceManager = new DeviceManagerD3D9();
+    if (!mDeviceManager->Init()) {
+      NS_WARNING("Could not initialise devive manager");
+      mDeviceManager = nullptr;
+    }
+  }
+
+  return mDeviceManager;
+}
+
 ID3D11Device*
 gfxWindowsPlatform::GetD3D11Device()
 {
   if (mD3D11DeviceInitialized) {
     return mD3D11Device;
   }
 
   mD3D11DeviceInitialized = true;
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -38,16 +38,22 @@
 #include <d3dcommon.h>
 // Win 8.0 SDK types we'll need when building using older sdks.
 #if !defined(D3D_FEATURE_LEVEL_11_1) // defined in the 8.0 SDK only
 #define D3D_FEATURE_LEVEL_11_1 static_cast<D3D_FEATURE_LEVEL>(0xb100)
 #define D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION 2048
 #define D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION 4096
 #endif
 
+namespace mozilla {
+namespace layers {
+class DeviceManagerD3D9;
+}
+}
+class IDirect3DDevice9;
 class ID3D11Device;
 class IDXGIAdapter1;
 
 class nsIMemoryMultiReporter;
 
 // Utility to get a Windows HDC from a thebes context,
 // used by both GDI and Uniscribe font shapers
 struct DCFromContext {
@@ -260,16 +266,18 @@ public:
     inline DWRITE_MEASURING_MODE DWriteMeasuringMode() { return mMeasuringMode; }
     IDWriteTextAnalyzer *GetDWriteAnalyzer() { return mDWriteAnalyzer; }
 
     IDWriteRenderingParams *GetRenderingParams(TextRenderingMode aRenderMode)
     { return mRenderingParams[aRenderMode]; }
 #else
     inline bool DWriteEnabled() { return false; }
 #endif
+    mozilla::layers::DeviceManagerD3D9* GetD3D9DeviceManager();
+    IDirect3DDevice9* GetD3D9Device();
 #ifdef CAIRO_HAS_D2D_SURFACE
     cairo_device_t *GetD2DDevice() { return mD2DDevice; }
     ID3D10Device1 *GetD3D10Device() { return mD2DDevice ? cairo_d2d_device_get_device(mD2DDevice) : nullptr; }
 #endif
     ID3D11Device *GetD3D11Device();
 
     static bool IsOptimus();
 
@@ -292,17 +300,19 @@ private:
     nsRefPtr<IDWriteTextAnalyzer> mDWriteAnalyzer;
     nsRefPtr<IDWriteRenderingParams> mRenderingParams[TEXT_RENDERING_COUNT];
     DWRITE_MEASURING_MODE mMeasuringMode;
 #endif
 #ifdef CAIRO_HAS_D2D_SURFACE
     cairo_device_t *mD2DDevice;
 #endif
     mozilla::RefPtr<IDXGIAdapter1> mAdapter;
+    nsRefPtr<mozilla::layers::DeviceManagerD3D9> mDeviceManager;
     mozilla::RefPtr<ID3D11Device> mD3D11Device;
+    bool mD3D9DeviceInitialized;
     bool mD3D11DeviceInitialized;
 
     virtual qcms_profile* GetPlatformCMSOutputProfile();
 
     // TODO: unify this with mPrefFonts (NB: holds families, not fonts) in gfxPlatformFontList
     nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<gfxFontEntry> > > mPrefFonts;
 
     nsIMemoryMultiReporter* mGPUAdapterMultiReporter;
--- a/js/ipc/JavaScriptChild.cpp
+++ b/js/ipc/JavaScriptChild.cpp
@@ -2,16 +2,17 @@
  * vim: set ts=4 sw=4 et 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 "JavaScriptChild.h"
 #include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/BindingUtils.h"
 #include "nsContentUtils.h"
 #include "xpcprivate.h"
 #include "jsfriendapi.h"
 #include "nsCxPusher.h"
 
 using namespace JS;
 using namespace mozilla;
 using namespace mozilla::jsipc;
@@ -620,8 +621,32 @@ JavaScriptChild::AnswerInstanceOf(const 
     ConvertID(iid, &nsiid);
 
     nsresult rv = xpc::HasInstance(cx, obj, &nsiid, instanceof);
     if (rv != NS_OK)
         return fail(cx, rs);
 
     return ok(rs);
 }
+
+bool
+JavaScriptChild::AnswerDOMInstanceOf(const ObjectId &objId, const int &prototypeID,
+                                     const int &depth,
+                                     ReturnStatus *rs, bool *instanceof)
+{
+    AutoSafeJSContext cx;
+    JSAutoRequest request(cx);
+
+    *instanceof = false;
+
+    RootedObject obj(cx, findObject(objId));
+    if (!obj)
+        return false;
+
+    JSAutoCompartment comp(cx, obj);
+
+    JSBool tmp;
+    if (!mozilla::dom::InterfaceHasInstance(cx, prototypeID, depth, obj, &tmp))
+        return fail(cx, rs);
+    *instanceof = tmp;
+
+    return ok(rs);
+}
--- a/js/ipc/JavaScriptChild.h
+++ b/js/ipc/JavaScriptChild.h
@@ -61,16 +61,18 @@ class JavaScriptChild
     bool AnswerObjectClassIs(const ObjectId &objId, const uint32_t &classValue,
                              bool *result);
     bool AnswerClassName(const ObjectId &objId, nsString *result);
 
     bool AnswerGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
                                 ReturnStatus *rs, nsTArray<nsString> *names);
     bool AnswerInstanceOf(const ObjectId &objId, const JSIID &iid,
                           ReturnStatus *rs, bool *instanceof);
+    bool AnswerDOMInstanceOf(const ObjectId &objId, const int &prototypeID, const int &depth,
+                             ReturnStatus *rs, bool *instanceof);
 
   protected:
     JSObject *unwrap(JSContext *cx, ObjectId id);
 
   private:
     bool makeId(JSContext *cx, JSObject *obj, ObjectId *idp);
     bool fail(JSContext *cx, ReturnStatus *rs);
     bool ok(ReturnStatus *rs);
--- a/js/ipc/JavaScriptParent.cpp
+++ b/js/ipc/JavaScriptParent.cpp
@@ -509,17 +509,18 @@ JavaScriptParent::init()
         return false;
 
     return true;
 }
 
 bool
 JavaScriptParent::makeId(JSContext *cx, JSObject *obj, ObjectId *idp)
 {
-    if (!IsProxy(obj) || GetProxyHandler(obj) != &CPOWProxyHandler::singleton) {
+    obj = js::CheckedUnwrap(obj, false);
+    if (!obj || !IsProxy(obj) || GetProxyHandler(obj) != &CPOWProxyHandler::singleton) {
         JS_ReportError(cx, "cannot ipc non-cpow object");
         return false;
     }
 
     *idp = idOf(obj);
     return true;
 }
 
@@ -651,8 +652,29 @@ JavaScriptParent::instanceOf(JSObject *o
     if (!CallInstanceO