Merge m-c to b2ginbound, a=merge CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Tue, 20 Oct 2015 15:29:33 -0700
changeset 303773 c20a8e16ba880402f2f2f6c566e7eef70207a116
parent 303772 8e67ccdf1b8da951d63e44dc77fdd1f74cf56a84 (current diff)
parent 303764 f397034950304b845175f8dab8fccbdd0e8bf995 (diff)
child 303774 1c228d8375dd766a7adb0a015b12e9277d18f2fe
push id1001
push userraliiev@mozilla.com
push dateMon, 18 Jan 2016 19:06:03 +0000
treeherdermozilla-release@8b89261f3ac4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone44.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to b2ginbound, a=merge CLOSED TREE
mobile/android/base/resources/layout/tabs_panel_back_button.xml
mobile/android/gradle/branding/AndroidManifest.xml
mobile/android/gradle/branding/build.gradle
mobile/android/gradle/preprocessed_code/AndroidManifest.xml
mobile/android/gradle/preprocessed_code/build.gradle
mobile/android/gradle/preprocessed_resources/AndroidManifest.xml
mobile/android/gradle/preprocessed_resources/build.gradle
testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-add.https.html.ini
testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-delete.https.html.ini
testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-match.https.html.ini
testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-put.https.html.ini
testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-storage-keys.https.html.ini
testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-storage-match.https.html.ini
testing/web-platform/meta/service-workers/cache-storage/serviceworker/cache-storage.https.html.ini
testing/web-platform/meta/service-workers/cache-storage/window/cache-match.https.html.ini
testing/web-platform/meta/service-workers/cache-storage/window/cache-put.https.html.ini
testing/web-platform/meta/service-workers/cache-storage/window/cache-storage-match.https.html.ini
testing/web-platform/meta/service-workers/cache-storage/worker/cache-add.https.html.ini
testing/web-platform/meta/service-workers/cache-storage/worker/cache-delete.https.html.ini
testing/web-platform/meta/service-workers/cache-storage/worker/cache-match.https.html.ini
testing/web-platform/meta/service-workers/cache-storage/worker/cache-put.https.html.ini
testing/web-platform/meta/service-workers/cache-storage/worker/cache-storage-keys.https.html.ini
testing/web-platform/meta/service-workers/cache-storage/worker/cache-storage-match.https.html.ini
testing/web-platform/meta/service-workers/cache-storage/worker/cache-storage.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-request-xhr.https.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/request-end-to-end.https.html.ini
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -948,17 +948,17 @@ pref("dom.mozInputMethod.enabled", true)
 // Absolute path to the devtool unix domain socket file used
 // to communicate with a usb cable via adb forward
 pref("devtools.debugger.unix-domain-socket", "/data/local/debugger-socket");
 
 // enable Skia/GL (OpenGL-accelerated 2D drawing) for large enough 2d canvases,
 // falling back to Skia/software for smaller canvases
 #ifdef MOZ_WIDGET_GONK
 pref("gfx.canvas.azure.backends", "skia");
-pref("gfx.canvas.azure.accelerated", false);
+pref("gfx.canvas.azure.accelerated", true);
 #endif
 
 // Turn on dynamic cache size for Skia
 pref("gfx.canvas.skiagl.dynamic-cache", true);
 
 // Limit skia to canvases the size of the device screen or smaller
 pref("gfx.canvas.max-size-for-skia-gl", -1);
 
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -671,17 +671,17 @@
              overflowable="true"
              overflowbutton="nav-bar-overflow-button"
              overflowtarget="widget-overflow-list"
              overflowpanel="widget-overflow"
              context="toolbar-context-menu">
 
       <hbox id="nav-bar-customization-target" flex="1">
         <toolbaritem id="urlbar-container" flex="400" persist="width"
-                     title="&locationItem.title;" removable="false"
+                     removable="false"
                      class="chromeclass-location" overflows="false">
           <toolbarbutton id="back-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
                          label="&backCmd.label;"
                          command="Browser:BackOrBackDuplicate"
                          onclick="checkForMiddleClick(this, event);"
                          tooltip="back-button-tooltip"
                          context="backForwardMenu"/>
           <hbox id="urlbar-wrapper" flex="1">
@@ -794,26 +794,23 @@
               </hbox>
               <hbox id="userContext-icons">
                 <label id="userContext-label"/>
                 <image id="userContext-indicator"/>
               </hbox>
               <toolbarbutton id="urlbar-go-button"
                              class="chromeclass-toolbar-additional"
                              onclick="gURLBar.handleCommand(event);"
-                             aria-label="&goEndCap.tooltip;"
                              tooltiptext="&goEndCap.tooltip;"/>
               <toolbarbutton id="urlbar-reload-button"
                              class="chromeclass-toolbar-additional"
                              command="Browser:ReloadOrDuplicate"
                              onclick="checkForMiddleClick(this, event);"
-                             aria-label="&reloadButton.tooltip;"
                              tooltiptext="&reloadButton.tooltip;"/>
               <toolbarbutton id="urlbar-stop-button"
-                             aria-label="&stopButton.tooltip;"
                              class="chromeclass-toolbar-additional"
                              command="Browser:Stop"
                              tooltiptext="&stopButton.tooltip;"/>
             </textbox>
           </hbox>
         </toolbaritem>
 
         <toolbaritem id="search-container" title="&searchItem.title;"
--- a/browser/base/content/test/alerts/browser.ini
+++ b/browser/base/content/test/alerts/browser.ini
@@ -1,7 +1,9 @@
 [DEFAULT]
 support-files =
   file_dom_notifications.html
 
 [browser_notification_open_settings.js]
+[browser_notification_remove_permission.js]
+skip-if = e10s
 [browser_notification_tab_switching.js]
 skip-if = buildapp == 'mulet' || e10s # Bug 1100662 - content access causing uncaught exception - Error: cannot ipc non-cpow object at chrome://mochitests/content/browser/browser/base/content/test/general/browser_notification_tab_switching.js:32 (or in RemoteAddonsChild.jsm)
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/alerts/browser_notification_remove_permission.js
@@ -0,0 +1,79 @@
+"use strict";
+
+var tab;
+var notification;
+var notificationURL = "http://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html";
+var alertWindowClosed = false;
+var permRemoved = false;
+
+function test () {
+  waitForExplicitFinish();
+
+  let pm = Services.perms;
+  registerCleanupFunction(function() {
+    pm.remove(makeURI(notificationURL), "desktop-notification");
+    gBrowser.removeTab(tab);
+    window.restore();
+  });
+
+  pm.add(makeURI(notificationURL), "desktop-notification", pm.ALLOW_ACTION);
+
+  tab = gBrowser.addTab(notificationURL);
+  gBrowser.selectedTab = tab;
+  tab.linkedBrowser.addEventListener("load", onLoad, true);
+}
+
+function onLoad() {
+  tab.linkedBrowser.removeEventListener("load", onLoad, true);
+  let win = tab.linkedBrowser.contentWindow.wrappedJSObject;
+  notification = win.showNotification2();
+  notification.addEventListener("show", onAlertShowing);
+}
+
+function onAlertShowing() {
+  info("Notification alert showing");
+  notification.removeEventListener("show", onAlertShowing);
+
+  let alertWindow = Services.wm.getMostRecentWindow("alert:alert");
+  if (!alertWindow) {
+    ok(true, "Notifications don't use XUL windows on all platforms.");
+    notification.close();
+    finish();
+    return;
+  }
+  ok(Services.perms.testExactPermission(makeURI(notificationURL), "desktop-notification"),
+     "Permission should exist prior to removal");
+  let disableForOriginMenuItem = alertWindow.document.getElementById("disableForOriginMenuItem");
+  is(disableForOriginMenuItem.localName, "menuitem", "menuitem found");
+  Services.obs.addObserver(permObserver, "perm-changed", false);
+  alertWindow.addEventListener("beforeunload", onAlertClosing);
+  disableForOriginMenuItem.click();
+  info("Clicked on disable-for-origin menuitem")
+}
+
+function permObserver(subject, topic, data) {
+  if (topic != "perm-changed") {
+    return;
+  }
+
+  let permission = subject.QueryInterface(Ci.nsIPermission);
+  is(permission.type, "desktop-notification", "desktop-notification permission changed");
+  is(data, "deleted", "desktop-notification permission deleted");
+
+  Services.obs.removeObserver(permObserver, "perm-changed");
+  permRemoved = true;
+  if (alertWindowClosed) {
+    finish();
+  }
+}
+
+function onAlertClosing(event) {
+  event.target.removeEventListener("beforeunload", onAlertClosing);
+
+  alertWindowClosed = true;
+  if (permRemoved) {
+    finish();
+  }
+}
+
+
--- a/browser/base/content/test/alerts/browser_notification_tab_switching.js
+++ b/browser/base/content/test/alerts/browser_notification_tab_switching.js
@@ -55,17 +55,17 @@ function onLoad() {
 }
 
 function onAlertShowing() {
   info("Notification alert showing");
   notification.removeEventListener("show", onAlertShowing);
 
   let alertWindow = Services.wm.getMostRecentWindow("alert:alert");
   if (!alertWindow) {
-    todo(false, "Notifications don't use XUL windows on all platforms.");
+    ok(true, "Notifications don't use XUL windows on all platforms.");
     notification.close();
     newWindowOpenedFromTab.close();
     finish();
     return;
   }
   gBrowser.tabContainer.addEventListener("TabSelect", onTabSelect);
   EventUtils.synthesizeMouseAtCenter(alertWindow.document.getElementById("alertTitleLabel"), {}, alertWindow);
   info("Clicked on notification");
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -213,18 +213,16 @@ These should match what Safari and other
 <!ENTITY urlbar.pointerLockNotificationAnchor.label     "Change whether the site can hide the pointer">
 <!ENTITY urlbar.servicesNotificationAnchor.label        "View the service install message">
 <!ENTITY urlbar.translateNotificationAnchor.label       "Translate this page">
 <!ENTITY urlbar.translatedNotificationAnchor.label      "Manage page translation">
 <!ENTITY urlbar.emeNotificationAnchor.label             "Manage use of DRM software">
 
 <!ENTITY urlbar.toggleAutocomplete.label                "Toggle the autocomplete popup">
 
-
-<!ENTITY locationItem.title           "Location">
 <!ENTITY searchItem.title             "Search">
 
 <!-- Toolbar items --> 
 <!ENTITY homeButton.label             "Home">
 
 <!ENTITY tabGroupsButton.label        "Tab Groups">
 
 <!ENTITY bookmarksButton.label          "Bookmarks">
--- a/browser/locales/en-US/chrome/browser/devtools/inspector.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/inspector.dtd
@@ -120,8 +120,13 @@
      shown in the inspector contextual-menu for recursively collapsing
      mark-up elements -->
 <!ENTITY inspectorCollapseNode.label       "Collapse">
 
 <!-- LOCALIZATION NOTE (inspectorScreenshotNode.label): This is the label
      shown in the inspector contextual-menu for the item that lets users take
      a screenshot of the currently selected node. -->
 <!ENTITY inspectorScreenshotNode.label       "Screenshot Node">
+
+<!-- LOCALIZATION NOTE (inspectorDuplicateNode.label): This is the label
+     shown in the inspector contextual-menu for the item that lets users
+     duplicate the currently selected node. -->
+<!ENTITY inspectorDuplicateNode.label       "Duplicate Node">
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -888,17 +888,17 @@ toolbar .toolbarbutton-1:-moz-any(@prima
   -moz-margin-start: 0;
 }
 
 .urlbar-history-dropmarker {
   -moz-appearance: toolbarbutton-dropdown;
   transition: opacity 0.15s ease;
 }
 
-#navigator-toolbox:not(:hover) .urlbar-history-dropmarker {
+#navigator-toolbox:not(:hover) #urlbar:not([focused]) > .urlbar-textbox-container > .urlbar-history-dropmarker {
   opacity: 0;
 }
 
 #urlbar-container {
   -moz-box-align: center;
 }
 
 @conditionalForwardWithUrlbar@ > #urlbar {
--- a/browser/themes/linux/linuxShared.inc
+++ b/browser/themes/linux/linuxShared.inc
@@ -1,10 +1,10 @@
 /* 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/. */
 
 %filter substitution
 
-%define toolbarHighlight rgba(255,255,255,.3)
+%define toolbarHighlight rgba(255,255,255,.4)
 %define fgTabTexture linear-gradient(transparent 2px, @toolbarHighlight@ 2px, @toolbarHighlight@)
 %define fgTabTextureLWT @fgTabTexture@
 %define fgTabBackgroundColor -moz-dialog
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -1692,17 +1692,17 @@ toolbar .toolbarbutton-1 > .toolbarbutto
 
 .urlbar-history-dropmarker {
   padding: 0 3px;
   list-style-image: var(--urlbar-dropmarker-url);
   -moz-image-region: var(--urlbar-dropmarker-region);
   transition: opacity 0.15s ease;
 }
 
-#navigator-toolbox:not(:hover) .urlbar-history-dropmarker {
+#navigator-toolbox:not(:hover) #urlbar:not([focused]) > .urlbar-textbox-container > .urlbar-history-dropmarker {
   opacity: 0;
 }
 
 .urlbar-history-dropmarker[open="true"],
 .urlbar-history-dropmarker:hover:active {
   -moz-image-region: var(--urlbar-dropmarker-active-region);
 }
 
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -1405,17 +1405,17 @@ html|*.urlbar-input:-moz-lwtheme::-moz-p
   background-color: transparent;
   border: none;
   width: auto;
   list-style-image: var(--urlbar-dropmarker-url);
   -moz-image-region: var(--urlbar-dropmarker-region);
   transition: opacity 0.15s ease;
 }
 
-#navigator-toolbox:not(:hover) .urlbar-history-dropmarker {
+#navigator-toolbox:not(:hover) #urlbar:not([focused]) > .urlbar-textbox-container > .urlbar-history-dropmarker {
   opacity: 0;
 }
 
 .urlbar-history-dropmarker:hover {
   -moz-image-region: var(--urlbar-dropmarker-hover-region);
 }
 
 .urlbar-history-dropmarker:hover:active,
--- a/browser/themes/windows/windowsShared.inc
+++ b/browser/themes/windows/windowsShared.inc
@@ -1,13 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 %filter substitution
 
-%define toolbarHighlight rgba(255,255,255,.3)
+%define toolbarHighlight rgba(255,255,255,.4)
 %define fgTabTexture linear-gradient(transparent 2px, @toolbarHighlight@ 2px, @toolbarHighlight@)
 %define fgTabBackgroundColor -moz-dialog
 %define fgTabTextureLWT @fgTabTexture@
 
 % Aero-only defines
 %define customToolbarColor hsl(210,75%,92%)
--- a/config/external/icu/Makefile.in
+++ b/config/external/icu/Makefile.in
@@ -42,19 +42,19 @@ target:: buildicu
 # - Force ICU to use the standard suffix for object files because expandlibs
 #   will discard all files with a non-standard suffix (bug 857450).
 # - Options for genrb: -k strict parsing; -R omit collation tailoring rules.
 buildicu::
 # ICU's build system is full of races, so force non-parallel build.
 # Msys screws up GENRBOPTS when it contains spaces, so all genrb flags need
 # to be stuck together. See https://bugzilla.mozilla.org/show_bug.cgi?id=1034594#c34
 ifdef CROSS_COMPILE
-	+$(MAKE) -j1 -C $(DEPTH)/intl/icu/host STATIC_O=$(OBJ_SUFFIX) GENRBOPTS='-kRC'
+	+ASAN_OPTIONS=detect_leaks=0 $(MAKE) -j1 -C $(DEPTH)/intl/icu/host STATIC_O=$(OBJ_SUFFIX) GENRBOPTS='-kRC'
 endif
-	+$(MAKE) -j1 -C $(DEPTH)/intl/icu/target STATIC_O=$(OBJ_SUFFIX) GENRBOPTS='-kR'
+	+ASAN_OPTIONS=detect_leaks=0 $(MAKE) -j1 -C $(DEPTH)/intl/icu/target STATIC_O=$(OBJ_SUFFIX) GENRBOPTS='-kR'
 	$(ICU_LIB_RENAME)
 
 distclean clean::
 ifdef CROSS_COMPILE
 	+$(MAKE) -C $(DEPTH)/intl/icu/host $@ STATIC_O=$(OBJ_SUFFIX)
 endif
 	+$(MAKE) -C $(DEPTH)/intl/icu/target $@ STATIC_O=$(OBJ_SUFFIX)
 
--- a/config/external/nss/nss.def
+++ b/config/external/nss/nss.def
@@ -398,19 +398,16 @@ PK11_Logout
 PK11_LogoutAll
 PK11_MakeIDFromPubKey
 PK11_MechanismToAlgtag
 PK11_MergeTokens
 PK11_NeedLogin
 PK11_NeedUserInit
 PK11_ParamFromIV
 PK11_PBEKeyGen
-PK11_PQG_DestroyParams
-PK11_PQG_DestroyVerify
-PK11_PQG_ParamGen
 PK11_PrivDecrypt
 PK11_PrivDecryptPKCS1
 PK11_ProtectedAuthenticationPath
 PK11_PubDeriveWithKDF
 PK11_PubEncrypt
 PK11_PubEncryptPKCS1
 PK11_PubUnwrapSymKey
 PK11_PubWrapSymKey
@@ -680,9 +677,8 @@ VFY_CreateContext
 VFY_DestroyContext
 VFY_End
 VFY_EndWithSignature
 VFY_Update
 VFY_VerifyData
 VFY_VerifyDataWithAlgorithmID
 VFY_VerifyDigestDirect
 _SGN_VerifyPKCS1DigestInfo
-PK11_PQG_ParamGenV2
--- a/configure.in
+++ b/configure.in
@@ -48,17 +48,17 @@ dnl ====================================
 _SUBDIR_HOST_LDFLAGS="$HOST_LDFLAGS"
 _SUBDIR_CONFIG_ARGS="$ac_configure_args"
 
 dnl Set the version number of the libs included with mozilla
 dnl ========================================================
 MOZJPEG=62
 MOZPNG=10617
 NSPR_VERSION=4
-NSPR_MINVER=4.10.8
+NSPR_MINVER=4.10.10
 NSS_VERSION=3
 
 dnl Set the minimum version of toolkit libs used by mozilla
 dnl ========================================================
 GLIB_VERSION=2.22
 # 2_26 is the earliest version we can set GLIB_VERSION_MIN_REQUIRED.
 # The macro won't be used when compiling with earlier versions anyway.
 GLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_26
@@ -3422,17 +3422,17 @@ dnl = If NSS was not detected in the sys
 dnl = use the one in the source tree (mozilla/security/nss)
 dnl ========================================================
 
 MOZ_ARG_WITH_BOOL(system-nss,
 [  --with-system-nss       Use system installed NSS],
     _USE_SYSTEM_NSS=1 )
 
 if test -n "$_USE_SYSTEM_NSS"; then
-    AM_PATH_NSS(3.19.2, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
+    AM_PATH_NSS(3.20.1, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
 fi
 
 if test -n "$MOZ_NATIVE_NSS"; then
    NSS_LIBS="$NSS_LIBS -lcrmf"
 else
    NSS_CFLAGS='-I$(LIBXUL_DIST)/include/nss'
 
    if test -z "$GNU_CC" -a "$OS_ARCH" = "WINNT"; then
--- a/devtools/client/inspector/inspector-panel.js
+++ b/devtools/client/inspector/inspector-panel.js
@@ -649,16 +649,19 @@ InspectorPanel.prototype = {
   /**
    * Disable the delete item if needed. Update the pseudo classes.
    */
   _setupNodeMenu: function() {
     let isSelectionElement = this.selection.isElementNode() &&
                              !this.selection.isPseudoElementNode();
     let isEditableElement = isSelectionElement &&
                             !this.selection.isAnonymousNode();
+    let isDuplicatableElement = isSelectionElement &&
+                                !this.selection.isAnonymousNode() &&
+                                !this.selection.isRoot();
     let isScreenshotable = isSelectionElement &&
                            this.canGetUniqueSelector &&
                            this.selection.nodeFront.isTreeDisplayed;
 
     // Set the pseudo classes
     for (let name of ["hover", "active", "focus"]) {
       let menu = this.panelDoc.getElementById("node-menu-pseudo-" + name);
 
@@ -678,16 +681,17 @@ InspectorPanel.prototype = {
     } else {
       deleteNode.setAttribute("disabled", "true");
     }
 
     // Disable / enable "Copy Unique Selector", "Copy inner HTML",
     // "Copy outer HTML", "Scroll Into View" & "Screenshot Node" as appropriate
     let unique = this.panelDoc.getElementById("node-menu-copyuniqueselector");
     let screenshot = this.panelDoc.getElementById("node-menu-screenshotnode");
+    let duplicateNode = this.panelDoc.getElementById("node-menu-duplicatenode");
     let copyInnerHTML = this.panelDoc.getElementById("node-menu-copyinner");
     let copyOuterHTML = this.panelDoc.getElementById("node-menu-copyouter");
     let scrollIntoView = this.panelDoc.getElementById("node-menu-scrollnodeintoview");
     let expandAll = this.panelDoc.getElementById("node-menu-expand");
     let collapse = this.panelDoc.getElementById("node-menu-collapse");
 
     expandAll.setAttribute("disabled", "true");
     collapse.setAttribute("disabled", "true");
@@ -695,20 +699,30 @@ InspectorPanel.prototype = {
     let markUpContainer = this.markup.importNode(this.selection.nodeFront, false);
     if (this.selection.isNode() && markUpContainer.hasChildren) {
       if (markUpContainer.expanded) {
         collapse.removeAttribute("disabled");
       }
       expandAll.removeAttribute("disabled");
     }
 
+    this._target.actorHasMethod("domwalker", "duplicateNode").then(value => {
+      duplicateNode.hidden = !value;
+    });
     this._target.actorHasMethod("domnode", "scrollIntoView").then(value => {
       scrollIntoView.hidden = !value;
     });
 
+    if (isDuplicatableElement) {
+      duplicateNode.removeAttribute("disabled");
+    }
+    else {
+      duplicateNode.setAttribute("disabled", "true");
+    }
+
     if (isSelectionElement) {
       unique.removeAttribute("disabled");
       copyInnerHTML.removeAttribute("disabled");
       copyOuterHTML.removeAttribute("disabled");
       scrollIntoView.removeAttribute("disabled");
     } else {
       unique.setAttribute("disabled", "true");
       copyInnerHTML.setAttribute("disabled", "true");
@@ -1173,16 +1187,30 @@ InspectorPanel.prototype = {
     if (!this.selection.isNode()) {
       return;
     }
 
     this.selection.nodeFront.scrollIntoView();
   },
 
   /**
+   * Duplicate the selected node
+   */
+  duplicateNode: function() {
+    let selection = this.selection;
+    if (!selection.isElementNode() ||
+        selection.isRoot() ||
+        selection.isAnonymousNode() ||
+        selection.isPseudoElementNode()) {
+      return;
+    }
+    this.walker.duplicateNode(selection.nodeFront).catch(e => console.error(e));
+  },
+
+  /**
    * Delete the selected node.
    */
   deleteNode: function() {
     if (!this.selection.isNode() ||
          this.selection.isRoot()) {
       return;
     }
 
--- a/devtools/client/inspector/inspector.xul
+++ b/devtools/client/inspector/inspector.xul
@@ -98,16 +98,19 @@
       <menuseparator/>
       <menuitem id="node-menu-scrollnodeintoview"
         label="&inspectorScrollNodeIntoView.label;"
         accesskey="&inspectorScrollNodeIntoView.accesskey;"
         oncommand="inspector.scrollNodeIntoView()"/>
       <menuitem id="node-menu-screenshotnode"
         label="&inspectorScreenshotNode.label;"
         oncommand="inspector.screenshotNode()" />
+      <menuitem id="node-menu-duplicatenode"
+        label="&inspectorDuplicateNode.label;"
+        oncommand="inspector.duplicateNode()"/>
       <menuitem id="node-menu-delete"
         label="&inspectorHTMLDelete.label;"
         accesskey="&inspectorHTMLDelete.accesskey;"
         oncommand="inspector.deleteNode()"/>
       <menuseparator id="node-menu-link-separator"/>
       <menuitem id="node-menu-link-follow"
         oncommand="inspector.onFollowLink()"/>
       <menuitem id="node-menu-link-copy"
--- a/devtools/client/inspector/test/browser_inspector_menu-05-other.js
+++ b/devtools/client/inspector/test/browser_inspector_menu-05-other.js
@@ -1,53 +1,68 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
 http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
 // Tests for menuitem functionality that doesn't fit into any specific category
-
 const TEST_URL = TEST_URL_ROOT + "doc_inspector_menu.html";
-
 add_task(function* () {
   let { inspector, toolbox, testActor } = yield openInspectorForURL(TEST_URL);
-
   yield testShowDOMProperties();
+  yield testDuplicateNode();
   yield testDeleteNode();
   yield testDeleteRootNode();
   yield testScrollIntoView();
-
   function* testShowDOMProperties() {
     info("Testing 'Show DOM Properties' menu item.");
     let showDOMPropertiesNode = inspector.panelDoc.getElementById("node-menu-showdomproperties");
     ok(showDOMPropertiesNode, "the popup menu has a show dom properties item");
 
     let consoleOpened = toolbox.once("webconsole-ready");
 
     info("Triggering 'Show DOM Properties' and waiting for inspector open");
     dispatchCommandEvent(showDOMPropertiesNode);
     yield consoleOpened;
 
     let webconsoleUI = toolbox.getPanel("webconsole").hud.ui;
     let messagesAdded = webconsoleUI.once("new-messages");
     yield messagesAdded;
-
     info("Checking if 'inspect($0)' was evaluated");
     ok(webconsoleUI.jsterm.history[0] === 'inspect($0)');
+    yield toolbox.toggleSplitConsole();
+  }
+  function* testDuplicateNode() {
+    info("Testing 'Duplicate Node' menu item for normal elements.");
 
-    yield toolbox.toggleSplitConsole();
+    yield selectNode(".duplicate", inspector);
+    is((yield testActor.getNumberOfElementMatches(".duplicate")), 1,
+       "There should initially be 1 .duplicate node");
+
+    let menuItem = inspector.panelDoc.getElementById("node-menu-duplicatenode");
+    ok(menuItem, "'Duplicate node' menu item should exist");
+
+    info("Triggering 'Duplicate Node' and waiting for inspector to update");
+    let updated = inspector.once("markupmutation");
+    dispatchCommandEvent(menuItem);
+    yield updated;
+
+    is((yield testActor.getNumberOfElementMatches(".duplicate")), 2,
+       "The duplicated node should be in the markup.");
+
+    let container = yield getContainerForSelector(".duplicate + .duplicate",
+                                                   inspector);
+    ok(container, "A MarkupContainer should be created for the new node");
   }
 
   function* testDeleteNode() {
     info("Testing 'Delete Node' menu item for normal elements.");
-
     yield selectNode("#delete", inspector);
     let deleteNode = inspector.panelDoc.getElementById("node-menu-delete");
     ok(deleteNode, "the popup menu has a delete menu item");
-
     let updated = inspector.once("inspector-updated");
 
     info("Triggering 'Delete Node' and waiting for inspector to update");
     dispatchCommandEvent(deleteNode);
     yield updated;
 
     ok(!(yield testActor.hasNode("#delete")), "Node deleted");
   }
--- a/devtools/client/inspector/test/doc_inspector_menu.html
+++ b/devtools/client/inspector/test/doc_inspector_menu.html
@@ -10,16 +10,17 @@
         <h1>Inspector Tree Menu Test</h1>
         <p class="inner">Unset</p>
         <p class="adjacent">
           <span class="ref">3</span>
         </p>
       </div>
       <p data-id="copy">Paragraph for testing copy</p>
       <p id="sensitivity">Paragraph for sensitivity</p>
+      <p class="duplicate">This will be duplicated</p>
       <p id="delete">This has to be deleted</p>
       <img id="copyimage" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVQYV2P4DwABAQEAWk1v8QAAAABJRU5ErkJggg==" />
       <div id="hiddenElement" style="display: none;">
         <p id="nestedHiddenElement">Visible element nested inside a non-visible element</p>
       </div>
       <p id="console-var">Paragraph for testing console variables</p>
       <p id="console-var-multi">Paragraph for testing multiple console variables</p>
     </div>
--- a/devtools/client/jar.mn
+++ b/devtools/client/jar.mn
@@ -219,24 +219,24 @@ devtools.jar:
     skin/themes/images/editor-debug-location@2x.png (themes/images/editor-debug-location@2x.png)
 *   skin/themes/webconsole.css (themes/webconsole.css)
     skin/themes/images/webconsole.svg (themes/images/webconsole.svg)
     skin/themes/images/breadcrumbs-divider@2x.png (themes/images/breadcrumbs-divider@2x.png)
     skin/themes/images/breadcrumbs-scrollbutton.png (themes/images/breadcrumbs-scrollbutton.png)
     skin/themes/images/breadcrumbs-scrollbutton@2x.png (themes/images/breadcrumbs-scrollbutton@2x.png)
     skin/themes/animationinspector.css (themes/animationinspector.css)
     skin/themes/eyedropper.css (themes/eyedropper.css)
-*   skin/themes/canvasdebugger.css (themes/canvasdebugger.css)
+    skin/themes/canvasdebugger.css (themes/canvasdebugger.css)
     skin/themes/debugger.css (themes/debugger.css)
 *   skin/themes/netmonitor.css (themes/netmonitor.css)
     skin/themes/performance.css (themes/performance.css)
     skin/themes/memory.css (themes/memory.css)
     skin/themes/promisedebugger.css (themes/promisedebugger.css)
     skin/themes/images/timeline-filter.svg (themes/images/timeline-filter.svg)
-*   skin/themes/scratchpad.css (themes/scratchpad.css)
+    skin/themes/scratchpad.css (themes/scratchpad.css)
     skin/themes/shadereditor.css (themes/shadereditor.css)
     skin/themes/storage.css (themes/storage.css)
 *   skin/themes/splitview.css (themes/splitview.css)
     skin/themes/styleeditor.css (themes/styleeditor.css)
     skin/themes/webaudioeditor.css (themes/webaudioeditor.css)
     skin/themes/images/magnifying-glass.png (themes/images/magnifying-glass.png)
     skin/themes/images/magnifying-glass@2x.png (themes/images/magnifying-glass@2x.png)
     skin/themes/images/magnifying-glass-light.png (themes/images/magnifying-glass-light.png)
--- a/devtools/client/shared/test/test-actor.js
+++ b/devtools/client/shared/test/test-actor.js
@@ -77,16 +77,31 @@ var TestActor = exports.TestActor = prot
       selector = selector.shift();
     }
     let node = document.querySelector(selector);
     if (!node) {
       throw new Error("Unable to find element with selector \"" + selector + "\"");
     }
     return node;
   },
+  /**
+   * Helper to get the number of elements matching a selector
+   * @param {string} CSS selector.
+   */
+  getNumberOfElementMatches: protocol.method(function (selector,
+                                                       root=this.content.document) {
+    return root.querySelectorAll(selector).length;
+  }, {
+    request: {
+      selector: Arg(0, "string"),
+    },
+    response: {
+      value: RetVal("number")
+    }
+  }),
 
   /**
    * Get a value for a given attribute name, on one of the elements of the box
    * model highlighter, given its ID.
    * @param {Object} msg The msg.data part expects the following properties
    * - {String} nodeID The full ID of the element to get the attribute for
    * - {String} name The name of the attribute to get
    * - {String} actorID The highlighter actor ID
--- a/devtools/client/themes/canvasdebugger.css
+++ b/devtools/client/themes/canvasdebugger.css
@@ -1,20 +1,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/. */
 
-%filter substitution
-%define darkCheckerboardBackground #000
-%define lightCheckerboardBackground #fff
-%define checkerboardCell rgba(128,128,128,0.2)
-%define checkerboardPattern linear-gradient(45deg, @checkerboardCell@ 25%, transparent 25%, transparent 75%, @checkerboardCell@ 75%, @checkerboardCell@), linear-gradient(45deg, @checkerboardCell@ 25%, transparent 25%, transparent 75%, @checkerboardCell@ 75%, @checkerboardCell@)
-%define gutterWidth 3em
-%define gutterPaddingStart 22px
-
+:root {
+  --gutter-width: 3em;
+  --gutter-padding-start: 22px;
+  --checkerboard-pattern: linear-gradient(45deg, rgba(128,128,128,0.2) 25%, transparent 25%, transparent 75%, rgba(128,128,128,0.2) 75%, rgba(128,128,128,0.2)),
+                          linear-gradient(45deg, rgba(128,128,128,0.2) 25%, transparent 25%, transparent 75%, rgba(128,128,128,0.2) 75%, rgba(128,128,128,0.2));
+}
 /* Reload and waiting notices */
 
 .notice-container {
   margin-top: -50vh;
   background-color: var(--theme-toolbar-background);
   color: var(--theme-body-color-alt);
 }
 
@@ -30,62 +28,45 @@
 }
 
 #waiting-notice {
   font-size: 110%;
 }
 
 /* Snapshots pane */
 
-#snapshots-pane > tabs {
-  -moz-border-end: 1px solid;
-}
-
+#snapshots-pane > tabs,
 #snapshots-pane .devtools-toolbar {
-  -moz-border-end: 1px solid;
-}
-
-.theme-dark #snapshots-pane > tabs,
-.theme-dark #snapshots-pane .devtools-toolbar {
-  -moz-border-end-color: black; /* Match the splitter color. */
-}
-
-.theme-light #snapshots-pane > tabs,
-.theme-light #snapshots-pane .devtools-toolbar {
-  -moz-border-end-color: #aaa; /* Match the splitter color. */
+  -moz-border-end: 1px solid var(--theme-splitter-color);
 }
 
 #record-snapshot {
   list-style-image: url("chrome://devtools/skin/themes/images/profiler-stopwatch.svg");
 }
 
 #record-snapshot[checked] {
   list-style-image: url("chrome://devtools/skin/themes/images/profiler-stopwatch-checked.svg");
 }
 
 /* Snapshots items */
 
 .snapshot-item-thumbnail {
   image-rendering: -moz-crisp-edges;
-  background-image: @checkerboardPattern@;
+  background-image: var(--checkerboard-pattern);
   background-size: 12px 12px, 12px 12px;
   background-position: 0px 0px, 6px 6px;
   background-repeat: repeat, repeat;
 }
 
 .snapshot-item-thumbnail[flipped=true] {
   transform: scaleY(-1);
 }
 
-.theme-dark .snapshot-item-thumbnail {
-  background-color: @darkCheckerboardBackground@;
-}
-
-.theme-light .snapshot-item-thumbnail {
-  background-color: @lightCheckerboardBackground@;
+.snapshot-item-thumbnail {
+  background-color: var(--theme-body-background);
 }
 
 .snapshot-item-details {
   -moz-padding-start: 6px;
 }
 
 .snapshot-item-calls {
   padding-top: 4px;
@@ -229,19 +210,19 @@
   background-color: rgba(223,128,255,0.15);
 }
 
 .theme-light .call-item-view[interesting-call] {
   background-color: rgba(184,46,229,0.1);
 }
 
 .call-item-gutter {
-  width: calc(@gutterWidth@ + @gutterPaddingStart@);
-  -moz-padding-start: @gutterPaddingStart@;
-  -moz-padding-end: 4px;
+  width: calc(var(--gutter-width) + var(--gutter-padding-start));
+  padding-inline-start: var(--gutter-padding-start);
+  padding-inline-end: 4px;
   padding-top: 2px;
   padding-bottom: 2px;
   -moz-border-end: 1px solid;
   -moz-margin-end: 6px;
 }
 
 .selected .call-item-gutter {
   background-image: url("images/editor-debug-location.png");
@@ -295,17 +276,17 @@
   border-color: #111;
 }
 
 .theme-light .call-item-location {
   border-color: #eee;
 }
 
 .call-item-stack {
-  -moz-padding-start: calc(@gutterWidth@ + @gutterPaddingStart@);
+  -moz-padding-start: calc(var(--gutter-width) + var(--gutter-padding-start));
   padding-bottom: 10px;
 }
 
 .theme-dark .call-item-stack {
   background: rgba(0,0,0,0.9);
 }
 
 .theme-light .call-item-stack {
@@ -340,30 +321,23 @@
 #calls-list .selected .call-item-contents > label:not(.call-item-gutter) {
   /* Text inside a selected item should not be custom colored. */
   color: inherit !important;
 }
 
 /* Rendering preview */
 
 #screenshot-container {
-  background-image: @checkerboardPattern@;
+  background-color: var(--theme-body-background);
+  background-image: var(--checkerboard-pattern);
   background-size: 30px 30px, 30px 30px;
   background-position: 0px 0px, 15px 15px;
   background-repeat: repeat, repeat;
 }
 
-.theme-dark #screenshot-container {
-  background-color: @darkCheckerboardBackground@;
-}
-
-.theme-light #screenshot-container {
-  background-color: @lightCheckerboardBackground@;
-}
-
 @media (min-width: 701px) {
   #screenshot-container {
     width: 30vw;
     max-width: 50vw;
     min-width: 100px;
   }
 }
 
@@ -398,57 +372,46 @@
 
 .theme-light #screenshot-dimensions {
   background-color: rgba(255,255,255,0.8);
 }
 
 /* Snapshot filmstrip */
 
 #snapshot-filmstrip {
+  border-top: 1px solid var(--theme-splitter-color);
   overflow: hidden;
 }
 
 .theme-dark #snapshot-filmstrip {
-  border-top: 1px solid #000;
   color: var(--theme-selection-color);
 }
 
 .theme-light #snapshot-filmstrip {
-  border-top: 1px solid #aaa;
   color: var(--theme-body-color-alt);
 }
 
 .filmstrip-thumbnail {
   image-rendering: -moz-crisp-edges;
-  background-image: @checkerboardPattern@;
+  background-color: var(--theme-body-background);
+  background-image: var(--checkerboard-pattern);
   background-size: 12px 12px, 12px 12px;
   background-position: 0px -1px, 6px 5px;
   background-repeat: repeat, repeat;
   background-origin: content-box;
   cursor: pointer;
   padding-top: 1px;
   padding-bottom: 1px;
+  border-inline-end: 1px solid var(--theme-splitter-color);
   transition: opacity 0.1s ease-in-out;
 }
 
 .filmstrip-thumbnail[flipped=true] {
   transform: scaleY(-1);
 }
 
-.theme-dark .filmstrip-thumbnail {
-  background-color: @darkCheckerboardBackground@;
-}
-
-.theme-light .filmstrip-thumbnail {
-  background-color: @lightCheckerboardBackground@;
-}
-
-.filmstrip-thumbnail {
-  -moz-border-end: 1px solid var(--theme-splitter-color)
-}
-
 #snapshot-filmstrip > .filmstrip-thumbnail:hover,
 #snapshot-filmstrip:not(:hover) > .filmstrip-thumbnail[highlighted] {
   border: 1px solid var(--theme-highlight-blue);
   margin: 0 0 0 -1px;
   padding: 0;
   opacity: 0.66;
 }
--- a/devtools/client/themes/scratchpad.css
+++ b/devtools/client/themes/scratchpad.css
@@ -1,13 +1,11 @@
-%if 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/. */
-%endif
 
 #scratchpad-sidebar > tabs {
   height: 0;
   border: none;
 }
 
 #sp-toolbar {
   border: none;
--- a/devtools/client/themes/styleeditor.css
+++ b/devtools/client/themes/styleeditor.css
@@ -62,24 +62,17 @@
 
 .splitview-nav.empty > p {
   padding: 0 10px;
 }
 
 .stylesheet-sidebar {
   max-width: 400px;
   min-width: 100px;
-}
-
-.theme-light .stylesheet-sidebar {
-  border-color: #aaa; /* Splitters */
-}
-
-.theme-dark .stylesheet-sidebar {
-  border-color: #000;  /* Splitters */
+  border-color: var(--theme-splitter-color);
 }
 
 .theme-light .media-rule-label {
   border-bottom-color: #cddae5; /* Grey */
 }
 
 .theme-dark .media-rule-label {
   border-bottom-color: #303b47; /* Grey */
--- a/devtools/client/themes/toolbars.inc.css
+++ b/devtools/client/themes/toolbars.inc.css
@@ -558,57 +558,31 @@
 }
 
 .devtools-sidebar-tabs tabs > tab[selected],
 .devtools-sidebar-tabs tabs > tab[selected] + tab {
   border-image: linear-gradient(var(--theme-splitter-color), var(--theme-splitter-color)) 1 1;
 }
 
 .devtools-sidebar-tabs tabs > tab:first-child {
-  -moz-border-start-width: 0;
-}
-
-.theme-dark .devtools-sidebar-tabs tabs > tab:hover {
-  background: hsla(206,37%,4%,.2);
+  border-inline-start-width: 0;
 }
 
-.theme-dark .devtools-sidebar-tabs tabs > tab:hover:active {
-  background: hsla(206,37%,4%,.4);
-}
-
-.theme-dark .devtools-sidebar-tabs tabs > tab[selected] + tab:hover {
-  background: hsla(206,37%,4%,.2);
-}
-
-.theme-dark .devtools-sidebar-tabs tabs > tab[selected] + tab:hover:active {
-  background: hsla(206,37%,4%,.4);
+.devtools-sidebar-tabs tabs > tab:hover {
+  background: rgba(0, 0, 0, 0.12);
 }
 
-.theme-dark .devtools-sidebar-tabs tabs > tab[selected],
-.theme-dark .devtools-sidebar-tabs tabs > tab[selected]:hover:active {
-  color: var(--theme-selection-color);
-  background: #1d4f73;
-}
-
-.theme-light .devtools-sidebar-tabs tabs > tab:hover {
-  background: #ddd;
+.devtools-sidebar-tabs tabs > tab:hover:active {
+  background: rgba(0, 0, 0, 0.2);
 }
 
-.theme-light .devtools-sidebar-tabs tabs > tab:hover:active {
-  background: #ddd;
-}
-
-.theme-light .devtools-sidebar-tabs tabs > tab[selected] + tab:hover {
-  background: #ddd;
-}
-
-.theme-light .devtools-sidebar-tabs tabs > tab[selected],
-.theme-light .devtools-sidebar-tabs tabs > tab[selected]:hover:active {
+.devtools-sidebar-tabs tabs > tab[selected],
+.devtools-sidebar-tabs tabs > tab[selected]:hover:active {
   color: var(--theme-selection-color);
-  background: #4c9ed9;
+  background: var(--theme-selection-background);
 }
 
 /* Toolbox - moved from toolbox.css.
  * Rules that apply to the global toolbox like command buttons,
  * devtools tabs, docking buttons, etc. */
 
 #toolbox-controls > toolbarbutton,
 #toolbox-dock-buttons > toolbarbutton {
--- a/devtools/client/themes/webaudioeditor.css
+++ b/devtools/client/themes/webaudioeditor.css
@@ -25,49 +25,43 @@ svg {
 
 /* Edges in graph */
 .edgePath path {
   stroke-width: 1px;
   fill: none;
 }
 
 .theme-dark .edgePath path {
-  stroke: #b6babf; /* Grey foreground text */
+  stroke: var(--theme-body-color-alt);
 }
 .theme-light .edgePath path {
-  stroke: #aaaaaa; /* Splitters */
+  stroke: var(--theme-splitter-color);
 }
 
 /* AudioParam connection edges */
 g.edgePath.param-connection {
   stroke-dasharray: 5,5;
 }
 
 .theme-dark .edgePath.param-connection path {
-  stroke: #b6babf; /* Grey foreground text */
+  stroke: var(--theme-body-color-alt);
 }
 .theme-light .edgePath.param-connection path {
-  stroke: #aaaaaa; /* Splitters */
+  stroke: var(--theme-splitter-color);
 }
 
 /* Labels in AudioParam connection should have background that match
  * the main background so there's whitespace around the label, on top of the
  * dotted lines. */
-.theme-dark g.edgeLabel rect {
-  fill: #14171a;
-}
-.theme-light g.edgeLabel rect {
-  fill: #fcfcfc; /* Background - Editor */
+g.edgeLabel rect {
+  fill: var(--theme-body-background);
 }
-.theme-dark g.edgeLabel tspan {
+g.edgeLabel tspan {
   fill: var(--theme-body-color-alt);
 }
-.theme-light g.edgeLabel tspan {
-  fill: #585959; /* Grey foreground text */
-}
 
 /* Audio Nodes */
 .nodes rect {
   stroke-width: 1px;
   cursor: pointer;
 }
 
 .nodes rect {
@@ -214,21 +208,18 @@ text {
   list-style-image: url(images/power.svg);
 }
 
 #audio-node-toolbar toolbarbutton[disabled] {
   opacity: 0.5;
   background-color: transparent;
 }
 
-.theme-dark #audio-node-toolbar toolbarbutton[checked] {
-  background-color: #1d4f73; /* Select Highlight Blue */
-}
-.theme-light #audio-node-toolbar toolbarbutton[checked] {
-  background-color: #4c9ed9; /* Select Highlight Blue */
+#audio-node-toolbar toolbarbutton[checked] {
+  background-color: var(--theme-selection-background);
 }
 
 /* don't invert checked buttons so we can have white icons on light theme */
 #audio-node-toolbar toolbarbutton[checked] > .toolbarbutton-icon {
   filter: none;
 }
 
 
--- a/devtools/client/themes/webconsole.css
+++ b/devtools/client/themes/webconsole.css
@@ -21,17 +21,17 @@ a {
   padding: 0 7px;
   width: 100%;
   box-sizing: border-box;
 }
 
 .message > .prefix,
 .message > .timestamp {
   flex: none;
-  color: GrayText;
+  color: var(--theme-comment);
   margin: 3px 6px 0 0;
 }
 
 .message > .indent {
   flex: none;
 }
 
 .message > .icon {
@@ -126,21 +126,16 @@ a {
   flex: 1 1 auto;
   vertical-align: middle;
 }
 
 .message-flex-body > .message-location {
   margin-top: 0;
 }
 
-.jsterm-input-container {
-  border-top-width: 1px;
-  border-top-style: solid;
-}
-
 #output-wrapper {
   direction: ltr;
   overflow: auto;
 }
 
 #output-container {
   -moz-user-select: text;
   -moz-box-flex: 1;
@@ -248,21 +243,21 @@ a {
 }
 
 .message[category=network] .status {
   flex: none;
   -moz-margin-start: 6px;
 }
 
 .message[category=network].mixed-content .url {
-  color: #FF0000;
+  color: var(--theme-highlight-red);
 }
 
 .message .learn-more-link {
-  color: -moz-nativehyperlinktext;
+  color: var(--theme-highlight-blue);
   margin: 0 6px;
 }
 
 .message[category=network] .xhr {
   background-color: var(--theme-body-color-alt);
   color: var(--theme-body-background);
   border-radius: 3px;
   font-weight: bold;
@@ -355,28 +350,45 @@ a {
   background-position: -48px -36px;
 }
 
 .message[category=output] > .icon::before {
   background-position: -60px -36px;
 }
 
 /* JSTerm Styles */
+.jsterm-input-container {
+  background-color: var(--theme-tab-toolbar-background);
+  border-top: 1px solid var(--theme-splitter-color);
+}
+
+.theme-light .jsterm-input-container {
+  /* For light theme use a white background for the input - it looks better
+     than off-white */
+  background-color: #fff;
+  border-top-color: #e0e0e0;
+}
+
 .jsterm-input-node,
 .jsterm-complete-node {
   border: none;
   padding: 0 0 0 16px;
   -moz-appearance: none;
   background-color: transparent;
 }
 
+.jsterm-complete-node {
+  color: var(--theme-comment);
+}
+
 .jsterm-input-node {
   background-image: -moz-image-rect(url("chrome://devtools/skin/themes/images/commandline-icon.png"), 0, 32, 16, 16);
   background-repeat: no-repeat;
   background-size: 16px 16px;
+  color: var(--theme-content-color1);
 }
 
 @media (min-resolution: 1.1dppx) {
   .jsterm-input-node {
     background-image: -moz-image-rect(url('chrome://devtools/skin/themes/images/commandline-icon@2x.png'), 0, 64, 32, 32);
   }
 }
 
@@ -393,17 +405,17 @@ a {
   min-height: 200px;
 }
 .inlined-variables-view iframe {
   display: block;
   flex: 1;
   margin-top: 5px;
   margin-bottom: 15px;
   -moz-margin-end: 15px;
-  border: 1px solid rgba(128, 128, 128, .5);
+  border: 1px solid var(--theme-splitter-color);
   border-radius: 3px;
 }
 
 #webconsole-sidebar > tabs {
   height: 0;
   border: none;
 }
 
@@ -437,26 +449,31 @@ a {
   margin-top: 6px;
   margin-bottom: 6px;
   font-size: 0.9em;
 }
 
 .navigation-marker .url {
   -moz-padding-end: 9px;
   text-decoration: none;
+  background: var(--theme-body-background);
+}
+
+.theme-light .navigation-marker .url {
+  background: #fff;
 }
 
 .stacktrace {
   display: none;
   list-style: none;
   padding: 0 1em 0 1.5em;
   margin: 5px 0 0 0;
   max-height: 10em;
   overflow-y: auto;
-  border: 1px solid rgb(200,200,200);
+  border: 1px solid var(--theme-splitter-color);
   border-radius: 3px;
 }
 
 .consoletable {
   margin: 5px 0 0 0;
 }
 
 .theme-light .message[severity=error] .stacktrace {
@@ -509,59 +526,16 @@ a {
 .open-inspector:hover {
   background-position: -32px 0;
 }
 
 .open-inspector:active {
   background-position: -16px 0;
 }
 
-.jsterm-input-container {
-  background-color: var(--theme-tab-toolbar-background);
-  border-color: var(--theme-body-background);
-}
-
-.jsterm-input-node {
-  color: var(--theme-content-color1);
-}
-
-.jsterm-complete-node {
-  color: var(--theme-comment);
-}
-
-.navigation-marker .url {
-  background: var(--theme-body-background);
-}
-
-.theme-dark .inlined-variables-view iframe {
-  border-color: #333;
-}
-
-.theme-dark .stacktrace {
-  border-color: #333;
-}
-
-.theme-light .jsterm-input-container {
-  /* For light theme use a white background for the input - it looks better
-     than off-white */
-  background-color: #fff;
-  border-color: ThreeDShadow;
-}
-.theme-light .navigation-marker .url {
-  background: #fff;
-}
-
-.theme-light .inlined-variables-view iframe {
-  border-color: #ccc;
-}
-
-.theme-light .stacktrace {
-  border-color: #ccc;
-}
-
 @media (max-width: 500px) {
   .message > .timestamp {
     display: none;
   }
   .hud-console-filter-toolbar .webconsole-filter-button .toolbarbutton-text {
     display: none;
   }
   .hud-console-filter-toolbar .webconsole-filter-button {
--- a/devtools/server/actors/inspector.js
+++ b/devtools/server/actors/inspector.js
@@ -2588,16 +2588,31 @@ var WalkerActor = protocol.ActorClass({
       node: Arg(0, "domnode"),
       position: Arg(1, "string"),
       value: Arg(2, "string")
     },
     response: RetVal("disconnectedNodeArray")
   }),
 
   /**
+   * Duplicate a specified node
+   *
+   * @param {NodeActor} node The node to duplicate.
+   */
+  duplicateNode: method(function({rawNode}) {
+    let clonedNode = rawNode.cloneNode(true);
+    rawNode.parentNode.insertBefore(clonedNode, rawNode.nextSibling);
+  }, {
+    request: {
+      node: Arg(0, "domnode")
+    },
+    response: {}
+  }),
+
+  /**
    * Test whether a node is a document or a document element.
    *
    * @param {NodeActor} node The node to remove.
    * @return {boolean} True if the node is a document or a document element.
    */
   isDocumentOrDocumentElementNode: function(node) {
       return ((node.rawNode.ownerDocument &&
         node.rawNode.ownerDocument.documentElement === this.rawNode) ||
--- a/devtools/server/tests/mochitest/chrome.ini
+++ b/devtools/server/tests/mochitest/chrome.ini
@@ -52,16 +52,17 @@ skip-if = buildapp == 'mulet'
 [test_framerate_06.html]
 skip-if = buildapp == 'mulet'
 [test_getProcess.html]
 skip-if = buildapp == 'mulet'
 [test_inspector-anonymous.html]
 [test_inspector-changeattrs.html]
 [test_inspector-changevalue.html]
 [test_inspector-dead-nodes.html]
+[test_inspector-duplicate-node.html]
 [test_inspector_getImageData.html]
 skip-if = buildapp == 'mulet'
 [test_inspector_getImageDataFromURL.html]
 skip-if = buildapp == 'mulet'
 [test_inspector_getImageData-wait-for-load.html]
 skip-if = buildapp == 'mulet'
 [test_inspector_getNodeFromActor.html]
 [test_inspector-hide.html]
--- a/devtools/server/tests/mochitest/inspector-traversal-data.html
+++ b/devtools/server/tests/mochitest/inspector-traversal-data.html
@@ -75,17 +75,16 @@
   <div id="longlist-sibling">
     <div id="longlist-sibling-firstchild"></div>
   </div>
   <p id="edit-html"></p>
 
   <select multiple><option>one</option><option>two</option></select>
   <div id="pseudo"><span>middle</span></div>
   <div id="pseudo-empty"></div>
-
   <div id="shadow">light dom</div>
-
   <object>
       <div id="1"></div>
   </object>
+  <div class="node-to-duplicate"></div>
   <div id="scroll-into-view" style="margin-top: 1000px;">scroll</div>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/devtools/server/tests/mochitest/test_inspector-duplicate-node.html
@@ -0,0 +1,75 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1208864
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1208864</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">
+  <script type="application/javascript;version=1.8" src="inspector-helpers.js"></script>
+  <script type="application/javascript;version=1.8">
+const inspector = require("devtools/server/actors/inspector");
+
+window.onload = function() {
+  SimpleTest.waitForExplicitFinish();
+  runNextTest();
+}
+
+var gInspectee = null;
+var gClient = null;
+var gWalker = null;
+
+function assertOwnership() {
+  assertOwnershipTrees(gWalker);
+}
+
+addTest(function setup() {
+  let url = document.getElementById("inspectorContent").href;
+  attachURL(url, function(err, client, tab, doc) {
+    gInspectee = doc;
+    let {InspectorFront} = require("devtools/server/actors/inspector");
+    let inspector = InspectorFront(client, tab);
+    promiseDone(inspector.getWalker().then(walker => {
+      ok(walker, "getWalker() should return an actor.");
+      gClient = client;
+      gWalker = walker;
+    }).then(runNextTest));
+  });
+});
+
+addTest(Task.async(function* testDuplicateNode() {
+  let className = ".node-to-duplicate";
+  let matches = yield gWalker.querySelectorAll(gWalker.rootNode, className);
+  is(matches.length, 1, "There should initially be one node to duplicate.");
+
+  let nodeFront = yield gWalker.querySelector(gWalker.rootNode, className);
+  yield gWalker.duplicateNode(nodeFront);
+
+  matches = yield gWalker.querySelectorAll(gWalker.rootNode, className);
+  is(matches.length, 2, "The node should now be duplicated.");
+
+  runNextTest();
+}));
+
+addTest(function cleanup() {
+  delete gWalker;
+  delete gInspectee;
+  delete gClient;
+  runNextTest();
+});
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1208864">Mozilla Bug 1208864</a>
+<a id="inspectorContent" target="_blank" href="inspector-traversal-data.html">Test Document</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/devtools/shared/DevToolsUtils.js
+++ b/devtools/shared/DevToolsUtils.js
@@ -453,16 +453,35 @@ exports.dbg_assert = function dbg_assert
     }
   }
 
   if (!cond) {
     return e;
   }
 };
 
+exports.defineLazyGetter(this, "AppConstants", () => {
+  const scope = {};
+  Cu.import("resource://gre/modules/AppConstants.jsm", scope);
+  return scope.AppConstants;
+});
+
+/**
+ * No operation. The empty function.
+ */
+exports.noop = function () { };
+
+function reallyAssert(condition, message) {
+  if (!condition) {
+    const err = new Error("Assertion failure: " + message);
+    exports.reportException("DevToolsUtils.assert", err);
+    throw err;
+  }
+}
+
 /**
  * DevToolsUtils.assert(condition, message)
  *
  * @param Boolean condition
  * @param String message
  *
  * Assertions are enabled when any of the following are true:
  *   - This is a DEBUG_JS_MODULES build
@@ -472,33 +491,21 @@ exports.dbg_assert = function dbg_assert
  * If assertions are enabled, then `condition` is checked and if false-y, the
  * assertion failure is logged and then an error is thrown.
  *
  * If assertions are not enabled, then this function is a no-op.
  *
  * This is an improvement over `dbg_assert`, which doesn't actually cause any
  * fatal behavior, and is therefore much easier to accidentally ignore.
  */
-exports.defineLazyGetter(exports, "assert", () => {
-  function noop(condition, msg) { }
-
-  function assert(condition, message) {
-    if (!condition) {
-      const err = new Error("Assertion failure: " + message);
-      exports.reportException("DevToolsUtils.assert", err);
-      throw err;
-    }
-  }
-
-  const scope = {};
-  Cu.import("resource://gre/modules/AppConstants.jsm", scope);
-  const { DEBUG, DEBUG_JS_MODULES } = scope.AppConstants;
-
-  return (DEBUG || DEBUG_JS_MODULES || exports.testing) ? assert : noop;
-});
+Object.defineProperty(exports, "assert", {
+  get: () => (AppConstants.DEBUG || AppConstants.DEBUG_JS_MODULES || this.testing)
+    ? reallyAssert
+    : exports.noop,
+})
 
 /**
  * Defines a getter on a specified object for a module.  The module will not
  * be imported until first use.
  *
  * @param aObject
  *        The object to define the lazy getter on.
  * @param aName
--- a/devtools/shared/heapsnapshot/HeapSnapshot.h
+++ b/devtools/shared/heapsnapshot/HeapSnapshot.h
@@ -5,16 +5,17 @@
 
 #ifndef mozilla_devtools_HeapSnapshot__
 #define mozilla_devtools_HeapSnapshot__
 
 #include "js/HashTable.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/devtools/DeserializedNode.h"
 #include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/Nullable.h"
 #include "mozilla/HashFunctions.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/RefCounted.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/UniquePtr.h"
 
 #include "CoreDump.pb.h"
@@ -134,16 +135,25 @@ public:
     auto p = nodes.lookup(rootId);
     MOZ_ASSERT(p);
     const DeserializedNode& node = *p;
     return JS::ubi::Node(const_cast<DeserializedNode*>(&node));
   }
 
   void TakeCensus(JSContext* cx, JS::HandleObject options,
                   JS::MutableHandleValue rval, ErrorResult& rv);
+
+  dom::Nullable<uint64_t> GetCreationTime() {
+    static const uint64_t maxTime = uint64_t(1) << 53;
+    if (timestamp.isSome() && timestamp.ref() <= maxTime) {
+      return dom::Nullable<uint64_t>(timestamp.ref());
+    }
+
+    return dom::Nullable<uint64_t>();
+  }
 };
 
 // A `CoreDumpWriter` is given the data we wish to save in a core dump and
 // serializes it to disk, or memory, or a socket, etc.
 class CoreDumpWriter
 {
 public:
   virtual ~CoreDumpWriter() { };
new file mode 100644
--- /dev/null
+++ b/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_creationTime_01.js
@@ -0,0 +1,29 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// HeapSnapshot.prototype.creationTime returns the expected time.
+
+function waitForTenMilliseconds() {
+  const start = Date.now();
+  while (Date.now() - start < 10) ;
+}
+
+function run_test() {
+  const start = Date.now() * 1000;
+  do_print("start                 = " + start);
+
+  // Because Date.now() is less precise than the snapshot's time stamp, give it
+  // a little bit of head room.
+  waitForTenMilliseconds();
+  const path = ChromeUtils.saveHeapSnapshot({ runtime: true });
+  waitForTenMilliseconds();
+
+  const end = Date.now() * 1000;
+  do_print("end                   = " + end);
+
+  const snapshot = ChromeUtils.readHeapSnapshot(path);
+  do_print("snapshot.creationTime = " + snapshot.creationTime);
+
+  ok(snapshot.creationTime >= start);
+  ok(snapshot.creationTime <= end);
+}
--- a/devtools/shared/heapsnapshot/tests/unit/xpcshell.ini
+++ b/devtools/shared/heapsnapshot/tests/unit/xpcshell.ini
@@ -20,16 +20,17 @@ support-files =
 [test_census-tree-node-03.js]
 [test_HeapAnalyses_readHeapSnapshot_01.js]
 [test_HeapAnalyses_takeCensusDiff_01.js]
 [test_HeapAnalyses_takeCensus_01.js]
 [test_HeapAnalyses_takeCensus_02.js]
 [test_HeapAnalyses_takeCensus_03.js]
 [test_HeapAnalyses_takeCensus_04.js]
 [test_HeapAnalyses_takeCensus_05.js]
+[test_HeapSnapshot_creationTime_01.js]
 [test_HeapSnapshot_takeCensus_01.js]
 [test_HeapSnapshot_takeCensus_02.js]
 [test_HeapSnapshot_takeCensus_03.js]
 [test_HeapSnapshot_takeCensus_04.js]
 [test_HeapSnapshot_takeCensus_05.js]
 [test_HeapSnapshot_takeCensus_06.js]
 [test_HeapSnapshot_takeCensus_07.js]
 [test_HeapSnapshot_takeCensus_08.js]
--- a/devtools/shared/tests/unit/head_devtools.js
+++ b/devtools/shared/tests/unit/head_devtools.js
@@ -4,16 +4,21 @@ var Ci = Components.interfaces;
 var Cu = Components.utils;
 var Cr = Components.results;
 
 var {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm");
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 
 // Register a console listener, so console messages don't just disappear
 // into the ether.
+
+// If for whatever reason the test needs to post console errors that aren't
+// failures, set this to true.
+var ALLOW_CONSOLE_ERRORS = false;
+
 var errorCount = 0;
 var listener = {
   observe: function (aMessage) {
     errorCount++;
     try {
       // If we've been given an nsIScriptError, then we can print out
       // something nicely formatted, for tools like Emacs to pick up.
       var scriptError = aMessage.QueryInterface(Ci.nsIScriptError);
@@ -30,14 +35,17 @@ var listener = {
         var string = "<error converting error message to string>";
       }
     }
 
     // Make sure we exit all nested event loops so that the test can finish.
     while (DebuggerServer.xpcInspector.eventLoopNestLevel > 0) {
       DebuggerServer.xpcInspector.exitNestedEventLoop();
     }
-    do_throw("head_dbg.js got console message: " + string + "\n");
+
+    if (!ALLOW_CONSOLE_ERRORS) {
+      do_throw("head_devtools.js got console message: " + string + "\n");
+    }
   }
 };
 
 var consoleService = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
 consoleService.registerListener(listener);
new file mode 100644
--- /dev/null
+++ b/devtools/shared/tests/unit/test_assert.js
@@ -0,0 +1,36 @@
+/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test DevToolsUtils.assert
+
+ALLOW_CONSOLE_ERRORS = true;
+
+function run_test() {
+  // Enable assertions.
+  DevToolsUtils.testing = true;
+
+  const { assert } = DevToolsUtils;
+  equal(typeof assert, "function");
+
+  try {
+    assert(true, "this assertion should not fail");
+  } catch (e) {
+    // If you catch assertion failures in practice, I will hunt you down. I get
+    // email notifications every time it happens.
+    ok(false, "Should not get an error for an assertion that should not fail. Got "
+       + DevToolsUtils.safeErrorString(e));
+  }
+
+  let assertionFailed = false;
+  try {
+    assert(false, "this assertion should fail");
+  } catch (e) {
+    ok(e.message.startsWith("Assertion failure:"),
+       "Should be an assertion failure error");
+    assertionFailed = true;
+  }
+
+  ok(assertionFailed,
+     "The assertion should have failed, which should throw an error when assertions are enabled.");
+}
--- a/devtools/shared/tests/unit/xpcshell.ini
+++ b/devtools/shared/tests/unit/xpcshell.ini
@@ -1,16 +1,17 @@
 [DEFAULT]
 tags = devtools
 head = head_devtools.js
 tail =
 skip-if = toolkit == 'android' || toolkit == 'gonk'
 support-files =
   exposeLoader.js
 
+[test_assert.js]
 [test_fetch-chrome.js]
 [test_fetch-file.js]
 [test_fetch-http.js]
 [test_fetch-resource.js]
 [test_indentation.js]
 [test_independent_loaders.js]
 [test_invisible_loader.js]
 [test_safeErrorString.js]
--- a/dom/base/StructuredCloneHolder.cpp
+++ b/dom/base/StructuredCloneHolder.cpp
@@ -857,39 +857,40 @@ WriteFormData(JSStructuredCloneWriter* a
   public:
     Closure(JSStructuredCloneWriter* aWriter,
             StructuredCloneHolder* aHolder)
       : mWriter(aWriter),
         mHolder(aHolder)
     { }
 
     static bool
-    Write(const nsString& aName, bool isFile, const nsString& aValue,
-          File* aFile, void* aClosure)
+    Write(const nsString& aName, const OwningFileOrUSVString& aValue,
+          void* aClosure)
     {
       Closure* closure = static_cast<Closure*>(aClosure);
       if (!WriteString(closure->mWriter, aName)) {
         return false;
       }
 
-      if (isFile) {
-        BlobImpl* blobImpl = aFile->Impl();
+      if (aValue.IsFile()) {
+        BlobImpl* blobImpl = aValue.GetAsFile()->Impl();
         if (!JS_WriteUint32Pair(closure->mWriter, SCTAG_DOM_BLOB,
                                 closure->mHolder->BlobImpls().Length())) {
           return false;
         }
 
         closure->mHolder->BlobImpls().AppendElement(blobImpl);
         return true;
       }
 
       size_t charSize = sizeof(nsString::char_type);
-      if (!JS_WriteUint32Pair(closure->mWriter, 0, aValue.Length()) ||
-          !JS_WriteBytes(closure->mWriter, aValue.get(),
-                         aValue.Length() * charSize)) {
+      if (!JS_WriteUint32Pair(closure->mWriter, 0,
+                              aValue.GetAsUSVString().Length()) ||
+          !JS_WriteBytes(closure->mWriter, aValue.GetAsUSVString().get(),
+                         aValue.GetAsUSVString().Length() * charSize)) {
         return false;
       }
 
       return true;
     }
   };
   Closure closure(aWriter, aHolder);
   return aFormData->ForEach(Closure::Write, &closure);
--- a/dom/base/nsFormData.cpp
+++ b/dom/base/nsFormData.cpp
@@ -56,28 +56,28 @@ CreateNewFileInstance(Blob& aBlob, const
 // nsISupports
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsFormData)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFormData)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
 
   for (uint32_t i = 0, len = tmp->mFormData.Length(); i < len; ++i) {
-    ImplCycleCollectionUnlink(tmp->mFormData[i].fileValue);
+    ImplCycleCollectionUnlink(tmp->mFormData[i].value);
   }
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFormData)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
 
   for (uint32_t i = 0, len = tmp->mFormData.Length(); i < len; ++i) {
-   ImplCycleCollectionTraverse(cb,tmp->mFormData[i].fileValue,
-                               "mFormData[i].fileValue", 0);
+    ImplCycleCollectionTraverse(cb, tmp->mFormData[i].value,
+                                "mFormData[i].GetAsFile()", 0);
   }
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsFormData)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFormData)
@@ -122,48 +122,37 @@ nsFormData::Delete(const nsAString& aNam
   for (uint32_t i = mFormData.Length(); i-- > 0; ) {
     if (aName.Equals(mFormData[i].name)) {
       mFormData.RemoveElementAt(i);
     }
   }
 }
 
 void
-nsFormData::ExtractValue(const FormDataTuple& aTuple,
-                         OwningFileOrUSVString* aOutValue)
-{
-  if (aTuple.valueIsFile) {
-    aOutValue->SetAsFile() = aTuple.fileValue;
-  } else {
-    aOutValue->SetAsUSVString() = aTuple.stringValue;
-  }
-}
-
-void
 nsFormData::Get(const nsAString& aName,
                 Nullable<OwningFileOrUSVString>& aOutValue)
 {
   for (uint32_t i = 0; i < mFormData.Length(); ++i) {
     if (aName.Equals(mFormData[i].name)) {
-      ExtractValue(mFormData[i], &aOutValue.SetValue());
+      aOutValue.SetValue() = mFormData[i].value;
       return;
     }
   }
 
   aOutValue.SetNull();
 }
 
 void
 nsFormData::GetAll(const nsAString& aName,
                    nsTArray<OwningFileOrUSVString>& aValues)
 {
   for (uint32_t i = 0; i < mFormData.Length(); ++i) {
     if (aName.Equals(mFormData[i].name)) {
       OwningFileOrUSVString* element = aValues.AppendElement();
-      ExtractValue(mFormData[i], element);
+      *element = mFormData[i].value;
     }
   }
 }
 
 bool
 nsFormData::Has(const nsAString& aName)
 {
   for (uint32_t i = 0; i < mFormData.Length(); ++i) {
@@ -224,16 +213,36 @@ nsFormData::Set(const nsAString& aName, 
   FormDataTuple* tuple = RemoveAllOthersAndGetFirstFormDataTuple(aName);
   if (tuple) {
     SetNameValuePair(tuple, aName, aValue);
   } else {
     Append(aName, aValue);
   }
 }
 
+uint32_t
+nsFormData::GetIterableLength() const
+{
+  return mFormData.Length();
+}
+
+const nsAString&
+nsFormData::GetKeyAtIndex(uint32_t aIndex) const
+{
+  MOZ_ASSERT(aIndex < mFormData.Length());
+  return mFormData[aIndex].name;
+}
+
+const OwningFileOrUSVString&
+nsFormData::GetValueAtIndex(uint32_t aIndex) const
+{
+  MOZ_ASSERT(aIndex < mFormData.Length());
+  return mFormData[aIndex].value;
+}
+
 // -------------------------------------------------------------------------
 // nsIDOMFormData
 
 NS_IMETHODIMP
 nsFormData::Append(const nsAString& aName, nsIVariant* aValue)
 {
   uint16_t dataType;
   nsresult rv = aValue->GetDataType(&dataType);
@@ -292,21 +301,23 @@ nsFormData::Constructor(const GlobalObje
 
 NS_IMETHODIMP
 nsFormData::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
                         nsACString& aContentType, nsACString& aCharset)
 {
   nsFSMultipartFormData fs(NS_LITERAL_CSTRING("UTF-8"), nullptr);
 
   for (uint32_t i = 0; i < mFormData.Length(); ++i) {
-    if (mFormData[i].valueIsFile) {
-      fs.AddNameFilePair(mFormData[i].name, mFormData[i].fileValue);
-    }
-    else {
-      fs.AddNameValuePair(mFormData[i].name, mFormData[i].stringValue);
+    if (mFormData[i].value.IsFile()) {
+      fs.AddNameFilePair(mFormData[i].name, mFormData[i].value.GetAsFile());
+    } else if (mFormData[i].value.IsUSVString()) {
+      fs.AddNameValuePair(mFormData[i].name,
+                          mFormData[i].value.GetAsUSVString());
+    } else {
+      fs.AddNameFilePair(mFormData[i].name, nullptr);
     }
   }
 
   fs.GetContentType(aContentType);
   aCharset.Truncate();
   *aContentLength = 0;
   NS_ADDREF(*aBody = fs.GetSubmissionBody(aContentLength));
 
--- a/dom/base/nsFormData.h
+++ b/dom/base/nsFormData.h
@@ -32,52 +32,49 @@ class nsFormData final : public nsIDOMFo
                          public nsFormSubmission,
                          public nsWrapperCache
 {
 private:
   ~nsFormData() {}
 
   typedef mozilla::dom::Blob Blob;
   typedef mozilla::dom::File File;
+  typedef mozilla::dom::OwningFileOrUSVString OwningFileOrUSVString;
 
   struct FormDataTuple
   {
     nsString name;
-    nsString stringValue;
-    RefPtr<File> fileValue;
-    bool valueIsFile;
+    OwningFileOrUSVString value;
   };
 
   // Returns the FormDataTuple to modify. This may be null, in which case
   // no element with aName was found.
   FormDataTuple*
   RemoveAllOthersAndGetFirstFormDataTuple(const nsAString& aName);
 
   void SetNameValuePair(FormDataTuple* aData,
                         const nsAString& aName,
                         const nsAString& aValue)
   {
     MOZ_ASSERT(aData);
     aData->name = aName;
-    aData->stringValue = aValue;
-    aData->valueIsFile = false;
+    aData->value.SetAsUSVString() = aValue;
   }
 
   void SetNameFilePair(FormDataTuple* aData,
                        const nsAString& aName,
                        File* aFile)
   {
     MOZ_ASSERT(aData);
     aData->name = aName;
-    aData->fileValue = aFile;
-    aData->valueIsFile = true;
+    if (aFile) {
+      aData->value.SetAsFile() = aFile;
+    }
   }
 
-  void ExtractValue(const FormDataTuple& aTuple,
-                    mozilla::dom::OwningFileOrUSVString* aOutValue);
 public:
   explicit nsFormData(nsISupports* aOwner = nullptr);
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsFormData,
                                                          nsIDOMFormData)
 
   NS_DECL_NSIDOMFORMDATA
@@ -95,55 +92,58 @@ public:
   static already_AddRefed<nsFormData>
   Constructor(const mozilla::dom::GlobalObject& aGlobal,
               const mozilla::dom::Optional<mozilla::dom::NonNull<mozilla::dom::HTMLFormElement> >& aFormElement,
               mozilla::ErrorResult& aRv);
   void Append(const nsAString& aName, const nsAString& aValue);
   void Append(const nsAString& aName, Blob& aBlob,
               const mozilla::dom::Optional<nsAString>& aFilename);
   void Delete(const nsAString& aName);
-  void Get(const nsAString& aName, mozilla::dom::Nullable<mozilla::dom::OwningFileOrUSVString>& aOutValue);
-  void GetAll(const nsAString& aName, nsTArray<mozilla::dom::OwningFileOrUSVString>& aValues);
+  void Get(const nsAString& aName, mozilla::dom::Nullable<OwningFileOrUSVString>& aOutValue);
+  void GetAll(const nsAString& aName, nsTArray<OwningFileOrUSVString>& aValues);
   bool Has(const nsAString& aName);
   void Set(const nsAString& aName, Blob& aBlob,
            const mozilla::dom::Optional<nsAString>& aFilename);
   void Set(const nsAString& aName, const nsAString& aValue);
 
+  uint32_t GetIterableLength() const;
+  const nsAString& GetKeyAtIndex(uint32_t aIndex) const;
+  const OwningFileOrUSVString& GetValueAtIndex(uint32_t aIndex) const;
+
   // nsFormSubmission
   virtual nsresult GetEncodedSubmission(nsIURI* aURI,
                                         nsIInputStream** aPostDataStream) override;
   virtual nsresult AddNameValuePair(const nsAString& aName,
                                     const nsAString& aValue) override
   {
     FormDataTuple* data = mFormData.AppendElement();
     SetNameValuePair(data, aName, aValue);
     return NS_OK;
   }
   virtual nsresult AddNameFilePair(const nsAString& aName,
                                    File* aFile) override;
 
-  typedef bool (*FormDataEntryCallback)(const nsString& aName, bool aIsFile,
-                                        const nsString& aValue,
-                                        File* aFile, void* aClosure);
+  typedef bool (*FormDataEntryCallback)(const nsString& aName,
+                                        const OwningFileOrUSVString& aValue,
+                                        void* aClosure);
 
   uint32_t
   Length() const
   {
     return mFormData.Length();
   }
 
   // Stops iteration and returns false if any invocation of callback returns
   // false. Returns true otherwise.
   bool
   ForEach(FormDataEntryCallback aFunc, void* aClosure)
   {
     for (uint32_t i = 0; i < mFormData.Length(); ++i) {
       FormDataTuple& tuple = mFormData[i];
-      if (!aFunc(tuple.name, tuple.valueIsFile, tuple.stringValue,
-                 tuple.fileValue, aClosure)) {
+      if (!aFunc(tuple.name, tuple.value, aClosure)) {
         return false;
       }
     }
 
     return true;
   }
 
 private:
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -5593,16 +5593,18 @@ CanvasRenderingContext2D::GetCanvasLayer
 
     GLuint skiaGLTex = SkiaGLTex();
     if (skiaGLTex) {
       SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
       MOZ_ASSERT(glue);
 
       data.mGLContext = glue->GetGLContext();
       data.mFrontbufferGLTex = skiaGLTex;
+      PersistentBufferProvider *provider = GetBufferProvider(aManager);
+      data.mBufferProvider = provider;
     } else {
       PersistentBufferProvider *provider = GetBufferProvider(aManager);
       data.mBufferProvider = provider;
     }
 
     if (userData && userData->IsForContext(this) && aOldLayer->IsDataValid(data)) {
       RefPtr<CanvasLayer> ret = aOldLayer;
       return ret.forget();
@@ -5643,16 +5645,18 @@ CanvasRenderingContext2D::GetCanvasLayer
 
   GLuint skiaGLTex = SkiaGLTex();
   if (skiaGLTex) {
     SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
     MOZ_ASSERT(glue);
 
     data.mGLContext = glue->GetGLContext();
     data.mFrontbufferGLTex = skiaGLTex;
+    PersistentBufferProvider *provider = GetBufferProvider(aManager);
+    data.mBufferProvider = provider;
   } else {
     PersistentBufferProvider *provider = GetBufferProvider(aManager);
     data.mBufferProvider = provider;
   }
 
   canvasLayer->Initialize(data);
   uint32_t flags = mOpaque ? Layer::CONTENT_OPAQUE : 0;
   canvasLayer->SetContentFlags(flags);
--- a/dom/fetch/Headers.h
+++ b/dom/fetch/Headers.h
@@ -97,16 +97,29 @@ public:
     return mInternalHeaders->Has(aName, aRv);
   }
 
   void Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv)
   {
     mInternalHeaders->Set(aName, aValue, aRv);
   }
 
+  uint32_t GetIterableLength() const
+  {
+    return mInternalHeaders->GetIterableLength();
+  }
+  const nsString GetKeyAtIndex(unsigned aIndex) const
+  {
+    return mInternalHeaders->GetKeyAtIndex(aIndex);
+  }
+  const nsString GetValueAtIndex(unsigned aIndex) const
+  {
+    return mInternalHeaders->GetValueAtIndex(aIndex);
+  }
+
   // ChromeOnly
   HeadersGuardEnum Guard() const
   {
     return mInternalHeaders->Guard();
   }
 
   void SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv)
   {
--- a/dom/fetch/InternalHeaders.h
+++ b/dom/fetch/InternalHeaders.h
@@ -46,35 +46,53 @@ private:
 
 public:
   explicit InternalHeaders(HeadersGuardEnum aGuard = HeadersGuardEnum::None)
     : mGuard(aGuard)
   {
   }
 
   explicit InternalHeaders(const InternalHeaders& aOther)
-    : mGuard(aOther.mGuard)
+    : mGuard(HeadersGuardEnum::None)
   {
     ErrorResult result;
     Fill(aOther, result);
     MOZ_ASSERT(!result.Failed());
+    // Note that it's important to set the guard after Fill(), to make sure
+    // that Fill() doesn't fail if aOther is immutable.
+    mGuard = aOther.mGuard;
   }
 
   explicit InternalHeaders(const nsTArray<Entry>&& aHeaders,
                            HeadersGuardEnum aGuard = HeadersGuardEnum::None);
 
   void Append(const nsACString& aName, const nsACString& aValue,
               ErrorResult& aRv);
   void Delete(const nsACString& aName, ErrorResult& aRv);
   void Get(const nsACString& aName, nsCString& aValue, ErrorResult& aRv) const;
   void GetAll(const nsACString& aName, nsTArray<nsCString>& aResults,
               ErrorResult& aRv) const;
   bool Has(const nsACString& aName, ErrorResult& aRv) const;
   void Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv);
 
+  uint32_t GetIterableLength() const
+  {
+    return mList.Length();
+  }
+  const NS_ConvertASCIItoUTF16 GetKeyAtIndex(unsigned aIndex) const
+  {
+    MOZ_ASSERT(aIndex < mList.Length());
+    return NS_ConvertASCIItoUTF16(mList[aIndex].mName);
+  }
+  const NS_ConvertASCIItoUTF16 GetValueAtIndex(unsigned aIndex) const
+  {
+    MOZ_ASSERT(aIndex < mList.Length());
+    return NS_ConvertASCIItoUTF16(mList[aIndex].mValue);
+  }
+
   void Clear();
 
   HeadersGuardEnum Guard() const { return mGuard; }
   void SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv);
 
   void Fill(const InternalHeaders& aInit, ErrorResult& aRv);
   void Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& aRv);
   void Fill(const MozMap<nsCString>& aInit, ErrorResult& aRv);
--- a/dom/html/test/formData_test.js
+++ b/dom/html/test/formData_test.js
@@ -100,16 +100,66 @@ function testFilename() {
   file = new File(["hi"], "file2.txt");
   f.append("file2", file, "fakename.txt");
   ok(f.get("file2") !== file, "Retrieved File object should be new File object if explicit filename is passed.");
   is(f.get("file2").name, "fakename.txt", "File's filename should be explicitly passed name.");
   f.append("file3", new File(["hi"], ""));
   is(f.get("file3").name, "", "File's filename is returned even if empty.");
 }
 
+function testIterable() {
+  var fd = new FormData();
+  fd.set('1','2');
+  fd.set('2','4');
+  fd.set('3','6');
+  fd.set('4','8');
+  fd.set('5','10');
+
+  var key_iter = fd.keys();
+  var value_iter = fd.values();
+  var entries_iter = fd.entries();
+  for (var i = 0; i < 5; ++i) {
+    var v = i + 1;
+    var key = key_iter.next();
+    var value = value_iter.next();
+    var entry = entries_iter.next();
+    is(key.value, v.toString(), "Correct Key iterator: " + v.toString());
+    ok(!key.done, "key.done is false");
+    is(value.value, (v * 2).toString(), "Correct Value iterator: " + (v * 2).toString());
+    ok(!value.done, "value.done is false");
+    is(entry.value[0], v.toString(), "Correct Entry 0 iterator: " + v.toString());
+    is(entry.value[1], (v * 2).toString(), "Correct Entry 1 iterator: " + (v * 2).toString());
+    ok(!entry.done, "entry.done is false");
+  }
+
+  var last = key_iter.next();
+  ok(last.done, "Nothing more to read.");
+  is(last.value, undefined, "Undefined is the last key");
+
+  last = value_iter.next();
+  ok(last.done, "Nothing more to read.");
+  is(last.value, undefined, "Undefined is the last value");
+
+  last = entries_iter.next();
+  ok(last.done, "Nothing more to read.");
+
+  key_iter = fd.keys();
+  key_iter.next();
+  key_iter.next();
+  fd.delete('1');
+  fd.delete('2');
+  fd.delete('3');
+  fd.delete('4');
+  fd.delete('5');
+
+  last = key_iter.next();
+  ok(last.done, "Nothing more to read.");
+  is(last.value, undefined, "Undefined is the last key");
+}
+
 function testSend(doneCb) {
   var xhr = new XMLHttpRequest();
   xhr.open("POST", "form_submit_server.sjs");
   xhr.onload = function () {
     var response = xhr.response;
 
     for (var entry of response) {
       is(entry.body, 'hey');
@@ -156,12 +206,13 @@ function testSend(doneCb) {
 function runTest(doneCb) {
   testHas();
   testGet();
   testGetAll();
   testDelete();
   testSet();
   testIterate();
   testFilename();
+  testIterable();
   // Finally, send an XHR and verify the response matches.
   testSend(doneCb);
 }
 
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -2107,16 +2107,17 @@ SourceMediaStream::AddTrackInternal(Trac
                                     MediaSegment* aSegment, uint32_t aFlags)
 {
   MutexAutoLock lock(mMutex);
   nsTArray<TrackData> *track_data = (aFlags & ADDTRACK_QUEUED) ?
                                     &mPendingTracks : &mUpdateTracks;
   TrackData* data = track_data->AppendElement();
   data->mID = aID;
   data->mInputRate = aRate;
+  data->mResamplerChannelCount = 0;
   data->mStart = aStart;
   data->mEndOfFlushedData = aStart;
   data->mCommands = TRACK_CREATE;
   data->mData = aSegment;
   if (!(aFlags & ADDTRACK_QUEUED) && GraphImpl()) {
     GraphImpl()->EnsureNextIteration();
   }
 }
--- a/dom/media/webaudio/OscillatorNode.cpp
+++ b/dom/media/webaudio/OscillatorNode.cpp
@@ -32,16 +32,18 @@ public:
     , mDestination(aDestination->Stream())
     , mStart(-1)
     , mStop(STREAM_TIME_MAX)
     // Keep the default values in sync with OscillatorNode::OscillatorNode.
     , mFrequency(440.f)
     , mDetune(0.f)
     , mType(OscillatorType::Sine)
     , mPhase(0.)
+    , mFinalFrequency(0.)
+    , mPhaseIncrement(0.)
     , mRecomputeParameters(true)
     , mCustomLength(0)
   {
     MOZ_ASSERT(NS_IsMainThread());
     mBasicWaveFormCache = aDestination->Context()->GetBasicWaveFormCache();
   }
 
   void SetSourceStream(AudioNodeStream* aSource)
--- a/dom/presentation/PresentationDeviceManager.cpp
+++ b/dom/presentation/PresentationDeviceManager.cpp
@@ -16,17 +16,16 @@
 #include "PresentationSessionRequest.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_ISUPPORTS(PresentationDeviceManager,
                   nsIPresentationDeviceManager,
                   nsIPresentationDeviceListener,
-                  nsIPresentationDeviceEventListener,
                   nsIObserver,
                   nsISupportsWeakReference)
 
 PresentationDeviceManager::PresentationDeviceManager()
 {
 }
 
 PresentationDeviceManager::~PresentationDeviceManager()
@@ -175,17 +174,16 @@ PresentationDeviceManager::AddDevice(nsI
   NS_ENSURE_ARG(aDevice);
   MOZ_ASSERT(NS_IsMainThread());
 
   if (NS_WARN_IF(mDevices.Contains(aDevice))) {
     return NS_ERROR_FAILURE;
   }
 
   mDevices.AppendElement(aDevice);
-  aDevice->SetListener(this);
 
   NotifyDeviceChange(aDevice, MOZ_UTF16("add"));
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationDeviceManager::RemoveDevice(nsIPresentationDevice* aDevice)
@@ -193,17 +191,16 @@ PresentationDeviceManager::RemoveDevice(
   NS_ENSURE_ARG(aDevice);
   MOZ_ASSERT(NS_IsMainThread());
 
   int32_t index = mDevices.IndexOf(aDevice);
   if (NS_WARN_IF(index < 0)) {
     return NS_ERROR_FAILURE;
   }
 
-  mDevices[index]->SetListener(nullptr);
   mDevices.RemoveElementAt(index);
 
   NotifyDeviceChange(aDevice, MOZ_UTF16("remove"));
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -216,17 +213,16 @@ PresentationDeviceManager::UpdateDevice(
     return NS_ERROR_FAILURE;
   }
 
   NotifyDeviceChange(aDevice, MOZ_UTF16("update"));
 
   return NS_OK;
 }
 
-// nsIPresentationDeviceListener
 NS_IMETHODIMP
 PresentationDeviceManager::OnSessionRequest(nsIPresentationDevice* aDevice,
                                             const nsAString& aUrl,
                                             const nsAString& aPresentationId,
                                             nsIPresentationControlChannel* aControlChannel)
 {
   NS_ENSURE_ARG(aDevice);
   NS_ENSURE_ARG(aControlChannel);
--- a/dom/presentation/PresentationDeviceManager.h
+++ b/dom/presentation/PresentationDeviceManager.h
@@ -14,25 +14,23 @@
 #include "nsCOMArray.h"
 #include "nsWeakReference.h"
 
 namespace mozilla {
 namespace dom {
 
 class PresentationDeviceManager final : public nsIPresentationDeviceManager
                                       , public nsIPresentationDeviceListener
-                                      , public nsIPresentationDeviceEventListener
                                       , public nsIObserver
                                       , public nsSupportsWeakReference
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIPRESENTATIONDEVICEMANAGER
   NS_DECL_NSIPRESENTATIONDEVICELISTENER
-  NS_DECL_NSIPRESENTATIONDEVICEEVENTLISTENER
   NS_DECL_NSIOBSERVER
 
   PresentationDeviceManager();
 
 private:
   virtual ~PresentationDeviceManager();
 
   void Init();
--- a/dom/presentation/interfaces/nsIPresentationDevice.idl
+++ b/dom/presentation/interfaces/nsIPresentationDevice.idl
@@ -1,54 +1,32 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsIPresentationControlChannel;
-interface nsIPresentationDevice;
-
-/*
- * Event callbacks from remote presentation device.
- */
-[scriptable, uuid(81984458-b9d1-4731-a26a-ba62ab339aac)]
-interface nsIPresentationDeviceEventListener : nsISupports
-{
-  /*
-   * Callback while the remote device is requesting to start a presentation session.
-   * @param url The URL requested to open by remote device.
-   * @param presentationId The Id for representing this session.
-   * @param controlChannel The control channel for this session.
-   */
-  void onSessionRequest(in nsIPresentationDevice device,
-                        in DOMString url,
-                        in DOMString presentationId,
-                        in nsIPresentationControlChannel controlChannel);
-};
 
 /*
  * Remote device.
  */
-[scriptable, uuid(7fac99d4-9b19-4b8d-b5cd-5da8adbe58f1)]
+[scriptable, uuid(b1e0a7af-5936-4066-8f2e-f789fb9a7e8f)]
 interface nsIPresentationDevice : nsISupports
 {
   // The unique Id for the device. UUID is recommanded.
   readonly attribute AUTF8String id;
 
   // The human-readable name of this device.
   readonly attribute AUTF8String name;
 
   //TODO expose more info in order to fulfill UX spec
   // The category of this device, could be "wifi", "bluetooth", "hdmi", etc.
   readonly attribute AUTF8String type;
 
-  // The listener for handling remote session request.
-  attribute nsIPresentationDeviceEventListener listener;
-
   /*
    * Establish a control channel to this device.
    * @param url The URL requested to open by remote device.
    * @param presentationId The Id for representing this session.
    * @returns The control channel for this session.
    * @throws  NS_ERROR_FAILURE if the establishment fails
    */
   nsIPresentationControlChannel establishControlChannel(in DOMString url,
--- a/dom/presentation/interfaces/nsIPresentationDeviceProvider.idl
+++ b/dom/presentation/interfaces/nsIPresentationDeviceProvider.idl
@@ -1,29 +1,42 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsIPresentationDevice;
+interface nsIPresentationControlChannel;
 
 %{C++
 #define PRESENTATION_DEVICE_PROVIDER_CATEGORY "presentation-device-provider"
 %}
 
 /*
- * The callbacks for any device updates.
+ * The callbacks for any device updates and session request.
  */
-[scriptable, uuid(7f9f0514-d957-485a-90e8-57cc3acbf15b)]
+[scriptable, uuid(46fd372b-2e40-4179-9b36-0478d141e440)]
 interface nsIPresentationDeviceListener: nsISupports
 {
   void addDevice(in nsIPresentationDevice device);
   void removeDevice(in nsIPresentationDevice device);
   void updateDevice(in nsIPresentationDevice device);
+
+  /*
+   * Callback while the remote device is requesting to start a presentation session.
+   * @param device The remote device that sent session request.
+   * @param url The URL requested to open by remote device.
+   * @param presentationId The Id for representing this session.
+   * @param controlChannel The control channel for this session.
+   */
+  void onSessionRequest(in nsIPresentationDevice device,
+                        in DOMString url,
+                        in DOMString presentationId,
+                        in nsIPresentationControlChannel controlChannel);
 };
 
 /*
  * Device provider for any device protocol, can be registered as default
  * providers by adding its contractID to category "presentation-device-provider".
  */
 [scriptable, uuid(3db2578a-0f50-44ad-b01b-28427b71b7bf)]
 interface nsIPresentationDeviceProvider: nsISupports
--- a/dom/presentation/interfaces/nsITCPPresentationServer.idl
+++ b/dom/presentation/interfaces/nsITCPPresentationServer.idl
@@ -1,32 +1,60 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
-interface nsIPresentationDevice;
+interface nsIPresentationControlChannel;
+
+%{C++
+#define TCP_PRESENTATION_SERVER_CONTACT_ID \
+  "@mozilla.org/presentation-device/tcp-presentation-server;1"
+%}
 
-[scriptable, uuid(b0dc6b1f-5f6f-455d-a917-90d0ad37186b)]
+/*
+ * The device information required for establishing TCP control channel.
+ */
+[scriptable, uuid(7fce55c0-2470-4a41-a3b9-c35fbe55f206)]
+interface nsITCPDeviceInfo: nsISupports
+{
+  readonly attribute AUTF8String id;
+  readonly attribute AUTF8String host;
+  readonly attribute uint16_t port;
+};
+
+[scriptable, uuid(fbb890a9-9e95-47d1-a425-86fd95881d81)]
 interface nsITCPPresentationServerListener: nsISupports
 {
   /**
    * Callback while the server socket stops listening.
    * @param   aReason
    *          The reason of the socket close. NS_OK for manually |close|.
    *          <other-error> on failure.
    */
   void onClose(in nsresult aReason);
+
+  /**
+   * Callback while the remote host is requesting to start a presentation session.
+   * @param aDeviceInfo The device information related to the remote host.
+   * @param aUrl The URL requested to open by remote device.
+   * @param aPresentationId The Id for representing this session.
+   * @param aControlChannel The control channel for this session.
+   */
+  void onSessionRequest(in nsITCPDeviceInfo aDeviceInfo,
+                        in DOMString aUrl,
+                        in DOMString aPresentationId,
+                        in nsIPresentationControlChannel aControlChannel);
 };
 
 /**
  * TCP presentation server which can be used by discovery services.
  */
-[scriptable, uuid(fcadc9fe-f1e9-4f74-b9d3-9cd6b74afc9e)]
+[scriptable, uuid(494237ec-c567-41ab-afc9-82d26c4fe1dc)]
 interface nsITCPPresentationServer: nsISupports
 {
   /**
    * This method initializes a TCP presentation server.
    * @param   aId
    *          The unique Id for the device within the discovery scope. If aId
    *          is null, empty string or opt-out, the TCP presentation server
    *          should not work until the |id| is set appropriately.
@@ -34,80 +62,37 @@ interface nsITCPPresentationServer: nsIS
    *          The port of the server socket.  Pass 0 or opt-out to indicate no
    *          preference, and a port will be selected automatically.
    * @throws  NS_ERROR_FAILURE if the server socket has been inited or the
    *          server socket can not be inited.
    */
   void init([optional] in AUTF8String aId, [optional] in uint16_t aPort);
 
   /**
+   * Request session to designated remote TCP device.
+   * @param   aDeviceInfo
+   *          The remtoe device info for establish connection.
+   * @param   aUrl
+   *          The URL requested to open by remote device.
+   * @param   aPresentationId
+   *          The Id for representing this session.
+   * @returns The control channel for this session.
+   * @throws  NS_ERROR_FAILURE if the server socket has been inited or the
+   *          server socket can not be inited.
+   */
+  nsIPresentationControlChannel requestSession(in nsITCPDeviceInfo aDeviceInfo,
+                                               in DOMString aUrl,
+                                               in DOMString aPresentationId);
+
+  /**
    * Close server socket and call |listener.onClose(NS_OK)|
    */
   void close();
 
   /**
-   * Create TCPDevice for this server.
-   * @param   aId
-   *          The unique Id for the discovered device
-   * @param   aName
-   *          The human-readable name of the discovered device
-   * @param   aType
-   *          The category of the discovered device
-   * @param   aHost
-   *          The host of the provided control channel of the discovered device
-   * @param   aPort
-   *          The port of the provided control channel of the discovered device
-   * @returns The created device
-   * @throws  NS_ERROR_INVALID_ARG if a TCPDevice with |aId| have existed.
-   */
-  nsIPresentationDevice createTCPDevice(in AUTF8String aId,
-                                        in AUTF8String aName,
-                                        in AUTF8String aType,
-                                        in AUTF8String aHost,
-                                        in uint16_t aPort);
-
-  /**
-   * Update TCPDevice for this server.
-   * @param   aId
-   *          The unique Id for the discovered device
-   * @param   aName
-   *          The human-readable name of the discovered device
-   * @param   aType
-   *          The category of the discovered device
-   * @param   aHost
-   *          The host of the provided control channel of the discovered device
-   * @param   aPort
-   *          The port of the provided control channel of the discovered device
-   * @returns The updated device
-   * @throws  NS_ERROR_INVALID_ARG if a TCPDevice with |aId| does not existed.
-   */
-  nsIPresentationDevice updateTCPDevice(in AUTF8String aId,
-                                        in AUTF8String aName,
-                                        in AUTF8String aType,
-                                        in AUTF8String aHost,
-                                        in uint16_t aPort);
-
-  /**
-   * Get TCPDevice with |aID|.
-   * @param   aId
-   *          The unique Id for the query device
-   * @returns The queried device; return |undefined|
-   * @throws  NS_ERROR_INVALID_ARG if a TCPDevice with |aId| does not exist.
-   */
-  nsIPresentationDevice getTCPDevice(in AUTF8String aId);
-
-  /**
-   * Remove TCPDevice with |aID|.
-   * @param   aId
-   *          The unique Id for the device which needs to be removed
-   * @throws  NS_ERROR_INVALID_ARG if a TCPDevice with |aId| does not exist.
-   */
-  void removeTCPDevice(in AUTF8String aId);
-
-  /**
    * Get the listen port of the TCP socket, valid after |init|. 0 indicates
    * the server socket is not inited or closed.
    */
   readonly attribute uint16_t port;
 
   /**
    * The id of the TCP presentation server. The setter should be use if the |id|
    * is not set by the |init|. Moreover, if the |id| is not set by |init|, the
--- a/dom/presentation/provider/MulticastDNSDeviceProvider.cpp
+++ b/dom/presentation/provider/MulticastDNSDeviceProvider.cpp
@@ -7,27 +7,23 @@
 #include "MainThreadUtils.h"
 #include "mozilla/Logging.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/unused.h"
 #include "nsAutoPtr.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIObserverService.h"
-#include "nsIPresentationDevice.h"
 #include "nsServiceManagerUtils.h"
 
 #define PREF_PRESENTATION_DISCOVERY "dom.presentation.discovery.enabled"
 #define PREF_PRESENTATION_DISCOVERY_TIMEOUT_MS "dom.presentation.discovery.timeout_ms"
 #define PREF_PRESENTATION_DISCOVERABLE "dom.presentation.discoverable"
 #define PREF_PRESENTATION_DEVICE_NAME "dom.presentation.device.name"
 
-#define TCP_PRESENTATION_SERVER_CONTACT_ID \
-  "@mozilla.org/presentation-device/tcp-presentation-server;1"
-
 #define SERVICE_TYPE "_mozilla_papi._tcp."
 
 inline static PRLogModuleInfo*
 GetProviderLog()
 {
   static PRLogModuleInfo* log = PR_NewLogModule("MulticastDNSDeviceProvider");
   return log;
 }
@@ -43,16 +39,68 @@ namespace presentation {
 static const char* kObservedPrefs[] = {
   PREF_PRESENTATION_DISCOVERY,
   PREF_PRESENTATION_DISCOVERY_TIMEOUT_MS,
   PREF_PRESENTATION_DISCOVERABLE,
   PREF_PRESENTATION_DEVICE_NAME,
   nullptr
 };
 
+namespace {
+
+class TCPDeviceInfo final : public nsITCPDeviceInfo
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSITCPDEVICEINFO
+
+  explicit TCPDeviceInfo(const nsACString& aId,
+                         const nsACString& aHost,
+                         const uint16_t aPort)
+    : mId(aId)
+    , mHost(aHost)
+    , mPort(aPort)
+  {
+  }
+
+private:
+  virtual ~TCPDeviceInfo() {}
+
+  nsCString mId;
+  nsCString mHost;
+  uint16_t mPort;
+};
+
+NS_IMPL_ISUPPORTS(TCPDeviceInfo,
+                  nsITCPDeviceInfo)
+
+// nsITCPDeviceInfo
+NS_IMETHODIMP
+TCPDeviceInfo::GetId(nsACString& aId)
+{
+  aId = mId;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TCPDeviceInfo::GetHost(nsACString& aHost)
+{
+  aHost = mHost;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TCPDeviceInfo::GetPort(uint16_t* aPort)
+{
+  *aPort = mPort;
+  return NS_OK;
+}
+
+} //anonymous namespace
+
 /**
  * This wrapper is used to break circular-reference problem.
  */
 class DNSServiceWrappedListener final
   : public nsIDNSServiceDiscoveryListener
   , public nsIDNSRegistrationListener
   , public nsIDNSServiceResolveListener
   , public nsITCPPresentationServerListener
@@ -257,43 +305,54 @@ MulticastDNSDeviceProvider::StopDiscover
     mDiscoveryRequest->Cancel(aReason);
     mDiscoveryRequest = nullptr;
   }
 
   return NS_OK;
 }
 
 nsresult
+MulticastDNSDeviceProvider::RequestSession(Device* aDevice,
+                                           const nsAString& aUrl,
+                                           const nsAString& aPresentationId,
+                                           nsIPresentationControlChannel** aRetVal)
+{
+  MOZ_ASSERT(aDevice);
+  MOZ_ASSERT(mPresentationServer);
+
+  RefPtr<TCPDeviceInfo> deviceInfo = new TCPDeviceInfo(aDevice->Id(),
+                                                       aDevice->Host(),
+                                                       aDevice->Port());
+
+  return mPresentationServer->RequestSession(deviceInfo, aUrl, aPresentationId, aRetVal);
+}
+
+nsresult
 MulticastDNSDeviceProvider::AddDevice(const nsACString& aServiceName,
                                       const nsACString& aServiceType,
                                       const nsACString& aHost,
                                       const uint16_t aPort)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mPresentationServer);
 
-  nsresult rv;
-
-  nsCOMPtr<nsIPresentationDevice> device;
-  if (NS_WARN_IF(NS_FAILED(rv =
-      mPresentationServer->CreateTCPDevice(aHost, /* ID */
-                                           aServiceName,
-                                           aServiceType,
-                                           aHost,
-                                           aPort,
-                                           getter_AddRefs(device))))) {
-    return rv;
-  }
+  RefPtr<Device> device = new Device(aHost, /* ID */
+                                     aServiceName,
+                                     aServiceType,
+                                     aHost,
+                                     aPort,
+                                     DeviceState::eActive,
+                                     this);
 
   nsCOMPtr<nsIPresentationDeviceListener> listener;
   if (NS_SUCCEEDED(GetListener(getter_AddRefs(listener))) && listener) {
     unused << listener->AddDevice(device);
   }
 
-  mDevices.AppendElement(Device(aHost, DeviceState::eActive));
+  mDevices.AppendElement(device);
 
   return NS_OK;
 }
 
 nsresult
 MulticastDNSDeviceProvider::UpdateDevice(const uint32_t aIndex,
                                          const nsACString& aServiceName,
                                          const nsACString& aServiceType,
@@ -302,110 +361,116 @@ MulticastDNSDeviceProvider::UpdateDevice
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mPresentationServer);
 
   if (NS_WARN_IF(aIndex >= mDevices.Length())) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  nsresult rv;
-
-  nsCOMPtr<nsIPresentationDevice> device;
-  if (NS_WARN_IF(NS_FAILED(rv =
-      mPresentationServer->UpdateTCPDevice(aHost, /* ID */
-                                           aServiceName,
-                                           aServiceType,
-                                           aHost,
-                                           aPort,
-                                           getter_AddRefs(device))))) {
-    return rv;
-  }
+  RefPtr<Device> device = mDevices[aIndex];
+  device->Update(aServiceName, aServiceType, aHost, aPort);
+  device->ChangeState(DeviceState::eActive);
 
   nsCOMPtr<nsIPresentationDeviceListener> listener;
   if (NS_SUCCEEDED(GetListener(getter_AddRefs(listener))) && listener) {
     unused << listener->UpdateDevice(device);
   }
 
-  mDevices[aIndex].state = DeviceState::eActive;
-
   return NS_OK;
 }
 
 nsresult
 MulticastDNSDeviceProvider::RemoveDevice(const uint32_t aIndex)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mPresentationServer);
 
   if (NS_WARN_IF(aIndex >= mDevices.Length())) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  nsCString deviceId = mDevices[aIndex].id;
-  LOG_I("RemoveDevice: %s", deviceId.get());
+  RefPtr<Device> device = mDevices[aIndex];
 
-  nsCOMPtr<nsIPresentationDevice> device;
-  if (NS_FAILED(mPresentationServer->GetTCPDevice(deviceId,
-                                                  getter_AddRefs(device)))) {
-    LOG_I("ignore non-existing device: %s", deviceId.get());
-    return NS_OK;
-  }
-
-  nsresult rv;
-  if (NS_WARN_IF(NS_FAILED(rv = mPresentationServer->RemoveTCPDevice(deviceId)))) {
-    return rv;
-  }
+  LOG_I("RemoveDevice: %s", device->Id().get());
+  mDevices.RemoveElementAt(aIndex);
 
   nsCOMPtr<nsIPresentationDeviceListener> listener;
   if (NS_SUCCEEDED(GetListener(getter_AddRefs(listener))) && listener) {
     unused << listener->RemoveDevice(device);
   }
 
-  mDevices.RemoveElementAt(aIndex);
   return NS_OK;
 }
 
 bool
-MulticastDNSDeviceProvider::FindDevice(const nsACString& aId,
-                                       uint32_t& aIndex)
+MulticastDNSDeviceProvider::FindDeviceById(const nsACString& aId,
+                                           uint32_t& aIndex)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  size_t index = mDevices.IndexOf(Device(aId, DeviceState::eUnknown),
-                                  0,
-                                  DeviceIdComparator());
+  RefPtr<Device> device = new Device(aId,
+                                     /* aName = */ EmptyCString(),
+                                     /* aType = */ EmptyCString(),
+                                     /* aHost = */ EmptyCString(),
+                                     /* aPort = */ 0,
+                                     /* aState = */ DeviceState::eUnknown,
+                                     /* aProvider = */ nullptr);
+  size_t index = mDevices.IndexOf(device, 0, DeviceIdComparator());
+
+  if (index == mDevices.NoIndex) {
+    return false;
+  }
+
+  aIndex = index;
+  return true;
+}
+
+bool
+MulticastDNSDeviceProvider::FindDeviceByHost(const nsACString& aHost,
+                                             uint32_t& aIndex)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  RefPtr<Device> device = new Device(/* aId = */ EmptyCString(),
+                                     /* aName = */ EmptyCString(),
+                                     /* aType = */ EmptyCString(),
+                                     aHost,
+                                     /* aPort = */ 0,
+                                     /* aState = */ DeviceState::eUnknown,
+                                     /* aProvider = */ nullptr);
+  size_t index = mDevices.IndexOf(device, 0, DeviceHostComparator());
 
   if (index == mDevices.NoIndex) {
     return false;
   }
 
   aIndex = index;
   return true;
 }
 
 void
 MulticastDNSDeviceProvider::MarkAllDevicesUnknown()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   for (auto& device : mDevices) {
-    device.state = DeviceState::eUnknown;
+    device->ChangeState(DeviceState::eUnknown);
   }
 }
 
 void
 MulticastDNSDeviceProvider::ClearUnknownDevices()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   size_t i = mDevices.Length();
   while (i > 0) {
     --i;
-    if (mDevices[i].state == DeviceState::eUnknown) {
+    if (mDevices[i]->State() == DeviceState::eUnknown) {
       NS_WARN_IF(NS_FAILED(RemoveDevice(i)));
     }
   }
 }
 
 void
 MulticastDNSDeviceProvider::ClearDevices()
 {
@@ -584,17 +649,17 @@ MulticastDNSDeviceProvider::OnServiceLos
   LOG_I("OnServiceLost: %s", serviceName.get());
 
   nsAutoCString host;
   if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetHost(host)))) {
     return rv;
   }
 
   uint32_t index;
-  if (!FindDevice(host, index)) {
+  if (!FindDeviceById(host, index)) {
     // given device was not found
     return NS_OK;
   }
 
   if (NS_WARN_IF(NS_FAILED(rv = RemoveDevice(index)))) {
     return rv;
   }
 
@@ -716,17 +781,17 @@ MulticastDNSDeviceProvider::OnServiceRes
   }
 
   nsAutoCString serviceType;
   if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetServiceType(serviceType)))) {
     return rv;
   }
 
   uint32_t index;
-  if (FindDevice(host, index)) {
+  if (FindDeviceById(host, index)) {
     return UpdateDevice(index,
                         serviceName,
                         serviceType,
                         host,
                         port);
   } else {
     return AddDevice(serviceName,
                      serviceType,
@@ -753,22 +818,62 @@ MulticastDNSDeviceProvider::OnClose(nsre
 {
   LOG_I("OnClose: %x", aReason);
   MOZ_ASSERT(NS_IsMainThread());
 
   UnregisterService(aReason);
 
   nsresult rv;
 
-  if (mDiscoveryEnabled && NS_WARN_IF(NS_FAILED(rv = ForceDiscovery()))) {
+  if (mDiscoverable && NS_WARN_IF(NS_FAILED(rv = RegisterService()))) {
     return rv;
   }
 
-  if (mDiscoverable && NS_WARN_IF(NS_FAILED(rv = RegisterService()))) {
-    return rv;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+MulticastDNSDeviceProvider::OnSessionRequest(nsITCPDeviceInfo* aDeviceInfo,
+                                             const nsAString& aUrl,
+                                             const nsAString& aPresentationId,
+                                             nsIPresentationControlChannel* aControlChannel)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoCString host;
+  unused << aDeviceInfo->GetHost(host);
+
+  LOG_I("OnSessionRequest: %s", host.get());
+
+  RefPtr<Device> device;
+  uint32_t index;
+  if (FindDeviceByHost(host, index)) {
+    device = mDevices[index];
+  } else {
+    // create a one-time device object for non-discoverable controller
+    // this device will not be listed in available device list and cannot
+    // be used for requesting session.
+    nsAutoCString id;
+    unused << aDeviceInfo->GetId(id);
+    uint16_t port;
+    unused << aDeviceInfo->GetPort(&port);
+
+    device = new Device(id,
+                        /* aName = */ id,
+                        /* aType = */ EmptyCString(),
+                        host,
+                        port,
+                        DeviceState::eActive,
+                        /* aProvider = */ nullptr);
+  }
+
+  nsCOMPtr<nsIPresentationDeviceListener> listener;
+  if (NS_SUCCEEDED(GetListener(getter_AddRefs(listener))) && listener) {
+    unused << listener->OnSessionRequest(device, aUrl, aPresentationId,
+                                         aControlChannel);
   }
 
   return NS_OK;
 }
 
 // nsIObserver
 NS_IMETHODIMP
 MulticastDNSDeviceProvider::Observe(nsISupports* aSubject,
@@ -853,11 +958,52 @@ MulticastDNSDeviceProvider::OnServiceNam
 
   if (mDiscoverable) {
     return RegisterService();
   }
 
   return NS_OK;
 }
 
+// MulticastDNSDeviceProvider::Device
+NS_IMPL_ISUPPORTS(MulticastDNSDeviceProvider::Device,
+                  nsIPresentationDevice)
+
+// nsIPresentationDevice
+NS_IMETHODIMP
+MulticastDNSDeviceProvider::Device::GetId(nsACString& aId)
+{
+  aId = mId;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+MulticastDNSDeviceProvider::Device::GetName(nsACString& aName)
+{
+  aName = mName;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+MulticastDNSDeviceProvider::Device::GetType(nsACString& aType)
+{
+  aType = mType;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+MulticastDNSDeviceProvider::Device::EstablishControlChannel(const nsAString& aUrl,
+                                                            const nsAString& aPresentationId,
+                                                            nsIPresentationControlChannel** aRetVal)
+{
+  if (!mProvider) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return mProvider->RequestSession(this, aUrl, aPresentationId, aRetVal);
+}
+
 } // namespace presentation
 } // namespace dom
 } // namespace mozilla
--- a/dom/presentation/provider/MulticastDNSDeviceProvider.h
+++ b/dom/presentation/provider/MulticastDNSDeviceProvider.h
@@ -6,16 +6,17 @@
 #ifndef mozilla_dom_presentation_provider_MulticastDNSDeviceProvider_h
 #define mozilla_dom_presentation_provider_MulticastDNSDeviceProvider_h
 
 #include "mozilla/RefPtr.h"
 #include "nsCOMPtr.h"
 #include "nsICancelable.h"
 #include "nsIDNSServiceDiscovery.h"
 #include "nsIObserver.h"
+#include "nsIPresentationDevice.h"
 #include "nsIPresentationDeviceProvider.h"
 #include "nsITCPPresentationServer.h"
 #include "nsITimer.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsWeakPtr.h"
 
 namespace mozilla {
@@ -47,51 +48,125 @@ public:
   nsresult Uninit();
 
 private:
   enum class DeviceState : uint32_t {
     eUnknown,
     eActive
   };
 
-  struct Device final {
-    explicit Device(const nsACString& aId, DeviceState aState)
-      : id(aId), state(aState)
+  class Device final : public nsIPresentationDevice
+  {
+  public:
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIPRESENTATIONDEVICE
+
+    explicit Device(const nsACString& aId,
+                    const nsACString& aName,
+                    const nsACString& aType,
+                    const nsACString& aHost,
+                    const uint16_t aPort,
+                    DeviceState aState,
+                    MulticastDNSDeviceProvider* aProvider)
+      : mId(aId)
+      , mName(aName)
+      , mType(aType)
+      , mHost(aHost)
+      , mPort(aPort)
+      , mState(aState)
+      , mProvider(aProvider)
     {
     }
 
-    nsCString id;
-    DeviceState state;
+    const nsCString& Id() const
+    {
+      return mId;
+    }
+
+    const nsCString& Host() const
+    {
+      return mHost;
+    }
+
+    const uint16_t Port() const
+    {
+      return mPort;
+    }
+
+    const DeviceState State() const
+    {
+      return mState;
+    }
+
+    void ChangeState(DeviceState aState)
+    {
+      mState = aState;
+    }
+
+    void Update(const nsACString& aName,
+                const nsACString& aType,
+                const nsACString& aHost,
+                const uint16_t aPort)
+    {
+      mName = aName;
+      mType = aType;
+      mHost = aHost;
+      mPort = aPort;
+    }
+
+  private:
+    virtual ~Device() = default;
+
+    nsCString mId;
+    nsCString mName;
+    nsCString mType;
+    nsCString mHost;
+    uint16_t mPort;
+    DeviceState mState;
+    MulticastDNSDeviceProvider* mProvider;
   };
 
   struct DeviceIdComparator {
-    bool Equals(const Device& aA, const Device& aB) const {
-      return aA.id == aB.id;
+    bool Equals(const RefPtr<Device>& aA, const RefPtr<Device>& aB) const {
+      return aA->Id() == aB->Id();
+    }
+  };
+
+  struct DeviceHostComparator {
+    bool Equals(const RefPtr<Device>& aA, const RefPtr<Device>& aB) const {
+      return aA->Host() == aB->Host();
     }
   };
 
   virtual ~MulticastDNSDeviceProvider();
   nsresult RegisterService();
   nsresult UnregisterService(nsresult aReason);
   nsresult StopDiscovery(nsresult aReason);
+  nsresult RequestSession(Device* aDevice,
+                          const nsAString& aUrl,
+                          const nsAString& aPresentationId,
+                          nsIPresentationControlChannel** aRetVal);
 
   // device manipulation
   nsresult AddDevice(const nsACString& aServiceName,
                      const nsACString& aServiceType,
                      const nsACString& aHost,
                      const uint16_t aPort);
   nsresult UpdateDevice(const uint32_t aIndex,
                         const nsACString& aServiceName,
                         const nsACString& aServiceType,
                         const nsACString& aHost,
                         const uint16_t aPort);
   nsresult RemoveDevice(const uint32_t aIndex);
-  bool FindDevice(const nsACString& aId,
+  bool FindDeviceById(const nsACString& aId,
                       uint32_t& aIndex);
 
+  bool FindDeviceByHost(const nsACString& aHost,
+                        uint32_t& aIndex);
+
   void MarkAllDevicesUnknown();
   void ClearUnknownDevices();
   void ClearDevices();
 
   // preferences
   nsresult OnDiscoveryChanged(bool aEnabled);
   nsresult OnDiscoveryTimeoutChanged(uint32_t aTimeoutMs);
   nsresult OnDiscoverableChanged(bool aEnabled);
@@ -101,17 +176,17 @@ private:
   nsWeakPtr mDeviceListener;
   nsCOMPtr<nsITCPPresentationServer> mPresentationServer;
   nsCOMPtr<nsIDNSServiceDiscovery> mMulticastDNS;
   RefPtr<DNSServiceWrappedListener> mWrappedListener;
 
   nsCOMPtr<nsICancelable> mDiscoveryRequest;
   nsCOMPtr<nsICancelable> mRegisterRequest;
 
-  nsTArray<Device> mDevices;
+  nsTArray<RefPtr<Device>> mDevices;
 
   bool mDiscoveryEnabled = false;
   bool mIsDiscovering = false;
   uint32_t mDiscveryTimeoutMs;
   nsCOMPtr<nsITimer> mDiscoveryTimer;
 
   bool mDiscoverable = false;
 
--- a/dom/presentation/provider/TCPPresentationServer.js
+++ b/dom/presentation/provider/TCPPresentationServer.js
@@ -9,29 +9,26 @@ Cu.import("resource://gre/modules/XPCOMU
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/NetUtil.jsm");
 
 const DEBUG = Services.prefs.getBoolPref("dom.presentation.tcp_server.debug");
 function log(aMsg) {
   dump("-*- TCPPresentationServer.js: " + aMsg + "\n");
 }
 
-function TCPDeviceInfo(aHost, aPort, aId, aName, aType) {
+function TCPDeviceInfo(aHost, aPort, aId) {
   this.host = aHost;
   this.port = aPort;
   this.id = aId;
-  this.name = aName;
-  this.type = aType;
 }
 
 function TCPPresentationServer() {
   this._id = null;
   this._port = 0;
   this._serverSocket = null;
-  this._devices = new Map(); // id -> device
 }
 
 TCPPresentationServer.prototype = {
   /**
    * If a user agent connects to this server, we create a control channel but
    * hand it to |TCPDevice.listener| when the initial information exchange
    * finishes. Therefore, we hold the control channels in this period.
    */
@@ -108,130 +105,80 @@ TCPPresentationServer.prototype = {
   get listener() {
     return this._listener;
   },
 
   _isInit: function() {
     return this._id !== null && this._serverSocket !== null;
   },
 
-  createTCPDevice: function(aId, aName, aType, aHost, aPort) {
-    DEBUG && log("TCPPresentationServer - createTCPDevice with id: " + aId);
-    if (this._devices.has(aId)) {
-      throw Cr.NS_ERROR_INVALID_ARG;
-    }
-
-    this._devices.set(aId, new TCPDevice(this, {id: aId,
-                                                name: aName,
-                                                type: aType,
-                                                host: aHost,
-                                                port: aPort}));
-    return this._devices.get(aId);
-  },
-
-  updateTCPDevice: function(aId, aName, aType, aHost, aPort) {
-    DEBUG && log("TCPPresentationServer - updateTCPDevice with id: " + aId);
-    if (!this._devices.has(aId)) {
-      throw Cr.NS_ERROR_INVALID_ARG;
-    }
-
-    let device = this._devices.get(aId);
-    device.name = aName;
-    device.type = aType;
-    device.host = aHost;
-    device.port = aPort;
-
-    return device;
-  },
-
-  getTCPDevice: function(aId) {
-    DEBUG && log("TCPPresentationServer - getTCPDevice with id: " + aId);
-    if (!this._devices.has(aId)) {
-      throw Cr.NS_ERROR_INVALID_ARG;
-    }
-    return this._devices.get(aId);
-  },
-
-  removeTCPDevice: function(aId) {
-    DEBUG && log("TCPPresentationServer - removeTCPDevice with id: " + aId);
-    if (!this._devices.has(aId)) {
-      throw Cr.NS_ERROR_INVALID_ARG;
-    }
-    this._devices.delete(aId);
-  },
-
-  requestSession: function(aDevice, aUrl, aPresentationId) {
+  requestSession: function(aDeviceInfo, aUrl, aPresentationId) {
     if (!this._isInit()) {
       DEBUG && log("TCPPresentationServer - has not initialized; requestSession fails");
       return null;
     }
-    DEBUG && log("TCPPresentationServer - requestSession to " + aDevice.name
+    DEBUG && log("TCPPresentationServer - requestSession to " + aDeviceInfo.id
                  + ": " + aUrl + ", " + aPresentationId);
 
     let sts = Cc["@mozilla.org/network/socket-transport-service;1"]
                 .getService(Ci.nsISocketTransportService)
 
     let socketTransport;
     try {
       socketTransport = sts.createTransport(null,
                                             0,
-                                            aDevice.host,
-                                            aDevice.port,
+                                            aDeviceInfo.host,
+                                            aDeviceInfo.port,
                                             null);
     } catch (e) {
       DEBUG && log("TCPPresentationServer - createTransport throws: " + e);
       // Pop the exception to |TCPDevice.establishControlChannel|
       throw Cr.NS_ERROR_FAILURE;
     }
     return new TCPControlChannel(this,
                                  socketTransport,
-                                 aDevice,
+                                 aDeviceInfo,
                                  aPresentationId,
                                  "sender",
                                  aUrl);
   },
 
-  responseSession: function(aDevice, aSocketTransport) {
+  responseSession: function(aDeviceInfo, aSocketTransport) {
     if (!this._isInit()) {
       DEBUG && log("TCPPresentationServer - has not initialized; responseSession fails");
       return null;
     }
     DEBUG && log("TCPPresentationServer - responseSession to "
-                 + JSON.stringify(aDevice));
+                 + JSON.stringify(aDeviceInfo));
     return new TCPControlChannel(this,
                                  aSocketTransport,
-                                 aDevice,
+                                 aDeviceInfo,
                                  null, // presentation ID
                                  "receiver",
                                  null // url
                                  );
   },
 
   // Triggered by TCPControlChannel
-  onSessionRequest: function(aId, aUrl, aPresentationId, aControlChannel) {
-    let device = this._devices.get(aId);
-    if (!device) {
-      //XXX Bug 1136565 - should have a way to recovery
-      DEBUG && log("TCPPresentationServer - onSessionRequest not found device for id: "
-                   + aId );
-      return;
-    }
-    device.listener.onSessionRequest(device,
-                                     aUrl,
-                                     aPresentationId,
-                                     aControlChannel);
+  onSessionRequest: function(aDeviceInfo, aUrl, aPresentationId, aControlChannel) {
+    DEBUG && log("TCPPresentationServer - onSessionRequest: "
+                 + aDeviceInfo.host + ":" + aDeviceInfo.port);
+    this.listener.onSessionRequest(aDeviceInfo,
+                                   aUrl,
+                                   aPresentationId,
+                                   aControlChannel);
     this.releaseControlChannel(aControlChannel);
   },
 
   // nsIServerSocketListener (Triggered by nsIServerSocket.init)
   onSocketAccepted: function(aServerSocket, aClientSocket) {
     DEBUG && log("TCPPresentationServer - onSocketAccepted: "
                  + aClientSocket.host + ":" + aClientSocket.port);
-    let device = new TCPDeviceInfo(aClientSocket.host, aClientSocket.port);
-    this.holdControlChannel(this.responseSession(device, aClientSocket));
+    let deviceInfo = new TCPDeviceInfo(aClientSocket.host, aClientSocket.port);
+    this.holdControlChannel(this.responseSession(deviceInfo, aClientSocket));
   },
 
   holdControlChannel: function(aControlChannel) {
     this._controlChannels.push(aControlChannel);
   },
 
   releaseControlChannel: function(aControlChannel) {
     let index = this._controlChannels.indexOf(aControlChannel);
@@ -259,17 +206,16 @@ TCPPresentationServer.prototype = {
     DEBUG && log("TCPPresentationServer - close");
     if (this._serverSocket) {
       DEBUG && log("TCPPresentationServer - close server socket");
       this._serverSocket.close();
       this._serverSocket = null;
     }
     this._id = null;
     this._port = 0;
-    this._devices && this._devices.clear();
   },
 
   classID: Components.ID("{f4079b8b-ede5-4b90-a112-5b415a931deb}"),
   QueryInterface : XPCOMUtils.generateQI([Ci.nsIServerSocketListener,
                                           Ci.nsITCPPresentationServer]),
 };
 
 function ChannelDescription(aInit) {
@@ -337,23 +283,23 @@ function discriptionAsJson(aDescription)
       json.dataChannelSDP = aDescription.dataChannelSDP;
       break;
   }
   return json;
 }
 
 function TCPControlChannel(presentationServer,
                            transport,
-                           device,
+                           deviceInfo,
                            presentationId,
                            direction,
                            url) {
   DEBUG && log("create TCPControlChannel: " + presentationId + " with role: "
                + direction);
-  this._device = device;
+  this._deviceInfo = deviceInfo;
   this._presentationId = presentationId;
   this._direction = direction;
   this._transport = transport;
   this._url = url;
 
   this._presentationServer =  presentationServer;
 
   let currentThread = Services.tm.currentThread;
@@ -537,23 +483,23 @@ TCPControlChannel.prototype = {
                createInstance(Ci.nsIInputStreamPump);
     this._pump.init(this._input, -1, -1, 0, 0, false);
     this._pump.asyncRead(this, null);
   },
 
   // Handle command from remote side
   _handleMessage: function(aMsg) {
     DEBUG && log("TCPControlChannel - handleMessage from "
-                 + JSON.stringify(this._device) + ": " + JSON.stringify(aMsg));
+                 + JSON.stringify(this._deviceInfo) + ": " + JSON.stringify(aMsg));
     switch (aMsg.type) {
       case "requestSession:Init": {
-        this._device.id = aMsg.id;
+        this._deviceInfo.id = aMsg.id;
         this._url = aMsg.url;
         this._presentationId = aMsg.presentationId;
-        this._presentationServer.onSessionRequest(aMsg.id,
+        this._presentationServer.onSessionRequest(this._deviceInfo,
                                                   aMsg.url,
                                                   aMsg.presentationId,
                                                   this);
         this._notifyOpened();
         break;
       }
       case "requestSession:Offer": {
         this._onOffer(aMsg.offer);
@@ -683,48 +629,9 @@ TCPControlChannel.prototype = {
     }
   },
 
   classID: Components.ID("{fefb8286-0bdc-488b-98bf-0c11b485c955}"),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel,
                                          Ci.nsIStreamListener]),
 };
 
-function TCPDevice(aPresentationServer, aInfo) {
-  DEBUG && log("create TCPDevice");
-  this.id = aInfo.id;
-  this.name = aInfo.name;
-  this.type = aInfo.type
-  this.host = aInfo.host;
-  this.port = aInfo.port;
-
-  this._presentationServer = aPresentationServer;
-  this._listener = null;
-}
-
-TCPDevice.prototype = {
-  establishControlChannel: function(aUrl, aPresentationId) {
-    DEBUG && log("TCPDevice - establishControlChannel: " + aUrl + ", "
-                 + aPresentationId);
-    return this._presentationServer
-               .requestSession(this._getDeviceInfo(), aUrl, aPresentationId);
-  },
-  get listener() {
-    return this._listener;
-  },
-  set listener(aListener) {
-    DEBUG && log("TCPDevice - set listener");
-    this._listener = aListener;
-  },
-
-  _getDeviceInfo: function() {
-    return new TCPDeviceInfo(this.host,
-                             this.port,
-                             this.id,
-                             this.name,
-                             this.type);
-  },
-
-  classID: Components.ID("{d6492549-a4f2-4a0c-9a93-00f0e9918b0a}"),
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
-};
-
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TCPPresentationServer]);
--- a/dom/presentation/tests/mochitest/PresentationSessionChromeScript.js
+++ b/dom/presentation/tests/mochitest/PresentationSessionChromeScript.js
@@ -162,25 +162,16 @@ const mockedDevice = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
   id: 'id',
   name: 'name',
   type: 'type',
   establishControlChannel: function(url, presentationId) {
     sendAsyncMessage('control-channel-established');
     return mockedControlChannel;
   },
-  set listener(listener) {
-    this._listener = listener;
-  },
-  get listener() {
-    return this._listener;
-  },
-  simulateSessionRequest: function(url, presentationId, controlChannel) {
-    this._listener.onSessionRequest(this, url, presentationId, controlChannel);
-  },
 };
 
 const mockedDevicePrompt = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevicePrompt,
                                          Ci.nsIFactory]),
   createInstance: function(aOuter, aIID) {
     if (aOuter) {
       throw Components.results.NS_ERROR_NO_AGGREGATION;
@@ -353,17 +344,20 @@ addMessageListener('trigger-device-promp
   mockedDevicePrompt.simulateSelect();
 });
 
 addMessageListener('trigger-device-prompt-cancel', function() {
   mockedDevicePrompt.simulateCancel();
 });
 
 addMessageListener('trigger-incoming-session-request', function(url) {
-  mockedDevice.simulateSessionRequest(url, sessionId, mockedControlChannel);
+  var deviceManager = Cc['@mozilla.org/presentation-device/manager;1']
+                      .getService(Ci.nsIPresentationDeviceManager);
+  deviceManager.QueryInterface(Ci.nsIPresentationDeviceListener)
+	       .onSessionRequest(mockedDevice, url, sessionId, mockedControlChannel);
 });
 
 addMessageListener('trigger-incoming-offer', function() {
   mockedControlChannel.simulateOnOffer();
 });
 
 addMessageListener('trigger-incoming-answer', function() {
   mockedControlChannel.simulateOnAnswer();
--- a/dom/presentation/tests/xpcshell/test_multicast_dns_device_provider.js
+++ b/dom/presentation/tests/xpcshell/test_multicast_dns_device_provider.js
@@ -9,16 +9,17 @@ const { classes: Cc, interfaces: Ci, man
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 const INFO_CONTRACT_ID = "@mozilla.org/toolkit/components/mdnsresponder/dns-info;1";
 const PROVIDER_CONTRACT_ID = "@mozilla.org/presentation-device/multicastdns-provider;1";
 const SD_CONTRACT_ID = "@mozilla.org/toolkit/components/mdnsresponder/dns-sd;1";
 const UUID_CONTRACT_ID = "@mozilla.org/uuid-generator;1";
+const SERVER_CONTRACT_ID = "@mozilla.org/presentation-device/tcp-presentation-server;1";
 
 const PREF_DISCOVERY = "dom.presentation.discovery.enabled";
 const PREF_DISCOVERABLE = "dom.presentation.discoverable";
 
 var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
 
 function MockFactory(aClass) {
   this._cls = aClass;
@@ -164,16 +165,17 @@ function TestPresentationDeviceListener(
 }
 TestPresentationDeviceListener.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
                                          Ci.nsISupportsWeakReference]),
 
   addDevice: function(device) { this.devices[device.id] = device; },
   removeDevice: function(device) { delete this.devices[device.id]; },
   updateDevice: function(device) { this.devices[device.id] = device; },
+  onSessionRequest: function(device, url, presentationId, controlChannel) {},
 
   count: function() {
     var size = 0, key;
     for (key in this.devices) {
         if (this.devices.hasOwnProperty(key)) {
           ++size;
         }
     }
@@ -363,16 +365,241 @@ function addDevice() {
   Assert.equal(listener.count(), 1);
 
   provider.listener = null;
   Assert.equal(listener.count(), 1);
 
   run_next_test();
 }
 
+function handleSessionRequest() {
+  Services.prefs.setBoolPref(PREF_DISCOVERY, true);
+
+  const testUrl = "http://example.com";
+  const testPresentationId = "test-presentation-id";
+
+  let mockDevice = createDevice("device.local",
+                                12345,
+                                "service.name",
+                                "_mozilla_papi._tcp");
+  let mockSDObj = {
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
+    startDiscovery: function(serviceType, listener) {
+      listener.onDiscoveryStarted(serviceType);
+      listener.onServiceFound(createDevice("",
+                                           0,
+                                           mockDevice.serviceName,
+                                           mockDevice.serviceType));
+      return {
+        QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
+        cancel: function() {}
+      };
+    },
+    registerService: function(serviceInfo, listener) {},
+    resolveService: function(serviceInfo, listener) {
+      listener.onServiceResolved(createDevice(mockDevice.host,
+                                              mockDevice.port,
+                                              mockDevice.serviceName,
+                                              mockDevice.serviceType));
+    }
+  };
+
+  let mockServerObj = {
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPPresentationServer]),
+    requestSession: function(deviceInfo, url, presentationId) {
+      this.request = {
+        deviceInfo: deviceInfo,
+        url: url,
+        presentationId: presentationId,
+      };
+      return {
+        QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
+      };
+    },
+  };
+
+  let contractHookSD = new ContractHook(SD_CONTRACT_ID, mockSDObj);
+  let contractHookServer = new ContractHook(SERVER_CONTRACT_ID, mockServerObj);
+  let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
+  let listener = {
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
+                                           Ci.nsISupportsWeakReference]),
+    addDevice: function(device) {
+      this.device = device;
+    },
+  };
+
+  provider.listener = listener;
+
+  let controlChannel = listener.device.establishControlChannel(testUrl, testPresentationId);
+
+  Assert.equal(mockServerObj.request.deviceInfo.id, mockDevice.host);
+  Assert.equal(mockServerObj.request.deviceInfo.host, mockDevice.host);
+  Assert.equal(mockServerObj.request.deviceInfo.port, mockDevice.port);
+  Assert.equal(mockServerObj.request.url, testUrl);
+  Assert.equal(mockServerObj.request.presentationId, testPresentationId);
+
+  provider.listener = null;
+
+  run_next_test();
+}
+
+function handleOnSessionRequest() {
+  Services.prefs.setBoolPref(PREF_DISCOVERY, true);
+
+  let mockDevice = createDevice("device.local",
+                                12345,
+                                "service.name",
+                                "_mozilla_papi._tcp");
+  let mockSDObj = {
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
+    startDiscovery: function(serviceType, listener) {
+      listener.onDiscoveryStarted(serviceType);
+      listener.onServiceFound(createDevice("",
+                                           0,
+                                           mockDevice.serviceName,
+                                           mockDevice.serviceType));
+      return {
+        QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
+        cancel: function() {}
+      };
+    },
+    registerService: function(serviceInfo, listener) {},
+    resolveService: function(serviceInfo, listener) {
+      listener.onServiceResolved(createDevice(mockDevice.host,
+                                              mockDevice.port,
+                                              mockDevice.serviceName,
+                                              mockDevice.serviceType));
+    }
+  };
+
+  let mockServerObj = {
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPPresentationServer]),
+    init: function() {},
+    sessionRequest: function() {},
+    close: function() {},
+    id: '',
+    port: 0,
+    listener: null,
+  };
+
+  let contractHookSD = new ContractHook(SD_CONTRACT_ID, mockSDObj);
+  let contractHookServer = new ContractHook(SERVER_CONTRACT_ID, mockServerObj);
+  let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
+  let listener = {
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
+                                           Ci.nsISupportsWeakReference]),
+    addDevice: function(device) {},
+    removeDevice: function(device) {},
+    updateDevice: function(device) {},
+    onSessionRequest: function(device, url, presentationId, controlChannel) {
+      Assert.ok(true, "recieve onSessionRequest event");
+      this.request = {
+        deviceId: device.id,
+        url: url,
+        presentationId: presentationId,
+      };
+    }
+  };
+
+  provider.listener = listener;
+
+  const deviceInfo = {
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPDeviceInfo]),
+    id: mockDevice.host,
+    host: mockDevice.host,
+    port: 54321,
+  };
+
+  const testUrl = "http://example.com";
+  const testPresentationId = "test-presentation-id";
+  const testControlChannel = {
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
+  };
+  provider.QueryInterface(Ci.nsITCPPresentationServerListener)
+          .onSessionRequest(deviceInfo, testUrl, testPresentationId, testControlChannel);
+
+  Assert.equal(listener.request.deviceId, deviceInfo.id);
+  Assert.equal(listener.request.url, testUrl);
+  Assert.equal(listener.request.presentationId, testPresentationId);
+
+  provider.listener = null;
+
+  run_next_test();
+}
+
+function handleOnSessionRequestFromUnknownDevice() {
+  let mockSDObj = {
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
+    startDiscovery: function(serviceType, listener) {},
+    registerService: function(serviceInfo, listener) {},
+    resolveService: function(serviceInfo, listener) {}
+  };
+
+  let mockServerObj = {
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPPresentationServer]),
+    init: function() {},
+    sessionRequest: function() {},
+    close: function() {},
+    id: '',
+    port: 0,
+    listener: null,
+  };
+
+  let contractHookSD = new ContractHook(SD_CONTRACT_ID, mockSDObj);
+  let contractHookServer = new ContractHook(SERVER_CONTRACT_ID, mockServerObj);
+  let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
+  let listener = {
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
+                                           Ci.nsISupportsWeakReference]),
+    addDevice: function(device) {
+      Assert.ok(false, "shouldn't create any new device");
+    },
+    removeDevice: function(device) {
+      Assert.ok(false, "shouldn't remote any device");
+    },
+    updateDevice: function(device) {
+      Assert.ok(false, "shouldn't update any device");
+    },
+    onSessionRequest: function(device, url, presentationId, controlChannel) {
+      Assert.ok(true, "recieve onSessionRequest event");
+      this.request = {
+        deviceId: device.id,
+        url: url,
+        presentationId: presentationId,
+      };
+    }
+  };
+
+  provider.listener = listener;
+
+  const deviceInfo = {
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPDeviceInfo]),
+    id: "unknown-device.local",
+    host: "unknown-device.local",
+    port: 12345,
+  };
+
+  const testUrl = "http://example.com";
+  const testPresentationId = "test-presentation-id";
+  const testControlChannel = {
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
+  };
+  provider.QueryInterface(Ci.nsITCPPresentationServerListener)
+          .onSessionRequest(deviceInfo, testUrl, testPresentationId, testControlChannel);
+
+  Assert.equal(listener.request.deviceId, deviceInfo.id);
+  Assert.equal(listener.request.url, testUrl);
+  Assert.equal(listener.request.presentationId, testPresentationId);
+
+  provider.listener = null;
+
+  run_next_test();
+}
+
 function noAddDevice() {
   Services.prefs.setBoolPref(PREF_DISCOVERY, false);
 
   let mockDevice = createDevice("device.local", 12345, "service.name", "_mozilla_papi._tcp");
   let mockObj = {
     QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
     startDiscovery: function(serviceType, listener) {
       Assert.ok(false, "shouldn't perform any device discovery");
@@ -709,16 +936,19 @@ function run_test() {
     Services.prefs.clearUserPref(PREF_DISCOVERY);
     Services.prefs.clearUserPref(PREF_DISCOVERABLE);
   });
 
   add_test(registerService);
   add_test(noRegisterService);
   add_test(registerServiceDynamically);
   add_test(addDevice);
+  add_test(handleSessionRequest);
+  add_test(handleOnSessionRequest);
+  add_test(handleOnSessionRequestFromUnknownDevice);
   add_test(noAddDevice);
   add_test(addDeviceDynamically);
   add_test(updateDevice);
   add_test(diffDiscovery);
   add_test(serverClosed);
 
   run_next_test();
 }
--- a/dom/presentation/tests/xpcshell/test_presentation_device_manager.js
+++ b/dom/presentation/tests/xpcshell/test_presentation_device_manager.js
@@ -40,26 +40,16 @@ var testProvider = {
 var testDevice = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
   id: 'id',
   name: 'name',
   type: 'type',
   establishControlChannel: function(url, presentationId) {
     return null;
   },
-  set listener(listener) {
-    this._listener = listener;
-  },
-  get listener() {
-    return this._listener;
-  },
-
-  simulateSessionRequest: function(url, presentationId, controlChannel) {
-    this._listener.onSessionRequest(this, url, presentationId, controlChannel);
-  },
 };
 
 function addProvider() {
   Object.defineProperty(testProvider, 'listener', {
     configurable: true,
     set: function(listener) {
       Assert.strictEqual(listener, manager, 'listener setter is invoked by PresentationDeviceManager');
       delete testProvider.listener;
@@ -139,17 +129,18 @@ function sessionRequest() {
     let request = subject.QueryInterface(Ci.nsIPresentationSessionRequest);
 
     Assert.equal(request.device.id, testDevice.id, 'expected device');
     Assert.equal(request.url, testUrl, 'expected requesting URL');
     Assert.equal(request.presentationId, testPresentationId, 'expected presentation Id');
 
     run_next_test();
   }, 'presentation-session-request', false);
-  testDevice.simulateSessionRequest(testUrl, testPresentationId, testControlChannel);
+  manager.QueryInterface(Ci.nsIPresentationDeviceListener)
+         .onSessionRequest(testDevice, testUrl, testPresentationId, testControlChannel);
 }
 
 function removeDevice() {
   Services.obs.addObserver(function observer(subject, topic, data) {
     Services.obs.removeObserver(observer, topic);
 
     let updatedDevice = subject.QueryInterface(Ci.nsIPresentationDevice);
     Assert.equal(updatedDevice.id, testDevice.id, 'expected device id');
--- a/dom/presentation/tests/xpcshell/test_tcp_control_channel.js
+++ b/dom/presentation/tests/xpcshell/test_tcp_control_channel.js
@@ -60,32 +60,24 @@ function loopOfferAnser() {
 
   testPresentationServer();
 }
 
 
 function testPresentationServer() {
   let yayFuncs = makeJointSuccess(['controllerControlChannelClose',
                                    'presenterControlChannelClose']);
-  let controllerDevice, controllerControlChannel;
-  let presenterDevice, presenterControlChannel;
+  let controllerControlChannel;
 
+  tps.listener = {
 
-  controllerDevice = tps.createTCPDevice('controllerID',
-                                         'controllerName',
-                                         'testType',
-                                         '127.0.0.1',
-                                         CONTROLLER_CONTROL_CHANNEL_PORT)
-                        .QueryInterface(Ci.nsIPresentationDevice);
-
-  controllerDevice.listener = {
-
-    onSessionRequest: function(device, url, presentationId, controlChannel) {
+    onSessionRequest: function(deviceInfo, url, presentationId, controlChannel) {
       controllerControlChannel = controlChannel;
-      Assert.strictEqual(device, controllerDevice, 'expected device object');
+      Assert.equal(deviceInfo.id, tps.id, 'expected device id');
+      Assert.equal(deviceInfo.host, '127.0.0.1', 'expected device host');
       Assert.equal(url, 'http://example.com', 'expected url');
       Assert.equal(presentationId, 'testPresentationId', 'expected presentation id');
 
       controllerControlChannel.listener = {
         status: 'created',
         onOffer: function(aOffer) {
           Assert.equal(this.status, 'opened', '1. controllerControlChannel: get offer, send answer');
           this.status = 'onOffer';
@@ -111,38 +103,33 @@ function testPresentationServer() {
           this.status = 'opened';
         },
         notifyClosed: function(aReason) {
           Assert.equal(this.status, 'onOffer', '3. controllerControlChannel: closed');
           Assert.equal(aReason, Cr.NS_OK, 'presenterControlChannel notify closed NS_OK');
           this.status = 'closed';
           yayFuncs.controllerControlChannelClose();
         },
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceEventListener]),
+        QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
       };
     },
 
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPPresentationServerListener]),
   };
 
-  presenterDevice = tps.createTCPDevice('presentatorID',
-                                        'presentatorName',
-                                        'testType',
-                                        '127.0.0.1',
-                                        PRESENTER_CONTROL_CHANNEL_PORT)
-                       .QueryInterface(Ci.nsIPresentationDevice);
+  let presenterDeviceInfo = {
+    id: 'presentatorID',
+    host: '127.0.0.1',
+    port: PRESENTER_CONTROL_CHANNEL_PORT,
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPDeviceInfo]),
+  };
 
-  presenterDevice.listener = {
-    onSessionRequest: function(device, url, presentationId, controlChannel) {
-      Assert.ok(false, 'presenterDevice.listener.onSessionRequest should not be called');
-    },
-  }
-
-  presenterControlChannel =
-  presenterDevice.establishControlChannel('http://example.com', 'testPresentationId');
+  let presenterControlChannel = tps.requestSession(presenterDeviceInfo,
+                                                   'http://example.com',
+                                                   'testPresentationId');
 
   presenterControlChannel.listener = {
     status: 'created',
     onOffer: function(offer) {
       Assert.ok(false, 'get offer');
     },
     onAnswer: function(aAnswer) {
       Assert.equal(this.status, 'opened', '2. presenterControlChannel: get answer, close channel');
@@ -206,28 +193,22 @@ function shutdown()
     onClose: function(aReason) {
       Assert.equal(aReason, Cr.NS_OK, 'TCPPresentationServer close success');
       run_next_test();
     },
   }
   tps.close();
 }
 
-function setPref() {
-  Services.prefs.setBoolPref("dom.presentation.tcp_server.debug", true);
-  run_next_test();
-}
-
-function clearPref() {
-  Services.prefs.clearUserPref("dom.presentation.tcp_server.debug");
-  run_next_test();
-}
-
-add_test(setPref);
 add_test(loopOfferAnser);
 add_test(setOffline);
 add_test(oneMoreLoop);
 add_test(shutdown);
-add_test(clearPref);
 
 function run_test() {
+  Services.prefs.setBoolPref("dom.presentation.tcp_server.debug", true);
+
+  do_register_cleanup(() => {
+    Services.prefs.clearUserPref("dom.presentation.tcp_server.debug");
+  });
+
   run_next_test();
 }
--- a/dom/requestsync/RequestSyncService.jsm
+++ b/dom/requestsync/RequestSyncService.jsm
@@ -96,17 +96,19 @@ this.RequestSyncService = {
     // Loading all the data from the database into the _registrations map.
     // Any incoming message will be stored and processed when the async
     // operation is completed.
 
     this.dbTxn("readonly", function(aStore) {
       aStore.openCursor().onsuccess = event => {
         let cursor = event.target.result;
         if (cursor) {
-          this.addRegistration(cursor.value, cursor.continue);
+          this.addRegistration(cursor.value, function() {
+            cursor.continue();
+          });
         }
       }
     }.bind(this),
     function() {
       debug("initialization done");
     },
     function() {
       dump("ERROR!! RequestSyncService - Failed to retrieve data from the database.\n");
--- a/dom/tests/mochitest/fetch/test_headers_common.js
+++ b/dom/tests/mochitest/fetch/test_headers_common.js
@@ -8,26 +8,37 @@ function shouldThrow(func, expected, msg
     func();
   } catch(e) {
     err = e;
   } finally {
     ok(err instanceof expected, msg);
   }
 }
 
+function recursiveArrayCompare(actual, expected) {
+  is(Array.isArray(actual), Array.isArray(expected), "Both should either be arrays, or not");
+  if (Array.isArray(actual) && Array.isArray(expected)) {
+    var diff = actual.length !== expected.length;
+
+    for (var i = 0, n = actual.length; !diff && i < n; ++i) {
+      diff = recursiveArrayCompare(actual[i], expected[i]);
+    }
+
+    return diff;
+  } else {
+    return actual !== expected;
+  }
+}
+
 function arrayEquals(actual, expected, msg) {
   if (actual === expected) {
     return;
   }
 
-  var diff = actual.length !== expected.length;
-
-  for (var i = 0, n = actual.length; !diff && i < n; ++i) {
-    diff = actual[i] !== expected[i];
-  }
+  var diff = recursiveArrayCompare(actual, expected);
 
   ok(!diff, msg);
   if (diff) {
     is(actual, expected, msg);
   }
 }
 
 function checkHas(headers, name, msg) {
@@ -164,13 +175,65 @@ function TestFilledHeaders() {
   shouldThrow(function() {
     filled = new Headers([
       ["zxy"],
       ["uts", "321"]
     ]);
   }, TypeError, "Fill with non-tuple sequence should throw TypeError.");
 }
 
+function iterate(iter) {
+  var result = [];
+  for (var val = iter.next(); !val.done;) {
+    result.push(val.value);
+    val = iter.next();
+  }
+  return result;
+}
+
+function iterateForOf(iter) {
+  var result = [];
+  for (var value of iter) {
+    result.push(value);
+  }
+  return result;
+}
+
+function byteInflate(str) {
+  var encoder = new TextEncoder("utf-8");
+  var encoded = encoder.encode(str);
+  var result = "";
+  for (var i = 0; i < encoded.length; ++i) {
+    result += String.fromCharCode(encoded[i]);
+  }
+  return result
+}
+
+function TestHeadersIterator() {
+  var ehsanInflated = byteInflate("احسان");
+  var headers = new Headers();
+  headers.set("foo0", "bar0");
+  headers.append("foo", "bar");
+  headers.append("foo", ehsanInflated);
+  headers.append("Foo2", "bar2");
+  headers.set("Foo2", "baz2");
+  headers.set("foo3", "bar3");
+  headers.delete("foo0");
+  headers.delete("foo3");
+
+  var key_iter = headers.keys();
+  var value_iter = headers.values();
+  var entries_iter = headers.entries();
+
+  arrayEquals(iterate(key_iter), ["foo", "foo", "foo2"], "Correct key iterator");
+  arrayEquals(iterate(value_iter), ["bar", ehsanInflated, "baz2"], "Correct value iterator");
+  arrayEquals(iterate(entries_iter), [["foo", "bar"], ["foo", ehsanInflated], ["foo2", "baz2"]], "Correct entries iterator");
+
+  arrayEquals(iterateForOf(headers), [["foo", "bar"], ["foo", ehsanInflated], ["foo2", "baz2"]], "Correct entries iterator");
+  arrayEquals(iterateForOf(new Headers(headers)), [["foo", "bar"], ["foo", ehsanInflated], ["foo2", "baz2"]], "Correct entries iterator");
+}
+
 function runTest() {
   TestEmptyHeaders();
   TestFilledHeaders();
+  TestHeadersIterator();
   return Promise.resolve();
 }
--- a/dom/webidl/FormData.webidl
+++ b/dom/webidl/FormData.webidl
@@ -15,10 +15,10 @@ interface FormData {
   void append(USVString name, Blob value, optional USVString filename);
   void append(USVString name, USVString value);
   void delete(USVString name);
   FormDataEntryValue? get(USVString name);
   sequence<FormDataEntryValue> getAll(USVString name);
   boolean has(USVString name);
   void set(USVString name, Blob value, optional USVString filename);
   void set(USVString name, USVString value);
-  // iterable<USVString, FormDataEntryValue>; - Bug 1127703
+  iterable<USVString, FormDataEntryValue>;
 };
--- a/dom/webidl/Headers.webidl
+++ b/dom/webidl/Headers.webidl
@@ -22,13 +22,14 @@ enum HeadersGuardEnum {
  Exposed=(Window,Worker)]
 interface Headers {
   [Throws] void append(ByteString name, ByteString value);
   [Throws] void delete(ByteString name);
   [Throws] ByteString? get(ByteString name);
   [Throws] sequence<ByteString> getAll(ByteString name);
   [Throws] boolean has(ByteString name);
   [Throws] void set(ByteString name, ByteString value);
+  iterable<ByteString, ByteString>;
 
   // Used to test different guard states from mochitest.
   // Note: Must be set prior to populating headers or will throw.
   [ChromeOnly, SetterThrows] attribute HeadersGuardEnum guard;
 };
--- a/dom/webidl/HeapSnapshot.webidl
+++ b/dom/webidl/HeapSnapshot.webidl
@@ -5,16 +5,22 @@
  */
 
 /**
  * A HeapSnapshot represents a snapshot of the heap graph
  */
 [ChromeOnly, Exposed=(Window,System,Worker)]
 interface HeapSnapshot {
   /**
+   * A time stamp of when the heap snapshot was taken, if available. Units are
+   * microseconds since midnight (00:00:00) 1 January 1970 UTC.
+   */
+  readonly attribute unsigned long long? creationTime;
+
+  /**
    * Take a census of the heap snapshot.
    *
    * This is the same as |Debugger.Memory.prototype.takeCensus|, but operates on
    * the offline heap snapshot's serialized heap graph rather than the live heap
    * graph. The same optional configuration options that can be passed to that
    * function can be passed here.
    *
    * The returned value is determined by the `"breakdown"` option used, and is
--- a/dom/workers/ServiceWorkerPrivate.cpp
+++ b/dom/workers/ServiceWorkerPrivate.cpp
@@ -1032,16 +1032,22 @@ private:
     MOZ_ASSERT(internalReq);
     internalReq->SetCreatedByFetchEvent();
 
     internalReq->SetBody(mUploadStream);
     internalReq->SetReferrer(NS_ConvertUTF8toUTF16(mReferrer));
 
     request->SetContentPolicyType(mContentPolicyType);
 
+    request->GetInternalHeaders()->SetGuard(HeadersGuardEnum::Immutable, result);
+    if (NS_WARN_IF(result.Failed())) {
+      result.SuppressException();
+      return false;
+    }
+
     // TODO: remove conditional on http here once app protocol support is
     //       removed from service worker interception
     MOZ_ASSERT_IF(mIsHttpChannel && internalReq->IsNavigationRequest(),
                   request->Redirect() == RequestRedirect::Manual);
 
     RootedDictionary<FetchEventInit> init(aCx);
     init.mRequest.Construct();
     init.mRequest.Value() = request;
--- a/gfx/layers/CopyableCanvasLayer.cpp
+++ b/gfx/layers/CopyableCanvasLayer.cpp
@@ -56,16 +56,17 @@ CopyableCanvasLayer::Initialize(const Da
     mOriginPos = gl::OriginPos::BottomLeft;
 
     MOZ_ASSERT(mGLContext->IsOffscreen(), "canvas gl context isn't offscreen");
 
     if (aData.mFrontbufferGLTex) {
       gfx::IntSize size(aData.mSize.width, aData.mSize.height);
       mGLFrontbuffer = SharedSurface_Basic::Wrap(aData.mGLContext, size, aData.mHasAlpha,
                                                  aData.mFrontbufferGLTex);
+      mBufferProvider = aData.mBufferProvider;
     }
   } else if (aData.mBufferProvider) {
     mBufferProvider = aData.mBufferProvider;
   } else if (aData.mRenderer) {
     mAsyncRenderer = aData.mRenderer;
     mOriginPos = gl::OriginPos::BottomLeft;
   } else {
     MOZ_CRASH("CanvasLayer created without mSurface, mDrawTarget or mGLContext?");
@@ -80,32 +81,32 @@ CopyableCanvasLayer::IsDataValid(const D
   return mGLContext == aData.mGLContext;
 }
 
 void
 CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget)
 {
   if (mAsyncRenderer) {
     mSurface = mAsyncRenderer->GetSurface();
-  } else if (mBufferProvider) {
+  } else if (!mGLFrontbuffer && mBufferProvider) {
     mSurface = mBufferProvider->GetSnapshot();
   }
 
   if (!mGLContext && aDestTarget) {
     NS_ASSERTION(mSurface, "Must have surface to draw!");
     if (mSurface) {
       aDestTarget->CopySurface(mSurface,
                                IntRect(0, 0, mBounds.width, mBounds.height),
                                IntPoint(0, 0));
       mSurface = nullptr;
     }
     return;
   }
 
-  if (mBufferProvider || mAsyncRenderer) {
+  if ((!mGLFrontbuffer && mBufferProvider) || mAsyncRenderer) {
     return;
   }
 
   MOZ_ASSERT(mGLContext);
 
   SharedSurface* frontbuffer = nullptr;
   if (mGLFrontbuffer) {
     frontbuffer = mGLFrontbuffer.get();
--- a/gfx/layers/LayerScope.cpp
+++ b/gfx/layers/LayerScope.cpp
@@ -362,16 +362,48 @@ private:
     mozilla::UniquePtr<DrawSession> mSession;
     mozilla::UniquePtr<ContentMonitor> mContentMonitor;
     double mScale;
 };
 
 LayerScopeManager gLayerScopeManager;
 
 /*
+ * The static helper functions that set data into the packet
+ * 1. DumpRect
+ * 2. DumpFilter
+ */
+template<typename T>
+static void DumpRect(T* aPacketRect, const Rect& aRect)
+{
+    aPacketRect->set_x(aRect.x);
+    aPacketRect->set_y(aRect.y);
+    aPacketRect->set_w(aRect.width);
+    aPacketRect->set_h(aRect.height);
+}
+
+static void DumpFilter(TexturePacket* aTexturePacket, const Filter& aFilter)
+{
+    switch (aFilter) {
+        case Filter::GOOD:
+            aTexturePacket->set_mfilter(TexturePacket::GOOD);
+            break;
+        case Filter::LINEAR:
+            aTexturePacket->set_mfilter(TexturePacket::LINEAR);
+            break;
+        case Filter::POINT:
+            aTexturePacket->set_mfilter(TexturePacket::POINT);
+            break;
+        default:
+            MOZ_ASSERT(false, "Can't dump unexpected mFilter to texture packet!");
+            break;
+    }
+}
+
+/*
  * DebugGLData is the base class of
  * 1. DebugGLFrameStatusData (Frame start/end packet)
  * 2. DebugGLColorData (Color data packet)
  * 3. DebugGLTextureData (Texture data packet)
  * 4. DebugGLLayersData (Layers Tree data packet)
  * 5. DebugGLMetaData (Meta data packet)
  */
 class DebugGLData: public LinkedListElement<DebugGLData> {
@@ -431,36 +463,38 @@ protected:
 #ifdef MOZ_WIDGET_GONK
 // B2G optimization.
 class DebugGLGraphicBuffer final: public DebugGLData {
 public:
     DebugGLGraphicBuffer(void *layerRef,
                          GLenum target,
                          GLuint name,
                          const LayerRenderState &aState,
-                         bool aIsMask)
+                         bool aIsMask,
+                         UniquePtr<Packet> aPacket)
         : DebugGLData(Packet::TEXTURE),
           mLayerRef(reinterpret_cast<uint64_t>(layerRef)),
           mTarget(target),
           mName(name),
           mState(aState),
-          mIsMask(aIsMask)
+          mIsMask(aIsMask),
+          mPacket(Move(aPacket))
     {
     }
 
     virtual bool Write() override {
-        return WriteToStream(mPacket);
+        return WriteToStream(*mPacket);
     }
 
     bool TryPack(bool packData) {
         android::sp<android::GraphicBuffer> buffer = mState.mSurface;
         MOZ_ASSERT(buffer.get());
 
-        mPacket.set_type(mDataType);
-        TexturePacket* tp = mPacket.mutable_texture();
+        mPacket->set_type(mDataType);
+        TexturePacket* tp = mPacket->mutable_texture();
         tp->set_layerref(mLayerRef);
         tp->set_name(mName);
         tp->set_target(mTarget);
         tp->set_ismask(mIsMask);
 
         int pFormat = buffer->getPixelFormat();
         if (HAL_PIXEL_FORMAT_RGBA_8888 != pFormat &&
             HAL_PIXEL_FORMAT_RGBX_8888 != pFormat) {
@@ -512,52 +546,54 @@ public:
     }
 
 private:
     uint64_t mLayerRef;
     GLenum mTarget;
     GLuint mName;
     const LayerRenderState &mState;
     bool mIsMask;
-    Packet mPacket;
+    UniquePtr<Packet> mPacket;
 };
 #endif
 
 class DebugGLTextureData final: public DebugGLData {
 public:
     DebugGLTextureData(GLContext* cx,
                        void* layerRef,
                        GLenum target,
                        GLuint name,
                        DataSourceSurface* img,
-                       bool aIsMask)
+                       bool aIsMask,
+                       UniquePtr<Packet> aPacket)
         : DebugGLData(Packet::TEXTURE),
           mLayerRef(reinterpret_cast<uint64_t>(layerRef)),
           mTarget(target),
           mName(name),
           mContextAddress(reinterpret_cast<intptr_t>(cx)),
           mDatasize(0),
-          mIsMask(aIsMask)
+          mIsMask(aIsMask),
+          mPacket(Move(aPacket))
     {
         // pre-packing
         // DataSourceSurface may have locked buffer,
         // so we should compress now, and then it could
         // be unlocked outside.
         pack(img);
     }
 
     virtual bool Write() override {
-        return WriteToStream(mPacket);
+        return WriteToStream(*mPacket);
     }
 
 private:
     void pack(DataSourceSurface* aImage) {
-        mPacket.set_type(mDataType);
+        mPacket->set_type(mDataType);
 
-        TexturePacket* tp = mPacket.mutable_texture();
+        TexturePacket* tp = mPacket->mutable_texture();
         tp->set_layerref(mLayerRef);
         tp->set_name(mName);
         tp->set_target(mTarget);
         tp->set_dataformat(LOCAL_GL_RGBA);
         tp->set_glcontext(static_cast<uint64_t>(mContextAddress));
         tp->set_ismask(mIsMask);
 
         if (aImage) {
@@ -595,17 +631,17 @@ protected:
     uint64_t mLayerRef;
     GLenum mTarget;
     GLuint mName;
     intptr_t mContextAddress;
     uint32_t mDatasize;
     bool mIsMask;
 
     // Packet data
-    Packet mPacket;
+    UniquePtr<Packet> mPacket;
 };
 
 class DebugGLColorData final: public DebugGLData {
 public:
     DebugGLColorData(void* layerRef,
                      const Color& color,
                      int width,
                      int height)
@@ -716,28 +752,19 @@ public:
         for (int i = 0; i < 16; i++) {
           dp->add_mvmatrix(*element++);
         }
         dp->set_totalrects(mRects);
 
         MOZ_ASSERT(mRects > 0 && mRects < 4);
         for (size_t i = 0; i < mRects; i++) {
             // Vertex
-            layerscope::DrawPacket::Rect* pRect = dp->add_layerrect();
-            pRect->set_x(mLayerRects[i].x);
-            pRect->set_y(mLayerRects[i].y);
-            pRect->set_w(mLayerRects[i].width);
-            pRect->set_h(mLayerRects[i].height);
-
+            DumpRect(dp->add_layerrect(), mLayerRects[i]);
             // UV
-            pRect = dp->add_texturerect();
-            pRect->set_x(mTextureRects[i].x);
-            pRect->set_y(mTextureRects[i].y);
-            pRect->set_w(mTextureRects[i].width);
-            pRect->set_h(mTextureRects[i].height);
+            DumpRect(dp->add_texturerect(), mTextureRects[i]);
         }
 
         for (GLuint texId: mTexIDs) {
             dp->add_texids(texId);
         }
 
         return WriteToStream(packet);
     }
@@ -902,35 +929,39 @@ public:
     static void SetLayersTreeSendable(bool aSet) {sLayersTreeSendable = aSet;}
 
     static void SetLayersBufferSendable(bool aSet) {sLayersBufferSendable = aSet;}
 
     static bool GetLayersTreeSendable() {return sLayersTreeSendable;}
 
     static void ClearSentTextureIds();
 
-
 // Sender private functions
 private:
     static void SendColor(void* aLayerRef,
                           const Color& aColor,
                           int aWidth,
                           int aHeight);
     static void SendTextureSource(GLContext* aGLContext,
                                   void* aLayerRef,
                                   TextureSourceOGL* aSource,
                                   bool aFlipY,
-                                  bool aIsMask);
+                                  bool aIsMask,
+                                  UniquePtr<Packet> aPacket);
 #ifdef MOZ_WIDGET_GONK
     static bool SendGraphicBuffer(GLContext* aGLContext,
                                   void* aLayerRef,
                                   TextureSourceOGL* aSource,
                                   const TexturedEffect* aEffect,
                                   bool aIsMask);
 #endif
+    static void SetAndSendTexture(GLContext* aGLContext,
+                                  void* aLayerRef,
+                                  TextureSourceOGL* aSource,
+                                  const TexturedEffect* aEffect);
     static void SendTexturedEffect(GLContext* aGLContext,
                                    void* aLayerRef,
                                    const TexturedEffect* aEffect);
     static void SendMaskEffect(GLContext* aGLContext,
                                    void* aLayerRef,
                                    const EffectMask* aEffect);
     static void SendYCbCrEffect(GLContext* aGLContext,
                                 void* aLayerRef,
@@ -1039,17 +1070,18 @@ SenderHelper::GetTextureID(GLContext* aG
     return texID;
 }
 
 void
 SenderHelper::SendTextureSource(GLContext* aGLContext,
                                 void* aLayerRef,
                                 TextureSourceOGL* aSource,
                                 bool aFlipY,
-                                bool aIsMask)
+                                bool aIsMask,
+                                UniquePtr<Packet> aPacket)
 {
     MOZ_ASSERT(aGLContext);
     if (!aGLContext) {
         return;
     }
     GLuint texID = GetTextureID(aGLContext, aSource);
     if (HasTextureIdBeenSent(texID)) {
         return;
@@ -1065,17 +1097,17 @@ SenderHelper::SendTextureSource(GLContex
     // By sending 0 to ReadTextureImage rely upon aSource->BindTexture binding
     // texture correctly. texID is used for tracking in DebugGLTextureData.
     RefPtr<DataSourceSurface> img =
         aGLContext->ReadTexImageHelper()->ReadTexImage(0, textureTarget,
                                                          size,
                                                          shaderConfig, aFlipY);
     gLayerScopeManager.GetSocketManager()->AppendDebugData(
         new DebugGLTextureData(aGLContext, aLayerRef, textureTarget,
-                               texID, img, aIsMask));
+                               texID, img, aIsMask, Move(aPacket)));
 
     sSentTextureIds.push_back(texID);
     gLayerScopeManager.CurrentSession().mTexIDs.push_back(texID);
 
 }
 
 #ifdef MOZ_WIDGET_GONK
 bool
@@ -1087,19 +1119,26 @@ SenderHelper::SendGraphicBuffer(GLContex
     GLuint texID = GetTextureID(aGLContext, aSource);
     if (HasTextureIdBeenSent(texID)) {
         return false;
     }
     if (!aEffect->mState.mSurface.get()) {
         return false;
     }
 
+    // Expose packet creation here, so we could dump primary texture effect attributes.
+    auto packet = MakeUnique<layerscope::Packet>();
+    layerscope::TexturePacket* texturePacket = packet->mutable_texture();
+    texturePacket->set_mpremultiplied(aEffect->mPremultiplied);
+    DumpFilter(texturePacket, aEffect->mFilter);
+    DumpRect(texturePacket->mutable_mtexturecoords(), aEffect->mTextureCoords);
+
     GLenum target = aSource->GetTextureTarget();
     mozilla::UniquePtr<DebugGLGraphicBuffer> package =
-        MakeUnique<DebugGLGraphicBuffer>(aLayerRef, target, texID, aEffect->mState, aIsMask);
+        MakeUnique<DebugGLGraphicBuffer>(aLayerRef, target, texID, aEffect->mState, aIsMask, Move(packet));
 
     // The texure content in this TexureHost is not altered,
     // we don't need to send it again.
     bool changed = gLayerScopeManager.GetContentMonitor()->IsChangedOrNew(
         aEffect->mState.mTexture);
     if (!package->TryPack(changed)) {
         return false;
     }
@@ -1111,65 +1150,93 @@ SenderHelper::SendGraphicBuffer(GLContex
     gLayerScopeManager.CurrentSession().mTexIDs.push_back(texID);
 
     gLayerScopeManager.GetContentMonitor()->ClearChangedHost(aEffect->mState.mTexture);
     return true;
 }
 #endif
 
 void
+SenderHelper::SetAndSendTexture(GLContext* aGLContext,
+                                void* aLayerRef,
+                                TextureSourceOGL* aSource,
+                                const TexturedEffect* aEffect)
+{
+    // Expose packet creation here, so we could dump primary texture effect attributes.
+    auto packet = MakeUnique<layerscope::Packet>();
+    layerscope::TexturePacket* texturePacket = packet->mutable_texture();
+    texturePacket->set_mpremultiplied(aEffect->mPremultiplied);
+    DumpFilter(texturePacket, aEffect->mFilter);
+    DumpRect(texturePacket->mutable_mtexturecoords(), aEffect->mTextureCoords);
+    SendTextureSource(aGLContext, aLayerRef, aSource, false, false, Move(packet));
+}
+
+void
 SenderHelper::SendTexturedEffect(GLContext* aGLContext,
                                  void* aLayerRef,
                                  const TexturedEffect* aEffect)
 {
     TextureSourceOGL* source = aEffect->mTexture->AsSourceOGL();
     if (!source) {
         return;
     }
 
 #ifdef MOZ_WIDGET_GONK
     if (SendGraphicBuffer(aGLContext, aLayerRef, source, aEffect, false)) {
         return;
     }
 #endif
+
     // Fallback texture sending path.
-    // Render to texture and read pixels back.
-    SendTextureSource(aGLContext, aLayerRef, source, false, false);
+    SetAndSendTexture(aGLContext, aLayerRef, source, aEffect);
 }
 
 void
 SenderHelper::SendMaskEffect(GLContext* aGLContext,
                                  void* aLayerRef,
                                  const EffectMask* aEffect)
 {
     TextureSourceOGL* source = aEffect->mMaskTexture->AsSourceOGL();
     if (!source) {
         return;
     }
 
-    SendTextureSource(aGLContext, aLayerRef, source, false, true);
+    // Expose packet creation here, so we could dump secondary mask effect attributes.
+    auto packet = MakeUnique<layerscope::Packet>();
+    TexturePacket::EffectMask* mask = packet->mutable_texture()->mutable_mask();
+    mask->set_mis3d(aEffect->mIs3D);
+    mask->mutable_msize()->set_w(aEffect->mSize.width);
+    mask->mutable_msize()->set_h(aEffect->mSize.height);
+    auto element = reinterpret_cast<const Float *>(&(aEffect->mMaskTransform));
+    for (int i = 0; i < 16; i++) {
+        mask->mutable_mmasktransform()->add_m(*element++);
+    }
+
+    SendTextureSource(aGLContext, aLayerRef, source, false, true, Move(packet));
 }
 
 void
 SenderHelper::SendYCbCrEffect(GLContext* aGLContext,
                               void* aLayerRef,
                               const EffectYCbCr* aEffect)
 {
     TextureSource* sourceYCbCr = aEffect->mTexture;
     if (!sourceYCbCr)
         return;
 
     const int Y = 0, Cb = 1, Cr = 2;
-    TextureSourceOGL* sourceY =  sourceYCbCr->GetSubSource(Y)->AsSourceOGL();
-    TextureSourceOGL* sourceCb = sourceYCbCr->GetSubSource(Cb)->AsSourceOGL();
-    TextureSourceOGL* sourceCr = sourceYCbCr->GetSubSource(Cr)->AsSourceOGL();
+    TextureSourceOGL *sources[] = {
+        sourceYCbCr->GetSubSource(Y)->AsSourceOGL(),
+        sourceYCbCr->GetSubSource(Cb)->AsSourceOGL(),
+        sourceYCbCr->GetSubSource(Cr)->AsSourceOGL()
+    };
 
-    SendTextureSource(aGLContext, aLayerRef, sourceY, false, false);
-    SendTextureSource(aGLContext, aLayerRef, sourceCb, false, false);
-    SendTextureSource(aGLContext, aLayerRef, sourceCr, false, false);
+    for (auto source: sources) {
+        SetAndSendTexture(aGLContext, aLayerRef, source, aEffect);
+    }
 }
 
 void
 SenderHelper::SendEffectChain(GLContext* aGLContext,
                               const EffectChain& aEffectChain,
                               int aWidth,
                               int aHeight)
 {
--- a/gfx/layers/apz/src/TaskThrottler.cpp
+++ b/gfx/layers/apz/src/TaskThrottler.cpp
@@ -1,44 +1,39 @@
 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*- */
 /* vim: set sw=2 sts=2 ts=8 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 "TaskThrottler.h"
 
-#include "mozilla/layers/APZThreadUtils.h"  // for NewTimerCallback
-#include "nsComponentManagerUtils.h"        // for do_CreateInstance
-#include "nsITimer.h"
+#include "base/message_loop.h"
 
 #define TASK_LOG(...)
 // #define TASK_LOG(...) printf_stderr("TASK: " __VA_ARGS__)
 
 namespace mozilla {
 namespace layers {
 
 TaskThrottler::TaskThrottler(const TimeStamp& aTimeStamp, const TimeDuration& aMaxWait)
   : mMonitor("TaskThrottler")
   , mOutstanding(false)
   , mQueuedTask(nullptr)
   , mStartTime(aTimeStamp)
   , mMaxWait(aMaxWait)
   , mMean(1)
-  , mTimer(do_CreateInstance(NS_TIMER_CONTRACTID))
+  , mTimeoutTask(nullptr)
 {
-  // The TaskThrottler must be created on the main thread (or some nsITimer-
-  // compatible thread) for the nsITimer to work properly. In particular,
-  // creating it on the Compositor thread doesn't work.
-  MOZ_ASSERT(NS_IsMainThread());
 }
 
 TaskThrottler::~TaskThrottler()
 {
-  mTimer->Cancel();
+  // The timeout task holds a strong reference to the TaskThrottler, so if the
+  // TaskThrottler is being destroyed, there's no need to cancel the task.
 }
 
 void
 TaskThrottler::PostTask(const tracked_objects::Location& aLocation,
                         UniquePtr<CancelableTask> aTask, const TimeStamp& aTimeStamp)
 {
   MonitorAutoLock lock(mMonitor);
 
@@ -48,52 +43,56 @@ TaskThrottler::PostTask(const tracked_ob
   if (mOutstanding) {
     CancelPendingTask(lock);
     if (TimeSinceLastRequest(aTimeStamp, lock) < mMaxWait) {
       mQueuedTask = Move(aTask);
       TASK_LOG("%p queued task %p\n", this, mQueuedTask.get());
       // Make sure the queued task is sent after mMaxWait time elapses,
       // even if we don't get a TaskComplete() until then.
       TimeDuration timeout = mMaxWait - TimeSinceLastRequest(aTimeStamp, lock);
-      TimeStamp timeoutTime = mStartTime + mMaxWait;
-      RefPtr<TaskThrottler> refPtrThis = this;
-      mTimer->InitWithCallback(NewTimerCallback(
-          [refPtrThis, timeoutTime]()
-          {
-            MonitorAutoLock lock(refPtrThis->mMonitor);
-            if (refPtrThis->mQueuedTask) {
-              refPtrThis->RunQueuedTask(timeoutTime, lock);
-            }
-          }),
-          timeout.ToMilliseconds(), nsITimer::TYPE_ONE_SHOT);
+      mTimeoutTask = NewRunnableMethod(this, &TaskThrottler::OnTimeout);
+      MessageLoop::current()->PostDelayedTask(FROM_HERE, mTimeoutTask,
+          timeout.ToMilliseconds());
       return;
     }
     // we've been waiting for more than the max-wait limit, so just fall through
     // and send the new task already.
   }
 
   mStartTime = aTimeStamp;
   aTask->Run();
   mOutstanding = true;
 }
 
 void
+TaskThrottler::OnTimeout()
+{
+  MonitorAutoLock lock(mMonitor);
+  if (mQueuedTask) {
+    RunQueuedTask(TimeStamp::Now(), lock);
+  }
+  // The message loop will delete the posted timeout task. Make sure we don't
+  // keep a dangling pointer to it.
+  mTimeoutTask = nullptr;
+}
+
+void
 TaskThrottler::TaskComplete(const TimeStamp& aTimeStamp)
 {
   MonitorAutoLock lock(mMonitor);
 
   if (!mOutstanding) {
     return;
   }
 
   mMean.insert(aTimeStamp - mStartTime);
 
   if (mQueuedTask) {
     RunQueuedTask(aTimeStamp, lock);
-    mTimer->Cancel();
+    CancelTimeoutTask(lock);
   } else {
     mOutstanding = false;
   }
 }
 
 TimeDuration
 TaskThrottler::AverageDuration()
 {
@@ -121,17 +120,26 @@ TaskThrottler::CancelPendingTask()
 
 void
 TaskThrottler::CancelPendingTask(const MonitorAutoLock& aProofOfLock)
 {
   if (mQueuedTask) {
     TASK_LOG("%p cancelling task %p\n", this, mQueuedTask.get());
     mQueuedTask->Cancel();
     mQueuedTask = nullptr;
-    mTimer->Cancel();
+    CancelTimeoutTask(aProofOfLock);
+  }
+}
+
+void
+TaskThrottler::CancelTimeoutTask(const MonitorAutoLock& aProofOfLock)
+{
+  if (mTimeoutTask) {
+    mTimeoutTask->Cancel();
+    mTimeoutTask = nullptr;  // the MessageLoop will destroy it
   }
 }
 
 TimeDuration
 TaskThrottler::TimeSinceLastRequest(const TimeStamp& aTimeStamp)
 {
   MonitorAutoLock lock(mMonitor);
   return TimeSinceLastRequest(aTimeStamp, lock);
--- a/gfx/layers/apz/src/TaskThrottler.h
+++ b/gfx/layers/apz/src/TaskThrottler.h
@@ -13,18 +13,16 @@
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "mozilla/RollingMean.h"        // for RollingMean
 #include "mozilla/TimeStamp.h"          // for TimeDuration, TimeStamp
 #include "mozilla/UniquePtr.h"          // for UniquePtr
 #include "nsCOMPtr.h"                   // for nsCOMPtr
 #include "nsISupportsImpl.h"            // for NS_INLINE_DECL_THREADSAFE_REFCOUNTING
 #include "nsTArray.h"                   // for nsTArray
 
-class nsITimer;
-
 namespace tracked_objects {
 class Location;
 } // namespace tracked_objects
 
 namespace mozilla {
 namespace layers {
 
 /** The TaskThrottler prevents update event overruns. It is used in cases where
@@ -97,22 +95,25 @@ public:
 
 private:
   mutable Monitor mMonitor;
   bool mOutstanding;
   UniquePtr<CancelableTask> mQueuedTask;
   TimeStamp mStartTime;
   TimeDuration mMaxWait;
   RollingMean<TimeDuration, TimeDuration> mMean;
-  nsCOMPtr<nsITimer> mTimer;
+  CancelableTask* mTimeoutTask;  // not owned because it's posted to a MessageLoop
+                                 // which deletes it
 
   ~TaskThrottler();
   void RunQueuedTask(const TimeStamp& aTimeStamp,
                      const MonitorAutoLock& aProofOfLock);
   void CancelPendingTask(const MonitorAutoLock& aProofOfLock);
   TimeDuration TimeSinceLastRequest(const TimeStamp& aTimeStamp,
                                     const MonitorAutoLock& aProofOfLock);
+  void OnTimeout();
+  void CancelTimeoutTask(const MonitorAutoLock& aProofOfLock);
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // mozilla_dom_TaskThrottler_h
--- a/gfx/layers/apz/test/mochitest/mochitest.ini
+++ b/gfx/layers/apz/test/mochitest/mochitest.ini
@@ -24,8 +24,10 @@ skip-if = (os == 'android') || (os == 'b
 [test_layerization.html]
 skip-if = (os == 'android') || (os == 'b2g') # uses wheel events which are not supported on mobile
 [test_basic_pan.html]
 skip-if = toolkit != 'gonk'
 [test_scroll_inactive_flattened_frame.html]
 skip-if = (os == 'android') || (os == 'b2g') || (buildapp == 'mulet') # wheel events not supported on mobile; see bug 1164274 for mulet
 [test_scroll_inactive_bug1190112.html]
 skip-if = (os == 'android') || (os == 'b2g') || (buildapp == 'mulet') # wheel events not supported on mobile; see bug 1164274 for mulet
+[test_scroll_subframe_scrollbar.html]
+skip-if = (os == 'android') || (os == 'b2g') || (buildapp == 'mulet') # wheel events not supported on mobile; see bug 1164274 for mulet
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/test/mochitest/test_scroll_subframe_scrollbar.html
@@ -0,0 +1,119 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test scrolling subframe scrollbars</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/paint_listener.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+<style>
+p {
+  width:200px;
+  height:200px;
+  border:solid 1px black;
+}
+</style>
+</head>
+<body>
+<p id="subframe">
+1	<br>
+2	<br>
+3	<br>
+4	<br>
+5	<br>
+6	<br>
+7	<br>
+8	<br>
+9	<br>
+10	<br>
+11	<br>
+12	<br>
+13	<br>
+14	<br>
+15	<br>
+16	<br>
+17	<br>
+18	<br>
+19	<br>
+20	<br>
+21	<br>
+22	<br>
+23	<br>
+24	<br>
+25	<br>
+26	<br>
+27	<br>
+28	<br>
+29	<br>
+30	<br>
+31	<br>
+32	<br>
+33	<br>
+34	<br>
+35	<br>
+36	<br>
+37	<br>
+38	<br>
+39	<br>
+40	<br>
+</p>
+<script clss="testbody" type="text/javascript;version=1.7">
+
+var DefaultEvent = {
+  deltaMode: WheelEvent.DOM_DELTA_LINE,
+  deltaX: 0, deltaY: 1,
+  lineOrPageDeltaX: 0, lineOrPageDeltaY: 1,
+};
+
+var ScrollbarWidth = 0;
+
+function test() {
+  var subframe = document.getElementById('subframe');
+  var oldClientWidth = subframe.clientWidth;
+
+  subframe.style.overflow = 'auto';
+  subframe.getBoundingClientRect();
+
+  waitForAllPaintsFlushed(function () {
+    ScrollbarWidth = oldClientWidth - subframe.clientWidth;
+    if (!ScrollbarWidth) {
+      // Probably we have overlay scrollbars - abort the test.
+      ok(true, "overlay scrollbars - skipping test");
+      SimpleTest.finish();
+      return;
+    }
+
+    ok(subframe.scrollHeight > subframe.clientHeight, "subframe should have scrollable content");
+    testScrolling(subframe);
+  });
+}
+
+function testScrolling(subframe) {
+  // Send a wheel event roughly to where we think the trackbar is. We pick a
+  // point at the bottom, in the middle of the trackbar, where the slider is
+  // unlikely to be (since it starts at the top).
+  var posX = subframe.clientWidth + (ScrollbarWidth / 2);
+  var posY = subframe.clientHeight - 20;
+
+  var oldScrollTop = subframe.scrollTop;
+
+  sendWheelAndPaint(subframe, posX, posY, DefaultEvent, function () {
+    ok(subframe.scrollTop > oldScrollTop, "subframe should have scrolled");
+    SimpleTest.finish();
+  });
+}
+
+window.onload = function() {
+  SpecialPowers.pushPrefEnv({
+    'set': [['general.smoothScroll', false],
+            ['mousewheel.transaction.timeout', 0],
+            ['mousewheel.transaction.ignoremovedelay', 0]]
+  }, function () {
+    SimpleTest.waitForFocus(test);
+  });
+}
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</body>
+</html>
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -812,16 +812,20 @@ AsyncCompositionManager::ApplyAsyncConte
               metrics.GetScrollableRect(), displayPort, geckoZoom, mLayersUpdated,
               mPaintSyncId, fixedLayerMargins);
         }
         mIsFirstPaint = false;
         mLayersUpdated = false;
         mPaintSyncId = 0;
       }
     }
+#else
+    // Non-Android platforms still care about this flag being cleared after
+    // the first call to TransformShadowTree().
+    mIsFirstPaint = false;
 #endif
 
     // Transform the current local clip by this APZC's async transform. If we're
     // using containerful scrolling, then the clip is not part of the scrolled
     // frame and should not be transformed.
     if (asyncClip && !metrics.UsesContainerScrolling()) {
       MOZ_ASSERT(asyncTransform.Is2D());
       asyncClip = Some(TransformTo<ParentLayerPixel>(asyncTransform, *asyncClip));
--- a/gfx/layers/protobuf/LayerScopePacket.pb.cc
+++ b/gfx/layers/protobuf/LayerScopePacket.pb.cc
@@ -16,16 +16,20 @@
 namespace mozilla {
 namespace layers {
 namespace layerscope {
 
 void protobuf_ShutdownFile_LayerScopePacket_2eproto() {
   delete FramePacket::default_instance_;
   delete ColorPacket::default_instance_;
   delete TexturePacket::default_instance_;
+  delete TexturePacket_Rect::default_instance_;
+  delete TexturePacket_Size::default_instance_;
+  delete TexturePacket_Matrix::default_instance_;
+  delete TexturePacket_EffectMask::default_instance_;
   delete LayersPacket::default_instance_;
   delete LayersPacket_Layer::default_instance_;
   delete LayersPacket_Layer_Size::default_instance_;
   delete LayersPacket_Layer_Rect::default_instance_;
   delete LayersPacket_Layer_Region::default_instance_;
   delete LayersPacket_Layer_Matrix::default_instance_;
   delete LayersPacket_Layer_Shadow::default_instance_;
   delete MetaPacket::default_instance_;
@@ -45,31 +49,39 @@ void protobuf_AddDesc_LayerScopePacket_2
   if (already_here) return;
   already_here = true;
   GOOGLE_PROTOBUF_VERIFY_VERSION;
 
 #endif
   FramePacket::default_instance_ = new FramePacket();
   ColorPacket::default_instance_ = new ColorPacket();
   TexturePacket::default_instance_ = new TexturePacket();
+  TexturePacket_Rect::default_instance_ = new TexturePacket_Rect();
+  TexturePacket_Size::default_instance_ = new TexturePacket_Size();
+  TexturePacket_Matrix::default_instance_ = new TexturePacket_Matrix();
+  TexturePacket_EffectMask::default_instance_ = new TexturePacket_EffectMask();
   LayersPacket::default_instance_ = new LayersPacket();
   LayersPacket_Layer::default_instance_ = new LayersPacket_Layer();
   LayersPacket_Layer_Size::default_instance_ = new LayersPacket_Layer_Size();
   LayersPacket_Layer_Rect::default_instance_ = new LayersPacket_Layer_Rect();
   LayersPacket_Layer_Region::default_instance_ = new LayersPacket_Layer_Region();
   LayersPacket_Layer_Matrix::default_instance_ = new LayersPacket_Layer_Matrix();
   LayersPacket_Layer_Shadow::default_instance_ = new LayersPacket_Layer_Shadow();
   MetaPacket::default_instance_ = new MetaPacket();
   DrawPacket::default_instance_ = new DrawPacket();
   DrawPacket_Rect::default_instance_ = new DrawPacket_Rect();
   Packet::default_instance_ = new Packet();
   CommandPacket::default_instance_ = new CommandPacket();
   FramePacket::default_instance_->InitAsDefaultInstance();
   ColorPacket::default_instance_->InitAsDefaultInstance();
   TexturePacket::default_instance_->InitAsDefaultInstance();
+  TexturePacket_Rect::default_instance_->InitAsDefaultInstance();
+  TexturePacket_Size::default_instance_->InitAsDefaultInstance();
+  TexturePacket_Matrix::default_instance_->InitAsDefaultInstance();
+  TexturePacket_EffectMask::default_instance_->InitAsDefaultInstance();
   LayersPacket::default_instance_->InitAsDefaultInstance();
   LayersPacket_Layer::default_instance_->InitAsDefaultInstance();
   LayersPacket_Layer_Size::default_instance_->InitAsDefaultInstance();
   LayersPacket_Layer_Rect::default_instance_->InitAsDefaultInstance();
   LayersPacket_Layer_Region::default_instance_->InitAsDefaultInstance();
   LayersPacket_Layer_Matrix::default_instance_->InitAsDefaultInstance();
   LayersPacket_Layer_Shadow::default_instance_->InitAsDefaultInstance();
   MetaPacket::default_instance_->InitAsDefaultInstance();
@@ -633,36 +645,1150 @@ void ColorPacket::Swap(ColorPacket* othe
 
 ::std::string ColorPacket::GetTypeName() const {
   return "mozilla.layers.layerscope.ColorPacket";
 }
 
 
 // ===================================================================
 
+bool TexturePacket_Filter_IsValid(int value) {
+  switch(value) {
+    case 0:
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#ifndef _MSC_VER
+const TexturePacket_Filter TexturePacket::GOOD;
+const TexturePacket_Filter TexturePacket::LINEAR;
+const TexturePacket_Filter TexturePacket::POINT;
+const TexturePacket_Filter TexturePacket::Filter_MIN;
+const TexturePacket_Filter TexturePacket::Filter_MAX;
+const int TexturePacket::Filter_ARRAYSIZE;
+#endif  // _MSC_VER
+#ifndef _MSC_VER
+const int TexturePacket_Rect::kXFieldNumber;
+const int TexturePacket_Rect::kYFieldNumber;
+const int TexturePacket_Rect::kWFieldNumber;
+const int TexturePacket_Rect::kHFieldNumber;
+#endif  // !_MSC_VER
+
+TexturePacket_Rect::TexturePacket_Rect()
+  : ::google::protobuf::MessageLite() {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:mozilla.layers.layerscope.TexturePacket.Rect)
+}
+
+void TexturePacket_Rect::InitAsDefaultInstance() {
+}
+
+TexturePacket_Rect::TexturePacket_Rect(const TexturePacket_Rect& from)
+  : ::google::protobuf::MessageLite() {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:mozilla.layers.layerscope.TexturePacket.Rect)
+}
+
+void TexturePacket_Rect::SharedCtor() {
+  _cached_size_ = 0;
+  x_ = 0;
+  y_ = 0;
+  w_ = 0;
+  h_ = 0;
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+TexturePacket_Rect::~TexturePacket_Rect() {
+  // @@protoc_insertion_point(destructor:mozilla.layers.layerscope.TexturePacket.Rect)
+  SharedDtor();
+}
+
+void TexturePacket_Rect::SharedDtor() {
+  #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  if (this != &default_instance()) {
+  #else
+  if (this != default_instance_) {
+  #endif
+  }
+}
+
+void TexturePacket_Rect::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const TexturePacket_Rect& TexturePacket_Rect::default_instance() {
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  protobuf_AddDesc_LayerScopePacket_2eproto();
+#else
+  if (default_instance_ == NULL) protobuf_AddDesc_LayerScopePacket_2eproto();
+#endif
+  return *default_instance_;
+}
+
+TexturePacket_Rect* TexturePacket_Rect::default_instance_ = NULL;
+
+TexturePacket_Rect* TexturePacket_Rect::New() const {
+  return new TexturePacket_Rect;
+}
+
+void TexturePacket_Rect::Clear() {
+#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>(      \
+  &reinterpret_cast<TexturePacket_Rect*>(16)->f) - \
+   reinterpret_cast<char*>(16))
+
+#define ZR_(first, last) do {                              \
+    size_t f = OFFSET_OF_FIELD_(first);                    \
+    size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last);  \
+    ::memset(&first, 0, n);                                \
+  } while (0)
+
+  ZR_(x_, h_);
+
+#undef OFFSET_OF_FIELD_
+#undef ZR_
+
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+  mutable_unknown_fields()->clear();
+}
+
+bool TexturePacket_Rect::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  ::google::protobuf::io::StringOutputStream unknown_fields_string(
+      mutable_unknown_fields());
+  ::google::protobuf::io::CodedOutputStream unknown_fields_stream(
+      &unknown_fields_string);
+  // @@protoc_insertion_point(parse_start:mozilla.layers.layerscope.TexturePacket.Rect)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional float x = 1;
+      case 1: {
+        if (tag == 13) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &x_)));
+          set_has_x();
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(21)) goto parse_y;
+        break;
+      }
+
+      // optional float y = 2;
+      case 2: {
+        if (tag == 21) {
+         parse_y:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &y_)));
+          set_has_y();
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(29)) goto parse_w;
+        break;
+      }
+
+      // optional float w = 3;
+      case 3: {
+        if (tag == 29) {
+         parse_w:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &w_)));
+          set_has_w();
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(37)) goto parse_h;
+        break;
+      }
+
+      // optional float h = 4;
+      case 4: {
+        if (tag == 37) {
+         parse_h:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &h_)));
+          set_has_h();
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(
+            input, tag, &unknown_fields_stream));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:mozilla.layers.layerscope.TexturePacket.Rect)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:mozilla.layers.layerscope.TexturePacket.Rect)
+  return false;
+#undef DO_
+}
+
+void TexturePacket_Rect::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:mozilla.layers.layerscope.TexturePacket.Rect)
+  // optional float x = 1;
+  if (has_x()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(1, this->x(), output);
+  }
+
+  // optional float y = 2;
+  if (has_y()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(2, this->y(), output);
+  }
+
+  // optional float w = 3;
+  if (has_w()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(3, this->w(), output);
+  }
+
+  // optional float h = 4;
+  if (has_h()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(4, this->h(), output);
+  }
+
+  output->WriteRaw(unknown_fields().data(),
+                   unknown_fields().size());
+  // @@protoc_insertion_point(serialize_end:mozilla.layers.layerscope.TexturePacket.Rect)
+}
+
+int TexturePacket_Rect::ByteSize() const {
+  int total_size = 0;
+
+  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    // optional float x = 1;
+    if (has_x()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float y = 2;
+    if (has_y()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float w = 3;
+    if (has_w()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float h = 4;
+    if (has_h()) {
+      total_size += 1 + 4;
+    }
+
+  }
+  total_size += unknown_fields().size();
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void TexturePacket_Rect::CheckTypeAndMergeFrom(
+    const ::google::protobuf::MessageLite& from) {
+  MergeFrom(*::google::protobuf::down_cast<const TexturePacket_Rect*>(&from));
+}
+
+void TexturePacket_Rect::MergeFrom(const TexturePacket_Rect& from) {
+  GOOGLE_CHECK_NE(&from, this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_x()) {
+      set_x(from.x());
+    }
+    if (from.has_y()) {
+      set_y(from.y());
+    }
+    if (from.has_w()) {
+      set_w(from.w());
+    }
+    if (from.has_h()) {
+      set_h(from.h());
+    }
+  }
+  mutable_unknown_fields()->append(from.unknown_fields());
+}
+
+void TexturePacket_Rect::CopyFrom(const TexturePacket_Rect& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool TexturePacket_Rect::IsInitialized() const {
+
+  return true;
+}
+
+void TexturePacket_Rect::Swap(TexturePacket_Rect* other) {
+  if (other != this) {
+    std::swap(x_, other->x_);
+    std::swap(y_, other->y_);
+    std::swap(w_, other->w_);
+    std::swap(h_, other->h_);
+    std::swap(_has_bits_[0], other->_has_bits_[0]);
+    _unknown_fields_.swap(other->_unknown_fields_);
+    std::swap(_cached_size_, other->_cached_size_);
+  }
+}
+
+::std::string TexturePacket_Rect::GetTypeName() const {
+  return "mozilla.layers.layerscope.TexturePacket.Rect";
+}
+
+
+// -------------------------------------------------------------------
+
+#ifndef _MSC_VER
+const int TexturePacket_Size::kWFieldNumber;
+const int TexturePacket_Size::kHFieldNumber;
+#endif  // !_MSC_VER
+
+TexturePacket_Size::TexturePacket_Size()
+  : ::google::protobuf::MessageLite() {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:mozilla.layers.layerscope.TexturePacket.Size)
+}
+
+void TexturePacket_Size::InitAsDefaultInstance() {
+}
+
+TexturePacket_Size::TexturePacket_Size(const TexturePacket_Size& from)
+  : ::google::protobuf::MessageLite() {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:mozilla.layers.layerscope.TexturePacket.Size)
+}
+
+void TexturePacket_Size::SharedCtor() {
+  _cached_size_ = 0;
+  w_ = 0;
+  h_ = 0;
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+TexturePacket_Size::~TexturePacket_Size() {
+  // @@protoc_insertion_point(destructor:mozilla.layers.layerscope.TexturePacket.Size)
+  SharedDtor();
+}
+
+void TexturePacket_Size::SharedDtor() {
+  #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  if (this != &default_instance()) {
+  #else
+  if (this != default_instance_) {
+  #endif
+  }
+}
+
+void TexturePacket_Size::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const TexturePacket_Size& TexturePacket_Size::default_instance() {
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  protobuf_AddDesc_LayerScopePacket_2eproto();
+#else
+  if (default_instance_ == NULL) protobuf_AddDesc_LayerScopePacket_2eproto();
+#endif
+  return *default_instance_;
+}
+
+TexturePacket_Size* TexturePacket_Size::default_instance_ = NULL;
+
+TexturePacket_Size* TexturePacket_Size::New() const {
+  return new TexturePacket_Size;
+}
+
+void TexturePacket_Size::Clear() {
+#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>(      \
+  &reinterpret_cast<TexturePacket_Size*>(16)->f) - \
+   reinterpret_cast<char*>(16))
+
+#define ZR_(first, last) do {                              \
+    size_t f = OFFSET_OF_FIELD_(first);                    \
+    size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last);  \
+    ::memset(&first, 0, n);                                \
+  } while (0)
+
+  ZR_(w_, h_);
+
+#undef OFFSET_OF_FIELD_
+#undef ZR_
+
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+  mutable_unknown_fields()->clear();
+}
+
+bool TexturePacket_Size::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  ::google::protobuf::io::StringOutputStream unknown_fields_string(
+      mutable_unknown_fields());
+  ::google::protobuf::io::CodedOutputStream unknown_fields_stream(
+      &unknown_fields_string);
+  // @@protoc_insertion_point(parse_start:mozilla.layers.layerscope.TexturePacket.Size)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional int32 w = 1;
+      case 1: {
+        if (tag == 8) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &w_)));
+          set_has_w();
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_h;
+        break;
+      }
+
+      // optional int32 h = 2;
+      case 2: {
+        if (tag == 16) {
+         parse_h:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &h_)));
+          set_has_h();
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(
+            input, tag, &unknown_fields_stream));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:mozilla.layers.layerscope.TexturePacket.Size)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:mozilla.layers.layerscope.TexturePacket.Size)
+  return false;
+#undef DO_
+}
+
+void TexturePacket_Size::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:mozilla.layers.layerscope.TexturePacket.Size)
+  // optional int32 w = 1;
+  if (has_w()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->w(), output);
+  }
+
+  // optional int32 h = 2;
+  if (has_h()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->h(), output);
+  }
+
+  output->WriteRaw(unknown_fields().data(),
+                   unknown_fields().size());
+  // @@protoc_insertion_point(serialize_end:mozilla.layers.layerscope.TexturePacket.Size)
+}
+
+int TexturePacket_Size::ByteSize() const {
+  int total_size = 0;
+
+  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    // optional int32 w = 1;
+    if (has_w()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->w());
+    }
+
+    // optional int32 h = 2;
+    if (has_h()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->h());
+    }
+
+  }
+  total_size += unknown_fields().size();
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void TexturePacket_Size::CheckTypeAndMergeFrom(
+    const ::google::protobuf::MessageLite& from) {
+  MergeFrom(*::google::protobuf::down_cast<const TexturePacket_Size*>(&from));
+}
+
+void TexturePacket_Size::MergeFrom(const TexturePacket_Size& from) {
+  GOOGLE_CHECK_NE(&from, this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_w()) {
+      set_w(from.w());
+    }
+    if (from.has_h()) {
+      set_h(from.h());
+    }
+  }
+  mutable_unknown_fields()->append(from.unknown_fields());
+}
+
+void TexturePacket_Size::CopyFrom(const TexturePacket_Size& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool TexturePacket_Size::IsInitialized() const {
+
+  return true;
+}
+
+void TexturePacket_Size::Swap(TexturePacket_Size* other) {
+  if (other != this) {
+    std::swap(w_, other->w_);
+    std::swap(h_, other->h_);
+    std::swap(_has_bits_[0], other->_has_bits_[0]);
+    _unknown_fields_.swap(other->_unknown_fields_);
+    std::swap(_cached_size_, other->_cached_size_);
+  }
+}
+
+::std::string TexturePacket_Size::GetTypeName() const {
+  return "mozilla.layers.layerscope.TexturePacket.Size";
+}
+
+
+// -------------------------------------------------------------------
+
+#ifndef _MSC_VER
+const int TexturePacket_Matrix::kIs2DFieldNumber;
+const int TexturePacket_Matrix::kIsIdFieldNumber;
+const int TexturePacket_Matrix::kMFieldNumber;
+#endif  // !_MSC_VER
+
+TexturePacket_Matrix::TexturePacket_Matrix()
+  : ::google::protobuf::MessageLite() {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:mozilla.layers.layerscope.TexturePacket.Matrix)
+}
+
+void TexturePacket_Matrix::InitAsDefaultInstance() {
+}
+
+TexturePacket_Matrix::TexturePacket_Matrix(const TexturePacket_Matrix& from)
+  : ::google::protobuf::MessageLite() {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:mozilla.layers.layerscope.TexturePacket.Matrix)
+}
+
+void TexturePacket_Matrix::SharedCtor() {
+  _cached_size_ = 0;
+  is2d_ = false;
+  isid_ = false;
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+TexturePacket_Matrix::~TexturePacket_Matrix() {
+  // @@protoc_insertion_point(destructor:mozilla.layers.layerscope.TexturePacket.Matrix)
+  SharedDtor();
+}
+
+void TexturePacket_Matrix::SharedDtor() {
+  #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  if (this != &default_instance()) {
+  #else
+  if (this != default_instance_) {
+  #endif
+  }
+}
+
+void TexturePacket_Matrix::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const TexturePacket_Matrix& TexturePacket_Matrix::default_instance() {
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  protobuf_AddDesc_LayerScopePacket_2eproto();
+#else
+  if (default_instance_ == NULL) protobuf_AddDesc_LayerScopePacket_2eproto();
+#endif
+  return *default_instance_;
+}
+
+TexturePacket_Matrix* TexturePacket_Matrix::default_instance_ = NULL;
+
+TexturePacket_Matrix* TexturePacket_Matrix::New() const {
+  return new TexturePacket_Matrix;
+}
+
+void TexturePacket_Matrix::Clear() {
+#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>(      \
+  &reinterpret_cast<TexturePacket_Matrix*>(16)->f) - \
+   reinterpret_cast<char*>(16))
+
+#define ZR_(first, last) do {                              \
+    size_t f = OFFSET_OF_FIELD_(first);                    \
+    size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last);  \
+    ::memset(&first, 0, n);                                \
+  } while (0)
+
+  ZR_(is2d_, isid_);
+
+#undef OFFSET_OF_FIELD_
+#undef ZR_
+
+  m_.Clear();
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+  mutable_unknown_fields()->clear();
+}
+
+bool TexturePacket_Matrix::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  ::google::protobuf::io::StringOutputStream unknown_fields_string(
+      mutable_unknown_fields());
+  ::google::protobuf::io::CodedOutputStream unknown_fields_stream(
+      &unknown_fields_string);
+  // @@protoc_insertion_point(parse_start:mozilla.layers.layerscope.TexturePacket.Matrix)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional bool is2D = 1;
+      case 1: {
+        if (tag == 8) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &is2d_)));
+          set_has_is2d();
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_isId;
+        break;
+      }
+
+      // optional bool isId = 2;
+      case 2: {
+        if (tag == 16) {
+         parse_isId:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &isid_)));
+          set_has_isid();
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(29)) goto parse_m;
+        break;
+      }
+
+      // repeated float m = 3;
+      case 3: {
+        if (tag == 29) {
+         parse_m:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 1, 29, input, this->mutable_m())));
+        } else if (tag == 26) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, this->mutable_m())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(29)) goto parse_m;
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(
+            input, tag, &unknown_fields_stream));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:mozilla.layers.layerscope.TexturePacket.Matrix)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:mozilla.layers.layerscope.TexturePacket.Matrix)
+  return false;
+#undef DO_
+}
+
+void TexturePacket_Matrix::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:mozilla.layers.layerscope.TexturePacket.Matrix)
+  // optional bool is2D = 1;
+  if (has_is2d()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(1, this->is2d(), output);
+  }
+
+  // optional bool isId = 2;
+  if (has_isid()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(2, this->isid(), output);
+  }
+
+  // repeated float m = 3;
+  for (int i = 0; i < this->m_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(
+      3, this->m(i), output);
+  }
+
+  output->WriteRaw(unknown_fields().data(),
+                   unknown_fields().size());
+  // @@protoc_insertion_point(serialize_end:mozilla.layers.layerscope.TexturePacket.Matrix)
+}
+
+int TexturePacket_Matrix::ByteSize() const {
+  int total_size = 0;
+
+  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    // optional bool is2D = 1;
+    if (has_is2d()) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool isId = 2;
+    if (has_isid()) {
+      total_size += 1 + 1;
+    }
+
+  }
+  // repeated float m = 3;
+  {
+    int data_size = 0;
+    data_size = 4 * this->m_size();
+    total_size += 1 * this->m_size() + data_size;
+  }
+
+  total_size += unknown_fields().size();
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void TexturePacket_Matrix::CheckTypeAndMergeFrom(
+    const ::google::protobuf::MessageLite& from) {
+  MergeFrom(*::google::protobuf::down_cast<const TexturePacket_Matrix*>(&from));
+}
+
+void TexturePacket_Matrix::MergeFrom(const TexturePacket_Matrix& from) {
+  GOOGLE_CHECK_NE(&from, this);
+  m_.MergeFrom(from.m_);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_is2d()) {
+      set_is2d(from.is2d());
+    }
+    if (from.has_isid()) {
+      set_isid(from.isid());
+    }
+  }
+  mutable_unknown_fields()->append(from.unknown_fields());
+}
+
+void TexturePacket_Matrix::CopyFrom(const TexturePacket_Matrix& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool TexturePacket_Matrix::IsInitialized() const {
+
+  return true;
+}
+
+void TexturePacket_Matrix::Swap(TexturePacket_Matrix* other) {
+  if (other != this) {
+    std::swap(is2d_, other->is2d_);
+    std::swap(isid_, other->isid_);
+    m_.Swap(&other->m_);
+    std::swap(_has_bits_[0], other->_has_bits_[0]);
+    _unknown_fields_.swap(other->_unknown_fields_);
+    std::swap(_cached_size_, other->_cached_size_);
+  }
+}
+
+::std::string TexturePacket_Matrix::GetTypeName() const {
+  return "mozilla.layers.layerscope.TexturePacket.Matrix";
+}
+
+
+// -------------------------------------------------------------------
+
+#ifndef _MSC_VER
+const int TexturePacket_EffectMask::kMIs3DFieldNumber;
+const int TexturePacket_EffectMask::kMSizeFieldNumber;
+const int TexturePacket_EffectMask::kMMaskTransformFieldNumber;
+#endif  // !_MSC_VER
+
+TexturePacket_EffectMask::TexturePacket_EffectMask()
+  : ::google::protobuf::MessageLite() {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:mozilla.layers.layerscope.TexturePacket.EffectMask)
+}
+
+void TexturePacket_EffectMask::InitAsDefaultInstance() {
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  msize_ = const_cast< ::mozilla::layers::layerscope::TexturePacket_Size*>(
+      ::mozilla::layers::layerscope::TexturePacket_Size::internal_default_instance());
+#else
+  msize_ = const_cast< ::mozilla::layers::layerscope::TexturePacket_Size*>(&::mozilla::layers::layerscope::TexturePacket_Size::default_instance());
+#endif
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  mmasktransform_ = const_cast< ::mozilla::layers::layerscope::TexturePacket_Matrix*>(
+      ::mozilla::layers::layerscope::TexturePacket_Matrix::internal_default_instance());
+#else
+  mmasktransform_ = const_cast< ::mozilla::layers::layerscope::TexturePacket_Matrix*>(&::mozilla::layers::layerscope::TexturePacket_Matrix::default_instance());
+#endif
+}
+
+TexturePacket_EffectMask::TexturePacket_EffectMask(const TexturePacket_EffectMask& from)
+  : ::google::protobuf::MessageLite() {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:mozilla.layers.layerscope.TexturePacket.EffectMask)
+}
+
+void TexturePacket_EffectMask::SharedCtor() {
+  _cached_size_ = 0;
+  mis3d_ = false;
+  msize_ = NULL;
+  mmasktransform_ = NULL;
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+TexturePacket_EffectMask::~TexturePacket_EffectMask() {
+  // @@protoc_insertion_point(destructor:mozilla.layers.layerscope.TexturePacket.EffectMask)
+  SharedDtor();
+}
+
+void TexturePacket_EffectMask::SharedDtor() {
+  #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  if (this != &default_instance()) {
+  #else
+  if (this != default_instance_) {
+  #endif
+    delete msize_;
+    delete mmasktransform_;
+  }
+}
+
+void TexturePacket_EffectMask::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const TexturePacket_EffectMask& TexturePacket_EffectMask::default_instance() {
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  protobuf_AddDesc_LayerScopePacket_2eproto();
+#else
+  if (default_instance_ == NULL) protobuf_AddDesc_LayerScopePacket_2eproto();
+#endif
+  return *default_instance_;
+}
+
+TexturePacket_EffectMask* TexturePacket_EffectMask::default_instance_ = NULL;
+
+TexturePacket_EffectMask* TexturePacket_EffectMask::New() const {
+  return new TexturePacket_EffectMask;
+}
+
+void TexturePacket_EffectMask::Clear() {
+  if (_has_bits_[0 / 32] & 7) {
+    mis3d_ = false;
+    if (has_msize()) {
+      if (msize_ != NULL) msize_->::mozilla::layers::layerscope::TexturePacket_Size::Clear();
+    }
+    if (has_mmasktransform()) {
+      if (mmasktransform_ != NULL) mmasktransform_->::mozilla::layers::layerscope::TexturePacket_Matrix::Clear();
+    }
+  }
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+  mutable_unknown_fields()->clear();
+}
+
+bool TexturePacket_EffectMask::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  ::google::protobuf::io::StringOutputStream unknown_fields_string(
+      mutable_unknown_fields());
+  ::google::protobuf::io::CodedOutputStream unknown_fields_stream(
+      &unknown_fields_string);
+  // @@protoc_insertion_point(parse_start:mozilla.layers.layerscope.TexturePacket.EffectMask)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional bool mIs3D = 1;
+      case 1: {
+        if (tag == 8) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &mis3d_)));
+          set_has_mis3d();
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_mSize;
+        break;
+      }
+
+      // optional .mozilla.layers.layerscope.TexturePacket.Size mSize = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_mSize:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_msize()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_mMaskTransform;
+        break;
+      }
+
+      // optional .mozilla.layers.layerscope.TexturePacket.Matrix mMaskTransform = 3;
+      case 3: {
+        if (tag == 26) {
+         parse_mMaskTransform:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_mmasktransform()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(
+            input, tag, &unknown_fields_stream));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:mozilla.layers.layerscope.TexturePacket.EffectMask)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:mozilla.layers.layerscope.TexturePacket.EffectMask)
+  return false;
+#undef DO_
+}
+
+void TexturePacket_EffectMask::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:mozilla.layers.layerscope.TexturePacket.EffectMask)
+  // optional bool mIs3D = 1;
+  if (has_mis3d()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(1, this->mis3d(), output);
+  }
+
+  // optional .mozilla.layers.layerscope.TexturePacket.Size mSize = 2;
+  if (has_msize()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessage(
+      2, this->msize(), output);
+  }
+
+  // optional .mozilla.layers.layerscope.TexturePacket.Matrix mMaskTransform = 3;
+  if (has_mmasktransform()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessage(
+      3, this->mmasktransform(), output);
+  }
+
+  output->WriteRaw(unknown_fields().data(),
+                   unknown_fields().size());
+  // @@protoc_insertion_point(serialize_end:mozilla.layers.layerscope.TexturePacket.EffectMask)
+}
+
+int TexturePacket_EffectMask::ByteSize() const {
+  int total_size = 0;
+
+  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    // optional bool mIs3D = 1;
+    if (has_mis3d()) {
+      total_size += 1 + 1;
+    }
+
+    // optional .mozilla.layers.layerscope.TexturePacket.Size mSize = 2;
+    if (has_msize()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->msize());
+    }
+
+    // optional .mozilla.layers.layerscope.TexturePacket.Matrix mMaskTransform = 3;
+    if (has_mmasktransform()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->mmasktransform());
+    }
+
+  }
+  total_size += unknown_fields().size();
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void TexturePacket_EffectMask::CheckTypeAndMergeFrom(
+    const ::google::protobuf::MessageLite& from) {
+  MergeFrom(*::google::protobuf::down_cast<const TexturePacket_EffectMask*>(&from));
+}
+
+void TexturePacket_EffectMask::MergeFrom(const TexturePacket_EffectMask& from) {
+  GOOGLE_CHECK_NE(&from, this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_mis3d()) {
+      set_mis3d(from.mis3d());
+    }
+    if (from.has_msize()) {
+      mutable_msize()->::mozilla::layers::layerscope::TexturePacket_Size::MergeFrom(from.msize());
+    }
+    if (from.has_mmasktransform()) {
+      mutable_mmasktransform()->::mozilla::layers::layerscope::TexturePacket_Matrix::MergeFrom(from.mmasktransform());
+    }
+  }
+  mutable_unknown_fields()->append(from.unknown_fields());
+}
+
+void TexturePacket_EffectMask::CopyFrom(const TexturePacket_EffectMask& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool TexturePacket_EffectMask::IsInitialized() const {
+
+  return true;
+}
+
+void TexturePacket_EffectMask::Swap(TexturePacket_EffectMask* other) {
+  if (other != this) {
+    std::swap(mis3d_, other->mis3d_);
+    std::swap(msize_, other->msize_);
+    std::swap(mmasktransform_, other->mmasktransform_);
+    std::swap(_has_bits_[0], other->_has_bits_[0]);
+    _unknown_fields_.swap(other->_unknown_fields_);
+    std::swap(_cached_size_, other->_cached_size_);
+  }
+}
+
+::std::string TexturePacket_EffectMask::GetTypeName() const {
+  return "mozilla.layers.layerscope.TexturePacket.EffectMask";
+}
+
+
+// -------------------------------------------------------------------
+
 #ifndef _MSC_VER
 const int TexturePacket::kLayerrefFieldNumber;
 const int TexturePacket::kWidthFieldNumber;
 const int TexturePacket::kHeightFieldNumber;
 const int TexturePacket::kStrideFieldNumber;
 const int TexturePacket::kNameFieldNumber;
 const int TexturePacket::kTargetFieldNumber;
 const int TexturePacket::kDataformatFieldNumber;
 const int TexturePacket::kGlcontextFieldNumber;
 const int TexturePacket::kDataFieldNumber;
+const int TexturePacket::kMTextureCoordsFieldNumber;
+const int TexturePacket::kMPremultipliedFieldNumber;
+const int TexturePacket::kMFilterFieldNumber;
 const int TexturePacket::kIsMaskFieldNumber;
+const int TexturePacket::kMaskFieldNumber;
 #endif  // !_MSC_VER
 
 TexturePacket::TexturePacket()
   : ::google::protobuf::MessageLite() {
   SharedCtor();
   // @@protoc_insertion_point(constructor:mozilla.layers.layerscope.TexturePacket)
 }
 
 void TexturePacket::InitAsDefaultInstance() {
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  mtexturecoords_ = const_cast< ::mozilla::layers::layerscope::TexturePacket_Rect*>(
+      ::mozilla::layers::layerscope::TexturePacket_Rect::internal_default_instance());
+#else
+  mtexturecoords_ = const_cast< ::mozilla::layers::layerscope::TexturePacket_Rect*>(&::mozilla::layers::layerscope::TexturePacket_Rect::default_instance());
+#endif
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  mask_ = const_cast< ::mozilla::layers::layerscope::TexturePacket_EffectMask*>(
+      ::mozilla::layers::layerscope::TexturePacket_EffectMask::internal_default_instance());
+#else
+  mask_ = const_cast< ::mozilla::layers::layerscope::TexturePacket_EffectMask*>(&::mozilla::layers::layerscope::TexturePacket_EffectMask::default_instance());
+#endif
 }
 
 TexturePacket::TexturePacket(const TexturePacket& from)
   : ::google::protobuf::MessageLite() {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:mozilla.layers.layerscope.TexturePacket)
 }
@@ -674,17 +1800,21 @@ void TexturePacket::SharedCtor() {
   width_ = 0u;
   height_ = 0u;
   stride_ = 0u;
   name_ = 0u;
   target_ = 0u;
   dataformat_ = 0u;
   glcontext_ = GOOGLE_ULONGLONG(0);
   data_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  mtexturecoords_ = NULL;
+  mpremultiplied_ = false;
+  mfilter_ = 0;
   ismask_ = false;
+  mask_ = NULL;
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
 
 TexturePacket::~TexturePacket() {
   // @@protoc_insertion_point(destructor:mozilla.layers.layerscope.TexturePacket)
   SharedDtor();
 }
 
@@ -692,16 +1822,18 @@ void TexturePacket::SharedDtor() {
   if (data_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
     delete data_;
   }
   #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
   if (this != &default_instance()) {
   #else
   if (this != default_instance_) {
   #endif
+    delete mtexturecoords_;
+    delete mask_;
   }
 }
 
 void TexturePacket::SetCachedSize(int size) const {
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = size;
   GOOGLE_SAFE_CONCURRENT_WRITES_END();
 }
@@ -729,23 +1861,29 @@ void TexturePacket::Clear() {
     size_t f = OFFSET_OF_FIELD_(first);                    \
     size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last);  \
     ::memset(&first, 0, n);                                \
   } while (0)
 
   if (_has_bits_[0 / 32] & 255) {
     ZR_(layerref_, glcontext_);
   }
-  if (_has_bits_[8 / 32] & 768) {
+  if (_has_bits_[8 / 32] & 16128) {
+    ZR_(mfilter_, ismask_);
     if (has_data()) {
       if (data_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
         data_->clear();
       }
     }
-    ismask_ = false;
+    if (has_mtexturecoords()) {
+      if (mtexturecoords_ != NULL) mtexturecoords_->::mozilla::layers::layerscope::TexturePacket_Rect::Clear();
+    }
+    if (has_mask()) {
+      if (mask_ != NULL) mask_->::mozilla::layers::layerscope::TexturePacket_EffectMask::Clear();
+    }
   }
 
 #undef OFFSET_OF_FIELD_
 #undef ZR_
 
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
   mutable_unknown_fields()->clear();
 }
@@ -887,31 +2025,93 @@ bool TexturePacket::MergePartialFromCode
       case 9: {
         if (tag == 74) {
          parse_data:
           DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
                 input, this->mutable_data()));
         } else {
           goto handle_unusual;
         }
+        if (input->ExpectTag(82)) goto parse_mTextureCoords;
+        break;
+      }
+
+      // optional .mozilla.layers.layerscope.TexturePacket.Rect mTextureCoords = 10;
+      case 10: {
+        if (tag == 82) {
+         parse_mTextureCoords:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_mtexturecoords()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(88)) goto parse_mPremultiplied;
+        break;
+      }
+
+      // optional bool mPremultiplied = 11;
+      case 11: {
+        if (tag == 88) {
+         parse_mPremultiplied:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &mpremultiplied_)));
+          set_has_mpremultiplied();
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(96)) goto parse_mFilter;
+        break;
+      }
+
+      // optional .mozilla.layers.layerscope.TexturePacket.Filter mFilter = 12;
+      case 12: {
+        if (tag == 96) {
+         parse_mFilter:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::mozilla::layers::layerscope::TexturePacket_Filter_IsValid(value)) {
+            set_mfilter(static_cast< ::mozilla::layers::layerscope::TexturePacket_Filter >(value));
+          } else {
+            unknown_fields_stream.WriteVarint32(tag);
+            unknown_fields_stream.WriteVarint32(value);
+          }
+        } else {
+          goto handle_unusual;
+        }
         if (input->ExpectTag(160)) goto parse_isMask;
         break;
       }
 
       // optional bool isMask = 20;
       case 20: {
         if (tag == 160) {
          parse_isMask:
           DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
                    bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
                  input, &ismask_)));
           set_has_ismask();
         } else {
           goto handle_unusual;
         }
+        if (input->ExpectTag(170)) goto parse_mask;
+        break;
+      }
+
+      // optional .mozilla.layers.layerscope.TexturePacket.EffectMask mask = 21;
+      case 21: {
+        if (tag == 170) {
+         parse_mask:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_mask()));
+        } else {
+          goto handle_unusual;
+        }
         if (input->ExpectAtEnd()) goto success;
         break;
       }
 
       default: {
       handle_unusual:
         if (tag == 0 ||
             ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -977,21 +2177,44 @@ void TexturePacket::SerializeWithCachedS
   }
 
   // optional bytes data = 9;
   if (has_data()) {
     ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased(
       9, this->data(), output);
   }
 
+  // optional .mozilla.layers.layerscope.TexturePacket.Rect mTextureCoords = 10;
+  if (has_mtexturecoords()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessage(
+      10, this->mtexturecoords(), output);
+  }
+
+  // optional bool mPremultiplied = 11;
+  if (has_mpremultiplied()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(11, this->mpremultiplied(), output);
+  }
+
+  // optional .mozilla.layers.layerscope.TexturePacket.Filter mFilter = 12;
+  if (has_mfilter()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      12, this->mfilter(), output);
+  }
+
   // optional bool isMask = 20;
   if (has_ismask()) {
     ::google::protobuf::internal::WireFormatLite::WriteBool(20, this->ismask(), output);
   }
 
+  // optional .mozilla.layers.layerscope.TexturePacket.EffectMask mask = 21;
+  if (has_mask()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessage(
+      21, this->mask(), output);
+  }
+
   output->WriteRaw(unknown_fields().data(),
                    unknown_fields().size());
   // @@protoc_insertion_point(serialize_end:mozilla.layers.layerscope.TexturePacket)
 }
 
 int TexturePacket::ByteSize() const {
   int total_size = 0;
 
@@ -1056,21 +2279,46 @@ int TexturePacket::ByteSize() const {
   if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) {
     // optional bytes data = 9;
     if (has_data()) {
       total_size += 1 +
         ::google::protobuf::internal::WireFormatLite::BytesSize(
           this->data());
     }
 
+    // optional .mozilla.layers.layerscope.TexturePacket.Rect mTextureCoords = 10;
+    if (has_mtexturecoords()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->mtexturecoords());
+    }
+
+    // optional bool mPremultiplied = 11;
+    if (has_mpremultiplied()) {
+      total_size += 1 + 1;
+    }
+
+    // optional .mozilla.layers.layerscope.TexturePacket.Filter mFilter = 12;
+    if (has_mfilter()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->mfilter());
+    }
+
     // optional bool isMask = 20;
     if (has_ismask()) {
       total_size += 2 + 1;
     }
 
+    // optional .mozilla.layers.layerscope.TexturePacket.EffectMask mask = 21;
+    if (has_mask()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->mask());
+    }
+
   }
   total_size += unknown_fields().size();
 
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = total_size;
   GOOGLE_SAFE_CONCURRENT_WRITES_END();
   return total_size;
 }
@@ -1107,19 +2355,31 @@ void TexturePacket::MergeFrom(const Text
     if (from.has_glcontext()) {
       set_glcontext(from.glcontext());
     }
   }
   if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) {
     if (from.has_data()) {
       set_data(from.data());
     }
+    if (from.has_mtexturecoords()) {
+      mutable_mtexturecoords()->::mozilla::layers::layerscope::TexturePacket_Rect::MergeFrom(from.mtexturecoords());
+    }
+    if (from.has_mpremultiplied()) {
+      set_mpremultiplied(from.mpremultiplied());
+    }
+    if (from.has_mfilter()) {
+      set_mfilter(from.mfilter());
+    }
     if (from.has_ismask()) {
       set_ismask(from.ismask());
     }
+    if (from.has_mask()) {
+      mutable_mask()->::mozilla::layers::layerscope::TexturePacket_EffectMask::MergeFrom(from.mask());
+    }
   }
   mutable_unknown_fields()->append(from.unknown_fields());
 }
 
 void TexturePacket::CopyFrom(const TexturePacket& from) {
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -1137,17 +2397,21 @@ void TexturePacket::Swap(TexturePacket* 
     std::swap(width_, other->width_);
     std::swap(height_, other->height_);
     std::swap(stride_, other->stride_);
     std::swap(name_, other->name_);
     std::swap(target_, other->target_);
     std::swap(dataformat_, other->dataformat_);
     std::swap(glcontext_, other->glcontext_);
     std::swap(data_, other->data_);
+    std::swap(mtexturecoords_, other->mtexturecoords_);
+    std::swap(mpremultiplied_, other->mpremultiplied_);
+    std::swap(mfilter_, other->mfilter_);
     std::swap(ismask_, other->ismask_);
+    std::swap(mask_, other->mask_);
     std::swap(_has_bits_[0], other->_has_bits_[0]);
     _unknown_fields_.swap(other->_unknown_fields_);
     std::swap(_cached_size_, other->_cached_size_);
   }
 }
 
 ::std::string TexturePacket::GetTypeName() const {
   return "mozilla.layers.layerscope.TexturePacket";
@@ -1208,27 +2472,37 @@ bool LayersPacket_Layer_Filter_IsValid(i
   switch(value) {
     case 0:
     case 1:
     case 2:
     case 3:
     case 4:
     case 5:
     case 6:
+    case 7:
+    case 8:
       return true;
     default:
       return false;
   }
 }
 
 #ifndef _MSC_VER
+const LayersPacket_Layer_Filter LayersPacket_Layer::FILTER_FAST;
 const LayersPacket_Layer_Filter LayersPacket_Layer::FILTER_GOOD;
+const LayersPacket_Layer_Filter LayersPacket_Layer::FILTER_BEST;
+const LayersPacket_Layer_Filter LayersPacket_Layer::FILTER_NEAREST;
+const LayersPacket_Layer_Filter LayersPacket_Layer::FILTER_BILINEAR;
+const LayersPacket_Layer_Filter LayersPacket_Layer::FILTER_GAUSSIAN;
+const LayersPacket_Layer_Filter LayersPacket_Layer::FILTER_SENTINEL;
 const LayersPacket_Layer_Filter LayersPacket_Layer::FILTER_LINEAR;
 const LayersPacket_Layer_Filter LayersPacket_Layer::FILTER_POINT;
-const LayersPacket_Layer_Filter LayersPacket_Layer::FILTER_SENTINEL;
+const LayersPacket_Layer_Filter LayersPacket_Layer::Filter_MIN;
+const LayersPacket_Layer_Filter LayersPacket_Layer::Filter_MAX;
+const int LayersPacket_Layer::Filter_ARRAYSIZE;
 #endif  // _MSC_VER
 #ifndef _MSC_VER
 const int LayersPacket_Layer_Size::kWFieldNumber;
 const int LayersPacket_Layer_Size::kHFieldNumber;
 #endif  // !_MSC_VER
 
 LayersPacket_Layer_Size::LayersPacket_Layer_Size()
   : ::google::protobuf::MessageLite() {
--- a/gfx/layers/protobuf/LayerScopePacket.pb.h
+++ b/gfx/layers/protobuf/LayerScopePacket.pb.h
@@ -32,29 +32,43 @@ namespace layerscope {
 // Internal implementation detail -- do not call these.
 void  protobuf_AddDesc_LayerScopePacket_2eproto();
 void protobuf_AssignDesc_LayerScopePacket_2eproto();
 void protobuf_ShutdownFile_LayerScopePacket_2eproto();
 
 class FramePacket;
 class ColorPacket;
 class TexturePacket;
+class TexturePacket_Rect;
+class TexturePacket_Size;
+class TexturePacket_Matrix;
+class TexturePacket_EffectMask;
 class LayersPacket;
 class LayersPacket_Layer;
 class LayersPacket_Layer_Size;
 class LayersPacket_Layer_Rect;
 class LayersPacket_Layer_Region;
 class LayersPacket_Layer_Matrix;
 class LayersPacket_Layer_Shadow;
 class MetaPacket;
 class DrawPacket;
 class DrawPacket_Rect;
 class Packet;
 class CommandPacket;
 
+enum TexturePacket_Filter {
+  TexturePacket_Filter_GOOD = 0,
+  TexturePacket_Filter_LINEAR = 1,
+  TexturePacket_Filter_POINT = 2
+};
+bool TexturePacket_Filter_IsValid(int value);
+const TexturePacket_Filter TexturePacket_Filter_Filter_MIN = TexturePacket_Filter_GOOD;
+const TexturePacket_Filter TexturePacket_Filter_Filter_MAX = TexturePacket_Filter_POINT;
+const int TexturePacket_Filter_Filter_ARRAYSIZE = TexturePacket_Filter_Filter_MAX + 1;
+
 enum LayersPacket_Layer_LayerType {
   LayersPacket_Layer_LayerType_UnknownLayer = 0,
   LayersPacket_Layer_LayerType_LayerManager = 1,
   LayersPacket_Layer_LayerType_ContainerLayer = 2,
   LayersPacket_Layer_LayerType_PaintedLayer = 3,
   LayersPacket_Layer_LayerType_CanvasLayer = 4,
   LayersPacket_Layer_LayerType_ImageLayer = 5,
   LayersPacket_Layer_LayerType_ColorLayer = 6,
@@ -71,22 +85,30 @@ enum LayersPacket_Layer_ScrollingDirect 
   LayersPacket_Layer_ScrollingDirect_HORIZONTAL = 2
 };
 bool LayersPacket_Layer_ScrollingDirect_IsValid(int value);
 const LayersPacket_Layer_ScrollingDirect LayersPacket_Layer_ScrollingDirect_ScrollingDirect_MIN = LayersPacket_Layer_ScrollingDirect_VERTICAL;
 const LayersPacket_Layer_ScrollingDirect LayersPacket_Layer_ScrollingDirect_ScrollingDirect_MAX = LayersPacket_Layer_ScrollingDirect_HORIZONTAL;
 const int LayersPacket_Layer_ScrollingDirect_ScrollingDirect_ARRAYSIZE = LayersPacket_Layer_ScrollingDirect_ScrollingDirect_MAX + 1;
 
 enum LayersPacket_Layer_Filter {
-  LayersPacket_Layer_Filter_FILTER_GOOD = 0,
-  LayersPacket_Layer_Filter_FILTER_LINEAR = 1,
-  LayersPacket_Layer_Filter_FILTER_POINT = 2,
-  LayersPacket_Layer_Filter_FILTER_SENTINEL = 3
+  LayersPacket_Layer_Filter_FILTER_FAST = 0,
+  LayersPacket_Layer_Filter_FILTER_GOOD = 1,
+  LayersPacket_Layer_Filter_FILTER_BEST = 2,
+  LayersPacket_Layer_Filter_FILTER_NEAREST = 3,
+  LayersPacket_Layer_Filter_FILTER_BILINEAR = 4,
+  LayersPacket_Layer_Filter_FILTER_GAUSSIAN = 5,
+  LayersPacket_Layer_Filter_FILTER_SENTINEL = 6,
+  LayersPacket_Layer_Filter_FILTER_LINEAR = 7,
+  LayersPacket_Layer_Filter_FILTER_POINT = 8
 };
 bool LayersPacket_Layer_Filter_IsValid(int value);
+const LayersPacket_Layer_Filter LayersPacket_Layer_Filter_Filter_MIN = LayersPacket_Layer_Filter_FILTER_FAST;
+const LayersPacket_Layer_Filter LayersPacket_Layer_Filter_Filter_MAX = LayersPacket_Layer_Filter_FILTER_POINT;
+const int LayersPacket_Layer_Filter_Filter_ARRAYSIZE = LayersPacket_Layer_Filter_Filter_MAX + 1;
 
 enum Packet_DataType {
   Packet_DataType_FRAMESTART = 1,
   Packet_DataType_FRAMEEND = 2,
   Packet_DataType_COLOR = 3,
   Packet_DataType_TEXTURE = 4,
   Packet_DataType_LAYERS = 5,
   Packet_DataType_META = 6,
@@ -326,16 +348,467 @@ class ColorPacket : public ::google::pro
   friend void protobuf_AssignDesc_LayerScopePacket_2eproto();
   friend void protobuf_ShutdownFile_LayerScopePacket_2eproto();
 
   void InitAsDefaultInstance();
   static ColorPacket* default_instance_;
 };
 // -------------------------------------------------------------------
 
+class TexturePacket_Rect : public ::google::protobuf::MessageLite {
+ public:
+  TexturePacket_Rect();
+  virtual ~TexturePacket_Rect();
+
+  TexturePacket_Rect(const TexturePacket_Rect& from);
+
+  inline TexturePacket_Rect& operator=(const TexturePacket_Rect& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::std::string& unknown_fields() const {
+    return _unknown_fields_;
+  }
+
+  inline ::std::string* mutable_unknown_fields() {
+    return &_unknown_fields_;
+  }
+
+  static const TexturePacket_Rect& default_instance();
+
+  #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  // Returns the internal default instance pointer. This function can
+  // return NULL thus should not be used by the user. This is intended
+  // for Protobuf internal code. Please use default_instance() declared
+  // above instead.
+  static inline const TexturePacket_Rect* internal_default_instance() {
+    return default_instance_;
+  }
+  #endif
+
+  void Swap(TexturePacket_Rect* other);
+
+  // implements Message ----------------------------------------------
+
+  TexturePacket_Rect* New() const;
+  void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from);
+  void CopyFrom(const TexturePacket_Rect& from);
+  void MergeFrom(const TexturePacket_Rect& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  void DiscardUnknownFields();
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  public:
+  ::std::string GetTypeName() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional float x = 1;
+  inline bool has_x() const;
+  inline void clear_x();
+  static const int kXFieldNumber = 1;
+  inline float x() const;
+  inline void set_x(float value);
+
+  // optional float y = 2;
+  inline bool has_y() const;
+  inline void clear_y();
+  static const int kYFieldNumber = 2;
+  inline float y() const;
+  inline void set_y(float value);
+
+  // optional float w = 3;
+  inline bool has_w() const;
+  inline void clear_w();
+  static const int kWFieldNumber = 3;
+  inline float w() const;
+  inline void set_w(float value);
+
+  // optional float h = 4;
+  inline bool has_h() const;
+  inline void clear_h();
+  static const int kHFieldNumber = 4;
+  inline float h() const;
+  inline void set_h(float value);
+
+  // @@protoc_insertion_point(class_scope:mozilla.layers.layerscope.TexturePacket.Rect)
+ private:
+  inline void set_has_x();
+  inline void clear_has_x();
+  inline void set_has_y();
+  inline void clear_has_y();
+  inline void set_has_w();
+  inline void clear_has_w();
+  inline void set_has_h();
+  inline void clear_has_h();
+
+  ::std::string _unknown_fields_;
+
+  ::google::protobuf::uint32 _has_bits_[1];
+  mutable int _cached_size_;
+  float x_;
+  float y_;
+  float w_;
+  float h_;
+  #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  friend void  protobuf_AddDesc_LayerScopePacket_2eproto_impl();
+  #else
+  friend void  protobuf_AddDesc_LayerScopePacket_2eproto();
+  #endif
+  friend void protobuf_AssignDesc_LayerScopePacket_2eproto();
+  friend void protobuf_ShutdownFile_LayerScopePacket_2eproto();
+
+  void InitAsDefaultInstance();
+  static TexturePacket_Rect* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class TexturePacket_Size : public ::google::protobuf::MessageLite {
+ public:
+  TexturePacket_Size();
+  virtual ~TexturePacket_Size();
+
+  TexturePacket_Size(const TexturePacket_Size& from);
+
+  inline TexturePacket_Size& operator=(const TexturePacket_Size& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::std::string& unknown_fields() const {
+    return _unknown_fields_;
+  }
+
+  inline ::std::string* mutable_unknown_fields() {
+    return &_unknown_fields_;
+  }
+
+  static const TexturePacket_Size& default_instance();
+
+  #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  // Returns the internal default instance pointer. This function can
+  // return NULL thus should not be used by the user. This is intended
+  // for Protobuf internal code. Please use default_instance() declared
+  // above instead.
+  static inline const TexturePacket_Size* internal_default_instance() {
+    return default_instance_;
+  }
+  #endif
+
+  void Swap(TexturePacket_Size* other);
+
+  // implements Message ----------------------------------------------
+
+  TexturePacket_Size* New() const;
+  void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from);
+  void CopyFrom(const TexturePacket_Size& from);
+  void MergeFrom(const TexturePacket_Size& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  void DiscardUnknownFields();
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  public:
+  ::std::string GetTypeName() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional int32 w = 1;
+  inline bool has_w() const;
+  inline void clear_w();
+  static const int kWFieldNumber = 1;
+  inline ::google::protobuf::int32 w() const;
+  inline void set_w(::google::protobuf::int32 value);
+
+  // optional int32 h = 2;
+  inline bool has_h() const;
+  inline void clear_h();
+  static const int kHFieldNumber = 2;
+  inline ::google::protobuf::int32 h() const;
+  inline void set_h(::google::protobuf::int32 value);
+
+  // @@protoc_insertion_point(class_scope:mozilla.layers.layerscope.TexturePacket.Size)
+ private:
+  inline void set_has_w();
+  inline void clear_has_w();
+  inline void set_has_h();
+  inline void clear_has_h();
+
+  ::std::string _unknown_fields_;
+
+  ::google::protobuf::uint32 _has_bits_[1];
+  mutable int _cached_size_;
+  ::google::protobuf::int32 w_;
+  ::google::protobuf::int32 h_;
+  #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  friend void  protobuf_AddDesc_LayerScopePacket_2eproto_impl();
+  #else
+  friend void  protobuf_AddDesc_LayerScopePacket_2eproto();
+  #endif
+  friend void protobuf_AssignDesc_LayerScopePacket_2eproto();
+  friend void protobuf_ShutdownFile_LayerScopePacket_2eproto();
+
+  void InitAsDefaultInstance();
+  static TexturePacket_Size* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class TexturePacket_Matrix : public ::google::protobuf::MessageLite {
+ public:
+  TexturePacket_Matrix();
+  virtual ~TexturePacket_Matrix();
+
+  TexturePacket_Matrix(const TexturePacket_Matrix& from);
+
+  inline TexturePacket_Matrix& operator=(const TexturePacket_Matrix& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::std::string& unknown_fields() const {
+    return _unknown_fields_;
+  }
+
+  inline ::std::string* mutable_unknown_fields() {
+    return &_unknown_fields_;
+  }
+
+  static const TexturePacket_Matrix& default_instance();
+
+  #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  // Returns the internal default instance pointer. This function can
+  // return NULL thus should not be used by the user. This is intended
+  // for Protobuf internal code. Please use default_instance() declared
+  // above instead.
+  static inline const TexturePacket_Matrix* internal_default_instance() {
+    return default_instance_;
+  }
+  #endif
+
+  void Swap(TexturePacket_Matrix* other);
+
+  // implements Message ----------------------------------------------
+
+  TexturePacket_Matrix* New() const;
+  void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from);
+  void CopyFrom(const TexturePacket_Matrix& from);
+  void MergeFrom(const TexturePacket_Matrix& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  void DiscardUnknownFields();
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  public:
+  ::std::string GetTypeName() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional bool is2D = 1;
+  inline bool has_is2d() const;
+  inline void clear_is2d();
+  static const int kIs2DFieldNumber = 1;
+  inline bool is2d() const;
+  inline void set_is2d(bool value);
+
+  // optional bool isId = 2;
+  inline bool has_isid() const;
+  inline void clear_isid();
+  static const int kIsIdFieldNumber = 2;
+  inline bool isid() const;
+  inline void set_isid(bool value);
+
+  // repeated float m = 3;
+  inline int m_size() const;
+  inline void clear_m();
+  static const int kMFieldNumber = 3;
+  inline float m(int index) const;
+  inline void set_m(int index, float value);
+  inline void add_m(float value);
+  inline const ::google::protobuf::RepeatedField< float >&
+      m() const;
+  inline ::google::protobuf::RepeatedField< float >*
+      mutable_m();
+
+  // @@protoc_insertion_point(class_scope:mozilla.layers.layerscope.TexturePacket.Matrix)
+ private:
+  inline void set_has_is2d();
+  inline void clear_has_is2d();
+  inline void set_has_isid();
+  inline void clear_has_isid();
+
+  ::std::string _unknown_fields_;
+
+  ::google::protobuf::uint32 _has_bits_[1];
+  mutable int _cached_size_;
+  ::google::protobuf::RepeatedField< float > m_;
+  bool is2d_;
+  bool isid_;
+  #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  friend void  protobuf_AddDesc_LayerScopePacket_2eproto_impl();
+  #else
+  friend void  protobuf_AddDesc_LayerScopePacket_2eproto();
+  #endif
+  friend void protobuf_AssignDesc_LayerScopePacket_2eproto();
+  friend void protobuf_ShutdownFile_LayerScopePacket_2eproto();
+
+  void InitAsDefaultInstance();
+  static TexturePacket_Matrix* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class TexturePacket_EffectMask : public ::google::protobuf::MessageLite {
+ public:
+  TexturePacket_EffectMask();
+  virtual ~TexturePacket_EffectMask();
+
+  TexturePacket_EffectMask(const TexturePacket_EffectMask& from);
+
+  inline TexturePacket_EffectMask& operator=(const TexturePacket_EffectMask& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::std::string& unknown_fields() const {
+    return _unknown_fields_;
+  }
+
+  inline ::std::string* mutable_unknown_fields() {
+    return &_unknown_fields_;
+  }
+
+  static const TexturePacket_EffectMask& default_instance();
+
+  #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  // Returns the internal default instance pointer. This function can
+  // return NULL thus should not be used by the user. This is intended
+  // for Protobuf internal code. Please use default_instance() declared
+  // above instead.
+  static inline const TexturePacket_EffectMask* internal_default_instance() {
+    return default_instance_;
+  }
+  #endif
+
+  void Swap(TexturePacket_EffectMask* other);
+
+  // implements Message ----------------------------------------------
+
+  TexturePacket_EffectMask* New() const;
+  void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from);
+  void CopyFrom(const TexturePacket_EffectMask& from);
+  void MergeFrom(const TexturePacket_EffectMask& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  void DiscardUnknownFields();
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  public:
+  ::std::string GetTypeName() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional bool mIs3D = 1;
+  inline bool has_mis3d() const;
+  inline void clear_mis3d();
+  static const int kMIs3DFieldNumber = 1;
+  inline bool mis3d() const;
+  inline void set_mis3d(bool value);
+
+  // optional .mozilla.layers.layerscope.TexturePacket.Size mSize = 2;
+  inline bool has_msize() const;
+  inline void clear_msize();
+  static const int kMSizeFieldNumber = 2;
+  inline const ::mozilla::layers::layerscope::TexturePacket_Size& msize() const;
+  inline ::mozilla::layers::layerscope::TexturePacket_Size* mutable_msize();
+  inline ::mozilla::layers::layerscope::TexturePacket_Size* release_msize();
+  inline void set_allocated_msize(::mozilla::layers::layerscope::TexturePacket_Size* msize);
+
+  // optional .mozilla.layers.layerscope.TexturePacket.Matrix mMaskTransform = 3;
+  inline bool has_mmasktransform() const;
+  inline void clear_mmasktransform();
+  static const int kMMaskTransformFieldNumber = 3;
+  inline const ::mozilla::layers::layerscope::TexturePacket_Matrix& mmasktransform() const;
+  inline ::mozilla::layers::layerscope::TexturePacket_Matrix* mutable_mmasktransform();
+  inline ::mozilla::layers::layerscope::TexturePacket_Matrix* release_mmasktransform();
+  inline void set_allocated_mmasktransform(::mozilla::layers::layerscope::TexturePacket_Matrix* mmasktransform);
+
+  // @@protoc_insertion_point(class_scope:mozilla.layers.layerscope.TexturePacket.EffectMask)
+ private:
+  inline void set_has_mis3d();
+  inline void clear_has_mis3d();
+  inline void set_has_msize();
+  inline void clear_has_msize();
+  inline void set_has_mmasktransform();
+  inline void clear_has_mmasktransform();
+
+  ::std::string _unknown_fields_;
+
+  ::google::protobuf::uint32 _has_bits_[1];
+  mutable int _cached_size_;
+  ::mozilla::layers::layerscope::TexturePacket_Size* msize_;
+  ::mozilla::layers::layerscope::TexturePacket_Matrix* mmasktransform_;
+  bool mis3d_;
+  #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  friend void  protobuf_AddDesc_LayerScopePacket_2eproto_impl();
+  #else
+  friend void  protobuf_AddDesc_LayerScopePacket_2eproto();
+  #endif
+  friend void protobuf_AssignDesc_LayerScopePacket_2eproto();
+  friend void protobuf_ShutdownFile_LayerScopePacket_2eproto();
+
+  void InitAsDefaultInstance();
+  static TexturePacket_EffectMask* default_instance_;
+};
+// -------------------------------------------------------------------
+
 class TexturePacket : public ::google::protobuf::MessageLite {
  public:
   TexturePacket();
   virtual ~TexturePacket();
 
   TexturePacket(const TexturePacket& from);
 
   inline TexturePacket& operator=(const TexturePacket& from) {
@@ -385,16 +858,35 @@ class TexturePacket : public ::google::p
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
   public:
   ::std::string GetTypeName() const;
 
   // nested types ----------------------------------------------------
 
+  typedef TexturePacket_Rect Rect;
+  typedef TexturePacket_Size Size;
+  typedef TexturePacket_Matrix Matrix;
+  typedef TexturePacket_EffectMask EffectMask;
+
+  typedef TexturePacket_Filter Filter;
+  static const Filter GOOD = TexturePacket_Filter_GOOD;
+  static const Filter LINEAR = TexturePacket_Filter_LINEAR;
+  static const Filter POINT = TexturePacket_Filter_POINT;
+  static inline bool Filter_IsValid(int value) {
+    return TexturePacket_Filter_IsValid(value);
+  }
+  static const Filter Filter_MIN =
+    TexturePacket_Filter_Filter_MIN;
+  static const Filter Filter_MAX =
+    TexturePacket_Filter_Filter_MAX;
+  static const int Filter_ARRAYSIZE =
+    TexturePacket_Filter_Filter_ARRAYSIZE;
+
   // accessors -------------------------------------------------------
 
   // required uint64 layerref = 1;
   inline bool has_layerref() const;
   inline void clear_layerref();
   static const int kLayerrefFieldNumber = 1;
   inline ::google::protobuf::uint64 layerref() const;
   inline void set_layerref(::google::protobuf::uint64 value);
@@ -455,23 +947,55 @@ class TexturePacket : public ::google::p
   inline const ::std::string& data() const;
   inline void set_data(const ::std::string& value);
   inline void set_data(const char* value);
   inline void set_data(const void* value, size_t size);
   inline ::std::string* mutable_data();
   inline ::std::string* release_data();
   inline void set_allocated_data(::std::string* data);
 
+  // optional .mozilla.layers.layerscope.TexturePacket.Rect mTextureCoords = 10;
+  inline bool has_mtexturecoords() const;
+  inline void clear_mtexturecoords();
+  static const int kMTextureCoordsFieldNumber = 10;
+  inline const ::mozilla::layers::layerscope::TexturePacket_Rect& mtexturecoords() const;
+  inline ::mozilla::layers::layerscope::TexturePacket_Rect* mutable_mtexturecoords();
+  inline ::mozilla::layers::layerscope::TexturePacket_Rect* release_mtexturecoords();
+  inline void set_allocated_mtexturecoords(::mozilla::layers::layerscope::TexturePacket_Rect* mtexturecoords);
+
+  // optional bool mPremultiplied = 11;
+  inline bool has_mpremultiplied() const;
+  inline void clear_mpremultiplied();
+  static const int kMPremultipliedFieldNumber = 11;
+  inline bool mpremultiplied() const;
+  inline void set_mpremultiplied(bool value);
+
+  // optional .mozilla.layers.layerscope.TexturePacket.Filter mFilter = 12;
+  inline bool has_mfilter() const;
+  inline void clear_mfilter();
+  static const int kMFilterFieldNumber = 12;
+  inline ::mozilla::layers::layerscope::TexturePacket_Filter mfilter() const;
+  inline void set_mfilter(::mozilla::layers::layerscope::TexturePacket_Filter value);
+
   // optional bool isMask = 20;
   inline bool has_ismask() const;
   inline void clear_ismask();
   static const int kIsMaskFieldNumber = 20;
   inline bool ismask() const;
   inline void set_ismask(bool value);
 
+  // optional .mozilla.layers.layerscope.TexturePacket.EffectMask mask = 21;
+  inline bool has_mask() const;
+  inline void clear_mask();
+  static const int kMaskFieldNumber = 21;
+  inline const ::mozilla::layers::layerscope::TexturePacket_EffectMask& mask() const;
+  inline ::mozilla::layers::layerscope::TexturePacket_EffectMask* mutable_mask();
+  inline ::mozilla::layers::layerscope::TexturePacket_EffectMask* release_mask();
+  inline void set_allocated_mask(::mozilla::layers::layerscope::TexturePacket_EffectMask* mask);
+
   // @@protoc_insertion_point(class_scope:mozilla.layers.layerscope.TexturePacket)
  private:
   inline void set_has_layerref();
   inline void clear_has_layerref();
   inline void set_has_width();
   inline void clear_has_width();
   inline void set_has_height();
   inline void clear_has_height();
@@ -482,33 +1006,45 @@ class TexturePacket : public ::google::p
   inline void set_has_target();
   inline void clear_has_target();
   inline void set_has_dataformat();
   inline void clear_has_dataformat();
   inline void set_has_glcontext();
   inline void clear_has_glcontext();
   inline void set_has_data();
   inline void clear_has_data();
+  inline void set_has_mtexturecoords();
+  inline void clear_has_mtexturecoords();
+  inline void set_has_mpremultiplied();
+  inline void clear_has_mpremultiplied();
+  inline void set_has_mfilter();
+  inline void clear_has_mfilter();
   inline void set_has_ismask();
   inline void clear_has_ismask();
+  inline void set_has_mask();
+  inline void clear_has_mask();
 
   ::std::string _unknown_fields_;
 
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
   ::google::protobuf::uint64 layerref_;
   ::google::protobuf::uint32 width_;
   ::google::protobuf::uint32 height_;
   ::google::protobuf::uint32 stride_;
   ::google::protobuf::uint32 name_;
   ::google::protobuf::uint32 target_;
   ::google::protobuf::uint32 dataformat_;
   ::google::protobuf::uint64 glcontext_;
   ::std::string* data_;
+  ::mozilla::layers::layerscope::TexturePacket_Rect* mtexturecoords_;
+  int mfilter_;
+  bool mpremultiplied_;
   bool ismask_;
+  ::mozilla::layers::layerscope::TexturePacket_EffectMask* mask_;
   #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
   friend void  protobuf_AddDesc_LayerScopePacket_2eproto_impl();
   #else
   friend void  protobuf_AddDesc_LayerScopePacket_2eproto();
   #endif
   friend void protobuf_AssignDesc_LayerScopePacket_2eproto();
   friend void protobuf_ShutdownFile_LayerScopePacket_2eproto();
 
@@ -1158,23 +1694,34 @@ class LayersPacket_Layer : public ::goog
   static const ScrollingDirect ScrollingDirect_MIN =
     LayersPacket_Layer_ScrollingDirect_ScrollingDirect_MIN;
   static const ScrollingDirect ScrollingDirect_MAX =
     LayersPacket_Layer_ScrollingDirect_ScrollingDirect_MAX;
   static const int ScrollingDirect_ARRAYSIZE =
     LayersPacket_Layer_ScrollingDirect_ScrollingDirect_ARRAYSIZE;
 
   typedef LayersPacket_Layer_Filter Filter;
+  static const Filter FILTER_FAST = LayersPacket_Layer_Filter_FILTER_FAST;
   static const Filter FILTER_GOOD = LayersPacket_Layer_Filter_FILTER_GOOD;
+  static const Filter FILTER_BEST = LayersPacket_Layer_Filter_FILTER_BEST;
+  static const Filter FILTER_NEAREST = LayersPacket_Layer_Filter_FILTER_NEAREST;
+  static const Filter FILTER_BILINEAR = LayersPacket_Layer_Filter_FILTER_BILINEAR;
+  static const Filter FILTER_GAUSSIAN = LayersPacket_Layer_Filter_FILTER_GAUSSIAN;
+  static const Filter FILTER_SENTINEL = LayersPacket_Layer_Filter_FILTER_SENTINEL;
   static const Filter FILTER_LINEAR = LayersPacket_Layer_Filter_FILTER_LINEAR;
   static const Filter FILTER_POINT = LayersPacket_Layer_Filter_FILTER_POINT;
-  static const Filter FILTER_SENTINEL = LayersPacket_Layer_Filter_FILTER_SENTINEL;
   static inline bool Filter_IsValid(int value) {
     return LayersPacket_Layer_Filter_IsValid(value);
   }
+  static const Filter Filter_MIN =
+    LayersPacket_Layer_Filter_Filter_MIN;
+  static const Filter Filter_MAX =
+    LayersPacket_Layer_Filter_Filter_MAX;
+  static const int Filter_ARRAYSIZE =
+    LayersPacket_Layer_Filter_Filter_ARRAYSIZE;
 
   // accessors -------------------------------------------------------
 
   // required .mozilla.layers.layerscope.LayersPacket.Layer.LayerType type = 1;
   inline bool has_type() const;
   inline void clear_type();
   static const int kTypeFieldNumber = 1;
   inline ::mozilla::layers::layerscope::LayersPacket_Layer_LayerType type() const;
@@ -2399,16 +2946,368 @@ inline ::google::protobuf::uint32 ColorP
 inline void ColorPacket::set_color(::google::protobuf::uint32 value) {
   set_has_color();
   color_ = value;
   // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.ColorPacket.color)
 }
 
 // -------------------------------------------------------------------
 
+// TexturePacket_Rect
+
+// optional float x = 1;
+inline bool TexturePacket_Rect::has_x() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void TexturePacket_Rect::set_has_x() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void TexturePacket_Rect::clear_has_x() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void TexturePacket_Rect::clear_x() {
+  x_ = 0;
+  clear_has_x();
+}
+inline float TexturePacket_Rect::x() const {
+  // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.TexturePacket.Rect.x)
+  return x_;
+}
+inline void TexturePacket_Rect::set_x(float value) {
+  set_has_x();
+  x_ = value;
+  // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.TexturePacket.Rect.x)
+}
+
+// optional float y = 2;
+inline bool TexturePacket_Rect::has_y() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void TexturePacket_Rect::set_has_y() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void TexturePacket_Rect::clear_has_y() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void TexturePacket_Rect::clear_y() {
+  y_ = 0;
+  clear_has_y();
+}
+inline float TexturePacket_Rect::y() const {
+  // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.TexturePacket.Rect.y)
+  return y_;
+}
+inline void TexturePacket_Rect::set_y(float value) {
+  set_has_y();
+  y_ = value;
+  // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.TexturePacket.Rect.y)
+}
+
+// optional float w = 3;
+inline bool TexturePacket_Rect::has_w() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void TexturePacket_Rect::set_has_w() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void TexturePacket_Rect::clear_has_w() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void TexturePacket_Rect::clear_w() {
+  w_ = 0;
+  clear_has_w();
+}
+inline float TexturePacket_Rect::w() const {
+  // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.TexturePacket.Rect.w)
+  return w_;
+}
+inline void TexturePacket_Rect::set_w(float value) {
+  set_has_w();
+  w_ = value;
+  // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.TexturePacket.Rect.w)
+}
+
+// optional float h = 4;
+inline bool TexturePacket_Rect::has_h() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void TexturePacket_Rect::set_has_h() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void TexturePacket_Rect::clear_has_h() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void TexturePacket_Rect::clear_h() {
+  h_ = 0;
+  clear_has_h();
+}
+inline float TexturePacket_Rect::h() const {
+  // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.TexturePacket.Rect.h)
+  return h_;
+}
+inline void TexturePacket_Rect::set_h(float value) {
+  set_has_h();
+  h_ = value;
+  // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.TexturePacket.Rect.h)
+}
+
+// -------------------------------------------------------------------
+
+// TexturePacket_Size
+
+// optional int32 w = 1;
+inline bool TexturePacket_Size::has_w() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void TexturePacket_Size::set_has_w() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void TexturePacket_Size::clear_has_w() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void TexturePacket_Size::clear_w() {
+  w_ = 0;
+  clear_has_w();
+}
+inline ::google::protobuf::int32 TexturePacket_Size::w() const {
+  // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.TexturePacket.Size.w)
+  return w_;
+}
+inline void TexturePacket_Size::set_w(::google::protobuf::int32 value) {
+  set_has_w();
+  w_ = value;
+  // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.TexturePacket.Size.w)
+}
+
+// optional int32 h = 2;
+inline bool TexturePacket_Size::has_h() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void TexturePacket_Size::set_has_h() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void TexturePacket_Size::clear_has_h() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void TexturePacket_Size::clear_h() {
+  h_ = 0;
+  clear_has_h();
+}
+inline ::google::protobuf::int32 TexturePacket_Size::h() const {
+  // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.TexturePacket.Size.h)
+  return h_;
+}
+inline void TexturePacket_Size::set_h(::google::protobuf::int32 value) {
+  set_has_h();
+  h_ = value;
+  // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.TexturePacket.Size.h)
+}
+
+// -------------------------------------------------------------------
+
+// TexturePacket_Matrix
+
+// optional bool is2D = 1;
+inline bool TexturePacket_Matrix::has_is2d() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void TexturePacket_Matrix::set_has_is2d() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void TexturePacket_Matrix::clear_has_is2d() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void TexturePacket_Matrix::clear_is2d() {
+  is2d_ = false;
+  clear_has_is2d();
+}
+inline bool TexturePacket_Matrix::is2d() const {
+  // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.TexturePacket.Matrix.is2D)
+  return is2d_;
+}
+inline void TexturePacket_Matrix::set_is2d(bool value) {
+  set_has_is2d();
+  is2d_ = value;
+  // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.TexturePacket.Matrix.is2D)
+}
+
+// optional bool isId = 2;
+inline bool TexturePacket_Matrix::has_isid() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void TexturePacket_Matrix::set_has_isid() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void TexturePacket_Matrix::clear_has_isid() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void TexturePacket_Matrix::clear_isid() {
+  isid_ = false;
+  clear_has_isid();
+}
+inline bool TexturePacket_Matrix::isid() const {
+  // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.TexturePacket.Matrix.isId)
+  return isid_;
+}
+inline void TexturePacket_Matrix::set_isid(bool value) {
+  set_has_isid();
+  isid_ = value;
+  // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.TexturePacket.Matrix.isId)
+}
+
+// repeated float m = 3;
+inline int TexturePacket_Matrix::m_size() const {
+  return m_.size();
+}
+inline void TexturePacket_Matrix::clear_m() {
+  m_.Clear();
+}
+inline float TexturePacket_Matrix::m(int index) const {
+  // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.TexturePacket.Matrix.m)
+  return m_.Get(index);
+}
+inline void TexturePacket_Matrix::set_m(int index, float value) {
+  m_.Set(index, value);
+  // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.TexturePacket.Matrix.m)
+}
+inline void TexturePacket_Matrix::add_m(float value) {
+  m_.Add(value);
+  // @@protoc_insertion_point(field_add:mozilla.layers.layerscope.TexturePacket.Matrix.m)
+}
+inline const ::google::protobuf::RepeatedField< float >&
+TexturePacket_Matrix::m() const {
+  // @@protoc_insertion_point(field_list:mozilla.layers.layerscope.TexturePacket.Matrix.m)
+  return m_;
+}
+inline ::google::protobuf::RepeatedField< float >*
+TexturePacket_Matrix::mutable_m() {
+  // @@protoc_insertion_point(field_mutable_list:mozilla.layers.layerscope.TexturePacket.Matrix.m)
+  return &m_;
+}
+
+// -------------------------------------------------------------------
+
+// TexturePacket_EffectMask
+
+// optional bool mIs3D = 1;
+inline bool TexturePacket_EffectMask::has_mis3d() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void TexturePacket_EffectMask::set_has_mis3d() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void TexturePacket_EffectMask::clear_has_mis3d() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void TexturePacket_EffectMask::clear_mis3d() {
+  mis3d_ = false;
+  clear_has_mis3d();
+}
+inline bool TexturePacket_EffectMask::mis3d() const {
+  // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.TexturePacket.EffectMask.mIs3D)
+  return mis3d_;
+}
+inline void TexturePacket_EffectMask::set_mis3d(bool value) {
+  set_has_mis3d();
+  mis3d_ = value;
+  // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.TexturePacket.EffectMask.mIs3D)
+}
+
+// optional .mozilla.layers.layerscope.TexturePacket.Size mSize = 2;
+inline bool TexturePacket_EffectMask::has_msize() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void TexturePacket_EffectMask::set_has_msize() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void TexturePacket_EffectMask::clear_has_msize() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void TexturePacket_EffectMask::clear_msize() {
+  if (msize_ != NULL) msize_->::mozilla::layers::layerscope::TexturePacket_Size::Clear();
+  clear_has_msize();
+}
+inline const ::mozilla::layers::layerscope::TexturePacket_Size& TexturePacket_EffectMask::msize() const {
+  // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.TexturePacket.EffectMask.mSize)
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  return msize_ != NULL ? *msize_ : *default_instance().msize_;
+#else
+  return msize_ != NULL ? *msize_ : *default_instance_->msize_;
+#endif
+}
+inline ::mozilla::layers::layerscope::TexturePacket_Size* TexturePacket_EffectMask::mutable_msize() {
+  set_has_msize();
+  if (msize_ == NULL) msize_ = new ::mozilla::layers::layerscope::TexturePacket_Size;
+  // @@protoc_insertion_point(field_mutable:mozilla.layers.layerscope.TexturePacket.EffectMask.mSize)
+  return msize_;
+}
+inline ::mozilla::layers::layerscope::TexturePacket_Size* TexturePacket_EffectMask::release_msize() {
+  clear_has_msize();
+  ::mozilla::layers::layerscope::TexturePacket_Size* temp = msize_;
+  msize_ = NULL;
+  return temp;
+}
+inline void TexturePacket_EffectMask::set_allocated_msize(::mozilla::layers::layerscope::TexturePacket_Size* msize) {
+  delete msize_;
+  msize_ = msize;
+  if (msize) {
+    set_has_msize();
+  } else {
+    clear_has_msize();
+  }
+  // @@protoc_insertion_point(field_set_allocated:mozilla.layers.layerscope.TexturePacket.EffectMask.mSize)
+}
+
+// optional .mozilla.layers.layerscope.TexturePacket.Matrix mMaskTransform = 3;
+inline bool TexturePacket_EffectMask::has_mmasktransform() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void TexturePacket_EffectMask::set_has_mmasktransform() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void TexturePacket_EffectMask::clear_has_mmasktransform() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void TexturePacket_EffectMask::clear_mmasktransform() {
+  if (mmasktransform_ != NULL) mmasktransform_->::mozilla::layers::layerscope::TexturePacket_Matrix::Clear();
+  clear_has_mmasktransform();
+}
+inline const ::mozilla::layers::layerscope::TexturePacket_Matrix& TexturePacket_EffectMask::mmasktransform() const {
+  // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.TexturePacket.EffectMask.mMaskTransform)
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  return mmasktransform_ != NULL ? *mmasktransform_ : *default_instance().mmasktransform_;
+#else
+  return mmasktransform_ != NULL ? *mmasktransform_ : *default_instance_->mmasktransform_;
+#endif
+}
+inline ::mozilla::layers::layerscope::TexturePacket_Matrix* TexturePacket_EffectMask::mutable_mmasktransform() {
+  set_has_mmasktransform();
+  if (mmasktransform_ == NULL) mmasktransform_ = new ::mozilla::layers::layerscope::TexturePacket_Matrix;
+  // @@protoc_insertion_point(field_mutable:mozilla.layers.layerscope.TexturePacket.EffectMask.mMaskTransform)
+  return mmasktransform_;
+}
+inline ::mozilla::layers::layerscope::TexturePacket_Matrix* TexturePacket_EffectMask::release_mmasktransform() {
+  clear_has_mmasktransform();
+  ::mozilla::layers::layerscope::TexturePacket_Matrix* temp = mmasktransform_;
+  mmasktransform_ = NULL;
+  return temp;
+}
+inline void TexturePacket_EffectMask::set_allocated_mmasktransform(::mozilla::layers::layerscope::TexturePacket_Matrix* mmasktransform) {
+  delete mmasktransform_;
+  mmasktransform_ = mmasktransform;
+  if (mmasktransform) {
+    set_has_mmasktransform();
+  } else {
+    clear_has_mmasktransform();
+  }
+  // @@protoc_insertion_point(field_set_allocated:mozilla.layers.layerscope.TexturePacket.EffectMask.mMaskTransform)
+}
+
+// -------------------------------------------------------------------
+
 // TexturePacket
 
 // required uint64 layerref = 1;
 inline bool TexturePacket::has_layerref() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
 inline void TexturePacket::set_has_layerref() {
   _has_bits_[0] |= 0x00000001u;
@@ -2669,40 +3568,179 @@ inline void TexturePacket::set_allocated
     data_ = data;
   } else {
     clear_has_data();
     data_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
   // @@protoc_insertion_point(field_set_allocated:mozilla.layers.layerscope.TexturePacket.data)
 }
 
+// optional .mozilla.layers.layerscope.TexturePacket.Rect mTextureCoords = 10;
+inline bool TexturePacket::has_mtexturecoords() const {
+  return (_has_bits_[0] & 0x00000200u) != 0;
+}
+inline void TexturePacket::set_has_mtexturecoords() {
+  _has_bits_[0] |= 0x00000200u;
+}
+inline void TexturePacket::clear_has_mtexturecoords() {
+  _has_bits_[0] &= ~0x00000200u;
+}
+inline void TexturePacket::clear_mtexturecoords() {
+  if (mtexturecoords_ != NULL) mtexturecoords_->::mozilla::layers::layerscope::TexturePacket_Rect::Clear();
+  clear_has_mtexturecoords();
+}
+inline const ::mozilla::layers::layerscope::TexturePacket_Rect& TexturePacket::mtexturecoords() const {
+  // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.TexturePacket.mTextureCoords)
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  return mtexturecoords_ != NULL ? *mtexturecoords_ : *default_instance().mtexturecoords_;
+#else
+  return mtexturecoords_ != NULL ? *mtexturecoords_ : *default_instance_->mtexturecoords_;
+#endif
+}
+inline ::mozilla::layers::layerscope::TexturePacket_Rect* TexturePacket::mutable_mtexturecoords() {
+  set_has_mtexturecoords();
+  if (mtexturecoords_ == NULL) mtexturecoords_ = new ::mozilla::layers::layerscope::TexturePacket_Rect;
+  // @@protoc_insertion_point(field_mutable:mozilla.layers.layerscope.TexturePacket.mTextureCoords)
+  return mtexturecoords_;
+}
+inline ::mozilla::layers::layerscope::TexturePacket_Rect* TexturePacket::release_mtexturecoords() {
+  clear_has_mtexturecoords();
+  ::mozilla::layers::layerscope::TexturePacket_Rect* temp = mtexturecoords_;
+  mtexturecoords_ = NULL;
+  return temp;
+}
+inline void TexturePacket::set_allocated_mtexturecoords(::mozilla::layers::layerscope::TexturePacket_Rect* mtexturecoords) {
+  delete mtexturecoords_;
+  mtexturecoords_ = mtexturecoords;
+  if (mtexturecoords) {
+    set_has_mtexturecoords();
+  } else {
+    clear_has_mtexturecoords();
+  }
+  // @@protoc_insertion_point(field_set_allocated:mozilla.layers.layerscope.TexturePacket.mTextureCoords)
+}
+
+// optional bool mPremultiplied = 11;
+inline bool TexturePacket::has_mpremultiplied() const {
+  return (_has_bits_[0] & 0x00000400u) != 0;
+}
+inline void TexturePacket::set_has_mpremultiplied() {
+  _has_bits_[0] |= 0x00000400u;
+}
+inline void TexturePacket::clear_has_mpremultiplied() {
+  _has_bits_[0] &= ~0x00000400u;
+}
+inline void TexturePacket::clear_mpremultiplied() {
+  mpremultiplied_ = false;
+  clear_has_mpremultiplied();
+}
+inline bool TexturePacket::mpremultiplied() const {
+  // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.TexturePacket.mPremultiplied)
+  return mpremultiplied_;
+}
+inline void TexturePacket::set_mpremultiplied(bool value) {
+  set_has_mpremultiplied();
+  mpremultiplied_ = value;
+  // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.TexturePacket.mPremultiplied)
+}
+
+// optional .mozilla.layers.layerscope.TexturePacket.Filter mFilter = 12;
+inline bool TexturePacket::has_mfilter() const {
+  return (_has_bits_[0] & 0x00000800u) != 0;
+}
+inline void TexturePacket::set_has_mfilter() {
+  _has_bits_[0] |= 0x00000800u;
+}
+inline void TexturePacket::clear_has_mfilter() {
+  _has_bits_[0] &= ~0x00000800u;
+}
+inline void TexturePacket::clear_mfilter() {
+  mfilter_ = 0;
+  clear_has_mfilter();
+}
+inline ::mozilla::layers::layerscope::TexturePacket_Filter TexturePacket::mfilter() const {
+  // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.TexturePacket.mFilter)
+  return static_cast< ::mozilla::layers::layerscope::TexturePacket_Filter >(mfilter_);
+}
+inline void TexturePacket::set_mfilter(::mozilla::layers::layerscope::TexturePacket_Filter value) {
+  assert(::mozilla::layers::layerscope::TexturePacket_Filter_IsValid(value));
+  set_has_mfilter();
+  mfilter_ = value;
+  // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.TexturePacket.mFilter)
+}
+
 // optional bool isMask = 20;
 inline bool TexturePacket::has_ismask() const {
-  return (_has_bits_[0] & 0x00000200u) != 0;
+  return (_has_bits_[0] & 0x00001000u) != 0;
 }
 inline void TexturePacket::set_has_ismask() {
-  _has_bits_[0] |= 0x00000200u;
+  _has_bits_[0] |= 0x00001000u;
 }
 inline void TexturePacket::clear_has_ismask() {
-  _has_bits_[0] &= ~0x00000200u;
+  _has_bits_[0] &= ~0x00001000u;
 }
 inline void TexturePacket::clear_ismask() {
   ismask_ = false;
   clear_has_ismask();
 }
 inline bool TexturePacket::ismask() const {
   // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.TexturePacket.isMask)
   return ismask_;
 }
 inline void TexturePacket::set_ismask(bool value) {
   set_has_ismask();
   ismask_ = value;
   // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.TexturePacket.isMask)
 }
 
+// optional .mozilla.layers.layerscope.TexturePacket.EffectMask mask = 21;
+inline bool TexturePacket::has_mask() const {
+  return (_has_bits_[0] & 0x00002000u) != 0;
+}
+inline void TexturePacket::set_has_mask() {
+  _has_bits_[0] |= 0x00002000u;
+}
+inline void TexturePacket::clear_has_mask() {
+  _has_bits_[0] &= ~0x00002000u;
+}
+inline void TexturePacket::clear_mask() {
+  if (mask_ != NULL) mask_->::mozilla::layers::layerscope::TexturePacket_EffectMask::Clear();
+  clear_has_mask();
+}
+inline const ::mozilla::layers::layerscope::TexturePacket_EffectMask& TexturePacket::mask() const {
+  // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.TexturePacket.mask)
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  return mask_ != NULL ? *mask_ : *default_instance().mask_;
+#else
+  return mask_ != NULL ? *mask_ : *default_instance_->mask_;
+#endif
+}
+inline ::mozilla::layers::layerscope::TexturePacket_EffectMask* TexturePacket::mutable_mask() {
+  set_has_mask();
+  if (mask_ == NULL) mask_ = new ::mozilla::layers::layerscope::TexturePacket_EffectMask;
+  // @@protoc_insertion_point(field_mutable:mozilla.layers.layerscope.TexturePacket.mask)
+  return mask_;
+}
+inline ::mozilla::layers::layerscope::TexturePacket_EffectMask* TexturePacket::release_mask() {
+  clear_has_mask();
+  ::mozilla::layers::layerscope::TexturePacket_EffectMask* temp = mask_;
+  mask_ = NULL;
+  return temp;
+}
+inline void TexturePacket::set_allocated_mask(::mozilla::layers::layerscope::TexturePacket_EffectMask* mask) {
+  delete mask_;
+  mask_ = mask;
+  if (mask) {
+    set_has_mask();
+  } else {
+    clear_has_mask();
+  }
+  // @@protoc_insertion_point(field_set_allocated:mozilla.layers.layerscope.TexturePacket.mask)
+}
+
 // -------------------------------------------------------------------
 
 // LayersPacket_Layer_Size
 
 // optional int32 w = 1;
 inline bool LayersPacket_Layer_Size::has_w() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
--- a/gfx/layers/protobuf/LayerScopePacket.proto
+++ b/gfx/layers/protobuf/LayerScopePacket.proto
@@ -15,33 +15,61 @@ message FramePacket {
 message ColorPacket {
   required uint64 layerref = 1;
   optional uint32 width = 2;
   optional uint32 height = 3;
   optional uint32 color = 4;
 }
 
 message TexturePacket {
+  enum Filter {
+    GOOD = 0;
+    LINEAR = 1;
+    POINT = 2;
+  }
+  message Rect {
+    optional float x = 1;
+    optional float y = 2;
+    optional float w = 3;
+    optional float h = 4;
+  }
+  message Size {
+    optional int32 w = 1;
+    optional int32 h = 2;
+  }
+  message Matrix {
+    optional bool is2D = 1;
+    optional bool isId = 2;
+    repeated float m = 3;
+  }
+  message EffectMask {
+    optional bool mIs3D = 1;
+    optional Size mSize = 2;
+    optional Matrix mMaskTransform = 3;
+  }
+
   // Basic info
   required uint64 layerref = 1;
   optional uint32 width = 2;
   optional uint32 height = 3;
   optional uint32 stride = 4;
   optional uint32 name = 5;
   optional uint32 target = 6;
   optional uint32 dataformat = 7;
   optional uint64 glcontext = 8;
   optional bytes data = 9;
 
-  // Texture effect attributes (10 to 19)
-  // TODO: reserved for primary textured effect attributes, see Bug 1205521
+  // TextureEffect attributes
+  optional Rect mTextureCoords = 10;
+  optional bool mPremultiplied = 11;
+  optional Filter mFilter = 12;
 
-  // Mask effect attributes (20 to 29)
+  // Mask attributes
   optional bool isMask = 20;
-  // TODO: reserved for secondary mask effect attributes, see Bug 1205521
+  optional EffectMask mask = 21;
 }
 
 message LayersPacket {
   message Layer {
     enum LayerType {
       UnknownLayer = 0;
       LayerManager = 1;
       ContainerLayer = 2;
@@ -52,23 +80,25 @@ message LayersPacket {
       RefLayer = 7;
       ReadbackLayer = 8;
     }
     enum ScrollingDirect {
       VERTICAL = 1;
       HORIZONTAL = 2;
     }
     enum Filter {
-      FILTER_FAST = 0;
+      FILTER_FAST = 0; // deprecated
       FILTER_GOOD = 1;
-      FILTER_BEST = 2;
-      FILTER_NEAREST = 3;
-      FILTER_BILINEAR = 4;
-      FILTER_GAUSSIAN = 5;
-      FILTER_SENTINEL = 6;
+      FILTER_BEST = 2; // deprecated
+      FILTER_NEAREST = 3; //deprecated
+      FILTER_BILINEAR = 4; //deprecated
+      FILTER_GAUSSIAN = 5; //deprecated
+      FILTER_SENTINEL = 6; //deprecated
+      FILTER_LINEAR = 7;
+      FILTER_POINT = 8;
     }
     message Size {
       optional int32 w = 1;
       optional int32 h = 2;
     }
     message Rect {
       optional int32 x = 1;
       optional int32 y = 2;
--- a/gfx/tests/crashtests/crashtests.list
+++ b/gfx/tests/crashtests/crashtests.list
@@ -98,17 +98,17 @@ load 665218.html
 load 686190-1.html
 load 693143-1.html
 load 768079-1.html
 load 783041-1.html
 load 783041-2.html
 load 783041-3.html
 load 783041-4.html
 asserts-if(gtkWidget,0-1) load 798853.html # bug 868792
-asserts-if(winWidget,0-1) skip-if(B2G) load 815489.html
+asserts-if(winWidget,0-1) skip-if(B2G||Android) load 815489.html # bug 871763, 1216304
 load 836225-1.html
 load 839745-1.html
 load 856784-1.html
 load 893572-1.html
 load 893572-2.html
 load 893572-3.html
 load 893572-4.html
 pref(layers.force-active,true) load 914457-1.html
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1215363-1.js
@@ -0,0 +1,4 @@
+if (!('oomTest' in this))
+    quit();
+
+oomTest(() => parseModule(10));
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1215363-2.js
@@ -0,0 +1,7 @@
+if (!('oomTest' in this))
+    quit();
+
+var lfcode = new Array();
+oomTest((function(x) {
+    assertEq(...Object);
+}));
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1215363-3.js
@@ -0,0 +1,5 @@
+if (!('oomTest' in this))
+    quit();
+
+var lfcode = new Array();
+oomTest(() => getBacktrace({}));
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/oomInOffTheadCompile.js
@@ -0,0 +1,15 @@
+if (!('oomTest' in this) || helperThreadCount() === 0)
+    quit();
+
+oomTest(() => {
+    offThreadCompileScript(
+        `
+        function f(x) {
+            if (x == 0)
+                return "foobar";
+            return 1 + f(x - 1);
+        }
+        f(5);
+        `);
+    runOffThreadScript();
+});
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -8003,17 +8003,21 @@ CodeGenerator::link(JSContext* cx, Compi
 
     if (!linkSharedStubs(cx))
         return false;
 
     // Check to make sure we didn't have a mid-build invalidation. If so, we
     // will trickle to jit::Compile() and return Method_Skipped.
     uint32_t warmUpCount = script->getWarmUpCount();
     RecompileInfo recompileInfo;
-    if (!FinishCompilation(cx, script, constraints, &recompileInfo))
+    bool isValid;
+    if (!FinishCompilation(cx, script, constraints, &recompileInfo, &isValid))
+        return false;
+
+    if (!isValid)
         return true;
 
     // IonMonkey could have inferred better type information during
     // compilation. Since adding the new information to the actual type
     // information can reset the usecount, increase it back to what it was
     // before.
     if (warmUpCount > script->getWarmUpCount())
         script->incWarmUpCounter(warmUpCount - script->getWarmUpCount());
--- a/js/src/jit/CompactBuffer.h
+++ b/js/src/jit/CompactBuffer.h
@@ -120,17 +120,18 @@ class CompactBufferWriter
     // Note: writeByte() takes uint32 to catch implicit casts with a runtime
     // assert.
     void writeByte(uint32_t byte) {
         MOZ_ASSERT(byte <= 0xFF);
         enoughMemory_ &= buffer_.append(byte);
     }
     void writeByteAt(uint32_t pos, uint32_t byte) {
         MOZ_ASSERT(byte <= 0xFF);
-        buffer_[pos] = byte;
+        if (!oom())
+            buffer_[pos] = byte;
     }
     void writeUnsigned(uint32_t value) {
         do {
             uint8_t byte = ((value & 0x7F) << 1) | (value > 0x7F);
             writeByte(byte);
             value >>= 7;
         } while (value);
     }
@@ -173,19 +174,21 @@ class CompactBufferWriter
             return;
         uint8_t* endPtr = buffer() + length();
         reinterpret_cast<uint32_t*>(endPtr)[-1] = value;
     }
     size_t length() const {
         return buffer_.length();
     }
     uint8_t* buffer() {
+        MOZ_ASSERT(!oom());
         return &buffer_[0];
     }
     const uint8_t* buffer() const {
+        MOZ_ASSERT(!oom());
         return &buffer_[0];
     }
     bool oom() const {
         return !enoughMemory_;
     }
 };
 
 CompactBufferReader::CompactBufferReader(const CompactBufferWriter& writer)
--- a/js/src/jit/JitFrameIterator.h
+++ b/js/src/jit/JitFrameIterator.h
@@ -333,16 +333,19 @@ class RInstructionResults
     RInstructionResults(RInstructionResults&& src);
 
     RInstructionResults& operator=(RInstructionResults&& rhs);
 
     ~RInstructionResults();
 
     bool init(JSContext* cx, uint32_t numResults);
     bool isInitialized() const;
+#ifdef DEBUG
+    size_t length() const;
+#endif
 
     JitFrameLayout* frame() const;
 
     RelocatableValue& operator[](size_t index);
 
     void trace(JSTracer* trc);
 };
 
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -1745,16 +1745,24 @@ RInstructionResults::init(JSContext* cx,
 }
 
 bool
 RInstructionResults::isInitialized() const
 {
     return initialized_;
 }
 
+#ifdef DEBUG
+size_t
+RInstructionResults::length() const
+{
+    return results_->length();
+}
+#endif
+
 JitFrameLayout*
 RInstructionResults::frame() const
 {
     MOZ_ASSERT(fp_);
     return fp_;
 }
 
 RelocatableValue&
@@ -2211,16 +2219,17 @@ SnapshotIterator::initInstructionResults
             // If the evaluation failed because of OOMs, then we discard the
             // current set of result that we collected so far.
             fallback.activation->removeIonFrameRecovery(fp);
             return false;
         }
     }
 
     MOZ_ASSERT(results->isInitialized());
+    MOZ_ASSERT(results->length() == recover_.numInstructions() - 1);
     instructionResults_ = results;
     return true;
 }
 
 bool
 SnapshotIterator::computeInstructionResults(JSContext* cx, RInstructionResults* results) const
 {
     MOZ_ASSERT(!results->isInitialized());
--- a/js/src/jit/Snapshots.cpp
+++ b/js/src/jit/Snapshots.cpp
@@ -318,18 +318,17 @@ RValueAllocation::read(CompactBufferRead
     Payload arg1, arg2;
 
     readPayload(reader, layout.type1, &mode, &arg1);
     readPayload(reader, layout.type2, &mode, &arg2);
     return RValueAllocation(Mode(mode), arg1, arg2);
 }
 
 void
-RValueAllocation::writePayload(CompactBufferWriter& writer, PayloadType type,
-                               Payload p)
+RValueAllocation::writePayload(CompactBufferWriter& writer, PayloadType type, Payload p)
 {
     switch (type) {
       case PAYLOAD_NONE:
         break;
       case PAYLOAD_INDEX:
         writer.writeUnsigned(p.index);
         break;
       case PAYLOAD_STACK_OFFSET:
@@ -343,20 +342,22 @@ RValueAllocation::writePayload(CompactBu
       case PAYLOAD_FPU:
         static_assert(FloatRegisters::Total <= 0x100,
                       "Not enough bytes to encode all float registers.");
         writer.writeByte(p.fpu.code());
         break;
       case PAYLOAD_PACKED_TAG: {
         // This code assumes that the PACKED_TAG payload is following the
         // writeByte of the mode.
-        MOZ_ASSERT(writer.length());
-        uint8_t* mode = writer.buffer() + (writer.length() - 1);
-        MOZ_ASSERT((*mode & PACKED_TAG_MASK) == 0 && (p.type & ~PACKED_TAG_MASK) == 0);
-        *mode = *mode | p.type;
+        if (!writer.oom()) {
+            MOZ_ASSERT(writer.length());
+            uint8_t* mode = writer.buffer() + (writer.length() - 1);
+            MOZ_ASSERT((*mode & PACKED_TAG_MASK) == 0 && (p.type & ~PACKED_TAG_MASK) == 0);
+            *mode = *mode | p.type;
+        }
         break;
       }
     }
 }
 
 void
 RValueAllocation::writePadding(CompactBufferWriter& writer)
 {
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -155,18 +155,18 @@ CodeGeneratorARM::bailoutIf(Assembler::C
 }
 
 void
 CodeGeneratorARM::bailoutFrom(Label* label, LSnapshot* snapshot)
 {
     if (masm.bailed())
         return;
 
-    MOZ_ASSERT(label->used());
-    MOZ_ASSERT(!label->bound());
+    MOZ_ASSERT_IF(!masm.oom(), label->used());
+    MOZ_ASSERT_IF(!masm.oom(), !label->bound());
 
     encode(snapshot);
 
     // Though the assembler doesn't track all frame pushes, at least make sure
     // the known value makes sense. We can't use bailout tables if the stack
     // isn't properly aligned to the static frame size.
     MOZ_ASSERT_IF(frameClass_ != FrameSizeClass::None(),
                   frameClass_.frameSize() == masm.framePushed());
--- a/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp
+++ b/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp
@@ -166,18 +166,18 @@ CodeGeneratorMIPSShared::generateOutOfLi
 }
 
 void
 CodeGeneratorMIPSShared::bailoutFrom(Label* label, LSnapshot* snapshot)
 {
     if (masm.bailed())
         return;
 
-    MOZ_ASSERT(label->used());
-    MOZ_ASSERT(!label->bound());
+    MOZ_ASSERT_IF(!masm.oom(), label->used());
+    MOZ_ASSERT_IF(!masm.oom(), !label->bound());
 
     encode(snapshot);
 
     // Though the assembler doesn't track all frame pushes, at least make sure
     // the known value makes sense. We can't use bailout tables if the stack
     // isn't properly aligned to the static frame size.
     MOZ_ASSERT_IF(frameClass_ != FrameSizeClass::None(),
                   frameClass_.frameSize() == masm.framePushed());
--- a/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
+++ b/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
@@ -513,17 +513,17 @@ struct AssemblerBufferWithConstantPools 
         PoolInfo pi = getLastPoolInfo();
         return codeEnd + (pi.finalPos - pi.offset);
     }
 
   public:
     size_t size() const {
         // Return the current actual size of the buffer. This is only accurate
         // if there are no pending pool entries to dump, check.
-        MOZ_ASSERT(pool_.numEntries() == 0);
+        MOZ_ASSERT_IF(!this->oom(), pool_.numEntries() == 0);
         return sizeExcludingCurrentPool();
     }
 
   private:
     void insertNopFill() {
         // Insert fill for testing.
         if (nopFill_ > 0 && !inhibitNops_ && !canNotPlacePool_) {
             inhibitNops_ = true;
@@ -766,17 +766,17 @@ struct AssemblerBufferWithConstantPools 
         MOZ_ASSERT(numDumps_ < poolInfoSize_);
         poolInfo_[numDumps_] = newPoolInfo;
         numDumps_++;
 
         // Bind the current pool to the perforation point, copying the pool
         // state into the BufferSlice.
         Pool** tmp = &perforatedSlice->pool;
         *tmp = static_cast<Pool*>(this->lifoAlloc_.alloc(sizeof(Pool)));
-        if (tmp == nullptr) {
+        if (!*tmp) {
             this->fail_oom();
             return;
         }
         mozilla::PodCopy(*tmp, &pool_, 1);
 
         // Reset everything to the state that it was in when we started.
         if (!pool_.reset(this->lifoAlloc_)) {
             this->fail_oom();
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -427,18 +427,20 @@ js::ReportErrorVA(JSContext* cx, unsigne
     size_t messagelen;
     JSErrorReport report;
     bool warning;
 
     if (checkReportFlags(cx, &flags))
         return true;
 
     message = JS_vsmprintf(format, ap);
-    if (!message)
+    if (!message) {
+        ReportOutOfMemory(cx);
         return false;
+    }
     messagelen = strlen(message);
 
     report.flags = flags;
     report.errorNumber = JSMSG_USER_DEFINED_ERROR;
     report.ucmessage = ucmessage = InflateString(cx, message, &messagelen);
     PopulateReportBlame(cx, &report);
 
     warning = JSREPORT_IS_WARNING(report.flags);
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3506,18 +3506,25 @@ js::DumpBacktrace(JSContext* cx)
 {
     Sprinter sprinter(cx);
     sprinter.init();
     size_t depth = 0;
     for (AllFramesIter i(cx); !i.done(); ++i, ++depth) {
         const char* filename = JS_GetScriptFilename(i.script());
         unsigned line = PCToLineNumber(i.script(), i.pc());
         JSScript* script = i.script();
-        sprinter.printf("#%d %14p   %s:%d (%p @ %d)\n",
-                        depth, (i.isJit() ? 0 : i.interpFrame()), filename, line,
+        char frameType =
+            i.isInterp() ? 'i' :
+            i.isBaseline() ? 'b' :
+            i.isIon() ? 'I' :
+            i.isAsmJS() ? 'A' :
+            '?';
+
+        sprinter.printf("#%d %14p %c   %s:%d (%p @ %d)\n",
+                        depth, i.rawFramePtr(), frameType, filename, line,
                         script, script->pcToOffset(i.pc()));
     }
     fprintf(stdout, "%s", sprinter.string());
 #ifdef XP_WIN32
     if (IsDebuggerPresent()) {
         OutputDebugStringA(sprinter.string());
     }
 #endif
--- a/js/src/jsprf.cpp
+++ b/js/src/jsprf.cpp
@@ -370,21 +370,21 @@ BuildArgArray(const char* fmt, va_list a
             continue;
         if ((c = *p++) == '%')          // skip %% case
             continue;
 
         while (c != 0) {
             if (c > '9' || c < '0') {
                 if (c == '$') {         // numbered argument case
                     if (i > 0)
-                        return false;
+                        MOZ_CRASH("Bad format string");
                     number++;
                 } else {                // non-numbered argument case
                     if (number > 0)
-                        return false;
+                        MOZ_CRASH("Bad format string");
                     i = 1;
                 }
                 break;
             }
 
             c = *p++;
         }
     }
@@ -412,41 +412,41 @@ BuildArgArray(const char* fmt, va_list a
 
         cn = 0;
         while (c && c != '$') {     // should improve error check later
             cn = cn*10 + c - '0';
             c = *p++;
         }
 
         if (!c || cn < 1 || cn > number)
-            return false;
+            MOZ_CRASH("Bad format string");
 
         // nas[cn] starts from 0, and make sure nas[cn].type is not assigned.
         cn--;
         if (nas[cn].type != TYPE_UNKNOWN)
             continue;
 
         c = *p++;
 
         // width
         if (c == '*') {
             // not supported feature, for the argument is not numbered
-            return false;
+            MOZ_CRASH("Bad format string");
         }
 
         while ((c >= '0') && (c <= '9')) {
             c = *p++;
         }
 
         // precision
         if (c == '.') {
             c = *p++;
             if (c == '*') {
                 // not supported feature, for the argument is not numbered
-                return false;
+                MOZ_CRASH("Bad format string");
             }
 
             while ((c >= '0') && (c <= '9')) {
                 c = *p++;
             }
         }
 
         // size
@@ -522,17 +522,17 @@ BuildArgArray(const char* fmt, va_list a
         default:
             MOZ_ASSERT(0);
             nas[cn].type = TYPE_UNKNOWN;
             break;
         }
 
         // get a legal para.
         if (nas[cn].type == TYPE_UNKNOWN)
-            return false;
+            MOZ_CRASH("Bad format string");
     }
 
 
     // Third pass:
     // Fill nas[].ap.
 
     cn = 0;
     while (cn < number) {
@@ -552,17 +552,17 @@ BuildArgArray(const char* fmt, va_list a
         case TYPE_UINT32:       (void) va_arg(ap, uint32_t);    break;
         case TYPE_INT64:        (void) va_arg(ap, int64_t);     break;
         case TYPE_UINT64:       (void) va_arg(ap, uint64_t);    break;
         case TYPE_STRING:       (void) va_arg(ap, char*);       break;
         case TYPE_WSTRING:      (void) va_arg(ap, char16_t*);   break;
         case TYPE_INTSTR:       (void) va_arg(ap, int*);        break;
         case TYPE_DOUBLE:       (void) va_arg(ap, double);      break;
 
-        default: return false;
+        default: MOZ_CRASH();
         }
 
         cn++;
     }
 
     return true;
 }
 
@@ -594,18 +594,17 @@ dosprintf(SprintfState* ss, const char* 
     const char* dolPt = nullptr;  // in "%4$.2f", dolPt will point to '.'
 
     // Build an argument array, IF the fmt is numbered argument
     // list style, to contain the Numbered Argument list pointers.
 
     NumArgStateVector nas;
     if (!BuildArgArray(fmt, ap, nas)) {
         // the fmt contains error Numbered Argument format, jliu@netscape.com
-        MOZ_ASSERT(0);
-        return false;
+        MOZ_CRASH("Bad format string");
     }
 
     while ((c = *fmt++) != 0) {
         if (c != '%') {
             if (!(*ss->stuff)(ss, fmt - 1, 1))
                 return false;
 
             continue;
@@ -628,17 +627,17 @@ dosprintf(SprintfState* ss, const char* 
             // the fmt contains the Numbered Arguments feature
             i = 0;
             while (c && c != '$') {         // should improve error check later
                 i = (i * 10) + (c - '0');
                 c = *fmt++;
             }
 
             if (nas[i - 1].type == TYPE_UNKNOWN)
-                return false;
+                MOZ_CRASH("Bad format string");
 
             ap = nas[i - 1].ap;
             dolPt = fmt;
             c = *fmt++;
         }
 
         // Examine optional flags.  Note that we do not implement the
         // '#' flag of sprintf().  The ANSI C spec. of the '#' flag is
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -399,26 +399,28 @@ js::StartOffThreadParseScript(JSContext*
 
     helpercx.forget();
 
     if (!task->init(cx, options))
         return false;
 
     if (OffThreadParsingMustWaitForGC(cx->runtime())) {
         AutoLockHelperThreadState lock;
-        if (!HelperThreadState().parseWaitingOnGC().append(task.get()))
+        if (!HelperThreadState().parseWaitingOnGC().append(task.get())) {
+            ReportOutOfMemory(cx);
             return false;
+        }
     } else {
-        task->activate(cx->runtime());
+        AutoLockHelperThreadState lock;
+        if (!HelperThreadState().parseWorklist().append(task.get())) {
+            ReportOutOfMemory(cx);
+            return false;
+        }
 
-        AutoLockHelperThreadState lock;
-
-        if (!HelperThreadState().parseWorklist().append(task.get()))
-            return false;
-
+        task->activate(cx->runtime());
         HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER);
     }
 
     task.forget();
 
     return true;
 }
 
@@ -1061,25 +1063,30 @@ GlobalHelperThreadState::finishParseTask
     // debugger about the compiled scripts.
     for (size_t i = 0; i < parseTask->errors.length(); i++)
         parseTask->errors[i]->throwError(cx);
     if (parseTask->overRecursed)
         ReportOverRecursed(cx);
     if (cx->isExceptionPending())
         return nullptr;
 
-    if (script) {
-        // The Debugger only needs to be told about the topmost script that was compiled.
-        Debugger::onNewScript(cx, script);
+    if (!script) {
+        // No error was reported, but no script produced. Assume we hit out of
+        // memory.
+        ReportOutOfMemory(cx);
+        return nullptr;
+    }
 
-        // Update the compressed source table with the result. This is normally
-        // called by setCompressedSource when compilation occurs on the main thread.
-        if (script->scriptSource()->hasCompressedSource())
-            script->scriptSource()->updateCompressedSourceSet(rt);
-    }
+    // The Debugger only needs to be told about the topmost script that was compiled.
+    Debugger::onNewScript(cx, script);
+
+    // Update the compressed source table with the result. This is normally
+    // called by setCompressedSource when compilation occurs on the main thread.
+    if (script->scriptSource()->hasCompressedSource())
+        script->scriptSource()->updateCompressedSourceSet(rt);
 
     return script;
 }
 
 JSObject*
 GlobalObject::getStarGeneratorFunctionPrototype()
 {
     const Value& v = getReservedSlot(STAR_GENERATOR_FUNCTION_PROTO);
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -1442,18 +1442,20 @@ ObjectGroup::allocationSiteGroup(JSConte
         PreliminaryObjectArrayWithTemplate* preliminaryObjects =
             cx->new_<PreliminaryObjectArrayWithTemplate>(nullptr);
         if (preliminaryObjects)
             res->setPreliminaryObjects(preliminaryObjects);
         else
             cx->recoverFromOutOfMemory();
     }
 
-    if (!table->add(p, key, res))
+    if (!table->add(p, key, res)) {
+        ReportOutOfMemory(cx);
         return nullptr;
+    }
 
     return res;
 }
 
 void
 ObjectGroupCompartment::replaceAllocationSiteGroup(JSScript* script, jsbytecode* pc,
                                                    JSProtoKey kind, ObjectGroup* group)
 {
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -848,16 +848,31 @@ AbstractFramePtr
 FrameIter::copyDataAsAbstractFramePtr() const
 {
     AbstractFramePtr frame;
     if (Data* data = copyData())
         frame.ptr_ = uintptr_t(data);
     return frame;
 }
 
+void*
+FrameIter::rawFramePtr() const
+{
+    switch (data_.state_) {
+      case DONE:
+      case ASMJS:
+        return nullptr;
+      case JIT:
+        return data_.jitFrames_.fp();
+      case INTERP:
+        return interpFrame();
+    }
+    MOZ_CRASH("Unexpected state");
+}
+
 JSCompartment*
 FrameIter::compartment() const
 {
     switch (data_.state_) {
       case DONE:
         break;
       case INTERP:
       case JIT:
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -2035,16 +2035,19 @@ class FrameIter
     Data* copyData() const;
 
     // This can only be called when isInterp():
     inline InterpreterFrame* interpFrame() const;
 
     // This can only be called when isPhysicalIonFrame():
     inline jit::CommonFrameLayout* physicalIonFrame() const;
 
+    // This is used to provide a raw interface for debugging.
+    void* rawFramePtr() const;
+
   private:
     Data data_;
     jit::InlineFrameIterator ionInlineFrames_;
 
     void popActivation();
     void popInterpreterFrame();
     void nextJitFrame();
     void popJitFrame();
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -1363,17 +1363,17 @@ class TypeConstraintFreezeStack : public
         return true;
     }
 };
 
 } /* anonymous namespace */
 
 bool
 js::FinishCompilation(JSContext* cx, HandleScript script, CompilerConstraintList* constraints,
-                      RecompileInfo* precompileInfo)
+                      RecompileInfo* precompileInfo, bool* isValidOut)
 {
     if (constraints->failed())
         return false;
 
     CompilerOutput co(script);
 
     TypeZone& types = cx->zone()->types;
     if (!types.compilerOutputs) {
@@ -1447,19 +1447,21 @@ js::FinishCompilation(JSContext* cx, Han
             if (!array[i].addConstraint(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeStack>(entry.script), false))
                 succeeded = false;
         }
     }
 
     if (!succeeded || types.compilerOutputs->back().pendingInvalidation()) {
         types.compilerOutputs->back().invalidate();
         script->resetWarmUpCounter();
-        return false;
+        *isValidOut = false;
+        return true;
     }
 
+    *isValidOut = true;
     return true;
 }
 
 void
 js::InvalidateCompilerOutputsForScript(JSContext* cx, HandleScript script)
 {
     TypeZone& types = cx->zone()->types;
     if (types.compilerOutputs) {
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -1059,21 +1059,21 @@ class TypeScript
 };
 
 void
 FillBytecodeTypeMap(JSScript* script, uint32_t* bytecodeMap);
 
 class RecompileInfo;
 
 // Allocate a CompilerOutput for a finished compilation and generate the type
-// constraints for the compilation. Returns whether the type constraints
-// still hold.
+// constraints for the compilation. Sets |isValidOut| based on whether the type
+// constraints still hold.
 bool
 FinishCompilation(JSContext* cx, HandleScript script, CompilerConstraintList* constraints,
-                  RecompileInfo* precompileInfo);
+                  RecompileInfo* precompileInfo, bool* isValidOut);
 
 // Reset any CompilerOutput present for a script.
 void
 InvalidateCompilerOutputsForScript(JSContext* cx, HandleScript script);
 
 // Update the actual types in any scripts queried by constraints with any
 // speculative types added during the definite properties analysis.
 void
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -619,16 +619,17 @@ nsDisplayListBuilder::nsDisplayListBuild
       mDirtyRect(-1,-1,-1,-1),
       mGlassDisplayItem(nullptr),
       mPendingScrollInfoItems(nullptr),
       mCommittedScrollInfoItems(nullptr),
       mMode(aMode),
       mCurrentScrollParentId(FrameMetrics::NULL_SCROLL_ID),
       mCurrentScrollbarTarget(FrameMetrics::NULL_SCROLL_ID),
       mCurrentScrollbarFlags(0),
+      mCurrentScrollbarWillHaveLayer(false),
       mBuildCaret(aBuildCaret),
       mIgnoreSuppression(false),
       mHadToIgnoreSuppression(false),
       mIsAtRootOfPseudoStackingContext(false),
       mIncludeAllOutOfFlows(false),
       mDescendIntoSubdocuments(true),
       mSelectedFramesOnly(false),
       mAccurateVisibleRegions(false),
@@ -3209,17 +3210,25 @@ nsDisplayLayerEventRegions::AddFrame(nsD
     }
   }
   if (borderBoxHasRoundedCorners ||
       (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
     mMaybeHitRegion.Or(mMaybeHitRegion, borderBox);
   } else {
     mHitRegion.Or(mHitRegion, borderBox);
   }
-  if (aBuilder->GetAncestorHasApzAwareEventHandler()) {
+
+  if (aBuilder->IsBuildingNonLayerizedScrollbar() ||
+      aBuilder->GetAncestorHasApzAwareEventHandler())
+  {
+    // Scrollbars may be painted into a layer below the actual layer they will
+    // scroll, and therefore wheel events may be dispatched to the outer frame
+    // instead of the intended scrollframe. To address this, we force a d-t-c
+    // region on scrollbar frames that won't be placed in their own layer. See
+    // bug 1213324 for details.
     mDispatchToContentHitRegion.Or(mDispatchToContentHitRegion, borderBox);
   } else if (aFrame->GetType() == nsGkAtoms::objectFrame) {
     // If the frame is a plugin frame and wants to handle wheel events as
     // default action, we should add the frame to dispatch-to-content region.
     nsPluginFrame* pluginFrame = do_QueryFrame(aFrame);
     if (pluginFrame && pluginFrame->WantsToHandleWheelEventAsDefaultAction()) {
       mDispatchToContentHitRegion.Or(mDispatchToContentHitRegion, borderBox);
     }
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -308,16 +308,24 @@ public:
    * which we are building display items at the moment.
    */
   void GetScrollbarInfo(ViewID* aOutScrollbarTarget, uint32_t* aOutScrollbarFlags)
   {
     *aOutScrollbarTarget = mCurrentScrollbarTarget;
     *aOutScrollbarFlags = mCurrentScrollbarFlags;
   }
   /**
+   * Returns true if building a scrollbar, and the scrollbar will not be
+   * layerized.
+   */
+  bool IsBuildingNonLayerizedScrollbar() const {
+    return mCurrentScrollbarTarget != FrameMetrics::NULL_SCROLL_ID &&
+           !mCurrentScrollbarWillHaveLayer;
+  }
+  /**
    * Calling this setter makes us include all out-of-flow descendant
    * frames in the display list, wherever they may be positioned (even
    * outside the dirty rects).
    */
   void SetIncludeAllOutOfFlows() { mIncludeAllOutOfFlows = true; }
   bool GetIncludeAllOutOfFlows() const { return mIncludeAllOutOfFlows; }
   /**
    * Calling this setter makes us exclude all leaf frames that aren't
@@ -748,25 +756,27 @@ public:
    * A helper class to temporarily set the value of mCurrentScrollbarTarget
    * and mCurrentScrollbarFlags.
    */
   class AutoCurrentScrollbarInfoSetter;
   friend class AutoCurrentScrollbarInfoSetter;
   class AutoCurrentScrollbarInfoSetter {
   public:
     AutoCurrentScrollbarInfoSetter(nsDisplayListBuilder* aBuilder, ViewID aScrollTargetID,
-                                   uint32_t aScrollbarFlags)
+                                   uint32_t aScrollbarFlags, bool aWillHaveLayer)
      : mBuilder(aBuilder) {
       aBuilder->mCurrentScrollbarTarget = aScrollTargetID;
       aBuilder->mCurrentScrollbarFlags = aScrollbarFlags;
+      aBuilder->mCurrentScrollbarWillHaveLayer = aWillHaveLayer;
     }
     ~AutoCurrentScrollbarInfoSetter() {
       // No need to restore old values because scrollbars cannot be nested.
       mBuilder->mCurrentScrollbarTarget = FrameMetrics::NULL_SCROLL_ID;
       mBuilder->mCurrentScrollbarFlags = 0;
+      mBuilder->mCurrentScrollbarWillHaveLayer = false;
     }
   private:
     nsDisplayListBuilder* mBuilder;
   };
 
   /**
    * A helper class to track current effective transform for items.
    *
@@ -1151,16 +1161,17 @@ private:
   nsDisplayList*                 mCommittedScrollInfoItems;
   nsTArray<DisplayItemClip*>     mDisplayItemClipsToDestroy;
   Mode                           mMode;
   ViewID                         mCurrentScrollParentId;
   ViewID                         mCurrentScrollbarTarget;
   uint32_t                       mCurrentScrollbarFlags;
   BlendModeSet                   mContainedBlendModes;
   Preserves3DContext             mPreserves3DCtx;
+  bool                           mCurrentScrollbarWillHaveLayer;
   bool                           mBuildCaret;
   bool                           mIgnoreSuppression;
   bool                           mHadToIgnoreSuppression;
   bool                           mIsAtRootOfPseudoStackingContext;
   bool                           mIncludeAllOutOfFlows;
   bool                           mDescendIntoSubdocuments;
   bool                           mSelectedFramesOnly;
   bool                           mAccurateVisibleRegions;
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -693,17 +693,17 @@ nsPresContext::GetDocumentColorPreferenc
   mBackgroundColor = NS_ComposeColors(NS_RGB(0xFF, 0xFF, 0xFF),
                                       mBackgroundColor);
 
 
   // Now deal with the pref:
   // 0 = default: always, except in high contrast mode
   // 1 = always
   // 2 = never
-  if (sDocumentColorsSetting == 1) {
+  if (sDocumentColorsSetting == 1 || mDocument->IsBeingUsedAsImage()) {
     mUseDocumentColors = true;
   } else if (sDocumentColorsSetting == 2) {
     mUseDocumentColors = isChromeDocShell || mIsChromeOriginImage;
   } else {
     MOZ_ASSERT(!useAccessibilityTheme ||
                !(isChromeDocShell || mIsChromeOriginImage),
                "The accessibility theme should only be on for non-chrome");
     mUseDocumentColors = !useAccessibilityTheme;
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -2694,27 +2694,30 @@ ScrollFrameHelper::AppendScrollPartsTo(n
 
     // The display port doesn't necessarily include the scrollbars, so just
     // include all of the scrollbars if we have a display port.
     nsRect dirty = aUsingDisplayPort ?
       scrollParts[i]->GetVisualOverflowRectRelativeToParent() : aDirtyRect;
     nsDisplayListBuilder::AutoBuildingDisplayList
       buildingForChild(aBuilder, scrollParts[i],
                        dirty + mOuter->GetOffsetTo(scrollParts[i]), true);
+
+    // Always create layers for overlay scrollbars so that we don't create a
+    // giant layer covering the whole scrollport if both scrollbars are visible.
+    bool isOverlayScrollbar = (flags != 0) && overlayScrollbars;
+    bool createLayer = aCreateLayer || isOverlayScrollbar;
+
     nsDisplayListBuilder::AutoCurrentScrollbarInfoSetter
-      infoSetter(aBuilder, scrollTargetId, flags);
+      infoSetter(aBuilder, scrollTargetId, flags, createLayer);
     nsDisplayListCollection partList;
     mOuter->BuildDisplayListForChild(
       aBuilder, scrollParts[i], dirty, partList,
       nsIFrame::DISPLAY_CHILD_FORCE_STACKING_CONTEXT);
 
-    // Always create layers for overlay scrollbars so that we don't create a
-    // giant layer covering the whole scrollport if both scrollbars are visible.
-    bool isOverlayScrollbar = (flags != 0) && overlayScrollbars;
-    if (aCreateLayer || isOverlayScrollbar) {
+    if (createLayer) {
       appendToTopFlags |= APPEND_OWN_LAYER;
     }
     if (aPositioned) {
       appendToTopFlags |= APPEND_POSITIONED;
     }
 
     // DISPLAY_CHILD_FORCE_STACKING_CONTEXT put everything into
     // partList.PositionedDescendants().
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -3842,17 +3842,18 @@ CSS_PROP_SVGRESET(
     VARIANT_HK,
     kDominantBaselineKTable,
     offsetof(nsStyleSVGReset, mDominantBaseline),
     eStyleAnimType_EnumU8)
 CSS_PROP_SVG(
     fill,
     fill,
     Fill,
-    CSS_PROPERTY_PARSE_FUNCTION,
+    CSS_PROPERTY_PARSE_FUNCTION |
+        CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED,
     "",
     0,
     kContextPatternKTable,
     offsetof(nsStyleSVG, mFill),
     eStyleAnimType_PaintServer)
 CSS_PROP_SVG(
     fill-opacity,
     fill_opacity,
@@ -4010,17 +4011,18 @@ CSS_PROP_SVGRESET(
     VARIANT_HN,
     nullptr,
     offsetof(nsStyleSVGReset, mStopOpacity),
     eStyleAnimType_float)
 CSS_PROP_SVG(
     stroke,
     stroke,
     Stroke,
-    CSS_PROPERTY_PARSE_FUNCTION,
+    CSS_PROPERTY_PARSE_FUNCTION |
+        CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED,
     "",
     0,
     kContextPatternKTable,
     offsetof(nsStyleSVG, mStroke),
     eStyleAnimType_PaintServer)
 CSS_PROP_SVG(
     stroke-dasharray,
     stroke_dasharray,
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -458,17 +458,19 @@ update-generated-wrappers:
 	$(MAKE) -C ../app
 	$(MAKE) -C ../themes/core
 	$(MAKE) -C ../installer stage-package
 	$(MKDIR) -p $(@D)
 	rsync --update $(DIST)/fennec/$(notdir $(OMNIJAR_NAME)) $@
 	$(RM) $(DIST)/fennec/$(notdir $(OMNIJAR_NAME))
 
 # Targets built very early during a Gradle build.
-gradle-targets: .aapt.deps
+gradle-targets: $(foreach f,$(constants_PP_JAVAFILES),$(f))
+gradle-targets: $(abspath AndroidManifest.xml)
+gradle-targets: $(ANDROID_GENERATED_RESFILES)
 
 gradle-omnijar: $(abspath $(DIST)/fennec/$(OMNIJAR_NAME))
 
 .PHONY: gradle-targets gradle-omnijar
 
 ifndef MOZ_DISABLE_GECKOVIEW
 libs:: geckoview_resources.zip
 	$(INSTALL) geckoview_resources.zip $(FINAL_TARGET)
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -812,16 +812,17 @@ if CONFIG['MOZ_INSTALL_TRACKING']:
 # Putting branding earlier allows branders to override default resources.
 ANDROID_RES_DIRS += [
     '/' + CONFIG['MOZ_BRANDING_DIRECTORY'] + '/res',
     'resources',
     '!res',
 ]
 
 ANDROID_GENERATED_RESFILES += [
+    'res/raw/browsersearch.json',
     'res/raw/suggestedsites.json',
     'res/values/strings.xml',
 ]
 
 ANDROID_ASSETS_DIRS += [
     '/mobile/android/app/assets',
 ]
 
deleted file mode 100644
--- a/mobile/android/base/resources/layout/tabs_panel_back_button.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-
-<org.mozilla.gecko.tabs.TabPanelBackButton xmlns:android="http://schemas.android.com/apk/res/android"
-                                           xmlns:gecko="http://schemas.android.com/apk/res-auto"
-                                           android:id="@+id/nav_back"
-                                           android:layout_width="@dimen/tabs_panel_button_width"
-                                           android:layout_height="match_parent"
-                                           android:minWidth="@dimen/tabs_panel_button_width"
-                                           android:src="@drawable/tabs_panel_nav_back"
-                                           android:contentDescription="@string/back"
-                                           android:background="@drawable/action_bar_button_inverse"
-                                           gecko:dividerVerticalPadding="@dimen/tab_panel_divider_vertical_padding"
-                                           gecko:rightDivider="@drawable/tab_indicator_divider"/>
-
--- a/mobile/android/base/resources/layout/tabs_panel_default.xml
+++ b/mobile/android/base/resources/layout/tabs_panel_default.xml
@@ -13,20 +13,26 @@
                     android:layout_width="match_parent"
                     android:layout_height="@dimen/browser_toolbar_height">
 
         <view class="org.mozilla.gecko.tabs.TabsPanel$TabsPanelToolbar"
               android:layout_width="match_parent"
               android:layout_height="@dimen/browser_toolbar_height"
               android:background="@color/text_and_tabs_tray_grey">
 
-            <ViewStub android:id="@+id/nav_back_stub"
-                      android:layout="@layout/tabs_panel_back_button"
-                      android:layout_width="wrap_content"
-                      android:layout_height="match_parent"/>
+            <org.mozilla.gecko.tabs.TabPanelBackButton
+                android:id="@+id/nav_back"
+                android:layout_width="@dimen/tabs_panel_button_width"
+                android:layout_height="match_parent"
+                android:minWidth="@dimen/tabs_panel_button_width"
+                android:src="@drawable/tabs_panel_nav_back"
+                android:contentDescription="@string/back"
+                android:background="@drawable/action_bar_button_inverse"
+                gecko:dividerVerticalPadding="@dimen/tab_panel_divider_vertical_padding"
+                gecko:rightDivider="@drawable/tab_indicator_divider"/>
 
             <org.mozilla.gecko.widget.IconTabWidget android:id="@+id/tab_widget"
                                                     android:layout_width="wrap_content"
                                                     android:layout_height="match_parent"
                                                     android:tabStripEnabled="false"
                                                     android:divider="@drawable/tab_indicator_divider"
                                                     android:dividerPadding="@dimen/tab_panel_divider_vertical_padding"
                                                     android:layout="@layout/tabs_panel_indicator"/>
--- a/mobile/android/base/tabs/TabsLayoutItemView.java
+++ b/mobile/android/base/tabs/TabsLayoutItemView.java
@@ -91,19 +91,17 @@ public class TabsLayoutItemView extends 
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
         mTitle = (TextView) findViewById(R.id.title);
         mThumbnail = (TabsPanelThumbnailView) findViewById(R.id.thumbnail);
         mCloseButton = (ImageView) findViewById(R.id.close);
         mThumbnailWrapper = (TabThumbnailWrapper) findViewById(R.id.wrapper);
 
-        if (HardwareUtils.isTablet() || AppConstants.NIGHTLY_BUILD) {
-            growCloseButtonHitArea();
-        }
+        growCloseButtonHitArea();
     }
 
     private void growCloseButtonHitArea() {
         getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
             @Override
             public boolean onPreDraw() {
                 getViewTreeObserver().removeOnPreDrawListener(this);
 
--- a/mobile/android/base/tabs/TabsPanel.java
+++ b/mobile/android/base/tabs/TabsPanel.java
@@ -159,26 +159,23 @@ public class TabsPanel extends LinearLay
         mMenuButton = findViewById(R.id.menu);
         mMenuButton.setOnClickListener(new Button.OnClickListener() {
             @Override
             public void onClick(View view) {
                 showMenu();
             }
         });
 
-        if (AppConstants.NIGHTLY_BUILD || HardwareUtils.isTablet()) {
-            ViewStub backButtonStub = (ViewStub) findViewById(R.id.nav_back_stub);
-            mNavBackButton = (ImageButton) backButtonStub.inflate( );
-            mNavBackButton.setOnClickListener(new Button.OnClickListener() {
-                @Override
-                public void onClick(View view) {
-                    mActivity.onBackPressed();
-                }
-            });
-        }
+        mNavBackButton = (ImageButton) findViewById(R.id.nav_back);
+        mNavBackButton.setOnClickListener(new Button.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                mActivity.onBackPressed();
+            }
+        });
     }
 
     public void showMenu() {
         final Menu menu = mPopupMenu.getMenu();
 
         // Each panel has a "+" shortcut button, so don't show it for that panel.
         menu.findItem(R.id.new_tab).setVisible(mCurrentPanel != Panel.NORMAL_TABS);
         menu.findItem(R.id.new_private_tab).setVisible(mCurrentPanel != Panel.PRIVATE_TABS
@@ -244,49 +241,22 @@ public class TabsPanel extends LinearLay
         if (itemId == R.id.new_tab || itemId == R.id.new_private_tab) {
             hide();
         }
 
         return mActivity.onOptionsItemSelected(item);
     }
 
     private static int getTabContainerHeight(TabsLayoutContainer tabsContainer) {
-        Resources resources = tabsContainer.getContext().getResources();
-
-        int screenHeight = resources.getDisplayMetrics().heightPixels;
-
-        int actionBarHeight = resources.getDimensionPixelSize(R.dimen.browser_toolbar_height);
-
-        if (HardwareUtils.isTablet() || AppConstants.NIGHTLY_BUILD) {
-            return screenHeight - actionBarHeight;
-        }
-
-        PanelView panelView = tabsContainer.getCurrentPanelView();
-        if (panelView != null && !panelView.shouldExpand()) {
+        final Resources resources = tabsContainer.getContext().getResources();
 
-            // This allows us to accommodate varying height tab previews across different devices.
-            // We should be able to remove once we remove the list view and remove the chrome again
-            return resources.getDimensionPixelSize(R.dimen.tab_thumbnail_height)
-                 + resources.getDimensionPixelSize(R.dimen.tab_title_height)
-                 + 2 * (resources.getDimensionPixelSize(R.dimen.tab_highlight_stroke_width)
-                      + resources.getDimensionPixelSize(R.dimen.tab_vertical_padding)
-                      + resources.getDimensionPixelSize(R.dimen.tab_thumbnail_padding)
-                      + resources.getDimensionPixelSize(R.dimen.tab_thumbnail_margin));
-        }
+        final int screenHeight = resources.getDisplayMetrics().heightPixels;
+        final int actionBarHeight = resources.getDimensionPixelSize(R.dimen.browser_toolbar_height);
 
-        Rect windowRect = new Rect();
-        tabsContainer.getWindowVisibleDisplayFrame(windowRect);
-        int windowHeight = windowRect.bottom - windowRect.top;
-
-        // The web content area should have at least 1.5x the height of the action bar.
-        // The tabs panel shouldn't take less than 50% of the screen height and can take
-        // up to 80% of the window height.
-        return (int) Math.max(screenHeight * 0.5f,
-                Math.min(windowHeight - 2.5f * actionBarHeight, windowHeight * 0.8f) - actionBarHeight);
-
+        return screenHeight - actionBarHeight;
     }
 
     @Override
     public void onAttachedToWindow() {
         super.onAttachedToWindow();
         mTheme.addListener(this);
     }
 
--- a/mobile/android/base/tabs/TabsPanelThumbnailView.java
+++ b/mobile/android/base/tabs/TabsPanelThumbnailView.java
@@ -1,16 +1,15 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.tabs;
 
-import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.ThumbnailHelper;
 import org.mozilla.gecko.widget.CropImageView;
 
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 
@@ -30,21 +29,17 @@ public class TabsPanelThumbnailView exte
     }
 
     public TabsPanelThumbnailView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
     }
 
     @Override
     protected float getAspectRatio() {
-        if (AppConstants.NIGHTLY_BUILD) {
-            return ThumbnailHelper.TABS_PANEL_THUMBNAIL_ASPECT_RATIO;
-        } else {
-            return ThumbnailHelper.TOP_SITES_THUMBNAIL_ASPECT_RATIO;
-        }
+        return ThumbnailHelper.TABS_PANEL_THUMBNAIL_ASPECT_RATIO;
     }
 
     @Override
     public void setImageDrawable(Drawable drawable) {
         boolean resize = true;
 
         if (drawable == null) {
             drawable = getResources().getDrawable(R.drawable.tab_panel_tab_background);
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -1313,16 +1313,17 @@ var BrowserApp = {
    * @param  aURL URL to look for
    * @param  aOptions Options for the search. Currently supports:
    **  @option startsWith a Boolean indicating whether to search for a tab who's url starts with the
    *           requested url. Useful if you want to ignore hash codes on the end of a url. For instance
    *           to have about:downloads match about:downloads#123.
    * @return the tab with the given URL, or null if no such tab exists
    */
   getTabWithURL: function getTabWithURL(aURL, aOptions) {
+    aOptions = aOptions || {};
     let uri = Services.io.newURI(aURL, null, null);
     for (let i = 0; i < this._tabs.length; ++i) {
       let tab = this._tabs[i];
       if (aOptions.startsWith) {
         if (tab.browser.currentURI.spec.startsWith(aURL)) {
           return tab;
         }
       } else {
--- a/mobile/android/gradle/app/build.gradle
+++ b/mobile/android/gradle/app/build.gradle
@@ -2,16 +2,19 @@ apply plugin: 'com.android.application'
 
 android {
     compileSdkVersion 23
     buildToolsVersion "23.0.1"
 
     defaultConfig {
         targetSdkVersion 22
         minSdkVersion 9
+        applicationId mozconfig.substs.ANDROID_PACKAGE_NAME
+        testApplicationId 'org.mozilla.roboexample.test'
+        testInstrumentationRunner 'org.mozilla.gecko.FennecInstrumentationTestRunner'
     }
 
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_1_7
         targetCompatibility JavaVersion.VERSION_1_7
     }
 
     lintOptions {
@@ -20,23 +23,23 @@ android {
 
     buildTypes {
         release {
             minifyEnabled true
             proguardFile "${topsrcdir}/mobile/android/config/proguard/proguard.cfg"
         }
     }
 
-    defaultConfig {
-        testApplicationId 'org.mozilla.roboexample.test'
-        testInstrumentationRunner 'org.mozilla.gecko.FennecInstrumentationTestRunner'
-    }
+    sourceSets {
+        main {
+            manifest.srcFile "${topobjdir}/mobile/android/base/AndroidManifest.xml"
+        }
 
-    sourceSets {
         androidTest {
+            manifest.srcFile "${topobjdir}/build/mobile/robocop/AndroidManifest.xml"
             java {
                 srcDir "src/robocop_harness"
                 srcDir "src/robocop"
                 srcDir "src/background"
                 srcDir "src/browser"
                 srcDir "src/javaaddons"
             }
         }
--- a/mobile/android/gradle/base/build.gradle
+++ b/mobile/android/gradle/base/build.gradle
@@ -41,21 +41,28 @@ android {
                 }
 
                 if (mozconfig.substs.MOZ_WEBRTC) {
                     srcDir 'src/webrtc_audio_device'
                     srcDir 'src/webrtc_video_capture'
                     srcDir 'src/webrtc_video_render'
                 }
 
-                // Adjust helpers are included in the preprocessed_code project.
-                exclude 'org/mozilla/gecko/adjust/**'
+                if (mozconfig.substs.MOZ_INSTALL_TRACKING) {
+                    exclude 'org/mozilla/gecko/adjust/StubAdjustHelper.java'
+                } else {
+                    exclude 'org/mozilla/gecko/adjust/AdjustHelper.java'
+                }
+
+                srcDir "${project.buildDir}/generated/source/preprocessed_code" // See syncPreprocessedCode.
             }
 
             res {
+                srcDir "src/branding/res"
+                srcDir "${project.buildDir}/generated/source/preprocessed_resources" // See syncPreprocessedResources.
                 if (mozconfig.substs.MOZ_CRASHREPORTER) {
                     srcDir "src/crashreporter/res"
                 }
             }
         }
 
         test {
             java {
@@ -64,33 +71,50 @@ android {
 
             resources {
                 srcDir "resources/background_junit4"
             }
         }
     }
 }
 
+
+task syncPreprocessedCode(type: Sync, dependsOn: rootProject.generateCodeAndResources) {
+    into("${project.buildDir}/generated/source/preprocessed_code")
+    from("${topobjdir}/mobile/android/base/generated/preprocessed")
+}
+
+task syncPreprocessedResources(type: Sync, dependsOn: rootProject.generateCodeAndResources) {
+    into("${project.buildDir}/generated/source/preprocessed_resources")
+    from("${topobjdir}/mobile/android/base/res")
+}
+
+android.libraryVariants.all { variant ->
+    variant.preBuild.dependsOn syncPreprocessedCode
+    variant.preBuild.dependsOn syncPreprocessedResources
+}
+
 dependencies {
     compile 'com.android.support:support-v4:23.0.1'
     compile 'com.android.support:appcompat-v7:23.0.1'
     compile 'com.android.support:recyclerview-v7:23.0.1'
 
     if (mozconfig.substs.MOZ_NATIVE_DEVICES) {
         compile 'com.android.support:mediarouter-v7:22.2.1'
         compile 'com.google.android.gms:play-services-basement:8.1.0'
         compile 'com.google.android.gms:play-services-base:8.1.0'
         compile 'com.google.android.gms:play-services-cast:8.1.0'
     }
 
-    compile project(':branding')
-    compile project(':preprocessed_code')
-    compile project(':preprocessed_resources')
     compile project(':thirdparty')
 
+    if (mozconfig.substs.MOZ_INSTALL_TRACKING) {
+        compile project(':thirdparty_adjust_sdk')
+    }
+
     testCompile 'junit:junit:4.12'
     testCompile 'org.robolectric:robolectric:3.0'
     testCompile 'org.simpleframework:simple-http:4.1.13'
 }
 
 apply plugin: 'idea'
 
 idea {
deleted file mode 100644
--- a/mobile/android/gradle/branding/AndroidManifest.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="org.mozilla.gecko.branding">
-
-</manifest>
deleted file mode 100644
--- a/mobile/android/gradle/branding/build.gradle
+++ /dev/null
@@ -1,20 +0,0 @@
-apply plugin: 'com.android.library'
-
-android {
-    compileSdkVersion 23
-    buildToolsVersion "23.0.1"
-
-    defaultConfig {
-        targetSdkVersion 22
-        minSdkVersion 9
-    }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
-    }
-
-    lintOptions {
-        abortOnError false
-    }
-}
--- a/mobile/android/gradle/build.gradle
+++ b/mobile/android/gradle/build.gradle
@@ -77,23 +77,26 @@ gradle.taskGraph.beforeTask {
 }
 
 afterEvaluate {
     subprojects {
         if (!hasProperty('android')) {
             return
         }
         android.applicationVariants.all {
-            checkManifest.dependsOn rootProject.generateCodeAndResources
+            preBuild.dependsOn rootProject.generateCodeAndResources
         }
         android.libraryVariants.all {
-            checkManifest.dependsOn rootProject.generateCodeAndResources
+            preBuild.dependsOn rootProject.generateCodeAndResources
         }
     }
 }
 
 apply plugin: 'idea'
 
 idea {
     project {
         languageLevel = '1.7'
     }
 }
+
+task wrapper(type: Wrapper) {
+}
index c97a8bdb9088d370da7e88784a7a093b971aa23a..e8c6bf7bb47dff6b81c2cf7a349eb7e912c9fbe2
GIT binary patch
literal 53638
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
b_+P^+@1?;Ze)}-s*ALRKR{B%tZ%6+Rs1GVa
--- a/mobile/android/gradle/gradle/wrapper/gradle-wrapper.properties
+++ b/mobile/android/gradle/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Sun Dec 21 20:16:49 PST 2014
+#Sun Oct 18 17:00:46 PDT 2015
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.7-bin.zip
--- a/mobile/android/gradle/gradlew
+++ b/mobile/android/gradle/gradlew
@@ -37,21 +37,16 @@ case "`uname`" in
   Darwin* )
     darwin=true
     ;;
   MINGW* )
     msys=true
     ;;
 esac
 
-# For Cygwin, ensure paths are in UNIX format before anything is touched.
-if $cygwin ; then
-    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
-fi
-
 # Attempt to set APP_HOME
 # Resolve links: $0 may be a link
 PRG="$0"
 # Need this for relative symlinks.
 while [ -h "$PRG" ] ; do
     ls=`ls -ld "$PRG"`
     link=`expr "$ls" : '.*-> \(.*\)$'`
     if expr "$link" : '/.*' > /dev/null; then
@@ -109,16 +104,17 @@ fi
 if $darwin; then
     GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
 fi
 
 # For Cygwin, switch paths to Windows format before running java
 if $cygwin ; then
     APP_HOME=`cygpath --path --mixed "$APP_HOME"`
     CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
 
     # We build the pattern for arguments to be converted via cygpath
     ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
     SEP=""
     for dir in $ROOTDIRSRAW ; do
         ROOTDIRS="$ROOTDIRS$SEP$dir"
         SEP="|"
     done
deleted file mode 100644
--- a/mobile/android/gradle/preprocessed_code/AndroidManifest.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="org.mozilla.gecko.preprocessed_code">
-
-</manifest>
deleted file mode 100644
--- a/mobile/android/gradle/preprocessed_code/build.gradle
+++ /dev/null
@@ -1,53 +0,0 @@
-apply plugin: 'com.android.library'
-
-android {
-    compileSdkVersion 23
-    buildToolsVersion "23.0.1"
-
-    defaultConfig {
-        targetSdkVersion 22
-        minSdkVersion 9
-    }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
-    }
-
-    lintOptions {
-        abortOnError false
-    }
-
-    sourceSets {
-        main {
-            java {
-                srcDir "${project.buildDir}/generated/source/java"
-
-                srcDir 'src/adjust/java'
-                if (mozconfig.substs.MOZ_INSTALL_TRACKING) {
-                    exclude 'org/mozilla/gecko/adjust/StubAdjustHelper.java'
-                } else {
-                    exclude 'org/mozilla/gecko/adjust/AdjustHelper.java'
-                }
-            }
-        }
-    }
-}
-
-task syncGeneratedSources(type: Sync) {
-    into("${project.buildDir}/generated/source/java")
-    from("${topobjdir}/mobile/android/base/generated/preprocessed")
-}
-
-android.libraryVariants.all { variant ->
-    // variant does not expose its generate sources task.
-    def name = variant.buildType.name
-    def generateSourcesTask = tasks.findByName("generate${name.capitalize()}Sources")
-    generateSourcesTask.dependsOn syncGeneratedSources
-}
-
-dependencies {
-    if (mozconfig.substs.MOZ_INSTALL_TRACKING) {
-        compile project(':thirdparty_adjust_sdk')
-    }
-}
deleted file mode 100644
--- a/mobile/android/gradle/preprocessed_resources/AndroidManifest.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="org.mozilla.gecko.preprocessed_resources">
-
-</manifest>
deleted file mode 100644
--- a/mobile/android/gradle/preprocessed_resources/build.gradle
+++ /dev/null
@@ -1,44 +0,0 @@
-apply plugin: 'com.android.library'
-
-android {
-    compileSdkVersion 23
-    buildToolsVersion "23.0.1"
-
-    defaultConfig {
-        targetSdkVersion 22
-        minSdkVersion 9
-    }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
-    }
-
-    lintOptions {
-        abortOnError false
-    }
-
-    sourceSets {
-        main {
-            res {
-                srcDir "${project.buildDir}/generated/source/preprocessed_resources"
-            }
-        }
-    }
-}
-
-task syncPreprocessedResources(type: Sync) {
-    into("${project.buildDir}/generated/source/preprocessed_resources")
-    from("${topobjdir}/mobile/android/base/res")
-}
-
-android.libraryVariants.all { variant ->
-    // variant does not expose its generate debug res values task.
-    def name = variant.buildType.name
-    def generateResValuesTask = tasks.findByName("generate${name.capitalize()}ResValues")
-    generateResValuesTask.dependsOn syncPreprocessedResources
-}
-
-dependencies {
-    compile project(':branding')
-}
--- a/mobile/android/gradle/settings.gradle
+++ b/mobile/android/gradle/settings.gradle
@@ -20,29 +20,23 @@ if (proc.exitValue() != 0) {
 }
 
 import groovy.json.JsonSlurper
 def slurper = new JsonSlurper()
 def json = slurper.parseText(standardOutput.toString())
 
 include ':app'
<