Merge inbound to central, a=merge
authorWes Kocher <wkocher@mozilla.com>
Tue, 26 May 2015 16:16:26 -0700
changeset 276470 ff2e0722804149cc85a6f4a26ae9983a10e4800c
parent 276396 1e4e369822ac4672bddebc2f78d0df00a7904217 (current diff)
parent 276469 ff31a31f9203b1e63ee6b735a59696b29a0e49d5 (diff)
child 276477 bf5bdca043c525b3e349c77d40836f94ad4c3b65
child 276525 eba8b4d8703aae0dec7ed28ea3e7a01d7d68f993
child 276596 b991cd5a0ad1bb6ebcbdd7e01b1d13140dceef18
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-beta@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone41.0a1
first release with
nightly linux32
ff2e07228041 / 41.0a1 / 20150527030204 / files
nightly linux64
ff2e07228041 / 41.0a1 / 20150527030204 / files
nightly mac
ff2e07228041 / 41.0a1 / 20150527030204 / files
nightly win32
ff2e07228041 / 41.0a1 / 20150527135446 / files
nightly win64
ff2e07228041 / 41.0a1 / 20150527030204 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to central, a=merge
--- a/accessible/jsat/AccessFu.jsm
+++ b/accessible/jsat/AccessFu.jsm
@@ -412,24 +412,16 @@ this.AccessFu = { // jshint ignore:line
     function(aJsonBounds, aBrowser, aToCSSPixels) {
       let bounds = new Rect(aJsonBounds.left, aJsonBounds.top,
                             aJsonBounds.right - aJsonBounds.left,
                             aJsonBounds.bottom - aJsonBounds.top);
       let win = Utils.win;
       let dpr = win.devicePixelRatio;
       let offset = { left: -win.mozInnerScreenX, top: -win.mozInnerScreenY };
 
-      if (!aBrowser.contentWindow) {
-        // OOP browser, add offset of browser.
-        // The offset of the browser element in relation to its parent window.
-        let clientRect = aBrowser.getBoundingClientRect();
-        let win = aBrowser.ownerDocument.defaultView;
-        offset.left += clientRect.left + win.mozInnerScreenX;
-        offset.top += clientRect.top + win.mozInnerScreenY;
-      }
       // Add the offset; the offset is in CSS pixels, so multiply the
       // devicePixelRatio back in before adding to preserve unit consistency.
       bounds = bounds.translate(offset.left * dpr, offset.top * dpr);
 
       // If we want to get to CSS pixels from device pixels, this needs to be
       // further divided by the devicePixelRatio due to widget scaling.
       if (aToCSSPixels) {
         bounds = bounds.scale(1 / dpr, 1 / dpr);
--- a/browser/base/content/test/general/test_contextmenu.html
+++ b/browser/base/content/test/general/test_contextmenu.html
@@ -352,18 +352,18 @@ function runTest(testNum) {
         closeContextMenu();
         openContextMenuFor(textarea); // Invoke context menu for next test
     },
 
     function () {
         // Context menu for textarea before spell check initialization finishes
         checkContextMenu(["context-undo",                false,
                           "---",                         null,
-                          "context-cut",                 false,
-                          "context-copy",                false,
+                          "context-cut",                 true,
+                          "context-copy",                true,
                           "context-paste",               null,
                           "context-delete",              false,
                           "---",                         null,
                           "context-selectall",           true,
                           "---",                         null,
                           "spell-add-dictionaries-main", true,
                          ].concat(inspectItems));
         closeContextMenu();
@@ -372,18 +372,18 @@ function runTest(testNum) {
 
     function () {
         // Context menu for textarea after spell check initialization finishes
         checkContextMenu(["*chubbiness",         true, // spelling suggestion
                           "spell-add-to-dictionary", true,
                           "---",                 null,
                           "context-undo",        false,
                           "---",                 null,
-                          "context-cut",         false,
-                          "context-copy",        false,
+                          "context-cut",         true,
+                          "context-copy",        true,
                           "context-paste",       null, // ignore clipboard state
                           "context-delete",      false,
                           "---",                 null,
                           "context-selectall",   true,
                           "---",                 null,
                           "spell-check-enabled", true,
                           "spell-dictionaries",  true,
                               ["spell-check-dictionary-en-US", true,
@@ -404,18 +404,18 @@ function runTest(testNum) {
 
     function () {
         // Context menu for textarea after a word has been added
         // to the dictionary
         checkContextMenu(["spell-undo-add-to-dictionary", true,
                           "---",                 null,
                           "context-undo",        false,
                           "---",                 null,
-                          "context-cut",         false,
-                          "context-copy",        false,
+                          "context-cut",         true,
+                          "context-copy",        true,
                           "context-paste",       null, // ignore clipboard state
                           "context-delete",      false,
                           "---",                 null,
                           "context-selectall",   true,
                           "---",                 null,
                           "spell-check-enabled", true,
                           "spell-dictionaries",  true,
                               ["spell-check-dictionary-en-US", true,
@@ -429,18 +429,18 @@ function runTest(testNum) {
 
     function () {
         // Context menu for contenteditable
         checkContextMenu(["spell-no-suggestions", false,
                           "spell-add-to-dictionary", true,
                           "---",                 null,
                           "context-undo",        false,
                           "---",                 null,
-                          "context-cut",         false,
-                          "context-copy",        false,
+                          "context-cut",         true,
+                          "context-copy",        true,
                           "context-paste",       null, // ignore clipboard state
                           "context-delete",      false,
                           "---",                 null,
                           "context-selectall",   true,
                           "---",                 null,
                           "spell-check-enabled", true,
                           "spell-dictionaries",  true,
                               ["spell-check-dictionary-en-US", true,
@@ -645,18 +645,18 @@ function runTest(testNum) {
         selectInputText(select_inputtext_password); // Select text prior to opening context menu.
         openContextMenuFor(select_inputtext_password); // Invoke context menu for next test.
     },
 
     function () {
         // Context menu for selected text in input[type="password"]
         checkContextMenu(["context-undo",        false,
                           "---",                 null,
-                          "context-cut",         false,
-                          "context-copy",        false,
+                          "context-cut",         true,
+                          "context-copy",        true,
                           "context-paste",       null, // ignore clipboard state
                           "context-delete",      true,
                           "---",                 null,
                           "context-selectall",   true,
                           "---",                 null,
                           "spell-check-enabled", true,
                           //spell checker is shown on input[type="password"] on this testcase
                           "spell-dictionaries",  true,
@@ -738,18 +738,18 @@ function runTest(testNum) {
         closeContextMenu();
         openContextMenuFor(inputspellfalse, false, true); // Invoke context menu for next test.
     },
 
     function () {
         // Context menu for text input field with spellcheck=false
         checkContextMenu(["context-undo",        false,
                           "---",                 null,
-                          "context-cut",         false,
-                          "context-copy",        false,
+                          "context-cut",         true,
+                          "context-copy",        true,
                           "context-paste",       null, // ignore clipboard state
                           "context-delete",      false,
                           "---",                 null,
                           "context-selectall",   true,
                           "---",                 null,
                           "spell-add-dictionaries-main",  true,
                          ].concat(inspectItems));
 
--- a/browser/base/content/test/general/test_contextmenu_input.html
+++ b/browser/base/content/test/general/test_contextmenu_input.html
@@ -35,18 +35,18 @@ function runTest(testNum) {
     case 1:
         openContextMenuFor(input); // Invoke context menu for next test.
         break;
 
     case 2:
         // Context menu for text input field.
         checkContextMenu(["context-undo",        false,
                           "---",                 null,
-                          "context-cut",         false,
-                          "context-copy",        false,
+                          "context-cut",         true,
+                          "context-copy",        true,
                           "context-paste",       null, // ignore clipboard state
                           "context-delete",      false,
                           "---",                 null,
                           "context-selectall",   false,
                           "---",                 null,
                           "spell-check-enabled", true,
                           "---",                 null,
                           "context-inspect",     true]);
@@ -56,18 +56,18 @@ function runTest(testNum) {
         openContextMenuFor(input, false, true);
         break;
 
     case 3:
         var value = false;
         // Context menu for spell-check input.
         checkContextMenu(["context-undo",        value,
                           "---",                 null,
-                          "context-cut",         value,
-                          "context-copy",        value,
+                          "context-cut",         true,
+                          "context-copy",        true,
                           "context-paste",       null, // ignore clipboard state
                           "context-delete",      value,
                           "---",                 null,
                           "context-selectall",   value,
                           "---",                 null,
                           "spell-check-enabled", true,
                           "spell-dictionaries",  true,
                               ["spell-check-dictionary-en-US", true,
@@ -85,18 +85,18 @@ function runTest(testNum) {
     case 4:
         var value = false;
         // Context menu for spell-check input with a unknwon word.
         checkContextMenu(["*prodigality",        true, // spelling suggestion
                           "spell-add-to-dictionary", true,
                           "---",                 null,
                           "context-undo",        value,
                           "---",                 null,
-                          "context-cut",         value,
-                          "context-copy",        value,
+                          "context-cut",         true,
+                          "context-copy",        true,
                           "context-paste",       null, // ignore clipboard state
                           "context-delete",      value,
                           "---",                 null,
                           "context-selectall",   true,
                           "---",                 null,
                           "spell-check-enabled", true,
                           "spell-dictionaries",  true,
                               ["spell-check-dictionary-en-US", true,
@@ -110,18 +110,18 @@ function runTest(testNum) {
         openContextMenuFor(inputspellcorrect, false, true);
         break;
 
     case 5:
         var value = false;
         // Context menu for spell-check input with a known word.
         checkContextMenu(["context-undo",        value,
                           "---",                 null,
-                          "context-cut",         value,
-                          "context-copy",        value,
+                          "context-cut",         true,
+                          "context-copy",        true,
                           "context-paste",       null, // ignore clipboard state
                           "context-delete",      value,
                           "---",                 null,
                           "context-selectall",   true,
                           "---",                 null,
                           "spell-check-enabled", true,
                           "spell-dictionaries",  true,
                               ["spell-check-dictionary-en-US", true,
@@ -134,55 +134,72 @@ function runTest(testNum) {
         input.disabled = true;
         openContextMenuFor(input); // Invoke context menu for next test.
         break;
 
     case 6:
         // Context menu for disabled input.
         checkContextMenu(["context-undo",        false,
                           "---",                 null,
-                          "context-cut",         false,
-                          "context-copy",        false,
+                          "context-cut",         true,
+                          "context-copy",        true,
                           "context-paste",       null, // ignore clipboard state
                           "context-delete",      false,
                           "---",                 null,
                           "context-selectall",   true,
                           "---",                 null,
                           "spell-check-enabled", true,
                           "---",                 null,
                           "context-inspect",     true]);
 
         closeContextMenu();
         input.disabled = false;
         input.type = 'password';
         openContextMenuFor(input); // Invoke context menu for next test.
         break;
 
     case 7: // password
-    case 8: // email
-    case 9: // url
-    case 10: // tel
-    case 11: // type='number'
-        // Context menu for tel, password, email, url and number input fields.
+        // Context menu for password input fields.
         checkContextMenu(["context-undo",        false,
                           "---",                 null,
-                          "context-cut",         false,
-                          "context-copy",        false,
+                          "context-cut",         true,
+                          "context-copy",        true,
                           "context-paste",       null, // ignore clipboard state
                           "context-delete",      false,
                           "---",                 null,
                           "context-selectall",   false,
                           "---",                 null,
                           "context-inspect",     true]);
 
         closeContextMenu();
 
-        if (testNum == 7) {
-          input.type = 'email';
-        } else if (testNum == 8) {
+        input.type = 'email';
+
+        openContextMenuFor(input); // Invoke context menu for next test.
+        break;
+
+    case 8: // email
+    case 9: // url
+    case 10: // tel
+    case 11: // type='number'
+        // Context menu for tel, email, url and number input fields.
+        checkContextMenu(["context-undo",        false,
+                          "---",                 null,
+                          "context-cut",         true,
+                          "context-copy",        true,
+                          "context-paste",       null, // ignore clipboard state
+                          "context-delete",      false,
+                          "---",                 null,
+                          "context-selectall",   false,
+                          "---",                 null,
+                          "context-inspect",     true]);
+
+        closeContextMenu();
+
+        if (testNum == 8) {
           input.type = 'url';
         } else if (testNum == 9) {
           input.type = 'tel';
         } else if (testNum == 10) {
           input.type = 'number';
         } else if (testNum == 11) {
           input.type = 'date';
         }
@@ -223,18 +240,18 @@ function runTest(testNum) {
 
         openContextMenuFor(input);
         break;
 
     case 16: // type='search'
         // Context menu for search input fields.
         checkContextMenu(["context-undo",        false,
                           "---",                 null,
-                          "context-cut",         false,
-                          "context-copy",        false,
+                          "context-cut",         true,
+                          "context-copy",        true,
                           "context-paste",       null, // ignore clipboard state
                           "context-delete",      false,
                           "---",                 null,
                           "context-selectall",   false,
                           "---",                 null,
                           "spell-check-enabled", true,
                           "---",                 null,
                           "context-inspect",     true]);
@@ -252,18 +269,18 @@ function runTest(testNum) {
         input.readOnly = true;
         openContextMenuFor(input);
         break;
 
     case 17:
         // Context menu for a read-only input.
         checkContextMenu(["context-undo",        false,
                           "---",                 null,
-                          "context-cut",         false,
-                          "context-copy",        false,
+                          "context-cut",         true,
+                          "context-copy",        true,
                           "context-paste",       null, // ignore clipboard state
                           "context-delete",      false,
                           "---",                 null,
                           "context-selectall",   false,
                           "---",                 null,
                           "context-inspect",     true]);
         closeContextMenu();
 
--- a/browser/components/customizableui/test/browser_947914_button_copy.js
+++ b/browser/components/customizableui/test/browser_947914_button_copy.js
@@ -14,26 +14,26 @@ add_task(function() {
 
   gURLBar.focus();
   info("The URL bar was focused");
   yield PanelUI.show();
   info("Menu panel was opened");
 
   let copyButton = document.getElementById("copy-button");
   ok(copyButton, "Copy button exists in Panel Menu");
-  is(copyButton.getAttribute("disabled"), "true", "Copy button is initially disabled");
+  ok(!copyButton.getAttribute("disabled"), "Copy button is initially enabled");
 
   // copy text from URL bar
   gURLBar.value = testText;
   gURLBar.focus();
   gURLBar.select();
   yield PanelUI.show();
   info("Menu panel was opened");
 
-  ok(!copyButton.hasAttribute("disabled"), "Copy button gets enabled");
+  ok(!copyButton.hasAttribute("disabled"), "Copy button is enabled when selecting");
 
   copyButton.click();
   is(gURLBar.value, testText, "Selected text is unaltered when clicking copy");
 
   // check that the text was added to the clipboard
   let clipboard = Services.clipboard;
   let transferable = Cc["@mozilla.org/widget/transferable;1"].createInstance(Ci.nsITransferable);
   globalClipboard = clipboard.kGlobalClipboard;
--- a/browser/components/customizableui/test/browser_947914_button_cut.js
+++ b/browser/components/customizableui/test/browser_947914_button_cut.js
@@ -13,26 +13,26 @@ add_task(function() {
   let testText = "cut text test";
 
   gURLBar.focus();
   yield PanelUI.show();
   info("Menu panel was opened");
 
   let cutButton = document.getElementById("cut-button");
   ok(cutButton, "Cut button exists in Panel Menu");
-  ok(cutButton.getAttribute("disabled"), "Cut button is disabled");
+  ok(!cutButton.hasAttribute("disabled"), "Cut button is enabled");
 
   // cut text from URL bar
   gURLBar.value = testText;
   gURLBar.focus();
   gURLBar.select();
   yield PanelUI.show();
   info("Menu panel was opened");
 
-  ok(!cutButton.hasAttribute("disabled"), "Cut button gets enabled");
+  ok(!cutButton.hasAttribute("disabled"), "Cut button is enabled when selecting");
   cutButton.click();
   is(gURLBar.value, "", "Selected text is removed from source when clicking on cut");
 
   // check that the text was added to the clipboard
   let clipboard = Services.clipboard;
   let transferable = Cc["@mozilla.org/widget/transferable;1"].createInstance(Ci.nsITransferable);
   globalClipboard = clipboard.kGlobalClipboard;
 
--- a/browser/devtools/scratchpad/test/browser_scratchpad_edit_ui_updates.js
+++ b/browser/devtools/scratchpad/test/browser_scratchpad_edit_ui_updates.js
@@ -114,17 +114,17 @@ function runTests()
         }
       } else {
         menuPopup.hidePopup();
       }
     });
   };
 
   let firstShow = function() {
-    ok(cutItem.hasAttribute("disabled"), "cut menuitem is disabled");
+    ok(!cutItem.hasAttribute("disabled"), "cut menuitem is enabled");
     closeMenu(firstHide);
   };
 
   let firstHide = function() {
     sp.editor.setSelection({ line: 0, ch: 0 }, { line: 0, ch: 10 });
     openMenu(11, 11, showAfterSelect);
   };
 
@@ -144,17 +144,17 @@ function runTests()
   };
 
   let onCut = function() {
     sp.editor.off("change", onCut);
     openMenu(12, 12, showAfterCut);
   };
 
   let showAfterCut = function() {
-    ok(cutItem.hasAttribute("disabled"), "cut menuitem is disabled after cut");
+    ok(!cutItem.hasAttribute("disabled"), "cut menuitem is enabled after cut");
     ok(!pasteItem.hasAttribute("disabled"), "paste menuitem is enabled after cut");
     closeMenu(hideAfterCut);
   };
 
   let hideAfterCut = function() {
     waitForFocus(function () {
       sp.editor.on("change", onPaste);
       EventUtils.synthesizeKey("v", {accelKey: true}, gScratchpadWindow);
@@ -162,17 +162,17 @@ function runTests()
   };
 
   let onPaste = function() {
     sp.editor.off("change", onPaste);
     openMenu(13, 13, showAfterPaste);
   };
 
   let showAfterPaste = function() {
-    ok(cutItem.hasAttribute("disabled"), "cut menuitem is disabled after paste");
+    ok(!cutItem.hasAttribute("disabled"), "cut menuitem is enabled after paste");
     ok(!pasteItem.hasAttribute("disabled"), "paste menuitem is enabled after paste");
     closeMenu(hideAfterPaste);
   };
 
   let hideAfterPaste = function() {
     if (pass == 0) {
       pass++;
       testContextMenu();
--- a/build/unix/elfhack/inject/moz.build
+++ b/build/unix/elfhack/inject/moz.build
@@ -12,13 +12,11 @@ elif CONFIG['TARGET_CPU'].startswith('ar
     cpu = 'arm'
 else:
     cpu = CONFIG['TARGET_CPU']
 
 GENERATED_SOURCES += [
     "%s.c" % cpu,
 ]
 
-DEFINES['ELFHACK_BUILD'] = True
-
 NO_PGO = True
 
 NO_VISIBILITY_FLAGS = True
--- a/build/unix/elfhack/moz.build
+++ b/build/unix/elfhack/moz.build
@@ -20,11 +20,9 @@ if not CONFIG['CROSS_COMPILE']:
 
 HOST_SOURCES += [
     'elf.cpp',
     'elfhack.cpp',
 ]
 
 HostProgram('elfhack')
 
-DEFINES['ELFHACK_BUILD'] = True
-
 NO_PGO = True
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -6625,16 +6625,24 @@ nsContentUtils::IsRequestFullScreenAllow
 {
   return !sTrustedFullScreenOnly ||
          EventStateManager::IsHandlingUserInput() ||
          IsCallerChrome();
 }
 
 /* static */
 bool
+nsContentUtils::IsCutCopyAllowed()
+{
+  return EventStateManager::IsHandlingUserInput() ||
+         IsCallerChrome();
+}
+
+/* static */
+bool
 nsContentUtils::HaveEqualPrincipals(nsIDocument* aDoc1, nsIDocument* aDoc2)
 {
   if (!aDoc1 || !aDoc2) {
     return false;
   }
   bool principalsEqual = false;
   aDoc1->NodePrincipal()->Equals(aDoc2->NodePrincipal(), &principalsEqual);
   return principalsEqual;
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -1858,16 +1858,23 @@ public:
   /**
    * Returns true if requests for full-screen are allowed in the current
    * context. Requests are only allowed if the user initiated them (like with
    * a mouse-click or key press), unless this check has been disabled by
    * setting the pref "full-screen-api.allow-trusted-requests-only" to false.
    */
   static bool IsRequestFullScreenAllowed();
 
+  /**
+   * Returns true if calling execCommand with 'cut' or 'copy' arguments is
+   * allowed in the current context. These are only allowed if the user initiated
+   * them (like with a mouse-click or key press).
+   */
+  static bool IsCutCopyAllowed();
+
   /*
    * Returns true if the performance timing APIs are enabled.
    */
   static bool IsPerformanceTimingEnabled()
   {
     return sIsPerformanceTimingEnabled;
   }
   
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1147,20 +1147,22 @@ nsDOMClassInfo::PostCreatePrototype(JSCo
   nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
   NS_ENSURE_TRUE(nameSpaceManager, NS_OK);
 
   JS::Rooted<JSPropertyDescriptor> desc(cx);
   nsresult rv = ResolvePrototype(sXPConnect, win, cx, global, mData->mNameUTF16,
                                  mData, nullptr, nameSpaceManager, proto,
                                  &desc);
   NS_ENSURE_SUCCESS(rv, rv);
-  if (!contentDefinedProperty && desc.object() && !desc.value().isUndefined() &&
-      !JS_DefineUCProperty(cx, global, mData->mNameUTF16,
-                           NS_strlen(mData->mNameUTF16), desc)) {
-    return NS_ERROR_UNEXPECTED;
+  if (!contentDefinedProperty && desc.object() && !desc.value().isUndefined()) {
+    desc.attributesRef() |= JSPROP_RESOLVING;
+    if (!JS_DefineUCProperty(cx, global, mData->mNameUTF16,
+                             NS_strlen(mData->mNameUTF16), desc)) {
+      return NS_ERROR_UNEXPECTED;
+    }
   }
 
   return NS_OK;
 }
 
 // static
 nsIClassInfo *
 NS_GetDOMClassInfoInstance(nsDOMClassInfoID aID)
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -2116,16 +2116,19 @@ GK_ATOM(x_symbol, "x-symbol")
 // additional languages that have special case transformations
 GK_ATOM(az, "az")
 GK_ATOM(ba, "ba")
 GK_ATOM(crh, "crh")
 GK_ATOM(el, "el")
 GK_ATOM(ga, "ga")
 GK_ATOM(nl, "nl")
 
+// mathematical language, used for MathML
+GK_ATOM(x_math, "x-math")
+
 // Names for editor transactions
 GK_ATOM(TypingTxnName, "Typing")
 GK_ATOM(IMETxnName, "IME")
 GK_ATOM(DeleteTxnName, "Deleting")
 
 // IPC stuff
 GK_ATOM(Remote, "remote")
 GK_ATOM(RemoteId, "_remote_id")
--- a/dom/base/nsPerformance.h
+++ b/dom/base/nsPerformance.h
@@ -418,17 +418,17 @@ public:
 private:
   ~nsPerformance();
 
   nsISupports* GetAsISupports() override
   {
     return this;
   }
 
-  void InsertUserEntry(PerformanceEntry* aEntry);
+  void InsertUserEntry(PerformanceEntry* aEntry) override;
 
   bool IsPerformanceTimingAttribute(const nsAString& aName) override;
 
   DOMHighResTimeStamp
   DeltaFromNavigationStart(DOMHighResTimeStamp aTime) override;
 
   DOMHighResTimeStamp
   GetPerformanceTimingFromString(const nsAString& aTimingName) override;
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -545,17 +545,17 @@ DefineConstructor(JSContext* cx, JS::Han
 {
   bool alreadyDefined;
   if (!JS_AlreadyHasOwnProperty(cx, global, name, &alreadyDefined)) {
     return false;
   }
 
   // This is Enumerable: False per spec.
   return alreadyDefined ||
-         JS_DefineProperty(cx, global, name, constructor, 0);
+         JS_DefineProperty(cx, global, name, constructor, JSPROP_RESOLVING);
 }
 
 static JSObject*
 CreateInterfaceObject(JSContext* cx, JS::Handle<JSObject*> global,
                       JS::Handle<JSObject*> constructorProto,
                       const js::Class* constructorClass,
                       const JSNativeHolder* constructorNative,
                       unsigned ctorNargs, const NamedConstructor* namedConstructors,
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -7798,19 +7798,21 @@ class CGResolveHook(CGAbstractClassHook)
               return false;
             }
             if (!desc.object()) {
               return true;
             }
             // If desc.value() is undefined, then the DoResolve call
             // has already defined it on the object.  Don't try to also
             // define it.
-            if (!desc.value().isUndefined() &&
-                !JS_DefinePropertyById(cx, obj, id, desc)) {
-              return false;
+            if (!desc.value().isUndefined()) {
+              desc.attributesRef() |= JSPROP_RESOLVING;
+              if (!JS_DefinePropertyById(cx, obj, id, desc)) {
+                return false;
+              }
             }
             *resolvedp = true;
             return true;
             """)
 
     def definition_body(self):
         if self.descriptor.isGlobal():
             # Resolve standard classes
--- a/dom/crypto/CryptoKey.cpp
+++ b/dom/crypto/CryptoKey.cpp
@@ -58,16 +58,39 @@ StringToUsage(const nsString& aUsage, Cr
   } else if (aUsage.EqualsLiteral(WEBCRYPTO_KEY_USAGE_UNWRAPKEY)) {
     aUsageOut = CryptoKey::UNWRAPKEY;
   } else {
     return NS_ERROR_DOM_SYNTAX_ERR;
   }
   return NS_OK;
 }
 
+SECKEYPrivateKey*
+PrivateKeyFromPrivateKeyTemplate(SECItem* aObjID,
+                                 CK_ATTRIBUTE* aTemplate,
+                                 CK_ULONG aTemplateSize)
+{
+  // Create a generic object with the contents of the key
+  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+  if (!slot) {
+    return nullptr;
+  }
+
+  ScopedPK11GenericObject obj(PK11_CreateGenericObject(slot,
+                                                       aTemplate,
+                                                       aTemplateSize,
+                                                       PR_FALSE));
+  if (!obj) {
+    return nullptr;
+  }
+
+  // Have NSS translate the object to a private key.
+  return PK11_FindKeyByKeyID(slot, aObjID, nullptr);
+}
+
 CryptoKey::CryptoKey(nsIGlobalObject* aGlobal)
   : mGlobal(aGlobal)
   , mAttributes(0)
   , mSymKey()
   , mPrivateKey(nullptr)
   , mPublicKey(nullptr)
 {
 }
@@ -218,16 +241,83 @@ void
 CryptoKey::SetExtractable(bool aExtractable)
 {
   mAttributes &= CLEAR_EXTRACTABLE;
   if (aExtractable) {
     mAttributes |= EXTRACTABLE;
   }
 }
 
+// NSS exports private EC keys without the CKA_EC_POINT attribute, i.e. the
+// public value. To properly export the private key to JWK or PKCS #8 we need
+// the public key data though and so we use this method to augment a private
+// key with data from the given public key.
+nsresult
+CryptoKey::AddPublicKeyData(SECKEYPublicKey* aPublicKey)
+{
+  // This should be a private key.
+  MOZ_ASSERT(GetKeyType() == PRIVATE);
+  // There should be a private NSS key with type 'EC'.
+  MOZ_ASSERT(mPrivateKey && mPrivateKey->keyType == ecKey);
+  // The given public key should have the same key type.
+  MOZ_ASSERT(aPublicKey->keyType == mPrivateKey->keyType);
+
+  nsNSSShutDownPreventionLock locker;
+
+  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+  if (!slot) {
+    return NS_ERROR_DOM_OPERATION_ERR;
+  }
+
+  // Generate a random 160-bit object ID.
+  ScopedSECItem objID(::SECITEM_AllocItem(nullptr, nullptr, 20));
+  SECStatus rv = PK11_GenerateRandomOnSlot(slot, objID->data, objID->len);
+  if (rv != SECSuccess) {
+    return NS_ERROR_DOM_OPERATION_ERR;
+  }
+
+  // Read EC params.
+  ScopedSECItem params(::SECITEM_AllocItem(nullptr, nullptr, 0));
+  rv = PK11_ReadRawAttribute(PK11_TypePrivKey, mPrivateKey, CKA_EC_PARAMS,
+                             params);
+  if (rv != SECSuccess) {
+    return NS_ERROR_DOM_OPERATION_ERR;
+  }
+
+  // Read private value.
+  ScopedSECItem value(::SECITEM_AllocItem(nullptr, nullptr, 0));
+  rv = PK11_ReadRawAttribute(PK11_TypePrivKey, mPrivateKey, CKA_VALUE, value);
+  if (rv != SECSuccess) {
+    return NS_ERROR_DOM_OPERATION_ERR;
+  }
+
+  SECItem* point = &aPublicKey->u.ec.publicValue;
+  CK_OBJECT_CLASS privateKeyValue = CKO_PRIVATE_KEY;
+  CK_BBOOL falseValue = CK_FALSE;
+  CK_KEY_TYPE ecValue = CKK_EC;
+
+  CK_ATTRIBUTE keyTemplate[9] = {
+    { CKA_CLASS,            &privateKeyValue,     sizeof(privateKeyValue) },
+    { CKA_KEY_TYPE,         &ecValue,             sizeof(ecValue) },
+    { CKA_TOKEN,            &falseValue,          sizeof(falseValue) },
+    { CKA_SENSITIVE,        &falseValue,          sizeof(falseValue) },
+    { CKA_PRIVATE,          &falseValue,          sizeof(falseValue) },
+    { CKA_ID,               objID->data,          objID->len },
+    { CKA_EC_PARAMS,        params->data,         params->len },
+    { CKA_EC_POINT,         point->data,          point->len },
+    { CKA_VALUE,            value->data,          value->len },
+  };
+
+  mPrivateKey = PrivateKeyFromPrivateKeyTemplate(objID, keyTemplate,
+                                                 PR_ARRAY_SIZE(keyTemplate));
+  NS_ENSURE_TRUE(mPrivateKey, NS_ERROR_DOM_OPERATION_ERR);
+
+  return NS_OK;
+}
+
 void
 CryptoKey::ClearUsages()
 {
   mAttributes &= CLEAR_USAGES;
 }
 
 nsresult
 CryptoKey::AddUsage(const nsString& aUsage)
@@ -362,16 +452,19 @@ void CryptoKey::destructorSafeDestroyNSS
 // Serialization and deserialization convenience methods
 
 SECKEYPrivateKey*
 CryptoKey::PrivateKeyFromPkcs8(CryptoBuffer& aKeyData,
                          const nsNSSShutDownPreventionLock& /*proofOfLock*/)
 {
   SECKEYPrivateKey* privKey;
   ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+  if (!slot) {
+    return nullptr;
+  }
 
   ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
   if (!arena) {
     return nullptr;
   }
 
   SECItem pkcs8Item = { siBuffer, nullptr, 0 };
   if (!aKeyData.ToSECItem(arena, &pkcs8Item)) {
@@ -578,46 +671,16 @@ CreateECPointForCoordinates(const Crypto
   point->data[0] = EC_POINT_FORM_UNCOMPRESSED;
   memcpy(point->data + 1, aX.Elements(), aX.Length());
   memcpy(point->data + 1 + aX.Length(), aY.Elements(), aY.Length());
 
   return point;
 }
 
 SECKEYPrivateKey*
-PrivateKeyFromPrivateKeyTemplate(SECItem* aObjID,
-                                 CK_ATTRIBUTE* aTemplate,
-                                 CK_ULONG aTemplateSize)
-{
-  // Create a generic object with the contents of the key
-  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
-  if (!slot.get()) {
-    return nullptr;
-  }
-
-  ScopedPK11GenericObject obj(PK11_CreateGenericObject(slot.get(),
-                                                       aTemplate,
-                                                       aTemplateSize,
-                                                       PR_FALSE));
-  if (!obj.get()) {
-    return nullptr;
-  }
-
-  // Have NSS translate the object to a private key by inspection
-  // and make a copy we can own
-  ScopedSECKEYPrivateKey privKey(PK11_FindKeyByKeyID(slot.get(), aObjID,
-                                                     nullptr));
-  if (!privKey.get()) {
-    return nullptr;
-  }
-
-  return SECKEY_CopyPrivateKey(privKey.get());
-}
-
-SECKEYPrivateKey*
 CryptoKey::PrivateKeyFromJwk(const JsonWebKey& aJwk,
                              const nsNSSShutDownPreventionLock& /*proofOfLock*/)
 {
   CK_OBJECT_CLASS privateKeyValue = CKO_PRIVATE_KEY;
   CK_BBOOL falseValue = CK_FALSE;
 
   if (aJwk.mKty.EqualsLiteral(JWK_TYPE_EC)) {
     // Verify that all of the required parameters are present
@@ -1084,21 +1147,25 @@ CryptoKey::WriteStructuredClone(JSStruct
   // 1. Attributes
   // 2. Symmetric key as raw (if present)
   // 3. Private key as pkcs8 (if present)
   // 4. Public key as spki (if present)
   // 5. Algorithm in whatever form it chooses
   CryptoBuffer priv, pub;
 
   if (mPrivateKey) {
-    CryptoKey::PrivateKeyToPkcs8(mPrivateKey, priv, locker);
+    if (NS_FAILED(CryptoKey::PrivateKeyToPkcs8(mPrivateKey, priv, locker))) {
+      return false;
+    }
   }
 
   if (mPublicKey) {
-    CryptoKey::PublicKeyToSpki(mPublicKey, pub, locker);
+    if (NS_FAILED(CryptoKey::PublicKeyToSpki(mPublicKey, pub, locker))) {
+      return false;
+    }
   }
 
   return JS_WriteUint32Pair(aWriter, mAttributes, CRYPTOKEY_SC_VERSION) &&
          WriteBuffer(aWriter, mSymKey) &&
          WriteBuffer(aWriter, priv) &&
          WriteBuffer(aWriter, pub) &&
          mAlgorithm.WriteStructuredClone(aWriter);
 }
--- a/dom/crypto/CryptoKey.h
+++ b/dom/crypto/CryptoKey.h
@@ -111,16 +111,17 @@ public:
   // them to manipulate the object
 
   KeyAlgorithmProxy& Algorithm();
   const KeyAlgorithmProxy& Algorithm() const;
   KeyType GetKeyType() const;
   nsresult SetType(const nsString& aType);
   void SetType(KeyType aType);
   void SetExtractable(bool aExtractable);
+  nsresult AddPublicKeyData(SECKEYPublicKey* point);
   void ClearUsages();
   nsresult AddUsage(const nsString& aUsage);
   nsresult AddUsageIntersecting(const nsString& aUsage, uint32_t aUsageMask);
   void AddUsage(KeyUsage aUsage);
   bool HasAnyUsage();
   bool HasUsage(KeyUsage aUsage);
   bool HasUsageOtherThan(uint32_t aUsages);
   static bool IsRecognizedUsage(const nsString& aUsage);
@@ -150,29 +151,29 @@ public:
   static SECKEYPrivateKey* PrivateKeyFromPkcs8(CryptoBuffer& aKeyData,
                                                const nsNSSShutDownPreventionLock& /*proofOfLock*/);
   static nsresult PrivateKeyToPkcs8(SECKEYPrivateKey* aPrivKey,
                                     CryptoBuffer& aRetVal,
                                     const nsNSSShutDownPreventionLock& /*proofOfLock*/);
 
   static SECKEYPublicKey* PublicKeyFromSpki(CryptoBuffer& aKeyData,
                                             const nsNSSShutDownPreventionLock& /*proofOfLock*/);
-  static nsresult PublicKeyToSpki(SECKEYPublicKey* aPrivKey,
+  static nsresult PublicKeyToSpki(SECKEYPublicKey* aPubKey,
                                   CryptoBuffer& aRetVal,
                                   const nsNSSShutDownPreventionLock& /*proofOfLock*/);
 
   static SECKEYPrivateKey* PrivateKeyFromJwk(const JsonWebKey& aJwk,
                                              const nsNSSShutDownPreventionLock& /*proofOfLock*/);
   static nsresult PrivateKeyToJwk(SECKEYPrivateKey* aPrivKey,
                                   JsonWebKey& aRetVal,
                                   const nsNSSShutDownPreventionLock& /*proofOfLock*/);
 
   static SECKEYPublicKey* PublicKeyFromJwk(const JsonWebKey& aKeyData,
                                            const nsNSSShutDownPreventionLock& /*proofOfLock*/);
-  static nsresult PublicKeyToJwk(SECKEYPublicKey* aPrivKey,
+  static nsresult PublicKeyToJwk(SECKEYPublicKey* aPubKey,
                                  JsonWebKey& aRetVal,
                                  const nsNSSShutDownPreventionLock& /*proofOfLock*/);
 
   static SECKEYPublicKey* PublicDhKeyFromRaw(CryptoBuffer& aKeyData,
                                              const CryptoBuffer& aPrime,
                                              const CryptoBuffer& aGenerator,
                                              const nsNSSShutDownPreventionLock& /*proofOfLock*/);
   static nsresult PublicDhKeyToRaw(SECKEYPublicKey* aPubKey,
--- a/dom/crypto/WebCryptoTask.cpp
+++ b/dom/crypto/WebCryptoTask.cpp
@@ -1908,19 +1908,23 @@ private:
 
       return NS_OK;
     } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8)) {
       if (!mPrivateKey) {
         return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
       }
 
       switch (mPrivateKey->keyType) {
-        case rsaKey:
-          CryptoKey::PrivateKeyToPkcs8(mPrivateKey.get(), mResult, locker);
+        case rsaKey: {
+          nsresult rv = CryptoKey::PrivateKeyToPkcs8(mPrivateKey.get(), mResult, locker);
+          if (NS_FAILED(rv)) {
+            return NS_ERROR_DOM_OPERATION_ERR;
+          }
           return NS_OK;
+        }
         default:
           return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
       }
     } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) {
       if (!mPublicKey) {
         return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
       }
 
@@ -2322,16 +2326,24 @@ private:
                                        PR_FALSE, PR_FALSE, nullptr);
     mPublicKey = pubKey;
     if (!mPrivateKey.get() || !mPublicKey.get()) {
       return NS_ERROR_DOM_UNKNOWN_ERR;
     }
 
     mKeyPair.mPrivateKey.get()->SetPrivateKey(mPrivateKey);
     mKeyPair.mPublicKey.get()->SetPublicKey(mPublicKey);
+
+    // PK11_GenerateKeyPair() does not set a CKA_EC_POINT attribute on the
+    // private key, we need this later when exporting to PKCS8 and JWK though.
+    if (mMechanism == CKM_EC_KEY_PAIR_GEN) {
+      nsresult rv = mKeyPair.mPrivateKey->AddPublicKeyData(mPublicKey);
+      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
+    }
+
     return NS_OK;
   }
 
   virtual void Resolve() override
   {
     mResultPromise->MaybeResolve(mKeyPair);
   }
 };
--- a/dom/crypto/test/test_WebCrypto_ECDH.html
+++ b/dom/crypto/test/test_WebCrypto_ECDH.html
@@ -295,16 +295,47 @@ TestArray.addTest(
       .then(error(that), doTryImport(tvs.jwk_missing_x))
       .then(error(that), doTryImport(tvs.jwk_missing_y))
       .then(error(that), complete(that));
   }
 );
 
 // -----------------------------------------------------------------------------
 TestArray.addTest(
+  "JWK export of a newly generated ECDH private key",
+  function () {
+    var that = this;
+    var alg = { name: "ECDH", namedCurve: "P-256" };
+    var reBase64URL = /^[a-zA-Z0-9_-]+$/;
+
+    function doExportToJWK(x) {
+      return crypto.subtle.exportKey("jwk", x.privateKey)
+    }
+
+    crypto.subtle.generateKey(alg, true, ["deriveKey", "deriveBits"])
+      .then(doExportToJWK)
+      .then(
+        complete(that, function(x) {
+          return x.ext &&
+                 x.kty == 'EC' &&
+                 x.crv == 'P-256' &&
+                 reBase64URL.test(x.x) &&
+                 reBase64URL.test(x.y) &&
+                 reBase64URL.test(x.d) &&
+                 x.x.length == 43 && // 32 octets, base64-encoded
+                 x.y.length == 43 && // 32 octets, base64-encoded
+                 shallowArrayEquals(x.key_ops, ['deriveKey', 'deriveBits']);
+          }),
+        error(that)
+      );
+  }
+);
+
+// -----------------------------------------------------------------------------
+TestArray.addTest(
   "Derive an HMAC key from two ECDH keys and test sign/verify",
   function() {
     var that = this;
     var alg = { name: "ECDH" };
     var algDerived = { name: "HMAC", hash: {name: "SHA-1"} };
 
     var pubKey, privKey;
     function setPub(x) { pubKey = x; }
--- a/dom/crypto/test/test_WebCrypto_RSA_OAEP.html
+++ b/dom/crypto/test/test_WebCrypto_RSA_OAEP.html
@@ -17,16 +17,19 @@
 <script src="./test-vectors.js"></script>
 
 <!-- General testing framework -->
 <script src="./test-array.js"></script>
 
 <script>/*<![CDATA[*/
 "use strict";
 
+// Generating 2048-bit keys takes some time.
+SimpleTest.requestLongerTimeout(2);
+
 // -----------------------------------------------------------------------------
 TestArray.addTest(
   "RSA-OAEP encrypt/decrypt round-trip",
   function () {
     var that = this;
     var privKey, pubKey;
     var alg = {name: "RSA-OAEP", hash: "SHA-1"};
 
--- a/dom/crypto/test/test_WebCrypto_Reject_Generating_Keys_Without_Usages.html
+++ b/dom/crypto/test/test_WebCrypto_Reject_Generating_Keys_Without_Usages.html
@@ -17,16 +17,19 @@
 <script src="./test-vectors.js"></script>
 
 <!-- General testing framework -->
 <script src="./test-array.js"></script>
 
 <script>/*<![CDATA[*/
 "use strict";
 
+// Generating 2048-bit keys takes some time.
+SimpleTest.requestLongerTimeout(2);
+
 TestArray.addTest(
   "Test that we reject generating keys without any usage",
   function() {
     var that = this;
     var alg = {
       name: "RSA-OAEP",
       hash: "SHA-256",
       modulusLength: 2048,
--- a/dom/events/IMEContentObserver.cpp
+++ b/dom/events/IMEContentObserver.cpp
@@ -38,17 +38,18 @@ namespace mozilla {
 
 using namespace widget;
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(IMEContentObserver)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IMEContentObserver)
   nsAutoScriptBlocker scriptBlocker;
 
-  tmp->UnregisterObservers(true);
+  tmp->NotifyIMEOfBlur();
+  tmp->UnregisterObservers();
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mWidget)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSelection)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mRootContent)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mEditableNode)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mEditor)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mEndOfAddedTextCache.mContainerNode)
@@ -81,16 +82,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(IMEContentObserver)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(IMEContentObserver)
 
 IMEContentObserver::IMEContentObserver()
   : mESM(nullptr)
   , mPreCharacterDataChangeLength(-1)
+  , mIsObserving(false)
   , mIsSelectionChangeEventPending(false)
   , mSelectionChangeCausedOnlyByComposition(false)
   , mIsPositionChangeEventPending(false)
   , mIsFlushingPendingNotifications(false)
 {
 #ifdef DEBUG
   TestMergingTextChangeData();
 #endif
@@ -99,27 +101,45 @@ IMEContentObserver::IMEContentObserver()
 void
 IMEContentObserver::Init(nsIWidget* aWidget,
                          nsPresContext* aPresContext,
                          nsIContent* aContent,
                          nsIEditor* aEditor)
 {
   MOZ_ASSERT(aEditor, "aEditor must not be null");
 
+  State state = GetState();
+  if (NS_WARN_IF(state == eState_Observing)) {
+    return; // Nothing to do.
+  }
+
+  bool firstInitialization = state != eState_StoppedObserving;
+  if (!firstInitialization) {
+    // If this is now trying to initialize with new contents, all observers
+    // should be registered again for simpler implementation.
+    UnregisterObservers();
+    // Clear members which may not be initialized again.
+    mRootContent = nullptr;
+    mEditor = nullptr;
+    mSelection = nullptr;
+    mDocShell = nullptr;
+  }
+
   mESM = aPresContext->EventStateManager();
   mESM->OnStartToObserveContent(this);
 
   mWidget = aWidget;
-  mEditableNode = IMEStateManager::GetRootEditableNode(aPresContext, aContent);
+
+  mEditableNode =
+    IMEStateManager::GetRootEditableNode(aPresContext, aContent);
   if (!mEditableNode) {
     return;
   }
 
   mEditor = aEditor;
-  mEditor->AddEditorObserver(this);
 
   nsIPresShell* presShell = aPresContext->PresShell();
 
   // get selection and root content
   nsCOMPtr<nsISelectionController> selCon;
   if (mEditableNode->IsNodeOfType(nsINode::eCONTENT)) {
     nsIFrame* frame =
       static_cast<nsIContent*>(mEditableNode.get())->GetPrimaryFrame();
@@ -149,41 +169,50 @@ IMEContentObserver::Init(nsIWidget* aWid
   }
   if (!mRootContent && mEditableNode->IsNodeOfType(nsINode::eDOCUMENT)) {
     // The document node is editable, but there are no contents, this document
     // is not editable.
     return;
   }
   NS_ENSURE_TRUE_VOID(mRootContent);
 
-  if (IMEStateManager::IsTestingIME()) {
-    nsIDocument* doc = aPresContext->Document();
-    (new AsyncEventDispatcher(doc, NS_LITERAL_STRING("MozIMEFocusIn"),
-                              false, false))->RunDOMEventWhenSafe();
-  }
+  if (firstInitialization) {
+    aWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_FOCUS));
 
-  aWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_FOCUS));
+    // While Init() notifies IME of focus, pending layout may be flushed
+    // because the notification may cause querying content.  Then, recursive
+    // call of Init() with the latest content may be occur.  In such case, we
+    // shouldn't keep first initialization.
+    if (GetState() != eState_Initializing) {
+      return;
+    }
 
-  // NOTIFY_IME_OF_FOCUS might cause recreating IMEContentObserver
-  // instance via IMEStateManager::UpdateIMEState().  So, this
-  // instance might already have been destroyed, check it.
-  if (!mRootContent) {
-    return;
+    // NOTIFY_IME_OF_FOCUS might cause recreating IMEContentObserver
+    // instance via IMEStateManager::UpdateIMEState().  So, this
+    // instance might already have been destroyed, check it.
+    if (!mRootContent) {
+      return;
+    }
   }
 
   mDocShell = aPresContext->GetDocShell();
 
   ObserveEditableNode();
 }
 
 void
 IMEContentObserver::ObserveEditableNode()
 {
-  MOZ_ASSERT(mSelection);
-  MOZ_ASSERT(mRootContent);
+  MOZ_RELEASE_ASSERT(mEditor);
+  MOZ_RELEASE_ASSERT(mSelection);
+  MOZ_RELEASE_ASSERT(mRootContent);
+  MOZ_RELEASE_ASSERT(GetState() != eState_Observing);
+
+  mIsObserving = true;
+  mEditor->AddEditorObserver(this);
 
   mUpdatePreference = mWidget->GetIMEUpdatePreference();
   if (mUpdatePreference.WantSelectionChange()) {
     // add selection change listener
     nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(mSelection));
     NS_ENSURE_TRUE_VOID(selPrivate);
     nsresult rv = selPrivate->AddSelectionListener(this);
     NS_ENSURE_SUCCESS_VOID(rv);
@@ -198,42 +227,40 @@ IMEContentObserver::ObserveEditableNode(
     // Add scroll position listener and reflow observer to detect position and
     // size changes
     mDocShell->AddWeakScrollObserver(this);
     mDocShell->AddWeakReflowObserver(this);
   }
 }
 
 void
-IMEContentObserver::UnregisterObservers(bool aPostEvent)
+IMEContentObserver::NotifyIMEOfBlur()
 {
-  if (mEditor) {
-    mEditor->RemoveEditorObserver(this);
+  // If this failed to initialize, mRootContent may be null, then, we
+  // should not call NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR))
+  if (!mRootContent || !mWidget) {
+    return;
   }
 
-  // If CreateTextStateManager failed, mRootContent will be null, then, we
-  // should not call NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR))
-  if (mRootContent && mWidget) {
-    if (IMEStateManager::IsTestingIME() && mEditableNode) {
-      nsIDocument* doc = mEditableNode->OwnerDoc();
-      if (doc) {
-        nsRefPtr<AsyncEventDispatcher> dispatcher =
-          new AsyncEventDispatcher(doc, NS_LITERAL_STRING("MozIMEFocusOut"),
-                                   false, false);
-        if (aPostEvent) {
-          dispatcher->PostDOMEvent();
-        } else {
-          dispatcher->RunDOMEventWhenSafe();
-        }
-      }
-    }
-    // A test event handler might destroy the widget.
-    if (mWidget) {
-      mWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR));
-    }
+  // A test event handler might destroy the widget.
+  if (mWidget) {
+    mWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR));
+  }
+}
+
+void
+IMEContentObserver::UnregisterObservers()
+{
+  if (!mIsObserving) {
+    return;
+  }
+  mIsObserving = false;
+
+  if (mEditor) {
+    mEditor->RemoveEditorObserver(this);
   }
 
   if (mUpdatePreference.WantSelectionChange() && mSelection) {
     nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(mSelection));
     if (selPrivate) {
       selPrivate->RemoveSelectionListener(this);
     }
   }
@@ -254,17 +281,18 @@ IMEContentObserver::GetPresContext() con
   return mESM ? mESM->GetPresContext() : nullptr;
 }
 
 void
 IMEContentObserver::Destroy()
 {
   // WARNING: When you change this method, you have to check Unlink() too.
 
-  UnregisterObservers(false);
+  NotifyIMEOfBlur();
+  UnregisterObservers();
 
   mEditor = nullptr;
   // Even if there are some pending notification, it'll never notify the widget.
   mWidget = nullptr;
   mSelection = nullptr;
   mRootContent = nullptr;
   mEditableNode = nullptr;
   mDocShell = nullptr;
@@ -278,25 +306,56 @@ IMEContentObserver::Destroy()
 
 void
 IMEContentObserver::DisconnectFromEventStateManager()
 {
   mESM = nullptr;
 }
 
 bool
+IMEContentObserver::MaybeReinitialize(nsIWidget* aWidget,
+                                      nsPresContext* aPresContext,
+                                      nsIContent* aContent,
+                                      nsIEditor* aEditor)
+{
+  if (!IsObservingContent(aPresContext, aContent)) {
+    return false;
+  }
+
+  if (GetState() == eState_StoppedObserving) {
+    Init(aWidget, aPresContext, aContent, aEditor);
+  }
+  return IsManaging(aPresContext, aContent);
+}
+
+bool
 IMEContentObserver::IsManaging(nsPresContext* aPresContext,
                                nsIContent* aContent)
 {
+  return GetState() == eState_Observing &&
+         IsObservingContent(aPresContext, aContent);
+}
+
+IMEContentObserver::State
+IMEContentObserver::GetState() const
+{
   if (!mSelection || !mRootContent || !mEditableNode) {
-    return false; // failed to initialize.
+    return eState_NotObserving; // failed to initialize or finalized.
   }
   if (!mRootContent->IsInComposedDoc()) {
-    return false; // the focused editor has already been reframed.
+    // the focused editor has already been reframed.
+    return eState_StoppedObserving;
   }
+  return mIsObserving ? eState_Observing : eState_Initializing;
+}
+
+bool
+IMEContentObserver::IsObservingContent(nsPresContext* aPresContext,
+                                       nsIContent* aContent) const
+{
   return mEditableNode == IMEStateManager::GetRootEditableNode(aPresContext,
                                                                aContent);
 }
 
 bool
 IMEContentObserver::IsEditorHandlingEventForComposition() const
 {
   if (!mWidget) {
--- a/dom/events/IMEContentObserver.h
+++ b/dom/events/IMEContentObserver.h
@@ -67,16 +67,27 @@ public:
             nsIContent* aContent, nsIEditor* aEditor);
   void Destroy();
   /**
    * IMEContentObserver is stored by EventStateManager during observing.
    * DisconnectFromEventStateManager() is called when EventStateManager stops
    * storing the instance.
    */
   void DisconnectFromEventStateManager();
+  /**
+   * MaybeReinitialize() tries to restart to observe the editor's root node.
+   * This is useful when the editor is reframed and all children are replaced
+   * with new node instances.
+   * @return            Returns true if the instance is managing the content.
+   *                    Otherwise, false.
+   */
+  bool MaybeReinitialize(nsIWidget* aWidget,
+                         nsPresContext* aPresContext,
+                         nsIContent* aContent,
+                         nsIEditor* aEditor);
   bool IsManaging(nsPresContext* aPresContext, nsIContent* aContent);
   bool IsEditorHandlingEventForComposition() const;
   bool KeepAliveDuringDeactive() const
   {
     return mUpdatePreference.WantDuringDeactive();
   }
   nsIWidget* GetWidget() const { return mWidget; }
   nsPresContext* GetPresContext() const;
@@ -128,28 +139,39 @@ public:
     {
       return mAddedEndOffset - mRemovedEndOffset;
     }
   };
 
 private:
   ~IMEContentObserver() {}
 
+  enum State {
+    eState_NotObserving,
+    eState_Initializing,
+    eState_StoppedObserving,
+    eState_Observing
+  };
+  State GetState() const;
+  bool IsObservingContent(nsPresContext* aPresContext,
+                          nsIContent* aContent) const;
   void MaybeNotifyIMEOfTextChange(const TextChangeData& aTextChangeData);
   void MaybeNotifyIMEOfSelectionChange(bool aCausedByComposition);
   void MaybeNotifyIMEOfPositionChange();
 
   void NotifyContentAdded(nsINode* aContainer, int32_t aStart, int32_t aEnd);
   void ObserveEditableNode();
   /**
-   *  UnregisterObservers() unresiters all listeners and observers.
-   *  @param aPostEvent     When true, DOM event will be posted to the thread.
-   *                        Otherwise, dispatched when safe.
+   *  NotifyIMEOfBlur() notifies IME of blur.
    */
-  void UnregisterObservers(bool aPostEvent);
+  void NotifyIMEOfBlur();
+  /**
+   *  UnregisterObservers() unregisters all listeners and observers.
+   */
+  void UnregisterObservers();
   void StoreTextChangeData(const TextChangeData& aTextChangeData);
   void FlushMergeableNotifications();
 
 #ifdef DEBUG
   void TestMergingTextChangeData();
 #endif
 
   nsCOMPtr<nsIWidget> mWidget;
@@ -216,16 +238,17 @@ private:
   TextChangeData mTextChangeData;
 
   EventStateManager* mESM;
 
   nsIMEUpdatePreference mUpdatePreference;
   uint32_t mPreAttrChangeLength;
   int64_t mPreCharacterDataChangeLength;
 
+  bool mIsObserving;
   bool mIsSelectionChangeEventPending;
   bool mSelectionChangeCausedOnlyByComposition;
   bool mIsPositionChangeEventPending;
   bool mIsFlushingPendingNotifications;
 };
 
 } // namespace mozilla
 
--- a/dom/events/IMEStateManager.cpp
+++ b/dom/events/IMEStateManager.cpp
@@ -175,17 +175,16 @@ GetNotifyIMEMessageName(IMEMessage aMess
     default:
       return "unacceptable IME notification message";
   }
 }
 
 nsIContent* IMEStateManager::sContent = nullptr;
 nsPresContext* IMEStateManager::sPresContext = nullptr;
 bool IMEStateManager::sInstalledMenuKeyboardListener = false;
-bool IMEStateManager::sIsTestingIME = false;
 bool IMEStateManager::sIsGettingNewIMEState = false;
 
 // sActiveIMEContentObserver points to the currently active IMEContentObserver.
 // sActiveIMEContentObserver is null if there is no focused editor.
 IMEContentObserver* IMEStateManager::sActiveIMEContentObserver = nullptr;
 TextCompositionArray* IMEStateManager::sTextCompositions = nullptr;
 
 // static
@@ -644,19 +643,33 @@ IMEStateManager::UpdateIMEState(const IM
   nsCOMPtr<nsIWidget> widget = sPresContext->GetRootWidget();
   if (NS_WARN_IF(!widget)) {
     MOZ_LOG(sISMLog, PR_LOG_ERROR,
       ("ISM:   IMEStateManager::UpdateIMEState(), FAILED due to "
        "no widget for the managing nsPresContext"));
     return;
   }
 
-  // If the IMEContentObserver instance isn't managing the editor's current
-  // editable root content, the editor frame might be reframed.  We should
-  // recreate the instance at that time.
+  // Even if there is active IMEContentObserver, it may not be observing the
+  // editor with current editable root content due to reframed.  In such case,
+  // We should try to reinitialize the IMEContentObserver.
+  if (sActiveIMEContentObserver && IsIMEObserverNeeded(aNewIMEState)) {
+    PR_LOG(sISMLog, PR_LOG_DEBUG,
+      ("ISM:   IMEStateManager::UpdateIMEState(), try to reinitialize the "
+       "active IMEContentObserver"));
+    if (!sActiveIMEContentObserver->MaybeReinitialize(widget, sPresContext,
+                                                      aContent, aEditor)) {
+      PR_LOG(sISMLog, PR_LOG_ERROR,
+        ("ISM:   IMEStateManager::UpdateIMEState(), failed to reinitialize the "
+         "active IMEContentObserver"));
+    }
+  }
+
+  // If there is no active IMEContentObserver or it isn't observing the
+  // editor correctly, we should recreate it.
   bool createTextStateManager =
     (!sActiveIMEContentObserver ||
      !sActiveIMEContentObserver->IsManaging(sPresContext, aContent));
 
   bool updateIMEState =
     (widget->GetInputContext().mIMEState.mEnabled != aNewIMEState.mEnabled);
 
   if (updateIMEState) {
@@ -1123,28 +1136,19 @@ IMEStateManager::GetRootEditableNode(nsP
       return document;
     }
   }
   return nullptr;
 }
 
 // static
 bool
-IMEStateManager::IsEditableIMEState(nsIWidget* aWidget)
+IMEStateManager::IsIMEObserverNeeded(const IMEState& aState)
 {
-  switch (aWidget->GetInputContext().mIMEState.mEnabled) {
-    case IMEState::ENABLED:
-    case IMEState::PASSWORD:
-      return true;
-    case IMEState::PLUGIN:
-    case IMEState::DISABLED:
-      return false;
-    default:
-      MOZ_CRASH("Unknown IME enable state");
-  }
+  return aState.IsEditable();
 }
 
 // static
 void
 IMEStateManager::DestroyIMEContentObserver()
 {
   MOZ_LOG(sISMLog, PR_LOG_ALWAYS,
     ("ISM: IMEStateManager::DestroyIMEContentObserver(), "
@@ -1188,30 +1192,24 @@ IMEStateManager::CreateIMEContentObserve
   nsCOMPtr<nsIWidget> widget = sPresContext->GetRootWidget();
   if (!widget) {
     MOZ_LOG(sISMLog, PR_LOG_ERROR,
       ("ISM:   IMEStateManager::CreateIMEContentObserver(), FAILED due to "
        "there is a root widget for the nsPresContext"));
     return; // Sometimes, there are no widgets.
   }
 
-  // If it's not text ediable, we don't need to create IMEContentObserver.
-  if (!IsEditableIMEState(widget)) {
+  // If it's not text editable, we don't need to create IMEContentObserver.
+  if (!IsIMEObserverNeeded(widget->GetInputContext().mIMEState)) {
     MOZ_LOG(sISMLog, PR_LOG_DEBUG,
       ("ISM:   IMEStateManager::CreateIMEContentObserver() doesn't create "
        "IMEContentObserver because of non-editable IME state"));
     return;
   }
 
-  static bool sInitializeIsTestingIME = true;
-  if (sInitializeIsTestingIME) {
-    Preferences::AddBoolVarCache(&sIsTestingIME, "test.IME", false);
-    sInitializeIsTestingIME = false;
-  }
-
   MOZ_LOG(sISMLog, PR_LOG_DEBUG,
     ("ISM:   IMEStateManager::CreateIMEContentObserver() is creating an "
      "IMEContentObserver instance..."));
   sActiveIMEContentObserver = new IMEContentObserver();
   NS_ADDREF(sActiveIMEContentObserver);
 
   // IMEContentObserver::Init() might create another IMEContentObserver
   // instance.  So, sActiveIMEContentObserver would be replaced with new one.
--- a/dom/events/IMEStateManager.h
+++ b/dom/events/IMEStateManager.h
@@ -133,17 +133,16 @@ public:
    * Send a notification to IME.  It depends on the IME or platform spec what
    * will occur (or not occur).
    */
   static nsresult NotifyIME(IMEMessage aMessage, nsIWidget* aWidget);
   static nsresult NotifyIME(IMEMessage aMessage, nsPresContext* aPresContext);
 
   static nsINode* GetRootEditableNode(nsPresContext* aPresContext,
                                       nsIContent* aContent);
-  static bool IsTestingIME() { return sIsTestingIME; }
 
 protected:
   static nsresult OnChangeFocusInternal(nsPresContext* aPresContext,
                                         nsIContent* aContent,
                                         InputContextAction aAction);
   static void SetIMEState(const IMEState &aState,
                           nsIContent* aContent,
                           nsIWidget* aWidget,
@@ -152,22 +151,21 @@ protected:
                                  nsIContent* aContent);
 
   static void EnsureTextCompositionArray();
   static void CreateIMEContentObserver(nsIEditor* aEditor);
   static void DestroyIMEContentObserver();
 
   static bool IsEditable(nsINode* node);
 
-  static bool IsEditableIMEState(nsIWidget* aWidget);
+  static bool IsIMEObserverNeeded(const IMEState& aState);
 
   static nsIContent*    sContent;
   static nsPresContext* sPresContext;
   static bool           sInstalledMenuKeyboardListener;
-  static bool           sIsTestingIME;
   static bool           sIsGettingNewIMEState;
 
   class MOZ_STACK_CLASS GettingNewIMEStateBlocker final
   {
   public:
     GettingNewIMEStateBlocker()
       : mOldValue(IMEStateManager::sIsGettingNewIMEState)
     {
--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -219,33 +219,44 @@ FetchRequest(nsIGlobalObject* aGlobal, c
 
   aRv = UpdateRequestReferrer(aGlobal, r);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   if (NS_IsMainThread()) {
     nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal);
-    if (!window) {
-      aRv.Throw(NS_ERROR_FAILURE);
-      return nullptr;
-    }
-
-    nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
-    if (!doc) {
-      aRv.Throw(NS_ERROR_FAILURE);
-      return nullptr;
+    nsCOMPtr<nsIDocument> doc;
+    nsCOMPtr<nsILoadGroup> loadGroup;
+    nsIPrincipal* principal;
+    if (window) {
+      doc = window->GetExtantDoc();
+      if (!doc) {
+        aRv.Throw(NS_ERROR_FAILURE);
+        return nullptr;
+      }
+      principal = doc->NodePrincipal();
+      loadGroup = doc->GetDocumentLoadGroup();
+    } else {
+      principal = aGlobal->PrincipalOrNull();
+      if (NS_WARN_IF(!principal)) {
+        aRv.Throw(NS_ERROR_FAILURE);
+        return nullptr;
+      }
+      nsresult rv = NS_NewLoadGroup(getter_AddRefs(loadGroup), principal);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        aRv.Throw(rv);
+        return nullptr;
+      }
     }
 
     Telemetry::Accumulate(Telemetry::FETCH_IS_MAINTHREAD, 1);
 
     nsRefPtr<MainThreadFetchResolver> resolver = new MainThreadFetchResolver(p);
-    nsCOMPtr<nsILoadGroup> loadGroup = doc->GetDocumentLoadGroup();
-    nsRefPtr<FetchDriver> fetch =
-      new FetchDriver(r, doc->NodePrincipal(), loadGroup);
+    nsRefPtr<FetchDriver> fetch = new FetchDriver(r, principal, loadGroup);
     fetch->SetDocument(doc);
     aRv = fetch->Fetch(resolver);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
   } else {
     WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
     MOZ_ASSERT(worker);
@@ -406,16 +417,33 @@ UpdateRequestReferrer(nsIGlobalObject* a
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal);
   if (window) {
     nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
     if (doc) {
       nsAutoString referrer;
       doc->GetReferrer(referrer);
       aRequest->SetReferrer(referrer);
     }
+  } else if (NS_IsMainThread()) {
+    // Pull the principal from the global for non-worker scripts.
+    nsIPrincipal *principal = aGlobal->PrincipalOrNull();
+    bool isNull;
+    // Only set the referrer if the principal is present,
+    // and the principal is not null or the system principal.
+    if (principal &&
+        NS_SUCCEEDED(principal->GetIsNullPrincipal(&isNull)) && !isNull &&
+        !nsContentUtils::IsSystemPrincipal(principal)) {
+      nsCOMPtr<nsIURI> uri;
+      if (NS_SUCCEEDED(principal->GetURI(getter_AddRefs(uri))) && uri) {
+        nsAutoCString referrer;
+        if (NS_SUCCEEDED(uri->GetSpec(referrer))) {
+          aRequest->SetReferrer(NS_ConvertUTF8toUTF16(referrer));
+        }
+      }
+    }
   } else {
     WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
     MOZ_ASSERT(worker);
     worker->AssertIsOnWorkerThread();
     WorkerPrivate::LocationInfo& info = worker->GetLocationInfo();
     aRequest->SetReferrer(NS_ConvertUTF8toUTF16(info.mHref));
   }
 
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -3348,16 +3348,29 @@ nsHTMLDocument::QueryCommandEnabled(cons
 bool
 nsHTMLDocument::QueryCommandEnabled(const nsAString& commandID, ErrorResult& rv)
 {
   nsAutoCString cmdToDispatch;
   if (!ConvertToMidasInternalCommand(commandID, cmdToDispatch)) {
     return false;
   }
 
+  // cut & copy are always allowed
+  bool isCutCopy = commandID.LowerCaseEqualsLiteral("cut") ||
+                   commandID.LowerCaseEqualsLiteral("copy");
+  if (isCutCopy) {
+    return nsContentUtils::IsCutCopyAllowed();
+  }
+
+  // Report false for restricted commands
+  bool restricted = commandID.LowerCaseEqualsLiteral("paste");
+  if (restricted && !nsContentUtils::IsCallerChrome()) {
+    return false;
+  }
+
   // if editing is not on, bail
   if (!IsEditingOnAfterFlush()) {
     rv.Throw(NS_ERROR_FAILURE);
     return false;
   }
 
   // get command manager and dispatch command to our window if it's acceptable
   nsCOMPtr<nsICommandManager> cmdMgr;
--- a/dom/html/test/test_iframe_sandbox_navigation.html
+++ b/dom/html/test/test_iframe_sandbox_navigation.html
@@ -10,16 +10,17 @@ Implement HTML5 sandbox attribute for IF
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <script type="application/javascript">
 /** Test for Bug 341604 - Implement HTML5 sandbox attribute for IFRAMEs **/
 /** Navigation tests Part 1**/
 
+SimpleTest.requestLongerTimeout(2); // slow on Android
 SimpleTest.waitForExplicitFinish();
 SimpleTest.requestFlakyTimeout("untriaged");
 // a postMessage handler that is used by sandboxed iframes without
 // 'allow-same-origin'/other windows to communicate pass/fail back to this main page.
 // it expects to be called with an object like {ok: true/false, desc:
 // <description of the test> which it then forwards to ok()
 window.addEventListener("message", receiveMessage, false);
 
--- a/dom/html/test/test_iframe_sandbox_navigation2.html
+++ b/dom/html/test/test_iframe_sandbox_navigation2.html
@@ -11,16 +11,17 @@ Implement HTML5 sandbox attribute for IF
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <script type="application/javascript">
 /** Test for Bug 341604 - Implement HTML5 sandbox attribute for IFRAMEs **/
 /** Navigation tests Part 2**/
 
 SimpleTest.expectAssertions(0);
+SimpleTest.requestLongerTimeout(2); // slow on Android
 SimpleTest.waitForExplicitFinish();
 SimpleTest.requestFlakyTimeout("untriaged");
 // a postMessage handler that is used by sandboxed iframes without
 // 'allow-same-origin'/other windows to communicate pass/fail back to this main page.
 // it expects to be called with an object like {ok: true/false, desc:
 // <description of the test> which it then forwards to ok()
 window.addEventListener("message", receiveMessage, false);
 
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -2241,16 +2241,24 @@ TabParent::HandleQueryContentEvent(Widge
 
       uint32_t baseOffset = aEvent.mInput.mOffset - mIMECompositionRectOffset;
       uint32_t endOffset = baseOffset + aEvent.mInput.mLength;
       aEvent.mReply.mRect.SetEmpty();
       for (uint32_t i = baseOffset; i < endOffset; i++) {
         aEvent.mReply.mRect =
           aEvent.mReply.mRect.Union(mIMECompositionRects[i]);
       }
+      if (aEvent.mInput.mOffset < mIMECacheText.Length()) {
+        aEvent.mReply.mString =
+          Substring(mIMECacheText, aEvent.mInput.mOffset,
+                    mIMECacheText.Length() >= aEvent.mInput.EndOffset() ?
+                      aEvent.mInput.mLength : UINT32_MAX);
+      } else {
+        aEvent.mReply.mString.Truncate();
+      }
       aEvent.mReply.mOffset = aEvent.mInput.mOffset;
       aEvent.mReply.mRect = aEvent.mReply.mRect - GetChildProcessOffset();
       aEvent.mReply.mWritingMode = mWritingMode;
       aEvent.mSucceeded = true;
     }
     break;
   case NS_QUERY_CARET_RECT:
     {
--- a/dom/media/CanvasCaptureMediaStream.h
+++ b/dom/media/CanvasCaptureMediaStream.h
@@ -1,16 +1,19 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_CanvasCaptureMediaStream_h_
 #define mozilla_dom_CanvasCaptureMediaStream_h_
 
+#include "DOMMediaStream.h"
+#include "StreamBuffer.h"
+
 namespace mozilla {
 class DOMMediaStream;
 class MediaStreamListener;
 class SourceMediaStream;
 
 namespace layers {
 class Image;
 }
--- a/dom/media/IdpSandbox.jsm
+++ b/dom/media/IdpSandbox.jsm
@@ -202,17 +202,17 @@ IdpSandbox.prototype = {
 
     this.sandbox = Cu.Sandbox(principal, {
       sandboxName: 'IdP-' + this.source.host,
       wantComponents: false,
       wantExportHelpers: false,
       wantGlobalProperties: [
         'indexedDB', 'XMLHttpRequest', 'TextEncoder', 'TextDecoder',
         'URL', 'URLSearchParams', 'atob', 'btoa', 'Blob', 'crypto',
-        'rtcIdentityProvider'
+        'rtcIdentityProvider', 'fetch'
       ]
     });
     let registrar = this.sandbox.rtcIdentityProvider;
     if (!Cu.isXrayWrapper(registrar)) {
       throw new Error('IdP setup failed');
     }
 
     // have to use the ultimate URI, not the starting one to avoid
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -1073,16 +1073,27 @@ MediaDecoderStateMachine::OnVideoDecoded
     }
 
     case DECODER_STATE_DECODING: {
       Push(video);
       if (mIsVideoPrerolling && DonePrerollingVideo()) {
         StopPrerollingVideo();
       }
 
+      // Schedule the state machine to send stream data as soon as possible or
+      // the VideoQueue() is empty before the Push().
+      // VideoQueue() is empty implies the state machine thread doesn't have
+      // precise time information about video frames. Once the first video
+      // frame pushed in the queue, schedule the state machine as soon as
+      // possible to render the video frame or delay the state machine thread
+      // accurately.
+      if (mAudioCaptured || VideoQueue().GetSize() == 1) {
+        ScheduleStateMachine();
+      }
+
       // For non async readers, if the requested video sample was slow to
       // arrive, increase the amount of audio we buffer to ensure that we
       // don't run out of audio. This is unnecessary for async readers,
       // since they decode audio and video on different threads so they
       // are unlikely to run out of decoded audio.
       if (mReader->IsAsync()) {
         return;
       }
@@ -1092,21 +1103,16 @@ MediaDecoderStateMachine::OnVideoDecoded
       {
         mLowAudioThresholdUsecs =
           std::min(THRESHOLD_FACTOR * DurationToUsecs(decodeTime), mAmpleAudioThresholdUsecs);
         mAmpleAudioThresholdUsecs = std::max(THRESHOLD_FACTOR * mLowAudioThresholdUsecs,
                                               mAmpleAudioThresholdUsecs);
         DECODER_LOG("Slow video decode, set mLowAudioThresholdUsecs=%lld mAmpleAudioThresholdUsecs=%lld",
                     mLowAudioThresholdUsecs, mAmpleAudioThresholdUsecs);
       }
-
-      // Schedule the state machine to send stream data as soon as possible.
-      if (mAudioCaptured) {
-        ScheduleStateMachine();
-      }
       return;
     }
     case DECODER_STATE_SEEKING: {
       if (!mCurrentSeek.Exists()) {
         // We've received a sample from a previous decode. Discard it.
         return;
       }
       if (mDropVideoUntilNextDiscontinuity) {
@@ -2954,19 +2960,17 @@ void MediaDecoderStateMachine::AdvanceFr
       OnPlaybackOffsetUpdate(frame->mOffset);
       if (VideoQueue().GetSize() == 0)
         break;
       frame = VideoQueue().PeekFront();
     }
     // Current frame has already been presented, wait until it's time to
     // present the next frame.
     if (frame && !currentFrame) {
-      int64_t now = IsPlaying() ? clock_time : mStartTime + mPlayDuration;
-
-      remainingTime = frame->mTime - now;
+      remainingTime = frame->mTime - clock_time;
     }
   }
 
   // Check to see if we don't have enough data to play up to the next frame.
   // If we don't, switch to buffering mode.
   if (mState == DECODER_STATE_DECODING &&
       mPlayState == MediaDecoder::PLAY_STATE_PLAYING &&
       mDecoder->IsExpectingMoreData()) {
@@ -3038,16 +3042,32 @@ void MediaDecoderStateMachine::AdvanceFr
       return;
     }
     MediaDecoder::FrameStatistics& frameStats = mDecoder->GetFrameStatistics();
     frameStats.NotifyPresentedFrame();
     remainingTime = currentFrame->GetEndTime() - clock_time;
     currentFrame = nullptr;
   }
 
+  // The remainingTime is negative (include zero):
+  // 1. When the clock_time is larger than the latest video frame's endtime.
+  // All the video frames should be rendered or dropped, nothing left in
+  // VideoQueue. And since the VideoQueue is empty, we don't need to wake up
+  // statemachine thread immediately, so set the remainingTime to default value.
+  // 2. Current frame's endtime is smaller than clock_time but there still exist
+  // newer frames in queue. Re-calculate the remainingTime.
+  if (remainingTime <= 0) {
+    VideoData* nextFrame = VideoQueue().PeekFront();
+    if (nextFrame) {
+      remainingTime = nextFrame->mTime - clock_time;
+    } else {
+      remainingTime = AUDIO_DURATION_USECS;
+    }
+  }
+
   int64_t delay = remainingTime / mPlaybackRate;
   if (delay > 0) {
     ScheduleStateMachineIn(delay);
   } else {
     ScheduleStateMachine();
   }
 }
 
--- a/dom/media/omx/MediaCodecReader.cpp
+++ b/dom/media/omx/MediaCodecReader.cpp
@@ -62,43 +62,16 @@ IsValidDurationUs(int64_t aDuration)
 }
 
 inline bool
 IsValidTimestampUs(int64_t aTimestamp)
 {
   return aTimestamp >= INT64_C(0);
 }
 
-MediaCodecReader::VideoResourceListener::VideoResourceListener(
-  MediaCodecReader* aReader)
-  : mReader(aReader)
-{
-}
-
-MediaCodecReader::VideoResourceListener::~VideoResourceListener()
-{
-  mReader = nullptr;
-}
-
-void
-MediaCodecReader::VideoResourceListener::codecReserved()
-{
-  if (mReader) {
-    mReader->VideoCodecReserved();
-  }
-}
-
-void
-MediaCodecReader::VideoResourceListener::codecCanceled()
-{
-  if (mReader) {
-    mReader->VideoCodecCanceled();
-  }
-}
-
 MediaCodecReader::TrackInputCopier::~TrackInputCopier()
 {
 }
 
 bool
 MediaCodecReader::TrackInputCopier::Copy(MediaBuffer* aSourceBuffer,
                                          sp<ABuffer> aCodecBuffer)
 {
@@ -271,17 +244,16 @@ MediaCodecReader::MediaCodecReader(Abstr
   , mIsWaitingResources(false)
   , mTextureClientIndexesLock("MediaCodecReader::mTextureClientIndexesLock")
   , mColorConverterBufferSize(0)
   , mParserMonitor("MediaCodecReader::mParserMonitor")
   , mParseDataFromCache(true)
   , mNextParserPosition(INT64_C(0))
   , mParsedDataLength(INT64_C(0))
 {
-  mVideoListener = new VideoResourceListener(this);
 }
 
 MediaCodecReader::~MediaCodecReader()
 {
 }
 
 nsresult
 MediaCodecReader::Init(MediaDecoderReader* aCloneDonor)
@@ -671,24 +643,16 @@ MediaCodecReader::ReadMetadata(MediaInfo
   // relies on IsWaitingMediaResources() function. And the waiting state will be
   // changed by binder thread, so we store the waiting state in a cache value to
   // make them in the same waiting state.
   UpdateIsWaitingMediaResources();
   if (IsWaitingMediaResources()) {
     return NS_OK;
   }
 
-  // Configure video codec after the codecReserved.
-  if (mVideoTrack.mSource != nullptr) {
-    if (!ConfigureMediaCodec(mVideoTrack)) {
-      DestroyMediaCodec(mVideoTrack);
-      return NS_ERROR_FAILURE;
-    }
-  }
-
   // TODO: start streaming
 
   if (!UpdateDuration()) {
     return NS_ERROR_FAILURE;
   }
 
   if (!UpdateAudioInfo()) {
     return NS_ERROR_FAILURE;
@@ -1290,42 +1254,45 @@ MediaCodecReader::CreateTaskQueues()
   }
 
   return true;
 }
 
 bool
 MediaCodecReader::CreateMediaCodecs()
 {
-  if (CreateMediaCodec(mLooper, mAudioTrack, false, nullptr) &&
-      CreateMediaCodec(mLooper, mVideoTrack, true, mVideoListener)) {
+  if (CreateMediaCodec(mLooper, mAudioTrack, nullptr) &&
+      CreateMediaCodec(mLooper, mVideoTrack, nullptr)) {
     return true;
   }
 
   return false;
 }
 
 bool
 MediaCodecReader::CreateMediaCodec(sp<ALooper>& aLooper,
                                    Track& aTrack,
-                                   bool aAsync,
                                    wp<MediaCodecProxy::CodecResourceListener> aListener)
 {
   if (aTrack.mSource != nullptr && aTrack.mCodec == nullptr) {
     sp<MetaData> sourceFormat = aTrack.mSource->getFormat();
 
     const char* mime;
     if (sourceFormat->findCString(kKeyMIMEType, &mime)) {
       aTrack.mCodec = MediaCodecProxy::CreateByType(aLooper, mime, false, aListener);
     }
 
     if (aTrack.mCodec == nullptr) {
       NS_WARNING("Couldn't create MediaCodecProxy");
       return false;
     }
+    if (!aTrack.mCodec->AskMediaCodecAndWait()) {
+      NS_WARNING("AskMediaCodecAndWait fail");
+      return false;
+    }
 
     if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
       aTrack.mInputCopier = new VorbisInputCopier;
     } else {
       aTrack.mInputCopier = new TrackInputCopier;
     }
 
     uint32_t capability = MediaCodecProxy::kEmptyCapability;
@@ -1338,24 +1305,20 @@ MediaCodecReader::CreateMediaCodec(sp<AL
       GonkBufferQueue::createBufferQueue(&producer, &consumer);
       aTrack.mNativeWindow = new GonkNativeWindow(consumer);
       aTrack.mGraphicBufferProducer = producer;
 #else
       aTrack.mNativeWindow = new GonkNativeWindow();
 #endif
     }
 
-    if (!aAsync) {
-      // Pending configure() and start() to codecReserved() if the creation
-      // should be asynchronous.
-      if (!aTrack.mCodec->allocated() || !ConfigureMediaCodec(aTrack)){
-        NS_WARNING("Couldn't create and configure MediaCodec synchronously");
-        DestroyMediaCodec(aTrack);
-        return false;
-      }
+    if (!aTrack.mCodec->allocated() || !ConfigureMediaCodec(aTrack)) {
+      NS_WARNING("Couldn't create and configure MediaCodec synchronously");
+      DestroyMediaCodec(aTrack);
+      return false;
     }
   }
 
   return true;
 }
 
 bool
 MediaCodecReader::ConfigureMediaCodec(Track& aTrack)
@@ -1864,37 +1827,32 @@ MediaCodecReader::EnsureCodecFormatParse
   }
 
   status_t status = OK;
   size_t index = 0;
   size_t offset = 0;
   size_t size = 0;
   int64_t timeUs = INT64_C(0);
   uint32_t flags = 0;
+  FillCodecInputData(aTrack);
   while ((status = aTrack.mCodec->dequeueOutputBuffer(&index, &offset, &size,
                      &timeUs, &flags)) != INFO_FORMAT_CHANGED) {
     if (status == OK) {
       aTrack.mCodec->releaseOutputBuffer(index);
     } else if (status == INFO_OUTPUT_BUFFERS_CHANGED) {
       // Update output buffers of MediaCodec.
       if (aTrack.mCodec->getOutputBuffers(&aTrack.mOutputBuffers) != OK) {
         NS_WARNING("Couldn't get output buffers from MediaCodec");
         return false;
       }
-    } else if (status != -EAGAIN && status != INVALID_OPERATION){
+    } else if (status != -EAGAIN && status != INVALID_OPERATION) {
       // FIXME: let INVALID_OPERATION pass?
       return false; // something wrong!!!
     }
-
-    status = FillCodecInputData(aTrack);
-    if (status == INFO_FORMAT_CHANGED) {
-      break;
-    } else if (status != OK) {
-      return false;
-    }
+    FillCodecInputData(aTrack);
   }
   return aTrack.mCodec->getOutputFormat(&format) == OK;
 }
 
 uint8_t*
 MediaCodecReader::GetColorConverterBuffer(int32_t aWidth, int32_t aHeight)
 {
   // Allocate a temporary YUV420Planer buffer.
@@ -1912,27 +1870,9 @@ MediaCodecReader::GetColorConverterBuffe
 
 void
 MediaCodecReader::ClearColorConverterBuffer()
 {
   mColorConverterBuffer = nullptr;
   mColorConverterBufferSize = 0;
 }
 
-// Called on Binder thread.
-void
-MediaCodecReader::VideoCodecReserved()
-{
-  mDecoder->NotifyWaitingForResourcesStatusChanged();
-}
-
-// Called on Binder thread.
-void
-MediaCodecReader::VideoCodecCanceled()
-{
-  if (mVideoTrack.mTaskQueue) {
-    RefPtr<nsIRunnable> task =
-      NS_NewRunnableMethod(this, &MediaCodecReader::ReleaseCriticalResources);
-    mVideoTrack.mTaskQueue->Dispatch(task.forget());
-  }
-}
-
 } // namespace mozilla
--- a/dom/media/omx/MediaCodecReader.h
+++ b/dom/media/omx/MediaCodecReader.h
@@ -172,55 +172,28 @@ protected:
     Track(const Track &rhs) = delete;
     const Track &operator=(const Track&) = delete;
   };
 
   // Receive a message from MessageHandler.
   // Called on MediaCodecReader::mLooper thread.
   void onMessageReceived(const android::sp<android::AMessage>& aMessage);
 
-  // Receive a notify from ResourceListener.
-  // Called on Binder thread.
-  virtual void VideoCodecReserved();
-  virtual void VideoCodecCanceled();
-
   virtual bool CreateExtractor();
 
   // Check the underlying HW resource is available and store the result in
   // mIsWaitingResources.
   void UpdateIsWaitingMediaResources();
 
   android::sp<android::MediaExtractor> mExtractor;
   // A cache value updated by UpdateIsWaitingMediaResources(), makes the
   // "waiting resources state" is synchronous to StateMachine.
   bool mIsWaitingResources;
 
 private:
-
-  // An intermediary class that can be managed by android::sp<T>.
-  // Redirect codecReserved() and codecCanceled() to MediaCodecReader.
-  class VideoResourceListener : public android::MediaCodecProxy::CodecResourceListener
-  {
-  public:
-    VideoResourceListener(MediaCodecReader* aReader);
-    ~VideoResourceListener();
-
-    virtual void codecReserved();
-    virtual void codecCanceled();
-
-  private:
-    // Forbidden
-    VideoResourceListener() = delete;
-    VideoResourceListener(const VideoResourceListener& rhs) = delete;
-    const VideoResourceListener& operator=(const VideoResourceListener& rhs) = delete;
-
-    MediaCodecReader* mReader;
-  };
-  friend class VideoResourceListener;
-
   class VorbisInputCopier : public TrackInputCopier
   {
     virtual bool Copy(android::MediaBuffer* aSourceBuffer,
                       android::sp<android::ABuffer> aCodecBuffer);
   };
 
   struct AudioTrack : public Track
   {
@@ -349,17 +322,16 @@ private:
   void DestroyExtractor();
 
   bool CreateMediaSources();
   void DestroyMediaSources();
 
   bool CreateMediaCodecs();
   static bool CreateMediaCodec(android::sp<android::ALooper>& aLooper,
                                Track& aTrack,
-                               bool aAsync,
                                android::wp<android::MediaCodecProxy::CodecResourceListener> aListener);
   static bool ConfigureMediaCodec(Track& aTrack);
   void DestroyMediaCodecs();
   static void DestroyMediaCodec(Track& aTrack);
 
   bool CreateTaskQueues();
   void ShutdownTaskQueues();
   void DecodeVideoFrameTask(int64_t aTimeThreshold);
@@ -410,18 +382,16 @@ private:
   static PLDHashOperator ReleaseTextureClient(TextureClient* aClient,
                                               size_t& aIndex,
                                               void* aUserArg);
   PLDHashOperator ReleaseTextureClient(TextureClient* aClient,
                                        size_t& aIndex);
 
   void ReleaseAllTextureClients();
 
-  android::sp<VideoResourceListener> mVideoListener;
-
   android::sp<android::ALooper> mLooper;
   android::sp<android::MetaData> mMetaData;
 
   Mutex mTextureClientIndexesLock;
   nsDataHashtable<nsPtrHashKey<TextureClient>, size_t> mTextureClientIndexes;
 
   // media tracks
   AudioTrack mAudioTrack;
--- a/dom/media/tests/mochitest/identity/idp.js
+++ b/dom/media/tests/mochitest/identity/idp.js
@@ -16,22 +16,18 @@
     var path = global.location.pathname;
     this.protocol =
       path.substring(path.lastIndexOf('/') + 1) + global.location.hash;
     this.id = crypto.getRandomValues(new Uint8Array(10)).join('.');
   }
 
   IDPJS.prototype = {
     getLogin: function() {
-      var xhr = new XMLHttpRequest();
-      xhr.open('GET', 'https://example.com/.well-known/idp-proxy/idp.sjs?' + this.id);
-      return new Promise(resolve => {
-        xhr.onload = e => resolve(xhr.status === 200);
-        xhr.send();
-      });
+      return fetch('https://example.com/.well-known/idp-proxy/idp.sjs?' + this.id)
+        .then(response => response.status === 200);
     },
     checkLogin: function(result) {
       return this.getLogin()
         .then(loggedIn => {
           if (loggedIn) {
             return result;
           }
           return Promise.reject({
--- a/dom/tests/mochitest/bugs/test_bug346659.html
+++ b/dom/tests/mochitest/bugs/test_bug346659.html
@@ -14,16 +14,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 346659 **/
 var numTests = 10;
+SimpleTest.requestLongerTimeout(2); // test takes a long time on android and b2g emulators
 SimpleTest.waitForExplicitFinish();
 
 var wins = [];
 
 function r(base, tail) {
   return base.replace(/\/[^\/]*$/, "/" + tail);
 }
 
--- a/dom/tests/mochitest/fetch/test_fetch_basic.js
+++ b/dom/tests/mochitest/fetch/test_fetch_basic.js
@@ -34,16 +34,17 @@ function testDataURL() {
     });
   });
 }
 
 function testSameOriginBlobURL() {
   var blob = new Blob(["english ", "sentence"], { type: "text/plain" });
   var url = URL.createObjectURL(blob);
   return fetch(url).then(function(res) {
+    URL.revokeObjectURL(url);
     ok(true, "Blob URL fetch should resolve");
     if (res.type == "error") {
       ok(false, "Blob URL fetch should not fail.");
       return Promise.reject();
     }
     ok(res instanceof Response, "Fetch should resolve to a Response");
     is(res.status, 200, "Blob fetch status should be 200");
     is(res.statusText, "OK", "Blob fetch statusText should be OK");
--- a/editor/libeditor/tests/browserscope/lib/richtext2/currentStatus.js
+++ b/editor/libeditor/tests/browserscope/lib/richtext2/currentStatus.js
@@ -302,16 +302,25 @@ const knownFailures = {
     "QE-Proposed-INSERTLINEBREAK_TEXT-1-body": true,
     "QE-Proposed-INSERTLINEBREAK_TEXT-1-div": true,
     "QE-Proposed-CREATEBOOKMARK_TEXT-1-dM": true,
     "QE-Proposed-CREATEBOOKMARK_TEXT-1-body": true,
     "QE-Proposed-CREATEBOOKMARK_TEXT-1-div": true,
     "QE-Proposed-UNBOOKMARK_TEXT-1-dM": true,
     "QE-Proposed-UNBOOKMARK_TEXT-1-body": true,
     "QE-Proposed-UNBOOKMARK_TEXT-1-div": true,
+    "QE-Proposed-COPY_TEXT-1-dM": true,
+    "QE-Proposed-COPY_TEXT-1-body": true,
+    "QE-Proposed-COPY_TEXT-1-div": true,
+    "QE-Proposed-CUT_TEXT-1-dM": true,
+    "QE-Proposed-CUT_TEXT-1-body": true,
+    "QE-Proposed-CUT_TEXT-1-div": true,
+    "QE-Proposed-PASTE_TEXT-1-dM": true,
+    "QE-Proposed-PASTE_TEXT-1-body": true,
+    "QE-Proposed-PASTE_TEXT-1-div": true,
     "QS-Proposed-SUB_SPAN.sub-1-SI-dM": true,
     "QS-Proposed-SUB_SPAN.sub-1-SI-body": true,
     "QS-Proposed-SUB_SPAN.sub-1-SI-div": true,
     "QS-Proposed-SUB_MYSUB-1-SI-dM": true,
     "QS-Proposed-SUB_MYSUB-1-SI-body": true,
     "QS-Proposed-SUB_MYSUB-1-SI-div": true,
     "QS-Proposed-SUP_SPAN.sup-1-SI-dM": true,
     "QS-Proposed-SUP_SPAN.sup-1-SI-body": true,
--- a/editor/libeditor/tests/mochitest.ini
+++ b/editor/libeditor/tests/mochitest.ini
@@ -157,9 +157,10 @@ skip-if = toolkit == 'android' # bug 105
 [test_dom_input_event_on_texteditor.html]
 [test_keypress_untrusted_event.html]
 [test_root_element_replacement.html]
 [test_select_all_without_body.html]
 skip-if = e10s
 [test_spellcheck_pref.html]
 skip-if = toolkit == 'android'
 [test_bug1068979.html]
-[test_bug1109465.html]
\ No newline at end of file
+[test_bug1109465.html]
+[test_bug1162952.html]
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/tests/test_bug1162952.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1162952
+-->
+<head>
+  <title>Test for Bug 1162952</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1162952">Mozilla Bug 1162952</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 1162952 **/
+var userCallbackRun = false;
+
+document.addEventListener('keydown', function() {
+    // During a user callback, the commands should be enabled
+    userCallbackRun = true;
+    is(true, document.queryCommandEnabled('cut'));
+    is(true, document.queryCommandEnabled('copy'));
+});
+
+// Otherwise, they should be disabled
+is(false, document.queryCommandEnabled('cut'));
+is(false, document.queryCommandEnabled('copy'));
+
+// Fire a user callback
+synthesizeKey('A', {});
+
+ok(userCallbackRun, "User callback should've been run");
+
+</script>
+</pre>
+</body>
+</html>
--- a/editor/libeditor/tests/test_bug408231.html
+++ b/editor/libeditor/tests/test_bug408231.html
@@ -40,17 +40,17 @@ https://bugzilla.mozilla.org/show_bug.cg
       ["insertunorderedlist", "true"],
       ["insertparagraph", "true"],
       ["italic", "true"],
       ["justifycenter", "true"],
       ["justifyfull", "true"],
       ["justifyleft", "true"],
       ["justifyright", "true"],
       ["outdent", "true"],
-      //["paste", "true"],
+      ["paste", "false"],
       ["redo", "false"],
       ["removeformat", "true"],
       ["selectall", "true"],
       ["strikethrough", "true"],
       ["styleWithCSS", "true"],
       ["subscript", "true"],
       ["superscript", "true"],
       ["underline", "true"],
--- a/editor/libeditor/tests/test_bug676401.html
+++ b/editor/libeditor/tests/test_bug676401.html
@@ -30,16 +30,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 SimpleTest.waitForExplicitFinish();
 SimpleTest.waitForFocus(runTests);
 
 var gBlock1, gBlock2;
 
 var alwaysEnabledCommands = [
   "contentReadOnly",
   "copy",
+  "cut",
   "enableInlineTableEditing",
   "enableObjectResizing",
   "insertBrOnReturn",
   "selectAll",
   "styleWithCSS",
 ];
 
 function IsCommandEnabled(command) {
@@ -84,19 +85,22 @@ function runTests() {
     IsCommandEnabled(commands[i]);
 
   // Mozilla-specific stuff
   commands = ["enableInlineTableEditing", "enableObjectResizing", "insertBrOnReturn"];
   for (i = 0; i < commands.length; i++)
     IsCommandEnabled(commands[i]);
 
   // These are privileged, and available only to chrome.
-  commands = ["cut", "paste", "copy"];
+  commands = ["paste"];
   for (i = 0; i < commands.length; i++) {
-    IsCommandEnabled(commands[i]);
+    is(document.queryCommandEnabled(commands[i]), false,
+       "Command should not be enabled for non-privileged code");
+    is(SpecialPowers.wrap(document).queryCommandEnabled(commands[i]), true,
+       "Command should be enabled for privileged code");
     try {
       document.execCommand(commands[i], false, false);
       ok(false, "Thould have thrown: " + commands[i]);
     } catch (e) {
       ok(/insecure|denied/.test(e), "Threw correctly: " + commands[i] + " - " + e);
     }
     SpecialPowers.wrap(document).execCommand(commands[i], false, false);
   }
--- a/gfx/2d/Matrix.h
+++ b/gfx/2d/Matrix.h
@@ -148,17 +148,32 @@ public:
   {
     _11 *= aX;
     _12 *= aX;
     _21 *= aY;
     _22 *= aY;
 
     return *this;
   }
-  
+
+  /**
+   * Similar to PostTranslate, but applies a scale instead of a translation.
+   */
+  Matrix &PostScale(Float aScaleX, Float aScaleY)
+  {
+    _11 *= aScaleX;
+    _12 *= aScaleY;
+    _21 *= aScaleX;
+    _22 *= aScaleY;
+    _31 *= aScaleX;
+    _32 *= aScaleY;
+
+    return *this;
+  }
+
   GFX2D_API static Matrix Rotation(Float aAngle);
 
   /**
    * Similar to PreTranslate, but applies a rotation instead of a translation.
    */
   Matrix &PreRotate(Float aAngle)
   {
     return *this = Matrix::Rotation(aAngle) * *this;
--- a/gfx/layers/LayerScope.cpp
+++ b/gfx/layers/LayerScope.cpp
@@ -221,105 +221,91 @@ StaticAutoPtr<LayerScopeWebSocketManager
 class DebugGLData: public LinkedListElement<DebugGLData> {
 public:
     explicit DebugGLData(Packet::DataType aDataType)
         : mDataType(aDataType)
     { }
 
     virtual ~DebugGLData() { }
 
-    Packet::DataType GetDataType() const { return mDataType; }
-
     virtual bool Write() = 0;
 
+protected:
     static bool WriteToStream(Packet& aPacket) {
         if (!WebSocketHelper::GetSocketManager())
             return true;
 
         uint32_t size = aPacket.ByteSize();
         auto data = MakeUnique<uint8_t[]>(size);
         aPacket.SerializeToArray(data.get(), size);
         return WebSocketHelper::GetSocketManager()->WriteAll(data.get(), size);
     }
 
-protected:
     Packet::DataType mDataType;
 };
 
-class DebugGLFrameStatusData : public DebugGLData
+class DebugGLFrameStatusData final: public DebugGLData
 {
 public:
     DebugGLFrameStatusData(Packet::DataType aDataType,
                            int64_t aValue)
         : DebugGLData(aDataType),
           mFrameStamp(aValue)
     { }
 
     explicit DebugGLFrameStatusData(Packet::DataType aDataType)
         : DebugGLData(aDataType),
           mFrameStamp(0)
     { }
 
-    int64_t GetFrameStamp() const { return mFrameStamp; }
-
     virtual bool Write() override {
         Packet packet;
         packet.set_type(mDataType);
 
         FramePacket* fp = packet.mutable_frame();
         fp->set_value(static_cast<uint64_t>(mFrameStamp));
 
-        if (!WriteToStream(packet))
-            return false;
-        return true;
+        return WriteToStream(packet);
     }
 
 protected:
     int64_t mFrameStamp;
 };
 
-class DebugGLTextureData : public DebugGLData {
+class DebugGLTextureData final: public DebugGLData {
 public:
     DebugGLTextureData(GLContext* cx,
                        void* layerRef,
                        GLenum target,
                        GLuint name,
                        DataSourceSurface* img)
         : DebugGLData(Packet::TEXTURE),
-          mLayerRef(layerRef),
+          mLayerRef(reinterpret_cast<uint64_t>(layerRef)),
           mTarget(target),
           mName(name),
           mContextAddress(reinterpret_cast<intptr_t>(cx)),
           mDatasize(0)
     {
         // pre-packing
         // DataSourceSurface may have locked buffer,
         // so we should compress now, and then it could
         // be unlocked outside.
         pack(img);
     }
 
-    const void* GetLayerRef() const { return mLayerRef; }
-    GLuint GetName() const { return mName; }
-    GLenum GetTextureTarget() const { return mTarget; }
-    intptr_t GetContextAddress() const { return mContextAddress; }
-    uint32_t GetDataSize() const { return mDatasize; }
-
     virtual bool Write() override {
-        if (!WriteToStream(mPacket))
-            return false;
-        return true;
+        return WriteToStream(mPacket);
     }
 
 private:
     void pack(DataSourceSurface* aImage) {
         mPacket.set_type(mDataType);
 
         TexturePacket* tp = mPacket.mutable_texture();
-        tp->set_layerref(reinterpret_cast<uint64_t>(mLayerRef));
+        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));
 
         if (aImage) {
             tp->set_width(aImage->GetSize().width);
             tp->set_height(aImage->GetSize().height);
@@ -347,83 +333,74 @@ private:
         } else {
             tp->set_width(0);
             tp->set_height(0);
             tp->set_stride(0);
         }
     }
 
 protected:
-    void* mLayerRef;
+    uint64_t mLayerRef;
     GLenum mTarget;
     GLuint mName;
     intptr_t mContextAddress;
     uint32_t mDatasize;
 
     // Packet data
     Packet mPacket;
 };
 
-class DebugGLColorData : public DebugGLData {
+class DebugGLColorData final: public DebugGLData {
 public:
     DebugGLColorData(void* layerRef,
                      const gfxRGBA& color,
                      int width,
                      int height)
         : DebugGLData(Packet::COLOR),
-          mLayerRef(layerRef),
+          mLayerRef(reinterpret_cast<uint64_t>(layerRef)),
           mColor(color.Packed()),
           mSize(width, height)
     { }
 
-    const void* GetLayerRef() const { return mLayerRef; }
-    uint32_t GetColor() const { return mColor; }
-    const nsIntSize& GetSize() const { return mSize; }
-
     virtual bool Write() override {
         Packet packet;
         packet.set_type(mDataType);
 
         ColorPacket* cp = packet.mutable_color();
-        cp->set_layerref(reinterpret_cast<uint64_t>(mLayerRef));
+        cp->set_layerref(mLayerRef);
         cp->set_color(mColor);
         cp->set_width(mSize.width);
         cp->set_height(mSize.height);
 
-        if (!WriteToStream(packet))
-            return false;
-        return true;
+        return WriteToStream(packet);
     }
 
 protected:
-    void* mLayerRef;
+    uint64_t mLayerRef;
     uint32_t mColor;
     nsIntSize mSize;
 };
 
-class DebugGLLayersData : public DebugGLData {
+class DebugGLLayersData final: public DebugGLData {
 public:
     explicit DebugGLLayersData(UniquePtr<Packet> aPacket)
         : DebugGLData(Packet::LAYERS),
           mPacket(Move(aPacket))
     { }
 
     virtual bool Write() override {
         mPacket->set_type(mDataType);
-
-        if (!WriteToStream(*mPacket))
-            return false;
-        return true;
+        return WriteToStream(*mPacket);
     }
 
 protected:
     UniquePtr<Packet> mPacket;
 };
 
-class DebugGLMetaData : public DebugGLData
+class DebugGLMetaData final: public DebugGLData
 {
 public:
     DebugGLMetaData(Packet::DataType aDataType,
                     bool aValue)
         : DebugGLData(aDataType),
           mComposedByHwc(aValue)
     { }
 
@@ -434,25 +411,79 @@ public:
 
     virtual bool Write() override {
         Packet packet;
         packet.set_type(mDataType);
 
         MetaPacket* mp = packet.mutable_meta();
         mp->set_composedbyhwc(mComposedByHwc);
 
-        if (!WriteToStream(packet))
-            return false;
-        return true;
+        return WriteToStream(packet);
     }
 
 protected:
     bool mComposedByHwc;
 };
 
+class DebugGLDrawData final: public DebugGLData {
+public:
+    DebugGLDrawData(float aOffsetX,
+                    float aOffsetY,
+                    const gfx::Matrix4x4& aMVMatrix,
+                    size_t aRects,
+                    const gfx::Rect* aLayerRects,
+                    void* aLayerRef)
+        : DebugGLData(Packet::DRAW),
+          mOffsetX(aOffsetX),
+          mOffsetY(aOffsetY),
+          mMVMatrix(aMVMatrix),
+          mRects(aRects),
+          mLayerRef(reinterpret_cast<uint64_t>(aLayerRef))
+    {
+        for (size_t i = 0; i < mRects; i++){
+            mLayerRects[i] = aLayerRects[i];
+        }
+    }
+
+    virtual bool Write() override {
+        Packet packet;
+        packet.set_type(mDataType);
+
+        DrawPacket* dp = packet.mutable_draw();
+        dp->set_layerref(mLayerRef);
+
+        dp->set_offsetx(mOffsetX);
+        dp->set_offsety(mOffsetY);
+
+        auto element = reinterpret_cast<Float *>(&mMVMatrix);
+        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++) {
+            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);
+        }
+
+        return WriteToStream(packet);
+    }
+
+protected:
+    float mOffsetX;
+    float mOffsetY;
+    gfx::Matrix4x4 mMVMatrix;
+    size_t mRects;
+    gfx::Rect mLayerRects[4];
+    uint64_t mLayerRef;
+};
 
 class DebugListener : public nsIServerSocketListener
 {
     virtual ~DebugListener() { }
 
 public:
 
     NS_DECL_THREADSAFE_ISUPPORTS
@@ -798,17 +829,16 @@ SenderHelper::SendEffectChain(GLContext*
         default:
             break;
     }
 
     //const Effect* secondaryEffect = aEffectChain.mSecondaryEffects[EffectTypes::MASK];
     // TODO:
 }
 
-
 // ----------------------------------------------
 // LayerScopeWebSocketHandler implementation
 // ----------------------------------------------
 void
 LayerScopeWebSocketHandler::OpenStream(nsISocketTransport* aTransport)
 {
     MOZ_ASSERT(aTransport);
 
@@ -1291,26 +1321,117 @@ LayerScope::Init()
             return;
         }
         DebugOnly<nsresult> rv = NS_DispatchToMainThread(new CreateServerSocketRunnable());
         MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to dispatch WebSocket Creation to main thread");
         dispatched = true;
     }
 }
 
+class DrawSession {
+public:
+    NS_INLINE_DECL_REFCOUNTING(DrawSession)
+
+    DrawSession()
+      : mOffsetX(0.0),
+        mOffsetY(0.0),
+        mRects(0)
+    { }
+
+    float mOffsetX;
+    float mOffsetY;
+    gfx::Matrix4x4 mMVMatrix;
+    size_t mRects;
+    gfx::Rect mLayerRects[4];
+private:
+    ~DrawSession() {}
+};
+
+class DrawSessionHolder {
+public:
+    static void setSession(DrawSession *aSession) {
+        mSession = aSession;
+    }
+
+    static DrawSession& current() {
+        return *mSession;
+    }
+
+private:
+    static nsRefPtr<DrawSession> mSession;
+};
+
+nsRefPtr<DrawSession> DrawSessionHolder::mSession;
+
 void
-LayerScope::SendEffectChain(gl::GLContext* aGLContext,
-                            const EffectChain& aEffectChain,
-                            int aWidth,
-                            int aHeight)
+LayerScope::DrawBegin()
+{
+    if (!CheckSendable()) {
+        return;
+    }
+
+    DrawSessionHolder::setSession(new DrawSession());
+}
+
+void LayerScope::SetRenderOffset(float aX, float aY)
+{
+    if (!CheckSendable()) {
+        return;
+    }
+
+    DrawSessionHolder::current().mOffsetX = aX;
+    DrawSessionHolder::current().mOffsetY = aY;
+}
+
+void LayerScope::SetLayerTransform(const gfx::Matrix4x4& aMatrix)
+{
+    if (!CheckSendable()) {
+        return;
+    }
+
+    DrawSessionHolder::current().mMVMatrix = aMatrix;
+}
+
+void LayerScope::SetLayerRects(size_t aRects, const gfx::Rect* aLayerRects)
+{
+    if (!CheckSendable()) {
+        return;
+    }
+
+    MOZ_ASSERT(aRects > 0 && aRects <= 4);
+    MOZ_ASSERT(aLayerRects);
+
+    DrawSessionHolder::current().mRects = aRects;
+
+    for (size_t i = 0; i < aRects; i++){
+        DrawSessionHolder::current().mLayerRects[i] = aLayerRects[i];
+    }
+}
+
+void
+LayerScope::DrawEnd(gl::GLContext* aGLContext,
+                    const EffectChain& aEffectChain,
+                    int aWidth,
+                    int aHeight)
 {
     // Protect this public function
     if (!CheckSendable()) {
         return;
     }
+
+    // 1. Send parameters of draw call, such as uniforms and attributes of
+    // vertex adnd fragment shader.
+    DrawSession& draws = DrawSessionHolder::current();
+    WebSocketHelper::GetSocketManager()->AppendDebugData(
+        new DebugGLDrawData(draws.mOffsetX, draws.mOffsetY,
+                            draws.mMVMatrix, draws.mRects,
+                            draws.mLayerRects,
+                            aEffectChain.mLayerRef));
+
+    // 2. Send textures.
     SenderHelper::SendEffectChain(aGLContext, aEffectChain, aWidth, aHeight);
 }
 
 void
 LayerScope::SendLayer(LayerComposite* aLayer,
                       int aWidth,
                       int aHeight)
 {
@@ -1354,17 +1475,16 @@ LayerScope::CheckSendable()
 void
 LayerScope::CleanLayer()
 {
     if (CheckSendable()) {
         WebSocketHelper::GetSocketManager()->CleanDebugData();
     }
 }
 
-
 void
 LayerScope::SetHWComposed()
 {
     if (CheckSendable()) {
         WebSocketHelper::GetSocketManager()->AppendDebugData(
             new DebugGLMetaData(Packet::META, true));
     }
 }
--- a/gfx/layers/LayerScope.h
+++ b/gfx/layers/LayerScope.h
@@ -18,20 +18,25 @@ namespace layers {
 
 namespace layerscope { class Packet; }
 
 struct EffectChain;
 class LayerComposite;
 
 class LayerScope {
 public:
-    static void SendEffectChain(gl::GLContext* aGLContext,
-                                const EffectChain& aEffectChain,
-                                int aWidth,
-                                int aHeight);
+    static void DrawBegin();
+    static void SetRenderOffset(float aX, float aY);
+    static void SetLayerTransform(const gfx::Matrix4x4& aMatrix);
+    static void SetLayerRects(size_t aRects, const gfx::Rect* aLayerRects);
+    static void DrawEnd(gl::GLContext* aGLContext,
+                        const EffectChain& aEffectChain,
+                        int aWidth,
+                        int aHeight);
+
     static void SendLayer(LayerComposite* aLayer,
                           int aWidth,
                           int aHeight);
     static void SendLayerDump(UniquePtr<layerscope::Packet> aPacket);
     static bool CheckSendable();
     static void CleanLayer();
     static void SetHWComposed();
 
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -139,20 +139,49 @@ TextureHost::AsTextureHost(PTextureParen
 }
 
 PTextureParent*
 TextureHost::GetIPDLActor()
 {
   return mActor;
 }
 
+bool
+TextureHost::SetReleaseFenceHandle(const FenceHandle& aReleaseFenceHandle)
+{
+  if (!aReleaseFenceHandle.IsValid()) {
+    // HWC might not provide Fence.
+    // In this case, HWC implicitly handles buffer's fence.
+    return false;
+  }
+
+  mReleaseFenceHandle.Merge(aReleaseFenceHandle);
+
+  return true;
+}
+
 FenceHandle
 TextureHost::GetAndResetReleaseFenceHandle()
 {
-  return FenceHandle();
+  FenceHandle fence;
+  mReleaseFenceHandle.TransferToAnotherFenceHandle(fence);
+  return fence;
+}
+
+void
+TextureHost::SetAcquireFenceHandle(const FenceHandle& aAcquireFenceHandle)
+{
+  mAcquireFenceHandle = aAcquireFenceHandle;
+}
+
+FenceHandle
+TextureHost::GetAndResetAcquireFenceHandle()
+{
+  nsRefPtr<FenceHandle::FdObj> fdObj = mAcquireFenceHandle.GetAndResetFdObj();
+  return FenceHandle(fdObj);
 }
 
 // implemented in TextureHostOGL.cpp
 TemporaryRef<TextureHost> CreateTextureHostOGL(const SurfaceDescriptor& aDesc,
                                                ISurfaceAllocator* aDeallocator,
                                                TextureFlags aFlags);
 
 // implemented in TextureHostBasic.cpp
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -465,18 +465,16 @@ public:
   /**
    * Return a pointer to the IPDLActor.
    *
    * This is to be used with IPDL messages only. Do not store the returned
    * pointer.
    */
   PTextureParent* GetIPDLActor();
 
-  virtual FenceHandle GetAndResetReleaseFenceHandle();
-
   /**
    * Specific to B2G's Composer2D
    * XXX - more doc here
    */
   virtual LayerRenderState GetRenderState()
   {
     // By default we return an empty render state, this should be overridden
     // by the TextureHost implementations that are used on B2G with Composer2D
@@ -495,35 +493,54 @@ public:
 
   /**
    * Indicates whether the TextureHost implementation is backed by an
    * in-memory buffer. The consequence of this is that locking the
    * TextureHost does not contend with locking the texture on the client side.
    */
   virtual bool HasInternalBuffer() const { return false; }
 
-  /**
-   * Cast to a TextureHost for each backend.
-   */
-  virtual TextureHostOGL* AsHostOGL() { return nullptr; }
-
   void AddCompositableRef() { ++mCompositableCount; }
 
   void ReleaseCompositableRef()
   {
     --mCompositableCount;
     MOZ_ASSERT(mCompositableCount >= 0);
     if (mCompositableCount == 0) {
       UnbindTextureSource();
     }
   }
 
   int NumCompositableRefs() const { return mCompositableCount; }
 
+  /**
+   * Store a fence that will signal when the current buffer is no longer being read.
+   * Similar to android's GLConsumer::setReleaseFence()
+   */
+  bool SetReleaseFenceHandle(const FenceHandle& aReleaseFenceHandle);
+
+  /**
+   * Return a releaseFence's Fence and clear a reference to the Fence.
+   */
+  FenceHandle GetAndResetReleaseFenceHandle();
+
+  void SetAcquireFenceHandle(const FenceHandle& aAcquireFenceHandle);
+
+  /**
+   * Return a acquireFence's Fence and clear a reference to the Fence.
+   */
+  FenceHandle GetAndResetAcquireFenceHandle();
+
+  virtual void WaitAcquireFenceHandleSyncComplete() {};
+
 protected:
+  FenceHandle mReleaseFenceHandle;
+
+  FenceHandle mAcquireFenceHandle;
+
   void RecycleTexture(TextureFlags aFlags);
 
   PTextureParent* mActor;
   TextureFlags mFlags;
   int mCompositableCount;
 
   friend class TextureParent;
 };
--- a/gfx/layers/ipc/CompositableTransactionParent.cpp
+++ b/gfx/layers/ipc/CompositableTransactionParent.cpp
@@ -174,20 +174,17 @@ CompositableParentManager::ReceiveCompos
 
       MOZ_ASSERT(tex.get());
       compositable->UseTextureHost(tex);
 
       MaybeFence maybeFence = op.fence();
       if (maybeFence.type() == MaybeFence::TFenceHandle) {
         FenceHandle fence = maybeFence.get_FenceHandle();
         if (fence.IsValid() && tex) {
-          TextureHostOGL* hostOGL = tex->AsHostOGL();
-          if (hostOGL) {
-            hostOGL->SetAcquireFence(fence);
-          }
+          tex->SetAcquireFenceHandle(fence);
         }
       }
 
       if (IsAsync() && compositable->GetLayer()) {
         ScheduleComposition(op);
         // Async layer updates don't trigger invalidation, manually tell the layer
         // that its content have changed.
         compositable->GetLayer()->SetInvalidRectToVisibleRegion();
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -427,16 +427,17 @@ CompositorOGL::BindAndDrawQuadWithTextur
                                               TextureSource *aTexture)
 {
   Rect layerRects[4];
   Rect textureRects[4];
   size_t rects = DecomposeIntoNoRepeatRects(aRect,
                                             aTexCoordRect,
                                             &layerRects,
                                             &textureRects);
+
   BindAndDrawQuads(aProg, rects, layerRects, textureRects);
 }
 
 void
 CompositorOGL::PrepareViewport(const gfx::IntSize& aSize)
 {
   // Set the viewport correctly.
   mGLContext->fViewport(0, 0, aSize.width, aSize.height);
@@ -914,34 +915,32 @@ CompositorOGL::DrawQuad(const Rect& aRec
 
   MOZ_ASSERT(mFrameInProgress, "frame not started");
   MOZ_ASSERT(mCurrentRenderTarget, "No destination");
 
   if (aEffectChain.mPrimaryEffect->mType == EffectTypes::VR_DISTORTION) {
     DrawVRDistortion(aRect, aClipRect, aEffectChain, aOpacity, aTransform);
     return;
   }
+  LayerScope::DrawBegin();
 
   Rect clipRect = aClipRect;
   // aClipRect is in destination coordinate space (after all
   // transforms and offsets have been applied) so if our
   // drawing is going to be shifted by mRenderOffset then we need
   // to shift the clip rect by the same amount.
   if (!mTarget && mCurrentRenderTarget->IsWindow()) {
     clipRect.MoveBy(mRenderOffset.x, mRenderOffset.y);
   }
   IntRect intClipRect;
   clipRect.ToIntRect(&intClipRect);
 
   gl()->fScissor(intClipRect.x, FlipY(intClipRect.y + intClipRect.height),
                  intClipRect.width, intClipRect.height);
 
-  LayerScope::SendEffectChain(mGLContext, aEffectChain,
-                              aRect.width, aRect.height);
-
   MaskType maskType;
   EffectMask* effectMask;
   TextureSourceOGL* sourceMask = nullptr;
   gfx::Matrix4x4 maskQuadTransform;
   if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) {
     effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EffectTypes::MASK].get());
     sourceMask = effectMask->mMaskTexture->AsSourceOGL();
 
@@ -1004,25 +1003,27 @@ CompositorOGL::DrawQuad(const Rect& aRec
 
   bool colorMatrix = aEffectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX];
   ShaderConfigOGL config = GetShaderConfigFor(aEffectChain.mPrimaryEffect, maskType, blendMode, colorMatrix);
   config.SetOpacity(aOpacity != 1.f);
   ShaderProgramOGL *program = GetShaderProgramFor(config);
   ActivateProgram(program);
   program->SetProjectionMatrix(mProjMatrix);
   program->SetLayerTransform(aTransform);
-
+  LayerScope::SetLayerTransform(aTransform);
   if (colorMatrix) {
       EffectColorMatrix* effectColorMatrix =
         static_cast<EffectColorMatrix*>(aEffectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX].get());
       program->SetColorMatrix(effectColorMatrix->mColorMatrix);
   }
 
   IntPoint offset = mCurrentRenderTarget->GetOrigin();
   program->SetRenderOffset(offset.x, offset.y);
+  LayerScope::SetRenderOffset(offset.x, offset.y);
+
   if (aOpacity != 1.f)
     program->SetLayerOpacity(aOpacity);
   if (config.mFeatures & ENABLE_TEXTURE_RECT) {
     TexturedEffect* texturedEffect =
         static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
     TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL();
     // This is used by IOSurface that use 0,0...w,h coordinate rather then 0,0..1,1.
     program->SetTexCoordMultiplier(source->GetSize().width, source->GetSize().height);
@@ -1211,16 +1212,17 @@ CompositorOGL::DrawQuad(const Rect& aRec
 
   if (didSetBlendMode) {
     gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
                              LOCAL_GL_ONE, LOCAL_GL_ONE);
   }
 
   // in case rendering has used some other GL context
   MakeCurrent();
+  LayerScope::DrawEnd(mGLContext, aEffectChain, aRect.width, aRect.height);
 }
 
 void
 CompositorOGL::EndFrame()
 {
   PROFILER_LABEL("CompositorOGL", "EndFrame",
     js::ProfileEntry::Category::GRAPHICS);
 
@@ -1472,16 +1474,17 @@ CompositorOGL::BindAndDrawQuads(ShaderPr
   aProg->SetLayerRects(aLayerRects);
   if (aProg->GetTextureCount() > 0) {
     aProg->SetTextureRects(aTextureRects);
   }
 
   // We are using GL_TRIANGLES here because the Mac Intel drivers fail to properly
   // process uniform arrays with GL_TRIANGLE_STRIP. Go figure.
   mGLContext->fDrawArrays(LOCAL_GL_TRIANGLES, 0, 6 * aQuads);
+  LayerScope::SetLayerRects(aQuads, aLayerRects);
 }
 
 GLBlitTextureImageHelper*
 CompositorOGL::BlitTextureImageHelper()
 {
     if (!mBlitTextureImageHelper) {
         mBlitTextureImageHelper = MakeUnique<GLBlitTextureImageHelper>(this);
     }
--- a/gfx/layers/opengl/GrallocTextureHost.cpp
+++ b/gfx/layers/opengl/GrallocTextureHost.cpp
@@ -3,27 +3,29 @@
  * 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 "base/process.h"
 #include "GLContext.h"
 #include "gfx2DGlue.h"
 #include <ui/GraphicBuffer.h>
 #include "GrallocImages.h"  // for GrallocImage
+#include "GLLibraryEGL.h"   // for GLLibraryEGL
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/DataSurfaceHelpers.h"
 #include "mozilla/layers/GrallocTextureHost.h"
 #include "mozilla/layers/SharedBufferManagerParent.h"
 #include "EGLImageHelpers.h"
 #include "GLReadTexImageHelper.h"
 
 namespace mozilla {
 namespace layers {
 
 using namespace android;
+using namespace mozilla::gl;
 
 static gfx::SurfaceFormat
 SurfaceFormatForAndroidPixelFormat(android::PixelFormat aFormat,
                                    TextureFlags aFlags)
 {
   bool swapRB = bool(aFlags & TextureFlags::RB_SWAPPED);
   switch (aFormat) {
   case android::PIXEL_FORMAT_BGRA_8888:
@@ -258,22 +260,16 @@ GrallocTextureHostOGL::UnbindTextureSour
   // detached, Although decreasing the refcount of the TextureSource may lead
   // to the gl handle being destroyed, which would unlock the gralloc buffer.
   // That said, this method is called before another TextureHost attaches to the
   // TextureSource, which has the effect of unlocking the gralloc buffer. So when
   // this is called we know we are going to be unlocked soon.
   mGLTextureSource = nullptr;
 }
 
-FenceHandle
-GrallocTextureHostOGL::GetAndResetReleaseFenceHandle()
-{
-  return GetAndResetReleaseFence();
-}
-
 GLenum GetTextureTarget(gl::GLContext* aGL, android::PixelFormat aFormat) {
   MOZ_ASSERT(aGL);
   if (aGL->Renderer() == gl::GLRenderer::SGX530 ||
       aGL->Renderer() == gl::GLRenderer::SGX540) {
     // SGX has a quirk that only TEXTURE_EXTERNAL works and any other value will
     // result in black pixels when trying to draw from bound textures.
     // Unfortunately, using TEXTURE_EXTERNAL on Adreno has a terrible effect on
     // performance.
@@ -377,16 +373,52 @@ GrallocTextureHostOGL::PrepareTextureSou
 
     gl->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
     glSource->SetSize(mSize);
     glSource->SetFormat(mFormat);
     mGLTextureSource = glSource;
   }
 }
 
+void
+GrallocTextureHostOGL::WaitAcquireFenceHandleSyncComplete()
+{
+  if (!mAcquireFenceHandle.IsValid()) {
+    return;
+  }
+
+  nsRefPtr<FenceHandle::FdObj> fence = mAcquireFenceHandle.GetAndResetFdObj();
+  int fenceFd = fence->GetAndResetFd();
+
+  EGLint attribs[] = {
+              LOCAL_EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd,
+              LOCAL_EGL_NONE
+          };
+
+  EGLSync sync = sEGLLibrary.fCreateSync(EGL_DISPLAY(),
+                                         LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID,
+                                         attribs);
+  if (!sync) {
+    NS_WARNING("failed to create native fence sync");
+    return;
+  }
+
+  // Wait sync complete with timeout.
+  // If a source of the fence becomes invalid because of error,
+  // fene complete is not signaled. See Bug 1061435.
+  EGLint status = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(),
+                                              sync,
+                                              0,
+                                              400000000 /*400 usec*/);
+  if (status != LOCAL_EGL_CONDITION_SATISFIED) {
+    NS_ERROR("failed to wait native fence sync");
+  }
+  MOZ_ALWAYS_TRUE( sEGLLibrary.fDestroySync(EGL_DISPLAY(), sync) );
+}
+
 bool
 GrallocTextureHostOGL::BindTextureSource(CompositableTextureSourceRef& aTextureSource)
 {
   // This happens at composition time.
 
   // If mGLTextureSource is null it means PrepareTextureSource failed.
   if (!mGLTextureSource) {
     return false;
@@ -395,15 +427,15 @@ GrallocTextureHostOGL::BindTextureSource
   // If Prepare didn't fail, we expect our TextureSource to be the same as aTextureSource,
   // otherwise it means something has fiddled with the TextureSource between Prepare and
   // now.
   MOZ_ASSERT(mGLTextureSource == aTextureSource);
   aTextureSource = mGLTextureSource.get();
 
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
   // Wait until it's ready.
-  WaitAcquireFenceSyncComplete();
+  WaitAcquireFenceHandleSyncComplete();
 #endif
   return true;
 }
 
 } // namepsace layers
 } // namepsace mozilla
--- a/gfx/layers/opengl/GrallocTextureHost.h
+++ b/gfx/layers/opengl/GrallocTextureHost.h
@@ -11,17 +11,16 @@
 #include "mozilla/layers/TextureHostOGL.h"
 #include "mozilla/layers/ShadowLayerUtilsGralloc.h"
 #include <ui/GraphicBuffer.h>
 
 namespace mozilla {
 namespace layers {
 
 class GrallocTextureHostOGL : public TextureHost
-                            , public TextureHostOGL
 {
   friend class GrallocBufferActor;
 public:
   GrallocTextureHostOGL(TextureFlags aFlags,
                         const NewSurfaceDescriptorGralloc& aDescriptor);
 
   virtual ~GrallocTextureHostOGL();
 
@@ -46,26 +45,19 @@ public:
   virtual LayerRenderState GetRenderState() override;
 
   virtual void PrepareTextureSource(CompositableTextureSourceRef& aTextureSource) override;
 
   virtual bool BindTextureSource(CompositableTextureSourceRef& aTextureSource) override;
 
   virtual void UnbindTextureSource() override;
 
-  virtual FenceHandle GetAndResetReleaseFenceHandle() override;
+  virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() override;
 
-#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
-  virtual TextureHostOGL* AsHostOGL() override
-  {
-    return this;
-  }
-#endif
-
-  virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() override;
+  virtual void WaitAcquireFenceHandleSyncComplete() override;
 
   bool IsValid() const;
 
   virtual const char* Name() override { return "GrallocTextureHostOGL"; }
 
   gl::GLContext* GetGLContext() const { return mCompositor ? mCompositor->gl() : nullptr; }
 
 private:
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -106,87 +106,16 @@ FlagsToGLFlags(TextureFlags aFlags)
     result |= TextureImage::OriginBottomLeft;
   if (aFlags & TextureFlags::DISALLOW_BIGIMAGE)
     result |= TextureImage::DisallowBigImage;
 
   return static_cast<gl::TextureImage::Flags>(result);
 }
 
 bool
-TextureHostOGL::SetReleaseFence(const FenceHandle& aReleaseFence)
-{
-  if (!aReleaseFence.IsValid()) {
-    // HWC might not provide Fence.
-    // In this case, HWC implicitly handles buffer's fence.
-    return false;
-  }
-
-  mReleaseFence.Merge(aReleaseFence);
-
-  return true;
-}
-
-FenceHandle
-TextureHostOGL::GetAndResetReleaseFence()
-{
-  FenceHandle fence;
-  mReleaseFence.TransferToAnotherFenceHandle(fence);
-  return fence;
-}
-
-void
-TextureHostOGL::SetAcquireFence(const FenceHandle& aAcquireFence)
-{
-  mAcquireFence = aAcquireFence;
-}
-
-FenceHandle
-TextureHostOGL::GetAndResetAcquireFence()
-{
-  nsRefPtr<FenceHandle::FdObj> fdObj = mAcquireFence.GetAndResetFdObj();
-  return FenceHandle(fdObj);
-}
-
-void
-TextureHostOGL::WaitAcquireFenceSyncComplete()
-{
-  if (!mAcquireFence.IsValid()) {
-    return;
-  }
-
-  nsRefPtr<FenceHandle::FdObj> fence = mAcquireFence.GetAndResetFdObj();
-  int fenceFd = fence->GetAndResetFd();
-
-  EGLint attribs[] = {
-              LOCAL_EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd,
-              LOCAL_EGL_NONE
-          };
-
-  EGLSync sync = sEGLLibrary.fCreateSync(EGL_DISPLAY(),
-                                         LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID,
-                                         attribs);
-  if (!sync) {
-    NS_WARNING("failed to create native fence sync");
-    return;
-  }
-
-  // Wait sync complete with timeout.
-  // If a source of the fence becomes invalid because of error,
-  // fene complete is not signaled. See Bug 1061435.
-  EGLint status = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(),
-                                              sync,
-                                              0,
-                                              400000000 /*400 usec*/);
-  if (status != LOCAL_EGL_CONDITION_SATISFIED) {
-    NS_ERROR("failed to wait native fence sync");
-  }
-  MOZ_ALWAYS_TRUE( sEGLLibrary.fDestroySync(EGL_DISPLAY(), sync) );
-}
-
-bool
 TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface,
                                      nsIntRegion* aDestRegion,
                                      gfx::IntPoint* aSrcOffset)
 {
   GLContext *gl = mCompositor->gl();
   MOZ_ASSERT(gl);
   if (!gl) {
     NS_WARNING("trying to update TextureImageTextureSourceOGL without a GLContext");
--- a/gfx/layers/opengl/TextureHostOGL.h
+++ b/gfx/layers/opengl/TextureHostOGL.h
@@ -118,48 +118,16 @@ public:
   void ClearCachedFilter() { mHasCachedFilter = false; }
 
 private:
   gfx::Filter mCachedFilter;
   bool mHasCachedFilter;
 };
 
 /**
- * TextureHostOGL provides the necessary API for platform specific composition.
- */
-class TextureHostOGL
-{
-public:
-  /**
-   * Store a fence that will signal when the current buffer is no longer being read.
-   * Similar to android's GLConsumer::setReleaseFence()
-   */
-  virtual bool SetReleaseFence(const FenceHandle& aReleaseFence);
-
-  /**
-   * Return a releaseFence's Fence and clear a reference to the Fence.
-   */
-  virtual FenceHandle GetAndResetReleaseFence();
-
-  virtual void SetAcquireFence(const FenceHandle& aAcquireFence);
-
-  /**
-   * Return a acquireFence's Fence and clear a reference to the Fence.
-   */
-  virtual FenceHandle GetAndResetAcquireFence();
-
-  virtual void WaitAcquireFenceSyncComplete();
-
-protected:
-  FenceHandle mReleaseFence;
-
-  FenceHandle mAcquireFence;
-};
-
-/**
  * A TextureSource backed by a TextureImage.
  *
  * Depending on the underlying TextureImage, may support texture tiling, so
  * make sure to check AsBigImageIterator() and use the texture accordingly.
  *
  * This TextureSource can be used without a TextureHost and manage it's own
  * GL texture(s).
  */
--- a/gfx/layers/protobuf/LayerScopePacket.pb.cc
+++ b/gfx/layers/protobuf/LayerScopePacket.pb.cc
@@ -21,16 +21,18 @@ void protobuf_ShutdownFile_LayerScopePac
   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_;
+  delete DrawPacket::default_instance_;
+  delete DrawPacket_Rect::default_instance_;
   delete Packet::default_instance_;
   delete CommandPacket::default_instance_;
 }
 
 void protobuf_AddDesc_LayerScopePacket_2eproto() {
   static bool already_here = false;
   if (already_here) return;
   already_here = true;
@@ -42,29 +44,33 @@ void protobuf_AddDesc_LayerScopePacket_2
   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();
   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();
+  DrawPacket::default_instance_->InitAsDefaultInstance();
+  DrawPacket_Rect::default_instance_->InitAsDefaultInstance();
   Packet::default_instance_->InitAsDefaultInstance();
   CommandPacket::default_instance_->InitAsDefaultInstance();
   ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_LayerScopePacket_2eproto);
 }
 
 // Force AddDescriptors() to be called at static initialization time.
 struct StaticDescriptorInitializer_LayerScopePacket_2eproto {
   StaticDescriptorInitializer_LayerScopePacket_2eproto() {
@@ -3187,91 +3193,688 @@ void MetaPacket::Swap(MetaPacket* other)
 
 ::std::string MetaPacket::GetTypeName() const {
   return "mozilla.layers.layerscope.MetaPacket";
 }
 
 
 // ===================================================================
 
+#ifndef _MSC_VER
+const int DrawPacket_Rect::kXFieldNumber;
+const int DrawPacket_Rect::kYFieldNumber;
+const int DrawPacket_Rect::kWFieldNumber;
+const int DrawPacket_Rect::kHFieldNumber;
+#endif  // !_MSC_VER
+
+DrawPacket_Rect::DrawPacket_Rect()
+  : ::google::protobuf::MessageLite() {
+  SharedCtor();
+}
+
+void DrawPacket_Rect::InitAsDefaultInstance() {
+}
+
+DrawPacket_Rect::DrawPacket_Rect(const DrawPacket_Rect& from)
+  : ::google::protobuf::MessageLite() {
+  SharedCtor();
+  MergeFrom(from);
+}
+
+void DrawPacket_Rect::SharedCtor() {
+  _cached_size_ = 0;
+  x_ = 0;
+  y_ = 0;
+  w_ = 0;
+  h_ = 0;
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+DrawPacket_Rect::~DrawPacket_Rect() {
+  SharedDtor();
+}
+
+void DrawPacket_Rect::SharedDtor() {
+  if (this != default_instance_) {
+  }
+}
+
+void DrawPacket_Rect::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const DrawPacket_Rect& DrawPacket_Rect::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_LayerScopePacket_2eproto();  return *default_instance_;
+}
+
+DrawPacket_Rect* DrawPacket_Rect::default_instance_ = NULL;
+
+DrawPacket_Rect* DrawPacket_Rect::New() const {
+  return new DrawPacket_Rect;
+}
+
+void DrawPacket_Rect::Clear() {
+  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    x_ = 0;
+    y_ = 0;
+    w_ = 0;
+    h_ = 0;
+  }
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+bool DrawPacket_Rect::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+  ::google::protobuf::uint32 tag;
+  while ((tag = input->ReadTag()) != 0) {
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // required float x = 1;
+      case 1: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_FIXED32) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &x_)));
+          set_has_x();
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(21)) goto parse_y;
+        break;
+      }
+      
+      // required float y = 2;
+      case 2: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_FIXED32) {
+         parse_y:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &y_)));
+          set_has_y();
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(29)) goto parse_w;
+        break;
+      }
+      
+      // required float w = 3;
+      case 3: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_FIXED32) {
+         parse_w:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &w_)));
+          set_has_w();
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(37)) goto parse_h;
+        break;
+      }
+      
+      // required float h = 4;
+      case 4: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_FIXED32) {
+         parse_h:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &h_)));
+          set_has_h();
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectAtEnd()) return true;
+        break;
+      }
+      
+      default: {
+      handle_uninterpreted:
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          return true;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+  return true;
+#undef DO_
+}
+
+void DrawPacket_Rect::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // required float x = 1;
+  if (has_x()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(1, this->x(), output);
+  }
+  
+  // required float y = 2;
+  if (has_y()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(2, this->y(), output);
+  }
+  
+  // required float w = 3;
+  if (has_w()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(3, this->w(), output);
+  }
+  
+  // required float h = 4;
+  if (has_h()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(4, this->h(), output);
+  }
+  
+}
+
+int DrawPacket_Rect::ByteSize() const {
+  int total_size = 0;
+  
+  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    // required float x = 1;
+    if (has_x()) {
+      total_size += 1 + 4;
+    }
+    
+    // required float y = 2;
+    if (has_y()) {
+      total_size += 1 + 4;
+    }
+    
+    // required float w = 3;
+    if (has_w()) {
+      total_size += 1 + 4;
+    }
+    
+    // required float h = 4;
+    if (has_h()) {
+      total_size += 1 + 4;
+    }
+    
+  }
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void DrawPacket_Rect::CheckTypeAndMergeFrom(
+    const ::google::protobuf::MessageLite& from) {
+  MergeFrom(*::google::protobuf::down_cast<const DrawPacket_Rect*>(&from));
+}
+
+void DrawPacket_Rect::MergeFrom(const DrawPacket_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());
+    }
+  }
+}
+
+void DrawPacket_Rect::CopyFrom(const DrawPacket_Rect& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool DrawPacket_Rect::IsInitialized() const {
+  if ((_has_bits_[0] & 0x0000000f) != 0x0000000f) return false;
+  
+  return true;
+}
+
+void DrawPacket_Rect::Swap(DrawPacket_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]);
+    std::swap(_cached_size_, other->_cached_size_);
+  }
+}
+
+::std::string DrawPacket_Rect::GetTypeName() const {
+  return "mozilla.layers.layerscope.DrawPacket.Rect";
+}
+
+
+// -------------------------------------------------------------------
+
+#ifndef _MSC_VER
+const int DrawPacket::kOffsetXFieldNumber;
+const int DrawPacket::kOffsetYFieldNumber;
+const int DrawPacket::kMvMatrixFieldNumber;
+const int DrawPacket::kTotalRectsFieldNumber;
+const int DrawPacket::kLayerRectFieldNumber;
+const int DrawPacket::kLayerrefFieldNumber;
+#endif  // !_MSC_VER
+
+DrawPacket::DrawPacket()
+  : ::google::protobuf::MessageLite() {
+  SharedCtor();
+}
+
+void DrawPacket::InitAsDefaultInstance() {
+}
+
+DrawPacket::DrawPacket(const DrawPacket& from)
+  : ::google::protobuf::MessageLite() {
+  SharedCtor();
+  MergeFrom(from);
+}
+
+void DrawPacket::SharedCtor() {
+  _cached_size_ = 0;
+  offsetx_ = 0;
+  offsety_ = 0;
+  totalrects_ = 0u;
+  layerref_ = GOOGLE_ULONGLONG(0);
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+DrawPacket::~DrawPacket() {
+  SharedDtor();
+}
+
+void DrawPacket::SharedDtor() {
+  if (this != default_instance_) {
+  }
+}
+
+void DrawPacket::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const DrawPacket& DrawPacket::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_LayerScopePacket_2eproto();  return *default_instance_;
+}
+
+DrawPacket* DrawPacket::default_instance_ = NULL;
+
+DrawPacket* DrawPacket::New() const {
+  return new DrawPacket;
+}
+
+void DrawPacket::Clear() {
+  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    offsetx_ = 0;
+    offsety_ = 0;
+    totalrects_ = 0u;
+    layerref_ = GOOGLE_ULONGLONG(0);
+  }
+  mvmatrix_.Clear();
+  layerrect_.Clear();
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+bool DrawPacket::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+  ::google::protobuf::uint32 tag;
+  while ((tag = input->ReadTag()) != 0) {
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // required float offsetX = 1;
+      case 1: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_FIXED32) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &offsetx_)));
+          set_has_offsetx();
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(21)) goto parse_offsetY;
+        break;
+      }
+      
+      // required float offsetY = 2;
+      case 2: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_FIXED32) {
+         parse_offsetY:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &offsety_)));
+          set_has_offsety();
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(29)) goto parse_mvMatrix;
+        break;
+      }
+      
+      // repeated float mvMatrix = 3;
+      case 3: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_FIXED32) {
+         parse_mvMatrix:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 1, 29, input, this->mutable_mvmatrix())));
+        } else if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag)
+                   == ::google::protobuf::internal::WireFormatLite::
+                      WIRETYPE_LENGTH_DELIMITED) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, this->mutable_mvmatrix())));
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(29)) goto parse_mvMatrix;
+        if (input->ExpectTag(32)) goto parse_totalRects;
+        break;
+      }
+      
+      // required uint32 totalRects = 4;
+      case 4: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+         parse_totalRects:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &totalrects_)));
+          set_has_totalrects();
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(42)) goto parse_layerRect;
+        break;
+      }
+      
+      // repeated .mozilla.layers.layerscope.DrawPacket.Rect layerRect = 5;
+      case 5: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+         parse_layerRect:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+                input, add_layerrect()));
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(42)) goto parse_layerRect;
+        if (input->ExpectTag(48)) goto parse_layerref;
+        break;
+      }
+      
+      // required uint64 layerref = 6;
+      case 6: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+         parse_layerref:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>(
+                 input, &layerref_)));
+          set_has_layerref();
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectAtEnd()) return true;
+        break;
+      }
+      
+      default: {
+      handle_uninterpreted:
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          return true;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+  return true;
+#undef DO_
+}
+
+void DrawPacket::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // required float offsetX = 1;
+  if (has_offsetx()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(1, this->offsetx(), output);
+  }
+  
+  // required float offsetY = 2;
+  if (has_offsety()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(2, this->offsety(), output);
+  }
+  
+  // repeated float mvMatrix = 3;
+  for (int i = 0; i < this->mvmatrix_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(
+      3, this->mvmatrix(i), output);
+  }
+  
+  // required uint32 totalRects = 4;
+  if (has_totalrects()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(4, this->totalrects(), output);
+  }
+  
+  // repeated .mozilla.layers.layerscope.DrawPacket.Rect layerRect = 5;
+  for (int i = 0; i < this->layerrect_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessage(
+      5, this->layerrect(i), output);
+  }
+  
+  // required uint64 layerref = 6;
+  if (has_layerref()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt64(6, this->layerref(), output);
+  }
+  
+}
+
+int DrawPacket::ByteSize() const {
+  int total_size = 0;
+  
+  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    // required float offsetX = 1;
+    if (has_offsetx()) {
+      total_size += 1 + 4;
+    }
+    
+    // required float offsetY = 2;
+    if (has_offsety()) {
+      total_size += 1 + 4;
+    }
+    
+    // required uint32 totalRects = 4;
+    if (has_totalrects()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->totalrects());
+    }
+    
+    // required uint64 layerref = 6;
+    if (has_layerref()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt64Size(
+          this->layerref());
+    }
+    
+  }
+  // repeated float mvMatrix = 3;
+  {
+    int data_size = 0;
+    data_size = 4 * this->mvmatrix_size();
+    total_size += 1 * this->mvmatrix_size() + data_size;
+  }
+  
+  // repeated .mozilla.layers.layerscope.DrawPacket.Rect layerRect = 5;
+  total_size += 1 * this->layerrect_size();
+  for (int i = 0; i < this->layerrect_size(); i++) {
+    total_size +=
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        this->layerrect(i));
+  }
+  
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void DrawPacket::CheckTypeAndMergeFrom(
+    const ::google::protobuf::MessageLite& from) {
+  MergeFrom(*::google::protobuf::down_cast<const DrawPacket*>(&from));
+}
+
+void DrawPacket::MergeFrom(const DrawPacket& from) {
+  GOOGLE_CHECK_NE(&from, this);
+  mvmatrix_.MergeFrom(from.mvmatrix_);
+  layerrect_.MergeFrom(from.layerrect_);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_offsetx()) {
+      set_offsetx(from.offsetx());
+    }
+    if (from.has_offsety()) {
+      set_offsety(from.offsety());
+    }
+    if (from.has_totalrects()) {
+      set_totalrects(from.totalrects());
+    }
+    if (from.has_layerref()) {
+      set_layerref(from.layerref());
+    }
+  }
+}
+
+void DrawPacket::CopyFrom(const DrawPacket& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool DrawPacket::IsInitialized() const {
+  if ((_has_bits_[0] & 0x0000002b) != 0x0000002b) return false;
+  
+  for (int i = 0; i < layerrect_size(); i++) {
+    if (!this->layerrect(i).IsInitialized()) return false;
+  }
+  return true;
+}
+
+void DrawPacket::Swap(DrawPacket* other) {
+  if (other != this) {
+    std::swap(offsetx_, other->offsetx_);
+    std::swap(offsety_, other->offsety_);
+    mvmatrix_.Swap(&other->mvmatrix_);
+    std::swap(totalrects_, other->totalrects_);
+    layerrect_.Swap(&other->layerrect_);
+    std::swap(layerref_, other->layerref_);
+    std::swap(_has_bits_[0], other->_has_bits_[0]);
+    std::swap(_cached_size_, other->_cached_size_);
+  }
+}
+
+::std::string DrawPacket::GetTypeName() const {
+  return "mozilla.layers.layerscope.DrawPacket";
+}
+
+
+// ===================================================================
+
 bool Packet_DataType_IsValid(int value) {
   switch(value) {
     case 1:
     case 2:
     case 3:
     case 4:
     case 5:
     case 6:
+    case 7:
       return true;
     default:
       return false;
   }
 }
 
 #ifndef _MSC_VER
 const Packet_DataType Packet::FRAMESTART;
 const Packet_DataType Packet::FRAMEEND;
 const Packet_DataType Packet::COLOR;
 const Packet_DataType Packet::TEXTURE;
 const Packet_DataType Packet::LAYERS;
 const Packet_DataType Packet::META;
+const Packet_DataType Packet::DRAW;
 const Packet_DataType Packet::DataType_MIN;
 const Packet_DataType Packet::DataType_MAX;
 const int Packet::DataType_ARRAYSIZE;
 #endif  // _MSC_VER
 #ifndef _MSC_VER
 const int Packet::kTypeFieldNumber;
 const int Packet::kFrameFieldNumber;
 const int Packet::kColorFieldNumber;
 const int Packet::kTextureFieldNumber;
 const int Packet::kLayersFieldNumber;
 const int Packet::kMetaFieldNumber;
+const int Packet::kDrawFieldNumber;
 #endif  // !_MSC_VER
 
 Packet::Packet()
   : ::google::protobuf::MessageLite() {
   SharedCtor();
 }
 
 void Packet::InitAsDefaultInstance() {
   frame_ = const_cast< ::mozilla::layers::layerscope::FramePacket*>(&::mozilla::layers::layerscope::FramePacket::default_instance());
   color_ = const_cast< ::mozilla::layers::layerscope::ColorPacket*>(&::mozilla::layers::layerscope::ColorPacket::default_instance());
   texture_ = const_cast< ::mozilla::layers::layerscope::TexturePacket*>(&::mozilla::layers::layerscope::TexturePacket::default_instance());
   layers_ = const_cast< ::mozilla::layers::layerscope::LayersPacket*>(&::mozilla::layers::layerscope::LayersPacket::default_instance());
   meta_ = const_cast< ::mozilla::layers::layerscope::MetaPacket*>(&::mozilla::layers::layerscope::MetaPacket::default_instance());
+  draw_ = const_cast< ::mozilla::layers::layerscope::DrawPacket*>(&::mozilla::layers::layerscope::DrawPacket::default_instance());
 }
 
 Packet::Packet(const Packet& from)
   : ::google::protobuf::MessageLite() {
   SharedCtor();
   MergeFrom(from);
 }
 
 void Packet::SharedCtor() {
   _cached_size_ = 0;
   type_ = 1;
   frame_ = NULL;
   color_ = NULL;
   texture_ = NULL;
   layers_ = NULL;
   meta_ = NULL;
+  draw_ = NULL;
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
 
 Packet::~Packet() {
   SharedDtor();
 }
 
 void Packet::SharedDtor() {
   if (this != default_instance_) {
     delete frame_;
     delete color_;
     delete texture_;
     delete layers_;
     delete meta_;
+    delete draw_;
   }
 }
 
 void Packet::SetCachedSize(int size) const {
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = size;
   GOOGLE_SAFE_CONCURRENT_WRITES_END();
 }
@@ -3298,16 +3901,19 @@ void Packet::Clear() {
       if (texture_ != NULL) texture_->::mozilla::layers::layerscope::TexturePacket::Clear();
     }
     if (has_layers()) {
       if (layers_ != NULL) layers_->::mozilla::layers::layerscope::LayersPacket::Clear();
     }
     if (has_meta()) {
       if (meta_ != NULL) meta_->::mozilla::layers::layerscope::MetaPacket::Clear();
     }
+    if (has_draw()) {
+      if (draw_ != NULL) draw_->::mozilla::layers::layerscope::DrawPacket::Clear();
+    }
   }
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
 
 bool Packet::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
 #define DO_(EXPRESSION) if (!(EXPRESSION)) return false
   ::google::protobuf::uint32 tag;
@@ -3392,16 +3998,30 @@ bool Packet::MergePartialFromCodedStream
         if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
             ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
          parse_meta:
           DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
                input, mutable_meta()));
         } else {
           goto handle_uninterpreted;
         }
+        if (input->ExpectTag(58)) goto parse_draw;
+        break;
+      }
+      
+      // optional .mozilla.layers.layerscope.DrawPacket draw = 7;
+      case 7: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+         parse_draw:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_draw()));
+        } else {
+          goto handle_uninterpreted;
+        }
         if (input->ExpectAtEnd()) return true;
         break;
       }
       
       default: {
       handle_uninterpreted:
         if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
             ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
@@ -3449,16 +4069,22 @@ void Packet::SerializeWithCachedSizes(
   }
   
   // optional .mozilla.layers.layerscope.MetaPacket meta = 6;
   if (has_meta()) {
     ::google::protobuf::internal::WireFormatLite::WriteMessage(
       6, this->meta(), output);
   }
   
+  // optional .mozilla.layers.layerscope.DrawPacket draw = 7;
+  if (has_draw()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessage(
+      7, this->draw(), output);
+  }
+  
 }
 
 int Packet::ByteSize() const {
   int total_size = 0;
   
   if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     // required .mozilla.layers.layerscope.Packet.DataType type = 1;
     if (has_type()) {
@@ -3496,16 +4122,23 @@ int Packet::ByteSize() const {
     
     // optional .mozilla.layers.layerscope.MetaPacket meta = 6;
     if (has_meta()) {
       total_size += 1 +
         ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
           this->meta());
     }
     
+    // optional .mozilla.layers.layerscope.DrawPacket draw = 7;
+    if (has_draw()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->draw());
+    }
+    
   }
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = total_size;
   GOOGLE_SAFE_CONCURRENT_WRITES_END();
   return total_size;
 }
 
 void Packet::CheckTypeAndMergeFrom(
@@ -3529,16 +4162,19 @@ void Packet::MergeFrom(const Packet& fro
       mutable_texture()->::mozilla::layers::layerscope::TexturePacket::MergeFrom(from.texture());
     }
     if (from.has_layers()) {
       mutable_layers()->::mozilla::layers::layerscope::LayersPacket::MergeFrom(from.layers());
     }
     if (from.has_meta()) {
       mutable_meta()->::mozilla::layers::layerscope::MetaPacket::MergeFrom(from.meta());
     }
+    if (from.has_draw()) {
+      mutable_draw()->::mozilla::layers::layerscope::DrawPacket::MergeFrom(from.draw());
+    }
   }
 }
 
 void Packet::CopyFrom(const Packet& from) {
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
@@ -3550,27 +4186,31 @@ bool Packet::IsInitialized() const {
     if (!this->color().IsInitialized()) return false;
   }
   if (has_texture()) {
     if (!this->texture().IsInitialized()) return false;
   }
   if (has_layers()) {
     if (!this->layers().IsInitialized()) return false;
   }
+  if (has_draw()) {
+    if (!this->draw().IsInitialized()) return false;
+  }
   return true;
 }
 
 void Packet::Swap(Packet* other) {
   if (other != this) {
     std::swap(type_, other->type_);
     std::swap(frame_, other->frame_);
     std::swap(color_, other->color_);
     std::swap(texture_, other->texture_);
     std::swap(layers_, other->layers_);
     std::swap(meta_, other->meta_);
+    std::swap(draw_, other->draw_);
     std::swap(_has_bits_[0], other->_has_bits_[0]);
     std::swap(_cached_size_, other->_cached_size_);
   }
 }
 
 ::std::string Packet::GetTypeName() const {
   return "mozilla.layers.layerscope.Packet";
 }
--- a/gfx/layers/protobuf/LayerScopePacket.pb.h
+++ b/gfx/layers/protobuf/LayerScopePacket.pb.h
@@ -39,16 +39,18 @@ class TexturePacket;
 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 LayersPacket_Layer_LayerType {
   LayersPacket_Layer_LayerType_UnknownLayer = 0,
   LayersPacket_Layer_LayerType_LayerManager = 1,
   LayersPacket_Layer_LayerType_ContainerLayer = 2,
   LayersPacket_Layer_LayerType_PaintedLayer = 3,
@@ -87,21 +89,22 @@ const LayersPacket_Layer_Filter LayersPa
 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
+  Packet_DataType_META = 6,
+  Packet_DataType_DRAW = 7
 };
 bool Packet_DataType_IsValid(int value);
 const Packet_DataType Packet_DataType_DataType_MIN = Packet_DataType_FRAMESTART;
-const Packet_DataType Packet_DataType_DataType_MAX = Packet_DataType_META;
+const Packet_DataType Packet_DataType_DataType_MAX = Packet_DataType_DRAW;
 const int Packet_DataType_DataType_ARRAYSIZE = Packet_DataType_DataType_MAX + 1;
 
 enum CommandPacket_CmdType {
   CommandPacket_CmdType_NO_OP = 0,
   CommandPacket_CmdType_LAYERS_TREE = 1,
   CommandPacket_CmdType_LAYERS_BUFFER = 2
 };
 bool CommandPacket_CmdType_IsValid(int value);
@@ -1306,16 +1309,242 @@ class MetaPacket : public ::google::prot
   friend void protobuf_AssignDesc_LayerScopePacket_2eproto();
   friend void protobuf_ShutdownFile_LayerScopePacket_2eproto();
   
   void InitAsDefaultInstance();
   static MetaPacket* default_instance_;
 };
 // -------------------------------------------------------------------
 
+class DrawPacket_Rect : public ::google::protobuf::MessageLite {
+ public:
+  DrawPacket_Rect();
+  virtual ~DrawPacket_Rect();
+  
+  DrawPacket_Rect(const DrawPacket_Rect& from);
+  
+  inline DrawPacket_Rect& operator=(const DrawPacket_Rect& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  
+  static const DrawPacket_Rect& default_instance();
+  
+  void Swap(DrawPacket_Rect* other);
+  
+  // implements Message ----------------------------------------------
+  
+  DrawPacket_Rect* New() const;
+  void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from);
+  void CopyFrom(const DrawPacket_Rect& from);
+  void MergeFrom(const DrawPacket_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;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  public:
+  
+  ::std::string GetTypeName() const;
+  
+  // nested types ----------------------------------------------------
+  
+  // accessors -------------------------------------------------------
+  
+  // required 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);
+  
+  // required 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);
+  
+  // required 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);
+  
+  // required 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.DrawPacket.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();
+  
+  float x_;
+  float y_;
+  float w_;
+  float h_;
+  
+  mutable int _cached_size_;
+  ::google::protobuf::uint32 _has_bits_[(4 + 31) / 32];
+  
+  friend void  protobuf_AddDesc_LayerScopePacket_2eproto();
+  friend void protobuf_AssignDesc_LayerScopePacket_2eproto();
+  friend void protobuf_ShutdownFile_LayerScopePacket_2eproto();
+  
+  void InitAsDefaultInstance();
+  static DrawPacket_Rect* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class DrawPacket : public ::google::protobuf::MessageLite {
+ public:
+  DrawPacket();
+  virtual ~DrawPacket();
+  
+  DrawPacket(const DrawPacket& from);
+  
+  inline DrawPacket& operator=(const DrawPacket& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  
+  static const DrawPacket& default_instance();
+  
+  void Swap(DrawPacket* other);
+  
+  // implements Message ----------------------------------------------
+  
+  DrawPacket* New() const;
+  void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from);
+  void CopyFrom(const DrawPacket& from);
+  void MergeFrom(const DrawPacket& from);
+  void Clear();
+  bool IsInitialized() const;
+  
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  public:
+  
+  ::std::string GetTypeName() const;
+  
+  // nested types ----------------------------------------------------
+  
+  typedef DrawPacket_Rect Rect;
+  
+  // accessors -------------------------------------------------------
+  
+  // required float offsetX = 1;
+  inline bool has_offsetx() const;
+  inline void clear_offsetx();
+  static const int kOffsetXFieldNumber = 1;
+  inline float offsetx() const;
+  inline void set_offsetx(float value);
+  
+  // required float offsetY = 2;
+  inline bool has_offsety() const;
+  inline void clear_offsety();
+  static const int kOffsetYFieldNumber = 2;
+  inline float offsety() const;
+  inline void set_offsety(float value);
+  
+  // repeated float mvMatrix = 3;
+  inline int mvmatrix_size() const;
+  inline void clear_mvmatrix();
+  static const int kMvMatrixFieldNumber = 3;
+  inline float mvmatrix(int index) const;
+  inline void set_mvmatrix(int index, float value);
+  inline void add_mvmatrix(float value);
+  inline const ::google::protobuf::RepeatedField< float >&
+      mvmatrix() const;
+  inline ::google::protobuf::RepeatedField< float >*
+      mutable_mvmatrix();
+  
+  // required uint32 totalRects = 4;
+  inline bool has_totalrects() const;
+  inline void clear_totalrects();
+  static const int kTotalRectsFieldNumber = 4;
+  inline ::google::protobuf::uint32 totalrects() const;
+  inline void set_totalrects(::google::protobuf::uint32 value);
+  
+  // repeated .mozilla.layers.layerscope.DrawPacket.Rect layerRect = 5;
+  inline int layerrect_size() const;
+  inline void clear_layerrect();
+  static const int kLayerRectFieldNumber = 5;
+  inline const ::mozilla::layers::layerscope::DrawPacket_Rect& layerrect(int index) const;
+  inline ::mozilla::layers::layerscope::DrawPacket_Rect* mutable_layerrect(int index);
+  inline ::mozilla::layers::layerscope::DrawPacket_Rect* add_layerrect();
+  inline const ::google::protobuf::RepeatedPtrField< ::mozilla::layers::layerscope::DrawPacket_Rect >&
+      layerrect() const;
+  inline ::google::protobuf::RepeatedPtrField< ::mozilla::layers::layerscope::DrawPacket_Rect >*
+      mutable_layerrect();
+  
+  // required uint64 layerref = 6;
+  inline bool has_layerref() const;
+  inline void clear_layerref();
+  static const int kLayerrefFieldNumber = 6;
+  inline ::google::protobuf::uint64 layerref() const;
+  inline void set_layerref(::google::protobuf::uint64 value);
+  
+  // @@protoc_insertion_point(class_scope:mozilla.layers.layerscope.DrawPacket)
+ private:
+  inline void set_has_offsetx();
+  inline void clear_has_offsetx();
+  inline void set_has_offsety();
+  inline void clear_has_offsety();
+  inline void set_has_totalrects();
+  inline void clear_has_totalrects();
+  inline void set_has_layerref();
+  inline void clear_has_layerref();
+  
+  float offsetx_;
+  float offsety_;
+  ::google::protobuf::RepeatedField< float > mvmatrix_;
+  ::google::protobuf::RepeatedPtrField< ::mozilla::layers::layerscope::DrawPacket_Rect > layerrect_;
+  ::google::protobuf::uint64 layerref_;
+  ::google::protobuf::uint32 totalrects_;
+  
+  mutable int _cached_size_;
+  ::google::protobuf::uint32 _has_bits_[(6 + 31) / 32];
+  
+  friend void  protobuf_AddDesc_LayerScopePacket_2eproto();
+  friend void protobuf_AssignDesc_LayerScopePacket_2eproto();
+  friend void protobuf_ShutdownFile_LayerScopePacket_2eproto();
+  
+  void InitAsDefaultInstance();
+  static DrawPacket* default_instance_;
+};
+// -------------------------------------------------------------------
+
 class Packet : public ::google::protobuf::MessageLite {
  public:
   Packet();
   virtual ~Packet();
   
   Packet(const Packet& from);
   
   inline Packet& operator=(const Packet& from) {
@@ -1354,16 +1583,17 @@ class Packet : public ::google::protobuf
   
   typedef Packet_DataType DataType;
   static const DataType FRAMESTART = Packet_DataType_FRAMESTART;
   static const DataType FRAMEEND = Packet_DataType_FRAMEEND;
   static const DataType COLOR = Packet_DataType_COLOR;
   static const DataType TEXTURE = Packet_DataType_TEXTURE;
   static const DataType LAYERS = Packet_DataType_LAYERS;
   static const DataType META = Packet_DataType_META;
+  static const DataType DRAW = Packet_DataType_DRAW;
   static inline bool DataType_IsValid(int value) {
     return Packet_DataType_IsValid(value);
   }
   static const DataType DataType_MIN =
     Packet_DataType_DataType_MIN;
   static const DataType DataType_MAX =
     Packet_DataType_DataType_MAX;
   static const int DataType_ARRAYSIZE =
@@ -1413,40 +1643,51 @@ class Packet : public ::google::protobuf
   // optional .mozilla.layers.layerscope.MetaPacket meta = 6;
   inline bool has_meta() const;
   inline void clear_meta();
   static const int kMetaFieldNumber = 6;
   inline const ::mozilla::layers::layerscope::MetaPacket& meta() const;
   inline ::mozilla::layers::layerscope::MetaPacket* mutable_meta();
   inline ::mozilla::layers::layerscope::MetaPacket* release_meta();
   
+  // optional .mozilla.layers.layerscope.DrawPacket draw = 7;
+  inline bool has_draw() const;
+  inline void clear_draw();
+  static const int kDrawFieldNumber = 7;
+  inline const ::mozilla::layers::layerscope::DrawPacket& draw() const;
+  inline ::mozilla::layers::layerscope::DrawPacket* mutable_draw();
+  inline ::mozilla::layers::layerscope::DrawPacket* release_draw();
+  
   // @@protoc_insertion_point(class_scope:mozilla.layers.layerscope.Packet)
  private:
   inline void set_has_type();
   inline void clear_has_type();
   inline void set_has_frame();
   inline void clear_has_frame();
   inline void set_has_color();
   inline void clear_has_color();
   inline void set_has_texture();
   inline void clear_has_texture();
   inline void set_has_layers();
   inline void clear_has_layers();
   inline void set_has_meta();
   inline void clear_has_meta();
+  inline void set_has_draw();
+  inline void clear_has_draw();
   
   ::mozilla::layers::layerscope::FramePacket* frame_;
   ::mozilla::layers::layerscope::ColorPacket* color_;
   ::mozilla::layers::layerscope::TexturePacket* texture_;
   ::mozilla::layers::layerscope::LayersPacket* layers_;
   ::mozilla::layers::layerscope::MetaPacket* meta_;
+  ::mozilla::layers::layerscope::DrawPacket* draw_;
   int type_;
   
   mutable int _cached_size_;
-  ::google::protobuf::uint32 _has_bits_[(6 + 31) / 32];
+  ::google::protobuf::uint32 _has_bits_[(7 + 31) / 32];
   
   friend void  protobuf_AddDesc_LayerScopePacket_2eproto();
   friend void protobuf_AssignDesc_LayerScopePacket_2eproto();
   friend void protobuf_ShutdownFile_LayerScopePacket_2eproto();
   
   void InitAsDefaultInstance();
   static Packet* default_instance_;
 };
@@ -2732,16 +2973,250 @@ inline bool MetaPacket::composedbyhwc() 
 }
 inline void MetaPacket::set_composedbyhwc(bool value) {
   set_has_composedbyhwc();
   composedbyhwc_ = value;
 }
 
 // -------------------------------------------------------------------
 
+// DrawPacket_Rect
+
+// required float x = 1;
+inline bool DrawPacket_Rect::has_x() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void DrawPacket_Rect::set_has_x() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void DrawPacket_Rect::clear_has_x() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void DrawPacket_Rect::clear_x() {
+  x_ = 0;
+  clear_has_x();
+}
+inline float DrawPacket_Rect::x() const {
+  return x_;
+}
+inline void DrawPacket_Rect::set_x(float value) {
+  set_has_x();
+  x_ = value;
+}
+
+// required float y = 2;
+inline bool DrawPacket_Rect::has_y() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void DrawPacket_Rect::set_has_y() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void DrawPacket_Rect::clear_has_y() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void DrawPacket_Rect::clear_y() {
+  y_ = 0;
+  clear_has_y();
+}
+inline float DrawPacket_Rect::y() const {
+  return y_;
+}
+inline void DrawPacket_Rect::set_y(float value) {
+  set_has_y();
+  y_ = value;
+}
+
+// required float w = 3;
+inline bool DrawPacket_Rect::has_w() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void DrawPacket_Rect::set_has_w() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void DrawPacket_Rect::clear_has_w() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void DrawPacket_Rect::clear_w() {
+  w_ = 0;
+  clear_has_w();
+}
+inline float DrawPacket_Rect::w() const {
+  return w_;
+}
+inline void DrawPacket_Rect::set_w(float value) {
+  set_has_w();
+  w_ = value;
+}
+
+// required float h = 4;
+inline bool DrawPacket_Rect::has_h() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void DrawPacket_Rect::set_has_h() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void DrawPacket_Rect::clear_has_h() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void DrawPacket_Rect::clear_h() {
+  h_ = 0;
+  clear_has_h();
+}
+inline float DrawPacket_Rect::h() const {
+  return h_;
+}
+inline void DrawPacket_Rect::set_h(float value) {
+  set_has_h();
+  h_ = value;
+}
+
+// -------------------------------------------------------------------
+
+// DrawPacket
+
+// required float offsetX = 1;
+inline bool DrawPacket::has_offsetx() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void DrawPacket::set_has_offsetx() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void DrawPacket::clear_has_offsetx() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void DrawPacket::clear_offsetx() {
+  offsetx_ = 0;
+  clear_has_offsetx();
+}
+inline float DrawPacket::offsetx() const {
+  return offsetx_;
+}
+inline void DrawPacket::set_offsetx(float value) {
+  set_has_offsetx();
+  offsetx_ = value;
+}
+
+// required float offsetY = 2;
+inline bool DrawPacket::has_offsety() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void DrawPacket::set_has_offsety() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void DrawPacket::clear_has_offsety() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void DrawPacket::clear_offsety() {
+  offsety_ = 0;
+  clear_has_offsety();
+}
+inline float DrawPacket::offsety() const {
+  return offsety_;
+}
+inline void DrawPacket::set_offsety(float value) {
+  set_has_offsety();
+  offsety_ = value;
+}
+
+// repeated float mvMatrix = 3;
+inline int DrawPacket::mvmatrix_size() const {
+  return mvmatrix_.size();
+}
+inline void DrawPacket::clear_mvmatrix() {
+  mvmatrix_.Clear();
+}
+inline float DrawPacket::mvmatrix(int index) const {
+  return mvmatrix_.Get(index);
+}
+inline void DrawPacket::set_mvmatrix(int index, float value) {
+  mvmatrix_.Set(index, value);
+}
+inline void DrawPacket::add_mvmatrix(float value) {
+  mvmatrix_.Add(value);
+}
+inline const ::google::protobuf::RepeatedField< float >&
+DrawPacket::mvmatrix() const {
+  return mvmatrix_;
+}
+inline ::google::protobuf::RepeatedField< float >*
+DrawPacket::mutable_mvmatrix() {
+  return &mvmatrix_;
+}
+
+// required uint32 totalRects = 4;
+inline bool DrawPacket::has_totalrects() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void DrawPacket::set_has_totalrects() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void DrawPacket::clear_has_totalrects() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void DrawPacket::clear_totalrects() {
+  totalrects_ = 0u;
+  clear_has_totalrects();
+}
+inline ::google::protobuf::uint32 DrawPacket::totalrects() const {
+  return totalrects_;
+}
+inline void DrawPacket::set_totalrects(::google::protobuf::uint32 value) {
+  set_has_totalrects();
+  totalrects_ = value;
+}
+
+// repeated .mozilla.layers.layerscope.DrawPacket.Rect layerRect = 5;
+inline int DrawPacket::layerrect_size() const {
+  return layerrect_.size();
+}
+inline void DrawPacket::clear_layerrect() {
+  layerrect_.Clear();
+}
+inline const ::mozilla::layers::layerscope::DrawPacket_Rect& DrawPacket::layerrect(int index) const {
+  return layerrect_.Get(index);
+}
+inline ::mozilla::layers::layerscope::DrawPacket_Rect* DrawPacket::mutable_layerrect(int index) {
+  return layerrect_.Mutable(index);
+}
+inline ::mozilla::layers::layerscope::DrawPacket_Rect* DrawPacket::add_layerrect() {
+  return layerrect_.Add();
+}
+inline const ::google::protobuf::RepeatedPtrField< ::mozilla::layers::layerscope::DrawPacket_Rect >&
+DrawPacket::layerrect() const {
+  return layerrect_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::mozilla::layers::layerscope::DrawPacket_Rect >*
+DrawPacket::mutable_layerrect() {
+  return &layerrect_;
+}
+
+// required uint64 layerref = 6;
+inline bool DrawPacket::has_layerref() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+inline void DrawPacket::set_has_layerref() {
+  _has_bits_[0] |= 0x00000020u;
+}
+inline void DrawPacket::clear_has_layerref() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+inline void DrawPacket::clear_layerref() {
+  layerref_ = GOOGLE_ULONGLONG(0);
+  clear_has_layerref();
+}
+inline ::google::protobuf::uint64 DrawPacket::layerref() const {
+  return layerref_;
+}
+inline void DrawPacket::set_layerref(::google::protobuf::uint64 value) {
+  set_has_layerref();
+  layerref_ = value;
+}
+
+// -------------------------------------------------------------------
+
 // Packet
 
 // required .mozilla.layers.layerscope.Packet.DataType type = 1;
 inline bool Packet::has_type() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
 inline void Packet::set_has_type() {
   _has_bits_[0] |= 0x00000001u;
@@ -2902,16 +3377,45 @@ inline ::mozilla::layers::layerscope::Me
 }
 inline ::mozilla::layers::layerscope::MetaPacket* Packet::release_meta() {
   clear_has_meta();
   ::mozilla::layers::layerscope::MetaPacket* temp = meta_;
   meta_ = NULL;
   return temp;
 }
 
+// optional .mozilla.layers.layerscope.DrawPacket draw = 7;
+inline bool Packet::has_draw() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+inline void Packet::set_has_draw() {
+  _has_bits_[0] |= 0x00000040u;
+}
+inline void Packet::clear_has_draw() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+inline void Packet::clear_draw() {
+  if (draw_ != NULL) draw_->::mozilla::layers::layerscope::DrawPacket::Clear();
+  clear_has_draw();
+}
+inline const ::mozilla::layers::layerscope::DrawPacket& Packet::draw() const {
+  return draw_ != NULL ? *draw_ : *default_instance_->draw_;
+}
+inline ::mozilla::layers::layerscope::DrawPacket* Packet::mutable_draw() {
+  set_has_draw();
+  if (draw_ == NULL) draw_ = new ::mozilla::layers::layerscope::DrawPacket;
+  return draw_;
+}
+inline ::mozilla::layers::layerscope::DrawPacket* Packet::release_draw() {
+  clear_has_draw();
+  ::mozilla::layers::layerscope::DrawPacket* temp = draw_;
+  draw_ = NULL;
+  return temp;
+}
+
 // -------------------------------------------------------------------
 
 // CommandPacket
 
 // required .mozilla.layers.layerscope.CommandPacket.CmdType type = 1;
 inline bool CommandPacket::has_type() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
--- a/gfx/layers/protobuf/LayerScopePacket.proto
+++ b/gfx/layers/protobuf/LayerScopePacket.proto
@@ -112,34 +112,52 @@ message LayersPacket {
   }
   repeated Layer layer = 1;
 }
 
 message MetaPacket {
   optional bool composedByHwc = 1;
 }
 
+message DrawPacket {
+  message Rect {
+    required float x = 1;
+    required float y = 2;
+    required float w = 3;
+    required float h = 4;
+  }
+
+  required float  offsetX = 1;
+  required float  offsetY = 2;
+  repeated float  mvMatrix = 3;
+  required uint32 totalRects = 4;
+  repeated Rect   layerRect = 5;
+  required uint64 layerref = 6;
+}
+
 // We only need to use this Packet.
 // Other packet definitions are just type defines
 message Packet {
   enum DataType {
     FRAMESTART = 1;
     FRAMEEND = 2;
     COLOR = 3;
     TEXTURE = 4;
     LAYERS = 5;
     META = 6;
+    DRAW = 7;
   }
   required DataType type = 1;
 
   optional FramePacket frame = 2;
   optional ColorPacket color = 3;
   optional TexturePacket texture = 4;
   optional LayersPacket layers = 5;
   optional MetaPacket meta = 6;
+  optional DrawPacket draw = 7;
 }
 
 
 // ===============================
 // Client to Server messages
 // ===============================
 message CommandPacket {
   enum CmdType {
--- a/gfx/qcms/transform-sse1.c
+++ b/gfx/qcms/transform-sse1.c
@@ -43,17 +43,17 @@ void qcms_transform_data_rgb_out_lut_sse
     const __m128 mat2  = _mm_load_ps(mat[2]);
 
     /* these values don't change, either */
     const __m128 max   = _mm_load_ps(clampMaxValueX4);
     const __m128 min   = _mm_setzero_ps();
     const __m128 scale = _mm_load_ps(floatScaleX4);
 
     /* working variables */
-    __m128 vec_r, vec_g, vec_b, result, result_hi;
+    __m128 vec_r, vec_g, vec_b, result;
 
     /* CYA */
     if (!length)
         return;
 
     /* one pixel is handled outside of the loop */
     length--;
 
@@ -79,33 +79,31 @@ void qcms_transform_data_rgb_out_lut_sse
 
         /* crunch, crunch, crunch */
         vec_r  = _mm_add_ps(vec_r, _mm_add_ps(vec_g, vec_b));
         vec_r  = _mm_max_ps(min, vec_r);
         vec_r  = _mm_min_ps(max, vec_r);
         result = _mm_mul_ps(vec_r, scale);
 
         /* store calc'd output tables indices */
-        /* Bug 1163740 temporary investigation:
-         * Write output[0] last, to keep |result| in a register in minidumps */
-        result_hi = _mm_movehl_ps(result, result);
-        *((__m64 *)&output[2]) = _mm_cvtps_pi32(result_hi);
         *((__m64 *)&output[0]) = _mm_cvtps_pi32(result);
+        result = _mm_movehl_ps(result, result);
+        *((__m64 *)&output[2]) = _mm_cvtps_pi32(result) ;
+
+        /* load for next loop while store completes */
+        vec_r = _mm_load_ss(&igtbl_r[src[0]]);
+        vec_g = _mm_load_ss(&igtbl_g[src[1]]);
+        vec_b = _mm_load_ss(&igtbl_b[src[2]]);
+        src += 3;
 
         /* use calc'd indices to output RGB values */
         dest[OUTPUT_R_INDEX] = otdata_r[output[0]];
         dest[OUTPUT_G_INDEX] = otdata_g[output[1]];
         dest[OUTPUT_B_INDEX] = otdata_b[output[2]];
         dest += RGB_OUTPUT_COMPONENTS;
-
-        /* load for next loop while store completes */
-        vec_r = _mm_load_ss(&igtbl_r[src[0]]);
-        vec_g = _mm_load_ss(&igtbl_g[src[1]]);
-        vec_b = _mm_load_ss(&igtbl_b[src[2]]);
-        src += 3;
     }
 
     /* handle final (maybe only) pixel */
 
     vec_r = _mm_shuffle_ps(vec_r, vec_r, 0);
     vec_g = _mm_shuffle_ps(vec_g, vec_g, 0);
     vec_b = _mm_shuffle_ps(vec_b, vec_b, 0);
 
@@ -162,17 +160,17 @@ void qcms_transform_data_rgba_out_lut_ss
     const __m128 mat2  = _mm_load_ps(mat[2]);
 
     /* these values don't change, either */
     const __m128 max   = _mm_load_ps(clampMaxValueX4);
     const __m128 min   = _mm_setzero_ps();
     const __m128 scale = _mm_load_ps(floatScaleX4);
 
     /* working variables */
-    __m128 vec_r, vec_g, vec_b, result, result_hi;
+    __m128 vec_r, vec_g, vec_b, result;
     unsigned char alpha;
 
     /* CYA */
     if (!length)
         return;
 
     /* one pixel is handled outside of the loop */
     length--;
@@ -203,33 +201,32 @@ void qcms_transform_data_rgba_out_lut_ss
         alpha   = src[3];
 
         /* crunch, crunch, crunch */
         vec_r  = _mm_add_ps(vec_r, _mm_add_ps(vec_g, vec_b));
         vec_r  = _mm_max_ps(min, vec_r);
         vec_r  = _mm_min_ps(max, vec_r);
         result = _mm_mul_ps(vec_r, scale);
 
-        /* Bug 1163740 temporary investigation:
-         * Write output[0] last, to keep |result| in a register in minidumps */
-        result_hi = _mm_movehl_ps(result, result);
-        *((__m64 *)&output[2]) = _mm_cvtps_pi32(result_hi);
+        /* store calc'd output tables indices */
         *((__m64 *)&output[0]) = _mm_cvtps_pi32(result);
+        result = _mm_movehl_ps(result, result);
+        *((__m64 *)&output[2]) = _mm_cvtps_pi32(result);
+
+        /* load gamma values for next loop while store completes */
+        vec_r = _mm_load_ss(&igtbl_r[src[0]]);
+        vec_g = _mm_load_ss(&igtbl_g[src[1]]);
+        vec_b = _mm_load_ss(&igtbl_b[src[2]]);
+        src += 4;
 
         /* use calc'd indices to output RGB values */
         dest[OUTPUT_R_INDEX] = otdata_r[output[0]];
         dest[OUTPUT_G_INDEX] = otdata_g[output[1]];
         dest[OUTPUT_B_INDEX] = otdata_b[output[2]];
         dest += 4;
-
-        /* load gamma values for next loop while store completes */
-        vec_r = _mm_load_ss(&igtbl_r[src[0]]);
-        vec_g = _mm_load_ss(&igtbl_g[src[1]]);
-        vec_b = _mm_load_ss(&igtbl_b[src[2]]);
-        src += 4;
     }
 
     /* handle final (maybe only) pixel */
 
     vec_r = _mm_shuffle_ps(vec_r, vec_r, 0);
     vec_g = _mm_shuffle_ps(vec_g, vec_g, 0);
     vec_b = _mm_shuffle_ps(vec_b, vec_b, 0);
 
--- a/gfx/src/nsITheme.h
+++ b/gfx/src/nsITheme.h
@@ -19,20 +19,20 @@ struct nsIntMargin;
 class nsPresContext;
 class nsRenderingContext;
 class nsDeviceContext;
 class nsIFrame;
 class nsIAtom;
 class nsIWidget;
 
 // IID for the nsITheme interface
-// {a21dd936-5960-46da-a724-7c114e421b41}
+// {7329f760-08cb-450f-8225-dae729096dec}
  #define NS_ITHEME_IID     \
-{ 0xa21dd936, 0x5960, 0x46da, \
-  { 0xa7, 0x24, 0x7c, 0x11, 0x4e, 0x42, 0x1b, 0x41 } }
+{ 0x7329f760, 0x08cb, 0x450f, \
+  { 0x82, 0x25, 0xda, 0xe7, 0x29, 0x09, 0x6d, 0xec } }
 // {0ae05515-cf7a-45a8-9e02-6556de7685b1}
 #define NS_THEMERENDERER_CID \
 { 0x0ae05515, 0xcf7a, 0x45a8, \
   { 0x9e, 0x02, 0x65, 0x56, 0xde, 0x76, 0x85, 0xb1 } }
 
 /**
  * nsITheme is a service that provides platform-specific native
  * rendering for widgets.  In other words, it provides the necessary
@@ -131,17 +131,18 @@ public:
   NS_IMETHOD WidgetStateChanged(nsIFrame* aFrame, uint8_t aWidgetType, 
                                 nsIAtom* aAttribute, bool* aShouldRepaint)=0;
 
   NS_IMETHOD ThemeChanged()=0;
 
   virtual bool WidgetAppearanceDependsOnWindowFocus(uint8_t aWidgetType)
   { return false; }
 
-  virtual bool NeedToClearBackgroundBehindWidget(uint8_t aWidgetType)
+  virtual bool NeedToClearBackgroundBehindWidget(nsIFrame* aFrame,
+                                                 uint8_t aWidgetType)
   { return false; }
 
   virtual bool WidgetProvidesFontSmoothingBackgroundColor(nsIFrame* aFrame,
                                       uint8_t aWidgetType, nscolor* aColor)
   { return false; }
 
   /**
    * ThemeGeometryType values are used for describing themed nsIFrames in
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -381,48 +381,57 @@ static const char *gPrefLangNames[] = {
     "x-orya",
     "x-telu",
     "x-knda",
     "x-sinh",
     "x-tibt",
     "x-unicode",
 };
 
-// this needs to match the list of pref font.default.xx entries listed in all.js!
-// the order *must* match the order in eFontPrefLang
-static nsIAtom* gPrefLangToLangGroups[] = {
-    nsGkAtoms::x_western,
-    nsGkAtoms::Japanese,
-    nsGkAtoms::Taiwanese,
-    nsGkAtoms::Chinese,
-    nsGkAtoms::HongKongChinese,
-    nsGkAtoms::ko,
-    nsGkAtoms::x_cyrillic,
-    nsGkAtoms::el,
-    nsGkAtoms::th,
-    nsGkAtoms::he,
-    nsGkAtoms::ar,
-    nsGkAtoms::x_devanagari,
-    nsGkAtoms::x_tamil,
-    nsGkAtoms::x_armn,
-    nsGkAtoms::x_beng,
-    nsGkAtoms::x_cans,
-    nsGkAtoms::x_ethi,
-    nsGkAtoms::x_geor,
-    nsGkAtoms::x_gujr,
-    nsGkAtoms::x_guru,
-    nsGkAtoms::x_khmr,
-    nsGkAtoms::x_mlym,
-    nsGkAtoms::x_orya,
-    nsGkAtoms::x_telu,
-    nsGkAtoms::x_knda,
-    nsGkAtoms::x_sinh,
-    nsGkAtoms::x_tibt,
-    nsGkAtoms::Unicode
-};
+static nsIAtom* PrefLangToLangGroups(uint32_t aIndex)
+{
+    // This needs to match the list of pref font.default.xx entries listed in
+    // all.js! The order *must* match the order in eFontPrefLang.
+    //
+    // Having this array within a static function rather than at the top-level
+    // avoids a static constructor.
+    static nsIAtom* gPrefLangToLangGroups[] = {
+        nsGkAtoms::x_western,
+        nsGkAtoms::Japanese,
+        nsGkAtoms::Taiwanese,
+        nsGkAtoms::Chinese,
+        nsGkAtoms::HongKongChinese,
+        nsGkAtoms::ko,
+        nsGkAtoms::x_cyrillic,
+        nsGkAtoms::el,
+        nsGkAtoms::th,
+        nsGkAtoms::he,
+        nsGkAtoms::ar,
+        nsGkAtoms::x_devanagari,
+        nsGkAtoms::x_tamil,
+        nsGkAtoms::x_armn,
+        nsGkAtoms::x_beng,
+        nsGkAtoms::x_cans,
+        nsGkAtoms::x_ethi,
+        nsGkAtoms::x_geor,
+        nsGkAtoms::x_gujr,
+        nsGkAtoms::x_guru,
+        nsGkAtoms::x_khmr,
+        nsGkAtoms::x_mlym,
+        nsGkAtoms::x_orya,
+        nsGkAtoms::x_telu,
+        nsGkAtoms::x_knda,
+        nsGkAtoms::x_sinh,
+        nsGkAtoms::x_tibt,
+        nsGkAtoms::Unicode
+    };
+    return aIndex < ArrayLength(gPrefLangToLangGroups)
+         ? gPrefLangToLangGroups[aIndex]
+         : nsGkAtoms::Unicode;
+}
 
 gfxPlatform::gfxPlatform()
   : mTileWidth(-1)
   , mTileHeight(-1)
   , mAzureCanvasBackendCollector(this, &gfxPlatform::GetAzureBackendInfo)
   , mApzSupportCollector(this, &gfxPlatform::GetApzSupportInfo)
 {
     mAllowDownloadableFonts = UNINITIALIZED_VALUE;
@@ -1519,20 +1528,17 @@ gfxPlatform::GetFontPrefLangFor(nsIAtom 
 
 nsIAtom*
 gfxPlatform::GetLangGroupForPrefLang(eFontPrefLang aLang)
 {
     // the special CJK set pref lang should be resolved into separate
     // calls to individual CJK pref langs before getting here
     NS_ASSERTION(aLang != eFontPrefLang_CJKSet, "unresolved CJK set pref lang");
 
-    if (uint32_t(aLang) < ArrayLength(gPrefLangToLangGroups)) {
-        return gPrefLangToLangGroups[uint32_t(aLang)];
-    }
-    return nsGkAtoms::Unicode;
+    return PrefLangToLangGroups(uint32_t(aLang));
 }
 
 const char*
 gfxPlatform::GetPrefLangName(eFontPrefLang aLang)
 {
     if (uint32_t(aLang) < ArrayLength(gPrefLangNames)) {
         return gPrefLangNames[uint32_t(aLang)];
     }
--- a/hal/gonk/GonkHal.cpp
+++ b/hal/gonk/GonkHal.cpp
@@ -1642,18 +1642,22 @@ PriorityClass::PriorityClass(ProcessPrio
   }
   if (EnsureMemCGroupExists(mGroup)) {
     mMemCGroupProcsFd = OpenMemCGroupProcs();
   }
 }
 
 PriorityClass::~PriorityClass()
 {
-  close(mCpuCGroupProcsFd);
-  close(mMemCGroupProcsFd);
+  if (mCpuCGroupProcsFd != -1) {
+    close(mCpuCGroupProcsFd);
+  }
+  if (mMemCGroupProcsFd != -1) {
+    close(mMemCGroupProcsFd);
+  }
 }
 
 PriorityClass::PriorityClass(const PriorityClass& aOther)
   : mPriority(aOther.mPriority)
   , mOomScoreAdj(aOther.mOomScoreAdj)
   , mKillUnderKB(aOther.mKillUnderKB)
   , mGroup(aOther.mGroup)
 {
--- a/image/decoders/nsPNGDecoder.cpp
+++ b/image/decoders/nsPNGDecoder.cpp
@@ -106,16 +106,17 @@ nsPNGDecoder::AnimFrameInfo::AnimFrameIn
 const uint8_t
 nsPNGDecoder::pngSignatureBytes[] = { 137, 80, 78, 71, 13, 10, 26, 10 };
 
 nsPNGDecoder::nsPNGDecoder(RasterImage* aImage)
  : Decoder(aImage),
    mPNG(nullptr), mInfo(nullptr),
    mCMSLine(nullptr), interlacebuf(nullptr),
    mInProfile(nullptr), mTransform(nullptr),
+   format(gfx::SurfaceFormat::UNKNOWN),
    mHeaderBytesRead(0), mCMSMode(0),
    mChannels(0), mFrameIsHidden(false),
    mDisablePremultipliedAlpha(false),
    mNumFrames(0)
 {
 }
 
 nsPNGDecoder::~nsPNGDecoder()
@@ -631,16 +632,18 @@ nsPNGDecoder::info_callback(png_structp 
   //---------------------------------------------------------------//
   // copy PNG info into imagelib structs (formerly png_set_dims()) //
   //---------------------------------------------------------------//
 
   if (channels == 1 || channels == 3) {
     decoder->format = gfx::SurfaceFormat::B8G8R8X8;
   } else if (channels == 2 || channels == 4) {
     decoder->format = gfx::SurfaceFormat::B8G8R8A8;
+  } else {
+    png_longjmp(decoder->mPNG, 1); // invalid number of channels
   }
 
 #ifdef PNG_APNG_SUPPORTED
   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_acTL)) {
     png_set_progressive_frame_fn(png_ptr, nsPNGDecoder::frame_info_callback,
                                  nullptr);
   }
 
--- a/intl/locale/langGroups.properties
+++ b/intl/locale/langGroups.properties
@@ -209,16 +209,17 @@ x-cyrillic=x-cyrillic
 # zh-CN
 # ko
 # zh-TW
 x-tamil=x-tamil
 x-devanagari=x-devanagari
 x-unicode=x-unicode
 x-armn=x-armn
 x-geor=x-geor
+x-math=x-math
 # These self-mappings are not necessary unless somebody use them to specify
 # lang in (X)HTML/XML documents, which they shouldn't. (see bug 256257)
 #x-beng=x-beng
 #x-cans=x-cans
 #x-ethi=x-ethi
 #x-guru=x-guru
 #x-gujr=x-gujr
 #x-khmr=x-khmr
--- a/js/src/builtin/AtomicsObject.cpp
+++ b/js/src/builtin/AtomicsObject.cpp
@@ -1223,18 +1223,21 @@ AtomicsObject::initClass(JSContext* cx, 
     if (!JS_DefineFunctions(cx, Atomics, AtomicsMethods))
         return nullptr;
     if (!JS_DefineConstDoubles(cx, Atomics, AtomicsConstants))
         return nullptr;
 
     RootedValue AtomicsValue(cx, ObjectValue(*Atomics));
 
     // Everything is set up, install Atomics on the global object.
-    if (!DefineProperty(cx, global, cx->names().Atomics, AtomicsValue, nullptr, nullptr, 0))
+    if (!DefineProperty(cx, global, cx->names().Atomics, AtomicsValue, nullptr, nullptr,
+                        JSPROP_RESOLVING))
+    {
         return nullptr;
+    }
 
     global->setConstructor(JSProto_Atomics, AtomicsValue);
     return Atomics;
 }
 
 JSObject*
 js::InitAtomicsClass(JSContext* cx, HandleObject obj)
 {
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -2044,18 +2044,21 @@ js::InitIntlClass(JSContext* cx, HandleO
     // called with this being "the standard built-in Intl object". The global
     // object reserves slots to track standard built-in objects, but doesn't
     // normally keep references to non-constructors. This makes sure there is one.
     RootedObject Intl(cx, global->getOrCreateIntlObject(cx));
     if (!Intl)
         return nullptr;
 
     RootedValue IntlValue(cx, ObjectValue(*Intl));
-    if (!DefineProperty(cx, global, cx->names().Intl, IntlValue, nullptr, nullptr, 0))
+    if (!DefineProperty(cx, global, cx->names().Intl, IntlValue, nullptr, nullptr,
+                        JSPROP_RESOLVING))
+    {
         return nullptr;
+    }
 
     if (!JS_DefineFunctions(cx, Intl, intl_static_methods))
         return nullptr;
 
     if (!InitCollatorClass(cx, Intl, global))
         return nullptr;
     if (!InitNumberFormatClass(cx, Intl, global))
         return nullptr;
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -1127,17 +1127,18 @@ CreateObjectPrototype(JSContext* cx, JSP
 
 static bool
 FinishObjectClassInit(JSContext* cx, JS::HandleObject ctor, JS::HandleObject proto)
 {
     Rooted<GlobalObject*> self(cx, cx->global());
 
     /* ES5 15.1.2.1. */
     RootedId evalId(cx, NameToId(cx->names().eval));
-    JSObject* evalobj = DefineFunction(cx, self, evalId, IndirectEval, 1, JSFUN_STUB_GSOPS);
+    JSObject* evalobj = DefineFunction(cx, self, evalId, IndirectEval, 1,
+                                       JSFUN_STUB_GSOPS | JSPROP_RESOLVING);
     if (!evalobj)
         return false;
     self->setOriginalEval(evalobj);
 
     RootedObject intrinsicsHolder(cx);
     bool isSelfHostingGlobal = cx->runtime()->isSelfHostingGlobal(self);
     if (isSelfHostingGlobal) {
         intrinsicsHolder = self;
--- a/js/src/builtin/SIMD.cpp
+++ b/js/src/builtin/SIMD.cpp
@@ -470,18 +470,21 @@ SIMDObject::initClass(JSContext* cx, Han
     RootedObject f64x2(cx);
     f64x2 = CreateAndBindSimdClass<Float64x2Defn>(cx, global, SIMD, cx->names().float64x2);
     if (!f64x2)
         return nullptr;
     global->setFloat64x2TypeDescr(*f64x2);
 
     // Everything is set up, install SIMD on the global object.
     RootedValue SIMDValue(cx, ObjectValue(*SIMD));
-    if (!DefineProperty(cx, global, cx->names().SIMD, SIMDValue, nullptr, nullptr, 0))
+    if (!DefineProperty(cx, global, cx->names().SIMD, SIMDValue, nullptr, nullptr,
+                        JSPROP_RESOLVING))
+    {
         return nullptr;
+    }
 
     global->setConstructor(JSProto_SIMD, SIMDValue);
     return SIMD;
 }
 
 JSObject*
 js::InitSIMDClass(JSContext* cx, HandleObject obj)
 {
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -1320,18 +1320,21 @@ GlobalObject::initTypedObjectModule(JSCo
                         nullptr, nullptr, JSPROP_READONLY | JSPROP_PERMANENT))
     {
         return false;
     }
 
     // Everything is setup, install module on the global object:
     RootedValue moduleValue(cx, ObjectValue(*module));
     global->setConstructor(JSProto_TypedObject, moduleValue);
-    if (!DefineProperty(cx, global, cx->names().TypedObject, moduleValue, nullptr, nullptr, 0))
+    if (!DefineProperty(cx, global, cx->names().TypedObject, moduleValue, nullptr, nullptr,
+                        JSPROP_RESOLVING))
+    {
         return false;
+    }
 
     return module;
 }
 
 JSObject*
 js::InitTypedObjectModuleObject(JSContext* cx, HandleObject obj)
 {
     MOZ_ASSERT(obj->is<GlobalObject>());
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -24,55 +24,18 @@
 #include "vm/Interpreter-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using JS::GenericNaN;
 using JS::ToInt32;
 
-namespace {
-
-// Emulate a TypeSet logic from a Type object to avoid duplicating the guard
-// logic.
-class TypeWrapper {
-    TypeSet::Type t_;
-
-  public:
-    explicit TypeWrapper(TypeSet::Type t) : t_(t) {}
-
-    inline bool unknown() const {
-        return t_.isUnknown();
-    }
-    inline bool hasType(TypeSet::Type t) const {
-        if (t == TypeSet::Int32Type())
-            return t == t_ || t_ == TypeSet::DoubleType();
-        return t == t_;
-    }
-    inline unsigned getObjectCount() const {
-        if (t_.isAnyObject() || t_.isUnknown() || !t_.isObject())
-            return 0;
-        return 1;
-    }
-    inline JSObject* getSingletonNoBarrier(unsigned) const {
-        if (t_.isSingleton())
-            return t_.singletonNoBarrier();
-        return nullptr;
-    }
-    inline ObjectGroup* getGroupNoBarrier(unsigned) const {
-        if (t_.isGroup())
-            return t_.groupNoBarrier();
-        return nullptr;
-    }
-};
-
-} /* anonymous namespace */
-
-template <typename Source, typename Set> void
-MacroAssembler::guardTypeSet(const Source& address, const Set *types, BarrierKind kind,
+template <typename Source> void
+MacroAssembler::guardTypeSet(const Source& address, const TypeSet *types, BarrierKind kind,
                              Register scratch, Label* miss)
 {
     MOZ_ASSERT(kind == BarrierKind::TypeTagOnly || kind == BarrierKind::TypeSet);
     MOZ_ASSERT(!types->unknown());
 
     Label matched;
     TypeSet::Type tests[8] = {
         TypeSet::Int32Type(),
@@ -159,18 +122,18 @@ MacroAssembler::guardTypeSetMightBeIncom
     loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
     load32(Address(scratch, ObjectGroup::offsetOfFlags()), scratch);
     branchTest32(Assembler::NonZero, scratch, Imm32(OBJECT_FLAG_UNKNOWN_PROPERTIES), label);
     and32(Imm32(OBJECT_FLAG_ADDENDUM_MASK), scratch);
     branch32(Assembler::Equal,
              scratch, Imm32(ObjectGroup::addendumOriginalUnboxedGroupValue()), label);
 }
 
-template <typename Set> void
-MacroAssembler::guardObjectType(Register obj, const Set *types,
+void
+MacroAssembler::guardObjectType(Register obj, const TypeSet *types,
                                 Register scratch, Label* miss)
 {
     MOZ_ASSERT(!types->unknown());
     MOZ_ASSERT(!types->hasType(TypeSet::AnyObjectType()));
     MOZ_ASSERT(types->getObjectCount());
     MOZ_ASSERT(scratch != InvalidReg);
 
     // Note: this method elides read barriers on values read from type sets, as
@@ -231,58 +194,23 @@ MacroAssembler::guardObjectType(Register
     lastBranch.invertCondition();
     lastBranch.relink(miss);
     lastBranch.emit(*this);
 
     bind(&matched);
     return;
 }
 
-template <typename Source> void
-MacroAssembler::guardType(const Source& address, TypeSet::Type type,
-                          Register scratch, Label* miss)
-{
-    TypeWrapper wrapper(type);
-    guardTypeSet(address, &wrapper, BarrierKind::TypeSet, scratch, miss);
-}
-
-template void MacroAssembler::guardTypeSet(const Address& address, const TemporaryTypeSet* types,
-                                           BarrierKind kind, Register scratch, Label* miss);
-template void MacroAssembler::guardTypeSet(const ValueOperand& value, const TemporaryTypeSet* types,
-                                           BarrierKind kind, Register scratch, Label* miss);
-
-template void MacroAssembler::guardTypeSet(const Address& address, const HeapTypeSet* types,
-                                           BarrierKind kind, Register scratch, Label* miss);
-template void MacroAssembler::guardTypeSet(const ValueOperand& value, const HeapTypeSet* types,
-                                           BarrierKind kind, Register scratch, Label* miss);
-template void MacroAssembler::guardTypeSet(const TypedOrValueRegister& reg, const HeapTypeSet* types,
-                                           BarrierKind kind, Register scratch, Label* miss);
-
 template void MacroAssembler::guardTypeSet(const Address& address, const TypeSet* types,
                                            BarrierKind kind, Register scratch, Label* miss);
 template void MacroAssembler::guardTypeSet(const ValueOperand& value, const TypeSet* types,
                                            BarrierKind kind, Register scratch, Label* miss);
-
-template void MacroAssembler::guardTypeSet(const Address& address, const TypeWrapper* types,
-                                           BarrierKind kind, Register scratch, Label* miss);
-template void MacroAssembler::guardTypeSet(const ValueOperand& value, const TypeWrapper* types,
+template void MacroAssembler::guardTypeSet(const TypedOrValueRegister& value, const TypeSet* types,
                                            BarrierKind kind, Register scratch, Label* miss);
 
-template void MacroAssembler::guardObjectType(Register obj, const TemporaryTypeSet* types,
-                                              Register scratch, Label* miss);
-template void MacroAssembler::guardObjectType(Register obj, const TypeSet* types,
-                                              Register scratch, Label* miss);
-template void MacroAssembler::guardObjectType(Register obj, const TypeWrapper* types,
-                                              Register scratch, Label* miss);
-
-template void MacroAssembler::guardType(const Address& address, TypeSet::Type type,
-                                        Register scratch, Label* miss);
-template void MacroAssembler::guardType(const ValueOperand& value, TypeSet::Type type,
-                                        Register scratch, Label* miss);
-
 template<typename S, typename T>
 static void
 StoreToTypedFloatArray(MacroAssembler& masm, int arrayType, const S& value, const T& dest,
                        unsigned numElems)
 {
     switch (arrayType) {
       case Scalar::Float32:
         masm.storeFloat32(value, dest);
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -326,22 +326,20 @@ class MacroAssembler : public MacroAssem
     void popRooted(VMFunction::RootType rootType, Register cellReg, const ValueOperand& valueReg);
 
     void adjustStack(int amount);
 
   public:
 
     // Emits a test of a value against all types in a TypeSet. A scratch
     // register is required.
-    template <typename Source, typename TypeSet>
+    template <typename Source>
     void guardTypeSet(const Source& address, const TypeSet* types, BarrierKind kind, Register scratch, Label* miss);
-    template <typename TypeSet>
+
     void guardObjectType(Register obj, const TypeSet* types, Register scratch, Label* miss);
-    template <typename Source>
-    void guardType(const Source& address, TypeSet::Type type, Register scratch, Label* miss);
 
     void guardTypeSetMightBeIncomplete(Register obj, Register scratch, Label* label);
 
     void loadObjShape(Register objReg, Register dest) {
         loadPtr(Address(objReg, JSObject::offsetOfShape()), dest);
     }
     void loadObjGroup(Register objReg, Register dest) {
         loadPtr(Address(objReg, JSObject::offsetOfGroup()), dest);
--- a/js/src/jit/x86-shared/Assembler-x86-shared.h
+++ b/js/src/jit/x86-shared/Assembler-x86-shared.h
@@ -2761,17 +2761,17 @@ class AssemblerX86Shared : public Assemb
           case Operand::MEM_REG_DISP:
             masm.vinsertps_imr(mask, src1.disp(), src1.base(), src0.encoding(), dest.encoding());
             break;
           default:
             MOZ_CRASH("unexpected operand kind");
         }
     }
     unsigned blendpsMask(bool x, bool y, bool z, bool w) {
-        return x | (y << 1) | (z << 2) | (w << 3);
+        return (x << 0) | (y << 1) | (z << 2) | (w << 3);
     }
     void vblendps(unsigned mask, FloatRegister src1, FloatRegister src0, FloatRegister dest) {
         MOZ_ASSERT(HasSSE41());
         masm.vblendps_irr(mask, src1.encoding(), src0.encoding(), dest.encoding());
     }
     void vblendps(unsigned mask, const Operand& src1, FloatRegister src0, FloatRegister dest) {
         MOZ_ASSERT(HasSSE41());
         switch (src1.kind()) {
--- a/js/src/jsapi-tests/testLookup.cpp
+++ b/js/src/jsapi-tests/testLookup.cpp
@@ -56,17 +56,17 @@ document_resolve(JSContext* cx, JS::Hand
         if (!flatStr)
             return false;
         if (JS_FlatStringEqualsAscii(flatStr, "all")) {
             JS::Rooted<JSObject*> docAll(cx, JS_NewObject(cx, &DocumentAllClass));
             if (!docAll)
                 return false;
 
             JS::Rooted<JS::Value> allValue(cx, JS::ObjectValue(*docAll));
-            if (!JS_DefinePropertyById(cx, obj, id, allValue, 0))
+            if (!JS_DefinePropertyById(cx, obj, id, allValue, JSPROP_RESOLVING))
                 return false;
 
             *resolvedp = true;
             return true;
         }
     }
 
     *resolvedp = false;
--- a/js/src/jsapi-tests/testResolveRecursion.cpp
+++ b/js/src/jsapi-tests/testResolveRecursion.cpp
@@ -6,17 +6,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jsapi-tests/tests.h"
 
 /*
  * Test that resolve hook recursion for the same object and property is
  * prevented.
  */
-
 BEGIN_TEST(testResolveRecursion)
 {
     static const JSClass my_resolve_class = {
         "MyResolve",
         JSCLASS_HAS_PRIVATE,
         nullptr, // add
         nullptr, // delete
         nullptr, // get
@@ -83,29 +82,29 @@ doResolve(JS::HandleObject obj, JS::Hand
     CHECK(str);
     JS::RootedValue v(cx);
     if (JS_FlatStringEqualsAscii(str, "x")) {
         if (obj == obj1) {
             /* First resolve hook invocation. */
             CHECK_EQUAL(resolveEntryCount, 1);
             EVAL("obj2.y = true", &v);
             CHECK_SAME(v, JSVAL_TRUE);
-            CHECK(JS_DefinePropertyById(cx, obj, id, JS::FalseHandleValue, 0));
+            CHECK(JS_DefinePropertyById(cx, obj, id, JS::FalseHandleValue, JSPROP_RESOLVING));
             *resolvedp = true;
             return true;
         }
         if (obj == obj2) {
             CHECK_EQUAL(resolveEntryCount, 4);
             *resolvedp = false;
             return true;
         }
     } else if (JS_FlatStringEqualsAscii(str, "y")) {
         if (obj == obj2) {
             CHECK_EQUAL(resolveEntryCount, 2);
-            CHECK(JS_DefinePropertyById(cx, obj, id, JS::NullHandleValue, 0));
+            CHECK(JS_DefinePropertyById(cx, obj, id, JS::NullHandleValue, JSPROP_RESOLVING));
             EVAL("obj1.x", &v);
             CHECK(v.isUndefined());
             EVAL("obj1.y", &v);
             CHECK_SAME(v, JSVAL_ZERO);
             *resolvedp = true;
             return true;
         }
         if (obj == obj1) {
@@ -129,10 +128,54 @@ doResolve(JS::HandleObject obj, JS::Hand
 }
 
 static bool
 my_resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolvedp)
 {
     return static_cast<cls_testResolveRecursion*>(JS_GetPrivate(obj))->
            doResolve(obj, id, resolvedp);
 }
+END_TEST(testResolveRecursion)
 
-END_TEST(testResolveRecursion)
+/*
+ * Test that JS_InitStandardClasses does not cause resolve hooks to be called.
+ *
+ * (XPConnect apparently does have global classes, such as the one created by
+ * nsMessageManagerScriptExecutor::InitChildGlobalInternal(), that have resolve
+ * hooks which can call back into JS, and on which JS_InitStandardClasses is
+ * called. Calling back into JS in the middle of resolving `undefined` is bad.)
+ */
+BEGIN_TEST(testResolveRecursion_InitStandardClasses)
+{
+    CHECK(JS_InitStandardClasses(cx, global));
+    return true;
+}
+
+const JSClass* getGlobalClass() override {
+    static const JSClass myGlobalClass = {
+        "testResolveRecursion_InitStandardClasses_myGlobalClass",
+        JSCLASS_GLOBAL_FLAGS,
+        nullptr, // add
+        nullptr, // delete
+        nullptr, // get
+        nullptr, // set
+        nullptr, // enumerate
+        my_resolve,
+        nullptr, // mayResolve
+        nullptr, // convert
+        nullptr, // finalize
+        nullptr, // call
+        nullptr, // hasInstance
+        nullptr, // construct
+        JS_GlobalObjectTraceHook
+    };
+
+    return &myGlobalClass;
+}
+
+static bool
+my_resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolvedp)
+{
+    MOZ_ASSERT_UNREACHABLE("resolve hook should not be called from InitStandardClasses");
+    JS_ReportError(cx, "FAIL");
+    return false;
+}
+END_TEST(testResolveRecursion_InitStandardClasses)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1226,19 +1226,18 @@ JS_ResolveStandardClass(JSContext* cx, H
     if (!rt->hasContexts() || !JSID_IS_ATOM(id))
         return true;
 
     /* Check whether we're resolving 'undefined', and define it if so. */
     JSAtom* idAtom = JSID_TO_ATOM(id);
     JSAtom* undefinedAtom = cx->names().undefined;
     if (idAtom == undefinedAtom) {
         *resolved = true;
-        return DefineProperty(cx, obj, undefinedAtom->asPropertyName(),
-                              UndefinedHandleValue, nullptr, nullptr,
-                              JSPROP_PERMANENT | JSPROP_READONLY);
+        return DefineProperty(cx, global, id, UndefinedHandleValue, nullptr, nullptr,
+                              JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_RESOLVING);
     }
 
     /* Try for class constructors/prototypes named by well-known atoms. */
     stdnm = LookupStdName(cx->names(), idAtom, standard_class_names);
 
     /* Try less frequently used top-level functions and constants. */
     if (!stdnm)
         stdnm = LookupStdName(cx->names(), idAtom, builtin_property_names);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -856,51 +856,65 @@ class MOZ_STACK_CLASS SourceBufferHolder
                                            have self-hosted functions that can only be defined
                                            after the initialization is already finished. */
 #define JSFUN_STUB_GSOPS       0x200    /* use JS_PropertyStub getter/setter
                                            instead of defaulting to class gsops
                                            for property holding function */
 
 #define JSFUN_CONSTRUCTOR      0x400    /* native that can be called as a ctor */
 
-#define JSPROP_REDEFINE_NONCONFIGURABLE 0x800 /* If set, will allow redefining a
-                                                 non-configurable property, but
-                                                 only on a non-DOM global.  This
-                                                 is a temporary hack that will
-                                                 need to go away in bug
-                                                 1105518 */
-
-#define JSPROP_IGNORE_ENUMERATE 0x1000  /* ignore the value in JSPROP_ENUMERATE.
-                                           This flag only valid when defining over
-                                           an existing property. */
-#define JSPROP_IGNORE_READONLY  0x2000  /* ignore the value in JSPROP_READONLY.
-                                           This flag only valid when defining over
-                                           an existing property. */
-#define JSPROP_IGNORE_PERMANENT 0x4000  /* ignore the value in JSPROP_PERMANENT.
-                                           This flag only valid when defining over
-                                           an existing property. */
-#define JSPROP_IGNORE_VALUE     0x8000  /* ignore the Value in the descriptor. Nothing was
-                                           specified when passed to Object.defineProperty
-                                           from script. */
-
 /*
  * Specify a generic native prototype methods, i.e., methods of a class
  * prototype that are exposed as static methods taking an extra leading
  * argument: the generic |this| parameter.
  *
  * If you set this flag in a JSFunctionSpec struct's flags initializer, then
  * that struct must live at least as long as the native static method object
  * created due to this flag by JS_DefineFunctions or JS_InitClass.  Typically
  * JSFunctionSpec structs are allocated in static arrays.
  */
 #define JSFUN_GENERIC_NATIVE   0x800
 
 #define JSFUN_FLAGS_MASK       0xe00    /* | of all the JSFUN_* flags */
 
 /*
+ * If set, will allow redefining a non-configurable property, but only on a
+ * non-DOM global.  This is a temporary hack that will need to go away in bug
+ * 1105518.
+ */
+#define JSPROP_REDEFINE_NONCONFIGURABLE 0x1000
+
+/*
+ * Resolve hooks and enumerate hooks must pass this flag when calling
+ * JS_Define* APIs to reify lazily-defined properties.
+ *
+ * JSPROP_RESOLVING is used only with property-defining APIs. It tells the
+ * engine to skip the resolve hook when performing the lookup at the beginning
+ * of property definition. This keeps the resolve hook from accidentally
+ * triggering itself: unchecked recursion.
+ *
+ * For enumerate hooks, triggering the resolve hook would be merely silly, not
+ * fatal, except in some cases involving non-configurable properties.
+ */
+#define JSPROP_RESOLVING         0x2000
+
+#define JSPROP_IGNORE_ENUMERATE  0x4000  /* ignore the value in JSPROP_ENUMERATE.
+                                            This flag only valid when defining over
+                                            an existing property. */
+#define JSPROP_IGNORE_READONLY   0x8000  /* ignore the value in JSPROP_READONLY.
+                                            This flag only valid when defining over
+                                            an existing property. */
+#define JSPROP_IGNORE_PERMANENT 0x10000  /* ignore the value in JSPROP_PERMANENT.
+                                            This flag only valid when defining over
+                                            an existing property. */
+#define JSPROP_IGNORE_VALUE     0x20000  /* ignore the Value in the descriptor. Nothing was
+                                            specified when passed to Object.defineProperty
+                                            from script. */
+
+/*
  * The first call to JS_CallOnce by any thread in a process will call 'func'.
  * Later calls to JS_CallOnce with the same JSCallOnceType object will be
  * suppressed.
  *
  * Equivalently: each distinct JSCallOnceType object will allow one JS_CallOnce
  * to invoke its JSInitCallback.
  */
 extern JS_PUBLIC_API(bool)
@@ -2558,16 +2572,17 @@ class PropertyDescriptorOperations
         MOZ_ASSERT((attributes() & ~(JSPROP_ENUMERATE | JSPROP_IGNORE_ENUMERATE |
                                      JSPROP_PERMANENT | JSPROP_IGNORE_PERMANENT |
                                      JSPROP_READONLY | JSPROP_IGNORE_READONLY |
                                      JSPROP_IGNORE_VALUE |
                                      JSPROP_GETTER |
                                      JSPROP_SETTER |
                                      JSPROP_SHARED |
                                      JSPROP_REDEFINE_NONCONFIGURABLE |
+                                     JSPROP_RESOLVING |
                                      SHADOWABLE)) == 0);
         MOZ_ASSERT(!hasAll(JSPROP_IGNORE_ENUMERATE | JSPROP_ENUMERATE));
         MOZ_ASSERT(!hasAll(JSPROP_IGNORE_PERMANENT | JSPROP_PERMANENT));
         if (isAccessorDescriptor()) {
             MOZ_ASSERT(has(JSPROP_SHARED));
             MOZ_ASSERT(!has(JSPROP_READONLY));
             MOZ_ASSERT(!has(JSPROP_IGNORE_READONLY));
             MOZ_ASSERT(!has(JSPROP_IGNORE_VALUE));
@@ -2576,29 +2591,36 @@ class PropertyDescriptorOperations
             MOZ_ASSERT_IF(!has(JSPROP_GETTER), !getter());
             MOZ_ASSERT_IF(!has(JSPROP_SETTER), !setter());
         } else {
             MOZ_ASSERT(!hasAll(JSPROP_IGNORE_READONLY | JSPROP_READONLY));
             MOZ_ASSERT_IF(has(JSPROP_IGNORE_VALUE), value().isUndefined());
         }
         MOZ_ASSERT(getter() != JS_PropertyStub);
         MOZ_ASSERT(setter() != JS_StrictPropertyStub);
+
+        MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_ENUMERATE));
+        MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_PERMANENT));
+        MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_READONLY));
+        MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_VALUE));
+        MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_REDEFINE_NONCONFIGURABLE));
 #endif
     }
 
     void assertComplete() const {
 #ifdef DEBUG
         assertValid();
         MOZ_ASSERT((attributes() & ~(JSPROP_ENUMERATE |
                                      JSPROP_PERMANENT |
                                      JSPROP_READONLY |
                                      JSPROP_GETTER |
                                      JSPROP_SETTER |
                                      JSPROP_SHARED |
                                      JSPROP_REDEFINE_NONCONFIGURABLE |
+                                     JSPROP_RESOLVING |
                                      SHADOWABLE)) == 0);
         MOZ_ASSERT_IF(isAccessorDescriptor(), has(JSPROP_GETTER) && has(JSPROP_SETTER));
 #endif
     }
 
     void assertCompleteIfFound() const {
 #ifdef DEBUG
         if (object())
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -358,70 +358,63 @@ CallerSetter(JSContext* cx, unsigned arg
 }
 
 static const JSPropertySpec function_properties[] = {
     JS_PSGS("arguments", ArgumentsGetter, ArgumentsSetter, 0),
     JS_PSGS("caller", CallerGetter, CallerSetter, 0),
     JS_PS_END
 };
 
-static JSObject*
-ResolveInterpretedFunctionPrototype(JSContext* cx, HandleObject obj)
+static bool
+ResolveInterpretedFunctionPrototype(JSContext* cx, HandleFunction fun, HandleId id)
 {
-#ifdef DEBUG
-    JSFunction* fun = &obj->as<JSFunction>();
     MOZ_ASSERT(fun->isInterpreted() || fun->isAsmJSNative());
     MOZ_ASSERT(!fun->isFunctionPrototype());
-#endif
+    MOZ_ASSERT(id == NameToId(cx->names().prototype));
 
     // Assert that fun is not a compiler-created function object, which
     // must never leak to script or embedding code and then be mutated.
-    // Also assert that obj is not bound, per the ES5 15.3.4.5 ref above.
-    MOZ_ASSERT(!IsInternalFunctionObject(obj));
-    MOZ_ASSERT(!obj->isBoundFunction());
+    // Also assert that fun is not bound, per the ES5 15.3.4.5 ref above.
+    MOZ_ASSERT(!IsInternalFunctionObject(fun));
+    MOZ_ASSERT(!fun->isBoundFunction());
 
     // Make the prototype object an instance of Object with the same parent as
     // the function object itself, unless the function is an ES6 generator.  In
     // that case, per the 15 July 2013 ES6 draft, section 15.19.3, its parent is
     // the GeneratorObjectPrototype singleton.
-    bool isStarGenerator = obj->as<JSFunction>().isStarGenerator();
-    Rooted<GlobalObject*> global(cx, &obj->global());
+    bool isStarGenerator = fun->isStarGenerator();
+    Rooted<GlobalObject*> global(cx, &fun->global());
     RootedObject objProto(cx);
     if (isStarGenerator)
         objProto = GlobalObject::getOrCreateStarGeneratorObjectPrototype(cx, global);
     else
-        objProto = obj->global().getOrCreateObjectPrototype(cx);
+        objProto = fun->global().getOrCreateObjectPrototype(cx);
     if (!objProto)
         return nullptr;
 
     RootedPlainObject proto(cx, NewObjectWithGivenProto<PlainObject>(cx, objProto,
                                                                      SingletonObject));
     if (!proto)
         return nullptr;
 
-    // Per ES5 15.3.5.2 a user-defined function's .prototype property is
-    // initially non-configurable, non-enumerable, and writable.
-    RootedValue protoVal(cx, ObjectValue(*proto));
-    if (!DefineProperty(cx, obj, cx->names().prototype, protoVal, nullptr, nullptr,
-                        JSPROP_PERMANENT))
-    {
-        return nullptr;
-    }
-
     // Per ES5 13.2 the prototype's .constructor property is configurable,
     // non-enumerable, and writable.  However, per the 15 July 2013 ES6 draft,
     // section 15.19.3, the .prototype of a generator function does not link
     // back with a .constructor.
     if (!isStarGenerator) {
-        RootedValue objVal(cx, ObjectValue(*obj));
+        RootedValue objVal(cx, ObjectValue(*fun));
         if (!DefineProperty(cx, proto, cx->names().constructor, objVal, nullptr, nullptr, 0))
             return nullptr;
     }
 
-    return proto;
+    // Per ES5 15.3.5.2 a user-defined function's .prototype property is
+    // initially non-configurable, non-enumerable, and writable.
+    RootedValue protoVal(cx, ObjectValue(*proto));
+    return DefineProperty(cx, fun, id, protoVal, nullptr, nullptr,
+                          JSPROP_PERMANENT | JSPROP_RESOLVING);
 }
 
 static bool
 fun_mayResolve(const JSAtomState& names, jsid id, JSObject*)
 {
     if (!JSID_IS_ATOM(id))
         return false;
 
@@ -453,17 +446,17 @@ fun_resolve(JSContext* cx, HandleObject 
          * Thus all of the following don't get a .prototype property:
          * - Methods (that are not class-constructors or generators)
          * - Arrow functions
          * - Function.prototype
          */
         if (fun->isBuiltin() || !fun->isConstructor())
             return true;
 
-        if (!ResolveInterpretedFunctionPrototype(cx, fun))
+        if (!ResolveInterpretedFunctionPrototype(cx, fun, id))
             return false;
 
         *resolvedp = true;
         return true;
     }
 
     bool isLength = JSID_IS_ATOM(id, cx->names().length);
     if (isLength || JSID_IS_ATOM(id, cx->names().name)) {
@@ -496,18 +489,21 @@ fun_resolve(JSContext* cx, HandleObject 
             v.setInt32(length);
         } else {
             if (fun->hasResolvedName())
                 return true;
 
             v.setString(fun->atom() == nullptr ? cx->runtime()->emptyString : fun->atom());
         }
 
-        if (!NativeDefineProperty(cx, fun, id, v, nullptr, nullptr, JSPROP_READONLY))
+        if (!NativeDefineProperty(cx, fun, id, v, nullptr, nullptr,
+                                  JSPROP_READONLY | JSPROP_RESOLVING))
+        {
             return false;
+        }
 
         if (isLength)
             fun->setResolvedLength();
         else
             fun->setResolvedName();
 
         *resolvedp = true;
         return true;
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -1617,18 +1617,21 @@ js::InitMathClass(JSContext* cx, HandleO
 {
     RootedObject proto(cx, obj->as<GlobalObject>().getOrCreateObjectPrototype(cx));
     if (!proto)
         return nullptr;
     RootedObject Math(cx, NewObjectWithGivenProto(cx, &MathClass, proto, SingletonObject));
     if (!Math)
         return nullptr;
 
-    if (!JS_DefineProperty(cx, obj, js_Math_str, Math, 0, JS_STUBGETTER, JS_STUBSETTER))
+    if (!JS_DefineProperty(cx, obj, js_Math_str, Math, JSPROP_RESOLVING,
+                           JS_STUBGETTER, JS_STUBSETTER))
+    {
         return nullptr;
+    }
     if (!JS_DefineFunctions(cx, Math, math_static_methods))
         return nullptr;
     if (!JS_DefineConstDoubles(cx, Math, math_constants))
         return nullptr;
 
     obj->as<GlobalObject>().setConstructor(JSProto_Math, ObjectValue(*Math));
 
     return Math;
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -452,18 +452,18 @@ js::num_parseInt(JSContext* cx, unsigned
             return false;
     }
 
     args.rval().setNumber(number);
     return true;
 }
 
 static const JSFunctionSpec number_functions[] = {
-    JS_SELF_HOSTED_FN(js_isNaN_str, "Global_isNaN", 1,0),
-    JS_SELF_HOSTED_FN(js_isFinite_str, "Global_isFinite", 1,0),
+    JS_SELF_HOSTED_FN(js_isNaN_str, "Global_isNaN", 1, JSPROP_RESOLVING),
+    JS_SELF_HOSTED_FN(js_isFinite_str, "Global_isFinite", 1, JSPROP_RESOLVING),
     JS_FS_END
 };
 
 const Class NumberObject::class_ = {
     js_Number_str,
     JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Number)
 };
 
@@ -1171,40 +1171,42 @@ js::InitNumberClass(JSContext* cx, Handl
     if (!DefinePropertiesAndFunctions(cx, numberProto, nullptr, number_methods))
         return nullptr;
 
     if (!JS_DefineFunctions(cx, global, number_functions))
         return nullptr;
 
     /* Number.parseInt should be the same function object as global parseInt. */
     RootedId parseIntId(cx, NameToId(cx->names().parseInt));
-    JSFunction* parseInt = DefineFunction(cx, global, parseIntId, num_parseInt, 2, 0);
-    if(!parseInt)
+    JSFunction* parseInt = DefineFunction(cx, global, parseIntId, num_parseInt, 2,
+                                          JSPROP_RESOLVING);
+    if (!parseInt)
         return nullptr;
     RootedValue parseIntValue(cx, ObjectValue(*parseInt));
-    if(!DefineProperty(cx, ctor, parseIntId, parseIntValue, nullptr, nullptr, 0))
+    if (!DefineProperty(cx, ctor, parseIntId, parseIntValue, nullptr, nullptr, 0))
         return nullptr;
 
     /* Number.parseFloat should be the same function object as global parseFloat. */
     RootedId parseFloatId(cx, NameToId(cx->names().parseFloat));
-    JSFunction* parseFloat = DefineFunction(cx, global, parseFloatId, num_parseFloat, 1, 0);
-    if(!parseFloat)
+    JSFunction* parseFloat = DefineFunction(cx, global, parseFloatId, num_parseFloat, 1,
+                                            JSPROP_RESOLVING);
+    if (!parseFloat)
         return nullptr;
     RootedValue parseFloatValue(cx, ObjectValue(*parseFloat));
-    if(!DefineProperty(cx, ctor, parseFloatId, parseFloatValue, nullptr, nullptr, 0))
+    if (!DefineProperty(cx, ctor, parseFloatId, parseFloatValue, nullptr, nullptr, 0))
         return nullptr;
 
     RootedValue valueNaN(cx, cx->runtime()->NaNValue);
     RootedValue valueInfinity(cx, cx->runtime()->positiveInfinityValue);
 
     /* ES5 15.1.1.1, 15.1.1.2 */
     if (!NativeDefineProperty(cx, global, cx->names().NaN, valueNaN, nullptr, nullptr,
-                              JSPROP_PERMANENT | JSPROP_READONLY) ||
+                              JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_RESOLVING) ||
         !NativeDefineProperty(cx, global, cx->names().Infinity, valueInfinity, nullptr, nullptr,
-                              JSPROP_PERMANENT | JSPROP_READONLY))
+                              JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_RESOLVING))
     {
         return nullptr;
     }
 
     if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_Number, ctor, numberProto))
         return nullptr;
 
     return numberProto;
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3235,16 +3235,17 @@ js::WatchGuts(JSContext* cx, JS::HandleO
         MarkTypePropertyNonData(cx, obj, id);
     }
 
     WatchpointMap* wpmap = cx->compartment()->watchpointMap;
     if (!wpmap) {
         wpmap = cx->runtime()->new_<WatchpointMap>();
         if (!wpmap || !wpmap->init()) {
             ReportOutOfMemory(cx);
+            js_delete(wpmap);
             return false;
         }
         cx->compartment()->watchpointMap = wpmap;
     }
 
     return wpmap->watch(cx, obj, id, js::WatchHandler, callable);
 }
 
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -895,19 +895,21 @@ js::InitJSONClass(JSContext* cx, HandleO
 
     RootedObject proto(cx, global->getOrCreateObjectPrototype(cx));
     if (!proto)
         return nullptr;
     RootedObject JSON(cx, NewObjectWithGivenProto(cx, &JSONClass, proto, SingletonObject));
     if (!JSON)
         return nullptr;
 
-    if (!JS_DefineProperty(cx, global, js_JSON_str, JSON, 0,
+    if (!JS_DefineProperty(cx, global, js_JSON_str, JSON, JSPROP_RESOLVING,
                            JS_STUBGETTER, JS_STUBSETTER))
+    {
         return nullptr;
+    }
 
     if (!JS_DefineFunctions(cx, JSON, json_static_methods))
         return nullptr;
 
     global->setConstructor(JSProto_JSON, ObjectValue(*JSON));
 
     return JSON;
 }
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -357,43 +357,46 @@ str_uneval(JSContext* cx, unsigned argc,
         return false;
 
     args.rval().setString(str);
     return true;
 }
 #endif
 
 static const JSFunctionSpec string_functions[] = {
-    JS_FN(js_escape_str,             str_escape,                1,0),
-    JS_FN(js_unescape_str,           str_unescape,              1,0),
+    JS_FN(js_escape_str,             str_escape,                1, JSPROP_RESOLVING),
+    JS_FN(js_unescape_str,           str_unescape,              1, JSPROP_RESOLVING),
 #if JS_HAS_UNEVAL
-    JS_FN(js_uneval_str,             str_uneval,                1,0),
+    JS_FN(js_uneval_str,             str_uneval,                1, JSPROP_RESOLVING),
 #endif
-    JS_FN(js_decodeURI_str,          str_decodeURI,             1,0),
-    JS_FN(js_encodeURI_str,          str_encodeURI,             1,0),
-    JS_FN(js_decodeURIComponent_str, str_decodeURI_Component,   1,0),
-    JS_FN(js_encodeURIComponent_str, str_encodeURI_Component,   1,0),
+    JS_FN(js_decodeURI_str,          str_decodeURI,             1, JSPROP_RESOLVING),
+    JS_FN(js_encodeURI_str,          str_encodeURI,             1, JSPROP_RESOLVING),
+    JS_FN(js_decodeURIComponent_str, str_decodeURI_Component,   1, JSPROP_RESOLVING),
+    JS_FN(js_encodeURIComponent_str, str_encodeURI_Component,   1, JSPROP_RESOLVING),
 
     JS_FS_END
 };
 
 static const unsigned STRING_ELEMENT_ATTRS = JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT;
 
 static bool
 str_enumerate(JSContext* cx, HandleObject obj)
 {
     RootedString str(cx, obj->as<StringObject>().unbox());
     RootedValue value(cx);
     for (size_t i = 0, length = str->length(); i < length; i++) {
         JSString* str1 = NewDependentString(cx, str, i, 1);
         if (!str1)
             return false;
         value.setString(str1);
-        if (!DefineElement(cx, obj, i, value, nullptr, nullptr, STRING_ELEMENT_ATTRS))
+        if (!DefineElement(cx, obj, i, value, nullptr, nullptr,
+                           STRING_ELEMENT_ATTRS | JSPROP_RESOLVING))
+        {
             return false;
+        }
     }
 
     return true;
 }
 
 static bool
 str_mayResolve(const JSAtomState&, jsid id, JSObject*)
 {
@@ -410,18 +413,21 @@ str_resolve(JSContext* cx, HandleObject 
     RootedString str(cx, obj->as<StringObject>().unbox());
 
     int32_t slot = JSID_TO_INT(id);
     if ((size_t)slot < str->length()) {
         JSString* str1 = cx->staticStrings().getUnitStringForElement(cx, str, size_t(slot));
         if (!str1)
             return false;
         RootedValue value(cx, StringValue(str1));
-        if (!DefineElement(cx, obj, uint32_t(slot), value, nullptr, nullptr, STRING_ELEMENT_ATTRS))
+        if (!DefineElement(cx, obj, uint32_t(slot), value, nullptr, nullptr,
+                           STRING_ELEMENT_ATTRS | JSPROP_RESOLVING))
+        {
             return false;
+        }
         *resolvedp = true;
     }
     return true;
 }
 
 const Class StringObject::class_ = {
     js_String_str,
     JSCLASS_HAS_RESERVED_SLOTS(StringObject::RESERVED_SLOTS) |
--- a/js/src/proxy/Proxy.cpp
+++ b/js/src/proxy/Proxy.cpp
@@ -769,16 +769,14 @@ js::InitProxyClass(JSContext* cx, Handle
     Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
     RootedFunction ctor(cx);
     ctor = global->createConstructor(cx, proxy, cx->names().Proxy, 2);
     if (!ctor)
         return nullptr;
 
     if (!JS_DefineFunctions(cx, ctor, static_methods))
         return nullptr;
-    if (!JS_DefineProperty(cx, obj, "Proxy", ctor, 0,
-                           JS_STUBGETTER, JS_STUBSETTER)) {
+    if (!JS_DefineProperty(cx, obj, "Proxy", ctor, JSPROP_RESOLVING, JS_STUBGETTER, JS_STUBSETTER))
         return nullptr;
-    }
 
     global->setConstructor(JSProto_Proxy, ObjectValue(*ctor));
     return ctor;
 }
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -350,17 +350,17 @@ ArgSetter(JSContext* cx, HandleObject ob
            NativeDefineProperty(cx, argsobj, id, vp, nullptr, nullptr, attrs, result);
 }
 
 static bool
 args_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
 {
     Rooted<NormalArgumentsObject*> argsobj(cx, &obj->as<NormalArgumentsObject>());
 
-    unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
+    unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE | JSPROP_RESOLVING;
     if (JSID_IS_INT(id)) {
         uint32_t arg = uint32_t(JSID_TO_INT(id));
         if (arg >= argsobj->initialLength() || argsobj->isElementDeleted(arg))
             return true;
 
         attrs |= JSPROP_ENUMERATE;
     } else if (JSID_IS_ATOM(id, cx->names().length)) {
         if (argsobj->hasOverriddenLength())
@@ -485,16 +485,17 @@ strictargs_resolve(JSContext* cx, Handle
         if (!JSID_IS_ATOM(id, cx->names().callee) && !JSID_IS_ATOM(id, cx->names().caller))
             return true;
 
         attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED;
         getter = CastAsGetterOp(argsobj->global().getThrowTypeError());
         setter = CastAsSetterOp(argsobj->global().getThrowTypeError());
     }
 
+    attrs |= JSPROP_RESOLVING;
     if (!NativeDefineProperty(cx, argsobj, id, UndefinedHandleValue, getter, setter, attrs))
         return false;
 
     *resolvedp = true;
     return true;
 }
 
 static bool
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -324,17 +324,17 @@ GlobalObject::valueIsEval(Value val)
     return eval.isObject() && eval == val;
 }
 
 /* static */ bool
 GlobalObject::initStandardClasses(JSContext* cx, Handle<GlobalObject*> global)
 {
     /* Define a top-level property 'undefined' with the undefined value. */
     if (!DefineProperty(cx, global, cx->names().undefined, UndefinedHandleValue,
-                                  nullptr, nullptr, JSPROP_PERMANENT | JSPROP_READONLY))
+                        nullptr, nullptr, JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_RESOLVING))
     {
         return false;
     }
 
     for (size_t k = 0; k < JSProto_LIMIT; ++k) {
         if (!ensureConstructor(cx, global, static_cast<JSProtoKey>(k)))
             return false;
     }
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -1243,36 +1243,27 @@ js::NativeDefineProperty(ExclusiveContex
         }
     } else if (obj->is<ArgumentsObject>()) {
         if (id == NameToId(cx->names().length)) {
             // Either we are resolving the .length property on this object, or
             // redefining it. In the latter case only, we must set a bit. To
             // distinguish the two cases, we note that when resolving, the
             // property won't already exist; whereas the first time it is
             // redefined, it will.
-            if (obj->containsPure(id))
+            if ((desc_.attributes() & JSPROP_RESOLVING) == 0)
                 obj->as<ArgumentsObject>().markLengthOverridden();
         }
     }
 
     // 9.1.6.1 OrdinaryDefineOwnProperty steps 1-2.
     RootedShape shape(cx);
-    if (desc_.hasValue()) {
-        // If we did a normal lookup here, it would cause resolve hook recursion in
-        // the following case. Suppose the first script we run in a lazy global is
-        // |parseInt()|.
-        //   - js::InitNumberClass is called to resolve parseInt.
-        //   - js::InitNumberClass tries to define the Number constructor on the
-        //     global.
-        //   - We end up here.
-        //   - This lookup for 'Number' triggers the global resolve hook.
-        //   - js::InitNumberClass is called again, this time to resolve Number.
-        //   - It creates a second Number constructor, which trips an assertion.
-        //
-        // Therefore we do a special lookup that does not call the resolve hook.
+    if (desc_.attributes() & JSPROP_RESOLVING) {
+        // We are being called from a resolve or enumerate hook to reify a
+        // lazily-resolved property. To avoid reentering the resolve hook and
+        // recursing forever, skip the resolve hook when doing this lookup.
         NativeLookupOwnPropertyNoResolve(cx, obj, id, &shape);
     } else {
         if (!NativeLookupOwnProperty<CanGC>(cx, obj, id, &shape))
             return false;
     }
 
     // From this point, the step numbers refer to
     // 9.1.6.3, ValidateAndApplyPropertyDescriptor.
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -27,22 +27,26 @@
 #include "xpcprivate.h"
 #include "XPCWrapper.h"
 #include "XrayWrapper.h"
 #include "Crypto.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/BlobBinding.h"
 #include "mozilla/dom/CSSBinding.h"
 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
+#include "mozilla/dom/Fetch.h"
 #include "mozilla/dom/FileBinding.h"
 #include "mozilla/dom/PromiseBinding.h"
+#include "mozilla/dom/RequestBinding.h"
+#include "mozilla/dom/ResponseBinding.h"
 #include "mozilla/dom/RTCIdentityProviderRegistrar.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/TextDecoderBinding.h"
 #include "mozilla/dom/TextEncoderBinding.h"
+#include "mozilla/dom/UnionConversions.h"
 #include "mozilla/dom/URLBinding.h"
 #include "mozilla/dom/URLSearchParamsBinding.h"
 
 using namespace mozilla;
 using namespace JS;
 using namespace js;
 using namespace xpc;
 
@@ -232,16 +236,94 @@ SandboxCreateRTCIdentityProvider(JSConte
 
     dom::RTCIdentityProviderRegistrar* registrar =
             new dom::RTCIdentityProviderRegistrar(nativeGlobal);
     JS::RootedObject wrapped(cx, registrar->WrapObject(cx, nullptr));
     return JS_DefineProperty(cx, obj, "rtcIdentityProvider", wrapped, JSPROP_ENUMERATE);
 }
 
 static bool
+SetFetchRequestFromValue(JSContext *cx, RequestOrUSVString& request,
+                         const MutableHandleValue& requestOrUrl)
+{
+    RequestOrUSVStringArgument requestHolder(request);
+    bool noMatch = true;
+    if (requestOrUrl.isObject() &&
+        !requestHolder.TrySetToRequest(cx, requestOrUrl, noMatch, false)) {
+        return false;
+    }
+    if (noMatch &&
+        !requestHolder.TrySetToUSVString(cx, requestOrUrl, noMatch)) {
+        return false;
+    }
+    if (noMatch) {
+        return false;
+    }
+    return true;
+}
+
+static bool
+SandboxFetch(JSContext* cx, JS::HandleObject scope, const CallArgs& args)
+{
+    if (args.length() < 1) {
+        JS_ReportError(cx, "fetch requires at least 1 argument");
+        return false;
+    }
+
+    RequestOrUSVString request;
+    if (!SetFetchRequestFromValue(cx, request, args[0])) {
+        JS_ReportError(cx, "fetch requires a string or Request in argument 1");
+        return false;
+    }
+    RootedDictionary<dom::RequestInit> options(cx);
+    if (!options.Init(cx, args.hasDefined(1) ? args[1] : JS::NullHandleValue,
+                      "Argument 2 of fetch", false)) {
+        return false;
+    }
+    nsCOMPtr<nsIGlobalObject> global = xpc::NativeGlobal(scope);
+    if (!global) {
+        return false;
+    }
+    ErrorResult rv;
+    nsRefPtr<dom::Promise> response =
+        FetchRequest(global, Constify(request), Constify(options), rv);
+    rv.WouldReportJSException();
+    if (rv.Failed()) {
+        return ThrowMethodFailedWithDetails(cx, rv, "Sandbox", "fetch");
+    }
+    if (!GetOrCreateDOMReflector(cx, scope, response, args.rval())) {
+        return false;
+    }
+    return true;
+}
+
+static bool SandboxFetchPromise(JSContext* cx, unsigned argc, jsval* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    RootedObject callee(cx, &args.callee());
+    RootedObject scope(cx, JS::CurrentGlobalOrNull(cx));
+    if (SandboxFetch(cx, scope, args)) {
+        return true;
+    }
+    return ConvertExceptionToPromise(cx, scope, args.rval());
+}
+
+
+static bool
+SandboxCreateFetch(JSContext* cx, HandleObject obj)
+{
+    MOZ_ASSERT(JS_IsGlobalObject(obj));
+
+    return JS_DefineFunction(cx, obj, "fetch", SandboxFetchPromise, 2, 0) &&
+        dom::RequestBinding::GetConstructorObject(cx, obj) &&
+        dom::ResponseBinding::GetConstructorObject(cx, obj) &&
+        dom::HeadersBinding::GetConstructorObject(cx, obj);
+}
+
+static bool
 SandboxIsProxy(JSContext* cx, unsigned argc, jsval* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() < 1) {
         JS_ReportError(cx, "Function requires at least 1 argument");
         return false;
     }
     if (!args[0].isObject()) {
@@ -813,16 +895,18 @@ xpc::GlobalProperties::Parse(JSContext* 
         } else if (!strcmp(name.ptr(), "Blob")) {
             Blob = true;
         } else if (!strcmp(name.ptr(), "File")) {
             File = true;
         } else if (!strcmp(name.ptr(), "crypto")) {
             crypto = true;
         } else if (!strcmp(name.ptr(), "rtcIdentityProvider")) {
             rtcIdentityProvider = true;
+        } else if (!strcmp(name.ptr(), "fetch")) {
+            fetch = true;
         } else {
             JS_ReportError(cx, "Unknown property name: %s", name.ptr());
             return false;
         }
     }
     return true;
 }
 
@@ -873,16 +957,19 @@ xpc::GlobalProperties::Define(JSContext*
         return false;
 
     if (crypto && !SandboxCreateCrypto(cx, obj))
         return false;
 
     if (rtcIdentityProvider && !SandboxCreateRTCIdentityProvider(cx, obj))
         return false;
 
+    if (fetch && !SandboxCreateFetch(cx, obj))
+        return false;
+
     return true;
 }
 
 nsresult
 xpc::CreateSandboxObject(JSContext* cx, MutableHandleValue vp, nsISupports* prinOrSop,
                          SandboxOptions& options)
 {
     // Create the sandbox global object
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -314,17 +314,18 @@ nsXPCComponents_Interfaces::Resolve(nsIX
                 RootedObject idobj(cx);
                 if (holder &&
                     // Assign, not compare
                     (idobj = holder->GetJSObject())) {
                     *resolvedp = true;
                     *_retval = JS_DefinePropertyById(cx, obj, id, idobj,
                                                      JSPROP_ENUMERATE |
                                                      JSPROP_READONLY |
-                                                     JSPROP_PERMANENT);
+                                                     JSPROP_PERMANENT |
+                                                     JSPROP_RESOLVING);
                 }
             }
         }
     }
     return NS_OK;
 }
 
 /***************************************************************************/
@@ -552,17 +553,18 @@ nsXPCComponents_InterfacesByID::Resolve(
             if (holder &&
                 // Assign, not compare
                 (idobj = holder->GetJSObject())) {
                 *resolvedp = true;
                 *_retval =
                     JS_DefinePropertyById(cx, obj, id, idobj,
                                           JSPROP_ENUMERATE |
                                           JSPROP_READONLY |
-                                          JSPROP_PERMANENT);
+                                          JSPROP_PERMANENT |
+                                          JSPROP_RESOLVING);
             }
         }
     }
     return NS_OK;
 }
 
 /***************************************************************************/
 /***************************************************************************/
@@ -770,17 +772,18 @@ nsXPCComponents_Classes::Resolve(nsIXPCo
                 RootedObject idobj(cx);
                 if (holder &&
                     // Assign, not compare
                         (idobj = holder->GetJSObject())) {
                     *resolvedp = true;
                     *_retval = JS_DefinePropertyById(cx, obj, id, idobj,
                                                      JSPROP_ENUMERATE |
                                                      JSPROP_READONLY |
-                                                     JSPROP_PERMANENT);
+                                                     JSPROP_PERMANENT |
+                                                     JSPROP_RESOLVING);
                 }
             }
         }
     }
     return NS_OK;
 }
 
 /***************************************************************************/
@@ -1008,17 +1011,18 @@ nsXPCComponents_ClassesByID::Resolve(nsI
                 RootedObject idobj(cx);
                 if (holder &&
                     // Assign, not compare
                     (idobj = holder->GetJSObject())) {
                     *resolvedp = true;
                     *_retval = JS_DefinePropertyById(cx, obj, id, idobj,
                                                      JSPROP_ENUMERATE |
                                                      JSPROP_READONLY |
-                                                     JSPROP_PERMANENT);
+                                                     JSPROP_PERMANENT |
+                                                     JSPROP_RESOLVING);
                 }
             }
         }
     }
     return NS_OK;
 }
 
 
@@ -1203,17 +1207,18 @@ nsXPCComponents_Results::Resolve(nsIXPCo
         const void* iter = nullptr;
         nsresult rv;
         while (nsXPCException::IterateNSResults(&rv, &rv_name, nullptr, &iter)) {
             if (!strcmp(name.ptr(), rv_name)) {
                 *resolvedp = true;
                 if (!JS_DefinePropertyById(cx, obj, id, (uint32_t)rv,
                                            JSPROP_ENUMERATE |
                                            JSPROP_READONLY |
-                                           JSPROP_PERMANENT)) {
+                                           JSPROP_PERMANENT |
+                                           JSPROP_RESOLVING)) {
                     return NS_ERROR_UNEXPECTED;
                 }
             }
         }
     }
     return NS_OK;
 }
 
--- a/js/xpconnect/src/XPCJSID.cpp
+++ b/js/xpconnect/src/XPCJSID.cpp
@@ -397,17 +397,17 @@ nsJSIID::Resolve(nsIXPConnectWrappedNati
     if (member && member->IsConstant()) {
         RootedValue val(cx);
         if (!member->GetConstantValue(ccx, iface, val.address()))
             return NS_ERROR_OUT_OF_MEMORY;
 
         *resolvedp = true;
         *_retval = JS_DefinePropertyById(cx, obj, id, val,
                                          JSPROP_ENUMERATE | JSPROP_READONLY |
-                                         JSPROP_PERMANENT);
+                                         JSPROP_PERMANENT | JSPROP_RESOLVING);
     }
 
     return NS_OK;
 }
 
 /* bool enumerate (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj); */
 NS_IMETHODIMP
 nsJSIID::Enumerate(nsIXPConnectWrappedNative* wrapper,
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -194,16 +194,18 @@ DefinePropertyIfFound(XPCCallContext& cc
                       unsigned propFlags,
                       bool* resolved)
 {
     RootedId id(ccx, idArg);
     XPCJSRuntime* rt = ccx.GetRuntime();
     bool found;
     const char* name;
 
+    propFlags |= JSPROP_RESOLVING;
+
     if (set) {
         if (iface)
             found = true;
         else
             found = set->FindMember(id, &member, &iface);
     } else
         found = (nullptr != (member = iface->FindMember(id)));
 
@@ -359,16 +361,17 @@ DefinePropertyIfFound(XPCCallContext& cc
         Rooted<JSPropertyDescriptor> desc(ccx);
         if (!xpc::InterposeProperty(ccx, obj, iface->GetIID(), id, &desc))
             return false;
 
         if (desc.object()) {
             AutoResolveName arn(ccx, id);
             if (resolved)
                 *resolved = true;
+            desc.attributesRef() |= JSPROP_RESOLVING;
             return JS_DefinePropertyById(ccx, obj, id, desc);
         }
     }
 
     if (id == rt->GetStringID(XPCJSRuntime::IDX_TO_STRING) ||
         id == rt->GetStringID(XPCJSRuntime::IDX_TO_SOURCE) ||
         (scriptableInfo &&
          scriptableInfo->GetFlags().DontEnumQueryInterface() &&
--- a/js/xpconnect/src/XPCWrappedNativeScope.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp
@@ -205,17 +205,17 @@ XPCWrappedNativeScope::AttachComponentsO
         return false;
 
     RootedObject global(aCx, GetGlobalJSObject());
     MOZ_ASSERT(js::IsObjectInContextCompartment(global, aCx));
 
     // The global Components property is non-configurable if it's a full
     // nsXPCComponents object. That way, if it's an nsXPCComponentsBase,
     // enableUniversalXPConnect can upgrade it later.
-    unsigned attrs = JSPROP_READONLY;
+    unsigned attrs = JSPROP_READONLY | JSPROP_RESOLVING;
     nsCOMPtr<nsIXPCComponents> c = do_QueryInterface(mComponents);
     if (c)
         attrs |= JSPROP_PERMANENT;
 
     RootedId id(aCx, XPCJSRuntime::Get()->GetStringID(XPCJSRuntime::IDX_COMPONENTS));
     return JS_DefinePropertyById(aCx, global, id, components, attrs);
 }
 
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -3395,16 +3395,17 @@ struct GlobalProperties {
     bool URL : 1;
     bool URLSearchParams : 1;
     bool atob : 1;
     bool btoa : 1;
     bool Blob : 1;
     bool File : 1;
     bool crypto : 1;
     bool rtcIdentityProvider : 1;
+    bool fetch : 1;
 };
 
 // Infallible.
 already_AddRefed<nsIXPCComponents_utils_Sandbox>
 NewSandboxConstructor();
 
 // Returns true if class of 'obj' is SandboxClass.
 bool
--- a/js/xpconnect/tests/mochitest/mochitest.ini
+++ b/js/xpconnect/tests/mochitest/mochitest.ini
@@ -100,8 +100,11 @@ skip-if= buildapp == 'mulet'
 [test_crossOriginObjects.html]
 [test_crosscompartment_weakmap.html]
 [test_frameWrapping.html]
 # The JS test component we use below is only available in debug builds.
 [test_getWebIDLCaller.html]
 skip-if = (debug == false || os == "android")
 [test_nac.xhtml]
 [test_sameOriginPolicy.html]
+[test_sandbox_fetch.html]
+  support-files =
+    ../../../../dom/tests/mochitest/fetch/test_fetch_basic.js
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/mochitest/test_sandbox_fetch.html
@@ -0,0 +1,54 @@
+<!doctype html>
+<html>
+<head>
+  <title>Fetch in JS Sandbox</title>
+  <script src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"></link>
+  <script src="test_fetch_basic.js"></script>
+</head>
+<body>
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+function testHttpFetch(url) {
+  info('fetch: ' + url);
+  return fetch(new Request(url, { method: 'GET' }))
+    .then(response => {
+      is(response.status, 200, 'Response is 200');
+      is(response.url, url, 'Response URL matches');
+    });
+}
+
+function runSandboxTest(testFunc, argString) {
+  is(typeof testFunc, 'function');
+  var resolvePromise;
+  var testPromise = new Promise(r => resolvePromise = r);
+  var finishFuncName = 'finish_' + testFunc.name;
+  SpecialPowers.Cu.exportFunction(_ => resolvePromise(), sb,
+                                  { defineAs: finishFuncName });
+  SpecialPowers.Cu.evalInSandbox('(' + testFunc.toSource() + ')' +
+                                 '(' + argString + ')' +
+                                 '.then(' + finishFuncName + ');', sb);
+  return testPromise;
+}
+
+var origin = 'https://example.com';
+var properties = ['fetch', 'Blob', 'URL'];
+var sb = new SpecialPowers.Cu.Sandbox(origin,
+                                      { wantGlobalProperties: properties });
+
+sb.ok = SpecialPowers.Cu.exportFunction(ok, sb);
+sb.is = SpecialPowers.Cu.exportFunction(is, sb);
+sb.info = SpecialPowers.Cu.exportFunction(info, sb);
+
+Promise.resolve()
+  .then(_ => runSandboxTest(testHttpFetch, '"' + origin + window.location.pathname + '"'))
+  .then(_ => runSandboxTest(testAboutURL))
+  .then(_ => runSandboxTest(testDataURL))
+  .then(_ => runSandboxTest(testSameOriginBlobURL))
+  .then(_ => SimpleTest.finish());
+
+</script>
+</body>
+</html>
--- a/js/xpconnect/wrappers/AddonWrapper.cpp
+++ b/js/xpconnect/wrappers/AddonWrapper.cpp
@@ -27,17 +27,18 @@ InterposeProperty(JSContext* cx, HandleO
 {
     // We only want to do interpostion on DOM instances and
     // wrapped natives.
     RootedObject unwrapped(cx, UncheckedUnwrap(target));
     const js::Class* clasp = js::GetObjectClass(unwrapped);
     if (!mozilla::dom::IsDOMClass(clasp) &&
         !IS_WN_CLASS(clasp) &&
         !IS_PROTO_CLASS(clasp) &&
-        clasp != &OuterWindowProxyClass) {
+        clasp != &OuterWindowProxyClass &&
+        !jsipc::IsWrappedCPOW(unwrapped)) {
         return true;
     }
 
     XPCWrappedNativeScope* scope = ObjectScope(CurrentGlobalOrNull(cx));
     MOZ_ASSERT(scope->HasInterposition());
 
     nsCOMPtr<nsIAddonInterposition> interp = scope->GetInterposition();
     JSAddonId* addonId = AddonIdOfObject(target);
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -2159,17 +2159,17 @@ nsDisplayBackgroundImage::AppendBackgrou
     }
     bgItemList.AppendNewToTop(
         new (aBuilder) nsDisplayBackgroundColor(aBuilder, aFrame, bg,
                                                 drawBackgroundColor ? color : NS_RGBA(0, 0, 0, 0)));
   }
 
   if (isThemed) {
     nsITheme* theme = presContext->GetTheme();
-    if (theme->NeedToClearBackgroundBehindWidget(aFrame->StyleDisplay()->mAppearance) &&
+    if (theme->NeedToClearBackgroundBehindWidget(aFrame, aFrame->StyleDisplay()->mAppearance) &&
         aBuilder->IsInRootChromeDocumentOrPopup() && !aBuilder->IsInTransform()) {
       bgItemList.AppendNewToTop(
         new (aBuilder) nsDisplayClearBackground(aBuilder, aFrame));
     }
     nsDisplayThemedBackground* bgItem =
       new (aBuilder) nsDisplayThemedBackground(aBuilder, aFrame);
     bgItemList.AppendNewToTop(bgItem);
     aList->AppendToTop(&bgItemList);
@@ -4691,21 +4691,16 @@ nsDisplayTransform::GetDeltaToTransformO
       nscoord offset =
         (index == 0) ? aFrame->GetPosition().x : aFrame->GetPosition().y;
       coords[index] -= NSAppUnitsToFloatPixels(offset, aAppUnitsPerPixel);
     }
   }
 
   coords[2] = NSAppUnitsToFloatPixels(display->mTransformOrigin[2].GetCoordValue(),
                                       aAppUnitsPerPixel);
-  if (aBoundsOverride) {
-    // Adjust based on the origin of the override:
-    coords[0] += NSAppUnitsToFloatPixels(aBoundsOverride->x, aAppUnitsPerPixel);
-    coords[1] += NSAppUnitsToFloatPixels(aBoundsOverride->y, aAppUnitsPerPixel);
-  }
 
   return Point3D(coords[0], coords[1], coords[2]);
 }
 
 /* Returns the delta specified by the -moz-perspective-origin property.
  * This is a positive delta, meaning that it indicates the direction to move
  * to get from (0, 0) of the frame to the perspective origin. This function is
  * called off the main thread.
@@ -4909,16 +4904,27 @@ nsDisplayTransform::GetResultingTransfor
     Point3D(NSAppUnitsToFloatPixels(aOrigin.x, aAppUnitsPerPixel),
             NSAppUnitsToFloatPixels(aOrigin.y, aAppUnitsPerPixel),
             0.0f);
   Point3D roundedOrigin(hasSVGTransforms ? newOrigin.x : NS_round(newOrigin.x),
                         hasSVGTransforms ? newOrigin.y : NS_round(newOrigin.y),
                         0);
   Point3D offsetBetweenOrigins = roundedOrigin + aProperties.mToTransformOrigin;
 
+  if (aOffsetByOrigin) {
+    // We can fold the final translation by roundedOrigin into the first matrix
+    // basis change translation. This is more stable against variation due to
+    // insufficient floating point precision than reversing the translation
+    // afterwards.
+    result.Translate(-aProperties.mToTransformOrigin);
+    result.TranslatePost(offsetBetweenOrigins);
+  } else {
+    result.ChangeBasis(offsetBetweenOrigins);
+  }
+
   if (frame && frame->Preserves3D()) {
     // Include the transform set on our parent
     NS_ASSERTION(frame->GetParent() &&
                  frame->GetParent()->IsTransformed() &&
                  frame->GetParent()->Preserves3DChildren(),
                  "Preserve3D mismatch!");
     FrameTransformProperties props(frame->GetParent(),
                                    aAppUnitsPerPixel,
@@ -4928,37 +4934,19 @@ nsDisplayTransform::GetResultingTransfor
     // then we're not a reference frame so no offset to origin will be added. Our
     // parent transform however *is* the reference frame, so we pass true for
     // aOffsetByOrigin to convert into the correct coordinate space.
     gfx3DMatrix parent =
       GetResultingTransformMatrixInternal(props,
                                           aOrigin - frame->GetPosition(),
                                           aAppUnitsPerPixel, nullptr,
                                           aOutAncestor, !frame->IsTransformed());
-
-    if (aOffsetByOrigin) {
-      result.Translate(-aProperties.mToTransformOrigin);
-      result.TranslatePost(offsetBetweenOrigins);
-    } else {
-      result.ChangeBasis(offsetBetweenOrigins);
-    }
     result = result * parent;
-    return result;
-  }
-
-  if (aOffsetByOrigin) {
-    // We can fold the final translation by roundedOrigin into the first matrix
-    // basis change translation. This is more stable against variation due to
-    // insufficient floating point precision than reversing the translation
-    // afterwards.
-    result.Translate(-aProperties.mToTransformOrigin);
-    result.TranslatePost(offsetBetweenOrigins);
-  } else {
-    result.ChangeBasis(offsetBetweenOrigins);
-  }
+  }
+
   return result;
 }
 
 bool
 nsDisplayOpacity::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder)
 {
   if (ActiveLayerTracker::IsStyleAnimated(aBuilder, mFrame, eCSSProperty_opacity)) {
     return true;
--- a/layout/mathml/mathml.css
+++ b/layout/mathml/mathml.css
@@ -6,28 +6,26 @@
 /**************************************************************************/
 /* namespace for MathML elements                                          */
 /**************************************************************************/
 
 @namespace url(http://www.w3.org/1998/Math/MathML);
 
 /**************************************************************************/
 /* <math> - outermost math element                                        */
-/* Put Cambria before Cambria Math as Cambria Math has neither bold nor   */
-/* italic.                                                                */
 /**************************************************************************/
 
 math {
   writing-mode: horizontal-tb !important;
   direction: ltr;
   unicode-bidi: embed;
   display: inline;
   font-size: inherit;
   font-style: normal;
-  font-family: MathJax_Main, STIXGeneral, Cambria, Cambria Math, XITS, Latin Modern Math, DejaVu Serif, DejaVu Sans, Times, Lucida Sans Unicode, OpenSymbol, Standard Symbols L, serif;
+  font-family: serif;
   text-rendering: optimizeLegibility;
   -moz-float-edge: margin-box;
   -moz-math-display: inline;
 }
 math[mode="display"], math[display="block"] {
   display: block;
   text-align: -moz-center;
   -moz-math-display: block;
--- a/layout/mathml/nsMathMLChar.cpp
+++ b/layout/mathml/nsMathMLChar.cpp
@@ -1655,18 +1655,20 @@ nsMathMLChar::StretchInternal(nsPresCont
 
   if (!done) { // normal case
     // Use the css font-family but add preferred fallback fonts.
     font = mStyleContext->StyleFont()->mFont;
     NormalizeDefaultFont(font, aFontSizeInflation);
 
     // really shouldn't be doing things this way but for now
     // insert fallbacks into the list
-    nsAutoTArray<nsString, 10> mathFallbacks;
-    gfxFontUtils::GetPrefsFontList("font.mathfont-family", mathFallbacks);
+    nsAutoTArray<nsString, 16> mathFallbacks;
+    gfxFontUtils::GetPrefsFontList("font.name.serif.x-math", mathFallbacks);
+    gfxFontUtils::AppendPrefsFontList("font.name-list.serif.x-math",
+                                      mathFallbacks);
     InsertMathFallbacks(font.fontlist, mathFallbacks);
 
 
 #ifdef NOISY_SEARCH
     nsAutoString fontlistStr;
     font.fontlist.ToString(fontlistStr, false, true);
     printf("Searching in "%s" for a glyph of appropriate size for: 0x%04X:%c\n",
            NS_ConvertUTF16toUTF8(fontlistStr).get(), mData[0], mData[0]&0x00FF);
new file mode 100644
--- /dev/null
+++ b/layout/reftests/mathml/default-font-ref.html
@@ -0,0 +1,13 @@
+<html>
+  <head>
+    <title>default font</title>
+    <meta charset="utf-8"/>
+  </head>
+  <body style="font: 20px monospace;">
+
+    <math style="font-family: serif; font-size: 40px;">
+      <mn>x-math language</mn>
+    </math>
+
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/mathml/default-font.html
@@ -0,0 +1,14 @@
+<html>
+  <head>
+    <title>default font</title>
+    <meta charset="utf-8"/>
+  </head>
+  <body style="font: 20px monospace;">
+
+    <!-- font.minimum-size.x-math set to 40 -->
+    <math>
+      <mn>x-math language</mn>
+    </math>
+
+  </body>
+</html>
--- a/layout/reftests/mathml/reftest.list
+++ b/layout/reftests/mathml/reftest.list
@@ -34,17 +34,17 @@ skip-if((B2G&&browserIsRemote)||Mulet) r
 == mfenced-5b.xhtml mfenced-5-ref.xhtml
 == mfenced-5c.xhtml mfenced-5-ref.xhtml
 == mfenced-5d.xhtml mfenced-5-ref.xhtml
 == mfenced-6.html mfenced-6-ref.html
 == mfenced-7.html mfenced-7-ref.html
 != mfenced-8.html mfenced-8-ref.html
 == mfenced-9.html mfenced-9-ref.html
 fails-if(/^Windows\x20NT\x205\.1/.test(http.oscpu)) == mfenced-10.html mfenced-10-ref.html # Windows versions without Cambria Math, see bug 670592
-fails-if(winWidget&&d2d) == mfenced-11.html mfenced-11-ref.html
+== mfenced-11.html mfenced-11-ref.html
 skip-if(Mulet) == mfenced-12.html mfenced-12-ref.html # MULET: Bug 1144079: Re-enable Mulet mochitests and reftests taskcluster-specific disables
 == mi-mathvariant-1.xhtml mi-mathvariant-1-ref.xhtml
 == mi-mathvariant-2.xhtml mi-mathvariant-2-ref.xhtml
 != mi-mathvariant-3.html mi-mathvariant-3-ref.html
 != non-spacing-accent-1.xhtml non-spacing-accent-1-ref.xhtml
 == overbar-width-1.xhtml overbar-width-1-ref.xhtml
 skip-if(B2G||Mulet) == quotes-1.xhtml quotes-1-ref.xhtml # Initial mulet triage: parity with B2G/B2G Desktop
 != stretchy-underbar-1.xhtml stretchy-underbar-1-ref.xhtml
@@ -134,19 +134,19 @@ random-if(winWidget&&!/^Windows\x20NT\x2
 == mspace-1.html mspace-1-ref.html
 == mpadded-1.html mpadded-1-ref.html
 == mpadded-2.html mpadded-2-ref.html
 == mpadded-3.html mpadded-3-ref.html
 == mpadded-4.html mpadded-4-ref.html
 == mpadded-5.html mpadded-5-ref.html
 == mpadded-1-2.html mpadded-1-2-ref.html
 == mpadded-6.html mpadded-6-ref.html
-fails-if(B2G||Mulet) == mpadded-7.html mpadded-7-ref.html # B2G: slight character width variation # MULET: Bug 1144079: Re-enable Mulet mochitests and reftests taskcluster-specific disables
-fails-if(B2G) == mpadded-8.html mpadded-8-ref.html # B2G: slight character width variation
-fails-if(B2G) == mpadded-9.html mpadded-9-ref.html # B2G: slight character width variation
+fails-if(Mulet) == mpadded-7.html mpadded-7-ref.html # MULET: Bug 1144079: Re-enable Mulet mochitests and reftests taskcluster-specific disables
+== mpadded-8.html mpadded-8-ref.html
+== mpadded-9.html mpadded-9-ref.html
 == math-display.html math-display-ref.html
 == scriptlevel-1.html scriptlevel-1-ref.html
 == scriptlevel-movablelimits-1.html scriptlevel-movablelimits-1-ref.html
 == munderover-align-accent-false.html munderover-align-accent-false-ref.html
 == munderover-align-accent-true.html munderover-align-accent-true-ref.html
 == munder-mover-align-accent-true.html munder-mover-align-accent-true-ref.html
 == munder-mover-align-accent-false.html munder-mover-align-accent-false-ref.html
 == mfrac-linethickness-1.xhtml mfrac-linethickness-1-ref.xhtml
@@ -193,17 +193,17 @@ skip-if(B2G||Mulet) == maction-dynamic-3
 == whitespace-trim-3.html whitespace-trim-3-ref.html
 fails == whitespace-trim-4.html whitespace-trim-4-ref.html # Bug 787215
 == whitespace-trim-5.html whitespace-trim-5-ref.html
 random-if(winWidget&&!d2d) == opentype-stretchy.html opentype-stretchy-ref.html
 == opentype-fraction-dynamic-linethickness.html opentype-fraction-dynamic-linethickness-ref.html
 == operator-1.xhtml operator-1-ref.xhtml
 == scriptshift-1.xhtml scriptshift-1-ref.xhtml
 == number-size-1.xhtml number-size-1-ref.xhtml
-random-if((B2G&&browserIsRemote)||Mulet) == multiscripts-1.html multiscripts-1-ref.html # B2G - slight height variation from font metrics # Initial mulet triage: parity with B2G/B2G Desktop
+random-if((B2G&&browserIsRemote)||Mulet) fails-if(winWidget&&/^Windows\x20NT\x205\.1/.test(http.oscpu)) == multiscripts-1.html multiscripts-1-ref.html # B2G - slight height variation from font metrics # Initial mulet triage: parity with B2G/B2G Desktop
 == mathml-mmultiscript-base.html mathml-mmultiscript-base-ref.html
 == mathml-mmultiscript-mprescript.html mathml-mmultiscript-mprescript-ref.html
 != menclose-1a.html menclose-1-ref.html
 != menclose-1b.html menclose-1-ref.html
 != menclose-1c.html menclose-1-ref.html
 != menclose-1d.html menclose-1-ref.html
 != menclose-1e.html menclose-1-ref.html
 != menclose-1f.html menclose-1-ref.html
@@ -340,25 +340,26 @@ fails-if(B2G||Mulet||Android||/^Windows\
 == mfrac-A-2.html mfrac-A-2-ref.html
 == mfrac-A-3.html mfrac-A-3-ref.html
 == mfrac-A-4.html mfrac-A-4-ref.html
 == mfrac-A-5.html mfrac-A-5-ref.html
 == mfrac-A-6.html mfrac-A-6-ref.html
 == mfrac-A-7.html mfrac-A-7-ref.html
 == mfrac-A-8.html mfrac-A-8-ref.html
 == mfrac-B-1.html mfrac-B-1-ref.html
-random-if(winWidget&&!/^Windows\x20NT\x205\.1/.test(http.oscpu)) == mfrac-B-2.html mfrac-B-2-3-ref.html
-random-if(winWidget&&!/^Windows\x20NT\x205\.1/.test(http.oscpu)) == mfrac-B-3.html mfrac-B-2-3-ref.html
+fails-if(winWidget) == mfrac-B-2.html mfrac-B-2-3-ref.html
+fails-if(winWidget) == mfrac-B-3.html mfrac-B-2-3-ref.html
 == mfrac-B-4.html mfrac-B-4-5-ref.html
 == mfrac-B-5.html mfrac-B-4-5-ref.html
 == mfrac-B-6.html mfrac-B-6-7-ref.html
 == mfrac-B-7.html mfrac-B-6-7-ref.html
 fuzzy-if(OSX,1,100) == mfrac-C-1.html mfrac-C-1-ref.html
-random-if(winWidget&&!/^Windows\x20NT\x205\.1/.test(http.oscpu)) == mfrac-C-2.html mfrac-C-2-ref.html
+fails-if(winWidget) == mfrac-C-2.html mfrac-C-2-ref.html
 == mfrac-C-3.html mfrac-C-3-ref.html
 == mfrac-C-4.html mfrac-C-4-ref.html
 fuzzy-if(OSX,1,100) == mfrac-D-1.html mfrac-D-1-ref.html
-random-if(winWidget&&!/^Windows\x20NT\x205\.1/.test(http.oscpu)) == mfrac-D-2.html mfrac-D-2-ref.html
+fails-if(winWidget) == mfrac-D-2.html mfrac-D-2-ref.html
 == mfrac-D-3.html mfrac-D-3-ref.html
 == mfrac-D-4.html mfrac-D-4-ref.html
 == mfrac-E-1.html mfrac-E-1-ref.html
 test-pref(dom.webcomponents.enabled,true) == shadow-dom-1.html shadow-dom-1-ref.html
 pref(font.size.inflation.emPerLine,25) == font-inflation-1.html font-inflation-1-ref.html
+test-pref(font.minimum-size.x-math,40) == default-font.html default-font-ref.html
--- a/layout/style/TopLevelVideoDocument.css
+++ b/layout/style/TopLevelVideoDocument.css
@@ -19,13 +19,14 @@ video {
   position: absolute;
   top: 0;
   right: 0;
   bottom: 0;
   left: 0;
   margin: auto;
   max-width: 100%;
   max-height: 100%;
+  -moz-user-select: none;
 }
 
 video:focus {
   outline-width: 0;
 }
--- a/layout/style/nsHTMLStyleSheet.cpp
+++ b/layout/style/nsHTMLStyleSheet.cpp
@@ -301,16 +301,23 @@ nsHTMLStyleSheet::RulesMatching(ElementR
 
   // http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html#language
   // says that the xml:lang attribute overrides HTML's lang attribute,
   // so we need to do this after WalkContentStyleRules.
   nsString lang;
   if (aData->mElement->GetAttr(kNameSpaceID_XML, nsGkAtoms::lang, lang)) {
     ruleWalker->Forward(LangRuleFor(lang));
   }
+
+  // Set the language to "x-math" on the <math> element, so that appropriate
+  // font settings are used for MathML.
+  if (aData->mElement->IsMathMLElement(nsGkAtoms::math)) {
+    nsGkAtoms::x_math->ToString(lang);
+    ruleWalker->Forward(LangRuleFor(lang));
+  }
 }
 
 // Test if style is dependent on content state
 /* virtual */ nsRestyleHint
 nsHTMLStyleSheet::HasStateDependentStyle(StateRuleProcessorData* aData)
 {
   if (aData->mElement->IsHTMLElement(nsGkAtoms::a) &&
       nsCSSRuleProcessor::IsLink(aData->mElement) &&
--- a/layout/style/nsHTMLStyleSheet.h
+++ b/layout/style/nsHTMLStyleSheet.h
@@ -127,16 +127,18 @@ private:
 
     virtual void MapRuleInfoInto(nsRuleData* aRuleData) override;
   };
 
 public: // for mLangRuleTable structures only
 
   // Rule to handle xml:lang attributes, of which we have exactly one
   // per language string, maintained in mLangRuleTable.
+  // We also create one extra rule for the "x-math" language string, used on
+  // <math> elements.
   class LangRule final : public nsIStyleRule {
   private:
     ~LangRule() {}
   public:
     explicit LangRule(const nsSubstring& aLang) : mLang(aLang) {}
 
     NS_DECL_ISUPPORTS
 
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -65,32 +65,25 @@ struct nsTableReflowState {
   nsSize availSize;
 
   // Stationary x-offset
   nscoord x;
 
   // Running y-offset
   nscoord y;
 
-  nsTableReflowState(nsPresContext&           aPresContext,
-                     const nsHTMLReflowState& aReflowState,
-                     nsTableFrame&            aTableFrame,
+  nsTableReflowState(const nsHTMLReflowState& aReflowState,
                      nscoord                  aAvailWidth,
                      nscoord                  aAvailHeight)
     : reflowState(aReflowState)
   {
-    Init(aPresContext, aTableFrame, aAvailWidth, aAvailHeight);
-  }
-
-  void Init(nsPresContext&  aPresContext,
-            nsTableFrame&   aTableFrame,
-            nscoord         aAvailWidth,
-            nscoord         aAvailHeight)
-  {
-    nsTableFrame* table = static_cast<nsTableFrame*>(aTableFrame.FirstInFlow());
+    MOZ_ASSERT(reflowState.frame->GetType() == nsGkAtoms::tableFrame,
+               "nsTableReflowState should only be created for nsTableFrame");
+    nsTableFrame* table =
+      static_cast<nsTableFrame*>(reflowState.frame->FirstInFlow());
     nsMargin borderPadding = table->GetChildAreaOffset(&reflowState);
 
     x = borderPadding.left + table->GetColSpacing(-1);
     y = borderPadding.top; //cellspacing added during reflow
 
     availSize.width  = aAvailWidth;
     if (NS_UNCONSTRAINEDSIZE != availSize.width) {
       int32_t colCount = table->GetColCount();
@@ -103,25 +96,16 @@ struct nsTableReflowState {
     availSize.height = aAvailHeight;
     if (NS_UNCONSTRAINEDSIZE != availSize.height) {
       availSize.height -= borderPadding.top + borderPadding.bottom
                           + table->GetRowSpacing(-1)
                           + table->GetRowSpacing(table->GetRowCount());
       availSize.height = std::max(0, availSize.height);
     }
   }
-
-  nsTableReflowState(nsPresContext&           aPresContext,
-                     const nsHTMLReflowState& aReflowState,
-                     nsTableFrame&            aTableFrame)
-    : reflowState(aReflowState)
-  {
-    Init(aPresContext, aTableFrame, aReflowState.AvailableWidth(), aReflowState.AvailableHeight());
-  }
-
 };
 
 /********************************************************************************
  ** nsTableFrame                                                               **
  ********************************************************************************/
 
 struct BCPropertyData
 {
@@ -2048,17 +2032,17 @@ nsTableFrame::ReflowTable(nsHTMLReflowMe
 
   if (!GetPrevInFlow()) {
     mTableLayoutStrategy->ComputeColumnISizes(aReflowState);
   }
   // Constrain our reflow width to the computed table width (of the 1st in flow).
   // and our reflow height to our avail height minus border, padding, cellspacing
   aDesiredSize.Width() = aReflowState.ComputedWidth() +
                        aReflowState.ComputedPhysicalBorderPadding().LeftRight();
-  nsTableReflowState reflowState(*PresContext(), aReflowState, *this,
+  nsTableReflowState reflowState(aReflowState,
                                  aDesiredSize.Width(), aAvailHeight);
   ReflowChildren(reflowState, aStatus, aLastChildReflowed,
                  aDesiredSize.mOverflowAreas);
 
   ReflowColGroups(aReflowState.rendContext);
 }
 
 nsIFrame*
--- a/memory/mozjemalloc/jemalloc.c
+++ b/memory/mozjemalloc/jemalloc.c
@@ -5833,21 +5833,16 @@ MALLOC_OUT:
 	/* Take care to call atexit() only once. */
 	if (opt_print_stats) {
 #ifndef MOZ_MEMORY_WINDOWS
 		/* Print statistics at exit. */
 		atexit(malloc_print_stats);
 #endif
 	}
 
-#if !defined(MOZ_MEMORY_WINDOWS) && !defined(MOZ_MEMORY_DARWIN)
-	/* Prevent potential deadlock on malloc locks after fork. */
-	pthread_atfork(_malloc_prefork, _malloc_postfork, _malloc_postfork);
-#endif
-
 #ifndef MALLOC_STATIC_SIZES
 	/* Set variables according to the value of opt_small_max_2pow. */
 	if (opt_small_max_2pow < opt_quantum_2pow)
 		opt_small_max_2pow = opt_quantum_2pow;
 	small_max = (1U << opt_small_max_2pow);
 
 	/* Set bin-related variables. */
 	bin_maxclass = (pagesize >> 1);
@@ -6040,16 +6035,21 @@ MALLOC_OUT:
 #ifdef MALLOC_VALIDATE
 	chunk_rtree = malloc_rtree_new((SIZEOF_PTR << 3) - opt_chunk_2pow);
 	if (chunk_rtree == NULL)
 		return (true);
 #endif
 
 	malloc_initialized = true;
 
+#if !defined(MOZ_MEMORY_WINDOWS) && !defined(MOZ_MEMORY_DARWIN)
+	/* Prevent potential deadlock on malloc locks after fork. */
+	pthread_atfork(_malloc_prefork, _malloc_postfork, _malloc_postfork);
+#endif
+
 #if defined(NEEDS_PTHREAD_MMAP_UNALIGNED_TSD)
 	if (pthread_key_create(&mmap_unaligned_tsd, NULL) != 0) {
 		malloc_printf("<jemalloc>: Error in pthread_key_create()\n");
 	}
 #endif
 
 #if defined(MOZ_MEMORY_DARWIN) && !defined(MOZ_REPLACE_MALLOC)
 	/*
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1838,17 +1838,20 @@ pref("intl.hyphenation-alias.bs-*", "sh"
 
 // Norwegian has two forms, Bokmål and Nynorsk, with "no" as a macrolanguage encompassing both.
 // For "no", we'll alias to "nb" (Bokmål) as that is the more widely used written form.
 pref("intl.hyphenation-alias.no", "nb");
 pref("intl.hyphenation-alias.no-*", "nb");
 pref("intl.hyphenation-alias.nb-*", "nb");
 pref("intl.hyphenation-alias.nn-*", "nn");
 
-pref("font.mathfont-family", "Latin Modern Math, XITS Math, STIX Math, Cambria Math, Asana Math, TeX Gyre Bonum Math, TeX Gyre Pagella Math, TeX Gyre Termes Math, Neo Euler, Lucida Bright Math, MathJax_Main, STIXNonUnicode, STIXSizeOneSym, STIXGeneral, Standard Symbols L, DejaVu Sans");
+pref("font.name.serif.x-math", "Latin Modern Math");
+pref("font.name-list.serif.x-math", "Latin Modern Math, XITS Math, Cambria Math, TeX Gyre Bonum Math, TeX Gyre Pagella Math, TeX Gyre Schola, TeX Gyre Termes Math, STIX Math, Asana Math, MathJax_Main, STIXGeneral, DejaVu Serif, DejaVu Sans, Standard Symbols L, serif");
+pref("font.name.sans-serif.x-math", "sans-serif");
+pref("font.name.monospace.x-math", "monospace");
 
 // Some CJK fonts have bad underline offset, their CJK character glyphs are overlapped (or adjoined)  to its underline.
 // These fonts are ignored the underline offset, instead of it, the underline is lowered to bottom of its em descent.
 pref("font.blacklist.underline_offset", "FangSong,Gulim,GulimChe,MingLiU,MingLiU-ExtB,MingLiU_HKSCS,MingLiU-HKSCS-ExtB,MS Gothic,MS Mincho,MS PGothic,MS PMincho,MS UI Gothic,PMingLiU,PMingLiU-ExtB,SimHei,SimSun,SimSun-ExtB,Hei,Kai,Apple LiGothic,Apple LiSung,Osaka");
 
 #ifdef MOZ_B2G
 // Whitelist of fonts that ship with B2G that do not include space lookups in
 // default features. This allows us to skip analyzing the GSUB/GPOS tables
@@ -2623,16 +2626,20 @@ pref("font.minimum-size.zh-HK", 0);
 pref("font.size.variable.zh-HK", 16);
 pref("font.size.fixed.zh-HK", 16);
 
 pref("font.default.zh-TW", "sans-serif");
 pref("font.minimum-size.zh-TW", 0);
 pref("font.size.variable.zh-TW", 16);
 pref("font.size.fixed.zh-TW", 16);
 
+// mathml.css sets font-size to "inherit" and font-family to "serif" so only
+// font.name.*.x-math and font.minimum-size.x-math are really relevant.
+pref("font.minimum-size.x-math", 0);
+
 /*
  * A value greater than zero enables font size inflation for
  * pan-and-zoom UIs, so that the fonts in a block are at least the size
  * that, if a block's width is scaled to match the device's width, the
  * fonts in the block are big enough that at most the pref value ems of
  * text fit in *the width of the device*.
  *
  * When both this pref and the next are set, the larger inflation is
@@ -2945,18 +2952,22 @@ pref("font.name.sans-serif.x-tibt", "Tib
 pref("font.name.monospace.x-tibt", "Tibetan Machine Uni");
 pref("font.name-list.serif.x-tibt", "Tibetan Machine Uni, Jomolhari, Microsoft Himalaya");
 pref("font.name-list.sans-serif.x-tibt", "Tibetan Machine Uni, Jomolhari, Microsoft Himalaya");
 pref("font.name-list.monospace.x-tibt", "Tibetan Machine Uni, Jomolhari, Microsoft Himalaya");
 
 pref("font.minimum-size.th", 10);
 
 pref("font.default.x-devanagari", "sans-serif");
+pref("font.name.serif.x-math", "Latin Modern Math");
 // We have special support for Monotype Symbol on Windows.
-pref("font.mathfont-family", "MathJax_Main, STIXNonUnicode, STIXSizeOneSym, STIXGeneral, Asana Math, Symbol, DejaVu Sans, Cambria Math");
+pref("font.name-list.serif.x-math", "Latin Modern Math, XITS Math, Cambria Math, TeX Gyre Bonum Math, TeX Gyre Pagella Math, TeX Gyre Schola, TeX Gyre Termes Math, STIX Math, Asana Math, MathJax_Main, STIXGeneral, DejaVu Serif, DejaVu Sans, Symbol, Times New Roman");
+pref("font.name.sans-serif.x-math", "Arial");
+pref("font.name.monospace.x-math", "Courier New");
+pref("font.name.cursive.x-math", "Comic Sans MS");
 
 // cleartype settings - false implies default system settings
 
 // use cleartype rendering for downloadable fonts (win xp only)
 pref("gfx.font_rendering.cleartype.use_for_downloadable_fonts", true);
 
 // use cleartype rendering for all fonts always (win xp only)
 pref("gfx.font_rendering.cleartype.always_use_for_content", false);
@@ -3372,18 +3383,23 @@ pref("font.name-list.sans-serif.zh-HK", 
 pref("font.name-list.monospace.zh-HK", "Courier,Heiti TC,LiHei Pro");
 
 // XP_MACOSX changes to default font sizes
 pref("font.minimum-size.th", 10);
 pref("font.size.variable.zh-CN", 15);
 pref("font.size.variable.zh-HK", 15);
 pref("font.size.variable.zh-TW", 15);
 
+pref("font.name.serif.x-math", "Latin Modern Math");
 // Apple's Symbol is Unicode so use it
-pref("font.mathfont-family", "Latin Modern Math, XITS Math, STIX Math, Cambria Math, Asana Math, TeX Gyre Bonum Math, TeX Gyre Pagella Math, TeX Gyre Termes Math, Neo Euler, Lucida Bright Math, MathJax_Main, STIXNonUnicode, STIXSizeOneSym, STIXGeneral, Symbol, DejaVu Sans");
+pref("font.name-list.serif.x-math", "Latin Modern Math, XITS Math, Cambria Math, TeX Gyre Bonum Math, TeX Gyre Pagella Math, TeX Gyre Schola, TeX Gyre Termes Math, STIX Math, Asana Math, MathJax_Main, STIXGeneral, DejaVu Serif, DejaVu Sans, Symbol, Times");
+pref("font.name.sans-serif.x-math", "Helvetica");
+pref("font.name.monospace.x-math", "Courier");
+pref("font.name.cursive.x-math", "Apple Chancery");
+pref("font.name.fantasy.x-math", "Papyrus");
 
 // individual font faces to be treated as independent families
 // names are Postscript names of each face
 pref("font.single-face-list", "Osaka-Mono");
 
 // optimization hint for fonts with localized names to be read in at startup, otherwise read in at lookup miss
 // names are canonical family names (typically English names)
 pref("font.preload-names-list", "Hiragino Kaku Gothic ProN,Hiragino Mincho ProN,STSong");
@@ -3554,16 +3570,19 @@ pref("print.print_landscape", false);
 pref("print.print_paper_size", 0);
 
 // print_extra_margin enables platforms to specify an extra gap or margin
 // around the content of the page for Print Preview only
 pref("print.print_extra_margin", 0); // twips
 
 // font names
 
+pref("font.name.serif.ar", "serif");
+pref("font.name.sans-serif.ar", "sans-serif");
+pref("font.name.monospace.ar", "monospace");
 pref("font.size.fixed.ar", 12);
 
 pref("font.name.serif.el", "serif");
 pref("font.name.sans-serif.el", "sans-serif");
 pref("font.name.monospace.el", "monospace");
 pref("font.size.fixed.el", 12);
 
 pref("font.name.serif.he", "serif");
@@ -3576,45 +3595,109 @@ pref("font.name.sans-serif.ja", "sans-se
 pref("font.name.monospace.ja", "monospace");
 
 pref("font.name.serif.ko", "serif");
 pref("font.name.sans-serif.ko", "sans-serif");
 pref("font.name.monospace.ko", "monospace");
 
 pref("font.name.serif.th", "serif");
 pref("font.name.sans-serif.th", "sans-serif");
+pref("font.name.monospace.th", "monospace");
 pref("font.minimum-size.th", 13);
-pref("font.name.monospace.th", "monospace");
+
+pref("font.name.serif.x-armn", "serif");
+pref("font.name.sans-serif.x-armn", "sans-serif");
+pref("font.name.monospace.x-armn", "monospace");
+
+pref("font.name.serif.x-beng", "serif");
+pref("font.name.sans-serif.x-beng", "sans-serif");
+pref("font.name.monospace.x-beng", "monospace");
+
+pref("font.name.serif.x-cans", "serif");
+pref("font.name.sans-serif.x-cans", "sans-serif");
+pref("font.name.monospace.x-cans", "monospace");
 
 pref("font.name.serif.x-cyrillic", "serif");
 pref("font.name.sans-serif.x-cyrillic", "sans-serif");
 pref("font.name.monospace.x-cyrillic", "monospace");
 pref("font.size.fixed.x-cyrillic", 12);
 
+pref("font.name.serif.x-devanagari", "serif");
+pref("font.name.sans-serif.x-devanagari", "sans-serif");
+pref("font.name.monospace.x-devanagari", "monospace");
+
+pref("font.name.serif.x-ethi", "serif");
+pref("font.name.sans-serif.x-ethi", "sans-serif");
+pref("font.name.monospace.x-ethi", "monospace");
+
+pref("font.name.serif.x-geor", "serif");
+pref("font.name.sans-serif.x-geor", "sans-serif");
+pref("font.name.monospace.x-geor", "monospace");
+
+pref("font.name.serif.x-gujr", "serif");
+pref("font.name.sans-serif.x-gujr", "sans-serif");
+pref("font.name.monospace.x-gujr", "monospace");
+
+pref("font.name.serif.x-guru", "serif");
+pref("font.name.sans-serif.x-guru", "sans-serif");
+pref("font.name.monospace.x-guru", "monospace");
+
+pref("font.name.serif.x-khmr", "serif");
+pref("font.name.sans-serif.x-khmr", "sans-serif");
+pref("font.name.monospace.x-khmr", "monospace");
+
+pref("font.name.serif.x-knda", "serif");
+pref("font.name.sans-serif.x-knda", "sans-serif");
+pref("font.name.monospace.x-knda", "monospace");
+
+pref("font.name.serif.x-mlym", "serif");
+pref("font.name.sans-serif.x-mlym", "sans-serif");
+pref("font.name.monospace.x-mlym", "monospace");
+
+pref("font.name.serif.x-orya", "serif");
+pref("font.name.sans-serif.x-orya", "sans-serif");
+pref("font.name.monospace.x-orya", "monospace");
+
+pref("font.name.serif.x-sinh", "serif");
+pref("font.name.sans-serif.x-sinh", "sans-serif");
+pref("font.name.monospace.x-sinh", "monospace");
+
+pref("font.name.serif.x-tamil", "serif");
+pref("font.name.sans-serif.x-tamil", "sans-serif");
+pref("font.name.monospace.x-tamil", "monospace");
+
+pref("font.name.serif.x-telu", "serif");
+pref("font.name.sans-serif.x-telu", "sans-serif");
+pref("font.name.monospace.x-telu", "monospace");
+
+pref("font.name.serif.x-tibt", "serif");
+pref("font.name.sans-serif.x-tibt", "sans-serif");
+pref("font.name.monospace.x-tibt", "monospace");
+
 pref("font.name.serif.x-unicode", "serif");
 pref("font.name.sans-serif.x-unicode", "sans-serif");
 pref("font.name.monospace.x-unicode", "monospace");
 pref("font.size.fixed.x-unicode", 12);
 
 pref("font.name.serif.x-western", "serif");
 pref("font.name.sans-serif.x-western", "sans-serif");
 pref("font.name.monospace.x-western", "monospace");
 pref("font.size.fixed.x-western", 12);
 
 pref("font.name.serif.zh-CN", "serif");
 pref("font.name.sans-serif.zh-CN", "sans-serif");
 pref("font.name.monospace.zh-CN", "monospace");
 
-// ming_uni.ttf (HKSCS-2001)
-// http://www.info.gov.hk/digital21/eng/hkscs/download/uime.exe
 pref("font.name.serif.zh-HK", "serif");
 pref("font.name.sans-serif.zh-HK", "sans-serif");
 pref("font.name.monospace.zh-HK", "monospace");
 
-// zh-TW
+pref("font.name.serif.zh-TW", "serif");
+pref("font.name.sans-serif.zh-TW", "sans-serif");
+pref("font.name.monospace.zh-TW", "monospace");
 
 /* PostScript print module prefs */
 // pref("print.postscript.enabled",      true);
 pref("print.postscript.paper_size",    "letter");
 pref("print.postscript.orientation",   "portrait");
 pref("print.postscript.print_command", "lpr ${MOZ_PRINTER_NAME:+-P\"$MOZ_PRINTER_NAME\"}");
 
 // On GTK2 platform, we should use topmost window level for the default window
@@ -3727,16 +3810,21 @@ pref("font.name.sans-serif.zh-HK", "Fira
 pref("font.name.monospace.zh-HK", "Fira Mono");
 pref("font.name-list.sans-serif.zh-HK", "Fira Sans,Droid Sans Fallback");
 
 pref("font.name.serif.zh-TW", "Charis SIL Compact");
 pref("font.name.sans-serif.zh-TW", "Fira Sans");
 pref("font.name.monospace.zh-TW", "Fira Mono");
 pref("font.name-list.sans-serif.zh-TW", "Fira Sans,Droid Sans Fallback");
 
+pref("font.name.serif.x-math", "Latin Modern Math");
+pref("font.name-list.serif.x-math", "Latin Modern Math, XITS Math, Cambria Math, TeX Gyre Bonum Math, TeX Gyre Pagella Math, TeX Gyre Schola, TeX Gyre Termes Math, STIX Math, Asana Math, MathJax_Main, STIXGeneral, DejaVu Serif, DejaVu Sans, Charis SIL Compact");
+pref("font.name.sans-serif.x-math", "Fira Sans");
+pref("font.name.monospace.x-math", "Fira Mono");
+
 #elif defined(ANDROID)
 // We use the bundled fonts for Firefox for Android
 
 // ar
 
 pref("font.name.serif.el", "Droid Serif"); // not Charis SIL Compact, only has a few Greek chars
 pref("font.name.sans-serif.el", "Clear Sans");
 pref("font.name.monospace.el", "Droid Sans Mono");
@@ -3800,16 +3888,21 @@ pref("font.name-list.monospace.zh-HK", "
 
 pref("font.name.serif.zh-TW", "Charis SIL Compact");
 pref("font.name.sans-serif.zh-TW", "Clear Sans");
 pref("font.name.monospace.zh-TW", "Droid Sans Mono");
 pref("font.name-list.serif.zh-TW", "Droid Serif, Droid Sans Fallback");
 pref("font.name-list.sans-serif.zh-TW", "Roboto, Droid Sans, Noto Sans TC, Noto Sans SC, Droid Sans Fallback");
 pref("font.name-list.monospace.zh-TW", "Droid Sans Fallback");
 
+pref("font.name.serif.x-math", "Latin Modern Math");
+pref("font.name-list.serif.x-math", "Latin Modern Math, XITS Math, Cambria Math, TeX Gyre Bonum Math, TeX Gyre Pagella Math, TeX Gyre Schola, TeX Gyre Termes Math, STIX Math, Asana Math, MathJax_Main, STIXGeneral, DejaVu Serif, DejaVu Sans, Charis SIL Compact");
+pref("font.name.sans-serif.x-math", "Clear Sans");
+pref("font.name.monospace.x-math", "Droid Sans Mono");
+
 #endif
 
 #if OS_ARCH==AIX
 
 // Override default Japanese fonts
 pref("font.name.serif.ja", "dt-interface system-jisx0208.1983-0");
 pref("font.name.sans-serif.ja", "dt-interface system-jisx0208.1983-0");
 pref("font.name.monospace.ja", "dt-interface user-jisx0208.1983-0");
--- a/mozilla-config.h.in
+++ b/mozilla-config.h.in
@@ -36,21 +36,18 @@
 #pragma clang diagnostic pop
 #endif
 
 /*
  * Force-include Char16.h in order to define PRUnichar as char16_t everywhere.
  * Note that this should be the first #include to make sure that prtypes.h does
  * not attempt to define PRUnichar.  This includes the following hunspell-specific
  * includes.
- *
- * We don't use this to build elfhack and elf-dynstr-gc since those builds happen
- * during the export tier.  Also, disable this when building assembly files too.
  */
-#if !defined(ELFHACK_BUILD) && !defined(__ASSEMBLER__)
+#if !defined(__ASSEMBLER__)
 #include "mozilla/Char16.h"
 #endif
 
 /*
  * Force-include hunspell_alloc_hooks.h and hunspell_fopen_hooks.h for hunspell,
  * so that we don't need to modify them directly.
  *
  * HUNSPELL_STATIC is defined in extensions/spellcheck/hunspell/src/Makefile.in,
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -1227,16 +1227,21 @@ HttpChannelChild::Redirect3Complete()
   if (mLoadGroup)
     mLoadGroup->RemoveRequest(this, nullptr, NS_BINDING_ABORTED);
 
   if (NS_FAILED(rv))
     NS_WARNING("CompleteRedirectSetup failed, HttpChannelChild already open?");
 
   // Release ref to new channel.
   mRedirectChannelChild = nullptr;
+
+  if (mInterceptListener) {
+    mInterceptListener->Cleanup();
+    mInterceptListener = nullptr;
+  }
 }
 
 //-----------------------------------------------------------------------------
 // HttpChannelChild::nsIChildChannel
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 HttpChannelChild::ConnectParent(uint32_t id)
--- a/storage/mozStorageAsyncStatementParams.cpp
+++ b/storage/mozStorageAsyncStatementParams.cpp
@@ -101,25 +101,27 @@ AsyncStatementParams::Resolve(nsIXPConne
   // prototype chain to be checked for the property.
 
   bool resolved = false;
   bool ok = true;
   if (JSID_IS_INT(aId)) {
     uint32_t idx = JSID_TO_INT(aId);
     // All indexes are good because we don't know how many parameters there
     // really are.
-    ok = ::JS_DefineElement(aCtx, scopeObj, idx, JS::UndefinedHandleValue, 0);
+    ok = ::JS_DefineElement(aCtx, scopeObj, idx, JS::UndefinedHandleValue,
+                            JSPROP_RESOLVING);
     resolved = true;
   }
   else if (JSID_IS_STRING(aId)) {
     // We are unable to tell if there's a parameter with this name and so
     // we must assume that there is.  This screws the rest of the prototype
     // chain, but people really shouldn't be depending on this anyways.
     JS::Rooted<jsid> id(aCtx, aId);
-    ok = ::JS_DefinePropertyById(aCtx, scopeObj, id, JS::UndefinedHandleValue, 0);
+    ok = ::JS_DefinePropertyById(aCtx, scopeObj, id, JS::UndefinedHandleValue,
+                                 JSPROP_RESOLVING);
     resolved = true;
   }
 
   *_retval = ok;
   *aResolvedp = resolved && ok;
   return NS_OK;
 }
 
--- a/storage/mozStorageStatementJSHelper.cpp
+++ b/storage/mozStorageStatementJSHelper.cpp
@@ -229,17 +229,17 @@ StatementJSHelper::Resolve(nsIXPConnectW
                            bool *_retval)
 {
   if (!JSID_IS_STRING(aId))
     return NS_OK;
 
   JS::RootedObject scope(aCtx, aScopeObj);
   if (::JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(aId), "step")) {
     *_retval = ::JS_DefineFunction(aCtx, scope, "step", stepFunc,
-                                   0, 0) != nullptr;
+                                   0, JSPROP_RESOLVING) != nullptr;
     *aResolvedp = true;
     return NS_OK;
   }
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// StatementJSObjectHolder
--- a/storage/mozStorageStatementParams.cpp
+++ b/storage/mozStorageStatementParams.cpp
@@ -144,33 +144,35 @@ StatementParams::Resolve(nsIXPConnectWra
   if (JSID_IS_INT(id)) {
     uint32_t idx = JSID_TO_INT(id);
 
     // Ensure that our index is within range.  We do not care about the
     // prototype chain being checked here.
     if (idx >= mParamCount)
       return NS_ERROR_INVALID_ARG;
 
-    ok = ::JS_DefineElement(aCtx, scope, idx, JS::UndefinedHandleValue, JSPROP_ENUMERATE);
+    ok = ::JS_DefineElement(aCtx, scope, idx, JS::UndefinedHandleValue,
+                            JSPROP_ENUMERATE | JSPROP_RESOLVING);
     resolved = true;
   }
   else if (JSID_IS_STRING(id)) {
     JSString *str = JSID_TO_STRING(id);
     nsAutoJSString autoStr;
     if (!autoStr.init(aCtx, str)) {
       return NS_ERROR_FAILURE;
     }
 
     // Check to see if there's a parameter with this name, and if not, let
     // the rest of the prototype chain be checked.
     NS_ConvertUTF16toUTF8 name(autoStr);
     uint32_t idx;
     nsresult rv = mStatement->GetParameterIndex(name, &idx);
     if (NS_SUCCEEDED(rv)) {
-      ok = ::JS_DefinePropertyById(aCtx, scope, id, JS::UndefinedHandleValue, JSPROP_ENUMERATE);
+      ok = ::JS_DefinePropertyById(aCtx, scope, id, JS::UndefinedHandleValue,
+                                   JSPROP_ENUMERATE | JSPROP_RESOLVING);
       resolved = true;
     }
   }
 
   *_retval = ok;
   *resolvedp = resolved && ok;
   return NS_OK;
 }
--- a/storage/mozStorageStatementRow.cpp
+++ b/storage/mozStorageStatementRow.cpp
@@ -137,17 +137,18 @@ StatementRow::Resolve(nsIXPConnectWrappe
       // It's highly likely that the name doesn't exist, so let the JS engine
       // check the prototype chain and throw if that doesn't have the property
       // either.
       *aResolvedp = false;
       return NS_OK;
     }
 
     JS::Rooted<jsid> id(aCtx, aId);
-    *_retval = ::JS_DefinePropertyById(aCtx, scopeObj, id, JS::UndefinedHandleValue, 0);
+    *_retval = ::JS_DefinePropertyById(aCtx, scopeObj, id, JS::UndefinedHandleValue,
+                                       JSPROP_RESOLVING);
     *aResolvedp = true;
     return NS_OK;
   }
 
   return NS_OK;
 }
 
 } // namespace storage
new file mode 100644
--- /dev/null
+++ b/testing/docker/desktop-build/REGISTRY
@@ -0,0 +1,1 @@
+quay.io/djmitche
--- a/testing/docker/desktop-build/VERSION
+++ b/testing/docker/desktop-build/VERSION
@@ -1,1 +1,1 @@
-0.0.7
+0.0.11
--- a/testing/docker/desktop-build/bin/build.sh
+++ b/testing/docker/desktop-build/bin/build.sh
@@ -65,17 +65,17 @@ tc-vcs checkout mozharness $MOZHARNESS_B
 # check out tools where mozharness expects it to be ($PWD/build/tools and $WORKSPACE/build/tools)
 tc-vcs checkout $WORKSPACE/build/tools $TOOLS_BASE_REPOSITORY $TOOLS_HEAD_REPOSITORY $TOOLS_REV
 if [ ! -d build ]; then
     mkdir -p build
     ln -s $WORKSPACE/build/tools build/tools
 fi
 
 # and check out mozilla-central where mozharness will use it as a cache (/builds/hg-shared)
-tc-vcs checkout /builds/hg-shared/mozilla-central $GECKO_BASE_REPOSITORY $GECKO_HEAD_REPOSITORY $GECKO_REV
+tc-vcs checkout $WORKSPACE/build/src $GECKO_BASE_REPOSITORY $GECKO_HEAD_REPOSITORY $GECKO_REV
 
 # run mozharness in XVfb, if necessary; this is an array to maintain the quoting in the -s argument
 if $NEED_XVFB; then
     # Some mozharness scripts set DISPLAY=:2
     Xvfb :2 -screen 0 1024x768x24 &
     export DISPLAY=:2
     xvfb_pid=$!
     # Only error code 255 matters, because it signifies that no
@@ -126,21 +126,25 @@ set -x
 export TOOLTOOL_CACHE
 
 # support multiple, space delimited, config files
 config_cmds=""
 for cfg in $MOZHARNESS_CONFIG; do
   config_cmds="${config_cmds} --config ${cfg}"
 done
 
+# Mozharness would ordinarily do the checkouts itself, but they are disabled
+# here (--no-checkout-sources, --no-clone-tools) as the checkout is performed above.
+
 ./${MOZHARNESS_SCRIPT} ${config_cmds} \
   $debug_flag \
   $custom_build_variant_cfg_flag \
   --disable-mock \
   --no-setup-mock \
+  --no-checkout-sources \
   --no-clone-tools \
   --no-clobber \
   --no-update \
   --log-level=debug \
   --work-dir=$WORKSPACE/build \
   --no-action=generate-build-stats \
   --branch=${MH_BRANCH} \
   --build-pool=${MH_BUILD_POOL}
new file mode 100644
--- /dev/null
+++ b/testing/docker/ubuntu-build/REPOSITORY
@@ -0,0 +1,1 @@
+quay.io/djmitche
--- a/testing/taskcluster/tasks/branches/base_job_flags.yml
+++ b/testing/taskcluster/tasks/branches/base_job_flags.yml
@@ -20,16 +20,17 @@ flags:
     - flame-kk       # b2g flame kitkat
     - flame-kk-eng   # b2g flame eng build
     - dolphin
     - dolphin-eng
     - dolphin-512
     - dolphin-512-eng
     - aries-nightly
     - aries-eng
+    - android-api-11
 
   tests:
     - cppunit
     - crashtest
     - crashtest-ipc
     - gaia-build
     - gaia-build-unit
     - gaia-js-integration
--- a/testing/taskcluster/tasks/branches/try/job_flags.yml
+++ b/testing/taskcluster/tasks/branches/try/job_flags.yml
@@ -95,16 +95,22 @@ builds:
       opt:
         task: tasks/builds/b2g_dolphin_512_opt.yml
   dolphin-512-eng:
     platforms:
       - b2g
     types:
       opt:
         task: tasks/builds/b2g_dolphin_512_eng.yml
+  android-api-11:
+    platforms:
+      - Android
+    types:
+      opt:
+        task: tasks/builds/android_api_11.yml
 
 tests:
   cppunit:
     allowed_build_tasks:
       tasks/builds/b2g_emulator_ics_opt.yml:
         task: tasks/tests/b2g_emulator_cpp_unit.yml
       tasks/builds/b2g_emulator_ics_debug.yml:
         task: tasks/tests/b2g_emulator_cpp_unit.yml
new file mode 100644
--- /dev/null
+++ b/testing/taskcluster/tasks/builds/android_api_11.yml
@@ -0,0 +1,62 @@
+$inherits:
+  from: 'tasks/build.yml'
+  variables:
+    build_name: 'android'
+    build_type: 'opt'
+task:
+  metadata:
+      name: '[TC] Android armv7 API 11+'
+      description: 'Android armv7 API 11+'
+
+  workerType: b2g-desktop-opt
+
+  routes:
+    - 'index.buildbot.branches.{{project}}.android-api-11'
+    - 'index.buildbot.revisions.{{head_rev}}.{{project}}.android-api-11'
+
+  scopes:
+    - 'docker-worker:cache:build-android-api-11-workspace'
+    - 'docker-worker:cache:tooltool-cache'
+
+  payload:
+    image: '{{#docker_image}}desktop-build{{/docker_image}}'
+    cache:
+      build-android-api-11-workspace: '/home/worker/workspace'
+      tooltool-cache: '/home/worker/tools/tooltool-cache'
+
+    env:
+      # 1164623: rename this var
+      GECKO_REV: '{{head_rev}}'
+      # 1164623: rename these three vars
+      MOZHARNESS_BASE_REPOSITORY: '{{mozharness_repository}}'
+      MOZHARNESS_HEAD_REPOSITORY: '{{mozharness_repository}}'
+      MOZHARNESS_REV: '{{mozharness_rev}}'
+
+      MOZHARNESS_SCRIPT: 'mozharness/scripts/fx_desktop_build.py'
+      MOZHARNESS_CONFIG: 'builds/releng_base_android_64_builds.py'
+      MH_CUSTOM_BUILD_VARIANT_CFG: api-11
+      MH_BRANCH: {{project}}
+      MH_BUILD_POOL: taskcluster
+
+      TOOLTOOL_CACHE: '/home/worker/tooltool-cache'
+      RELENGAPI_TOKEN: 'TODO' # 1164612: encrypt this secret
+
+    maxRunTime: 36000
+
+    command: ["/bin/bash", "bin/build.sh"]
+
+  extra:
+    treeherderEnv:
+      - production
+      - staging
+    treeherder:
+      machine:
+        # see https://github.com/mozilla/treeherder/blob/master/ui/js/values.js
+        platform: android-4-0-armv7-api11
+    # Rather then enforcing particular conventions we require that all build
+    # tasks provide the "build" extra field to specify where the build and tests
+    # files are located.
+    locations:
+      build: 'public/build/target.linux-x86_64.tar.bz2'
+      tests: 'public/build/target.tests.zip'
+
--- a/toolkit/components/addoncompat/tests/addon/bootstrap.js
+++ b/toolkit/components/addoncompat/tests/addon/bootstrap.js
@@ -533,16 +533,67 @@ function testProgressListener()
       gBrowser.removeTab(tab);
       gBrowser.removeProgressListener(globalListener);
       gBrowser.removeTabsProgressListener(tabsListener);
       resolve();
     });
   });
 }
 
+function testRootTreeItem()
+{
+  return new Promise(function(resolve, reject) {
+    const url = baseURL + "browser_addonShims_testpage.html";
+    let tab = gBrowser.addTab(url);
+    gBrowser.selectedTab = tab;
+    let browser = tab.linkedBrowser;
+    addLoadListener(browser, function handler() {
+      let win = browser.contentWindow;
+
+      // Add-ons love this crap.
+      let root = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                    .getInterface(Components.interfaces.nsIWebNavigation)
+                    .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
+                    .rootTreeItem
+                    .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                    .getInterface(Components.interfaces.nsIDOMWindow);
+      is(root, gWin, "got correct chrome window");
+
+      gBrowser.removeTab(tab);
+      resolve();
+    });
+  });
+}
+
+function testImportNode()
+{
+  return new Promise(function(resolve, reject) {
+    const url = baseURL + "browser_addonShims_testpage.html";
+    let tab = gBrowser.addTab(url);
+    gBrowser.selectedTab = tab;
+    let browser = tab.linkedBrowser;
+    addLoadListener(browser, function handler() {
+      let node = gWin.document.createElement("div");
+      let doc = browser.contentDocument;
+      let result;
+      try {
+        result = doc.importNode(node, false);
+      } catch (e) {
+        ok(false, "importing threw an exception");
+      }
+      if (browser.isRemoteBrowser) {
+        is(result, node, "got expected import result");
+      }
+
+      gBrowser.removeTab(tab);
+      resolve();
+    });
+  });
+}
+
 function runTests(win, funcs)
 {
   ok = funcs.ok;
   is = funcs.is;
   info = funcs.info;
 
   gWin = win;
   gBrowser = win.gBrowser;
@@ -550,16 +601,18 @@ function runTests(win, funcs)
   return testContentWindow().
     then(testListeners).
     then(testCapturing).
     then(testObserver).
     then(testSandbox).
     then(testAddonContent).
     then(testAboutModuleRegistration).
     then(testProgressListener).
+    then(testRootTreeItem).
+    then(testImportNode).
     then(Promise.resolve());
 }
 
 /*
  bootstrap.js API
 */
 
 function startup(aData, aReason)
--- a/toolkit/content/editMenuOverlay.js
+++ b/toolkit/content/editMenuOverlay.js
@@ -12,18 +12,17 @@ function goUpdateGlobalEditMenuItems()
   // cut, copy, and paste buttons been added to the toolbars) for performance.
   // This only works in applications/on platforms that set the gEditUIVisible
   // flag, so we check to see if that flag is defined before using it.
   if (typeof gEditUIVisible != "undefined" && !gEditUIVisible)
     return;
 
   goUpdateCommand("cmd_undo");
   goUpdateCommand("cmd_redo");
-  goUpdateCommand("cmd_cut");
-  goUpdateCommand("cmd_copy");
+  // don't update the cmd_cut or cmd_copy items - as we want them to always be enabled
   goUpdateCommand("cmd_paste");
   goUpdateCommand("cmd_selectAll");
   goUpdateCommand("cmd_delete");
   goUpdateCommand("cmd_switchTextDirection");
 }
 
 // update menu items that relate to undo/redo
 function goUpdateUndoEditMenuItems()
--- a/toolkit/content/globalOverlay.js
+++ b/toolkit/content/globalOverlay.js
@@ -88,17 +88,17 @@ function goUpdateCommand(aCommand)
   }
 }
 
 function goDoCommand(aCommand)
 {
   try {
     var controller = top.document.commandDispatcher
                         .getControllerForCommand(aCommand);
-    if (controller && controller.isCommandEnabled(aCommand))
+    if (controller)
       controller.doCommand(aCommand);
   }
   catch (e) {
     Components.utils.reportError("An error occurred executing the " +
                                  aCommand + " command: " + e);
   }
 }
 
--- a/toolkit/content/tests/chrome/bug366992_window.xul
+++ b/toolkit/content/tests/chrome/bug366992_window.xul
@@ -14,44 +14,44 @@
         height="600"
         title="366992 test">
 
   <commandset id="editMenuCommands"/>
 
   <script type="application/javascript"
           src="chrome://global/content/globalOverlay.js"/>
   <script type="application/javascript"><![CDATA[
-    // Without the fix for bug 366992, the copy command would be enabled
+    // Without the fix for bug 366992, the delete command would be enabled
     // for the textbox even though the textbox's controller for this command
     // disables it.
     var gShouldNotBeReachedController = {
       supportsCommand: function(aCommand) {
-        return aCommand == "cmd_copy";
+        return aCommand == "cmd_delete";
       },
       isCommandEnabled: function(aCommand) {
-        return aCommand == "cmd_copy";
+        return aCommand == "cmd_delete";
       },
       doCommand: function(aCommand) { }
     }
 
     function ok(condition, message) {
       window.opener.wrappedJSObject.SimpleTest.ok(condition, message);
     }
     function finish() {
       window.controllers.removeController(gShouldNotBeReachedController);
       window.close();
       window.opener.wrappedJSObject.SimpleTest.finish();
     }
 
     function onLoad() {
       document.getElementById("textbox").focus();
-      var copyDisabled = document.getElementById("cmd_copy")
-                                 .getAttribute("disabled") == "true";
-      ok(copyDisabled,
-         "cmd_copy should be disabled when the empty textbox is focused");
+      var deleteDisabled = document.getElementById("cmd_delete")
+                                   .getAttribute("disabled") == "true";
+      ok(deleteDisabled,
+         "cmd_delete should be disabled when the empty textbox is focused");
       finish();
     }
     
     window.controllers.appendController(gShouldNotBeReachedController);
   ]]></script>
 
   <textbox id="textbox"/>
 </window>
--- a/widget/PuppetWidget.cpp
+++ b/widget/PuppetWidget.cpp
@@ -224,17 +224,17 @@ PuppetWidget::Resize(double aWidth,
   return NS_OK;
 }
 
 nsresult
 PuppetWidget::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
 {
   for (uint32_t i = 0; i < aConfigurations.Length(); ++i) {
     const Configuration& configuration = aConfigurations[i];
-    PuppetWidget* w = static_cast<PuppetWidget*>(configuration.mChild);
+    PuppetWidget* w = static_cast<PuppetWidget*>(configuration.mChild.get());
     NS_ASSERTION(w->GetParent() == this,
                  "Configured widget is not a child");
     w->SetWindowClipRegion(configuration.mClipRegion, true);
     nsIntRect bounds;
     w->GetBounds(bounds);
     if (bounds.Size() != configuration.mBounds.Size()) {
       w->Resize(configuration.mBounds.x, configuration.mBounds.y,
                 configuration.mBounds.width, configuration.mBounds.height,
--- a/widget/TextEvents.h
+++ b/widget/TextEvents.h
@@ -543,16 +543,21 @@ public:
   }
 
   bool mSucceeded;
   bool mWasAsync;
   bool mUseNativeLineBreak;
   bool mWithFontRanges;
   struct
   {
+    uint32_t EndOffset() const
+    {
+      return mOffset + mLength;
+    }
+
     uint32_t mOffset;
     uint32_t mLength;
   } mInput;
 
   struct Reply
   {
     void* mContentsRoot;
     uint32_t mOffset;
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -275,17 +275,17 @@ nsWindow::Destroy(void)
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::ConfigureChildren(const nsTArray<nsIWidget::Configuration>& config)
 {
     for (uint32_t i = 0; i < config.Length(); ++i) {
-        nsWindow *childWin = (nsWindow*) config[i].mChild;
+        nsWindow *childWin = (nsWindow*) config[i].mChild.get();
         childWin->Resize(config[i].mBounds.x,
                          config[i].mBounds.y,
                          config[i].mBounds.width,
                          config[i].mBounds.height,
                          false);
     }
 
     return NS_OK;
--- a/widget/cocoa/VibrancyManager.h
+++ b/widget/cocoa/VibrancyManager.h
@@ -21,17 +21,18 @@ class nsIntRegion;
 
 namespace mozilla {
 
 enum class VibrancyType {
   LIGHT,
   DARK,
   TOOLTIP,
   MENU,
-  HIGHLIGHTED_MENUITEM
+  HIGHLIGHTED_MENUITEM,
+  SHEET
 };
 
 /**
  * VibrancyManager takes care of updating the vibrant regions of a window.
  * Vibrancy is a visual look that was introduced on OS X starting with 10.10.
  * An app declares vibrant window regions to the window server, and the window
  * server will display a blurred rendering of the screen contents from behind
  * the window in these areas, behind the actual window contents. Consequently,
--- a/widget/cocoa/VibrancyManager.mm
+++ b/widget/cocoa/VibrancyManager.mm
@@ -185,16 +185,17 @@ static id
 AppearanceForVibrancyType(VibrancyType aType)
 {
   Class NSAppearanceClass = NSClassFromString(@"NSAppearance");
   switch (aType) {
     case VibrancyType::LIGHT:
     case VibrancyType::TOOLTIP:
     case VibrancyType::MENU:
     case VibrancyType::HIGHLIGHTED_MENUITEM:
+    case VibrancyType::SHEET:
       return [NSAppearanceClass performSelector:@selector(appearanceNamed:)
                                      withObject:@"NSAppearanceNameVibrantLight"];
     case VibrancyType::DARK:
       return [NSAppearanceClass performSelector:@selector(appearanceNamed:)
                                      withObject:@"NSAppearanceNameVibrantDark"];
   }
 }
 
@@ -212,18 +213,20 @@ enum {
 
 static NSUInteger
 VisualEffectStateForVibrancyType(VibrancyType aType)
 {
   switch (aType) {
     case VibrancyType::TOOLTIP:
     case VibrancyType::MENU:
     case VibrancyType::HIGHLIGHTED_MENUITEM:
-      // Tooltip and menu windows are never "key", so we need to tell the
-      // vibrancy effect to look active regardless of window state.
+    case VibrancyType::SHEET:
+      // Tooltip and menu windows are never "key" and sheets always looks
+      // active, so we need to tell the vibrancy effect to look active
+      // regardless of window state.
       return NSVisualEffectStateActive;
     default:
       return NSVisualEffectStateFollowsWindowActiveState;
   }
 }
 
 static BOOL
 HasVibrantForeground(VibrancyType aType)
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -2490,35 +2490,38 @@ static void MakeRegionsNonOverlapping(Re
 
 void
 nsChildView::UpdateVibrancy(const nsTArray<ThemeGeometry>& aThemeGeometries)
 {
   if (!VibrancyManager::SystemSupportsVibrancy()) {
     return;
   }
 
+  nsIntRegion sheetRegion =
+    GatherThemeGeometryRegion(aThemeGeometries, nsNativeThemeCocoa::eThemeGeometryTypeSheet);
   nsIntRegion vibrantLightRegion =
     GatherThemeGeometryRegion(aThemeGeometries, nsNativeThemeCocoa::eThemeGeometryTypeVibrancyLight);
   nsIntRegion vibrantDarkRegion =
     GatherThemeGeometryRegion(aThemeGeometries, nsNativeThemeCocoa::eThemeGeometryTypeVibrancyDark);
   nsIntRegion menuRegion =
     GatherThemeGeometryRegion(aThemeGeometries, nsNativeThemeCocoa::eThemeGeometryTypeMenu);
   nsIntRegion tooltipRegion =
     GatherThemeGeometryRegion(aThemeGeometries, nsNativeThemeCocoa::eThemeGeometryTypeTooltip);
   nsIntRegion highlightedMenuItemRegion =
     GatherThemeGeometryRegion(aThemeGeometries, nsNativeThemeCocoa::eThemeGeometryTypeHighlightedMenuItem);
 
-  MakeRegionsNonOverlapping(vibrantLightRegion, vibrantDarkRegion, menuRegion,
-                            tooltipRegion, highlightedMenuItemRegion);
+  MakeRegionsNonOverlapping(sheetRegion, vibrantLightRegion, vibrantDarkRegion,
+                            menuRegion, tooltipRegion, highlightedMenuItemRegion);
 
   auto& vm = EnsureVibrancyManager();
   vm.UpdateVibrantRegion(VibrancyType::LIGHT, vibrantLightRegion);
   vm.UpdateVibrantRegion(VibrancyType::TOOLTIP, tooltipRegion);
   vm.UpdateVibrantRegion(VibrancyType::MENU, menuRegion);
   vm.UpdateVibrantRegion(VibrancyType::HIGHLIGHTED_MENUITEM, highlightedMenuItemRegion);
+  vm.UpdateVibrantRegion(VibrancyType::SHEET, sheetRegion);
   vm.UpdateVibrantRegion(VibrancyType::DARK, vibrantDarkRegion);
 }
 
 void
 nsChildView::ClearVibrantAreas()
 {
   if (VibrancyManager::SystemSupportsVibrancy()) {
     EnsureVibrancyManager().ClearVibrantAreas();
@@ -2534,16 +2537,18 @@ ThemeGeometryTypeToVibrancyType(nsITheme
     case nsNativeThemeCocoa::eThemeGeometryTypeVibrancyDark:
       return VibrancyType::DARK;
     case nsNativeThemeCocoa::eThemeGeometryTypeTooltip:
       return VibrancyType::TOOLTIP;
     case nsNativeThemeCocoa::eThemeGeometryTypeMenu:
       return VibrancyType::MENU;
     case nsNativeThemeCocoa::eThemeGeometryTypeHighlightedMenuItem:
       return VibrancyType::HIGHLIGHTED_MENUITEM;
+    case nsNativeThemeCocoa::eThemeGeometryTypeSheet:
+      return VibrancyType::SHEET;
     default:
       MOZ_CRASH();
   }
 }
 
 NSColor*
 nsChildView::VibrancyFillColorForThemeGeometryType(nsITheme::ThemeGeometryType aThemeGeometryType)
 {
--- a/widget/cocoa/nsNativeThemeCocoa.h
+++ b/widget/cocoa/nsNativeThemeCocoa.h
@@ -34,16 +34,17 @@ public:
     eThemeGeometryTypeToolbox,
     eThemeGeometryTypeWindowButtons,
     eThemeGeometryTypeFullscreenButton,
     eThemeGeometryTypeMenu,
     eThemeGeometryTypeHighlightedMenuItem,
     eThemeGeometryTypeVibrancyLight,
     eThemeGeometryTypeVibrancyDark,
     eThemeGeometryTypeTooltip,
+    eThemeGeometryTypeSheet,
   };
 
   nsNativeThemeCocoa();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   // The nsITheme interface.
   NS_IMETHOD DrawWidgetBackground(nsRenderingContext* aContext,
@@ -70,17 +71,18 @@ public:
   NS_IMETHOD WidgetStateChanged(nsIFrame* aFrame, uint8_t aWidgetType, 
                                 nsIAtom* aAttribute, bool* aShouldRepaint) override;
   NS_IMETHOD ThemeChanged() override;
   bool ThemeSupportsWidget(nsPresContext* aPresContext, nsIFrame* aFrame, uint8_t aWidgetType) override;
   bool WidgetIsContainer(uint8_t aWidgetType) override;
   bool ThemeDrawsFocusForWidget(uint8_t aWidgetType) override;
   bool ThemeNeedsComboboxDropmarker() override;
   virtual bool WidgetAppearanceDependsOnWindowFocus(uint8_t aWidgetType) override;
-  virtual bool NeedToClearBackgroundBehindWidget(uint8_t aWidgetType) override;
+  virtual bool NeedToClearBackgroundBehindWidget(nsIFrame* aFrame,
+                                                 uint8_t aWidgetType) override;
   virtual bool WidgetProvidesFontSmoothingBackgroundColor(nsIFrame* aFrame, uint8_t aWidgetType,
                                                           nscolor* aColor) override;
   virtual ThemeGeometryType ThemeGeometryTypeForWidget(nsIFrame* aFrame,
                                                        uint8_t aWidgetType) override;
   virtual Transparency GetWidgetTransparency(nsIFrame* aFrame, uint8_t aWidgetType) override;
 
   void DrawProgress(CGContextRef context, const HIRect& inBoxRect,
                     bool inIsIndeterminate, bool inIsHorizontal,
@@ -91,16 +93,17 @@ public:
 
 protected:
   virtual ~nsNativeThemeCocoa();
 
   nsIntMargin DirectionAwareMargin(const nsIntMargin& aMargin, nsIFrame* aFrame);
   nsIFrame* SeparatorResponsibility(nsIFrame* aBefore, nsIFrame* aAfter);
   CGRect SeparatorAdjustedRect(CGRect aRect, nsIFrame* aLeft,
                                nsIFrame* aCurrent, nsIFrame* aRight);
+  bool IsWindowSheet(nsIFrame* aFrame);
 
   // HITheme drawing routines
   void DrawFrame(CGContextRef context, HIThemeFrameKind inKind,
                  const HIRect& inBoxRect, bool inReadOnly,
                  mozilla::EventStates inState);
   void DrawMeter(CGContextRef context, const HIRect& inBoxRect,
                  nsIFrame* aFrame);
   void DrawSegment(CGContextRef cgContext, const HIRect& inBoxRect,
--- a/widget/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/cocoa/nsNativeThemeCocoa.mm
@@ -2393,18 +2393,29 @@ nsNativeThemeCocoa::DrawWidgetBackground
   //CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 1.0, 0.1);
   //CGContextFillRect(cgContext, bounds);
 #endif
 
   EventStates eventState = GetContentState(aFrame, aWidgetType);
 
   switch (aWidgetType) {
     case NS_THEME_DIALOG: {
-      HIThemeSetFill(kThemeBrushDialogBackgroundActive, NULL, cgContext, HITHEME_ORIENTATION);
-      CGContextFillRect(cgContext, macRect);
+      if (IsWindowSheet(aFrame)) {
+        if (VibrancyManager::SystemSupportsVibrancy()) {
+          ThemeGeometryType type = ThemeGeometryTypeForWidget(aFrame, aWidgetType);
+          DrawVibrancyBackground(cgContext, macRect, aFrame, type);
+        } else {
+          HIThemeSetFill(kThemeBrushSheetBackgroundTransparent, NULL, cgContext, HITHEME_ORIENTATION);
+          CGContextFillRect(cgContext, macRect);
+        }
+      } else {
+        HIThemeSetFill(kThemeBrushDialogBackgroundActive, NULL, cgContext, HITHEME_ORIENTATION);
+        CGContextFillRect(cgContext, macRect);
+      }
+
     }
       break;
 
     case NS_THEME_MENUPOPUP:
       if (VibrancyManager::SystemSupportsVibrancy()) {
         DrawVibrancyBackground(cgContext, macRect, aFrame, eThemeGeometryTypeMenu, 4);
       } else {
         HIThemeMenuDrawInfo mdi;
@@ -3762,26 +3773,41 @@ nsNativeThemeCocoa::WidgetAppearanceDepe
     case NS_THEME_RESIZER:
       return false;
     default:
       return true;
   }
 }
 
 bool
-nsNativeThemeCocoa::NeedToClearBackgroundBehindWidget(uint8_t aWidgetType)
+nsNativeThemeCocoa::IsWindowSheet(nsIFrame* aFrame)
+{
+  NSWindow* win = NativeWindowForFrame(aFrame);
+  id winDelegate = [win delegate];
+  nsIWidget* widget = [(WindowDelegate *)winDelegate geckoWidget];
+  if (!widget) {
+    return false;
+  }
+  return (widget->WindowType() == eWindowType_sheet);
+}
+
+bool
+nsNativeThemeCocoa::NeedToClearBackgroundBehindWidget(nsIFrame* aFrame,
+                                                      uint8_t aWidgetType)
 {
   switch (aWidgetType) {
     case NS_THEME_MAC_VIBRANCY_LIGHT:
     case NS_THEME_MAC_VIBRANCY_DARK:
     case NS_THEME_TOOLTIP:
     case NS_THEME_MENUPOPUP:
     case NS_THEME_MENUITEM:
     case NS_THEME_CHECKMENUITEM:
       return true;
+    case NS_THEME_DIALOG:
+      return IsWindowSheet(aFrame);
     default:
       return false;
   }
 }
 
 static nscolor ConvertNSColor(NSColor* aColor)
 {
   NSColor* deviceColor = [aColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
@@ -3798,17 +3824,21 @@ nsNativeThemeCocoa::WidgetProvidesFontSm
 {
   switch (aWidgetType) {
     case NS_THEME_MAC_VIBRANCY_LIGHT:
     case NS_THEME_MAC_VIBRANCY_DARK:
     case NS_THEME_TOOLTIP:
     case NS_THEME_MENUPOPUP:
     case NS_THEME_MENUITEM:
     case NS_THEME_CHECKMENUITEM:
+    case NS_THEME_DIALOG:
     {
+      if (aWidgetType == NS_THEME_DIALOG && !IsWindowSheet(aFrame)) {
+        return false;
+      }
       ChildView* childView = ChildViewForFrame(aFrame);
       if (childView) {
         ThemeGeometryType type = ThemeGeometryTypeForWidget(aFrame, aWidgetType);
         NSColor* color = [childView vibrancyFontSmoothingBackgroundColorForThemeGeometryType:type];
         *aColor = ConvertNSColor(color);
         return true;
       }
       return false;
@@ -3843,29 +3873,34 @@ nsNativeThemeCocoa::ThemeGeometryTypeFor
       return eThemeGeometryTypeMenu;
     case NS_THEME_MENUITEM:
     case NS_THEME_CHECKMENUITEM: {
       EventStates eventState = GetContentState(aFrame, aWidgetType);
       bool isDisabled = IsDisabled(aFrame, eventState);
       bool isSelected = !isDisabled && CheckBooleanAttr(aFrame, nsGkAtoms::menuactive);
       return isSelected ? eThemeGeometryTypeHighlightedMenuItem : eThemeGeometryTypeMenu;
     }
+    case NS_THEME_DIALOG:
+      return IsWindowSheet(aFrame) ? eThemeGeometryTypeSheet : eThemeGeometryTypeUnknown;
     default:
       return eThemeGeometryTypeUnknown;
   }
 }
 
 nsITheme::Transparency
 nsNativeThemeCocoa::GetWidgetTransparency(nsIFrame* aFrame, uint8_t aWidgetType)
 {
   switch (aWidgetType) {
   case NS_THEME_MENUPOPUP:
   case NS_THEME_TOOLTIP:
     return eTransparent;
 
+  case NS_THEME_DIALOG:
+    return IsWindowSheet(aFrame) ? eTransparent : eOpaque;
+
   case NS_THEME_SCROLLBAR_SMALL:
   case NS_THEME_SCROLLBAR:
     return nsLookAndFeel::UseOverlayScrollbars() ? eTransparent : eOpaque;
 
   case NS_THEME_STATUSBAR:
     // Knowing that scrollbars and statusbars are opaque improves
     // performance, because we create layers for them.
     return eOpaque;
--- a/widget/gonk/HwcComposer2D.cpp
+++ b/widget/gonk/HwcComposer2D.cpp
@@ -853,21 +853,17 @@ HwcComposer2D::Commit()
         if (mHwcLayerMap.IsEmpty() ||
             (mList->hwLayers[j].compositionType == HWC_FRAMEBUFFER)) {
             continue;
         }
         LayerRenderState state = mHwcLayerMap[j]->GetLayer()->GetRenderState();
         if (!state.mTexture) {
             continue;
         }
-        TextureHostOGL* texture = state.mTexture->AsHostOGL();
-        if (!texture) {
-            continue;
-        }
-        FenceHandle fence = texture->GetAndResetAcquireFence();
+        FenceHandle fence = state.mTexture->GetAndResetAcquireFenceHandle();
         if (fence.IsValid()) {
             nsRefPtr<FenceHandle::FdObj> fdObj = fence.GetAndResetFdObj();
             mList->hwLayers[j].acquireFenceFd = fdObj->GetAndResetFd();
         }
     }
 
     int err = mHwc->set(mHwc, HWC_NUM_DISPLAY_TYPES, displays);
 
@@ -879,21 +875,17 @@ HwcComposer2D::Commit()
             mList->hwLayers[j].releaseFenceFd = -1;
             nsRefPtr<FenceHandle::FdObj> fdObj = new FenceHandle::FdObj(fd);
             FenceHandle fence(fdObj);
 
             LayerRenderState state = mHwcLayerMap[j]->GetLayer()->GetRenderState();
             if (!state.mTexture) {
                 continue;
             }
-            TextureHostOGL* texture = state.mTexture->AsHostOGL();
-            if (!texture) {
-                continue;
-            }
-            texture->SetReleaseFence(fence);
+            state.mTexture->SetReleaseFenceHandle(fence);
         }
     }
 
     if (mList->retireFenceFd >= 0) {
         mPrevRetireFence = FenceHandle(new FenceHandle::FdObj(mList->retireFenceFd));
     }
 
     mPrepared = false;
--- a/widget/gtk/mozgtk/mozgtk.c
+++ b/widget/gtk/mozgtk/mozgtk.c
@@ -204,16 +204,17 @@ STUB(gtk_file_chooser_set_current_folder
 STUB(gtk_file_chooser_set_current_name)
 STUB(gtk_file_chooser_set_do_overwrite_confirmation)
 STUB(gtk_file_chooser_set_filename)
 STUB(gtk_file_chooser_set_filter)
 STUB(gtk_file_chooser_set_local_only)
 STUB(gtk_file_chooser_set_preview_widget)
 STUB(gtk_file_chooser_set_preview_widget_active)
 STUB(gtk_file_chooser_set_select_multiple)
+STUB(gtk_file_chooser_widget_get_type)
 STUB(gtk_file_filter_add_pattern)
 STUB(gtk_file_filter_new)
 STUB(gtk_file_filter_set_name)
 STUB(gtk_fixed_new)
 STUB(gtk_frame_new)
 STUB(gtk_grab_add)
 STUB(gtk_grab_remove)
 STUB(gtk_handle_box_new)
--- a/widget/gtk/nsFilePicker.cpp
+++ b/widget/gtk/nsFilePicker.cpp
@@ -160,17 +160,18 @@ MakeCaseInsensitiveShellGlob(const char*
   return result;
 }
 
 NS_IMPL_ISUPPORTS(nsFilePicker, nsIFilePicker)
 
 nsFilePicker::nsFilePicker()
   : mSelectedType(0),
     mRunning(false),
-    mAllowURLs(false)
+    mAllowURLs(false),
+    mFileChooserDelegate(nullptr)
 {
 }
 
 nsFilePicker::~nsFilePicker()
 {
 }
 
 void
@@ -426,16 +427,37 @@ nsFilePicker::Open(nsIFilePickerShownCal
       // directories.
       defaultPath->AppendNative(defaultName);
       nsAutoCString path;
       defaultPath->GetNativePath(path);
       gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(file_chooser), path.get());
     } else {
       nsAutoCString directory;
       defaultPath->GetNativePath(directory);
+
+#if (MOZ_WIDGET_GTK == 3)
+      // Workaround for problematic refcounting in GTK3 before 3.16.
+      // We need to keep a reference to the dialog's internal delegate.
+      // Otherwise, if our dialog gets destroyed, we'll lose the dialog's
+      // delegate by the time this gets processed in the event loop.
+      // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1166741
+      GtkDialog *dialog = GTK_DIALOG(file_chooser);
+      GtkContainer *area = GTK_CONTAINER(gtk_dialog_get_content_area(dialog));
+      gtk_container_forall(area, [](GtkWidget *widget,
+                                    gpointer data) {
+          if (GTK_IS_FILE_CHOOSER_WIDGET(widget)) {
+            auto result = static_cast<GtkFileChooserWidget**>(data);
+            *result = GTK_FILE_CHOOSER_WIDGET(widget);
+          }
+      }, &mFileChooserDelegate);
+
+      if (mFileChooserDelegate)
+        g_object_ref(mFileChooserDelegate);
+#endif
+
       gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_chooser),
                                           directory.get());
     }
   }
 
   gtk_dialog_set_default_response(GTK_DIALOG(file_chooser), GTK_RESPONSE_ACCEPT);
 
   int32_t count = mFilters.Length();
@@ -543,16 +565,31 @@ nsFilePicker::Done(GtkWidget* file_choos
   // When response_id is GTK_RESPONSE_DELETE_EVENT or when called from
   // OnDestroy, the widget would be destroyed anyway but it is fine if
   // gtk_widget_destroy is called more than once.  gtk_widget_destroy has
   // requests that any remaining references be released, but the reference
   // count will not be decremented again if GtkWindow's reference has already
   // been released.
   gtk_widget_destroy(file_chooser);
 
+#if (MOZ_WIDGET_GTK == 3)
+      if (mFileChooserDelegate) {
+        // Properly deref our acquired reference. We call this after
+        // gtk_widget_destroy() to try and ensure that pending file info
+        // queries caused by updating the current folder have been cancelled.
+        // However, we do not know for certain when the callback will run after
+        // cancelled.
+        g_idle_add([](gpointer data) -> gboolean {
+            g_object_unref(data);
+            return G_SOURCE_REMOVE;
+        }, mFileChooserDelegate);
+        mFileChooserDelegate = nullptr;
+      }
+#endif
+
   if (mCallback) {
     mCallback->Done(result);
     mCallback = nullptr;
   } else {
     mResult = result;
   }
   NS_RELEASE_THIS();
 }
--- a/widget/gtk/nsFilePicker.h
+++ b/widget/gtk/nsFilePicker.h
@@ -68,11 +68,13 @@ protected:
   nsString  mDefault;
   nsString  mDefaultExtension;
 
   nsTArray<nsCString> mFilters;
   nsTArray<nsCString> mFilterNames;
 
 private:
   static nsIFile *mPrevDisplayDirectory;
+
+  GtkFileChooserWidget *mFileChooserDelegate;
 };
 
 #endif
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -4124,17 +4124,17 @@ nsWindow::ConfigureChildren(const nsTArr
     // size information from a source other than our owner. Don't let our parent
     // update this information.
     if (mWindowType == eWindowType_plugin_ipc_chrome) {
       return NS_OK;
     }
 
     for (uint32_t i = 0; i < aConfigurations.Length(); ++i) {
         const Configuration& configuration = aConfigurations[i];
-        nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
+        nsWindow* w = static_cast<nsWindow*>(configuration.mChild.get());
         NS_ASSERTION(w->GetParent() == this,
                      "Configured widget is not a child");
         w->SetWindowClipRegion(configuration.mClipRegion, true);
         if (w->mBounds.Size() != configuration.mBounds.Size()) {
             w->Resize(configuration.mBounds.x, configuration.mBounds.y,
                       configuration.mBounds.width, configuration.mBounds.height,
                       true);
         } else if (w->mBounds.TopLeft() != configuration.mBounds.TopLeft()) {
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -1454,17 +1454,17 @@ class nsIWidget : public nsISupports {
      */
     virtual nsTransparencyMode GetTransparencyMode() = 0;
 
     /**
      * This represents a command to set the bounds and clip region of
      * a child widget.
      */
     struct Configuration {
-        nsIWidget* mChild;
+        nsCOMPtr<nsIWidget> mChild;
         uintptr_t mWindowID; // e10s specific, the unique plugin port id
         bool mVisible; // e10s specific, widget visibility
         nsIntRect mBounds;
         nsTArray<nsIntRect> mClipRegion;
     };
 
     /**
      * Sets the clip region of each mChild (which must actually be a child
--- a/widget/tests/test_imestate.html
+++ b/widget/tests/test_imestate.html
@@ -140,16 +140,42 @@ const kIMEEnabledSupported = navigator.p
 // We support to control IME open state on Windows and Mac actually.  However,
 // we cannot test it on Mac if the current keyboard layout is not CJK. And also
 // we cannot test it on Win32 if the system didn't be installed IME. So,
 // currently we should not run the open state testing.
 const kIMEOpenSupported = false;
 
 function runBasicTest(aIsEditable, aInDesignMode, aDescription)
 {
+  var onIMEFocusBlurHandler = null;
+  var TIPCallback = function(aTIP, aNotification) {
+    switch (aNotification.type) {
+      case "request-to-commit":
+        aTIP.commitComposition();
+        break;
+      case "request-to-cancel":
+        aTIP.cancelComposition();
+        break;
+      case "notify-focus":
+      case "notify-blur":
+        if (onIMEFocusBlurHandler) {
+          onIMEFocusBlurHandler(aNotification);
+        }
+        break;
+    }
+    return true;
+  };
+
+  var TIP = Components.classes["@mozilla.org/text-input-processor;1"]
+              .createInstance(Components.interfaces.nsITextInputProcessor);
+  if (!TIP.beginInputTransactionForTests(window, TIPCallback)) {
+    ok(false, "runBasicTest(): failed to begin input transaction");
+    return;
+  }
+
   function test(aTest)
   {
     function moveFocus(aTest, aFocusEventHandler)
     {
       if (aInDesignMode) {
         if (document.activeElement) {
           document.activeElement.blur();
         }
@@ -166,32 +192,22 @@ function runBasicTest(aIsEditable, aInDe
       var subDocument = null;
       if (element.contentDocument) {
         focusEventTarget = element.contentDocument;
         subDocument = element.contentDocument;
         element = element.contentDocument.documentElement;
       }
 
       focusEventTarget.addEventListener("focus", aFocusEventHandler, true);
-      document.addEventListener("MozIMEFocusIn", aFocusEventHandler, true);
-      document.addEventListener("MozIMEFocusOut", aFocusEventHandler, true);
-      if (subDocument) {
-        subDocument.addEventListener("MozIMEFocusIn", aFocusEventHandler, true);
-        subDocument.addEventListener("MozIMEFocusOut", aFocusEventHandler, true);
-      }
+      onIMEFocusBlurHandler = aFocusEventHandler;
 
       element.focus();
 
       focusEventTarget.removeEventListener("focus", aFocusEventHandler, true);
-      document.removeEventListener("MozIMEFocusIn", aFocusEventHandler, true);
-      document.removeEventListener("MozIMEFocusOut", aFocusEventHandler, true);
-      if (element.contentDocument) {
-        subDocument.removeEventListener("MozIMEFocusIn", aFocusEventHandler, true);
-        subDocument.removeEventListener("MozIMEFocusOut", aFocusEventHandler, true);
-      }
+      onIMEFocusBlurHandler = null;
 
       var focusedElement = gFM.focusedElement;
       if (focusedElement) {
         var bindingParent = document.getBindingParent(focusedElement);
         if (bindingParent) {
           focusedElement = bindingParent;
         }
       }
@@ -217,101 +233,101 @@ function runBasicTest(aIsEditable, aInDe
       is(gUtils.IMEIsOpen,
          aTest.changeOpened ? aTest.expectedOpened : aOpened, message);
     }
 
     // IME Enabled state testing
     var enabled = gUtils.IME_STATUS_ENABLED;
     if (kIMEEnabledSupported) {
       var focusEventCount = 0;
-      var mozIMEFocusInCount = 0;
-      var mozIMEFocusOutCount = 0;
+      var IMEReceivesFocus = 0;
+      var IMEReceivesBlur = 0;
       var IMEHasFocus = false;
 
       function onFocus(aEvent)
       {
         switch (aEvent.type) {
           case "focus":
             focusEventCount++;
             is(gUtils.IMEStatus, aTest.expectedEnabled,
                aDescription + ": " + aTest.description + ", wrong enabled state at focus event");
             break;
-          case "MozIMEFocusIn":
-            mozIMEFocusInCount++;
+          case "notify-focus":
+            IMEReceivesFocus++;
             IMEHasFocus = true;
             is(gUtils.IMEStatus, aTest.expectedEnabled,
                aDescription + ": " + aTest.description +
-                 ", MozIMEFocusIn event must be fired after IME state is updated");
+                 ", IME should receive a focus notification after IME state is updated");
             break;
-          case "MozIMEFocusOut":
-            mozIMEFocusOutCount++;
+          case "notify-blur":
+            IMEReceivesBlur++;
             IMEHasFocus = false;
             var changingStatus = !(aIsEditable && aTest.expectedEnabled == gUtils.IME_STATUS_ENABLED);
             if (aTest.toDesignModeEditor) {
               is(gUtils.IME_STATUS_ENABLED, aTest.expectedEnabled,
                  aDescription + ": " + aTest.description +
-                   ", MozIMEFocusOut event must be fired after IME state is updated");
+                   ", IME should receive a blur notification after IME state is updated");
             } else if (changingStatus) {
               isnot(gUtils.IMEStatus, aTest.expectedEnabled,
                     aDescription + ": " + aTest.description +
-                      ", MozIMEFocusOut event must be fired before IME state is updated");
+                      ", IME should receive a blur notification before IME state is updated");
             } else {
               is(gUtils.IMEStatus, aTest.expectedEnabled,
                  aDescription + ": " + aTest.description +
-                   ", MozIMEFocusOut event must be fired with expected IME state if the state isn't being changed");
+                   ", IME should receive a blur notification and its context has expected IME state if the state isn't being changed");
             }
             break;
         }
       }
 
       if (!moveFocus(aTest, onFocus)) {
         return;
       }
 
       if (aTest.focusable) {
         if (!aTest.focusEventNotFired) {
           ok(focusEventCount > 0,
              aDescription + ": " + aTest.description + ", focus event is never fired");
           if (aTest.expectedEnabled == gUtils.IME_STATUS_ENABLED || aTest.expectedEnabled == gUtils.IME_STATUS_PASSWORD) {
-            ok(mozIMEFocusInCount > 0,
-               aDescription + ": " + aTest.description + ", MozIMEFocusIn event should be fired");
+            ok(IMEReceivesFocus > 0,
+               aDescription + ": " + aTest.description + ", IME should receive a focus notification");
             if (aInDesignMode && !aTest.toDesignModeEditor) {
-              is(mozIMEFocusOutCount, 0,
+              is(IMEReceivesBlur, 0,
                  aDescription + ": " + aTest.description +
-                   ", MozIMEFocusOut event shouldn't be fired in designMode since focus isn't moved from another editor");
+                   ", IME shouldn't receive a blur notification in designMode since focus isn't moved from another editor");
             } else {
-              ok(mozIMEFocusOutCount > 0,
+              ok(IMEReceivesBlur > 0,
                  aDescription + ": " + aTest.description +
-                   ", MozIMEFocusOut event should be fired for the previous focused editor");
+                   ", IME should receive a blur notification for the previous focused editor");
             }
             ok(IMEHasFocus,
                aDescription + ": " + aTest.description +
-                 ", The latest MozIMEFocus* event must be MozIMEFocusIn");
+                 ", IME should have focus right now");
           } else {
-            is(mozIMEFocusInCount, 0,
+            is(IMEReceivesFocus, 0,
                aDescription + ": " + aTest.description +
-                 ", MozIMEFocusIn event shouldn't be fired");
-            ok(mozIMEFocusOutCount > 0,
+                 ", IME shouldn't receive a focus notification");
+            ok(IMEReceivesBlur > 0,
                aDescription + ": " + aTest.description +
-                 ", MozIMEFocusOut event should be fired");
+                 ", IME should receive a blur notification");
             ok(!IMEHasFocus,
                aDescription + ": " + aTest.description +
-                 ", The latest MozIMEFocus* event must be MozIMEFocusOut");
+                 ", IME shouldn't have focus right now");
           }
         } else {
           todo(focusEventCount > 0,
                aDescription + ": " + aTest.description + ", focus event should be fired");
         }
       } else {
-        is(mozIMEFocusInCount, 0,
+        is(IMEReceivesFocus, 0,
            aDescription + ": " + aTest.description +
-             ", MozIMEFocusIn event shouldn't be fired at testing non-focusable element");
-        is(mozIMEFocusOutCount, 0,
+             ", IME shouldn't receive a focus notification at testing non-focusable element");
+        is(IMEReceivesBlur, 0,
            aDescription + ": " + aTest.description +
-             ", MozIMEFocusOut event shouldn't be fired at testing non-focusable element");
+             ", IME shouldn't receive a blur notification at testing non-focusable element");
       }
 
       enabled = gUtils.IMEStatus;
       inputtype = gUtils.focusedInputType;
       is(enabled, aTest.expectedEnabled,
          aDescription + ": " + aTest.description + ", wrong enabled state");
       if (aTest.expectedType && !aInDesignMode) {
         is(inputtype, aTest.expectedType,
@@ -1353,87 +1369,107 @@ function runTestPasswordFieldOnDialog()
 
 // Bug 580388 and bug 808287
 function runEditorReframeTests(aCallback)
 {
   if (document.activeElement) {
     document.activeElement.blur();
   }
 
-  var input = document.getElementById("text");
-  input.focus();
-  input.style.overflow = "visible";
-
-  var mozIMEFocusIn = 0;
-  var mozIMEFocusOut = 0;
+  var IMEFocus = 0;
+  var IMEBlur = 0;
   var IMEHasFocus = false;
-
-  var handler = function (aEvent) {
-    switch (aEvent.type) {
-      case "MozIMEFocusIn":
-        mozIMEFocusIn++;
+  var TIPCallback = function(aTIP, aNotification) {
+    switch (aNotification.type) {
+      case "request-to-commit":
+        aTIP.commitComposition();
+        break;
+      case "request-to-cancel":
+        aTIP.cancelComposition();
+        break;
+      case "notify-focus":
+        IMEFocus++;
         IMEHasFocus = true;
         break;
-      case "MozIMEFocusOut":
-        mozIMEFocusOut++;
+      case "notify-blur":
+        IMEBlur++;
         IMEHasFocus = false;
         break;
     }
+    return true;
   };
 
+  var TIP = Components.classes["@mozilla.org/text-input-processor;1"]
+              .createInstance(Components.interfaces.nsITextInputProcessor);
+  if (!TIP.beginInputTransactionForTests(window, TIPCallback)) {
+    ok(false, "runEditorReframeTests(): failed to begin input transaction");
+    return;
+  }
+
+  var input = document.getElementById("text");
+  input.focus();
+
+  is(IMEFocus, 1, "runEditorReframeTests(): IME should receive a focus notification by a call of <input>.focus()");
+  is(IMEBlur, 0, "runEditorReframeTests(): IME shouldn't receive a blur notification by a call of <input>.focus()");
+  ok(IMEHasFocus, "runEditorReframeTests(): IME should have focus because <input>.focus() is called");
+
+  IMEFocus = IMEBlur = 0;
+
+  input.style.overflow = "visible";
+
   var onInput = function (aEvent) {
     aEvent.target.style.overflow = "hidden";
   }
-
-  document.addEventListener("MozIMEFocusIn", handler, true);
-  document.addEventListener("MozIMEFocusOut", handler, true);
   input.addEventListener("input", onInput, true);
 
-  sendChar("a");
+  var AKey = new KeyboardEvent("", { key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A });
+  TIP.keydown(AKey);
+  TIP.keyup(AKey);
 
   hitEventLoop(function () {
-    ok(mozIMEFocusOut > 0, "runEditorReframeTests(): IME focus must be lost at reframing");
-    ok(mozIMEFocusIn > 0, "runEditorReframeTests(): IME focus must be restored after reframing");
-    ok(IMEHasFocus, "runEditorReframeTests(): IME must have focus after reframing");
+    is(IMEFocus, 0, "runEditorReframeTests(): IME shouldn't receive a focus notification during reframing");
+    is(IMEBlur, 0, "runEditorReframeTests(): IME shouldn't receive a blur notification during reframing");
+    ok(IMEHasFocus, "runEditorReframeTests(): IME must have focus even after reframing");
 
-    var focusQueryHandler = function(aEvent) {
-        // Perform a style change and query during focus to trigger reframing
-        input.style.overflow = "visible";
-        synthesizeQuerySelectedText();
-    }
-    document.addEventListener("MozIMEFocusIn", focusQueryHandler, true);
-    mozIMEFocusIn = mozIMEFocusOut = 0;
+    var onFocus = function(aEvent) {
+      // Perform a style change and query during focus to trigger reframing
+      input.style.overflow = "visible";
+      synthesizeQuerySelectedText();
+    };
+    input.addEventListener("focus", onFocus);
+    IMEFocus = IMEBlur = 0;
 
     input.blur();
     input.focus();
-    sendChar("a");
+    TIP.keydown(AKey);
+    TIP.keyup(AKey);
 
     hitEventLoop(function() {
-        ok(IMEHasFocus, "runEditorReframeTests(): IME must have focus after reframing during focus");
-        ok(mozIMEFocusOut == mozIMEFocusIn, "runEditorReframeTests(): IME focus/blur (" + mozIMEFocusIn + "/" + mozIMEFocusOut + ") must match after reframing during focus");
+      is(IMEFocus, 1, "runEditorReframeTests(): IME should receive a focus notification at focus but shouldn't receive it during reframing");
+      is(IMEBlur, 1, "runEditorReframeTests(): IME should receive a blur notification at blur but shouldn't receive it during reframing");
+      ok(IMEHasFocus, "runEditorReframeTests(): IME sould have focus after reframing during focus");
+
+      input.removeEventListener("input", onInput, true);
+      input.removeEventListener("focus", onFocus);
 
-        document.removeEventListener("MozIMEFocusIn", focusQueryHandler, true);
-        document.removeEventListener("MozIMEFocusIn", handler, true);
-        document.removeEventListener("MozIMEFocusOut", handler, true);
-        input.removeEventListener("input", onInput, true);
+      input.style.overflow = "visible";
+      input.value = "";
 
-        input.style.overflow = "visible";
-        input.value = "";
+      TIP = null;
 
-        hitEventLoop(aCallback, 20);
+      hitEventLoop(aCallback, 20);
     }, 20);
   }, 20);
 }
 
 function runTests()
 {
   if (!kIMEEnabledSupported && !kIMEOpenSupported)
     return;
 
-  SpecialPowers.pushPrefEnv({"set":[["test.IME", true]]}, function() {
   // test for normal contents.
   runBasicTest(false, false, "Testing of normal contents");
 
   // test for plugin contents
   runPluginTest();
 
   var container = document.getElementById("display");
   // test for contentEditable="true"
@@ -1473,17 +1509,16 @@ function runTests()
   // XXX temporary disable against failure
   //runTestPasswordFieldOnDialog();
 
   // Asynchronous tests
   runEditorReframeTests(function () {
     // This will call onFinish(), so, this test must be the last.
     runEditableSubframeTests();
   });
- });
 }
 
 function onFinish()
 {
   SimpleTest.finish();
 }
 
 </script>
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -6350,17 +6350,17 @@ nsWindow::ConfigureChildren(const nsTArr
     return NS_OK;
   }
 
   // XXXroc we could use BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos
   // here, if that helps in some situations. So far I haven't seen a
   // need.
   for (uint32_t i = 0; i < aConfigurations.Length(); ++i) {
     const Configuration& configuration = aConfigurations[i];
-    nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
+    nsWindow* w = static_cast<nsWindow*>(configuration.mChild.get());
     NS_ASSERTION(w->GetParent() == this,
                  "Configured widget is not a child");
     nsresult rv = w->SetWindowClipRegion(configuration.mClipRegion, true);
     NS_ENSURE_SUCCESS(rv, rv);
     nsIntRect bounds;
     w->GetBounds(bounds);
     if (bounds.Size() != configuration.mBounds.Size()) {
       w->Resize(configuration.mBounds.x, configuration.mBounds.y,
--- a/xpcom/glue/nsBaseHashtable.h
+++ b/xpcom/glue/nsBaseHashtable.h
@@ -166,17 +166,17 @@ public:
    * @param aUserArg passed unchanged to the EnumReadFunction
    */
   uint32_t EnumerateRead(EnumReadFunction aEnumFunc, void* aUserArg) const
   {
     NS_ASSERTION(this->mTable.IsInitialized(),
                  "nsBaseHashtable was not initialized properly.");
 
     s_EnumReadArgs enumData = { aEnumFunc, aUserArg };
-    return PL_DHashTableEnumerate(const_cast<PLDHashTable*>(&this->mTable),
+    return PL_DHashTableEnumerate(const_cast<PLDHashTable*>(static_cast<const PLDHashTable*>(&this->mTable)),
                                   s_EnumReadStub,
                                   &enumData);
   }
 
   /**
    * function type provided by the application for enumeration.
    * @param aKey the key being enumerated
    * @param aData Reference to data being enumerated, may be altered. e.g. for
--- a/xpcom/glue/nsTHashtable.h
+++ b/xpcom/glue/nsTHashtable.h
@@ -81,18 +81,22 @@ PLDHashOperator PL_DHashStubEnumRemove(P
 template<class EntryType>
 class nsTHashtable
 {
   typedef mozilla::fallible_t fallible_t;
 
 public:
   // Separate constructors instead of default aInitLength parameter since
   // otherwise the default no-arg constructor isn't found.
-  nsTHashtable() { Init(PL_DHASH_DEFAULT_INITIAL_LENGTH); }
-  explicit nsTHashtable(uint32_t aInitLength) { Init(aInitLength); }
+  nsTHashtable()
+    : mTable(Ops(), sizeof(EntryType), PL_DHASH_DEFAULT_INITIAL_LENGTH)
+  {}
+  explicit nsTHashtable(uint32_t aInitLength)
+    : mTable(Ops(), sizeof(EntryType), aInitLength)
+  {}
 
   /**
    * destructor, cleans up and deallocates
    */
   ~nsTHashtable();
 
   nsTHashtable(nsTHashtable<EntryType>&& aOther);
 
@@ -125,17 +129,17 @@ public:
    *            key doesn't exist
    */
   EntryType* GetEntry(KeyType aKey) const
   {
     NS_ASSERTION(mTable.IsInitialized(),
                  "nsTHashtable was not initialized properly.");
 
     return static_cast<EntryType*>(
-      PL_DHashTableSearch(const_cast<PLDHashTable*>(&mTable),
+      PL_DHashTableSearch(const_cast<PLDHashTable*>(static_cast<const PLDHashTable*>(&mTable)),
                           EntryType::KeyToPointer(aKey)));
   }
 
   /**
    * Return true if an entry for the given key exists, false otherwise.
    * @param     aKey the key to retrieve
    * @return    true if the key exists, false if the key doesn't exist
    */
@@ -319,17 +323,17 @@ public:
     NS_ASSERTION(mTable.IsInitialized(),
                  "nsTHashtable was not initialized properly.");
 
     PL_DHashMarkTableImmutable(&mTable);
   }
 #endif
 
 protected:
-  PLDHashTable mTable;
+  PLDHashTable2 mTable;
 
   static const void* s_GetKey(PLDHashTable* aTable, PLDHashEntryHdr* aEntry);
 
   static PLDHashNumber s_HashKey(PLDHashTable* aTable, const void* aKey);
 
   static bool s_MatchEntry(PLDHashTable* aTable, const PLDHashEntryHdr* aEntry,
                            const void* aKey);
 
@@ -373,20 +377,19 @@ protected:
   static size_t s_SizeOfStub(PLDHashEntryHdr* aEntry,
                              mozilla::MallocSizeOf aMallocSizeOf, void* aArg);
 
 private:
   // copy constructor, not implemented
   nsTHashtable(nsTHashtable<EntryType>& aToCopy) = delete;
 
   /**
-   * Initialize the table.
-   * @param aInitLength the initial number of buckets in the hashtable
+   * Gets the table's ops.
    */
-  void Init(uint32_t aInitLength);
+  static const PLDHashTableOps* Ops();
 
   /**
    * An implementation of SizeOfEntryExcludingThisFun that calls SizeOfExcludingThis()
    * on each entry.
    */
   static size_t BasicSizeOfEntryExcludingThisFun(EntryType* aEntry,
                                                  mozilla::MallocSizeOf aMallocSizeOf,
                                                  void*);
@@ -406,35 +409,34 @@ nsTHashtable<EntryType>::nsTHashtable(ns
   // aOther shouldn't touch mTable after this, because we've stolen the table's
   // pointers but not overwitten them.
   MOZ_MAKE_MEM_UNDEFINED(&aOther.mTable, sizeof(aOther.mTable));
 }
 
 template<class EntryType>
 nsTHashtable<EntryType>::~nsTHashtable()
 {
-  if (mTable.IsInitialized()) {
-    PL_DHashTableFinish(&mTable);
-  }
 }
 
 template<class EntryType>
-void
-nsTHashtable<EntryType>::Init(uint32_t aInitLength)
+/* static */ const PLDHashTableOps*
+nsTHashtable<EntryType>::Ops()
 {
+  // If this variable is a global variable, we get strange start-up failures on
+  // WindowsCrtPatch.h (see bug 1166598 comment 20). But putting it inside a
+  // function avoids that problem.
   static const PLDHashTableOps sOps =
   {
     s_HashKey,
     s_MatchEntry,
     EntryType::ALLOW_MEMMOVE ? ::PL_DHashMoveEntryStub : s_CopyEntry,
     s_ClearEntry,
     s_InitEntry
   };
-
-  PL_DHashTableInit(&mTable, &sOps, sizeof(EntryType), aInitLength);
+  return &sOps;
 }
 
 // static
 template<class EntryType>
 size_t
 nsTHashtable<EntryType>::BasicSizeOfEntryExcludingThisFun(EntryType* aEntry,
                                                           mozilla::MallocSizeOf aMallocSizeOf,
                                                           void*)