merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 21 Jan 2016 11:49:16 +0100
changeset 280893 977d78a8dd78afbc0153d37fd9887c3a200dce6a
parent 280729 aa416d2a76faf1346c1c9e8a2b6fa44a38cd68fc (current diff)
parent 280892 b578a9def3278b66b4ff63d167e5d9c1eff05a7b (diff)
child 280894 66e07ef46853709e3fa91e7c9ad9fe6abf0d5f06
child 280944 bd50a0b3f94d016c2aae15ea8fcf52bcca37c617
child 280967 b39718d9ea3cc74af292a3d162fe44907134a3ac
child 281024 bb351c1c6ca218d9364a89a4370b2b6f5ab8efa9
push id29922
push usercbook@mozilla.com
push dateThu, 21 Jan 2016 10:51:00 +0000
treeherderautoland@977d78a8dd78 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone46.0a1
first release with
nightly linux32
977d78a8dd78 / 46.0a1 / 20160121030208 / files
nightly linux64
977d78a8dd78 / 46.0a1 / 20160121030208 / files
nightly mac
977d78a8dd78 / 46.0a1 / 20160121030208 / files
nightly win32
977d78a8dd78 / 46.0a1 / 20160121030208 / files
nightly win64
977d78a8dd78 / 46.0a1 / 20160121030208 / 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 mozilla-inbound to mozilla-central a=merge
dom/ipc/TabChild.cpp
dom/media/platforms/ffmpeg/FFmpegFunctionList.h
dom/media/platforms/ffmpeg/FFmpegH264Decoder.cpp
dom/media/platforms/ffmpeg/FFmpegH264Decoder.h
gfx/2d/moz-d2d1-1.h
gfx/cairo/cairo/src/moz-d2d1-1.h
mobile/android/chrome/content/browser.js
testing/mozharness/configs/b2g_bumper/master.py
testing/mozharness/configs/b2g_bumper/v2.1s.py
testing/mozharness/configs/b2g_bumper/v2.2.py
testing/mozharness/configs/vcs_sync/beagle.py
testing/mozharness/configs/vcs_sync/build-repos.py
testing/mozharness/configs/vcs_sync/gecko-git.py
testing/mozharness/configs/vcs_sync/l10n.py
testing/mozharness/configs/vcs_sync/project-branches.py
testing/mozharness/scripts/b2g_bumper.py
testing/mozharness/scripts/vcs-sync/initial_beagle.py
testing/mozharness/scripts/vcs-sync/vcs_sync.py
testing/talos/talos/startup_test/media/__init__.py
testing/talos/talos/startup_test/media/html/audio_playback.js
testing/talos/talos/startup_test/media/html/input16.wav
testing/talos/talos/startup_test/media/html/media_api.js
testing/talos/talos/startup_test/media/html/media_tests.html
testing/talos/talos/startup_test/media/html/media_tests.js
testing/talos/talos/startup_test/media/html/pc_audio_quality.js
testing/talos/talos/startup_test/media/media_manager.py
testing/talos/talos/startup_test/media/media_utils.py
testing/talos/talos/startup_test/media/tools/MediaUtils
testing/talos/talos/startup_test/media/tools/PESQ
--- a/accessible/base/NotificationController.cpp
+++ b/accessible/base/NotificationController.cpp
@@ -136,16 +136,17 @@ NotificationController::IsUpdatePending(
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // NotificationCollector: private
 
 void
 NotificationController::WillRefresh(mozilla::TimeStamp aTime)
 {
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
   Telemetry::AutoTimer<Telemetry::A11Y_UPDATE_TIME> updateTimer;
 
   // If the document accessible that notification collector was created for is
   // now shut down, don't process notifications anymore.
   NS_ASSERTION(mDocument,
                "The document was shut down while refresh observer is attached!");
   if (!mDocument)
     return;
new file mode 100644
--- /dev/null
+++ b/accessible/base/TextRange-inl.h
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_TextRange_inl_h__
+#define mozilla_a11y_TextRange_inl_h__
+
+#include "TextRange.h"
+#include "HyperTextAccessible.h"
+
+namespace mozilla {
+namespace a11y {
+
+inline Accessible*
+TextRange::Container() const
+{
+  uint32_t pos1 = 0, pos2 = 0;
+  nsAutoTArray<Accessible*, 30> parents1, parents2;
+  return CommonParent(mStartContainer, mEndContainer,
+                      &parents1, &pos1, &parents2, &pos2);
+}
+
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
--- a/accessible/base/TextRange.cpp
+++ b/accessible/base/TextRange.cpp
@@ -1,18 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "TextRange.h"
+#include "TextRange-inl.h"
 
 #include "Accessible-inl.h"
-#include "HyperTextAccessible.h"
 #include "nsAccUtils.h"
 
 namespace mozilla {
 namespace a11y {
 
 ////////////////////////////////////////////////////////////////////////////////
 // TextPoint
 
@@ -54,90 +53,37 @@ TextPoint::operator <(const TextPoint& a
 TextRange::TextRange(HyperTextAccessible* aRoot,
                      HyperTextAccessible* aStartContainer, int32_t aStartOffset,
                      HyperTextAccessible* aEndContainer, int32_t aEndOffset) :
   mRoot(aRoot), mStartContainer(aStartContainer), mEndContainer(aEndContainer),
   mStartOffset(aStartOffset), mEndOffset(aEndOffset)
 {
 }
 
-Accessible*
-TextRange::Container() const
-{
-  if (mStartContainer == mEndContainer)
-    return mStartContainer;
-
-  // Build the chain of parents
-  Accessible* p1 = mStartContainer;
-  Accessible* p2 = mEndContainer;
-  nsAutoTArray<Accessible*, 30> parents1, parents2;
-  do {
-    parents1.AppendElement(p1);
-    p1 = p1->Parent();
-  } while (p1);
-  do {
-    parents2.AppendElement(p2);
-    p2 = p2->Parent();
-  } while (p2);
-
-  // Find where the parent chain differs
-  uint32_t pos1 = parents1.Length();
-  uint32_t pos2 = parents2.Length();
-  Accessible* parent = nullptr;
-  uint32_t len = 0;
-  for (len = std::min(pos1, pos2); len > 0; --len) {
-    Accessible* child1 = parents1.ElementAt(--pos1);
-    Accessible* child2 = parents2.ElementAt(--pos2);
-    if (child1 != child2)
-      break;
-
-    parent = child1;
-  }
-
-  return parent;
-}
-
 void
 TextRange::EmbeddedChildren(nsTArray<Accessible*>* aChildren) const
 {
   if (mStartContainer == mEndContainer) {
     int32_t startIdx = mStartContainer->GetChildIndexAtOffset(mStartOffset);
     int32_t endIdx = mStartContainer->GetChildIndexAtOffset(mEndOffset);
     for (int32_t idx = startIdx; idx <= endIdx; idx++) {
       Accessible* child = mStartContainer->GetChildAt(idx);
       if (nsAccUtils::IsEmbeddedObject(child))
         aChildren->AppendElement(child);
     }
     return;
   }
 
   Accessible* p1 = mStartContainer->GetChildAtOffset(mStartOffset);
   Accessible* p2 = mEndContainer->GetChildAtOffset(mEndOffset);
+
+  uint32_t pos1 = 0, pos2 = 0;
   nsAutoTArray<Accessible*, 30> parents1, parents2;
-  do {
-    parents1.AppendElement(p1);
-    p1 = p1->Parent();
-  } while (p1);
-  do {
-    parents2.AppendElement(p2);
-    p2 = p2->Parent();
-  } while (p2);
-
-  // Find deepest common container.
-  uint32_t pos1 = parents1.Length();
-  uint32_t pos2 = parents2.Length();
-  Accessible* container = nullptr;
-  for (uint32_t len = std::min(pos1, pos2); len > 0; --len) {
-    Accessible* child1 = parents1.ElementAt(--pos1);
-    Accessible* child2 = parents2.ElementAt(--pos2);
-    if (child1 != child2)
-      break;
-
-    container = child1;
-  }
+  Accessible* container =
+    CommonParent(p1, p2, &parents1, &pos1, &parents2, &pos2);
 
   // Traverse the tree up to the container and collect embedded objects.
   for (uint32_t idx = 0; idx < pos1 - 1; idx++) {
     Accessible* parent = parents1[idx + 1];
     Accessible* child = parents1[idx];
     uint32_t childCount = parent->ChildCount();
     for (uint32_t childIdx = child->IndexInParent(); childIdx < childCount; childIdx++) {
       Accessible* next = parent->GetChildAt(childIdx);
@@ -191,16 +137,105 @@ TextRange::Bounds(nsTArray<nsIntRect> aR
 }
 
 void
 TextRange::Normalize(ETextUnit aUnit)
 {
 
 }
 
+bool
+TextRange::Crop(Accessible* aContainer)
+{
+  uint32_t boundaryPos = 0, containerPos = 0;
+  nsAutoTArray<Accessible*, 30> boundaryParents, containerParents;
+
+  // Crop the start boundary.
+  Accessible* container = nullptr;
+  Accessible* boundary = mStartContainer->GetChildAtOffset(mStartOffset);
+  if (boundary != aContainer) {
+    CommonParent(boundary, aContainer, &boundaryParents, &boundaryPos,
+                 &containerParents, &containerPos);
+
+    if (boundaryPos == 0) {
+      if (containerPos != 0) {
+        // The container is contained by the start boundary, reduce the range to
+        // the point starting at the container.
+        aContainer->ToTextPoint(mStartContainer.StartAssignment(), &mStartOffset);
+        static_cast<Accessible*>(mStartContainer)->AddRef();
+      }
+      else {
+        // The start boundary and the container are siblings.
+        container = aContainer;
+      }
+    }
+    else if (containerPos != 0) {
+      // The container does not contain the start boundary.
+      boundary = boundaryParents[boundaryPos];
+      container = containerParents[containerPos];
+    }
+
+    if (container) {
+      // If the range start is after the container, then make the range invalid.
+      if (boundary->IndexInParent() > container->IndexInParent()) {
+        return !!(mRoot = nullptr);
+      }
+
+      // If the range starts before the container, then reduce the range to
+      // the point starting at the container.
+      if (boundary->IndexInParent() < container->IndexInParent()) {
+        container->ToTextPoint(mStartContainer.StartAssignment(), &mStartOffset);
+        mStartContainer.get()->AddRef();
+      }
+    }
+
+    boundaryParents.SetLengthAndRetainStorage(0);
+    containerParents.SetLengthAndRetainStorage(0);
+  }
+
+  boundary = mEndContainer->GetChildAtOffset(mEndOffset);
+  if (boundary == aContainer) {
+    return true;
+  }
+
+  // Crop the end boundary.
+  container = nullptr;
+  CommonParent(boundary, aContainer, &boundaryParents, &boundaryPos,
+               &containerParents, &containerPos);
+
+  if (boundaryPos == 0) {
+    if (containerPos != 0) {
+      aContainer->ToTextPoint(mEndContainer.StartAssignment(), &mEndOffset, false);
+      static_cast<Accessible*>(mEndContainer)->AddRef();
+    }
+    else {
+      container = aContainer;
+    }
+  }
+  else if (containerPos != 0) {
+    boundary = boundaryParents[boundaryPos];
+    container = containerParents[containerPos];
+  }
+
+  if (!container) {
+    return true;
+  }
+
+  if (boundary->IndexInParent() < container->IndexInParent()) {
+    return !!(mRoot = nullptr);
+  }
+
+  if (boundary->IndexInParent() > container->IndexInParent()) {
+    container->ToTextPoint(mEndContainer.StartAssignment(), &mEndOffset, false);
+    static_cast<Accessible*>(mEndContainer)->AddRef();
+  }
+
+  return true;
+}
+
 void
 TextRange::FindText(const nsAString& aText, EDirection aDirection,
                     nsCaseTreatment aCaseSensitive, TextRange* aFoundRange) const
 {
 
 }
 
 void
@@ -291,10 +326,51 @@ TextRange::TextInternal(nsAString& aText
 void
 TextRange::MoveInternal(ETextUnit aUnit, int32_t aCount,
                         HyperTextAccessible& aContainer, int32_t aOffset,
                         HyperTextAccessible* aStopContainer, int32_t aStopOffset)
 {
 
 }
 
+Accessible*
+TextRange::CommonParent(Accessible* aAcc1, Accessible* aAcc2,
+                        nsTArray<Accessible*>* aParents1, uint32_t* aPos1,
+                        nsTArray<Accessible*>* aParents2, uint32_t* aPos2) const
+{
+  if (aAcc1 == aAcc2) {
+    return aAcc1;
+  }
+
+  MOZ_ASSERT(aParents1->Length() == 0 || aParents2->Length() == 0,
+             "Wrong arguments");
+
+  // Build the chain of parents.
+  Accessible* p1 = aAcc1;
+  Accessible* p2 = aAcc2;
+  do {
+    aParents1->AppendElement(p1);
+    p1 = p1->Parent();
+  } while (p1);
+  do {
+    aParents2->AppendElement(p2);
+    p2 = p2->Parent();
+  } while (p2);
+
+  // Find where the parent chain differs
+  *aPos1 = aParents1->Length();
+  *aPos2 = aParents2->Length();
+  Accessible* parent = nullptr;
+  uint32_t len = 0;
+  for (len = std::min(*aPos1, *aPos2); len > 0; --len) {
+    Accessible* child1 = aParents1->ElementAt(--(*aPos1));
+    Accessible* child2 = aParents2->ElementAt(--(*aPos2));
+    if (child1 != child2)
+      break;
+
+    parent = child1;
+  }
+
+  return parent;
+}
+
 } // namespace a11y
 } // namespace mozilla
--- a/accessible/base/TextRange.h
+++ b/accessible/base/TextRange.h
@@ -126,16 +126,22 @@ public:
   void MoveEnd(ETextUnit aUnit, int32_t aCount)
     { MoveInternal(aUnit, aCount, *mEndContainer, mEndOffset); }
 
   /**
    * Move the range points to the closest unit boundaries.
    */
   void Normalize(ETextUnit aUnit);
 
+  /**
+   * Crops the range if it overlaps the given accessible element boundaries,
+   * returns true if the range was cropped successfully.
+   */
+  bool Crop(Accessible* aContainer);
+
   enum EDirection {
     eBackward,
     eForward
   };
 
   /**
    * Return range enclosing the found text.
    */
@@ -238,16 +244,24 @@ private:
   bool TextInternal(nsAString& aText, Accessible* aCurrent,
                     uint32_t aStartIntlOffset) const;
 
   void MoveInternal(ETextUnit aUnit, int32_t aCount,
                     HyperTextAccessible& aContainer, int32_t aOffset,
                     HyperTextAccessible* aStopContainer = nullptr,
                     int32_t aStopOffset = 0);
 
+  /**
+   * A helper method returning a common parent for two given accessible
+   * elements.
+   */
+  Accessible* CommonParent(Accessible* aAcc1, Accessible* aAcc2,
+                           nsTArray<Accessible*>* aParents1, uint32_t* aPos1,
+                           nsTArray<Accessible*>* aParents2, uint32_t* aPos2) const;
+
   RefPtr<HyperTextAccessible> mRoot;
   RefPtr<HyperTextAccessible> mStartContainer;
   RefPtr<HyperTextAccessible> mEndContainer;
   int32_t mStartOffset;
   int32_t mEndOffset;
 };
 
 
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -2245,16 +2245,40 @@ Accessible::AnchorAt(uint32_t aAnchorInd
 
 already_AddRefed<nsIURI>
 Accessible::AnchorURIAt(uint32_t aAnchorIndex)
 {
   NS_PRECONDITION(IsLink(), "AnchorURIAt is called on not hyper link!");
   return nullptr;
 }
 
+void
+Accessible::ToTextPoint(HyperTextAccessible** aContainer, int32_t* aOffset,
+                        bool aIsBefore) const
+{
+  if (IsHyperText()) {
+    *aContainer = const_cast<Accessible*>(this)->AsHyperText();
+    *aOffset = aIsBefore ? 0 : (*aContainer)->CharacterCount();
+    return;
+  }
+
+  const Accessible* child = nullptr;
+  const Accessible* parent = this;
+  do {
+    child = parent;
+    parent = parent->Parent();
+  } while (parent && !parent->IsHyperText());
+
+  if (parent) {
+    *aContainer = const_cast<Accessible*>(parent)->AsHyperText();
+    *aOffset = (*aContainer)->GetChildOffset(
+      child->IndexInParent() + static_cast<int32_t>(!aIsBefore));
+  }
+}
+
 
 ////////////////////////////////////////////////////////////////////////////////
 // SelectAccessible
 
 void
 Accessible::SelectedItems(nsTArray<Accessible*>* aItems)
 {
   AccIterator iter(this, filters::GetSelected);
--- a/accessible/generic/Accessible.h
+++ b/accessible/generic/Accessible.h
@@ -753,16 +753,22 @@ public:
    */
   virtual Accessible* AnchorAt(uint32_t aAnchorIndex);
 
   /**
    * Returns an anchor URI at the given index.
    */
   virtual already_AddRefed<nsIURI> AnchorURIAt(uint32_t aAnchorIndex);
 
+  /**
+   * Returns a text point for the accessible element.
+   */
+  void ToTextPoint(HyperTextAccessible** aContainer, int32_t* aOffset,
+                   bool aIsBefore = true) const;
+
   //////////////////////////////////////////////////////////////////////////////
   // SelectAccessible
 
   /**
    * Return an array of selected items.
    */
   virtual void SelectedItems(nsTArray<Accessible*>* aItems);
 
--- a/accessible/generic/HyperTextAccessible.cpp
+++ b/accessible/generic/HyperTextAccessible.cpp
@@ -1764,17 +1764,17 @@ HyperTextAccessible::EnclosingRange(a11y
   } else {
     aRange.Set(mDoc, mDoc, 0, mDoc, mDoc->CharacterCount());
   }
 }
 
 void
 HyperTextAccessible::SelectionRanges(nsTArray<a11y::TextRange>* aRanges) const
 {
-  NS_ASSERTION(aRanges->Length() != 0, "TextRange array supposed to be empty");
+  MOZ_ASSERT(aRanges->Length() == 0, "TextRange array supposed to be empty");
 
   dom::Selection* sel = DOMSelection();
   if (!sel)
     return;
 
   aRanges->SetCapacity(sel->RangeCount());
 
   for (uint32_t idx = 0; idx < sel->RangeCount(); idx++) {
--- a/accessible/generic/HyperTextAccessible.h
+++ b/accessible/generic/HyperTextAccessible.h
@@ -253,17 +253,17 @@ public:
   /**
    * Return text offset of the given child accessible within hypertext
    * accessible.
    *
    * @param  aChild           [in] accessible child to get text offset for
    * @param  aInvalidateAfter [in, optional] indicates whether invalidate
    *                           cached offsets for next siblings of the child
    */
-  int32_t GetChildOffset(Accessible* aChild,
+  int32_t GetChildOffset(const Accessible* aChild,
                          bool aInvalidateAfter = false) const
   {
     int32_t index = GetIndexOf(aChild);
     return index == -1 ? -1 : GetChildOffset(index, aInvalidateAfter);
   }
 
   /**
    * Return text offset for the child accessible index.
--- a/accessible/interfaces/ia2/Makefile.in
+++ b/accessible/interfaces/ia2/Makefile.in
@@ -6,16 +6,17 @@ IA2DIR        = $(topsrcdir)/other-licen
 
 GARBAGE       += $(MIDL_GENERATED_FILES)
 
 # Please keep this list in sync with the moz.build file until the rest of this
 # Makefile is ported over.
 MIDL_INTERFACES = \
   Accessible2.idl \
   Accessible2_2.idl \
+  Accessible2_3.idl \
   AccessibleAction.idl \
   AccessibleApplication.idl \
   AccessibleComponent.idl \
   AccessibleDocument.idl \
   AccessibleEditableText.idl \
   AccessibleHyperlink.idl \
   AccessibleHypertext.idl \
   AccessibleHypertext2.idl \
--- a/accessible/interfaces/nsIAccessibleTextRange.idl
+++ b/accessible/interfaces/nsIAccessibleTextRange.idl
@@ -8,17 +8,17 @@
 interface nsIAccessible;
 interface nsIAccessibleText;
 interface nsIArray;
 interface nsIVariant;
 
 /**
  * A range representing a piece of text in the document.
  */
-[scriptable, uuid(525b3401-8a67-4822-b35d-661065767cd8)]
+[scriptable, uuid(c4515623-55f9-4543-a3d5-c1e9afa588f4)]
 interface nsIAccessibleTextRange : nsISupports
 {
   readonly attribute nsIAccessibleText startContainer;
   readonly attribute long startOffset;
   readonly attribute nsIAccessibleText endContainer;
   readonly attribute long endOffset;
 
   /**
@@ -77,16 +77,21 @@ interface nsIAccessibleTextRange : nsISu
   void moveEnd(in unsigned long aUnit, in long aCount);
 
   /**
    * Normalize the range to the closest unit of the given type.
    */
   void normalize(in unsigned long aUnit);
 
   /**
+   * Crops the range by the given accessible element.
+   */
+  boolean crop(in nsIAccessible aContainer);
+
+  /**
    * Return range enclosing the found text.
    */
   nsIAccessibleTextRange findText(in AString aText, in boolean aIsBackward,
                                   in boolean aIsIgnoreCase);
 
   /**
    * Text attributes. Used in conjunction with findAttrs().
    */
--- a/accessible/tests/mochitest/text.js
+++ b/accessible/tests/mochitest/text.js
@@ -468,16 +468,20 @@ function testTextRange(aRange, aRangeDes
            "Wrong start container of " + aRangeDescr);
   is(aRange.startOffset, aStartOffset,
      "Wrong start offset of " + aRangeDescr);
   isObject(aRange.endContainer, getAccessible(aEndContainer),
            "Wrong end container of " + aRangeDescr);
   is(aRange.endOffset, aEndOffset,
      "Wrong end offset of " + aRangeDescr);
 
+  if (aText === undefined) {
+    return;
+  }
+
   is(aRange.text, aText, "Wrong text of " + aRangeDescr);
 
   var children = aRange.embeddedChildren;
   is(children ? children.length : 0, aChildren ? aChildren.length : 0,
      "Wrong embedded children count of " + aRangeDescr);
 
   isObject(aRange.container, getAccessible(aCommonContainer),
            "Wrong container of " + aRangeDescr);
--- a/accessible/tests/mochitest/textrange/a11y.ini
+++ b/accessible/tests/mochitest/textrange/a11y.ini
@@ -1,3 +1,4 @@
 [DEFAULT]
 
 [test_general.html]
+[test_selection.html]
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/textrange/test_selection.html
@@ -0,0 +1,120 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Text Range selection tests</title>
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../text.js"></script>
+  <script type="application/javascript"
+          src="../layout.js"></script>
+  <script type="application/javascript">
+
+    function doTest()
+    {
+      var sel = window.getSelection();
+      var p = getNode("p1");
+      var a = getNode("p2_a");
+
+      var range = document.createRange();
+      sel.addRange(range);
+
+      // the accessible is contained by the range
+      range.selectNode(p);
+
+      var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
+      var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
+
+      testTextRange(a11yrange, "selection range #1", document, 3, document, 4);
+
+      ok(a11yrange.crop(getAccessible(a)), "Range failed to crop #1.");
+      testTextRange(a11yrange, "cropped range #1", a, 0, a, 5);
+
+      // the range is contained by the accessible
+      range.selectNode(a);
+      var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
+      var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
+
+      testTextRange(a11yrange, "selection range #2", p, 5, p, 6);
+
+      ok(a11yrange.crop(getAccessible(p)), "Range failed to crop #2.");
+      testTextRange(a11yrange, "cropped range #2", p, 5, p, 6);
+
+      // the range starts before the accessible and ends inside it
+      range.setStart(p, 0);
+      range.setEndAfter(a.firstChild, 4);
+      var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
+      var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
+
+      testTextRange(a11yrange, "selection range #3", p, 0, a, 4);
+
+      ok(a11yrange.crop(getAccessible(a)), "Range failed to crop #3.");
+      testTextRange(a11yrange, "cropped range #3", a, 0, a, 4);
+
+      // the range starts inside the accessible and ends after it
+      range.setStart(a.firstChild, 1);
+      range.setEndAfter(p);
+      var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
+      var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
+
+      testTextRange(a11yrange, "selection range #4", a, 1, document, 4);
+
+      ok(a11yrange.crop(getAccessible(a)), "Range failed to crop #4.");
+      testTextRange(a11yrange, "cropped range #4", a, 1, a, 5);
+
+      // the range ends before the accessible
+      range.setStart(p.firstChild, 0);
+      range.setEnd(p.firstChild, 4);
+      var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
+      var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
+
+      testTextRange(a11yrange, "selection range #5", p, 0, p, 4);
+      ok(!a11yrange.crop(getAccessible(a)), "Crop #5 succeeded while it shouldn't");
+
+      // the range starts after the accessible
+      range.setStart(p.lastChild, 0);
+      range.setEnd(p.lastChild, 4);
+      var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
+      var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
+
+      testTextRange(a11yrange, "selection range #6", p, 6, p, 10);
+
+      ok(!a11yrange.crop(getAccessible(a)), "Crop #6 succeeded while it shouldn't");
+
+      // crop a range by a table
+      range.selectNode(getNode("c2"));
+      var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
+      var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
+
+      testTextRange(a11yrange, "selection range #7", document, 4, document, 5);
+
+      ok(a11yrange.crop(getAccessible("table")), "Range failed to crop #7.");
+      testTextRange(a11yrange, "cropped range #7", "c2", 5, "c2", 6);
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <a target="_blank"
+     title="Implement IAccessible2_3::selectionRanges"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=1233118">Bug 1233118</a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <p id="p1">text <a id="p2_a" href="www">link<img id="p2_img", src="../moz.png"></a> text</p>
+
+  <div id="c2">start<table id="table"><tr><td>cell</td></tr></table>end</div>
+</body>
+</html>
--- a/accessible/windows/ia2/ia2Accessible.cpp
+++ b/accessible/windows/ia2/ia2Accessible.cpp
@@ -3,26 +3,28 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "AccessibleWrap.h"
 
 #include "Accessible2_i.c"
 #include "Accessible2_2_i.c"
+#include "Accessible2_3_i.c"
 #include "AccessibleRole.h"
 #include "AccessibleStates.h"
 
 #include "Compatibility.h"
 #include "ia2AccessibleRelation.h"
 #include "IUnknownImpl.h"
 #include "nsCoreUtils.h"
 #include "nsIAccessibleTypes.h"
 #include "mozilla/a11y/PDocAccessible.h"
 #include "Relation.h"
+#include "TextRange-inl.h"
 #include "nsAccessibilityService.h"
 
 #include "nsIPersistentProperties2.h"
 #include "nsISimpleEnumerator.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
@@ -35,17 +37,19 @@ template<typename String> static void Es
 STDMETHODIMP
 ia2Accessible::QueryInterface(REFIID iid, void** ppv)
 {
   if (!ppv)
     return E_INVALIDARG;
 
   *ppv = nullptr;
 
-  if (IID_IAccessible2_2 == iid)
+  if (IID_IAccessible2_3 == iid)
+    *ppv = static_cast<IAccessible2_3*>(this);
+  else if (IID_IAccessible2_2 == iid)
     *ppv = static_cast<IAccessible2_2*>(this);
   else if (IID_IAccessible2 == iid && !Compatibility::IsIA2Off())
     *ppv = static_cast<IAccessible2*>(this);
 
   if (*ppv) {
     (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
     return S_OK;
   }
@@ -744,16 +748,68 @@ ia2Accessible::get_relationTargetsOfType
     (*aTargets)[i]->AddRef();
   }
 
   return S_OK;
 
   A11Y_TRYBLOCK_END
 }
 
+STDMETHODIMP
+ia2Accessible::get_selectionRanges(IA2Range** aRanges,
+                                   long *aNRanges)
+{
+  A11Y_TRYBLOCK_BEGIN
+
+  if (!aRanges || !aNRanges || aNRanges <= 0)
+    return E_INVALIDARG;
+
+  *aNRanges = 0;
+
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct())
+    return CO_E_OBJNOTCONNECTED;
+
+  nsAutoTArray<TextRange, 1> ranges;
+  acc->Document()->SelectionRanges(&ranges);
+  uint32_t len = ranges.Length();
+  for (uint32_t idx = 0; idx < len; idx++) {
+    if (!ranges[idx].Crop(acc)) {
+      ranges.RemoveElementAt(idx);
+    }
+  }
+
+  *aNRanges = ranges.Length();
+  *aRanges = static_cast<IA2Range*>(
+    ::CoTaskMemAlloc(sizeof(IA2Range) * *aNRanges));
+  if (!*aRanges)
+    return E_OUTOFMEMORY;
+
+  for (uint32_t idx = 0; idx < static_cast<uint32_t>(*aNRanges); idx++) {
+    AccessibleWrap* anchor =
+      static_cast<AccessibleWrap*>(ranges[idx].StartContainer());
+    (*aRanges)[idx].anchor = static_cast<IAccessible2*>(anchor);
+    anchor->AddRef();
+
+    (*aRanges)[idx].anchorOffset = ranges[idx].StartOffset();
+
+    AccessibleWrap* active =
+      static_cast<AccessibleWrap*>(ranges[idx].EndContainer());
+    (*aRanges)[idx].active = static_cast<IAccessible2*>(active);
+    active->AddRef();
+
+    (*aRanges)[idx].activeOffset = ranges[idx].EndOffset();
+  }
+
+  return S_OK;
+
+  A11Y_TRYBLOCK_END
+}
+
+
 ////////////////////////////////////////////////////////////////////////////////
 // Helpers
 
 template<typename String>
 static inline void
 EscapeAttributeChars(String& aStr)
 {
   int32_t offset = 0;
--- a/accessible/windows/ia2/ia2Accessible.h
+++ b/accessible/windows/ia2/ia2Accessible.h
@@ -4,23 +4,23 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_a11y_ia2Accessible_h_
 #define mozilla_a11y_ia2Accessible_h_
 
 #include "nsISupports.h"
 
-#include "Accessible2_2.h"
+#include "Accessible2_3.h"
 
 namespace mozilla {
 namespace a11y {
 class Attribute;
 
-class ia2Accessible : public IAccessible2_2
+class ia2Accessible : public IAccessible2_3
 {
 public:
 
   // IUnknown
   STDMETHODIMP QueryInterface(REFIID, void**);
 
   // IAccessible2
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nRelations(
@@ -99,16 +99,21 @@ public:
 
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_relationTargetsOfType(
     /* [in] */ BSTR type,
     /* [in] */ long maxTargets,
     /* [out, size_is(,*nTargets)] */ IUnknown*** targets,
     /* [out, retval] */ long* nTargets
   );
 
+  // IAccessible2_3
+  virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selectionRanges(
+    /* [out, size_is(,*nRanges)] */ IA2Range** ranges,
+    /* [out, retval] */ long *nRanges);
+
   // Helper method
   static HRESULT ConvertToIA2Attributes(nsIPersistentProperties* aAttributes,
                                         BSTR* aIA2Attributes);
   static HRESULT ConvertToIA2Attributes(nsTArray<Attribute>* aAttributes,
                                         BSTR* aIA2Attributes);
 };
 
 } // namespace a11y
--- a/accessible/xpcom/xpcAccessibleTextRange.cpp
+++ b/accessible/xpcom/xpcAccessibleTextRange.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "xpcAccessibleTextRange.h"
 
-#include "TextRange.h"
+#include "TextRange-inl.h"
 #include "xpcAccessibleDocument.h"
 
 #include "nsIMutableArray.h"
 #include "nsComponentManagerUtils.h"
 #include "nsQueryObject.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
@@ -166,16 +166,26 @@ xpcAccessibleTextRange::MoveEnd(uint32_t
 
 NS_IMETHODIMP
 xpcAccessibleTextRange::Normalize(uint32_t aUnit)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
+xpcAccessibleTextRange::Crop(nsIAccessible* aContainer, bool* aSuccess)
+{
+  Accessible* container = aContainer->ToInternalAccessible();
+  NS_ENSURE_TRUE(container, NS_ERROR_INVALID_ARG);
+
+  *aSuccess = mRange.Crop(container);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 xpcAccessibleTextRange::FindText(const nsAString& aText, bool aIsBackward,
                                  bool aIsIgnoreCase,
                                  nsIAccessibleTextRange** aRange)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/accessible/xpcom/xpcAccessibleTextRange.h
+++ b/accessible/xpcom/xpcAccessibleTextRange.h
@@ -44,16 +44,17 @@ public:
                               uint32_t aOtherRangeEndPoint,
                               int32_t* aResult) final override;
   NS_IMETHOD GetText(nsAString& aText) final override;
   NS_IMETHOD GetBounds(nsIArray** aRectList) final override;
   NS_IMETHOD Move(uint32_t aUnit, int32_t aCount) final override;
   NS_IMETHOD MoveStart(uint32_t aUnit, int32_t aCount) final override;
   NS_IMETHOD MoveEnd(uint32_t aUnit, int32_t aCount) final override;
   NS_IMETHOD Normalize(uint32_t aUnit) final override;
+  NS_IMETHOD Crop(nsIAccessible* aContainer, bool* aSuccess) final override;
   NS_IMETHOD FindText(const nsAString& aText, bool aIsBackward, bool aIsIgnoreCase,
                       nsIAccessibleTextRange** aRange) final override;
   NS_IMETHOD FindAttr(uint32_t aAttr, nsIVariant* aVal, bool aIsBackward,
                       nsIAccessibleTextRange** aRange) final override;
   NS_IMETHOD AddToSelection() final override;
   NS_IMETHOD RemoveFromSelection() final override;
   NS_IMETHOD Select() final override;
   NS_IMETHOD ScrollIntoView(uint32_t aHow) final override;
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1389,26 +1389,29 @@ pref("social.sidebar.unload_timeout_ms",
 pref("social.share.activationPanelEnabled", true);
 pref("social.shareDirectory", "https://activations.cdn.mozilla.net/sharePanel.html");
 
 pref("dom.identity.enabled", false);
 
 // Block insecure active content on https pages
 pref("security.mixed_content.block_active_content", true);
 
-// Show degraded UI for http pages with password fields
-#ifdef NIGHTLY_BUILD
+// Show degraded UI for http pages with password fields.
+// Only for Nightly and Dev Edition for not, not for beta or release.
+#ifndef RELEASE_BUILD
 pref("security.insecure_password.ui.enabled", true);
 #else
 pref("security.insecure_password.ui.enabled", false);
 #endif
 
 // 1 = allow MITM for certificate pinning checks.
 pref("security.cert_pinning.enforcement_level", 1);
 
+// NB: Changes to this pref affect CERT_CHAIN_SHA1_POLICY_STATUS telemetry.
+// See the comment in CertVerifier.cpp.
 // 0 = allow SHA-1
 pref("security.pki.sha1_enforcement_level", 0);
 
 // Required blocklist freshness for OneCRL OCSP bypass
 // (default is 1.25x extensions.blocklist.interval, or 30 hours)
 pref("security.onecrl.maximum_staleness_in_seconds", 108000);
 
 // Override the Gecko-default value of false for Firefox.
--- a/browser/base/content/test/general/browser_sanitizeDialog.js
+++ b/browser/base/content/test/general/browser_sanitizeDialog.js
@@ -549,17 +549,17 @@ add_task(function* test_offline_cache() 
 
   // Give www.example.com privileges to store offline data
   Services.perms.addFromPrincipal(principal, "offline-app", Ci.nsIPermissionManager.ALLOW_ACTION);
   Services.perms.addFromPrincipal(principal, "offline-app", Ci.nsIOfflineCacheUpdateService.ALLOW_NO_WARN);
 
   // Store something to the offline cache
   var appcacheserv = Cc["@mozilla.org/network/application-cache-service;1"]
                      .getService(Ci.nsIApplicationCacheService);
-  var appcachegroupid = appcacheserv.buildGroupID(makeURI(URL + "/manifest"), LoadContextInfo.default);
+  var appcachegroupid = appcacheserv.buildGroupIDForInfo(makeURI(URL + "/manifest"), LoadContextInfo.default);
   var appcache = appcacheserv.createApplicationCache(appcachegroupid);
   var storage = Services.cache2.appCacheStorage(LoadContextInfo.default, appcache);
 
   // Open the dialog
   let wh = new WindowHelper();
   wh.onload = function () {
     this.selectDuration(Sanitizer.TIMESPAN_EVERYTHING);
     // Show details
--- a/browser/components/search/test/browser.ini
+++ b/browser/components/search/test/browser.ini
@@ -9,42 +9,33 @@ support-files =
   test.html
   testEngine.xml
   testEngine_diacritics.xml
   testEngine_dupe.xml
   testEngine_mozsearch.xml
   webapi.html
 
 [browser_426329.js]
-skip-if = e10s # Bug ?????? - Test uses load event and checks event.target.
 [browser_483086.js]
 [browser_addEngine.js]
 [browser_amazon.js]
 [browser_amazon_behavior.js]
-skip-if = e10s # Bug ?????? - some issue with progress listeners [JavaScript Error: "req.originalURI is null" {file: "chrome://mochitests/content/browser/browser/components/search/test/browser_bing_behavior.js" line: 127}]
 [browser_bing.js]
 [browser_bing_behavior.js]
-skip-if = e10s # Bug ?????? - some issue with progress listeners [JavaScript Error: "req.originalURI is null" {file: "chrome://mochitests/content/browser/browser/components/search/test/browser_bing_behavior.js" line: 127}]
 [browser_contextmenu.js]
-skip-if = e10s # Bug ?????? - Test touches content (content.window.getSelection().QueryInterface(Ci.nsISelectionPrivate)....)
 [browser_eBay.js]
 [browser_eBay_behavior.js]
-skip-if = e10s # Bug ?????? - some issue with progress listeners [JavaScript Error: "req.originalURI is null" {file: "chrome://mochitests/content/browser/browser/components/search/test/browser_bing_behavior.js" line: 127}]
 [browser_google.js]
 [browser_google_behavior.js]
-skip-if = e10s # Bug ?????? - some issue with progress listeners [JavaScript Error: "req.originalURI is null" {file: "chrome://mochitests/content/browser/browser/components/search/test/browser_bing_behavior.js" line: 127}]
 [browser_healthreport.js]
 [browser_hiddenOneOffs_cleanup.js]
 [browser_hiddenOneOffs_diacritics.js]
 [browser_oneOffHeader.js]
-skip-if = e10s # bug ?????? - Test alters the searchbar textbox value which causes issues with other tests in e10s.
 [browser_private_search_perwindowpb.js]
-skip-if = e10s # Bug ?????? - Test uses load event and checks event.target.
 [browser_yahoo.js]
 [browser_yahoo_behavior.js]
-skip-if = e10s # Bug ?????? - some issue with progress listeners [JavaScript Error: "req.originalURI is null" {file: "chrome://mochitests/content/browser/browser/components/search/test/browser_bing_behavior.js" line: 127}]
 [browser_abouthome_behavior.js]
-skip-if = e10s || true # Bug ??????, Bug 1100301 - leaks windows until shutdown when --run-by-dir
+skip-if = true # Bug ??????, Bug 1100301 - leaks windows until shutdown when --run-by-dir
 [browser_searchbar_openpopup.js]
-skip-if = os == "linux" || e10s # Linux has different focus behaviours and e10s seems to have timing issues.
+skip-if = os == "linux" # Linux has different focus behaviours.
 [browser_searchbar_keyboard_navigation.js]
 [browser_searchbar_smallpanel_keyboard_navigation.js]
 [browser_webapi.js]
--- a/browser/components/search/test/browser_426329.js
+++ b/browser/components/search/test/browser_426329.js
@@ -1,19 +1,10 @@
-// Instead of loading ChromeUtils.js into the test scope in browser-test.js for all tests,
-// we only need ChromeUtils.js for a few files which is why we are using loadSubScript.
-var ChromeUtils = {};
-this._scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
-                     getService(Ci.mozIJSSubScriptLoader);
-this._scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js", ChromeUtils);
-
 XPCOMUtils.defineLazyModuleGetter(this, "FormHistory",
   "resource://gre/modules/FormHistory.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Promise",
-  "resource://gre/modules/Promise.jsm");
 
 function expectedURL(aSearchTerms) {
   const ENGINE_HTML_BASE = "http://mochi.test:8888/browser/browser/components/search/test/test.html";
   var textToSubURI = Cc["@mozilla.org/intl/texttosuburi;1"].
                      getService(Ci.nsITextToSubURI);
   var searchArg = textToSubURI.ConvertAndEscape("utf-8", aSearchTerms);
   return ENGINE_HTML_BASE + "?test=" + searchArg;
 }
@@ -48,216 +39,198 @@ function getMenuEntries() {
   var column = autocompleteMenu.tree.columns[0];
   var numRows = autocompleteMenu.tree.view.rowCount;
   for (var i = 0; i < numRows; i++) {
     entries.push(autocompleteMenu.tree.view.getValueAt(i, column));
   }
   return entries;
 }
 
-function* countEntries(name, value) {
-  let deferred = Promise.defer();
-  let count = 0;
-  let obj = name && value ? {fieldname: name, value: value} : {};
-  FormHistory.count(obj,
-                    { handleResult: function(result) { count = result; },
-                      handleError: function(error) { throw error; },
-                      handleCompletion: function(reason) {
-                        if (!reason) {
-                          deferred.resolve(count);
+function countEntries(name, value) {
+  return new Promise(resolve => {
+    let count = 0;
+    let obj = name && value ? {fieldname: name, value: value} : {};
+    FormHistory.count(obj,
+                      { handleResult: function(result) { count = result; },
+                        handleError: function(error) { throw error; },
+                        handleCompletion: function(reason) {
+                          if (!reason) {
+                            resolve(count);
+                          }
                         }
-                      }
-                    });
-  return deferred.promise;
+                      });
+  });
 }
 
 var searchBar;
 var searchButton;
 var searchEntries = ["test"];
-function* promiseSetEngine() {
-  let deferred = Promise.defer();
-  var ss = Services.search;
+function promiseSetEngine() {
+  return new Promise(resolve => {
+    var ss = Services.search;
 
-  function observer(aSub, aTopic, aData) {
-    switch (aData) {
-      case "engine-added":
-        var engine = ss.getEngineByName("Bug 426329");
-        ok(engine, "Engine was added.");
-        ss.currentEngine = engine;
-        break;
-      case "engine-current":
-        ok(ss.currentEngine.name == "Bug 426329", "currentEngine set");
-        searchBar = BrowserSearch.searchBar;
-        searchButton = document.getAnonymousElementByAttribute(searchBar,
-                           "anonid", "search-go-button");
-        ok(searchButton, "got search-go-button");
-        searchBar.value = "test";
+    function observer(aSub, aTopic, aData) {
+      switch (aData) {
+        case "engine-added":
+          var engine = ss.getEngineByName("Bug 426329");
+          ok(engine, "Engine was added.");
+          ss.currentEngine = engine;
+          break;
+        case "engine-current":
+          ok(ss.currentEngine.name == "Bug 426329", "currentEngine set");
+          searchBar = BrowserSearch.searchBar;
+          searchButton = document.getAnonymousElementByAttribute(searchBar,
+                             "anonid", "search-go-button");
+          ok(searchButton, "got search-go-button");
+          searchBar.value = "test";
 
-        Services.obs.removeObserver(observer, "browser-search-engine-modified");
-        deferred.resolve();
-        break;
-    }
-  };
+          Services.obs.removeObserver(observer, "browser-search-engine-modified");
+          resolve();
+          break;
+      }
+    };
 
-  Services.obs.addObserver(observer, "browser-search-engine-modified", false);
-  ss.addEngine("http://mochi.test:8888/browser/browser/components/search/test/426329.xml",
-               null, "data:image/x-icon,%00", false);
-
-  return deferred.promise;
+    Services.obs.addObserver(observer, "browser-search-engine-modified", false);
+    ss.addEngine("http://mochi.test:8888/browser/browser/components/search/test/426329.xml",
+                 null, "data:image/x-icon,%00", false);
+  });
 }
 
-function* promiseRemoveEngine() {
-  let deferred = Promise.defer();
-  var ss = Services.search;
+function promiseRemoveEngine() {
+  return new Promise(resolve => {
+    var ss = Services.search;
 
-  function observer(aSub, aTopic, aData) {
-    if (aData == "engine-removed") {
-      Services.obs.removeObserver(observer, "browser-search-engine-modified");
-      deferred.resolve();
-    }
-  };
+    function observer(aSub, aTopic, aData) {
+      if (aData == "engine-removed") {
+        Services.obs.removeObserver(observer, "browser-search-engine-modified");
+        resolve();
+      }
+    };
 
-  Services.obs.addObserver(observer, "browser-search-engine-modified", false);
-  var engine = ss.getEngineByName("Bug 426329");
-  ss.removeEngine(engine);
-
-  return deferred.promise;
+    Services.obs.addObserver(observer, "browser-search-engine-modified", false);
+    var engine = ss.getEngineByName("Bug 426329");
+    ss.removeEngine(engine);
+  });
 }
 
 
 var preSelectedBrowser;
 var preTabNo;
 function* prepareTest() {
   preSelectedBrowser = gBrowser.selectedBrowser;
   preTabNo = gBrowser.tabs.length;
   searchBar = BrowserSearch.searchBar;
 
-  let windowFocused = Promise.defer();
-  SimpleTest.waitForFocus(windowFocused.resolve, window);
-  yield windowFocused.promise;
+  yield SimpleTest.promiseFocus();
+
+  if (document.activeElement == searchBar)
+    return;
 
-  let deferred = Promise.defer();
-  if (document.activeElement != searchBar) {
-    searchBar.addEventListener("focus", function onFocus() {
-      searchBar.removeEventListener("focus", onFocus);
-      deferred.resolve();
-    });
-    gURLBar.focus();
-    searchBar.focus();
-  } else {
-    deferred.resolve();
-  }
-  return deferred.promise;
+  let focusPromise = BrowserTestUtils.waitForEvent(searchBar, "focus");
+  gURLBar.focus();
+  searchBar.focus();
+  yield focusPromise;
 }
 
 add_task(function* testSetupEngine() {
   yield promiseSetEngine();
 });
 
 add_task(function* testReturn() {
-  yield prepareTest();
+  yield* prepareTest();
   EventUtils.synthesizeKey("VK_RETURN", {});
-  let event = yield promiseOnLoad();
+  yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
 
   is(gBrowser.tabs.length, preTabNo, "Return key did not open new tab");
-  is(event.originalTarget, preSelectedBrowser.contentDocument,
-     "Return key loaded results in current tab");
-  is(event.originalTarget.URL, expectedURL(searchBar.value), "testReturn opened correct search page");
+  is(gBrowser.currentURI.spec, expectedURL(searchBar.value), "testReturn opened correct search page");
 });
 
 add_task(function* testAltReturn() {
-  yield prepareTest();
-  EventUtils.synthesizeKey("VK_RETURN", { altKey: true });
-  let event = yield promiseOnLoad();
+  yield* prepareTest();
+  yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
+    EventUtils.synthesizeKey("VK_RETURN", { altKey: true });
+  });
 
   is(gBrowser.tabs.length, preTabNo + 1, "Alt+Return key added new tab");
-  isnot(event.originalTarget, preSelectedBrowser.contentDocument,
-        "Alt+Return key loaded results in new tab");
-  is(event.originalTarget, gBrowser.contentDocument,
-     "Alt+Return key loaded results in foreground tab");
-  is(event.originalTarget.URL, expectedURL(searchBar.value), "testAltReturn opened correct search page");
+  is(gBrowser.currentURI.spec, expectedURL(searchBar.value), "testAltReturn opened correct search page");
 });
 
 //Shift key has no effect for now, so skip it
 add_task(function* testShiftAltReturn() {
   return;
 
-  yield prepareTest();
+  yield* prepareTest();
+
+  let url = expectedURL(searchBar.value);
+
+  let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, url);
   EventUtils.synthesizeKey("VK_RETURN", { shiftKey: true, altKey: true });
-  let event = yield promiseOnLoad();
+  let newTab = yield newTabPromise;
 
   is(gBrowser.tabs.length, preTabNo + 1, "Shift+Alt+Return key added new tab");
-  isnot(event.originalTarget, preSelectedBrowser.contentDocument,
-        "Shift+Alt+Return key loaded results in new tab");
-  isnot(event.originalTarget, gBrowser.contentDocument,
-        "Shift+Alt+Return key loaded results in background tab");
-  is(event.originalTarget.URL, expectedURL(searchBar.value), "testShiftAltReturn opened correct search page");
+  is(gBrowser.currentURI.spec, url, "testShiftAltReturn opened correct search page");
 });
 
 add_task(function* testLeftClick() {
-  yield prepareTest();
+  yield* prepareTest();
   simulateClick({ button: 0 }, searchButton);
-  let event = yield promiseOnLoad();
+  yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
   is(gBrowser.tabs.length, preTabNo, "LeftClick did not open new tab");
-  is(event.originalTarget, preSelectedBrowser.contentDocument,
-     "LeftClick loaded results in current tab");
-  is(event.originalTarget.URL, expectedURL(searchBar.value), "testLeftClick opened correct search page");
+  is(gBrowser.currentURI.spec, expectedURL(searchBar.value), "testLeftClick opened correct search page");
 });
 
 add_task(function* testMiddleClick() {
-  yield prepareTest();
-  simulateClick({ button: 1 }, searchButton);
-  let event = yield promiseOnLoad();
+  yield* prepareTest();
+  yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
+    simulateClick({ button: 1 }, searchButton);
+  });
   is(gBrowser.tabs.length, preTabNo + 1, "MiddleClick added new tab");
-  isnot(event.originalTarget, preSelectedBrowser.contentDocument,
-        "MiddleClick loaded results in new tab");
-  is(event.originalTarget, gBrowser.contentDocument,
-     "MiddleClick loaded results in foreground tab");
-  is(event.originalTarget.URL, expectedURL(searchBar.value), "testMiddleClick opened correct search page");
+  is(gBrowser.currentURI.spec, expectedURL(searchBar.value), "testMiddleClick opened correct search page");
 });
 
 add_task(function* testShiftMiddleClick() {
-  yield prepareTest();
+  yield* prepareTest();
+
+  let url = expectedURL(searchBar.value);
+
+  let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, url);
   simulateClick({ button: 1, shiftKey: true }, searchButton);
-  let event = yield promiseOnLoad();
+  let newTab = yield newTabPromise;
+
   is(gBrowser.tabs.length, preTabNo + 1, "Shift+MiddleClick added new tab");
-  isnot(event.originalTarget, preSelectedBrowser.contentDocument,
-        "Shift+MiddleClick loaded results in new tab");
-  isnot(event.originalTarget, gBrowser.contentDocument,
-        "Shift+MiddleClick loaded results in background tab");
-  is(event.originalTarget.URL, expectedURL(searchBar.value), "testShiftMiddleClick opened correct search page");
+  is(newTab.linkedBrowser.currentURI.spec, url, "testShiftMiddleClick opened correct search page");
 });
 
 add_task(function* testRightClick() {
   preTabNo = gBrowser.tabs.length;
-  content.location.href = "about:blank";
-  simulateClick({ button: 2 }, searchButton);
-  let deferred = Promise.defer();
-  setTimeout(function() {
-    is(gBrowser.tabs.length, preTabNo, "RightClick did not open new tab");
-    is(gBrowser.currentURI.spec, "about:blank", "RightClick did nothing");
-    deferred.resolve();
-  }, 5000);
-  yield deferred.promise;
+  gBrowser.selectedBrowser.loadURI("about:blank");
+  yield new Promise(resolve => {
+    setTimeout(function() {
+      is(gBrowser.tabs.length, preTabNo, "RightClick did not open new tab");
+      is(gBrowser.currentURI.spec, "about:blank", "RightClick did nothing");
+      resolve();
+    }, 5000);
+    simulateClick({ button: 2 }, searchButton);
+  });
   // The click in the searchbox focuses it, which opens the suggestion
   // panel. Clean up after ourselves.
   searchBar.textbox.popup.hidePopup();
 });
 
 add_task(function* testSearchHistory() {
   var textbox = searchBar._textbox;
   for (var i = 0; i < searchEntries.length; i++) {
     let count = yield countEntries(textbox.getAttribute("autocompletesearchparam"), searchEntries[i]);
     ok(count > 0, "form history entry '" + searchEntries[i] + "' should exist");
   }
 });
 
 add_task(function* testAutocomplete() {
   var popup = searchBar.textbox.popup;
-  let popupShownPromise = promiseEvent(popup, "popupshown");
+  let popupShownPromise = BrowserTestUtils.waitForEvent(popup, "popupshown");
   searchBar.textbox.showHistoryPopup();
   yield popupShownPromise;
   checkMenuEntries(searchEntries);
 });
 
 add_task(function* testClearHistory() {
   let controller = searchBar.textbox.controllers.getControllerForCommand("cmd_clearhistory")
   ok(controller.isCommandEnabled("cmd_clearhistory"), "Clear history command enabled");
@@ -266,11 +239,11 @@ add_task(function* testClearHistory() {
   ok(count == 0, "History cleared");
 });
 
 add_task(function* asyncCleanup() {
   searchBar.value = "";
   while (gBrowser.tabs.length != 1) {
     gBrowser.removeTab(gBrowser.tabs[0], {animate: false});
   }
-  content.location.href = "about:blank";
+  gBrowser.selectedBrowser.loadURI("about:blank");
   yield promiseRemoveEngine();
 });
--- a/browser/components/search/test/browser_abouthome_behavior.js
+++ b/browser/components/search/test/browser_abouthome_behavior.js
@@ -114,16 +114,19 @@ function test() {
     onStateChange: function onStateChange(webProgress, req, flags, status) {
       info("onStateChange");
       // Only care about top-level document starts
       let docStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
                      Ci.nsIWebProgressListener.STATE_START;
       if (!(flags & docStart) || !webProgress.isTopLevel)
         return;
 
+      if (req.originalURI.spec == "about:blank")
+        return;
+
       info("received document start");
 
       ok(req instanceof Ci.nsIChannel, "req is a channel");
       is(req.originalURI.spec, gCurrTest.searchURL, "search URL was loaded");
       info("Actual URI: " + req.URI.spec);
 
       req.cancel(Components.results.NS_ERROR_FAILURE);
 
--- a/browser/components/search/test/browser_amazon_behavior.js
+++ b/browser/components/search/test/browser_amazon_behavior.js
@@ -131,16 +131,19 @@ function test() {
     onStateChange: function onStateChange(webProgress, req, flags, status) {
       info("onStateChange");
       // Only care about top-level document starts
       let docStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
                      Ci.nsIWebProgressListener.STATE_START;
       if (!(flags & docStart) || !webProgress.isTopLevel)
         return;
 
+      if (req.originalURI.spec == "about:blank")
+        return;
+
       info("received document start");
 
       ok(req instanceof Ci.nsIChannel, "req is a channel");
       is(req.originalURI.spec, gCurrTest.searchURL, "search URL was loaded");
       info("Actual URI: " + req.URI.spec);
 
       req.cancel(Components.results.NS_ERROR_FAILURE);
 
--- a/browser/components/search/test/browser_bing_behavior.js
+++ b/browser/components/search/test/browser_bing_behavior.js
@@ -131,16 +131,19 @@ function test() {
     onStateChange: function onStateChange(webProgress, req, flags, status) {
       info("onStateChange");
       // Only care about top-level document starts
       let docStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
                      Ci.nsIWebProgressListener.STATE_START;
       if (!(flags & docStart) || !webProgress.isTopLevel)
         return;
 
+      if (req.originalURI.spec == "about:blank")
+        return;
+
       info("received document start");
 
       ok(req instanceof Ci.nsIChannel, "req is a channel");
       is(req.originalURI.spec, gCurrTest.searchURL, "search URL was loaded");
       info("Actual URI: " + req.URI.spec);
 
       req.cancel(Components.results.NS_ERROR_FAILURE);
 
--- a/browser/components/search/test/browser_contextmenu.js
+++ b/browser/components/search/test/browser_contextmenu.js
@@ -1,111 +1,98 @@
 /* Any copyright is dedicated to the Public Domain.
  *  * http://creativecommons.org/publicdomain/zero/1.0/ */
 /*
  * Test searching for the selected text using the context menu
  */
 
-function test() {
-  waitForExplicitFinish();
-
+add_task(function* () {
   const ss = Services.search;
   const ENGINE_NAME = "Foo";
   var contextMenu;
 
   let envService = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
   let originalValue = envService.get("XPCSHELL_TEST_PROFILE_DIR");
   envService.set("XPCSHELL_TEST_PROFILE_DIR", "1");
 
   let url = "chrome://mochitests/content/browser/browser/components/search/test/";
   let resProt = Services.io.getProtocolHandler("resource")
                         .QueryInterface(Ci.nsIResProtocolHandler);
   let originalSubstitution = resProt.getSubstitution("search-plugins");
   resProt.setSubstitution("search-plugins",
                           Services.io.newURI(url, null, null));
 
-  function observer(aSub, aTopic, aData) {
-    switch (aData) {
-      case "engine-added":
-        var engine = ss.getEngineByName(ENGINE_NAME);
-        ok(engine, "Engine was added.");
-        ss.currentEngine = engine;
-        envService.set("XPCSHELL_TEST_PROFILE_DIR", originalValue);
-        resProt.setSubstitution("search-plugins", originalSubstitution);
-        break;
-      case "engine-current":
-        is(ss.currentEngine.name, ENGINE_NAME, "currentEngine set");
-        startTest();
-        break;
-      case "engine-removed":
-        Services.obs.removeObserver(observer, "browser-search-engine-modified");
-        finish();
-        break;
-    }
-  }
-
-  Services.obs.addObserver(observer, "browser-search-engine-modified", false);
-  ss.addEngine("resource://search-plugins/testEngine_mozsearch.xml",
-               null, "data:image/x-icon,%00", false);
-
-  function startTest() {
-    contextMenu = document.getElementById("contentAreaContextMenu");
-    ok(contextMenu, "Got context menu XUL");
-
-    doOnloadOnce(testContextMenu);
-    let tab = gBrowser.selectedTab = gBrowser.addTab("data:text/plain;charset=utf8,test%20search");
-    registerCleanupFunction(function () {
-      gBrowser.removeTab(tab);
-    });
-  }
-
-  function testContextMenu() {
-    function rightClickOnDocument() {
-      info("rightClickOnDocument: " + content.window.location);
-      waitForBrowserContextMenu(checkContextMenu);
-      var clickTarget = content.document.body;
-      var eventDetails = { type: "contextmenu", button: 2 };
-      EventUtils.synthesizeMouseAtCenter(clickTarget, eventDetails, content);
+  let searchDonePromise;
+  yield new Promise(resolve => {
+    function observer(aSub, aTopic, aData) {
+      switch (aData) {
+        case "engine-added":
+          var engine = ss.getEngineByName(ENGINE_NAME);
+          ok(engine, "Engine was added.");
+          ss.currentEngine = engine;
+          envService.set("XPCSHELL_TEST_PROFILE_DIR", originalValue);
+          resProt.setSubstitution("search-plugins", originalSubstitution);
+          break;
+        case "engine-current":
+          is(ss.currentEngine.name, ENGINE_NAME, "currentEngine set");
+          resolve();
+          break;
+        case "engine-removed":
+          Services.obs.removeObserver(observer, "browser-search-engine-modified");
+          if (searchDonePromise) {
+            searchDonePromise();
+          }
+          break;
+      }
     }
 
-    // check the search menu item and then perform a search
-    function checkContextMenu() {
-      info("checkContextMenu");
-      var searchItem = contextMenu.getElementsByAttribute("id", "context-searchselect")[0];
-      ok(searchItem, "Got search context menu item");
-      is(searchItem.label, 'Search ' + ENGINE_NAME + ' for "test search"', "Check context menu label");
-      is(searchItem.disabled, false, "Check that search context menu item is enabled");
-      doOnloadOnce(checkSearchURL);
-      searchItem.click();
-      contextMenu.hidePopup();
-    }
+    Services.obs.addObserver(observer, "browser-search-engine-modified", false);
+    ss.addEngine("resource://search-plugins/testEngine_mozsearch.xml",
+                 null, "data:image/x-icon,%00", false);
+  });
+
+  contextMenu = document.getElementById("contentAreaContextMenu");
+  ok(contextMenu, "Got context menu XUL");
+
+  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "data:text/plain;charset=utf8,test%20search");
 
-    function checkSearchURL(event) {
-      is(event.originalTarget.URL,
-         "http://mochi.test:8888/browser/browser/components/search/test/?test=test+search&ie=utf-8&channel=contextsearch",
-         "Checking context menu search URL");
-      // Remove the tab opened by the search
-      gBrowser.removeCurrentTab();
-      ss.removeEngine(ss.currentEngine);
-    }
+  yield ContentTask.spawn(tab.linkedBrowser, "", function*() {
+    return new Promise(resolve => {
+      content.document.addEventListener("selectionchange", function selectionChanged() {
+        content.document.removeEventListener("selectionchange", selectionChanged);
+        resolve();
+      });
+      content.document.getSelection().selectAllChildren(content.document.body);
+    });
+  });
+
+  var eventDetails = { type: "contextmenu", button: 2 };
+
+  let popupPromise = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
+  BrowserTestUtils.synthesizeMouseAtCenter("body", eventDetails, gBrowser.selectedBrowser);
+  yield popupPromise;
 
-    var selectionListener = {
-      notifySelectionChanged: function(doc, sel, reason) {
-        if (reason != Ci.nsISelectionListener.SELECTALL_REASON || sel.toString() != "test search")
-          return;
-        info("notifySelectionChanged: Text selected");
-        content.window.getSelection().QueryInterface(Ci.nsISelectionPrivate).
-                                      removeSelectionListener(selectionListener);
-        SimpleTest.executeSoon(rightClickOnDocument);
-      }
-    };
+  info("checkContextMenu");
+  var searchItem = contextMenu.getElementsByAttribute("id", "context-searchselect")[0];
+  ok(searchItem, "Got search context menu item");
+  is(searchItem.label, 'Search ' + ENGINE_NAME + ' for "test search"', "Check context menu label");
+  is(searchItem.disabled, false, "Check that search context menu item is enabled");
+
+  yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
+    searchItem.click();
+  });
 
-    // Delay the select all to avoid intermittent selection failures.
-    setTimeout(function delaySelectAll() {
-      info("delaySelectAll: " + content.window.location.toString());
-      // add a listener to know when the selection takes effect
-      content.window.getSelection().QueryInterface(Ci.nsISelectionPrivate).
-                                    addSelectionListener(selectionListener);
-      // select the text on the page
-      goDoCommand('cmd_selectAll');
-    }, 500);
-  }
-}
+  is(gBrowser.currentURI.spec,
+     "http://mochi.test:8888/browser/browser/components/search/test/?test=test+search&ie=utf-8&channel=contextsearch",
+     "Checking context menu search URL");
+
+  contextMenu.hidePopup();
+
+  // Remove the tab opened by the search
+  gBrowser.removeCurrentTab();
+
+  yield new Promise(resolve => {
+    searchDonePromise = resolve;
+    ss.removeEngine(ss.currentEngine);
+  });
+
+  gBrowser.removeCurrentTab();
+});
--- a/browser/components/search/test/browser_eBay_behavior.js
+++ b/browser/components/search/test/browser_eBay_behavior.js
@@ -131,16 +131,19 @@ function test() {
     onStateChange: function onStateChange(webProgress, req, flags, status) {
       info("onStateChange");
       // Only care about top-level document starts
       let docStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
                      Ci.nsIWebProgressListener.STATE_START;
       if (!(flags & docStart) || !webProgress.isTopLevel)
         return;
 
+      if (req.originalURI.spec == "about:blank")
+        return;
+
       info("received document start");
 
       ok(req instanceof Ci.nsIChannel, "req is a channel");
       is(req.originalURI.spec, gCurrTest.searchURL, "search URL was loaded");
       info("Actual URI: " + req.URI.spec);
 
       req.cancel(Components.results.NS_ERROR_FAILURE);
 
--- a/browser/components/search/test/browser_google_behavior.js
+++ b/browser/components/search/test/browser_google_behavior.js
@@ -129,16 +129,19 @@ function test() {
     onStateChange: function onStateChange(webProgress, req, flags, status) {
       info("onStateChange");
       // Only care about top-level document starts
       let docStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
                      Ci.nsIWebProgressListener.STATE_START;
       if (!(flags & docStart) || !webProgress.isTopLevel)
         return;
 
+      if (req.originalURI.spec == "about:blank")
+        return;
+
       info("received document start");
 
       ok(req instanceof Ci.nsIChannel, "req is a channel");
       is(req.originalURI.spec, gCurrTest.searchURL, "search URL was loaded");
       info("Actual URI: " + req.URI.spec);
 
       req.cancel(Components.results.NS_ERROR_FAILURE);
 
--- a/browser/components/search/test/browser_private_search_perwindowpb.js
+++ b/browser/components/search/test/browser_private_search_perwindowpb.js
@@ -1,109 +1,73 @@
 // This test performs a search in a public window, then a different
 // search in a private window, and then checks in the public window
 // whether there is an autocomplete entry for the private search.
 
-function test() {
+add_task(function* () {
   // Don't use about:home as the homepage for new windows
   Services.prefs.setIntPref("browser.startup.page", 0);
   registerCleanupFunction(() => Services.prefs.clearUserPref("browser.startup.page"));
 
-  waitForExplicitFinish();
-
   let engineURL =
     "http://mochi.test:8888/browser/browser/components/search/test/";
   let windowsToClose = [];
-  registerCleanupFunction(function() {
-    let engine = Services.search.getEngineByName("Bug 426329");
-    Services.search.removeEngine(engine);
-    windowsToClose.forEach(function(win) {
-      win.close();
-    });
-  });
 
-  function onPageLoad(aWin, aCallback) {
-    aWin.gBrowser.addEventListener("DOMContentLoaded", function load(aEvent) {
-      let doc = aEvent.originalTarget;
-      info(doc.location.href);
-      if (doc.location.href.indexOf(engineURL) != -1) {
-        aWin.gBrowser.removeEventListener("DOMContentLoaded", load, false);
-        aCallback();
-      }
-    }, false);
-  }
-
-  function performSearch(aWin, aIsPrivate, aCallback) {
+  function performSearch(aWin, aIsPrivate) {
     let searchBar = aWin.BrowserSearch.searchBar;
     ok(searchBar, "got search bar");
-    onPageLoad(aWin, aCallback);
+
+    let loadPromise = BrowserTestUtils.browserLoaded(aWin.gBrowser.selectedBrowser);
 
     searchBar.value = aIsPrivate ? "private test" : "public test";
     searchBar.focus();
     EventUtils.synthesizeKey("VK_RETURN", {}, aWin);
+
+    return loadPromise;
   }
 
-  function addEngine(aCallback) {
-    let installCallback = {
-      onSuccess: function (engine) {
-        Services.search.currentEngine = engine;
-        aCallback();
-      },
-      onError: function (errorCode) {
-        ok(false, "failed to install engine: " + errorCode);
-      }
-    };
-    Services.search.addEngine(engineURL + "426329.xml", null,
-                              "data:image/x-icon,%00", false, installCallback);
+  function* testOnWindow(aIsPrivate) {
+    let win = yield BrowserTestUtils.openNewBrowserWindow({ private: aIsPrivate });
+    yield SimpleTest.promiseFocus(win);
+    windowsToClose.push(win);
+    return win;
   }
 
-  function testOnWindow(aIsPrivate, aCallback) {
-    let win = whenNewWindowLoaded({ private: aIsPrivate }, function() {
-      waitForFocus(aCallback, win);
-    });
-    windowsToClose.push(win);
-  }
+  yield promiseNewEngine("426329.xml", { iconURL: "data:image/x-icon,%00" });
+
+  let newWindow = yield* testOnWindow(false);
+  yield performSearch(newWindow, false);
 
-  addEngine(function() {
-    testOnWindow(false, function(win) {
-      performSearch(win, false, function() {
-        testOnWindow(true, function(win) {
-          performSearch(win, true, function() {
-            testOnWindow(false, function(win) {
-              checkSearchPopup(win, finish);
-            });
-          });
-        });
-      });
-    });
-  });
-}
+  newWindow = yield* testOnWindow(true);
+  yield performSearch(newWindow, true);
 
-function checkSearchPopup(aWin, aCallback) {
-  let searchBar = aWin.BrowserSearch.searchBar;
+  newWindow = yield* testOnWindow(false);
+
+  let searchBar = newWindow.BrowserSearch.searchBar;
   searchBar.value = "p";
   searchBar.focus();
 
   let popup = searchBar.textbox.popup;
-  popup.addEventListener("popupshowing", function showing() {
-    popup.removeEventListener("popupshowing", showing, false);
+  let popupPromise = BrowserTestUtils.waitForEvent(popup, "popupshown");
+  searchBar.textbox.showHistoryPopup();
+  yield popupPromise;
 
-    let entries = getMenuEntries(searchBar);
-    for (let i = 0; i < entries.length; i++) {
-      isnot(entries[i], "private test",
-            "shouldn't see private autocomplete entries");
-    }
+  let entries = getMenuEntries(searchBar);
+  for (let i = 0; i < entries.length; i++) {
+    isnot(entries[i], "private test",
+          "shouldn't see private autocomplete entries");
+  }
 
-    searchBar.textbox.toggleHistoryPopup();
-    searchBar.value = "";
-    aCallback();
-  }, false);
+  searchBar.textbox.toggleHistoryPopup();
+  searchBar.value = "";
 
-  searchBar.textbox.showHistoryPopup();
-}
+  windowsToClose.forEach(function(win) {
+    win.close();
+  });
+});
 
 function getMenuEntries(searchBar) {
   let entries = [];
   let autocompleteMenu = searchBar.textbox.popup;
   // Could perhaps pull values directly from the controller, but it seems
   // more reliable to test the values that are actually in the tree?
   let column = autocompleteMenu.tree.columns[0];
   let numRows = autocompleteMenu.tree.view.rowCount;
--- a/browser/components/search/test/browser_searchbar_keyboard_navigation.js
+++ b/browser/components/search/test/browser_searchbar_keyboard_navigation.js
@@ -376,30 +376,18 @@ add_task(function* test_tab_and_arrows()
 
   // Finally close the panel.
   let promise = promiseEvent(searchPopup, "popuphidden");
   searchPopup.hidePopup();
   yield promise;
 });
 
 add_task(function* test_open_search() {
-  let tab = gBrowser.addTab();
-  gBrowser.selectedTab = tab;
-
-  let deferred = Promise.defer();
-  let browser = gBrowser.selectedBrowser;
-  browser.addEventListener("load", function onload() {
-    browser.removeEventListener("load", onload, true);
-    deferred.resolve();
-  }, true);
-
   let rootDir = getRootDirectory(gTestPath);
-  content.location = rootDir + "opensearch.html";
-
-  yield deferred.promise;
+  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, rootDir + "opensearch.html");
 
   let promise = promiseEvent(searchPopup, "popupshown");
   info("Opening search panel");
   searchbar.focus();
   yield promise;
 
   let engines = getOpenSearchItems();
   is(engines.length, 2, "the opensearch.html page exposes 2 engines")
--- a/browser/components/search/test/browser_searchbar_openpopup.js
+++ b/browser/components/search/test/browser_searchbar_openpopup.js
@@ -408,17 +408,17 @@ add_task(function* refocus_window_doesnt
 // Clicking the search go button shouldn't open the popup
 add_no_popup_task(function* search_go_doesnt_open_popup() {
   gBrowser.selectedTab = gBrowser.addTab();
 
   gURLBar.focus();
   textbox.value = "foo";
   searchbar.updateGoButtonVisibility();
 
-  let promise = promiseOnLoad();
+  let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
   EventUtils.synthesizeMouseAtCenter(goButton, {});
   yield promise;
 
   textbox.value = "";
   gBrowser.removeCurrentTab();
 });
 
 // Clicks outside the search popup should close the popup but not consume the click.
--- a/browser/components/search/test/browser_searchbar_smallpanel_keyboard_navigation.js
+++ b/browser/components/search/test/browser_searchbar_smallpanel_keyboard_navigation.js
@@ -304,30 +304,18 @@ add_task(function* test_tab_and_arrows()
 
   // Finally close the panel.
   let promise = promiseEvent(searchPopup, "popuphidden");
   searchPopup.hidePopup();
   yield promise;
 });
 
 add_task(function* test_open_search() {
-  let tab = gBrowser.addTab();
-  gBrowser.selectedTab = tab;
-
-  let deferred = Promise.defer();
-  let browser = gBrowser.selectedBrowser;
-  browser.addEventListener("load", function onload() {
-    browser.removeEventListener("load", onload, true);
-    deferred.resolve();
-  }, true);
-
   let rootDir = getRootDirectory(gTestPath);
-  content.location = rootDir + "opensearch.html";
-
-  yield deferred.promise;
+  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, rootDir + "opensearch.html");
 
   let promise = promiseEvent(searchPopup, "popupshown");
   info("Opening search panel");
   EventUtils.synthesizeMouseAtCenter(searchIcon, {});
   yield promise;
   is(searchPopup.getAttribute("showonlysettings"), "true", "Should show the small popup");
 
   let engines = getOpenSearchItems();
--- a/browser/components/search/test/browser_yahoo_behavior.js
+++ b/browser/components/search/test/browser_yahoo_behavior.js
@@ -131,16 +131,19 @@ function test() {
     onStateChange: function onStateChange(webProgress, req, flags, status) {
       info("onStateChange");
       // Only care about top-level document starts
       let docStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
                      Ci.nsIWebProgressListener.STATE_START;
       if (!(flags & docStart) || !webProgress.isTopLevel)
         return;
 
+      if (req.originalURI.spec == "about:blank")
+        return;
+
       info("received document start");
 
       ok(req instanceof Ci.nsIChannel, "req is a channel");
       is(req.originalURI.spec, gCurrTest.searchURL, "search URL was loaded");
       info("Actual URI: " + req.URI.spec);
 
       req.cancel(Components.results.NS_ERROR_FAILURE);
 
--- a/browser/components/search/test/head.js
+++ b/browser/components/search/test/head.js
@@ -1,25 +1,11 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-XPCOMUtils.defineLazyModuleGetter(this, "Promise",
-  "resource://gre/modules/Promise.jsm");
-
-function whenNewWindowLoaded(aOptions, aCallback) {
-  let win = OpenBrowserWindow(aOptions);
-  let focused = SimpleTest.promiseFocus(win);
-  let startupFinished = TestUtils.topicObserved("browser-delayed-startup-finished",
-                                                subject => subject == win).then(() => win);
-  Promise.all([focused, startupFinished])
-    .then(results => executeSoon(() => aCallback(results[1])));
-
-  return win;
-}
-
 /**
  * Recursively compare two objects and check that every property of expectedObj has the same value
  * on actualObj.
  */
 function isSubObjectOf(expectedObj, actualObj, name) {
   for (let prop in expectedObj) {
     if (typeof expectedObj[prop] == 'function')
       continue;
@@ -48,87 +34,39 @@ function getLocalizedPref(aPrefName, aDe
     return Services.prefs.getComplexValue(aPrefName, Ci.nsIPrefLocalizedString).data;
   } catch (ex) {
     return aDefault;
   }
 
   return aDefault;
 }
 
-function waitForPopupShown(aPopupId, aCallback) {
-  let popup = document.getElementById(aPopupId);
-  info("waitForPopupShown: got popup: " + popup.id);
-  function onPopupShown() {
-    info("onPopupShown");
-    removePopupShownListener();
-    SimpleTest.executeSoon(aCallback);
-  }
-  function removePopupShownListener() {
-    popup.removeEventListener("popupshown", onPopupShown);
-  }
-  popup.addEventListener("popupshown", onPopupShown);
-  registerCleanupFunction(removePopupShownListener);
-}
-
 function promiseEvent(aTarget, aEventName, aPreventDefault) {
-  let deferred = Promise.defer();
-  aTarget.addEventListener(aEventName, function onEvent(aEvent) {
-    aTarget.removeEventListener(aEventName, onEvent, true);
+  function cancelEvent(event) {
     if (aPreventDefault) {
-      aEvent.preventDefault();
+      event.preventDefault();
     }
-    deferred.resolve();
-  }, true);
-  return deferred.promise;
-}
 
-function waitForBrowserContextMenu(aCallback) {
-  waitForPopupShown(gBrowser.selectedBrowser.contextMenu, aCallback);
-}
-
-function doOnloadOnce(aCallback) {
-  function doOnloadOnceListener(aEvent) {
-    info("doOnloadOnce: " + aEvent.originalTarget.location);
-    removeDoOnloadOnceListener();
-    SimpleTest.executeSoon(function doOnloadOnceCallback() {
-      aCallback(aEvent);
-    });
-  }
-  function removeDoOnloadOnceListener() {
-    gBrowser.removeEventListener("load", doOnloadOnceListener, true);
+    return true;
   }
-  gBrowser.addEventListener("load", doOnloadOnceListener, true);
-  registerCleanupFunction(removeDoOnloadOnceListener);
-}
 
-function* promiseOnLoad() {
-  return new Promise(resolve => {
-    gBrowser.addEventListener("load", function onLoadListener(aEvent) {
-      let cw = aEvent.target.defaultView;
-      let tab = gBrowser._getTabForContentWindow(cw);
-      if (tab) {
-        info("onLoadListener: " + aEvent.originalTarget.location);
-        gBrowser.removeEventListener("load", onLoadListener, true);
-        resolve(aEvent);
-      }
-    }, true);
-  });
+  return BrowserTestUtils.waitForEvent(aTarget, aEventName, false, cancelEvent);
 }
 
 function promiseNewEngine(basename, options = {}) {
   return new Promise((resolve, reject) => {
     //Default the setAsCurrent option to true.
     let setAsCurrent =
       options.setAsCurrent == undefined ? true : options.setAsCurrent;
     info("Waiting for engine to be added: " + basename);
     Services.search.init({
       onInitComplete: function() {
         let url = getRootDirectory(gTestPath) + basename;
         let current = Services.search.currentEngine;
-        Services.search.addEngine(url, null, "", false, {
+        Services.search.addEngine(url, null, options.iconURL || "", false, {
           onSuccess: function (engine) {
             info("Search engine added: " + basename);
             if (setAsCurrent) {
               Services.search.currentEngine = engine;
             }
             registerCleanupFunction(() => {
               if (setAsCurrent) {
                 Services.search.currentEngine = current;
--- a/browser/modules/DirectoryLinksProvider.jsm
+++ b/browser/modules/DirectoryLinksProvider.jsm
@@ -91,19 +91,16 @@ const DEFAULT_TOTAL_FREQUENCY_CAP = 10;
 const DEFAULT_PRUNE_TIME_DELTA = 10*24*60*60*1000;
 
 // The min number of visible (not blocked) history tiles to have before showing suggested tiles
 const MIN_VISIBLE_HISTORY_TILES = 8;
 
 // The max number of visible (not blocked) history tiles to test for inadjacency
 const MAX_VISIBLE_HISTORY_TILES = 15;
 
-// Divide frecency by this amount for pings
-const PING_SCORE_DIVISOR = 10000;
-
 // Allowed ping actions remotely stored as columns: case-insensitive [a-z0-9_]
 const PING_ACTIONS = ["block", "click", "pin", "sponsored", "sponsored_link", "unpin", "view"];
 
 // Location of inadjacent sites json
 const INADJACENCY_SOURCE = "chrome://browser/content/newtab/newTab.inadjacent.json";
 
 // Fake URL to keep track of last block of a suggested tile in the frequency cap object
 const FAKE_SUGGESTED_BLOCK_URL = "ignore://suggested_block";
@@ -561,60 +558,23 @@ var DirectoryLinksProvider = {
     let newtabEnhanced = false;
     let pingEndPoint = "";
     try {
       newtabEnhanced = Services.prefs.getBoolPref(PREF_NEWTAB_ENHANCED);
       pingEndPoint = Services.prefs.getCharPref(PREF_DIRECTORY_PING);
     }
     catch (ex) {}
 
-    // Only send pings when enhancing tiles with an endpoint and valid action
+    // Bug 1240245 - We no longer send pings, but frequency capping and fetching
+    // tests depend on the following actions, so references to PING remain.
     let invalidAction = PING_ACTIONS.indexOf(action) == -1;
     if (!newtabEnhanced || pingEndPoint == "" || invalidAction) {
       return Promise.resolve();
     }
 
-    let actionIndex;
-    let data = {
-      locale: this.locale,
-      tiles: sites.reduce((tiles, site, pos) => {
-        // Only add data for non-empty tiles
-        if (site) {
-          // Remember which tiles data triggered the action
-          let {link} = site;
-          let tilesIndex = tiles.length;
-          if (triggeringSiteIndex == pos) {
-            actionIndex = tilesIndex;
-          }
-
-          // Make the payload in a way so keys can be excluded when stringified
-          let id = link.directoryId;
-          tiles.push({
-            id: id || site.enhancedId,
-            pin: site.isPinned() ? 1 : undefined,
-            pos: pos != tilesIndex ? pos : undefined,
-            past_impressions: pos == triggeringSiteIndex ? pastImpressions : undefined,
-            score: Math.round(link.frecency / PING_SCORE_DIVISOR) || undefined,
-            url: site.enhancedId && "",
-          });
-        }
-        return tiles;
-      }, []),
-    };
-
-    // Provide a direct index to the tile triggering the action
-    if (actionIndex !== undefined) {
-      data[action] = actionIndex;
-    }
-
-    // Package the data to be sent with the ping
-    let ping = this._newXHR();
-    ping.open("POST", pingEndPoint + (action == "view" ? "view" : "click"));
-    ping.send(JSON.stringify(data));
-
     return Task.spawn(function* () {
       // since we updated views/clicks we need write _frequencyCaps to disk
       yield this._writeFrequencyCapFile();
       // Use this as an opportunity to potentially fetch new links
       yield this._fetchAndCacheLinksIfNecessary();
     }.bind(this));
   },
 
--- a/browser/modules/WindowsPreviewPerTab.jsm
+++ b/browser/modules/WindowsPreviewPerTab.jsm
@@ -366,18 +366,16 @@ XPCOMUtils.defineLazyGetter(PreviewContr
  *
  * @param win
  *        The nsIDOMWindow browser window
  */
 function TabWindow(win) {
   this.win = win;
   this.tabbrowser = win.gBrowser;
 
-  this.cacheDims();
-
   this.previews = new Map();
 
   for (let i = 0; i < this.tabEvents.length; i++)
     this.tabbrowser.tabContainer.addEventListener(this.tabEvents[i], this, false);
 
   for (let i = 0; i < this.winEvents.length; i++)
     this.win.addEventListener(this.winEvents[i], this, false);
 
@@ -389,28 +387,30 @@ function TabWindow(win) {
     this.newTab(tabs[i]);
 
   this.updateTabOrdering();
   AeroPeek.checkPreviewCount();
 }
 
 TabWindow.prototype = {
   _enabled: false,
+  _cachedWidth: 0,
+  _cachedHeight: 0,
   tabEvents: ["TabOpen", "TabClose", "TabSelect", "TabMove"],
   winEvents: ["resize"],
 
   destroy: function () {
     this._destroying = true;
 
     let tabs = this.tabbrowser.tabs;
 
     this.tabbrowser.removeTabsProgressListener(this);
 
-  for (let i = 0; i < this.winEvents.length; i++)
-    this.win.removeEventListener(this.winEvents[i], this, false);
+    for (let i = 0; i < this.winEvents.length; i++)
+      this.win.removeEventListener(this.winEvents[i], this, false);
 
     for (let i = 0; i < this.tabEvents.length; i++)
       this.tabbrowser.tabContainer.removeEventListener(this.tabEvents[i], this, false);
 
     for (let i = 0; i < tabs.length; i++)
       this.removeTab(tabs[i]);
 
     let idx = AeroPeek.windows.indexOf(this.win.gTaskbarTabGroup);
--- a/browser/modules/test/xpcshell/test_DirectoryLinksProvider.js
+++ b/browser/modules/test/xpcshell/test_DirectoryLinksProvider.js
@@ -711,123 +711,16 @@ add_task(function* test_frequencyCappedS
   // Cleanup.
   NewTabUtils.isTopPlacesSite = origIsTopPlacesSite;
   DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount;
   gLinks.removeProvider(DirectoryLinksProvider);
   DirectoryLinksProvider.removeObserver(gLinks);
   Services.prefs.setCharPref(kPingUrlPref, kPingUrl);
 });
 
-add_task(function* test_reportSitesAction() {
-  yield DirectoryLinksProvider.init();
-  let deferred, expectedPath, expectedPost;
-  let done = false;
-  server.registerPrefixHandler(kPingPath, (aRequest, aResponse) => {
-    if (done) {
-      return;
-    }
-
-    do_check_eq(aRequest.path, expectedPath);
-
-    let bodyStream = new BinaryInputStream(aRequest.bodyInputStream);
-    let bodyObject = JSON.parse(NetUtil.readInputStreamToString(bodyStream, bodyStream.available()));
-    isIdentical(bodyObject, expectedPost);
-
-    deferred.resolve();
-  });
-
-  function sendPingAndTest(path, action, index) {
-    deferred = Promise.defer();
-    expectedPath = kPingPath + path;
-    DirectoryLinksProvider.reportSitesAction(sites, action, index);
-    return deferred.promise;
-  }
-
-  // Start with a single pinned link at position 3
-  let sites = [,,{
-    isPinned: _ => true,
-    link: {
-      directoryId: 1,
-      frecency: 30000,
-      url: "http://directory1/",
-    },
-  }];
-
-  // Make sure we get the click ping for the directory link with fields we want
-  // and unwanted fields removed by stringify/parse
-  expectedPost = JSON.parse(JSON.stringify({
-    click: 0,
-    locale: "en-US",
-    tiles: [{
-      id: 1,
-      pin: 1,
-      pos: 2,
-      score: 3,
-      url: undefined,
-    }],
-  }));
-  yield sendPingAndTest("click", "click", 2);
-
-  // Try a pin click ping
-  delete expectedPost.click;
-  expectedPost.pin = 0;
-  yield sendPingAndTest("click", "pin", 2);
-
-  // Try a block click ping
-  delete expectedPost.pin;
-  expectedPost.block = 0;
-  yield sendPingAndTest("click", "block", 2);
-
-  // A view ping has no actions
-  delete expectedPost.block;
-  expectedPost.view = 0;
-  yield sendPingAndTest("view", "view", 2);
-
-  // Remove the identifier that makes it a directory link so just plain history
-  delete sites[2].link.directoryId;
-  delete expectedPost.tiles[0].id;
-  yield sendPingAndTest("view", "view", 2);
-
-  // Add directory link at position 0
-  sites[0] = {
-    isPinned: _ => false,
-    link: {
-      directoryId: 1234,
-      frecency: 1000,
-      url: "http://directory/",
-    }
-  };
-  expectedPost.tiles.unshift(JSON.parse(JSON.stringify({
-    id: 1234,
-    pin: undefined,
-    pos: undefined,
-    score: undefined,
-    url: undefined,
-  })));
-  expectedPost.view = 1;
-  yield sendPingAndTest("view", "view", 2);
-
-  // Make the history tile enhanced so it reports both id and url
-  sites[2].enhancedId = "id from enhanced";
-  expectedPost.tiles[1].id = "id from enhanced";
-  expectedPost.tiles[1].url = "";
-  yield sendPingAndTest("view", "view", 2);
-
-  // Click the 0th site / 0th tile
-  delete expectedPost.view;
-  expectedPost.click = 0;
-  yield sendPingAndTest("click", "click", 0);
-
-  // Click the 2th site / 1th tile
-  expectedPost.click = 1;
-  yield sendPingAndTest("click", "click", 2);
-
-  done = true;
-});
-
 add_task(function* test_fetchAndCacheLinks_local() {
   yield DirectoryLinksProvider.init();
   yield cleanJsonFile();
   // Trigger cache of data or chrome uri files in profD
   yield DirectoryLinksProvider._fetchAndCacheLinks(kTestURL);
   let data = yield readJsonFile();
   isIdentical(data, kURLData);
 });
@@ -1896,120 +1789,16 @@ add_task(function* test_inadjecentSites(
   gLinks.removeProvider(DirectoryLinksProvider);
   DirectoryLinksProvider._inadjacentSitesUrl = origInadjacentSitesUrl;
   NewTabUtils.isTopPlacesSite = origIsTopPlacesSite;
   NewTabUtils.getProviderLinks = origGetProviderLinks;
   DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount;
   yield promiseCleanDirectoryLinksProvider();
 });
 
-add_task(function* test_reportPastImpressions() {
-  let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite;
-  NewTabUtils.isTopPlacesSite = () => true;
-  let origCurrentTopSiteCount = DirectoryLinksProvider._getCurrentTopSiteCount;
-  DirectoryLinksProvider._getCurrentTopSiteCount = () => 8;
-
-  let testUrl = "http://frequency.capped/link";
-  let targets = ["top.site.com"];
-  let data = {
-    suggested: [{
-      type: "affiliate",
-      frecent_sites: targets,
-      url: testUrl,
-      adgroup_name: "Test"
-    }]
-  };
-  let dataURI = "data:application/json," + JSON.stringify(data);
-  yield promiseSetupDirectoryLinksProvider({linksURL: dataURI});
-
-  // make DirectoryLinksProvider load json
-  let loadPromise = Promise.defer();
-  DirectoryLinksProvider.getLinks(_ => {loadPromise.resolve();});
-  yield loadPromise.promise;
-
-  // setup ping handler
-  let deferred, expectedPath, expectedAction, expectedImpressions;
-  let done = false;
-  server.registerPrefixHandler(kPingPath, (aRequest, aResponse) => {
-    if (done) {
-      return;
-    }
-
-    do_check_eq(aRequest.path, expectedPath);
-
-    let bodyStream = new BinaryInputStream(aRequest.bodyInputStream);
-    let bodyObject = JSON.parse(NetUtil.readInputStreamToString(bodyStream, bodyStream.available()));
-    let expectedActionIndex = bodyObject[expectedAction];
-    if (bodyObject.unpin) {
-      // unpin should not report past_impressions
-      do_check_false(bodyObject.tiles[expectedActionIndex].hasOwnProperty("past_impressions"));
-    }
-    else if (expectedImpressions) {
-      do_check_eq(bodyObject.tiles[expectedActionIndex].past_impressions.total, expectedImpressions);
-      do_check_eq(bodyObject.tiles[expectedActionIndex].past_impressions.daily, expectedImpressions);
-    }
-    else {
-      do_check_eq(expectedPath, "/ping/view");
-      do_check_false(bodyObject.tiles[expectedActionIndex].hasOwnProperty("past_impressions"));
-    }
-
-    deferred.resolve();
-  });
-
-  // setup ping sender
-  function sendPingAndTest(path, action, index) {
-    deferred = Promise.defer();
-    expectedPath = kPingPath + path;
-    expectedAction = action;
-    DirectoryLinksProvider.reportSitesAction(sites, action, index);
-    return deferred.promise;
-  }
-
-  // Start with a view ping first
-  let site = {
-    isPinned: _ => false,
-    link: {
-      directoryId: 1,
-      frecency: 30000,
-      frecent_sites: targets,
-      targetedSite: targets[0],
-      url: testUrl
-    }
-  };
-  let sites = [,
-    {
-      isPinned: _ => false,
-      link: {type: "history", url: "https://foo.com"}
-    },
-    site
-  ];
-
-  yield sendPingAndTest("view", "view", 2);
-  yield sendPingAndTest("view", "view", 2);
-  yield sendPingAndTest("view", "view", 2);
-
-  expectedImpressions = DirectoryLinksProvider._frequencyCaps[testUrl].totalViews;
-  do_check_eq(expectedImpressions, 3);
-
-  // now report pin, unpin, block and click
-  sites.isPinned = _ => true;
-  yield sendPingAndTest("click", "pin", 2);
-  sites.isPinned = _ => false;
-  yield sendPingAndTest("click", "unpin", 2);
-  sites.isPinned = _ => false;
-  yield sendPingAndTest("click", "click", 2);
-  sites.isPinned = _ => false;
-  yield sendPingAndTest("click", "block", 2);
-
-  // Cleanup.
-  done = true;
-  NewTabUtils.isTopPlacesSite = origIsTopPlacesSite;
-  DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount;
-});
-
 add_task(function* test_blockSuggestedTiles() {
   // Initial setup
   let suggestedTile = suggestedTile1;
   let topSites = ["site0.com", "1040.com", "site2.com", "hrblock.com", "site4.com", "freetaxusa.com", "site6.com"];
   let data = {"suggested": [suggestedTile1, suggestedTile2, suggestedTile3], "directory": [someOtherSite]};
   let dataURI = 'data:application/json,' + JSON.stringify(data);
 
   yield promiseSetupDirectoryLinksProvider({linksURL: dataURI});
--- a/build/autoconf/config.status.m4
+++ b/build/autoconf/config.status.m4
@@ -226,14 +226,14 @@ define([AC_CONFIG_HEADER],
 [m4_fatal([Use CONFIGURE_DEFINE_FILES in moz.build files to produce header files.])
 ])
 
 define([MOZ_BUILD_BACKEND],
 [
 BUILD_BACKENDS="RecursiveMake"
 
 MOZ_ARG_ENABLE_STRING(build-backend,
-[  --enable-build-backend={AndroidEclipse,CppEclipse,VisualStudio,FasterMake,CompileDB,ChromeMap}
+[  --enable-build-backend={$($(dirname ]$[0)/$1/mach python -c "from mozbuild.backend import backends; print ','.join(sorted(backends))")}
                          Enable additional build backends],
 [ BUILD_BACKENDS="RecursiveMake `echo $enableval | sed 's/,/ /g'`"])
 
 AC_SUBST_SET([BUILD_BACKENDS])
 ])
--- a/build/unix/elfhack/elf.cpp
+++ b/build/unix/elfhack/elf.cpp
@@ -253,26 +253,29 @@ Elf::Elf(std::ifstream &file)
         }
         if (phdr.p_type == PT_PHDR)
             segment->addSection(phdr_section);
         for (int j = 1; j < ehdr->e_shnum; j++)
             if (phdr.contains(sections[j]))
                 segment->addSection(sections[j]);
         // Make sure that our view of segments corresponds to the original
         // ELF file.
-        assert(segment->getFileSize() == phdr.p_filesz);
+        // GNU gold likes to start some segments before the first section
+        // they contain. https://sourceware.org/bugzilla/show_bug.cgi?id=19392
+        unsigned int gold_adjustment = segment->getAddr() - phdr.p_vaddr;
+        assert(segment->getFileSize() == phdr.p_filesz - gold_adjustment);
         // gold makes TLS segments end on an aligned virtual address, even
         // when the underlying section ends before that, while bfd ld
         // doesn't. It's fine if we don't keep that alignment.
         unsigned int memsize = segment->getMemSize();
         if (phdr.p_type == PT_TLS && memsize != phdr.p_memsz) {
             unsigned int align = segment->getAlign();
             memsize = (memsize + align - 1) & ~(align - 1);
         }
-        assert(memsize == phdr.p_memsz);
+        assert(memsize == phdr.p_memsz - gold_adjustment);
         segments.push_back(segment);
     }
 
     new (&eh_entry) ElfLocation(ehdr->e_entry, this);
 }
 
 Elf::~Elf()
 {
--- a/config/external/nss/nss.symbols
+++ b/config/external/nss/nss.symbols
@@ -687,11 +687,16 @@ VFY_DestroyContext
 VFY_End
 VFY_EndWithSignature
 VFY_Update
 VFY_VerifyData
 VFY_VerifyDataWithAlgorithmID
 VFY_VerifyDigestDirect
 _SGN_VerifyPKCS1DigestInfo
 __PK11_SetCertificateNickname
+# These symbols are not used by Firefox itself, but are used by Java's security
+# libraries, which in turn are used by Java applets/plugins/etc.  Provide them
+# to make Java code happy.
+NSS_VersionCheck
+NSS_Initialize
 #ifdef NSS_EXTRA_SYMBOLS_FILE
 #include @NSS_EXTRA_SYMBOLS_FILE@
 #endif
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -1576,12 +1576,8 @@ default all:: $(PURGECACHES_FILES)
 
 #############################################################################
 # Derived targets and dependencies
 
 include $(MOZILLA_DIR)/config/makefiles/autotargets.mk
 ifneq ($(NULL),$(AUTO_DEPS))
   default all libs tools export:: $(AUTO_DEPS)
 endif
-
-export:: $(GENERATED_FILES)
-
-GARBAGE += $(GENERATED_FILES)
--- a/configure.in
+++ b/configure.in
@@ -134,17 +134,17 @@ EOF
   exit 1
   break
 fi
 MOZ_BUILD_ROOT=`pwd -W 2>/dev/null || pwd -P`
 DIST="$MOZ_BUILD_ROOT/dist"
 
 MOZ_PYTHON
 
-MOZ_BUILD_BACKEND
+MOZ_BUILD_BACKEND(.)
 
 MOZ_DEFAULT_COMPILER
 
 COMPILE_ENVIRONMENT=1
 MOZ_ARG_DISABLE_BOOL(compile-environment,
 [  --disable-compile-environment
                           Disable compiler/library checks.],
     COMPILE_ENVIRONMENT= )
@@ -2283,16 +2283,21 @@ ia64*-hpux*)
             # tree.  clang-cl doesn't support -fno-exceptions or equivalent,
             # so there doesn't seem to be any way to convince clang-cl to
             # declare |delete| differently.  Therefore, suppress this
             # warning.
             CXXFLAGS="$CXXFLAGS -Wno-implicit-exception-spec-mismatch"
             # At least one MSVC header and several headers in-tree have
             # unused typedefs, so turn this on.
             CXXFLAGS="$CXXFLAGS -Wno-unused-local-typedef"
+            # Several JS engine header files use __declspec(dllimport) on
+            # classes, and clang-cl helpfully warns about its non-support
+            # for such cases.  We're not particularly worried about that,
+            # so ignore that warning.
+            CXXFLAGS="$CXXFLAGS -Wno-ignored-attributes"
         fi
         # make 'foo == bar;' error out
         CFLAGS="$CFLAGS -we4553"
         CXXFLAGS="$CXXFLAGS -we4553"
         LIBS="$LIBS kernel32.lib user32.lib gdi32.lib winmm.lib wsock32.lib advapi32.lib secur32.lib netapi32.lib"
         MOZ_DEBUG_LDFLAGS='-DEBUG -DEBUGTYPE:CV'
         WARNINGS_AS_ERRORS='-WX'
         MOZ_OPTIMIZE_FLAGS='-O1 -Oi'
--- a/devtools/client/shared/browser-loader.js
+++ b/devtools/client/shared/browser-loader.js
@@ -65,16 +65,19 @@ function BrowserLoader(baseURI, window) 
 
       if (!uri.startsWith(baseURI) && !isBrowserDir) {
         return devtools.require(uri);
       }
 
       return require(uri);
     },
     globals: {
+      // Allow modules to use the window's console to ensure logs appear in a
+      // tab toolbox, if one exists, instead of just the browser console.
+      console: window.console,
       // Make sure 'define' function exists. This allows reusing AMD modules.
       define: function(callback) {
         callback(this.require, this.exports, this.module);
         return this.exports;
       }
     }
   };
 
--- a/devtools/shared/heapsnapshot/tests/gtest/DoesCrossZoneBoundaries.cpp
+++ b/devtools/shared/heapsnapshot/tests/gtest/DoesCrossZoneBoundaries.cpp
@@ -4,20 +4,22 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Test that heap snapshots cross zone boundaries when expected.
 
 #include "DevTools.h"
 
 DEF_TEST(DoesCrossZoneBoundaries, {
     // Create a new global to get a new zone.
+    JS::CompartmentOptions options;
     JS::RootedObject newGlobal(cx, JS_NewGlobalObject(cx,
                                                       getGlobalClass(),
                                                       nullptr,
-                                                      JS::FireOnNewGlobalHook));
+                                                      JS::FireOnNewGlobalHook,
+                                                      options));
     ASSERT_TRUE(newGlobal);
     JS::Zone* newZone = nullptr;
     {
       JSAutoCompartment ac(cx, newGlobal);
       ASSERT_TRUE(JS_InitStandardClasses(cx, newGlobal));
       newZone = js::GetContextZone(cx);
     }
     ASSERT_TRUE(newZone);
--- a/devtools/shared/heapsnapshot/tests/gtest/DoesntCrossZoneBoundaries.cpp
+++ b/devtools/shared/heapsnapshot/tests/gtest/DoesntCrossZoneBoundaries.cpp
@@ -4,20 +4,22 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Test that heap snapshots walk the zone boundaries correctly.
 
 #include "DevTools.h"
 
 DEF_TEST(DoesntCrossZoneBoundaries, {
     // Create a new global to get a new zone.
+    JS::CompartmentOptions options;
     JS::RootedObject newGlobal(cx, JS_NewGlobalObject(cx,
                                                       getGlobalClass(),
                                                       nullptr,
-                                                      JS::FireOnNewGlobalHook));
+                                                      JS::FireOnNewGlobalHook,
+                                                      options));
     ASSERT_TRUE(newGlobal);
     JS::Zone* newZone = nullptr;
     {
       JSAutoCompartment ac(cx, newGlobal);
       ASSERT_TRUE(JS_InitStandardClasses(cx, newGlobal));
       newZone = js::GetContextZone(cx);
     }
     ASSERT_TRUE(newZone);
--- a/dom/animation/EffectCompositor.cpp
+++ b/dom/animation/EffectCompositor.cpp
@@ -138,19 +138,20 @@ EffectCompositor::RequestRestyle(dom::El
   if (!mPresContext) {
     // Pres context will be null after the effect compositor is disconnected.
     return;
   }
 
   auto& elementsToRestyle = mElementsToRestyle[aCascadeLevel];
   PseudoElementHashKey key = { aElement, aPseudoType };
 
-  if (aRestyleType == RestyleType::Throttled &&
-      !elementsToRestyle.Contains(key)) {
-    elementsToRestyle.Put(key, false);
+  if (aRestyleType == RestyleType::Throttled) {
+    if (!elementsToRestyle.Contains(key)) {
+      elementsToRestyle.Put(key, false);
+    }
     mPresContext->Document()->SetNeedStyleFlush();
   } else {
     // Get() returns 0 if the element is not found. It will also return
     // false if the element is found but does not have a pending restyle.
     bool hasPendingRestyle = elementsToRestyle.Get(key);
     if (!hasPendingRestyle) {
       PostRestyleForAnimation(aElement, aPseudoType, aCascadeLevel);
     }
--- a/dom/animation/test/chrome.ini
+++ b/dom/animation/test/chrome.ini
@@ -1,8 +1,9 @@
 [DEFAULT]
 support-files =
   testcommon.js
   ../../imptests/testharness.js
   ../../imptests/testharnessreport.js
 [chrome/test_animation_observers.html]
+[chrome/test_restyles.html]
 [chrome/test_running_on_compositor.html]
 skip-if = buildapp == 'b2g'
new file mode 100644
--- /dev/null
+++ b/dom/animation/test/chrome/test_restyles.html
@@ -0,0 +1,328 @@
+<!doctype html>
+<head>
+<meta charset=utf-8>
+<title>Tests restyles caused by animations</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+<script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
+<script src="chrome://mochikit/content/tests/SimpleTest/paint_listener.js"></script>
+<script src="../testcommon.js"></script>
+<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+<style>
+@keyframes opacity {
+  from { opacity: 1; }
+  to { opacity: 0; }
+}
+@keyframes background-color {
+  from { background-color: red; }
+  to { background-color: blue; }
+}
+@keyframes rotate {
+  from { transform: rotate(0deg); }
+  to { transform: rotate(360deg); }
+}
+div {
+  /* Element needs geometry to be eligible for layerization */
+  width: 100px;
+  height: 100px;
+  background-color: white;
+}
+</style>
+</head>
+<body>
+<script>
+'use strict';
+
+function observeStyling(frameCount, onFrame) {
+  var docShell = window.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
+                       .getInterface(SpecialPowers.Ci.nsIWebNavigation)
+                       .QueryInterface(SpecialPowers.Ci.nsIDocShell);
+
+  docShell.recordProfileTimelineMarkers = true;
+  docShell.popProfileTimelineMarkers();
+
+  return new Promise(function(resolve) {
+    return waitForAnimationFrames(frameCount, onFrame).then(function() {
+      var markers = docShell.popProfileTimelineMarkers();
+      docShell.recordProfileTimelineMarkers = false;
+      var stylingMarkers = markers.filter(function(marker, index) {
+        return marker.name == 'Styles';
+      });
+      resolve(stylingMarkers);
+    });
+  });
+}
+
+SimpleTest.waitForExplicitFinish();
+
+const OMTAPrefKey = 'layers.offmainthreadcomposition.async-animations';
+var omtaEnabled = SpecialPowers.DOMWindowUtils.layerManagerRemote &&
+                  SpecialPowers.getBoolPref(OMTAPrefKey);
+
+function add_task_if_omta_enabled(test) {
+  if (!omtaEnabled) {
+    info(test.name + " is skipped because OMTA is disabled");
+    return;
+  }
+  add_task(test);
+}
+
+// We need to wait for all paints before running tests to avoid contaminations
+// from styling of this document itself.
+waitForAllPaints(function() {
+  add_task_if_omta_enabled(function* no_restyling_for_compositor_animations() {
+    var div = addDiv(null, { style: 'animation: opacity 100s' });
+    var animation = div.getAnimations()[0];
+
+    yield animation.ready;
+    ok(animation.isRunningOnCompositor);
+
+    var markers = yield observeStyling(5);
+    is(markers.length, 0,
+       'CSS animations running on the compositor should not update style ' +
+       'on the main thread');
+    div.remove(div);
+  });
+
+  add_task_if_omta_enabled(function* no_restyling_for_compositor_transitions() {
+    var div = addDiv(null, { style: 'transition: opacity 100s; opacity: 0' });
+    getComputedStyle(div).opacity;
+    div.style.opacity = 1;
+
+    var animation = div.getAnimations()[0];
+
+    yield animation.ready;
+    ok(animation.isRunningOnCompositor);
+
+    var markers = yield observeStyling(5);
+    is(markers.length, 0,
+       'CSS transitions running on the compositor should not update style ' +
+       'on the main thread');
+    div.remove(div);
+  });
+
+  add_task_if_omta_enabled(function* no_restyling_when_animation_duration_is_changed() {
+    var div = addDiv(null, { style: 'animation: opacity 100s' });
+    var animation = div.getAnimations()[0];
+
+    yield animation.ready;
+    ok(animation.isRunningOnCompositor);
+
+    div.animationDuration = '200s';
+
+    var markers = yield observeStyling(5);
+    is(markers.length, 0,
+       'Animations running on the compositor should not update style ' +
+       'on the main thread');
+    div.remove(div);
+  });
+
+  add_task_if_omta_enabled(function* only_one_restyling_after_finish_is_called() {
+    var div = addDiv(null, { style: 'animation: opacity 100s' });
+    var animation = div.getAnimations()[0];
+
+    yield animation.ready;
+    ok(animation.isRunningOnCompositor);
+
+    animation.finish();
+
+    var markers = yield observeStyling(5);
+    is(markers.length, 1,
+       'Animations running on the compositor should only update style ' +
+       'once after finish() is called');
+    div.remove(div);
+  });
+
+  add_task(function* no_restyling_mouse_movement_on_finished_transition() {
+    var div = addDiv(null, { style: 'transition: opacity 1ms; opacity: 0' });
+    getComputedStyle(div).opacity;
+    div.style.opacity = 1;
+
+    var animation = div.getAnimations()[0];
+    var initialRect = div.getBoundingClientRect();
+
+    yield animation.finished;
+
+    var mouseX = initialRect.left + initialRect.width / 2;
+    var mouseY = initialRect.top + initialRect.height / 2;
+    var markers = yield observeStyling(5, function() {
+      // We can't use synthesizeMouse here since synthesizeMouse causes
+      // layout flush.
+      synthesizeMouseAtPoint(mouseX++, mouseY++,
+                             { type: 'mousemove' }, window);
+    });
+
+    is(markers.length, 0,
+       'Bug 1219236: Finished transitions should never cause restyles ' +
+       'when mouse is moved on the animations');
+    div.remove(div);
+  });
+
+  add_task(function* no_restyling_mouse_movement_on_finished_animation() {
+    var div = addDiv(null, { style: 'animation: opacity 1ms' });
+    var animation = div.getAnimations()[0];
+
+    var initialRect = div.getBoundingClientRect();
+
+    yield animation.finished;
+
+    var mouseX = initialRect.left + initialRect.width / 2;
+    var mouseY = initialRect.top + initialRect.height / 2;
+    var markers = yield observeStyling(5, function() {
+      // We can't use synthesizeMouse here since synthesizeMouse causes
+      // layout flush.
+      synthesizeMouseAtPoint(mouseX++, mouseY++,
+                             { type: 'mousemove' }, window);
+    });
+
+    is(markers.length, 0,
+       'Bug 1219236: Finished animations should never cause restyles ' +
+       'when mouse is moved on the animations');
+    div.remove(div);
+  });
+
+  add_task_if_omta_enabled(function* no_restyling_compositor_animations_out_of_view_element() {
+    var div = addDiv(null,
+      { style: 'animation: opacity 100s; transform: translateY(-400px);' });
+    var animation = div.getAnimations()[0];
+
+    yield animation.ready;
+    ok(!animation.isRunningOnCompositor);
+
+    var markers = yield observeStyling(5);
+
+    todo_is(markers.length, 0,
+            'Bug 1166500: Animations running on the compositor in out of ' +
+            'view element should never cause restyles');
+    div.remove(div);
+  });
+
+  add_task(function* no_restyling_main_thread_animations_out_of_view_element() {
+    var div = addDiv(null,
+      { style: 'animation: background-color 100s; transform: translateY(-400px);' });
+    var animation = div.getAnimations()[0];
+
+    yield animation.ready;
+    var markers = yield observeStyling(5);
+
+    todo_is(markers.length, 0,
+            'Bug 1166500: Animations running on the main-thread in out of ' +
+            'view element should never cause restyles');
+    div.remove(div);
+  });
+
+  /*
+   Disabled for now since, on Android, the opacity animation runs on the
+   compositor even if it is scrolled out of view.
+   We will fix this in bug 1166500 or a follow-up bug
+  add_task_if_omta_enabled(function* no_restyling_compositor_animations_in_scrolled_out_element() {
+    var parentElement = addDiv(null,
+      { style: 'overflow-y: scroll; height: 20px;' });
+    var div = addDiv(null,
+      { style: 'animation: opacity 100s; position: relative; top: 100px;' });
+    parentElement.appendChild(div);
+    var animation = div.getAnimations()[0];
+
+    yield animation.ready;
+    ok(!animation.isRunningOnCompositor);
+
+    var markers = yield observeStyling(5);
+
+    todo_is(markers.length, 0,
+            'Bug 1166500: Animations running on the compositor in elements ' +
+            'which are scrolled out should never cause restyles');
+    parentElement.remove(div);
+  });
+  */
+
+  add_task(function* no_restyling_main_thread_animations_in_scrolled_out_element() {
+    var parentElement = addDiv(null,
+      { style: 'overflow-y: scroll; height: 20px;' });
+    var div = addDiv(null,
+      { style: 'animation: background-color 100s; position: relative; top: 100px;' });
+    parentElement.appendChild(div);
+    var animation = div.getAnimations()[0];
+
+    yield animation.ready;
+    var markers = yield observeStyling(5);
+
+    todo_is(markers.length, 0,
+            'Bug 1166500: Animations running on the main-thread in elements ' +
+            'which are scrolled out should never cause restyles');
+    parentElement.remove(div);
+  });
+
+  /*
+   Disabled for now since, on Android and B2G, the opacity animation runs on the
+   compositor even if the associated element has visibility:hidden.
+   We will fix this in bug 1237454 or a follow-up bug.
+  add_task_if_omta_enabled(function* no_restyling_compositor_animations_in_visiblily_hidden_element() {
+    var div = addDiv(null,
+     { style: 'animation: opacity 100s; visibility: hidden' });
+    var animation = div.getAnimations()[0];
+
+    yield animation.ready;
+    ok(!animation.isRunningOnCompositor);
+
+    var markers = yield observeStyling(5);
+
+    todo_is(markers.length, 0,
+            'Bug 1237454: Animations running on the compositor in ' +
+            'visibility hidden element should never cause restyles');
+    div.remove(div);
+  });
+  */
+
+  add_task(function* no_restyling_main_thread_animations_in_visiblily_hidden_element() {
+    var div = addDiv(null,
+     { style: 'animation: background-color 100s; visibility: hidden' });
+    var animation = div.getAnimations()[0];
+
+    yield animation.ready;
+    var markers = yield observeStyling(5);
+
+    todo_is(markers.length, 0,
+            'Bug 1237454: Animations running on the main-thread in ' +
+            'visibility hidden element should never cause restyles');
+    div.remove(div);
+  });
+
+  add_task_if_omta_enabled(function* no_restyling_compositor_animations_after_pause_is_called() {
+    var div = addDiv(null, { style: 'animation: opacity 100s' });
+    var animation = div.getAnimations()[0];
+
+    yield animation.ready;
+    ok(animation.isRunningOnCompositor);
+
+    animation.pause();
+
+    yield animation.ready;
+
+    var markers = yield observeStyling(5);
+    is(markers.length, 0,
+       'Bug 1232563: Paused animations running on the compositor should ' +
+       'never cause restyles once after pause() is called');
+    div.remove(div);
+  });
+
+  add_task(function* no_restyling_matn_thread_animations_after_pause_is_called() {
+    var div = addDiv(null, { style: 'animation: background-color 100s' });
+    var animation = div.getAnimations()[0];
+
+    yield animation.ready;
+
+    animation.pause();
+
+    yield animation.ready;
+
+    var markers = yield observeStyling(5);
+    is(markers.length, 0,
+       'Bug 1232563: Paused animations running on the main-thread should ' +
+       'never cause restyles after pause() is called');
+    div.remove(div);
+  });
+
+});
+
+</script>
+</body>
--- a/dom/animation/test/testcommon.js
+++ b/dom/animation/test/testcommon.js
@@ -36,23 +36,29 @@ function waitForFrame() {
   return new Promise(function(resolve, reject) {
     window.requestAnimationFrame(resolve);
   });
 }
 
 /**
  * Returns a Promise that is resolved after the given number of consecutive
  * animation frames have occured (using requestAnimationFrame callbacks).
+ *
+ * @param frameCount  The number of animation frames.
+ * @param onFrame  An optional function to be processed in each animation frame.
  */
-function waitForAnimationFrames(frameCount) {
+function waitForAnimationFrames(frameCount, onFrame) {
   return new Promise(function(resolve, reject) {
     function handleFrame() {
       if (--frameCount <= 0) {
         resolve();
       } else {
+        if (onFrame && typeof onFrame === 'function') {
+          onFrame();
+        }
         window.requestAnimationFrame(handleFrame); // wait another frame
       }
     }
     window.requestAnimationFrame(handleFrame);
   });
 }
 
 /**
--- a/dom/apps/Webapps.jsm
+++ b/dom/apps/Webapps.jsm
@@ -2046,17 +2046,17 @@ this.DOMApplicationRegistry = {
         },
         id: aApp.id
       });
       let appURI = NetUtil.newURI(aApp.origin, null, null);
       let principal =
         Services.scriptSecurityManager.createCodebasePrincipal(appURI,
                                                                {appId: aApp.localId});
       let cacheUpdate = updateSvc.scheduleAppUpdate(
-        appcacheURI, docURI, principal, aApp.localId, false, aProfileDir);
+        appcacheURI, docURI, principal, aProfileDir);
 
       // We save the download details for potential further usage like
       // cancelling it.
       let download = {
         cacheUpdate: cacheUpdate,
         appId: this._appIdForManifestURL(aApp.manifestURL),
         previousState: aIsUpdate ? "installed" : "pending"
       };
@@ -2200,17 +2200,17 @@ this.DOMApplicationRegistry = {
           new ManifestHelper(manifest, aData.origin, aData.manifestURL);
         debug("onlyCheckAppCache - launch updateSvc.checkForUpdate for " +
               helper.fullAppcachePath());
         let appURI = NetUtil.newURI(aApp.origin, null, null);
         let principal =
           Services.scriptSecurityManager.createCodebasePrincipal(appURI,
                                                                  {appId: aApp.localId});
         updateSvc.checkForUpdate(Services.io.newURI(helper.fullAppcachePath(), null, null),
-                                 principal, app.localId, false, updateObserver);
+                                 principal, updateObserver);
       });
       return;
     }
 
     // On xhr load request event
     function onload(xhr, oldManifest) {
       debug("Got http status=" + xhr.status + " for " + aData.manifestURL);
       let oldHash = app.manifestHash;
@@ -2474,18 +2474,17 @@ this.DOMApplicationRegistry = {
 
       let updateDeferred = Promise.defer();
       let appURI = NetUtil.newURI(aApp.origin, null, null);
       let principal =
         Services.scriptSecurityManager.createCodebasePrincipal(appURI,
                                                                {appId: aApp.localId});
 
       updateSvc.checkForUpdate(Services.io.newURI(manifest.fullAppcachePath(), null, null),
-                               principal, aApp.localId, false,
-                               (aSubject, aTopic, aData) => updateDeferred.resolve(aTopic));
+                               principal, (aSubject, aTopic, aData) => updateDeferred.resolve(aTopic));
 
       let topic = yield updateDeferred.promise;
 
       debug("updateHostedApp: updateSvc.checkForUpdate return for " +
             aApp.manifestURL + " - event is " + topic);
 
       let eventType =
         topic == "offline-cache-update-available" ? "downloadavailable"
--- a/dom/base/DOMMatrix.h
+++ b/dom/base/DOMMatrix.h
@@ -137,17 +137,17 @@ protected:
   virtual ~DOMMatrixReadOnly() {}
 
 private:
   DOMMatrixReadOnly() = delete;
   DOMMatrixReadOnly(const DOMMatrixReadOnly&) = delete;
   DOMMatrixReadOnly& operator=(const DOMMatrixReadOnly&) = delete;
 };
 
-class DOMMatrix final : public DOMMatrixReadOnly
+class DOMMatrix : public DOMMatrixReadOnly
 {
 public:
   explicit DOMMatrix(nsISupports* aParent)
     : DOMMatrixReadOnly(aParent)
   {}
 
   DOMMatrix(nsISupports* aParent, const DOMMatrixReadOnly& other)
     : DOMMatrixReadOnly(aParent, other)
@@ -239,16 +239,18 @@ public:
   DOMMatrix* RotateAxisAngleSelf(double aX,
                                  double aY,
                                  double aZ,
                                  double aAngle);
   DOMMatrix* SkewXSelf(double aSx);
   DOMMatrix* SkewYSelf(double aSy);
   DOMMatrix* InvertSelf();
   DOMMatrix* SetMatrixValue(const nsAString& aTransformList, ErrorResult& aRv);
-private:
+protected:
   void Ensure3DMatrix();
+
+  virtual ~DOMMatrix() {}
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /*MOZILLA_DOM_DOMMATRIX_H_*/
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -2910,32 +2910,32 @@ Element::PreHandleEventForLinks(EventCha
   nsresult rv = NS_OK;
 
   // We do the status bar updates in PreHandleEvent so that the status bar gets
   // updated even if the event is consumed before we have a chance to set it.
   switch (aVisitor.mEvent->mMessage) {
   // Set the status bar similarly for mouseover and focus
   case eMouseOver:
     aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
-    // FALL THROUGH
+    MOZ_FALLTHROUGH;
   case eFocus: {
     InternalFocusEvent* focusEvent = aVisitor.mEvent->AsFocusEvent();
     if (!focusEvent || !focusEvent->isRefocus) {
       nsAutoString target;
       GetLinkTarget(target);
       nsContentUtils::TriggerLink(this, aVisitor.mPresContext, absURI, target,
                                   false, true, true);
       // Make sure any ancestor links don't also TriggerLink
       aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
     }
     break;
   }
   case eMouseOut:
     aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
-    // FALL THROUGH
+    MOZ_FALLTHROUGH;
   case eBlur:
     rv = LeaveLink(aVisitor.mPresContext);
     if (NS_SUCCEEDED(rv)) {
       aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
     }
     break;
 
   default:
--- a/dom/base/File.cpp
+++ b/dom/base/File.cpp
@@ -953,33 +953,33 @@ BlobImplFile::LookupAndCacheIsDirectory(
              "This should only be called when this object has been created "
              "from an nsIFile to note that the nsIFile is a directory");
   bool isDir;
   mFile->IsDirectory(&isDir);
   mDirState = isDir ? BlobDirState::eIsDir : BlobDirState::eIsNotDir;
 }
 
 ////////////////////////////////////////////////////////////////////////////
-// BlobImplEmptyFile implementation
+// EmptyBlobImpl implementation
 
-NS_IMPL_ISUPPORTS_INHERITED0(BlobImplEmptyFile, BlobImpl)
+NS_IMPL_ISUPPORTS_INHERITED0(EmptyBlobImpl, BlobImpl)
 
 already_AddRefed<BlobImpl>
-BlobImplEmptyFile::CreateSlice(uint64_t aStart, uint64_t aLength,
-                               const nsAString& aContentType,
-                               ErrorResult& aRv)
+EmptyBlobImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
+                           const nsAString& aContentType,
+                           ErrorResult& aRv)
 {
   MOZ_ASSERT(!aStart && !aLength);
-  RefPtr<BlobImpl> impl = new BlobImplEmptyFile(aContentType);
+  RefPtr<BlobImpl> impl = new EmptyBlobImpl(aContentType);
   return impl.forget();
 }
 
 void
-BlobImplEmptyFile::GetInternalStream(nsIInputStream** aStream,
-                                     ErrorResult& aRv)
+EmptyBlobImpl::GetInternalStream(nsIInputStream** aStream,
+                                 ErrorResult& aRv)
 {
   nsresult rv = NS_NewCStringInputStream(aStream, EmptyCString());
   if (NS_WARN_IF(NS_FAILED(rv))) {
     aRv.Throw(rv);
     return;
   }
 }
 
--- a/dom/base/File.h
+++ b/dom/base/File.h
@@ -65,16 +65,17 @@ class Blob : public nsIDOMBlob
 public:
   NS_DECL_NSIDOMBLOB
   NS_DECL_NSIXHRSENDABLE
   NS_DECL_NSIMUTABLE
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(Blob, nsIDOMBlob)
 
+  // This creates a Blob or a File based on the type of BlobImpl.
   static Blob*
   Create(nsISupports* aParent, BlobImpl* aImpl);
 
   static already_AddRefed<Blob>
   Create(nsISupports* aParent, const nsAString& aContentType,
          uint64_t aLength);
 
   static already_AddRefed<Blob>
@@ -828,37 +829,37 @@ private:
   CreateSlice(uint64_t aStart, uint64_t aLength,
               const nsAString& aContentType, ErrorResult& aRv) override;
 
   nsCOMPtr<nsIFile> mFile;
   bool mWholeFile;
   bool mIsTemporary;
 };
 
-class BlobImplEmptyFile final : public BlobImplBase
+class EmptyBlobImpl final : public BlobImplBase
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
-  explicit BlobImplEmptyFile(const nsAString& aContentType)
-    : BlobImplBase(EmptyString(), aContentType, 0 /* aLength */)
+  explicit EmptyBlobImpl(const nsAString& aContentType)
+    : BlobImplBase(aContentType, 0 /* aLength */)
   {}
 
   virtual void GetInternalStream(nsIInputStream** aStream,
                                  ErrorResult& aRv) override;
 
   virtual already_AddRefed<BlobImpl>
   CreateSlice(uint64_t aStart, uint64_t aLength,
               const nsAString& aContentType, ErrorResult& aRv) override;
 
   virtual bool IsMemoryFile() const override
   {
     return true;
   }
 
 private:
-  ~BlobImplEmptyFile() {}
+  ~EmptyBlobImpl() {}
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_File_h
--- a/dom/base/FileReader.cpp
+++ b/dom/base/FileReader.cpp
@@ -93,64 +93,56 @@ public:
 void
 FileReader::RootResultArrayBuffer()
 {
   mozilla::HoldJSObjects(this);
 }
 
 //FileReader constructors/initializers
 
-FileReader::FileReader(nsPIDOMWindow* aWindow,
+FileReader::FileReader(nsIGlobalObject* aGlobal,
                        WorkerPrivate* aWorkerPrivate)
-  : DOMEventTargetHelper(aWindow)
+  : DOMEventTargetHelper(aGlobal)
   , mFileData(nullptr)
   , mDataLen(0)
   , mDataFormat(FILE_AS_BINARY)
   , mResultArrayBuffer(nullptr)
   , mProgressEventWasDelayed(false)
   , mTimerIsActive(false)
   , mReadyState(EMPTY)
   , mTotal(0)
   , mTransferred(0)
   , mTarget(do_GetCurrentThread())
   , mBusyCount(0)
   , mWorkerPrivate(aWorkerPrivate)
 {
-  MOZ_ASSERT_IF(!NS_IsMainThread(), mWorkerPrivate && !aWindow);
-  MOZ_ASSERT_IF(NS_IsMainThread(), !mWorkerPrivate);
+  MOZ_ASSERT(aGlobal);
+  MOZ_ASSERT(NS_IsMainThread() == !mWorkerPrivate);
   SetDOMStringToNull(mResult);
 }
 
 FileReader::~FileReader()
 {
   Shutdown();
   DropJSObjects(this);
 }
 
 /* static */ already_AddRefed<FileReader>
 FileReader::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
 {
-  // The owner can be null when this object is used by chrome code.
-  nsCOMPtr<nsPIDOMWindow> owner = do_QueryInterface(aGlobal.GetAsSupports());
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
   WorkerPrivate* workerPrivate = nullptr;
 
   if (!NS_IsMainThread()) {
     JSContext* cx = aGlobal.Context();
     workerPrivate = GetWorkerPrivateFromContext(cx);
     MOZ_ASSERT(workerPrivate);
   }
 
-  RefPtr<FileReader> fileReader = new FileReader(owner, workerPrivate);
-
-  if (!owner && nsContentUtils::ThreadsafeIsCallerChrome()) {
-    // Instead of grabbing some random global from the context stack,
-    // let's use the default one (junk scope) for now.
-    // We should move away from this Init...
-    fileReader->BindToOwner(xpc::NativeGlobal(xpc::PrivilegedJunkScope()));
-  }
+  RefPtr<FileReader> fileReader = new FileReader(global, workerPrivate);
 
   return fileReader.forget();
 }
 
 // nsIInterfaceRequestor
 
 NS_IMETHODIMP
 FileReader::GetInterface(const nsIID & aIID, void **aResult)
@@ -237,27 +229,17 @@ FileReader::DoOnLoadEnd(nsresult aStatus
 
   aSuccessEvent = NS_LITERAL_STRING(LOAD_STR);
   aTerminationEvent = NS_LITERAL_STRING(LOADEND_STR);
 
   nsresult rv = NS_OK;
   switch (mDataFormat) {
     case FILE_AS_ARRAYBUFFER: {
       AutoJSAPI jsapi;
-      nsCOMPtr<nsIGlobalObject> globalObject;
-
-      if (NS_IsMainThread()) {
-        globalObject = do_QueryInterface(GetParentObject());
-      } else {
-        MOZ_ASSERT(mWorkerPrivate);
-        MOZ_ASSERT(mBusyCount);
-        globalObject = mWorkerPrivate->GlobalScope();
-      }
-
-      if (!globalObject || !jsapi.Init(globalObject)) {
+      if (!jsapi.Init(GetParentObject())) {
         FreeFileData();
         return NS_ERROR_FAILURE;
       }
 
       RootResultArrayBuffer();
       mResultArrayBuffer = JS_NewArrayBufferWithContents(jsapi.cx(), mDataLen, mFileData);
       if (!mResultArrayBuffer) {
         JS_ClearPendingException(jsapi.cx());
@@ -360,16 +342,24 @@ FileReader::ReadFileContent(Blob& aBlob,
                             eDataFormat aDataFormat,
                             ErrorResult& aRv)
 {
   //Implicit abort to clear any other activity going on
   ErrorResult error;
   Abort(error);
   error.SuppressException();
 
+  if (mReadyState == LOADING) {
+    // A nested ReadAsSomething() as been called during one of the events
+    // dispatched by Abort(). We have to terminate this operation in order to
+    // continue the nested one.
+    aRv.Throw(NS_ERROR_ABORT);
+    return;
+  }
+
   mError = nullptr;
   SetDOMStringToNull(mResult);
   mTransferred = 0;
   mTotal = 0;
   mReadyState = EMPTY;
   FreeFileData();
 
   mBlob = &aBlob;
--- a/dom/base/FileReader.h
+++ b/dom/base/FileReader.h
@@ -41,17 +41,17 @@ class FileReader final : public DOMEvent
                          public nsSupportsWeakReference,
                          public nsIInputStreamCallback,
                          public nsITimerCallback,
                          public workers::WorkerFeature
 {
   friend class FileReaderDecreaseBusyCounter;
 
 public:
-  FileReader(nsPIDOMWindow* aWindow,
+  FileReader(nsIGlobalObject* aGlobal,
              workers::WorkerPrivate* aWorkerPrivate);
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSITIMERCALLBACK
   NS_DECL_NSIINPUTSTREAMCALLBACK
   NS_DECL_NSIINTERFACEREQUESTOR
 
--- a/dom/base/FormData.cpp
+++ b/dom/base/FormData.cpp
@@ -18,42 +18,26 @@ using namespace mozilla::dom;
 FormData::FormData(nsISupports* aOwner)
   : nsFormSubmission(NS_LITERAL_CSTRING("UTF-8"), nullptr)
   , mOwner(aOwner)
 {
 }
 
 namespace {
 
-// Implements steps 3 and 4 of the "create an entry" algorithm of FormData.
-already_AddRefed<File>
-CreateNewFileInstance(Blob& aBlob, const Optional<nsAString>& aFilename,
-                      ErrorResult& aRv)
+already_AddRefed<Blob>
+GetBlobForFormDataStorage(Blob& aBlob, const Optional<nsAString>& aFilename,
+                          ErrorResult& aRv)
 {
-  // Step 3 "If value is a Blob object and not a File object, set value to
-  // a new File object, representing the same bytes, whose name attribute value
-  // is "blob"."
-  // Step 4 "If value is a File object and filename is given, set value to
-  // a new File object, representing the same bytes, whose name attribute
-  // value is filename."
-  nsAutoString filename;
-  if (aFilename.WasPassed()) {
-    filename = aFilename.Value();
-  } else {
-    // If value is already a File and filename is not passed, the spec says not
-    // to create a new instance.
-    RefPtr<File> file = aBlob.ToFile();
-    if (file) {
-      return file.forget();
-    }
-
-    filename = NS_LITERAL_STRING("blob");
+  if (!aFilename.WasPassed()) {
+    RefPtr<Blob> blob = &aBlob;
+    return blob.forget();
   }
 
-  RefPtr<File> file = aBlob.ToFile(filename, aRv);
+  RefPtr<File> file = aBlob.ToFile(aFilename.Value(), aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   return file.forget();
 }
 
 } // namespace
@@ -73,17 +57,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Fo
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(FormData)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
 
   for (uint32_t i = 0, len = tmp->mFormData.Length(); i < len; ++i) {
     ImplCycleCollectionTraverse(cb, tmp->mFormData[i].value,
-                                "mFormData[i].GetAsFile()", 0);
+                                "mFormData[i].GetAsBlob()", 0);
   }
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(FormData)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(FormData)
@@ -111,59 +95,59 @@ FormData::Append(const nsAString& aName,
                  ErrorResult& aRv)
 {
   AddNameValuePair(aName, aValue);
 }
 
 void
 FormData::Append(const nsAString& aName, Blob& aBlob,
                  const Optional<nsAString>& aFilename,
-                   ErrorResult& aRv)
+                 ErrorResult& aRv)
 {
-  RefPtr<File> file = CreateNewFileInstance(aBlob, aFilename, aRv);
+  RefPtr<Blob> blob = GetBlobForFormDataStorage(aBlob, aFilename, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
-  AddNameFilePair(aName, file);
+  AddNameBlobPair(aName, blob);
 }
 
 void
 FormData::Delete(const nsAString& aName)
 {
   // We have to use this slightly awkward for loop since uint32_t >= 0 is an
   // error for being always true.
   for (uint32_t i = mFormData.Length(); i-- > 0; ) {
     if (aName.Equals(mFormData[i].name)) {
       mFormData.RemoveElementAt(i);
     }
   }
 }
 
 void
 FormData::Get(const nsAString& aName,
-              Nullable<OwningFileOrUSVString>& aOutValue)
+              Nullable<OwningBlobOrUSVString>& aOutValue)
 {
   for (uint32_t i = 0; i < mFormData.Length(); ++i) {
     if (aName.Equals(mFormData[i].name)) {
       aOutValue.SetValue() = mFormData[i].value;
       return;
     }
   }
 
   aOutValue.SetNull();
 }
 
 void
 FormData::GetAll(const nsAString& aName,
-                 nsTArray<OwningFileOrUSVString>& aValues)
+                 nsTArray<OwningBlobOrUSVString>& aValues)
 {
   for (uint32_t i = 0; i < mFormData.Length(); ++i) {
     if (aName.Equals(mFormData[i].name)) {
-      OwningFileOrUSVString* element = aValues.AppendElement();
+      OwningBlobOrUSVString* element = aValues.AppendElement();
       *element = mFormData[i].value;
     }
   }
 }
 
 bool
 FormData::Has(const nsAString& aName)
 {
@@ -172,22 +156,22 @@ FormData::Has(const nsAString& aName)
       return true;
     }
   }
 
   return false;
 }
 
 nsresult
-FormData::AddNameFilePair(const nsAString& aName, File* aFile)
+FormData::AddNameBlobPair(const nsAString& aName, Blob* aBlob)
 {
-  MOZ_ASSERT(aFile);
+  MOZ_ASSERT(aBlob);
 
   FormDataTuple* data = mFormData.AppendElement();
-  SetNameFilePair(data, aName, aFile);
+  SetNameBlobPair(data, aName, aBlob);
   return NS_OK;
 }
 
 FormData::FormDataTuple*
 FormData::RemoveAllOthersAndGetFirstFormDataTuple(const nsAString& aName)
 {
   FormDataTuple* lastFoundTuple = nullptr;
   uint32_t lastFoundIndex = mFormData.Length();
@@ -210,22 +194,22 @@ FormData::RemoveAllOthersAndGetFirstForm
 
 void
 FormData::Set(const nsAString& aName, Blob& aBlob,
               const Optional<nsAString>& aFilename,
               ErrorResult& aRv)
 {
   FormDataTuple* tuple = RemoveAllOthersAndGetFirstFormDataTuple(aName);
   if (tuple) {
-    RefPtr<File> file = CreateNewFileInstance(aBlob, aFilename, aRv);
+    RefPtr<Blob> blob = GetBlobForFormDataStorage(aBlob, aFilename, aRv);
     if (NS_WARN_IF(aRv.Failed())) {
       return;
     }
 
-    SetNameFilePair(tuple, aName, file);
+    SetNameBlobPair(tuple, aName, blob);
   } else {
     Append(aName, aBlob, aFilename, aRv);
   }
 }
 
 void
 FormData::Set(const nsAString& aName, const nsAString& aValue,
               ErrorResult& aRv)
@@ -246,17 +230,17 @@ FormData::GetIterableLength() const
 
 const nsAString&
 FormData::GetKeyAtIndex(uint32_t aIndex) const
 {
   MOZ_ASSERT(aIndex < mFormData.Length());
   return mFormData[aIndex].name;
 }
 
-const OwningFileOrUSVString&
+const OwningBlobOrUSVString&
 FormData::GetValueAtIndex(uint32_t aIndex) const
 {
   MOZ_ASSERT(aIndex < mFormData.Length());
   return mFormData[aIndex].value;
 }
 
 void
 FormData::SetNameValuePair(FormDataTuple* aData,
@@ -264,25 +248,25 @@ FormData::SetNameValuePair(FormDataTuple
                            const nsAString& aValue)
 {
   MOZ_ASSERT(aData);
   aData->name = aName;
   aData->value.SetAsUSVString() = aValue;
 }
 
 void
-FormData::SetNameFilePair(FormDataTuple* aData,
+FormData::SetNameBlobPair(FormDataTuple* aData,
                           const nsAString& aName,
-                          File* aFile)
+                          Blob* aBlob)
 {
   MOZ_ASSERT(aData);
-  MOZ_ASSERT(aFile);
+  MOZ_ASSERT(aBlob);
 
   aData->name = aName;
-  aData->value.SetAsFile() = aFile;
+  aData->value.SetAsBlob() = aBlob;
 }
 
 // -------------------------------------------------------------------------
 // nsIDOMFormData
 
 NS_IMETHODIMP
 FormData::Append(const nsAString& aName, nsIVariant* aValue)
 {
@@ -353,18 +337,31 @@ FormData::Constructor(const GlobalObject
 
 NS_IMETHODIMP
 FormData::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
                       nsACString& aContentType, nsACString& aCharset)
 {
   nsFSMultipartFormData fs(NS_LITERAL_CSTRING("UTF-8"), nullptr);
 
   for (uint32_t i = 0; i < mFormData.Length(); ++i) {
-    if (mFormData[i].value.IsFile()) {
-      fs.AddNameFilePair(mFormData[i].name, mFormData[i].value.GetAsFile());
+    if (mFormData[i].value.IsBlob()) {
+      RefPtr<File> file = mFormData[i].value.GetAsBlob()->ToFile();
+      if (file) {
+        fs.AddNameBlobPair(mFormData[i].name, file);
+        continue;
+      }
+
+      ErrorResult rv;
+      file =
+        mFormData[i].value.GetAsBlob()->ToFile(NS_LITERAL_STRING("blob"), rv);
+      if (NS_WARN_IF(rv.Failed())) {
+        return rv.StealNSResult();
+      }
+
+      fs.AddNameBlobPair(mFormData[i].name, file);
     } else if (mFormData[i].value.IsUSVString()) {
       fs.AddNameValuePair(mFormData[i].name,
                           mFormData[i].value.GetAsUSVString());
     } else {
       MOZ_CRASH("This should no be possible.");
     }
   }
 
--- a/dom/base/FormData.h
+++ b/dom/base/FormData.h
@@ -30,31 +30,31 @@ class FormData final : public nsIDOMForm
                        public nsWrapperCache
 {
 private:
   ~FormData() {}
 
   struct FormDataTuple
   {
     nsString name;
-    OwningFileOrUSVString value;
+    OwningBlobOrUSVString value;
   };
 
   // Returns the FormDataTuple to modify. This may be null, in which case
   // no element with aName was found.
   FormDataTuple*
   RemoveAllOthersAndGetFirstFormDataTuple(const nsAString& aName);
 
   void SetNameValuePair(FormDataTuple* aData,
                         const nsAString& aName,
                         const nsAString& aValue);
 
-  void SetNameFilePair(FormDataTuple* aData,
+  void SetNameBlobPair(FormDataTuple* aData,
                        const nsAString& aName,
-                       File* aFile);
+                       Blob* aBlob);
 
 public:
   explicit FormData(nsISupports* aOwner = nullptr);
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(FormData,
                                                          nsIDOMFormData)
 
@@ -79,51 +79,51 @@ public:
   void Append(const nsAString& aName, const nsAString& aValue,
               ErrorResult& aRv);
   void Append(const nsAString& aName, Blob& aBlob,
               const Optional<nsAString>& aFilename,
               ErrorResult& aRv);
 
   void Delete(const nsAString& aName);
 
-  void Get(const nsAString& aName, Nullable<OwningFileOrUSVString>& aOutValue);
+  void Get(const nsAString& aName, Nullable<OwningBlobOrUSVString>& aOutValue);
 
-  void GetAll(const nsAString& aName, nsTArray<OwningFileOrUSVString>& aValues);
+  void GetAll(const nsAString& aName, nsTArray<OwningBlobOrUSVString>& aValues);
 
   bool Has(const nsAString& aName);
 
   void Set(const nsAString& aName, Blob& aBlob,
            const Optional<nsAString>& aFilename,
            ErrorResult& aRv);
   void Set(const nsAString& aName, const nsAString& aValue,
            ErrorResult& aRv);
 
   uint32_t GetIterableLength() const;
 
   const nsAString& GetKeyAtIndex(uint32_t aIndex) const;
 
-  const OwningFileOrUSVString& GetValueAtIndex(uint32_t aIndex) const;
+  const OwningBlobOrUSVString& GetValueAtIndex(uint32_t aIndex) const;
 
   // nsFormSubmission
   virtual nsresult
   GetEncodedSubmission(nsIURI* aURI, nsIInputStream** aPostDataStream) override;
 
   virtual nsresult AddNameValuePair(const nsAString& aName,
                                     const nsAString& aValue) override
   {
     FormDataTuple* data = mFormData.AppendElement();
     SetNameValuePair(data, aName, aValue);
     return NS_OK;
   }
 
-  virtual nsresult AddNameFilePair(const nsAString& aName,
-                                   File* aFile) override;
+  virtual nsresult AddNameBlobPair(const nsAString& aName,
+                                   Blob* aBlob) override;
 
   typedef bool (*FormDataEntryCallback)(const nsString& aName,
-                                        const OwningFileOrUSVString& aValue,
+                                        const OwningBlobOrUSVString& aValue,
                                         void* aClosure);
 
   uint32_t
   Length() const
   {
     return mFormData.Length();
   }
 
--- a/dom/base/StructuredCloneHolder.cpp
+++ b/dom/base/StructuredCloneHolder.cpp
@@ -831,24 +831,23 @@ ReadFormData(JSContext* aCx,
         return nullptr;
       }
 
       if (tag == SCTAG_DOM_BLOB) {
         MOZ_ASSERT(indexOrLengthOfString < aHolder->BlobImpls().Length());
 
         RefPtr<BlobImpl> blobImpl =
           aHolder->BlobImpls()[indexOrLengthOfString];
-        MOZ_ASSERT(blobImpl->IsFile());
 
-        RefPtr<File> file =
-          File::Create(aHolder->ParentDuringRead(), blobImpl);
-        MOZ_ASSERT(file);
+        RefPtr<Blob> blob =
+          Blob::Create(aHolder->ParentDuringRead(), blobImpl);
+        MOZ_ASSERT(blob);
 
         ErrorResult rv;
-        formData->Append(name, *file, thirdArg, rv);
+        formData->Append(name, *blob, thirdArg, rv);
         if (NS_WARN_IF(rv.Failed())) {
           return nullptr;
         }
 
       } else {
         MOZ_ASSERT(tag == 0);
 
         nsAutoString value;
@@ -907,26 +906,26 @@ WriteFormData(JSStructuredCloneWriter* a
   public:
     Closure(JSStructuredCloneWriter* aWriter,
             StructuredCloneHolder* aHolder)
       : mWriter(aWriter),
         mHolder(aHolder)
     { }
 
     static bool
-    Write(const nsString& aName, const OwningFileOrUSVString& aValue,
+    Write(const nsString& aName, const OwningBlobOrUSVString& aValue,
           void* aClosure)
     {
       Closure* closure = static_cast<Closure*>(aClosure);
       if (!WriteString(closure->mWriter, aName)) {
         return false;
       }
 
-      if (aValue.IsFile()) {
-        BlobImpl* blobImpl = aValue.GetAsFile()->Impl();
+      if (aValue.IsBlob()) {
+        BlobImpl* blobImpl = aValue.GetAsBlob()->Impl();
         if (!JS_WriteUint32Pair(closure->mWriter, SCTAG_DOM_BLOB,
                                 closure->mHolder->BlobImpls().Length())) {
           return false;
         }
 
         closure->mHolder->BlobImpls().AppendElement(blobImpl);
         return true;
       }
new file mode 100644
--- /dev/null
+++ b/dom/base/WebKitCSSMatrix.cpp
@@ -0,0 +1,192 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/WebKitCSSMatrix.h"
+
+#include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/WebKitCSSMatrixBinding.h"
+
+namespace mozilla {
+namespace dom {
+
+static const double sRadPerDegree = 2.0 * M_PI / 360.0;
+
+bool
+WebKitCSSMatrix::FeatureEnabled(JSContext* aCx, JSObject* aObj)
+{
+  return Preferences::GetBool("layout.css.DOMMatrix.enabled", false) &&
+         Preferences::GetBool("layout.css.prefixes.webkit", false);
+}
+
+already_AddRefed<WebKitCSSMatrix>
+WebKitCSSMatrix::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
+{
+  RefPtr<WebKitCSSMatrix> obj = new WebKitCSSMatrix(aGlobal.GetAsSupports());
+  return obj.forget();
+}
+
+already_AddRefed<WebKitCSSMatrix>
+WebKitCSSMatrix::Constructor(const GlobalObject& aGlobal,
+                             const nsAString& aTransformList, ErrorResult& aRv)
+{
+  RefPtr<WebKitCSSMatrix> obj = new WebKitCSSMatrix(aGlobal.GetAsSupports());
+  obj = obj->SetMatrixValue(aTransformList, aRv);
+  return obj.forget();
+}
+
+already_AddRefed<WebKitCSSMatrix>
+WebKitCSSMatrix::Constructor(const GlobalObject& aGlobal,
+                             const DOMMatrixReadOnly& aOther, ErrorResult& aRv)
+{
+  RefPtr<WebKitCSSMatrix> obj = new WebKitCSSMatrix(aGlobal.GetAsSupports(),
+                                                    aOther);
+  return obj.forget();
+}
+
+JSObject*
+WebKitCSSMatrix::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  return WebKitCSSMatrixBinding::Wrap(aCx, this, aGivenProto);
+}
+
+WebKitCSSMatrix*
+WebKitCSSMatrix::SetMatrixValue(const nsAString& aTransformList,
+                                ErrorResult& aRv)
+{
+  DOMMatrix::SetMatrixValue(aTransformList, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+
+  return this;
+}
+
+already_AddRefed<WebKitCSSMatrix>
+WebKitCSSMatrix::Multiply(const WebKitCSSMatrix& other) const
+{
+  RefPtr<WebKitCSSMatrix> retval = new WebKitCSSMatrix(mParent, *this);
+  retval->MultiplySelf(other);
+
+  return retval.forget();
+}
+
+already_AddRefed<WebKitCSSMatrix>
+WebKitCSSMatrix::Inverse() const
+{
+  RefPtr<WebKitCSSMatrix> retval = new WebKitCSSMatrix(mParent, *this);
+  retval->InvertSelf();
+
+  return retval.forget();
+}
+
+already_AddRefed<WebKitCSSMatrix>
+WebKitCSSMatrix::Translate(double aTx,
+                           double aTy,
+                           double aTz) const
+{
+  RefPtr<WebKitCSSMatrix> retval = new WebKitCSSMatrix(mParent, *this);
+  retval->TranslateSelf(aTx, aTy, aTz);
+
+  return retval.forget();
+}
+
+already_AddRefed<WebKitCSSMatrix>
+WebKitCSSMatrix::Scale(double aScaleX,
+                       const Optional<double>& aScaleY,
+                       double aScaleZ) const
+{
+  double scaleX = aScaleX;
+  double scaleY = aScaleY.WasPassed() ? aScaleY.Value() : scaleX;
+  double scaleZ = aScaleZ;
+
+  RefPtr<WebKitCSSMatrix> retval = new WebKitCSSMatrix(mParent, *this);
+  retval->ScaleNonUniformSelf(scaleX, scaleY, scaleZ);
+
+  return retval.forget();
+}
+
+already_AddRefed<WebKitCSSMatrix>
+WebKitCSSMatrix::Rotate(double aRotX,
+                        const Optional<double>& aRotY,
+                        const Optional<double>& aRotZ) const
+{
+  double rotX = aRotX;
+  double rotY;
+  double rotZ;
+
+  if (!aRotY.WasPassed() && !aRotZ.WasPassed()) {
+    rotZ = rotX;
+    rotX = 0;
+    rotY = 0;
+  } else {
+    rotY = aRotY.WasPassed() ? aRotY.Value() : 0;
+    rotZ = aRotZ.WasPassed() ? aRotZ.Value() : 0;
+  }
+
+  RefPtr<WebKitCSSMatrix> retval = new WebKitCSSMatrix(mParent, *this);
+  retval->Rotate3dSelf(rotX, rotY, rotZ);
+
+  return retval.forget();
+}
+
+WebKitCSSMatrix*
+WebKitCSSMatrix::Rotate3dSelf(double aRotX,
+                              double aRotY,
+                              double aRotZ)
+{
+  if (aRotX != 0 || aRotY != 0) {
+    Ensure3DMatrix();
+  }
+
+  if (mMatrix3D) {
+    if (fmod(aRotZ, 360) != 0) {
+      mMatrix3D->RotateZ(aRotZ * sRadPerDegree);
+    }
+    if (fmod(aRotY, 360) != 0) {
+      mMatrix3D->RotateY(aRotY * sRadPerDegree);
+    }
+    if (fmod(aRotX, 360) != 0) {
+      mMatrix3D->RotateX(aRotX * sRadPerDegree);
+    }
+  } else if (fmod(aRotZ, 360) != 0) {
+    mMatrix2D->PreRotate(aRotZ * sRadPerDegree);
+  }
+
+  return this;
+}
+
+already_AddRefed<WebKitCSSMatrix>
+WebKitCSSMatrix::RotateAxisAngle(double aX,
+                                 double aY,
+                                 double aZ,
+                                 double aAngle) const
+{
+  RefPtr<WebKitCSSMatrix> retval = new WebKitCSSMatrix(mParent, *this);
+  retval->RotateAxisAngleSelf(aX, aY, aZ, aAngle);
+
+  return retval.forget();
+}
+
+already_AddRefed<WebKitCSSMatrix>
+WebKitCSSMatrix::SkewX(double aSx) const
+{
+  RefPtr<WebKitCSSMatrix> retval = new WebKitCSSMatrix(mParent, *this);
+  retval->SkewXSelf(aSx);
+
+  return retval.forget();
+}
+
+already_AddRefed<WebKitCSSMatrix>
+WebKitCSSMatrix::SkewY(double aSy) const
+{
+  RefPtr<WebKitCSSMatrix> retval = new WebKitCSSMatrix(mParent, *this);
+  retval->SkewYSelf(aSy);
+
+  return retval.forget();
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/base/WebKitCSSMatrix.h
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_webkitcssmatrix_h__
+#define mozilla_dom_webkitcssmatrix_h__
+
+#include "mozilla/dom/DOMMatrix.h"
+
+namespace mozilla {
+namespace dom {
+
+class WebKitCSSMatrix final : public DOMMatrix
+{
+public:
+  explicit WebKitCSSMatrix(nsISupports* aParent)
+    : DOMMatrix(aParent)
+  {}
+
+  WebKitCSSMatrix(nsISupports* aParent, const DOMMatrixReadOnly& other)
+    : DOMMatrix(aParent, other)
+  {}
+
+  static bool FeatureEnabled(JSContext* aCx, JSObject* aObj);
+
+  static already_AddRefed<WebKitCSSMatrix>
+  Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
+  static already_AddRefed<WebKitCSSMatrix>
+  Constructor(const GlobalObject& aGlobal,
+              const nsAString& aTransformList, ErrorResult& aRv);
+  static already_AddRefed<WebKitCSSMatrix>
+  Constructor(const GlobalObject& aGlobal,
+              const DOMMatrixReadOnly& aOther, ErrorResult& aRv);
+
+  nsISupports* GetParentObject() const { return mParent; }
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aGivenProto) override;
+
+  WebKitCSSMatrix* SetMatrixValue(const nsAString& aTransformList,
+                                  ErrorResult& aRv);
+
+  already_AddRefed<WebKitCSSMatrix> Multiply(const WebKitCSSMatrix& aOther) const;
+  already_AddRefed<WebKitCSSMatrix> Inverse() const;
+  already_AddRefed<WebKitCSSMatrix> Translate(double aTx,
+                                              double aTy,
+                                              double aTz) const;
+  already_AddRefed<WebKitCSSMatrix> Scale(double aScaleX,
+                                          const Optional<double>& aScaleY,
+                                          double aScaleZ) const;
+  already_AddRefed<WebKitCSSMatrix> Rotate(double aRotX,
+                                           const Optional<double>& aRotY,
+                                           const Optional<double>& aRotZ) const;
+  already_AddRefed<WebKitCSSMatrix> RotateAxisAngle(double aX,
+                                                    double aY,
+                                                    double aZ,
+                                                    double aAngle) const;
+  already_AddRefed<WebKitCSSMatrix> SkewX(double aSx) const;
+  already_AddRefed<WebKitCSSMatrix> SkewY(double aSy) const;
+protected:
+  WebKitCSSMatrix* Rotate3dSelf(double aRotX,
+                                double aRotY,
+                                double aRotZ);
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif /* mozilla_dom_webkitcssmatrix_h__ */
--- a/dom/base/WindowNamedPropertiesHandler.cpp
+++ b/dom/base/WindowNamedPropertiesHandler.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WindowNamedPropertiesHandler.h"
 #include "mozilla/dom/EventTargetBinding.h"
 #include "mozilla/dom/WindowBinding.h"
+#include "nsContentUtils.h"
 #include "nsDOMClassInfo.h"
 #include "nsGlobalWindow.h"
 #include "nsHTMLDocument.h"
 #include "nsJSUtils.h"
 #include "xpcprivate.h"
 
 namespace mozilla {
 namespace dom {
new file mode 100644
--- /dev/null
+++ b/dom/base/crashtests/1230422.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+<script>
+
+var a = new FileReader();
+
+function f() {
+  a.removeEventListener("loadend", f);
+  g();
+}
+
+function g() {
+  a.readAsBinaryString(new Blob());
+}
+
+a.addEventListener("loadend", f);
+
+try {
+  g();
+  g();
+} catch(e) {}
+
+</script>
+</body>
+</html>
--- a/dom/base/crashtests/crashtests.list
+++ b/dom/base/crashtests/crashtests.list
@@ -200,8 +200,9 @@ pref(dom.webcomponents.enabled,true) loa
 pref(dom.webcomponents.enabled,true) load 1029710.html
 load 1154598.xhtml
 load 1157995.html
 load 1181619.html
 load structured_clone_container_throws.html
 HTTP(..) load xhr_abortinprogress.html
 load xhr_empty_datauri.html
 load xhr_html_nullresponse.html
+load 1230422.html
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -207,16 +207,17 @@ EXPORTS.mozilla.dom += [
     'StructuredCloneHolder.h',
     'StructuredCloneTags.h',
     'StyleSheetList.h',
     'SubtleCrypto.h',
     'Text.h',
     'TreeWalker.h',
     'URL.h',
     'URLSearchParams.h',
+    'WebKitCSSMatrix.h',
     'WebSocket.h',
     'WindowOrientationObserver.h',
 ]
 
 UNIFIED_SOURCES += [
     'AnonymousContent.cpp',
     'Attr.cpp',
     'BarProps.cpp',
@@ -354,16 +355,17 @@ UNIFIED_SOURCES += [
     'StyleSheetList.cpp',
     'SubtleCrypto.cpp',
     'Text.cpp',
     'TextInputProcessor.cpp',
     'ThirdPartyUtil.cpp',
     'TreeWalker.cpp',
     'URL.cpp',
     'URLSearchParams.cpp',
+    'WebKitCSSMatrix.cpp',
     'WebSocket.cpp',
     'WindowNamedPropertiesHandler.cpp',
     'WindowOrientationObserver.cpp',
 ]
 
 if CONFIG['MOZ_WEBRTC']:
     UNIFIED_SOURCES += [
         'nsDOMDataChannel.cpp',
--- a/dom/base/nsContentPermissionHelper.cpp
+++ b/dom/base/nsContentPermissionHelper.cpp
@@ -440,38 +440,38 @@ nsContentPermissionUtils::NotifyRemoveCo
   MOZ_ASSERT(it != ContentPermissionRequestChildMap().end());
 
   ContentPermissionRequestChildMap().erase(it);
 }
 
 NS_IMPL_ISUPPORTS(nsContentPermissionRequester, nsIContentPermissionRequester)
 
 nsContentPermissionRequester::nsContentPermissionRequester(nsPIDOMWindow* aWindow)
-  : mWindow(aWindow)
+  : mWindow(do_GetWeakReference(aWindow))
+  , mListener(new VisibilityChangeListener(aWindow))
 {
-  mListener = new VisibilityChangeListener(mWindow);
 }
 
 nsContentPermissionRequester::~nsContentPermissionRequester()
 {
   mListener->RemoveListener();
   mListener = nullptr;
 }
 
 NS_IMETHODIMP
 nsContentPermissionRequester::GetVisibility(nsIContentPermissionRequestCallback* aCallback)
 {
   NS_ENSURE_ARG_POINTER(aCallback);
 
-  if (!mWindow) {
-    MOZ_ASSERT(false);
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
+  if (!window) {
     return NS_ERROR_FAILURE;
   }
 
-  nsCOMPtr<nsIDocShell> docshell = mWindow->GetDocShell();
+  nsCOMPtr<nsIDocShell> docshell = window->GetDocShell();
   if (!docshell) {
     return NS_ERROR_FAILURE;
   }
 
   bool isActive = false;
   docshell->GetIsActive(&isActive);
   aCallback->NotifyVisibility(isActive);
   return NS_OK;
--- a/dom/base/nsContentPermissionHelper.h
+++ b/dom/base/nsContentPermissionHelper.h
@@ -122,17 +122,17 @@ public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSICONTENTPERMISSIONREQUESTER
 
   explicit nsContentPermissionRequester(nsPIDOMWindow* aWindow);
 
 private:
   virtual ~nsContentPermissionRequester();
 
-  nsCOMPtr<nsPIDOMWindow> mWindow;
+  nsWeakPtr mWindow;
   RefPtr<VisibilityChangeListener> mListener;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 using mozilla::dom::ContentPermissionRequestParent;
 
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -100,16 +100,17 @@
 #include "nsIContentIterator.h"
 #include "nsIDOMStyleSheet.h"
 #include "nsIStyleSheetService.h"
 #include "nsContentPermissionHelper.h"
 #include "nsNetUtil.h"
 #include "nsDocument.h"
 #include "HTMLImageElement.h"
 #include "mozilla/css/ImageLoader.h"
+#include "mozilla/layers/APZCTreeManager.h" // for layers::ZoomToRectBehavior
 
 #ifdef XP_WIN
 #undef GetClassName
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::ipc;
@@ -2417,16 +2418,69 @@ nsDOMWindowUtils::FlushApzRepaints(bool*
     return NS_OK;
   }
   forwarder->GetShadowManager()->SendFlushApzRepaints();
   *aOutResult = true;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsDOMWindowUtils::ZoomToFocusedInput()
+{
+  nsIWidget* widget = GetWidget();
+  if (!widget) {
+    return NS_OK;
+  }
+  // If APZ is not enabled, this function is a no-op.
+  if (!widget->AsyncPanZoomEnabled()) {
+    return NS_OK;
+  }
+
+  nsFocusManager* fm = nsFocusManager::GetFocusManager();
+  if (!fm) {
+    return NS_OK;
+  }
+
+  nsIContent* content = fm->GetFocusedContent();
+  if (!content) {
+    return NS_OK;
+  }
+
+  nsIPresShell* shell = APZCCallbackHelper::GetRootContentDocumentPresShellForContent(content);
+  if (!shell) {
+    return NS_OK;
+  }
+
+  nsIScrollableFrame* rootScrollFrame = shell->GetRootScrollFrameAsScrollable();
+  if (!rootScrollFrame) {
+    return NS_OK;
+  }
+
+  nsIDocument* document = shell->GetDocument();
+  if (!document) {
+    return NS_OK;
+  }
+
+  uint32_t presShellId;
+  FrameMetrics::ViewID viewId;
+  if (APZCCallbackHelper::GetOrCreateScrollIdentifiers(document->GetDocumentElement(), &presShellId, &viewId)) {
+    uint32_t flags = layers::DISABLE_ZOOM_OUT;
+    if (!Preferences::GetBool("formhelper.autozoom")) {
+      flags |= layers::PAN_INTO_VIEW_ONLY;
+    }
+
+    CSSRect bounds = nsLayoutUtils::GetBoundingContentRect(content, rootScrollFrame);
+    bounds.Inflate(15.0f, 0.0f);
+    widget->ZoomToRect(presShellId, viewId, bounds, flags);
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsDOMWindowUtils::ComputeAnimationDistance(nsIDOMElement* aElement,
                                            const nsAString& aProperty,
                                            const nsAString& aValue1,
                                            const nsAString& aValue2,
                                            double* aResult)
 {
   nsresult rv;
   nsCOMPtr<nsIContent> content = do_QueryInterface(aElement, &rv);
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -6587,16 +6587,17 @@ nsIDocument::ImportNode(nsINode& aNode, 
     {
       break;
     }
     case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
     {
       if (ShadowRoot::FromNode(imported)) {
         break;
       }
+      MOZ_FALLTHROUGH;
     }
     case nsIDOMNode::ATTRIBUTE_NODE:
     case nsIDOMNode::ELEMENT_NODE:
     case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
     case nsIDOMNode::TEXT_NODE:
     case nsIDOMNode::CDATA_SECTION_NODE:
     case nsIDOMNode::COMMENT_NODE:
     case nsIDOMNode::DOCUMENT_TYPE_NODE:
@@ -7623,16 +7624,17 @@ nsIDocument::AdoptNode(nsINode& aAdopted
       break;
     }
     case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
     {
       if (ShadowRoot::FromNode(adoptedNode)) {
         rv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
         return nullptr;
       }
+      MOZ_FALLTHROUGH;
     }
     case nsIDOMNode::ELEMENT_NODE:
     case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
     case nsIDOMNode::TEXT_NODE:
     case nsIDOMNode::CDATA_SECTION_NODE:
     case nsIDOMNode::COMMENT_NODE:
     case nsIDOMNode::DOCUMENT_TYPE_NODE:
     {
@@ -7914,16 +7916,17 @@ nsDocument::GetViewportInfo(const Screen
     }
 
     mScaleStrEmpty = scaleStr.IsEmpty();
     mWidthStrEmpty = widthStr.IsEmpty();
     mValidScaleFloat = !scaleStr.IsEmpty() && NS_SUCCEEDED(scaleErrorCode);
     mValidMaxScale = !maxScaleStr.IsEmpty() && NS_SUCCEEDED(scaleMaxErrorCode);
 
     mViewportType = Specified;
+    MOZ_FALLTHROUGH;
   }
   case Specified:
   default:
     LayoutDeviceToScreenScale effectiveMinScale = mScaleMinFloat;
     LayoutDeviceToScreenScale effectiveMaxScale = mScaleMaxFloat;
     bool effectiveValidMaxScale = mValidMaxScale;
     bool effectiveAllowZoom = mAllowZoom;
     if (gfxPrefs::ForceUserScalable()) {
--- a/dom/base/nsDocumentEncoder.cpp
+++ b/dom/base/nsDocumentEncoder.cpp
@@ -1095,16 +1095,19 @@ nsDocumentEncoder::EncodeToStringWithMax
     return NS_ERROR_NOT_INITIALIZED;
 
   aOutputString.Truncate();
 
   nsString output;
   static const size_t bufferSize = 2048;
   if (!mCachedBuffer) {
     mCachedBuffer = nsStringBuffer::Alloc(bufferSize).take();
+    if (NS_WARN_IF(!mCachedBuffer)) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
   }
   NS_ASSERTION(!mCachedBuffer->IsReadonly(),
                "DocumentEncoder shouldn't keep reference to non-readonly buffer!");
   static_cast<char16_t*>(mCachedBuffer->Data())[0] = char16_t(0);
   mCachedBuffer->ToString(0, output, true);
   // output owns the buffer now!
   mCachedBuffer = nullptr;
   
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -776,16 +776,17 @@ nsFrameLoader::MarginsChanged(uint32_t a
   if (presContext)
     presContext->RebuildAllStyleData(nsChangeHint(0), eRestyle_Subtree);
 }
 
 bool
 nsFrameLoader::ShowRemoteFrame(const ScreenIntSize& size,
                                nsSubDocumentFrame *aFrame)
 {
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::GRAPHICS);
   NS_ASSERTION(IsRemoteFrame(), "ShowRemote only makes sense on remote frames.");
 
   if (!mRemoteBrowser && !TryRemoteBrowser()) {
     NS_ERROR("Couldn't create child process.");
     return false;
   }
 
   // FIXME/bug 589337: Show()/Hide() is pretty expensive for
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -7596,16 +7596,17 @@ nsGlobalWindow::RevisePopupAbuseLevel(Po
 
   PopupControlState abuse = aControl;
   switch (abuse) {
   case openControlled:
   case openAbused:
   case openOverridden:
     if (PopupWhitelisted())
       abuse = PopupControlState(abuse - 1);
+    break;
   case openAllowed: break;
   default:
     NS_WARNING("Strange PopupControlState!");
   }
 
   // limit the number of simultaneously open popups
   if (abuse == openAbused || abuse == openControlled) {
     int32_t popupMax = Preferences::GetInt("dom.popup_maximum", -1);
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -1330,16 +1330,18 @@ nsJSContext::ShrinkGCBuffersNow()
   KillShrinkGCBuffersTimer();
 
   JS::ShrinkGCBuffers(sRuntime);
 }
 
 static void
 FinishAnyIncrementalGC()
 {
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::GC);
+
   if (sCCLockedOut) {
     // We're in the middle of an incremental GC, so finish it.
     JS::PrepareForIncrementalGC(sRuntime);
     JS::FinishIncrementalGC(sRuntime, JS::gcreason::CC_FORCED);
   }
 }
 
 static void
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -3097,16 +3097,17 @@ nsObjectLoadingContent::DoStopPlugin(nsP
 
   TeardownProtoChain();
   mIsStopping = false;
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::StopPluginInstance()
 {
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
   // Clear any pending events
   mPendingInstantiateEvent = nullptr;
   mPendingCheckPluginStopEvent = nullptr;
 
   // If we're currently instantiating, clearing this will cause
   // InstantiatePluginInstance's re-entrance check to destroy the created plugin
   mInstantiating = false;
 
--- a/dom/base/nsXMLContentSerializer.cpp
+++ b/dom/base/nsXMLContentSerializer.cpp
@@ -14,16 +14,17 @@
 
 #include "nsGkAtoms.h"
 #include "nsIDOMProcessingInstruction.h"
 #include "nsIDOMComment.h"
 #include "nsIDOMDocumentType.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsIDocumentEncoder.h"
+#include "nsIParserService.h"
 #include "nsNameSpaceManager.h"
 #include "nsTextFragment.h"
 #include "nsString.h"
 #include "prprf.h"
 #include "nsUnicharUtils.h"
 #include "nsCRT.h"
 #include "nsContentUtils.h"
 #include "nsAttrName.h"
@@ -1424,17 +1425,17 @@ nsXMLContentSerializer::AppendFormatedWr
   bool sawBlankOrTab = false;
   bool leaveLoop = false;
 
   do {
     switch (*aPos) {
       case ' ':
       case '\t':
         sawBlankOrTab = true;
-        // no break
+        MOZ_FALLTHROUGH;
       case '\n':
         ++aPos;
         // do not increase mColPos,
         // because we will reduce the whitespace to a single char
         break;
       default:
         leaveLoop = true;
         break;
--- a/dom/base/test/test_bug1187157.html
+++ b/dom/base/test/test_bug1187157.html
@@ -11,19 +11,18 @@ https://bugzilla.mozilla.org/show_bug.cg
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=789315">Mozilla Bug 789315</a>
 <form id="a"><input name="b" type="file"/></form>
 
 <script type="text/javascript">
   var obj = new FormData(document.getElementById('a')).get('b');
 
-  ok(obj instanceof File, "This should return an empty File");
+  ok(obj instanceof Blob, "This should return an empty Blob");
   is(obj.size, 0, "Size should be 0");
-  is(obj.name, "", "Name should be an empty string");
   is(obj.type, "application/octet-stream", "Type should be application/octet-stream");
 
   var o = obj.slice(10, 100, "foo/bar");
   is(o.size, 0, "The new blob has size 0");
   is(o.type, "foo/bar", "The new blob has type foo/bar");
 </script>
 
 </body>
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -8767,17 +8767,17 @@ class CGMemberJITInfo(CGThing):
         assert(not alwaysInSlot or eliminatable)  # Things always in slots had better be eliminatable
 
         def jitInfoInitializer(isTypedMethod):
             initializer = fill(
                 """
                 {
                   { ${opName} },
                   { prototypes::id::${name} },
-                  PrototypeTraits<prototypes::id::${name}>::Depth,
+                  { PrototypeTraits<prototypes::id::${name}>::Depth },
                   JSJitInfo::${opType},
                   JSJitInfo::${aliasSet}, /* aliasSet.  Not relevant for setters. */
                   ${returnType},  /* returnType.  Not relevant for setters. */
                   ${isInfallible},  /* isInfallible. False in setters. */
                   ${isMovable},  /* isMovable.  Not relevant for setters. */
                   ${isEliminatable}, /* isEliminatable.  Not relevant for setters. */
                   ${isAlwaysInSlot}, /* isAlwaysInSlot.  Only relevant for getters. */
                   ${isLazilyCachedInSlot}, /* isLazilyCachedInSlot.  Only relevant for getters. */
@@ -9147,17 +9147,17 @@ class CGStaticMethodJitinfo(CGGeneric):
     A class for generating the JITInfo for a promise-returning static method.
     """
     def __init__(self, method):
         CGGeneric.__init__(
             self,
             "\n"
             "static const JSJitInfo %s_methodinfo = {\n"
             "  { (JSJitGetterOp)%s },\n"
-            "  { prototypes::id::_ID_Count }, 0, JSJitInfo::StaticMethod,\n"
+            "  { prototypes::id::_ID_Count }, { 0 }, JSJitInfo::StaticMethod,\n"
             "  JSJitInfo::AliasEverything, JSVAL_TYPE_MISSING, false, false,\n"
             "  false, false, 0\n"
             "};\n" %
             (IDLToCIdentifier(method.identifier.name),
              CppKeywords.checkMethodName(
                  IDLToCIdentifier(method.identifier.name))))
 
 
--- a/dom/bindings/moz.build
+++ b/dom/bindings/moz.build
@@ -134,13 +134,8 @@ if CONFIG['MOZ_BUILD_APP'] in ['browser'
 
 
 if CONFIG['MOZ_SIMPLEPUSH']:
     DEFINES['MOZ_SIMPLEPUSH'] = True
 
 PYTHON_UNIT_TESTS += [
     'mozwebidlcodegen/test/test_mozwebidlcodegen.py',
 ]
-
-if CONFIG['GNU_CC']:
-    CXXFLAGS += [
-        '-Wno-uninitialized',
-    ]
--- a/dom/bindings/test/moz.build
+++ b/dom/bindings/test/moz.build
@@ -47,13 +47,8 @@ LOCAL_INCLUDES += [
 ]
 
 LOCAL_INCLUDES += [
     '!..',
     '/dom/bindings',
     '/js/xpconnect/src',
     '/js/xpconnect/wrappers',
 ]
-
-if CONFIG['GNU_CC']:
-    CXXFLAGS += [
-        '-Wno-uninitialized',
-    ]
--- a/dom/bluetooth/common/webapi/BluetoothGatt.cpp
+++ b/dom/bluetooth/common/webapi/BluetoothGatt.cpp
@@ -107,35 +107,35 @@ BluetoothGatt::Connect(ErrorResult& aRv)
   BT_ENSURE_TRUE_REJECT(
     mConnectionState == BluetoothConnectionState::Disconnected,
     promise,
     NS_ERROR_DOM_INVALID_STATE_ERR);
 
   BluetoothService* bs = BluetoothService::Get();
   BT_ENSURE_TRUE_REJECT(bs, promise, NS_ERROR_NOT_AVAILABLE);
 
-  BluetoothUuid appUuid;
-  BT_ENSURE_TRUE_REJECT(NS_SUCCEEDED(StringToUuid(mAppUuid, appUuid)),
-                        promise,
-                        NS_ERROR_DOM_OPERATION_ERR);
-
   BluetoothAddress deviceAddr;
   BT_ENSURE_TRUE_REJECT(
     NS_SUCCEEDED(StringToAddress(mDeviceAddr, deviceAddr)),
     promise,
     NS_ERROR_DOM_OPERATION_ERR);
 
   if (mAppUuid.IsEmpty()) {
     nsresult rv = GenerateUuid(mAppUuid);
     BT_ENSURE_TRUE_REJECT(NS_SUCCEEDED(rv) && !mAppUuid.IsEmpty(),
                           promise,
                           NS_ERROR_DOM_OPERATION_ERR);
     RegisterBluetoothSignalHandler(mAppUuid, this);
   }
 
+  BluetoothUuid appUuid;
+  BT_ENSURE_TRUE_REJECT(NS_SUCCEEDED(StringToUuid(mAppUuid, appUuid)),
+                        promise,
+                        NS_ERROR_DOM_OPERATION_ERR);
+
   UpdateConnectionState(BluetoothConnectionState::Connecting);
   bs->ConnectGattClientInternal(
     appUuid, deviceAddr, new BluetoothVoidReplyRunnable(nullptr, promise));
 
   return promise.forget();
 }
 
 already_AddRefed<Promise>
--- a/dom/cache/AutoUtils.cpp
+++ b/dom/cache/AutoUtils.cpp
@@ -478,16 +478,17 @@ AutoParentOpResult::~AutoParentOpResult(
     }
     case CacheOpResult::TStorageOpenResult:
     {
       StorageOpenResult& result = mOpResult.get_StorageOpenResult();
       if (action == Forget || result.actorParent() == nullptr) {
         break;
       }
       Unused << PCacheParent::Send__delete__(result.actorParent());
+      break;
     }
     default:
       // other types do not need clean up
       break;
   }
 
   if (action == Delete && mStreamControl) {
     Unused << PCacheStreamControlParent::Send__delete__(mStreamControl);
--- a/dom/canvas/WebGL2ContextState.cpp
+++ b/dom/canvas/WebGL2ContextState.cpp
@@ -107,16 +107,17 @@ WebGL2Context::GetParameter(JSContext* c
 
     case LOCAL_GL_MAX_ELEMENT_INDEX:
       // GL_MAX_ELEMENT_INDEX becomes available in GL 4.3 or via ES3
       // compatibility
       if (!gl->IsSupported(gl::GLFeature::ES3_compatibility))
         return JS::NumberValue(0);
 
       /*** fall through to fGetInteger64v ***/
+      MOZ_FALLTHROUGH;
 
     case LOCAL_GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS:
     case LOCAL_GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS:
     case LOCAL_GL_MAX_UNIFORM_BLOCK_SIZE: {
       GLint64 val;
       gl->fGetInteger64v(pname, &val);
       return JS::DoubleValue(static_cast<double>(val));
     }
--- a/dom/canvas/WebGLVertexAttribData.h
+++ b/dom/canvas/WebGLVertexAttribData.h
@@ -47,22 +47,28 @@ struct WebGLVertexAttribData
             return sizeof(GLubyte);
 
         case LOCAL_GL_SHORT:
             return sizeof(GLshort);
 
         case LOCAL_GL_UNSIGNED_SHORT:
             return sizeof(GLushort);
 
+        case LOCAL_GL_INT:
+            return sizeof(GLint);
+
+        case LOCAL_GL_UNSIGNED_INT:
+            return sizeof(GLuint);
+
         // case LOCAL_GL_FIXED:
         case LOCAL_GL_FLOAT:
             return sizeof(GLfloat);
 
         default:
-            NS_ERROR("Should never get here!");
+            MOZ_ASSERT(false, "Should never get here!");
             return 0;
         }
     }
 
     GLuint actualStride() const {
         if (stride)
             return stride;
 
--- a/dom/canvas/moz.build
+++ b/dom/canvas/moz.build
@@ -53,17 +53,16 @@ UNIFIED_SOURCES += [
     'ImageBitmap.cpp',
     'ImageBitmapRenderingContext.cpp',
     'ImageData.cpp',
     'OffscreenCanvas.cpp',
 ]
 
 # WebGL Sources
 UNIFIED_SOURCES += [
-    'MurmurHash3.cpp',
     'TexUnpackBlob.cpp',
     'WebGL1Context.cpp',
     'WebGL1ContextBuffers.cpp',
     'WebGL1ContextUniforms.cpp',
     'WebGL2Context.cpp',
     'WebGL2ContextBuffers.cpp',
     'WebGL2ContextDraw.cpp',
     'WebGL2ContextFramebuffers.cpp',
@@ -144,16 +143,24 @@ UNIFIED_SOURCES += [
     'WebGLUniformLocation.cpp',
     'WebGLValidateStrings.cpp',
     'WebGLVertexArray.cpp',
     'WebGLVertexArrayFake.cpp',
     'WebGLVertexArrayGL.cpp',
     'WebGLVertexArrayObject.cpp',
 ]
 
+SOURCES += [
+    'MurmurHash3.cpp',
+]
+
+# Suppress warnings from third-party code.
+if CONFIG['CLANG_CXX']:
+    SOURCES['MurmurHash3.cpp'].flags += ['-Wno-implicit-fallthrough']
+
 LOCAL_INCLUDES += [
     '/js/xpconnect/wrappers',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 LOCAL_INCLUDES += [
--- a/dom/events/test/test_bug328885.html
+++ b/dom/events/test/test_bug328885.html
@@ -108,17 +108,17 @@ https://bugzilla.mozilla.org/show_bug.cg
           function (evt2) {
             evt.originalTarget.textContent =  "bar" + mutationCount;
           }, false);
         // This one deletes and inserts a new node, then DOMSubtreeModified.
         inputelement.textContent = "bar";
         ok(mutationCount == 19, "(20) Mutation listener should have been called! ["+ mutationCount + "]");
       }
     ,false);
-    synthesizeMouseAtPoint(5, 5, {}, window);
+    synthesizeMouseAtCenter(inputelement, {}, window);
     SimpleTest.finish();
   }
 
   function doTest() {
     inputelement = document.getElementById('inputelement');
     inputelement.focus();
     setTimeout(clickTest, 100);
   }
--- a/dom/geolocation/nsGeolocation.cpp
+++ b/dom/geolocation/nsGeolocation.cpp
@@ -1250,29 +1250,31 @@ Geolocation::Init(nsIDOMWindow* aContent
                                   /* use capture */ true,
                                   /* wants untrusted */ false);
     }
 
     nsCOMPtr<nsIURI> uri;
     nsresult rv = mPrincipal->GetURI(getter_AddRefs(uri));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    bool isHttp;
-    rv = uri->SchemeIs("http", &isHttp);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (uri) {
+      bool isHttp;
+      rv = uri->SchemeIs("http", &isHttp);
+      NS_ENSURE_SUCCESS(rv, rv);
 
-    bool isHttps;
-    rv = uri->SchemeIs("https", &isHttps);
-    NS_ENSURE_SUCCESS(rv, rv);
+      bool isHttps;
+      rv = uri->SchemeIs("https", &isHttps);
+      NS_ENSURE_SUCCESS(rv, rv);
 
-    // Store the protocol to send via telemetry later.
-    if (isHttp) {
-      mProtocolType = ProtocolType::HTTP;
-    } else if (isHttps) {
-      mProtocolType = ProtocolType::HTTPS;
+      // Store the protocol to send via telemetry later.
+      if (isHttp) {
+        mProtocolType = ProtocolType::HTTP;
+      } else if (isHttps) {
+        mProtocolType = ProtocolType::HTTPS;
+      }
     }
   }
 
   // If no aContentDom was passed into us, we are being used
   // by chrome/c++ and have no mOwner, no mPrincipal, and no need
   // to prompt.
   mService = nsGeolocationService::GetGeolocationService();
   if (mService) {
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -3801,16 +3801,17 @@ HTMLInputElement::PostHandleEvent(EventC
               {
                 // Checkbox and Radio try to submit on Enter press
                 if (keyEvent->keyCode != NS_VK_SPACE) {
                   MaybeSubmitForm(aVisitor.mPresContext);
 
                   break;  // If we are submitting, do not send click event
                 }
                 // else fall through and treat Space like click...
+                MOZ_FALLTHROUGH;
               }
               case NS_FORM_INPUT_BUTTON:
               case NS_FORM_INPUT_RESET:
               case NS_FORM_INPUT_SUBMIT:
               case NS_FORM_INPUT_IMAGE: // Bug 34418
               case NS_FORM_INPUT_COLOR:
               {
                 WidgetMouseEvent event(aVisitor.mEvent->mFlags.mIsTrusted,
@@ -3829,17 +3830,17 @@ HTMLInputElement::PostHandleEvent(EventC
           if (aVisitor.mEvent->mMessage == eKeyPress &&
               mType == NS_FORM_INPUT_RADIO && !keyEvent->IsAlt() &&
               !keyEvent->IsControl() && !keyEvent->IsMeta()) {
             bool isMovingBack = false;
             switch (keyEvent->keyCode) {
               case NS_VK_UP:
               case NS_VK_LEFT:
                 isMovingBack = true;
-                // FALLTHROUGH
+                MOZ_FALLTHROUGH;
               case NS_VK_DOWN:
               case NS_VK_RIGHT:
               // Arrow key pressed, focus+select prev/next radio button
               nsIRadioGroupContainer* container = GetRadioGroupContainer();
               if (container) {
                 nsAutoString name;
                 GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
                 RefPtr<HTMLInputElement> selectedRadioButton;
@@ -5566,24 +5567,24 @@ HTMLInputElement::SubmitNamesValues(nsFo
   // Submit file if its input type=file and this encoding method accepts files
   //
   if (mType == NS_FORM_INPUT_FILE) {
     // Submit files
 
     const nsTArray<RefPtr<File>>& files = GetFilesInternal();
 
     for (uint32_t i = 0; i < files.Length(); ++i) {
-      aFormSubmission->AddNameFilePair(name, files[i]);
+      aFormSubmission->AddNameBlobPair(name, files[i]);
     }
 
     if (files.IsEmpty()) {
       RefPtr<BlobImpl> blobImpl =
-        new BlobImplEmptyFile(NS_LITERAL_STRING("application/octet-stream"));
-      RefPtr<File> file = File::Create(OwnerDoc()->GetInnerWindow(), blobImpl);
-      aFormSubmission->AddNameFilePair(name, file);
+        new EmptyBlobImpl(NS_LITERAL_STRING("application/octet-stream"));
+      RefPtr<Blob> blob = Blob::Create(OwnerDoc()->GetInnerWindow(), blobImpl);
+      aFormSubmission->AddNameBlobPair(name, blob);
     }
 
     return NS_OK;
   }
 
   if (mType == NS_FORM_INPUT_HIDDEN && name.EqualsLiteral("_charset_")) {
     nsCString charset;
     aFormSubmission->GetCharset(charset);
--- a/dom/html/nsFormSubmission.cpp
+++ b/dom/html/nsFormSubmission.cpp
@@ -49,16 +49,27 @@ SendJSWarning(nsIDocument* aDocument,
 {
   nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                   NS_LITERAL_CSTRING("HTML"), aDocument,
                                   nsContentUtils::eFORMS_PROPERTIES,
                                   aWarningName,
                                   aWarningArgs, aWarningArgsLen);
 }
 
+static void
+RetrieveFileName(Blob* aBlob, nsAString& aFilename)
+{
+  MOZ_ASSERT(aBlob);
+
+  RefPtr<File> file = aBlob->ToFile();
+  if (file) {
+    file->GetName(aFilename);
+  }
+}
+
 // --------------------------------------------------------------------------
 
 class nsFSURLEncoded : public nsEncodingFormSubmission
 {
 public:
   /**
    * @param aCharset the charset of the form as a string
    * @param aMethod the method of the submit (either NS_FORM_METHOD_GET or
@@ -72,18 +83,18 @@ public:
       mMethod(aMethod),
       mDocument(aDocument),
       mWarnedFileControl(false)
   {
   }
 
   virtual nsresult AddNameValuePair(const nsAString& aName,
                                     const nsAString& aValue) override;
-  virtual nsresult AddNameFilePair(const nsAString& aName,
-                                   File* aFile) override;
+  virtual nsresult AddNameBlobPair(const nsAString& aName,
+                                   Blob* aBlob) override;
   virtual nsresult GetEncodedSubmission(nsIURI* aURI,
                                         nsIInputStream** aPostDataStream)
                                                                        override;
 
   virtual bool SupportsIsindexSubmission() override
   {
     return true;
   }
@@ -159,29 +170,28 @@ nsFSURLEncoded::AddIsindex(const nsAStri
   } else {
     mQueryString += NS_LITERAL_CSTRING("&isindex=") + convValue;
   }
 
   return NS_OK;
 }
 
 nsresult
-nsFSURLEncoded::AddNameFilePair(const nsAString& aName,
-                                File* aFile)
+nsFSURLEncoded::AddNameBlobPair(const nsAString& aName,
+                                Blob* aBlob)
 {
-  MOZ_ASSERT(aFile);
+  MOZ_ASSERT(aBlob);
 
   if (!mWarnedFileControl) {
     SendJSWarning(mDocument, "ForgotFileEnctypeWarning", nullptr, 0);
     mWarnedFileControl = true;
   }
 
   nsAutoString filename;
-  aFile->GetName(filename);
-
+  RetrieveFileName(aBlob, filename);
   return AddNameValuePair(aName, filename);
 }
 
 static void
 HandleMailtoSubject(nsCString& aPath) {
 
   // Walk through the string and see if we have a subject already.
   bool hasSubject = false;
@@ -433,61 +443,64 @@ nsFSMultipartFormData::AddNameValuePair(
                  + NS_LITERAL_CSTRING("Content-Disposition: form-data; name=\"")
                  + nameStr + NS_LITERAL_CSTRING("\"" CRLF CRLF)
                  + valueStr + NS_LITERAL_CSTRING(CRLF);
 
   return NS_OK;
 }
 
 nsresult
-nsFSMultipartFormData::AddNameFilePair(const nsAString& aName,
-                                       File* aFile)
+nsFSMultipartFormData::AddNameBlobPair(const nsAString& aName,
+                                       Blob* aBlob)
 {
-  MOZ_ASSERT(aFile);
+  MOZ_ASSERT(aBlob);
 
   // Encode the control name
   nsAutoCString nameStr;
   nsresult rv = EncodeVal(aName, nameStr, true);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoString filename16;
-  aFile->GetName(filename16);
+  RetrieveFileName(aBlob, filename16);
 
   ErrorResult error;
   nsAutoString filepath16;
-  aFile->GetPath(filepath16, error);
-  if (NS_WARN_IF(error.Failed())) {
-    return error.StealNSResult();
+  RefPtr<File> file = aBlob->ToFile();
+  if (file) {
+    file->GetPath(filepath16, error);
+    if (NS_WARN_IF(error.Failed())) {
+      return error.StealNSResult();
+    }
   }
 
   if (!filepath16.IsEmpty()) {
     // File.path includes trailing "/"
     filename16 = filepath16 + filename16;
   }
 
   nsAutoCString filename;
   rv = EncodeVal(filename16, filename, true);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Get content type
   nsAutoString contentType16;
-  aFile->GetType(contentType16);
+  aBlob->GetType(contentType16);
   if (contentType16.IsEmpty()) {
     contentType16.AssignLiteral("application/octet-stream");
   }
 
   nsAutoCString contentType;
   contentType.Adopt(nsLinebreakConverter::
                     ConvertLineBreaks(NS_ConvertUTF16toUTF8(contentType16).get(),
                                       nsLinebreakConverter::eLinebreakAny,
                                       nsLinebreakConverter::eLinebreakSpace));
 
   // Get input stream
   nsCOMPtr<nsIInputStream> fileStream;
-  aFile->GetInternalStream(getter_AddRefs(fileStream), error);
+  aBlob->GetInternalStream(getter_AddRefs(fileStream), error);
   if (NS_WARN_IF(error.Failed())) {
     return error.StealNSResult();
   }
 
   if (fileStream) {
     // Create buffered stream (for efficiency)
     nsCOMPtr<nsIInputStream> bufferedStream;
     rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
@@ -512,17 +525,17 @@ nsFSMultipartFormData::AddNameFilePair(c
        + filename + NS_LITERAL_CSTRING("\"" CRLF)
        + NS_LITERAL_CSTRING("Content-Type: ")
        + contentType + NS_LITERAL_CSTRING(CRLF CRLF);
 
   // We should not try to append an invalid stream. That will happen for example
   // if we try to update a file that actually do not exist.
   if (fileStream) {
     ErrorResult error;
-    uint64_t size = aFile->GetSize(error);
+    uint64_t size = aBlob->GetSize(error);
     if (error.Failed()) {
       error.SuppressException();
     } else {
       // We need to dump the data up to this point into the POST data stream
       // here, since we're about to add the file input stream
       AddPostDataStream();
 
       mPostDataStream->AppendStream(fileStream);
@@ -585,18 +598,18 @@ class nsFSTextPlain : public nsEncodingF
 public:
   nsFSTextPlain(const nsACString& aCharset, nsIContent* aOriginatingElement)
     : nsEncodingFormSubmission(aCharset, aOriginatingElement)
   {
   }
 
   virtual nsresult AddNameValuePair(const nsAString& aName,
                                     const nsAString& aValue) override;
-  virtual nsresult AddNameFilePair(const nsAString& aName,
-                                   File* aFile) override;
+  virtual nsresult AddNameBlobPair(const nsAString& aName,
+                                   Blob* aBlob) override;
   virtual nsresult GetEncodedSubmission(nsIURI* aURI,
                                         nsIInputStream** aPostDataStream)
                                                                        override;
 
 private:
   nsString mBody;
 };
 
@@ -609,22 +622,23 @@ nsFSTextPlain::AddNameValuePair(const ns
   // values so we'll have to live with it.
   mBody.Append(aName + NS_LITERAL_STRING("=") + aValue +
                NS_LITERAL_STRING(CRLF));
 
   return NS_OK;
 }
 
 nsresult
-nsFSTextPlain::AddNameFilePair(const nsAString& aName,
-                               File* aFile)
+nsFSTextPlain::AddNameBlobPair(const nsAString& aName,
+                               Blob* aBlob)
 {
+  MOZ_ASSERT(aBlob);
+
   nsAutoString filename;
-  aFile->GetName(filename);
-
+  RetrieveFileName(aBlob, filename);
   AddNameValuePair(aName, filename);
   return NS_OK;
 }
 
 nsresult
 nsFSTextPlain::GetEncodedSubmission(nsIURI* aURI,
                                     nsIInputStream** aPostDataStream)
 {
--- a/dom/html/nsFormSubmission.h
+++ b/dom/html/nsFormSubmission.h
@@ -14,17 +14,17 @@
 
 class nsIURI;
 class nsIInputStream;
 class nsGenericHTMLElement;
 class nsIMultiplexInputStream;
 
 namespace mozilla {
 namespace dom {
-class File;
+class Blob;
 } // namespace dom
 } // namespace mozilla
 
 /**
  * Class for form submissions; encompasses the function to call to submit as
  * well as the form submission name/value pairs
  */
 class nsFormSubmission
@@ -40,23 +40,24 @@ public:
    *
    * @param aName the name of the parameter
    * @param aValue the value of the parameter
    */
   virtual nsresult AddNameValuePair(const nsAString& aName,
                                     const nsAString& aValue) = 0;
 
   /**
-   * Submit a name/file pair
+   * Submit a name/blob pair
    *
    * @param aName the name of the parameter
-   * @param aFile the file to submit. The file's name will be used
+   * @param aBlob the blob to submit. The file's name will be used if the Blob
+   * is actually a File, otherwise 'blob' string is used instead.
    */
-  virtual nsresult AddNameFilePair(const nsAString& aName,
-                                   mozilla::dom::File* aFile) = 0;
+  virtual nsresult AddNameBlobPair(const nsAString& aName,
+                                   mozilla::dom::Blob* aBlob) = 0;
 
   /**
    * Reports whether the instance supports AddIsindex().
    *
    * @return true if supported.
    */
   virtual bool SupportsIsindexSubmission()
   {
@@ -154,18 +155,18 @@ public:
    * @param aCharset the charset of the form as a string
    */
   nsFSMultipartFormData(const nsACString& aCharset,
                         nsIContent* aOriginatingElement);
   ~nsFSMultipartFormData();
  
   virtual nsresult AddNameValuePair(const nsAString& aName,
                                     const nsAString& aValue) override;
-  virtual nsresult AddNameFilePair(const nsAString& aName,
-                                   mozilla::dom::File* aFile) override;
+  virtual nsresult AddNameBlobPair(const nsAString& aName,
+                                   mozilla::dom::Blob* aBlob) override;
   virtual nsresult GetEncodedSubmission(nsIURI* aURI,
                                         nsIInputStream** aPostDataStream) override;
 
   void GetContentType(nsACString& aContentType)
   {
     aContentType =
       NS_LITERAL_CSTRING("multipart/form-data; boundary=") + mBoundary;
   }
--- a/dom/html/test/formData_test.js
+++ b/dom/html/test/formData_test.js
@@ -72,25 +72,21 @@ function testSet() {
   f.append("other", "value3");
   is(f.getAll("other").length, 5, "append() should not replace existing entries.");
 
   f.set("other", "value4");
   is(f.getAll("other").length, 1, "set() should replace existing entries.");
   is(f.getAll("other")[0], "value4", "set() should replace existing entries.");
 }
 
-function testIterate() {
-  todo(false, "Implement this in Bug 1085284.");
-}
-
 function testFilename() {
   var f = new FormData();
   // Spec says if a Blob (which is not a File) is added, the name parameter is set to "blob".
   f.append("blob", new Blob(["hi"]));
-  is(f.get("blob").name, "blob", "Blob's filename should be blob.");
+  ok(f.get("blob") instanceof Blob, "We should have a blob back.");
 
   // If a filename is passed, that should replace the original.
   f.append("blob2", new Blob(["hi"]), "blob2.txt");
   is(f.get("blob2").name, "blob2.txt", "Explicit filename should override \"blob\".");
 
   var file = new File(["hi"], "file1.txt");
   f.append("file1", file);
   // If a file is passed, the "create entry" algorithm should not create a new File, but reuse the existing one.
@@ -204,15 +200,14 @@ function testSend(doneCb) {
 }
 
 function runTest(doneCb) {
   testHas();
   testGet();
   testGetAll();
   testDelete();
   testSet();
-  testIterate();
   testFilename();
   testIterable();
   // Finally, send an XHR and verify the response matches.
   testSend(doneCb);
 }
 
--- a/dom/html/test/test_formSubmission.html
+++ b/dom/html/test/test_formSubmission.html
@@ -585,17 +585,17 @@ var expectedAugment = [
   { name: "aNameNum", value: "9.2" },
   { name: "aNameFile1", value: placeholder_myFile1 },
   { name: "aNameFile2", value: placeholder_myFile2 },
   //{ name: "aNameObj", value: "[object XMLHttpRequest]" },
   //{ name: "aNameNull", value: "null" },
   //{ name: "aNameUndef", value: "undefined" },
 ];
 
-function checkMPSubmission(sub, expected, test) {
+function checkMPSubmission(sub, expected, test, isFormData = false) {
   function getPropCount(o) {
     var x, l = 0;
     for (x in o) ++l;
     return l;
   }
   function mpquote(s) {
     return s.replace(/\r\n/g, " ")
             .replace(/\r/g, " ")
@@ -620,17 +620,17 @@ function checkMPSubmission(sub, expected
           "Wrong number of headers in " + test);
       is(sub[i].body,
          expected[i].value.replace(/\r\n|\r|\n/, "\r\n"),
          "Correct value in " + test);
     }
     else {
       is(sub[i].headers["Content-Disposition"],
          "form-data; name=\"" + mpquote(expected[i].name) + "\"; filename=\"" +
-           mpquote(expected[i].fileName) + "\"",
+           mpquote(expected[i].fileName != "" || !isFormData ? expected[i].fileName : "blob") + "\"",
          "Correct name in " + test);
       is(sub[i].headers["Content-Type"],
          expected[i].contentType,
          "Correct content type in " + test);
       is (getPropCount(sub[i].headers), 2,
           "Wrong number of headers in " + test);
       is(sub[i].body,
          expected[i].value,
@@ -777,48 +777,48 @@ function runTest() {
   checkURLSubmission(submission, expectedSub);
 
   // Send form using XHR and FormData
   xhr = new XMLHttpRequest();
   xhr.onload = function() { gen.next(); };
   xhr.open("POST", "form_submit_server.sjs");
   xhr.send(new FormData(form));
   yield undefined; // Wait for XHR load
-  checkMPSubmission(JSON.parse(xhr.responseText), expectedSub, "send form using XHR and FormData");
+  checkMPSubmission(JSON.parse(xhr.responseText), expectedSub, "send form using XHR and FormData", true);
   
   // Send disabled form using XHR and FormData
   setDisabled(document.querySelectorAll("input, select, textarea"), true);
   xhr.open("POST", "form_submit_server.sjs");
   xhr.send(new FormData(form));
   yield undefined;
-  checkMPSubmission(JSON.parse(xhr.responseText), [], "send disabled form using XHR and FormData");
+  checkMPSubmission(JSON.parse(xhr.responseText), [], "send disabled form using XHR and FormData", true);
   setDisabled(document.querySelectorAll("input, select, textarea"), false);
   
   // Send FormData
   function addToFormData(fd) {
     fd.append("aName", "aValue");
     fd.append("aNameNum", 9.2);
     fd.append("aNameFile1", myFile1);
     fd.append("aNameFile2", myFile2);
   }
   var fd = new FormData();
   addToFormData(fd);
   xhr.open("POST", "form_submit_server.sjs");
   xhr.send(fd);
   yield undefined;
-  checkMPSubmission(JSON.parse(xhr.responseText), expectedAugment, "send FormData");
+  checkMPSubmission(JSON.parse(xhr.responseText), expectedAugment, "send FormData", true);
 
   // Augment <form> using FormData
   fd = new FormData(form);
   addToFormData(fd);
   xhr.open("POST", "form_submit_server.sjs");
   xhr.send(fd);
   yield undefined;
   checkMPSubmission(JSON.parse(xhr.responseText),
-                    expectedSub.concat(expectedAugment), "send augmented FormData");
+                    expectedSub.concat(expectedAugment), "send augmented FormData", true);
 
   SimpleTest.finish();
   yield undefined;
 }
 
 </script>
 </pre>
 </body>
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -23223,18 +23223,19 @@ NormalJSRuntime::Init()
 
   mContext = JS_NewContext(mRuntime, 0);
   if (NS_WARN_IF(!mContext)) {
     return false;
   }
 
   JSAutoRequest ar(mContext);
 
+  JS::CompartmentOptions options;
   mGlobal = JS_NewGlobalObject(mContext, &kGlobalClass, nullptr,
-                               JS::FireOnNewGlobalHook);
+                               JS::FireOnNewGlobalHook, options);
   if (NS_WARN_IF(!mGlobal)) {
     return false;
   }
 
   return true;
 }
 
 // static
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -44,17 +44,17 @@ interface nsIDOMClientRect;
 interface nsIURI;
 interface nsIDOMEventTarget;
 interface nsIRunnable;
 interface nsITranslationNodeList;
 interface nsIJSRAIIHelper;
 interface nsIContentPermissionRequest;
 interface nsIObserver;
 
-[scriptable, uuid(7846c43d-e131-40a6-8417-3be2c7e11df1)]
+[scriptable, uuid(ca6a458c-82e7-4979-886e-6d214eac6f0b)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -1454,16 +1454,21 @@ interface nsIDOMWindowUtils : nsISupport
    * triggered and an "apz-repaints-flushed" notification will be dispatched via
    * the observer service once the flush is complete. If the function returns
    * false, an error occurred or a flush is not needed, and the notification
    * will not fire. This is intended to be used by test code only!
    */
   bool flushApzRepaints();
 
   /**
+   * Ask APZ to pan and zoom to the focused input element.
+   */
+  void zoomToFocusedInput();
+
+  /**
    * Method for testing StyleAnimationValue::ComputeDistance.
    *
    * Returns the distance between the two values as reported by
    * StyleAnimationValue::ComputeDistance for the given element and
    * property.
    */
   double computeAnimationDistance(in nsIDOMElement element,
                                   in AString property,
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -2808,18 +2808,17 @@ ContentChild::RecvUnregisterSheet(const 
 
   return true;
 }
 
 POfflineCacheUpdateChild*
 ContentChild::AllocPOfflineCacheUpdateChild(const URIParams& manifestURI,
                                             const URIParams& documentURI,
                                             const PrincipalInfo& aLoadingPrincipalInfo,
-                                            const bool& stickDocument,
-                                            const TabId& aTabId)
+                                            const bool& stickDocument)
 {
   NS_RUNTIMEABORT("unused");
   return nullptr;
 }
 
 bool
 ContentChild::DeallocPOfflineCacheUpdateChild(POfflineCacheUpdateChild* actor)
 {
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -569,18 +569,17 @@ public:
 
   PBrowserOrId
   GetBrowserOrId(TabChild* aTabChild);
 
   virtual POfflineCacheUpdateChild*
   AllocPOfflineCacheUpdateChild(const URIParams& manifestURI,
                                 const URIParams& documentURI,
                                 const PrincipalInfo& aLoadingPrincipalInfo,
-                                const bool& stickDocument,
-                                const TabId& aTabId) override;
+                                const bool& stickDocument) override;
 
   virtual bool
   DeallocPOfflineCacheUpdateChild(POfflineCacheUpdateChild* offlineCacheUpdate) override;
 
   virtual PWebrtcGlobalChild* AllocPWebrtcGlobalChild() override;
 
   virtual bool DeallocPWebrtcGlobalChild(PWebrtcGlobalChild *aActor) override;
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1232,16 +1232,18 @@ ContentParent::RecvFindPlugins(const uin
   return true;
 }
 
 /*static*/ TabParent*
 ContentParent::CreateBrowserOrApp(const TabContext& aContext,
                                   Element* aFrameElement,
                                   ContentParent* aOpenerContentParent)
 {
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
+
   if (!sCanLaunchSubprocesses) {
     return nullptr;
   }
 
   if (TabParent* parent = TabParent::GetNextTabParent()) {
     parent->SetOwnerElement(aFrameElement);
     return parent;
   }
@@ -2381,16 +2383,18 @@ ContentParent::InitializeMembers()
   mShutdownPending = false;
   mIPCOpen = true;
   mHangMonitorActor = nullptr;
 }
 
 bool
 ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PRIORITY_FOREGROUND */)
 {
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
+
   std::vector<std::string> extraArgs;
   if (mIsNuwaProcess) {
     extraArgs.push_back("-nuwa");
   }
 
   if (!mSubprocess->LaunchAndWaitForProcessHandle(extraArgs)) {
     MarkAsDead();
     return false;
@@ -3637,16 +3641,18 @@ ContentParent::ForceKillTimerCallback(ns
 
   auto self = static_cast<ContentParent*>(aClosure);
   self->KillHard("ShutDownKill");
 }
 
 void
 ContentParent::KillHard(const char* aReason)
 {
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
+
   // On Windows, calling KillHard multiple times causes problems - the
   // process handle becomes invalid on the first call, causing a second call
   // to crash our process - more details in bug 890840.
   if (mCalledKillHard) {
     return;
   }
   mCalledKillHard = true;
   mForceKillTimer = nullptr;
@@ -5235,38 +5241,30 @@ ContentParent::GetManagedTabContext()
   return Move(ContentProcessManager::GetSingleton()->
           GetTabContextByContentProcess(this->ChildID()));
 }
 
 mozilla::docshell::POfflineCacheUpdateParent*
 ContentParent::AllocPOfflineCacheUpdateParent(const URIParams& aManifestURI,
                                               const URIParams& aDocumentURI,
                                               const PrincipalInfo& aLoadingPrincipalInfo,
-                                              const bool& aStickDocument,
-                                              const TabId& aTabId)
-{
-  TabContext tabContext;
-  if (!ContentProcessManager::GetSingleton()->
-    GetTabContextByProcessAndTabId(this->ChildID(), aTabId, &tabContext)) {
-    return nullptr;
-  }
+                                              const bool& aStickDocument)
+{
   RefPtr<mozilla::docshell::OfflineCacheUpdateParent> update =
-    new mozilla::docshell::OfflineCacheUpdateParent(
-      tabContext.OriginAttributesRef());
+        new mozilla::docshell::OfflineCacheUpdateParent();
   // Use this reference as the IPDL reference.
   return update.forget().take();
 }
 
 bool
 ContentParent::RecvPOfflineCacheUpdateConstructor(POfflineCacheUpdateParent* aActor,
                                                   const URIParams& aManifestURI,
                                                   const URIParams& aDocumentURI,
                                                   const PrincipalInfo& aLoadingPrincipal,
-                                                  const bool& aStickDocument,
-                                                  const TabId& aTabId)
+                                                  const bool& aStickDocument)
 {
   MOZ_ASSERT(aActor);
 
   RefPtr<mozilla::docshell::OfflineCacheUpdateParent> update =
     static_cast<mozilla::docshell::OfflineCacheUpdateParent*>(aActor);
 
   nsresult rv = update->Schedule(aManifestURI, aDocumentURI, aLoadingPrincipal, aStickDocument);
   if (NS_FAILED(rv) && IsAlive()) {
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -452,26 +452,24 @@ public:
                                        const ContentParentId& aCpId) override;
 
   nsTArray<TabContext> GetManagedTabContext();
 
   virtual POfflineCacheUpdateParent*
   AllocPOfflineCacheUpdateParent(const URIParams& aManifestURI,
                                  const URIParams& aDocumentURI,
                                  const PrincipalInfo& aLoadingPrincipalInfo,
-                                 const bool& aStickDocument,
-                                 const TabId& aTabId) override;
+                                 const bool& aStickDocument) override;
 
   virtual bool
   RecvPOfflineCacheUpdateConstructor(POfflineCacheUpdateParent* aActor,
                                      const URIParams& aManifestURI,
                                      const URIParams& aDocumentURI,
                                      const PrincipalInfo& aLoadingPrincipal,
-                                     const bool& stickDocument,
-                                     const TabId& aTabId) override;
+                                     const bool& stickDocument) override;
 
   virtual bool
   DeallocPOfflineCacheUpdateParent(POfflineCacheUpdateParent* aActor) override;
 
   virtual bool RecvSetOfflinePermission(const IPC::Principal& principal) override;
 
   virtual bool RecvFinishShutdown() override;
 
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -415,17 +415,17 @@ parent:
     sync BrowserFrameOpenWindow(PBrowser opener, nsString aURL,
                                 nsString aName, nsString aFeatures)
       returns (bool windowOpened);
 
     /**
      * Instructs the TabParent to forward a request to zoom to a rect given in
      * CSS pixels. This rect is relative to the document.
      */
-    ZoomToRect(uint32_t aPresShellId, ViewID aViewId, CSSRect aRect);
+    ZoomToRect(uint32_t aPresShellId, ViewID aViewId, CSSRect aRect, uint32_t aFlags);
 
     /**
      * We know for sure that content has either preventDefaulted or not
      * preventDefaulted. This applies to an entire batch of touch events. It is
      * expected that, if there are any DOM touch listeners, touch events will be
      * batched and only processed for panning and zooming if content does not
      * preventDefault.
      */
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -1080,18 +1080,17 @@ parent:
      *   cache group update. But we must cache the document (identified by the
      *   documentURI). This argument will ensure that a previously uncached
      *   document will get cached and that we don't re-cache a document that
      *   has already been cached (stickDocument=false).
      * @param tabId
      *   To identify which tab owns the app.
      */
     POfflineCacheUpdate(URIParams manifestURI, URIParams documentURI,
-                        PrincipalInfo loadingPrincipal, bool stickDocument,
-                        TabId tabId);
+                        PrincipalInfo loadingPrincipal, bool stickDocument);
 
     /**
      * Sets "offline-app" permission for the principal.  Called when we hit
      * a web app with the manifest attribute in <html> and
      * offline-apps.allow_by_default is set to true.
      */
     SetOfflinePermission(Principal principal);
 
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1686,17 +1686,17 @@ TabChild::RecvHandleDoubleTap(const CSSP
     // The double-tap can be dispatched by any scroll frame (so |aGuid| could be
     // the guid of any scroll frame), but the zoom-to-rect operation must be
     // performed by the root content scroll frame, so query its identifiers
     // for the SendZoomToRect() call rather than using the ones from |aGuid|.
     uint32_t presShellId;
     ViewID viewId;
     if (APZCCallbackHelper::GetOrCreateScrollIdentifiers(
         document->GetDocumentElement(), &presShellId, &viewId)) {
-      SendZoomToRect(presShellId, viewId, zoomToRect);
+      SendZoomToRect(presShellId, viewId, zoomToRect, DEFAULT_BEHAVIOR);
     }
 
     return true;
 }
 
 bool
 TabChild::RecvHandleSingleTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid)
 {
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -2793,20 +2793,21 @@ TabParent::RecvBrowserFrameOpenWindow(PB
                                         this, aURL, aName, aFeatures);
   *aOutWindowOpened = (opened == BrowserElementParent::OPEN_WINDOW_ADDED);
   return true;
 }
 
 bool
 TabParent::RecvZoomToRect(const uint32_t& aPresShellId,
                           const ViewID& aViewId,
-                          const CSSRect& aRect)
+                          const CSSRect& aRect,
+                          const uint32_t& aFlags)
 {
   if (RenderFrameParent* rfp = GetRenderFrame()) {
-    rfp->ZoomToRect(aPresShellId, aViewId, aRect);
+    rfp->ZoomToRect(aPresShellId, aViewId, aRect, aFlags);
   }
   return true;
 }
 
 bool
 TabParent::RecvUpdateZoomConstraints(const uint32_t& aPresShellId,
                                      const ViewID& aViewId,
                                      const MaybeZoomConstraints& aConstraints)
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -294,17 +294,18 @@ public:
   virtual bool RecvGetWidgetNativeData(WindowsHandle* aValue) override;
 
   virtual bool RecvSetNativeChildOfShareableWindow(const uintptr_t& childWindow) override;
 
   virtual bool RecvDispatchFocusToTopLevelWindow() override;
 
   virtual bool RecvZoomToRect(const uint32_t& aPresShellId,
                               const ViewID& aViewId,
-                              const CSSRect& aRect) override;
+                              const CSSRect& aRect,
+                              const uint32_t& aFlags) override;
 
   virtual bool
   RecvUpdateZoomConstraints(const uint32_t& aPresShellId,
                             const ViewID& aViewId,
                             const MaybeZoomConstraints& aConstraints) override;
 
   virtual bool RecvRespondStartSwipeEvent(const uint64_t& aInputBlockId,
                                           const bool& aStartSwipe) override;
--- a/dom/media/AudioStream.cpp
+++ b/dom/media/AudioStream.cpp
@@ -16,23 +16,23 @@
 #include <algorithm>
 #include "mozilla/Telemetry.h"
 #include "CubebUtils.h"
 #include "nsPrintfCString.h"
 #include "gfxPrefs.h"
 
 namespace mozilla {
 
-#ifdef LOG
 #undef LOG
-#endif
+#undef LOGW
 
 LazyLogModule gAudioStreamLog("AudioStream");
 // For simple logs
-#define LOG(x) MOZ_LOG(gAudioStreamLog, mozilla::LogLevel::Debug, x)
+#define LOG(x, ...) MOZ_LOG(gAudioStreamLog, mozilla::LogLevel::Debug, ("%p " x, this, ##__VA_ARGS__))
+#define LOGW(x, ...) MOZ_LOG(gAudioStreamLog, mozilla::LogLevel::Warning, ("%p " x, this, ##__VA_ARGS__))
 
 /**
  * When MOZ_DUMP_AUDIO is set in the environment (to anything),
  * we'll drop a series of files in the current working directory named
  * dumped-audio-<nnn>.wav, one per AudioStream created, containing
  * the audio for the stream including any skips due to underruns.
  */
 static int gDumpedAudioCount = 0;
@@ -122,26 +122,25 @@ AudioStream::AudioStream(DataSource& aSo
   : mMonitor("AudioStream")
   , mInRate(0)
   , mOutRate(0)
   , mChannels(0)
   , mOutChannels(0)
   , mAudioClock(this)
   , mTimeStretcher(nullptr)
   , mDumpFile(nullptr)
-  , mBytesPerFrame(0)
   , mState(INITIALIZED)
   , mIsMonoAudioEnabled(gfxPrefs::MonoAudio())
   , mDataSource(aSource)
 {
 }
 
 AudioStream::~AudioStream()
 {
-  LOG(("AudioStream: delete %p, state %d", this, mState));
+  LOG("deleted, state %d", mState);
   MOZ_ASSERT(mState == SHUTDOWN && !mCubebStream,
              "Should've called Shutdown() before deleting an AudioStream");
   if (mDumpFile) {
     fclose(mDumpFile);
   }
   if (mTimeStretcher) {
     soundtouch::destroySoundTouchObj(mTimeStretcher);
   }
@@ -334,17 +333,16 @@ AudioStream::Init(int32_t aNumChannels, 
     return NS_ERROR_INVALID_ARG;
   }
 #endif
   if (AUDIO_OUTPUT_FORMAT == AUDIO_FORMAT_S16) {
     params.format = CUBEB_SAMPLE_S16NE;
   } else {
     params.format = CUBEB_SAMPLE_FLOAT32NE;
   }
-  mBytesPerFrame = sizeof(AudioDataValue) * mOutChannels;
 
   mAudioClock.Init();
 
   return OpenCubeb(params);
 }
 
 // This code used to live inside AudioStream::Init(), but on Mac (others?)
 // it has been known to take 300-800 (or even 8500) ms to execute(!)
@@ -378,18 +376,18 @@ AudioStream::OpenCubeb(cubeb_stream_para
       return NS_ERROR_FAILURE;
     }
   }
 
   mState = INITIALIZED;
 
   if (!mStartTime.IsNull()) {
     TimeDuration timeDelta = TimeStamp::Now() - mStartTime;
-    LOG(("AudioStream creation time %sfirst: %u ms", mIsFirst ? "" : "not ",
-          (uint32_t) timeDelta.ToMilliseconds()));
+    LOG("creation time %sfirst: %u ms", mIsFirst ? "" : "not ",
+        (uint32_t) timeDelta.ToMilliseconds());
     Telemetry::Accumulate(mIsFirst ? Telemetry::AUDIOSTREAM_FIRST_OPEN_MS :
         Telemetry::AUDIOSTREAM_LATER_OPEN_MS, timeDelta.ToMilliseconds());
   }
 
   return NS_OK;
 }
 
 void
@@ -425,17 +423,17 @@ AudioStream::StartUnlocked()
       r = cubeb_stream_start(mCubebStream.get());
       // DataCallback might be called before we exit this scope
       // if cubeb_stream_start() succeeds. mState must be set to STARTED
       // beforehand.
     }
     if (r != CUBEB_OK) {
       mState = ERRORED;
     }
-    LOG(("AudioStream: started %p, state %s", this, mState == STARTED ? "STARTED" : "ERRORED"));
+    LOG("started, state %s", mState == STARTED ? "STARTED" : "ERRORED");
   }
 }
 
 void
 AudioStream::Pause()
 {
   MonitorAutoLock mon(mMonitor);
 
@@ -475,17 +473,17 @@ AudioStream::Resume()
     mState = STARTED;
   }
 }
 
 void
 AudioStream::Shutdown()
 {
   MonitorAutoLock mon(mMonitor);
-  LOG(("AudioStream: Shutdown %p, state %d", this, mState));
+  LOG("Shutdown, state %d", mState);
 
   if (mCubebStream) {
     MonitorAutoUnlock mon(mMonitor);
     // Force stop to put the cubeb stream in a stable state before deletion.
     cubeb_stream_stop(mCubebStream.get());
     // Must not try to shut down cubeb from within the lock!  wasapi may still
     // call our callback after Pause()/stop()!?! Bug 996162
     mCubebStream.reset();
@@ -548,157 +546,147 @@ AudioStream::Downmix(AudioDataValue* aBu
 
   if (mChannels >= 2 && mIsMonoAudioEnabled) {
     DownmixStereoToMono(aBuffer, aFrames);
   }
 
   return true;
 }
 
-long
-AudioStream::GetUnprocessed(void* aBuffer, long aFrames)
+void
+AudioStream::GetUnprocessed(AudioBufferWriter& aWriter)
 {
   mMonitor.AssertCurrentThreadOwns();
-  uint8_t* wpos = reinterpret_cast<uint8_t*>(aBuffer);
 
   // Flush the timestretcher pipeline, if we were playing using a playback rate
   // other than 1.0.
-  uint32_t flushedFrames = 0;
   if (mTimeStretcher && mTimeStretcher->numSamples()) {
-    flushedFrames = mTimeStretcher->receiveSamples(reinterpret_cast<AudioDataValue*>(wpos), aFrames);
-    wpos += FramesToBytes(flushedFrames);
+    auto timeStretcher = mTimeStretcher;
+    aWriter.Write([timeStretcher] (AudioDataValue* aPtr, uint32_t aFrames) {
+      return timeStretcher->receiveSamples(aPtr, aFrames);
+    }, aWriter.Available());
 
     // TODO: There might be still unprocessed samples in the stretcher.
     // We should either remove or flush them so they won't be in the output
     // next time we switch a playback rate other than 1.0.
     NS_WARN_IF(mTimeStretcher->numUnprocessedSamples() > 0);
   }
 
-  uint32_t toPopFrames = aFrames - flushedFrames;
-  while (toPopFrames > 0) {
-    UniquePtr<Chunk> c = mDataSource.PopFrames(toPopFrames);
+  while (aWriter.Available() > 0) {
+    UniquePtr<Chunk> c = mDataSource.PopFrames(aWriter.Available());
     if (c->Frames() == 0) {
       break;
     }
-    MOZ_ASSERT(c->Frames() <= toPopFrames);
+    MOZ_ASSERT(c->Frames() <= aWriter.Available());
     if (Downmix(c->GetWritable(), c->Frames())) {
-      memcpy(wpos, c->Data(), FramesToBytes(c->Frames()));
+      aWriter.Write(c->Data(), c->Frames());
     } else {
       // Write silence if downmixing fails.
-      memset(wpos, 0, FramesToBytes(c->Frames()));
+      aWriter.WriteZeros(c->Frames());
     }
-    wpos += FramesToBytes(c->Frames());
-    toPopFrames -= c->Frames();
   }
-
-  return aFrames - toPopFrames;
 }
 
-long
-AudioStream::GetTimeStretched(void* aBuffer, long aFrames)
+void
+AudioStream::GetTimeStretched(AudioBufferWriter& aWriter)
 {
   mMonitor.AssertCurrentThreadOwns();
 
   // We need to call the non-locking version, because we already have the lock.
   if (EnsureTimeStretcherInitializedUnlocked() != NS_OK) {
-    return 0;
+    return;
   }
 
-  uint8_t* wpos = reinterpret_cast<uint8_t*>(aBuffer);
   double playbackRate = static_cast<double>(mInRate) / mOutRate;
-  uint32_t toPopFrames = ceil(aFrames * playbackRate);
+  uint32_t toPopFrames = ceil(aWriter.Available() * playbackRate);
 
-  while (mTimeStretcher->numSamples() < static_cast<uint32_t>(aFrames)) {
+  while (mTimeStretcher->numSamples() < aWriter.Available()) {
     UniquePtr<Chunk> c = mDataSource.PopFrames(toPopFrames);
     if (c->Frames() == 0) {
       break;
     }
     MOZ_ASSERT(c->Frames() <= toPopFrames);
     if (Downmix(c->GetWritable(), c->Frames())) {
       mTimeStretcher->putSamples(c->Data(), c->Frames());
     } else {
       // Write silence if downmixing fails.
       nsAutoTArray<AudioDataValue, 1000> buf;
       buf.SetLength(mOutChannels * c->Frames());
       memset(buf.Elements(), 0, buf.Length() * sizeof(AudioDataValue));
       mTimeStretcher->putSamples(buf.Elements(), c->Frames());
     }
   }
 
-  uint32_t receivedFrames = mTimeStretcher->receiveSamples(reinterpret_cast<AudioDataValue*>(wpos), aFrames);
-  wpos += FramesToBytes(receivedFrames);
-  return receivedFrames;
+  auto timeStretcher = mTimeStretcher;
+  aWriter.Write([timeStretcher] (AudioDataValue* aPtr, uint32_t aFrames) {
+    return timeStretcher->receiveSamples(aPtr, aFrames);
+  }, aWriter.Available());
 }
 
 long
 AudioStream::DataCallback(void* aBuffer, long aFrames)
 {
   MonitorAutoLock mon(mMonitor);
   MOZ_ASSERT(mState != SHUTDOWN, "No data callback after shutdown");
-  uint32_t underrunFrames = 0;
-  uint32_t servicedFrames = 0;
+
+  auto writer = AudioBufferWriter(
+    reinterpret_cast<AudioDataValue*>(aBuffer), mOutChannels, aFrames);
 
   // FIXME: cubeb_pulse sometimes calls us before cubeb_stream_start() is called.
   // We don't want to consume audio data until Start() is called by the client.
   if (mState == INITIALIZED) {
     NS_WARNING("data callback fires before cubeb_stream_start() is called");
     mAudioClock.UpdateFrameHistory(0, aFrames);
-    memset(aBuffer, 0, FramesToBytes(aFrames));
-    return aFrames;
+    return writer.WriteZeros(aFrames);
   }
 
   // NOTE: wasapi (others?) can call us back *after* stop()/Shutdown() (mState == SHUTDOWN)
   // Bug 996162
 
   // callback tells us cubeb succeeded initializing
   if (mState == STARTED) {
     mState = RUNNING;
   }
 
   if (mInRate == mOutRate) {
-    servicedFrames = GetUnprocessed(aBuffer, aFrames);
+    GetUnprocessed(writer);
   } else {
-    servicedFrames = GetTimeStretched(aBuffer, aFrames);
+    GetTimeStretched(writer);
   }
 
-  underrunFrames = aFrames - servicedFrames;
-
   // Always send audible frames first, and silent frames later.
   // Otherwise it will break the assumption of FrameHistory.
   if (!mDataSource.Ended()) {
-    mAudioClock.UpdateFrameHistory(servicedFrames, underrunFrames);
-    uint8_t* rpos = static_cast<uint8_t*>(aBuffer) + FramesToBytes(aFrames - underrunFrames);
-    memset(rpos, 0, FramesToBytes(underrunFrames));
-    if (underrunFrames) {
-      MOZ_LOG(gAudioStreamLog, LogLevel::Warning,
-             ("AudioStream %p lost %d frames", this, underrunFrames));
+    mAudioClock.UpdateFrameHistory(aFrames - writer.Available(), writer.Available());
+    if (writer.Available() > 0) {
+      LOGW("lost %d frames", writer.Available());
+      writer.WriteZeros(writer.Available());
     }
-    servicedFrames += underrunFrames;
   } else {
     // No more new data in the data source. Don't send silent frames so the
     // cubeb stream can start draining.
-    mAudioClock.UpdateFrameHistory(servicedFrames, 0);
+    mAudioClock.UpdateFrameHistory(aFrames - writer.Available(), 0);
   }
 
   WriteDumpFile(mDumpFile, this, aFrames, aBuffer);
 
-  return servicedFrames;
+  return aFrames - writer.Available();
 }
 
 void
 AudioStream::StateCallback(cubeb_state aState)
 {
   MonitorAutoLock mon(mMonitor);
   MOZ_ASSERT(mState != SHUTDOWN, "No state callback after shutdown");
-  LOG(("AudioStream: StateCallback %p, mState=%d cubeb_state=%d", this, mState, aState));
+  LOG("StateCallback, mState=%d cubeb_state=%d", mState, aState);
   if (aState == CUBEB_STATE_DRAINED) {
     mState = DRAINED;
     mDataSource.Drained();
   } else if (aState == CUBEB_STATE_ERROR) {
-    LOG(("AudioStream::StateCallback() state %d cubeb error", mState));
+    LOG("StateCallback() state %d cubeb error", mState);
     mState = ERRORED;
   }
 }
 
 AudioClock::AudioClock(AudioStream* aStream)
  :mAudioStream(aStream),
   mOutRate(0),
   mInRate(0),
--- a/dom/media/AudioStream.h
+++ b/dom/media/AudioStream.h
@@ -143,16 +143,76 @@ public:
 
 private:
   UniquePtr<uint8_t[]> mBuffer;
   uint32_t mCapacity;
   uint32_t mStart;
   uint32_t mCount;
 };
 
+/*
+ * A bookkeeping class to track the read/write position of an audio buffer.
+ */
+class AudioBufferCursor {
+public:
+  AudioBufferCursor(AudioDataValue* aPtr, uint32_t aChannels, uint32_t aFrames)
+    : mPtr(aPtr), mChannels(aChannels), mFrames(aFrames) {}
+
+  // Advance the cursor to account for frames that are consumed.
+  uint32_t Advance(uint32_t aFrames) {
+    MOZ_ASSERT(mFrames >= aFrames);
+    mFrames -= aFrames;
+    mPtr += mChannels * aFrames;
+    return aFrames;
+  }
+
+  // The number of frames available for read/write in this buffer.
+  uint32_t Available() const { return mFrames; }
+
+  // Return a pointer where read/write should begin.
+  AudioDataValue* Ptr() const { return mPtr; }
+
+protected:
+  AudioDataValue* mPtr;
+  const uint32_t mChannels;
+  uint32_t mFrames;
+};
+
+/*
+ * A helper class to encapsulate pointer arithmetic and provide means to modify
+ * the underlying audio buffer.
+ */
+class AudioBufferWriter : private AudioBufferCursor {
+public:
+  AudioBufferWriter(AudioDataValue* aPtr, uint32_t aChannels, uint32_t aFrames)
+    : AudioBufferCursor(aPtr, aChannels, aFrames) {}
+
+  uint32_t WriteZeros(uint32_t aFrames) {
+    memset(mPtr, 0, sizeof(AudioDataValue) * mChannels * aFrames);
+    return Advance(aFrames);
+  }
+
+  uint32_t Write(const AudioDataValue* aPtr, uint32_t aFrames) {
+    memcpy(mPtr, aPtr, sizeof(AudioDataValue) * mChannels * aFrames);
+    return Advance(aFrames);
+  }
+
+  // Provide a write fuction to update the audio buffer with the following
+  // signature: uint32_t(const AudioDataValue* aPtr, uint32_t aFrames)
+  // aPtr: Pointer to the audio buffer.
+  // aFrames: The number of frames available in the buffer.
+  // return: The number of frames actually written by the function.
+  template <typename Function>
+  uint32_t Write(const Function& aFunction, uint32_t aFrames) {
+    return Advance(aFunction(mPtr, aFrames));
+  }
+
+  using AudioBufferCursor::Available;
+};
+
 // Access to a single instance of this class must be synchronized by
 // callers, or made from a single thread.  One exception is that access to
 // GetPosition, GetPositionInFrames, SetVolume, and Get{Rate,Channels},
 // SetMicrophoneActive is thread-safe without external synchronization.
 class AudioStream final
 {
   virtual ~AudioStream();
 
@@ -258,18 +318,18 @@ private:
   long DataCallback(void* aBuffer, long aFrames);
   void StateCallback(cubeb_state aState);
 
   nsresult EnsureTimeStretcherInitializedUnlocked();
 
   // Return true if downmixing succeeds otherwise false.
   bool Downmix(AudioDataValue* aBuffer, uint32_t aFrames);
 
-  long GetUnprocessed(void* aBuffer, long aFrames);
-  long GetTimeStretched(void* aBuffer, long aFrames);
+  void GetUnprocessed(AudioBufferWriter& aWriter);
+  void GetTimeStretched(AudioBufferWriter& aWriter);
 
   void StartUnlocked();
 
   // The monitor is held to protect all access to member variables.
   Monitor mMonitor;
 
   // Input rate in Hz (characteristic of the media being played)
   int mInRate;
@@ -287,28 +347,16 @@ private:
   TimeStamp mStartTime;
 
   // Output file for dumping audio
   FILE* mDumpFile;
 
   // Owning reference to a cubeb_stream.
   UniquePtr<cubeb_stream, CubebDestroyPolicy> mCubebStream;
 
-  uint32_t mBytesPerFrame;
-
-  uint32_t BytesToFrames(uint32_t aBytes) {
-    NS_ASSERTION(aBytes % mBytesPerFrame == 0,
-                 "Byte count not aligned on frames size.");
-    return aBytes / mBytesPerFrame;
-  }
-
-  uint32_t FramesToBytes(uint32_t aFrames) {
-    return aFrames * mBytesPerFrame;
-  }
-
   enum StreamState {
     INITIALIZED, // Initialized, playback has not begun.
     STARTED,     // cubeb started, but callbacks haven't started
     RUNNING,     // DataCallbacks have started after STARTED, or after Resume().
     STOPPED,     // Stopped by a call to Pause().
     DRAINED,     // StateCallback has indicated that the drain is complete.
     ERRORED,     // Stream disabled due to an internal error.
     SHUTDOWN     // Shutdown has been called
--- a/dom/media/mediasink/DecodedAudioDataSink.cpp
+++ b/dom/media/mediasink/DecodedAudioDataSink.cpp
@@ -162,27 +162,22 @@ DecodedAudioDataSink::GetEndTime() const
   return playedUsecs.value();
 }
 
 UniquePtr<AudioStream::Chunk>
 DecodedAudioDataSink::PopFrames(uint32_t aFrames)
 {
   class Chunk : public AudioStream::Chunk {
   public:
-    Chunk(AudioData* aBuffer, uint32_t aFrames, uint32_t aOffset)
-      : mBuffer(aBuffer)
-      , mFrames(aFrames)
-      , mData(aBuffer->mAudioData.get() + aBuffer->mChannels * aOffset) {
-      MOZ_ASSERT(aOffset + aFrames <= aBuffer->mFrames);
-    }
+    Chunk(AudioData* aBuffer, uint32_t aFrames, AudioDataValue* aData)
+      : mBuffer(aBuffer), mFrames(aFrames), mData(aData) {}
     Chunk() : mFrames(0), mData(nullptr) {}
     const AudioDataValue* Data() const { return mData; }
     uint32_t Frames() const { return mFrames; }
     AudioDataValue* GetWritable() const { return mData; }
-
   private:
     const RefPtr<AudioData> mBuffer;
     const uint32_t mFrames;
     AudioDataValue* const mData;
   };
 
   class SilentChunk : public AudioStream::Chunk {
   public:
@@ -227,42 +222,44 @@ DecodedAudioDataSink::PopFrames(uint32_t
       // hardware so that the next audio chunk begins playback at the correct
       // time.
       missingFrames = std::min<int64_t>(UINT32_MAX, missingFrames.value());
       auto framesToPop = std::min<uint32_t>(missingFrames.value(), aFrames);
       mWritten += framesToPop;
       return MakeUnique<SilentChunk>(framesToPop, mInfo.mChannels);
     }
 
-    mFramesPopped = 0;
     mCurrentData = dont_AddRef(AudioQueue().PopFront().take()->As<AudioData>());
+    mCursor = MakeUnique<AudioBufferCursor>(mCurrentData->mAudioData.get(),
+                                            mCurrentData->mChannels,
+                                            mCurrentData->mFrames);
   }
 
-  auto framesToPop = std::min(aFrames, mCurrentData->mFrames - mFramesPopped);
+  auto framesToPop = std::min(aFrames, mCursor->Available());
 
   SINK_LOG_V("playing audio at time=%lld offset=%u length=%u",
-             mCurrentData->mTime, mFramesPopped, framesToPop);
+             mCurrentData->mTime, mCurrentData->mFrames - mCursor->Available(), framesToPop);
 
   UniquePtr<AudioStream::Chunk> chunk;
 
   if (mCurrentData->mRate == mInfo.mRate &&
       mCurrentData->mChannels == mInfo.mChannels) {
-    chunk = MakeUnique<Chunk>(mCurrentData, framesToPop, mFramesPopped);
+    chunk = MakeUnique<Chunk>(mCurrentData, framesToPop, mCursor->Ptr());
   } else {
     SINK_LOG_V("mismatched sample format mInfo=[%uHz/%u channels] audio=[%uHz/%u channels]",
                mInfo.mRate, mInfo.mChannels, mCurrentData->mRate, mCurrentData->mChannels);
     chunk = MakeUnique<SilentChunk>(framesToPop, mInfo.mChannels);
   }
 
   mWritten += framesToPop;
-  mFramesPopped += framesToPop;
+  mCursor->Advance(framesToPop);
 
   // All frames are popped. Reset mCurrentData so we can pop new elements from
   // the audio queue in next calls to PopFrames().
-  if (mFramesPopped == mCurrentData->mFrames) {
+  if (mCursor->Available() == 0) {
     mCurrentData = nullptr;
   }
 
   return chunk;
 }
 
 bool
 DecodedAudioDataSink::Ended() const
--- a/dom/media/mediasink/DecodedAudioDataSink.h
+++ b/dom/media/mediasink/DecodedAudioDataSink.h
@@ -92,18 +92,18 @@ private:
   MozPromiseHolder<GenericPromise> mEndPromise;
 
   /*
    * Members to implement AudioStream::DataSource.
    * Used on the callback thread of cubeb.
    */
   // The AudioData at which AudioStream::DataSource is reading.
   RefPtr<AudioData> mCurrentData;
-  // The number of frames that have been popped from mCurrentData.
-  uint32_t mFramesPopped = 0;
+  // Keep track of the read positoin of mCurrentData.
+  UniquePtr<AudioBufferCursor> mCursor;
   // True if there is any error in processing audio data like overflow.
   bool mErrored = false;
 };
 
 } // namespace media
 } // namespace mozilla
 
 #endif
--- a/dom/media/systemservices/CamerasChild.cpp
+++ b/dom/media/systemservices/CamerasChild.cpp
@@ -138,16 +138,72 @@ CamerasChild::RecvReplyNumberOfCapabilit
   MonitorAutoLock monitor(mReplyMonitor);
   mReceivedReply = true;
   mReplySuccess = true;
   mReplyInteger = numdev;
   monitor.Notify();
   return true;
 }
 
+// Helper function to dispatch calls to the IPC Thread and
+// CamerasChild object. Takes the needed locks and dispatches.
+// Takes a "failed" value and a reference to the output variable
+// as parameters, will return the right one depending on whether
+// dispatching succeeded.
+template <class T = int>
+class LockAndDispatch
+{
+public:
+  LockAndDispatch(CamerasChild* aCamerasChild,
+                  const char* aRequestingFunc,
+                  nsIRunnable *aRunnable,
+                  const T& aFailureValue = T(-1), const T& aSuccessValue = T(0))
+    : mCamerasChild(aCamerasChild), mRequestingFunc(aRequestingFunc),
+      mRunnable(aRunnable),
+      mReplyLock(aCamerasChild->mReplyMonitor),
+      mRequestLock(aCamerasChild->mRequestMutex),
+      mSuccess(true),
+      mFailureValue(aFailureValue), mSuccessValue(aSuccessValue)
+  {
+    Dispatch();
+  }
+
+  const T& ReturnValue() const {
+    if (mSuccess) {
+      return mSuccessValue;
+    } else {
+      return mFailureValue;
+    }
+  }
+
+  const bool& Success() const {
+    return mSuccess;
+  }
+
+private:
+  void Dispatch() {
+    if (!mCamerasChild->DispatchToParent(mRunnable, mReplyLock)) {
+      LOG(("Cameras dispatch for IPC failed in %s", mRequestingFunc));
+      mSuccess = false;
+    }
+  }
+
+  CamerasChild* mCamerasChild;
+  const char* mRequestingFunc;
+  nsIRunnable* mRunnable;
+  // Prevent concurrent use of the reply variables by holding
+  // the mReplyMonitor. Note that this is unlocked while waiting for
+  // the reply to be filled in, necessitating the additional mRequestLock/Mutex;
+  MonitorAutoLock mReplyLock;
+  MutexAutoLock mRequestLock;
+  bool mSuccess;
+  const T& mFailureValue;
+  const T& mSuccessValue;
+};
+
 bool
 CamerasChild::DispatchToParent(nsIRunnable* aRunnable,
                                MonitorAutoLock& aMonitor)
 {
   CamerasSingleton::Mutex().AssertCurrentThreadOwns();
   CamerasSingleton::Thread()->Dispatch(aRunnable, NS_DISPATCH_NORMAL);
   // We can't see if the send worked, so we need to be able to bail
   // out on shutdown (when it failed and we won't get a reply).
@@ -165,59 +221,45 @@ CamerasChild::DispatchToParent(nsIRunnab
   }
   return true;
 }
 
 int
 CamerasChild::NumberOfCapabilities(CaptureEngine aCapEngine,
                                    const char* deviceUniqueIdUTF8)
 {
-  // Prevents multiple outstanding requests from happening.
-  MutexAutoLock requestLock(mRequestMutex);
   LOG((__PRETTY_FUNCTION__));
   LOG(("NumberOfCapabilities for %s", deviceUniqueIdUTF8));
   nsCString unique_id(deviceUniqueIdUTF8);
   nsCOMPtr<nsIRunnable> runnable =
     media::NewRunnableFrom([this, aCapEngine, unique_id]() -> nsresult {
       if (this->SendNumberOfCapabilities(aCapEngine, unique_id)) {
         return NS_OK;
       }
       return NS_ERROR_FAILURE;
     });
-  // Prevent concurrent use of the reply variables. Note
-  // that this is unlocked while waiting for the reply to be
-  // filled in, necessitating the first Mutex above.
-  MonitorAutoLock monitor(mReplyMonitor);
-  if (!DispatchToParent(runnable, monitor)) {
-    LOG(("Get capture capability count failed"));
-    return 0;
-  }
-  LOG(("Capture capability count: %d", mReplyInteger));
-  return mReplyInteger;
+  LockAndDispatch<> dispatcher(this, __func__, runnable, 0, mReplyInteger);
+  LOG(("Capture capability count: %d", dispatcher.ReturnValue()));
+  return dispatcher.ReturnValue();
 }
 
 int
 CamerasChild::NumberOfCaptureDevices(CaptureEngine aCapEngine)
 {
-  MutexAutoLock requestLock(mRequestMutex);
   LOG((__PRETTY_FUNCTION__));
   nsCOMPtr<nsIRunnable> runnable =
     media::NewRunnableFrom([this, aCapEngine]() -> nsresult {
       if (this->SendNumberOfCaptureDevices(aCapEngine)) {
         return NS_OK;
       }
       return NS_ERROR_FAILURE;
     });
-  MonitorAutoLock monitor(mReplyMonitor);
-  if (!DispatchToParent(runnable, monitor)) {
-    LOG(("Get NumberOfCaptureDevices failed"));
-    return 0;
-  }
-  LOG(("Capture Devices: %d", mReplyInteger));
-  return mReplyInteger;
+  LockAndDispatch<> dispatcher(this, __func__, runnable, 0, mReplyInteger);
+  LOG(("Capture Devices: %d", dispatcher.ReturnValue()));
+  return dispatcher.ReturnValue();
 }
 
 bool
 CamerasChild::RecvReplyNumberOfCaptureDevices(const int& numdev)
 {
   LOG((__PRETTY_FUNCTION__));
   MonitorAutoLock monitor(mReplyMonitor);
   mReceivedReply = true;
@@ -228,32 +270,30 @@ CamerasChild::RecvReplyNumberOfCaptureDe
 }
 
 int
 CamerasChild::GetCaptureCapability(CaptureEngine aCapEngine,
                                    const char* unique_idUTF8,
                                    const unsigned int capability_number,
                                    webrtc::CaptureCapability& capability)
 {
-  MutexAutoLock requestLock(mRequestMutex);
   LOG(("GetCaptureCapability: %s %d", unique_idUTF8, capability_number));
   nsCString unique_id(unique_idUTF8);
   nsCOMPtr<nsIRunnable> runnable =
     media::NewRunnableFrom([this, aCapEngine, unique_id, capability_number]() -> nsresult {
       if (this->SendGetCaptureCapability(aCapEngine, unique_id, capability_number)) {
         return NS_OK;
       }
       return NS_ERROR_FAILURE;
     });
-  MonitorAutoLock monitor(mReplyMonitor);
-  if (!DispatchToParent(runnable, monitor)) {
-    return -1;
+  LockAndDispatch<> dispatcher(this, __func__, runnable);
+  if (dispatcher.Success()) {
+    capability = mReplyCapability;
   }
-  capability = mReplyCapability;
-  return 0;
+  return dispatcher.ReturnValue();
 }
 
 bool
 CamerasChild::RecvReplyGetCaptureCapability(const CaptureCapability& ipcCapability)
 {
   LOG((__PRETTY_FUNCTION__));
   MonitorAutoLock monitor(mReplyMonitor);
   mReceivedReply = true;
@@ -271,34 +311,31 @@ CamerasChild::RecvReplyGetCaptureCapabil
 
 int
 CamerasChild::GetCaptureDevice(CaptureEngine aCapEngine,
                                unsigned int list_number, char* device_nameUTF8,
                                const unsigned int device_nameUTF8Length,
                                char* unique_idUTF8,
                                const unsigned int unique_idUTF8Length)
 {
-  MutexAutoLock requestLock(mRequestMutex);
   LOG((__PRETTY_FUNCTION__));
   nsCOMPtr<nsIRunnable> runnable =
     media::NewRunnableFrom([this, aCapEngine, list_number]() -> nsresult {
       if (this->SendGetCaptureDevice(aCapEngine, list_number)) {
         return NS_OK;
       }
       return NS_ERROR_FAILURE;
     });
-  MonitorAutoLock monitor(mReplyMonitor);
-  if (!DispatchToParent(runnable, monitor)) {
-    LOG(("GetCaptureDevice failed"));
-    return -1;
+  LockAndDispatch<> dispatcher(this, __func__, runnable);
+  if (dispatcher.Success()) {
+    base::strlcpy(device_nameUTF8, mReplyDeviceName.get(), device_nameUTF8Length);
+    base::strlcpy(unique_idUTF8, mReplyDeviceID.get(), unique_idUTF8Length);
+    LOG(("Got %s name %s id", device_nameUTF8, unique_idUTF8));
   }
-  base::strlcpy(device_nameUTF8, mReplyDeviceName.get(), device_nameUTF8Length);
-  base::strlcpy(unique_idUTF8, mReplyDeviceID.get(), unique_idUTF8Length);
-  LOG(("Got %s name %s id", device_nameUTF8, unique_idUTF8));
-  return 0;
+  return dispatcher.ReturnValue();
 }
 
 bool
 CamerasChild::RecvReplyGetCaptureDevice(const nsCString& device_name,
                                         const nsCString& device_id)
 {
   LOG((__PRETTY_FUNCTION__));
   MonitorAutoLock monitor(mReplyMonitor);
@@ -311,34 +348,31 @@ CamerasChild::RecvReplyGetCaptureDevice(
 }
 
 int
 CamerasChild::AllocateCaptureDevice(CaptureEngine aCapEngine,
                                     const char* unique_idUTF8,
                                     const unsigned int unique_idUTF8Length,
                                     int& capture_id)
 {
-  MutexAutoLock requestLock(mRequestMutex);
   LOG((__PRETTY_FUNCTION__));
   nsCString unique_id(unique_idUTF8);
   nsCOMPtr<nsIRunnable> runnable =
     media::NewRunnableFrom([this, aCapEngine, unique_id]() -> nsresult {
       if (this->SendAllocateCaptureDevice(aCapEngine, unique_id)) {
         return NS_OK;
       }
       return NS_ERROR_FAILURE;
     });
-  MonitorAutoLock monitor(mReplyMonitor);
-  if (!DispatchToParent(runnable, monitor)) {
-    LOG(("AllocateCaptureDevice failed"));
-    return -1;
+  LockAndDispatch<> dispatcher(this, __func__, runnable);
+  if (dispatcher.Success()) {
+    LOG(("Capture Device allocated: %d", mReplyInteger));
+    capture_id = mReplyInteger;
   }
-  LOG(("Capture Device allocated: %d", mReplyInteger));
-  capture_id = mReplyInteger;
-  return 0;
+  return dispatcher.ReturnValue();
 }
 
 
 bool
 CamerasChild::RecvReplyAllocateCaptureDevice(const int& numdev)
 {
   LOG((__PRETTY_FUNCTION__));
   MonitorAutoLock monitor(mReplyMonitor);
@@ -348,30 +382,26 @@ CamerasChild::RecvReplyAllocateCaptureDe
   monitor.Notify();
   return true;
 }
 
 int
 CamerasChild::ReleaseCaptureDevice(CaptureEngine aCapEngine,
                                    const int capture_id)
 {
-  MutexAutoLock requestLock(mRequestMutex);
   LOG((__PRETTY_FUNCTION__));
   nsCOMPtr<nsIRunnable> runnable =
     media::NewRunnableFrom([this, aCapEngine, capture_id]() -> nsresult {
       if (this->SendReleaseCaptureDevice(aCapEngine, capture_id)) {
         return NS_OK;
       }
       return NS_ERROR_FAILURE;
     });
-  MonitorAutoLock monitor(mReplyMonitor);
-  if (!DispatchToParent(runnable, monitor)) {
-    return -1;
-  }
-  return 0;
+  LockAndDispatch<> dispatcher(this, __func__, runnable);
+  return dispatcher.ReturnValue();
 }
 
 void
 CamerasChild::AddCallback(const CaptureEngine aCapEngine, const int capture_id,
                           webrtc::ExternalRenderer* render)
 {
   MutexAutoLock lock(mCallbackMutex);
   CapturerElement ce;
@@ -395,58 +425,52 @@ CamerasChild::RemoveCallback(const Captu
 }
 
 int
 CamerasChild::StartCapture(CaptureEngine aCapEngine,
                            const int capture_id,
                            webrtc::CaptureCapability& webrtcCaps,
                            webrtc::ExternalRenderer* cb)
 {
-  MutexAutoLock requestLock(mRequestMutex);
   LOG((__PRETTY_FUNCTION__));
   AddCallback(aCapEngine, capture_id, cb);
   CaptureCapability capCap(webrtcCaps.width,
                            webrtcCaps.height,
                            webrtcCaps.maxFPS,
                            webrtcCaps.expectedCaptureDelay,
                            webrtcCaps.rawType,
                            webrtcCaps.codecType,
                            webrtcCaps.interlaced);
   nsCOMPtr<nsIRunnable> runnable =
     media::NewRunnableFrom([this, aCapEngine, capture_id, capCap]() -> nsresult {
       if (this->SendStartCapture(aCapEngine, capture_id, capCap)) {
         return NS_OK;
       }
       return NS_ERROR_FAILURE;
     });
-  MonitorAutoLock monitor(mReplyMonitor);
-  if (!DispatchToParent(runnable, monitor)) {
-    return -1;
-  }
-  return 0;
+  LockAndDispatch<> dispatcher(this, __func__, runnable);
+  return dispatcher.ReturnValue();
 }
 
 int
 CamerasChild::StopCapture(CaptureEngine aCapEngine, const int capture_id)
 {
-  MutexAutoLock requestLock(mRequestMutex);
   LOG((__PRETTY_FUNCTION__));
   nsCOMPtr<nsIRunnable> runnable =
     media::NewRunnableFrom([this, aCapEngine, capture_id]() -> nsresult {
       if (this->SendStopCapture(aCapEngine, capture_id)) {
         return NS_OK;
       }
       return NS_ERROR_FAILURE;
     });
-  MonitorAutoLock monitor(mReplyMonitor);
-  if (!DispatchToParent(runnable, monitor)) {
-    return -1;
+  LockAndDispatch<> dispatcher(this, __func__, runnable);
+  if (dispatcher.Success()) {
+    RemoveCallback(aCapEngine, capture_id);
   }
-  RemoveCallback(aCapEngine, capture_id);
-  return 0;
+  return dispatcher.ReturnValue();
 }
 
 void
 Shutdown(void)
 {
   OffTheBooksMutexAutoLock lock(CamerasSingleton::Mutex());
   if (!CamerasSingleton::Child()) {
     // We don't want to cause everything to get fired up if we're
--- a/dom/media/systemservices/CamerasChild.h
+++ b/dom/media/systemservices/CamerasChild.h
@@ -44,16 +44,18 @@ enum CaptureEngine : int {
 struct CapturerElement {
   CaptureEngine engine;
   int id;
   webrtc::ExternalRenderer* callback;
 };
 
 // Forward declaration so we can work with pointers to it.
 class CamerasChild;
+// Helper class in impl that we friend.
+template <class T> class LockAndDispatch;
 
 // We emulate the sync webrtc.org API with the help of singleton
 // CamerasSingleton, which manages a pointer to an IPC object, a thread
 // where IPC operations should run on, and a mutex.
 // The static function Cameras() will use that Singleton to set up,
 // if needed, both the thread and the associated IPC objects and return
 // a pointer to the IPC object. Users can then do IPC calls on that object
 // after dispatching them to aforementioned thread.
@@ -135,16 +137,17 @@ int GetChildAndCall(MEM_FUN&& f, ARGS&&.
   } else {
     return -1;
   }
 }
 
 class CamerasChild final : public PCamerasChild
 {
   friend class mozilla::ipc::BackgroundChildImpl;
+  template <class T> friend class mozilla::camera::LockAndDispatch;
 
 public:
   // We are owned by the PBackground thread only. CamerasSingleton
   // takes a non-owning reference.
   NS_INLINE_DECL_REFCOUNTING(CamerasChild)
 
   // IPC messages recevied, received on the PBackground thread
   // these are the actual callbacks with data
--- a/dom/media/webspeech/synth/windows/SapiService.cpp
+++ b/dom/media/webspeech/synth/windows/SapiService.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.h"
 #include "SapiService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsWin32Locale.h"
+#include "GeckoProfiler.h"
 
 #include "mozilla/dom/nsSynthVoiceRegistry.h"
 #include "mozilla/dom/nsSpeechTask.h"
 #include "mozilla/Preferences.h"
 
 namespace mozilla {
 namespace dom {
 
@@ -191,16 +192,18 @@ SapiService::SapiService()
 
 SapiService::~SapiService()
 {
 }
 
 bool
 SapiService::Init()
 {
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
+
   MOZ_ASSERT(!mInitialized);
 
   if (Preferences::GetBool("media.webspeech.synth.test") ||
       !Preferences::GetBool("media.webspeech.synth.enabled")) {
     // When enabled, we shouldn't add OS backend (Bug 1160844)
     return false;
   }
 
--- a/dom/offline/nsDOMOfflineResourceList.cpp
+++ b/dom/offline/nsDOMOfflineResourceList.cpp
@@ -20,16 +20,17 @@
 #include "nsContentUtils.h"
 #include "nsIObserverService.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIWebNavigation.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/OfflineResourceListBinding.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/BasePrincipal.h"
 
 #include "nsXULAppAPI.h"
 #define IS_CHILD_PROCESS() \
     (GeckoProcessType_Default != XRE_GetProcessType())
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
@@ -808,26 +809,28 @@ nsDOMOfflineResourceList::CacheKeys()
 
   if (mCachedKeys)
     return NS_OK;
 
   nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(GetOwner());
   nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(window);
   nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(webNav);
 
-  uint32_t appId = 0;
-  bool inBrowser = false;
+  nsAutoCString originSuffix;
   if (loadContext) {
-    loadContext->GetAppId(&appId);
-    loadContext->GetIsInBrowserElement(&inBrowser);
+    mozilla::DocShellOriginAttributes oa;
+    bool ok = loadContext->GetOriginAttributes(oa);
+    NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED);
+
+    oa.CreateSuffix(originSuffix);
   }
 
   nsAutoCString groupID;
-  mApplicationCacheService->BuildGroupIDForApp(
-      mManifestURI, appId, inBrowser, groupID);
+  mApplicationCacheService->BuildGroupIDForSuffix(
+      mManifestURI, originSuffix, groupID);
 
   nsCOMPtr<nsIApplicationCache> appCache;
   mApplicationCacheService->GetActiveCache(groupID,
                                            getter_AddRefs(appCache));
 
   if (!appCache) {
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -1641,16 +1641,18 @@ NPObjWrapper_Enumerate(JSContext *cx, JS
 
 static bool
 NPObjWrapper_Resolve(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
                      bool *resolvedp)
 {
   if (JSID_IS_SYMBOL(id))
     return true;
 
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::JS);
+
   NPObject *npobj = GetNPObject(cx, obj);
 
   if (!npobj || !npobj->_class || !npobj->_class->hasProperty ||
       !npobj->_class->hasMethod) {
     ThrowJSException(cx, "Bad NPObject as private data!");
 
     return false;
   }
@@ -2105,16 +2107,18 @@ CreateNPObjectMember(NPP npp, JSContext 
 
   return true;
 }
 
 static bool
 NPObjectMember_GetProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
                            JS::MutableHandleValue vp)
 {
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
+
   if (JSID_IS_SYMBOL(id)) {
     JS::RootedSymbol sym(cx, JSID_TO_SYMBOL(id));
     if (JS::GetSymbolCode(sym) == JS::SymbolCode::toPrimitive) {
       JS::RootedObject obj(cx, JS_GetFunctionObject(
                                  JS_NewFunction(
                                    cx, NPObjectMember_toPrimitive, 1, 0,
                                    "Symbol.toPrimitive")));
       if (!obj)
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -260,16 +260,18 @@ nsNPAPIPlugin::RunPluginOOP(const nsPlug
 #else
   return true;
 #endif
 }
 
 inline PluginLibrary*
 GetNewPluginLibrary(nsPluginTag *aPluginTag)
 {
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
+
   if (!aPluginTag) {
     return nullptr;
   }
 
   if (XRE_IsContentProcess()) {
     return PluginModuleContentParent::LoadModule(aPluginTag->mId, aPluginTag);
   }
 
@@ -278,16 +280,17 @@ GetNewPluginLibrary(nsPluginTag *aPlugin
   }
   return new PluginPRLibrary(aPluginTag->mFullPath.get(), aPluginTag->mLibrary);
 }
 
 // Creates an nsNPAPIPlugin object. One nsNPAPIPlugin object exists per plugin (not instance).
 nsresult
 nsNPAPIPlugin::CreatePlugin(nsPluginTag *aPluginTag, nsNPAPIPlugin** aResult)
 {
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
   *aResult = nullptr;
 
   if (!aPluginTag) {
     return NS_ERROR_FAILURE;
   }
 
   CheckClassInitialized();
 
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -275,16 +275,17 @@ nsNPAPIPluginInstance::Destroy()
 TimeStamp
 nsNPAPIPluginInstance::StopTime()
 {
   return mStopTime;
 }
 
 nsresult nsNPAPIPluginInstance::Initialize(nsNPAPIPlugin *aPlugin, nsPluginInstanceOwner* aOwner, const nsACString& aMIMEType)
 {
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
   PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::Initialize this=%p\n",this));
 
   NS_ENSURE_ARG_POINTER(aPlugin);
   NS_ENSURE_ARG_POINTER(aOwner);
 
   mPlugin = aPlugin;
   mOwner = aOwner;
 
@@ -650,16 +651,18 @@ nsresult nsNPAPIPluginInstance::Print(NP
 }
 
 nsresult nsNPAPIPluginInstance::HandleEvent(void* event, int16_t* result,
                                             NSPluginCallReentry aSafeToReenterGecko)
 {
   if (RUNNING != mRunning)
     return NS_OK;
 
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
+
   if (!event)
     return NS_ERROR_FAILURE;
 
   PluginDestructionGuard guard(this);
 
   if (!mPlugin || !mPlugin->GetLibrary())
     return NS_ERROR_FAILURE;
 
--- a/dom/plugins/base/nsNPAPIPluginStreamListener.cpp
+++ b/dom/plugins/base/nsNPAPIPluginStreamListener.cpp
@@ -281,16 +281,17 @@ nsNPAPIPluginStreamListener::CallURLNoti
                    ("NPP URLNotify called: this=%p, npp=%p, notify=%p, reason=%d, url=%s\n",
                     this, npp, mNPStreamWrapper->mNPStream.notifyData, reason, mNotifyURL));
   }
 }
 
 nsresult
 nsNPAPIPluginStreamListener::OnStartBinding(nsPluginStreamListenerPeer* streamPeer)
 {
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
   if (!mInst || !mInst->CanFireNotifications() || mStreamCleanedUp)
     return NS_ERROR_FAILURE;
 
   PluginDestructionGuard guard(mInst);
 
   nsNPAPIPlugin* plugin = mInst->GetPlugin();
   if (!plugin || !plugin->GetLibrary())
     return NS_ERROR_FAILURE;
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -1361,16 +1361,17 @@ nsresult nsPluginHost::EnsurePluginLoade
     aPluginTag->mPlugin = plugin;
   }
   return NS_OK;
 }
 
 nsresult
 nsPluginHost::GetPluginForContentProcess(uint32_t aPluginId, nsNPAPIPlugin** aPlugin)
 {
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
   MOZ_ASSERT(XRE_IsParentProcess());
 
   // If plugins haven't been scanned yet, do so now
   LoadPlugins();
 
   nsPluginTag* pluginTag = PluginWithId(aPluginId);
   if (pluginTag) {
     // When setting up a bridge, double check with chrome to see if this plugin
@@ -3516,16 +3517,17 @@ nsPluginHost::AddHeadersToChannel(const 
       return rv;
     }
   }
 }
 
 nsresult
 nsPluginHost::StopPluginInstance(nsNPAPIPluginInstance* aInstance)
 {
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
   if (PluginDestructionGuard::DelayDestroy(aInstance)) {
     return NS_OK;
   }
 
   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
   ("nsPluginHost::StopPluginInstance called instance=%p\n",aInstance));
 
   if (aInstance->HasStartedDestroying()) {
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -3595,16 +3595,18 @@ nsPluginInstanceOwner::UpdateWindowVisib
   mPluginWindowVisible = aVisible;
   UpdateWindowPositionAndClipRect(true);
 }
 #endif // XP_MACOSX
 
 void
 nsPluginInstanceOwner::UpdateDocumentActiveState(bool aIsActive)
 {
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
+
   mPluginDocumentActiveState = aIsActive;
 #ifndef XP_MACOSX
   UpdateWindowPositionAndClipRect(true);
 
 #ifdef MOZ_WIDGET_ANDROID
   if (mInstance) {
     if (!mPluginDocumentActiveState) {
       RemovePluginView();
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -105,16 +105,17 @@ struct RunnableMethodTraits<mozilla::plu
 
 bool
 mozilla::plugins::SetupBridge(uint32_t aPluginId,
                               dom::ContentParent* aContentParent,
                               bool aForceBridgeNow,
                               nsresult* rv,
                               uint32_t* runID)
 {
+    PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
     if (NS_WARN_IF(!rv) || NS_WARN_IF(!runID)) {
         return false;
     }
 
     PluginModuleChromeParent::ClearInstantiationFlag();
     RefPtr<nsPluginHost> host = nsPluginHost::GetInst();
     RefPtr<nsNPAPIPlugin> plugin;
     *rv = host->GetPluginForContentProcess(aPluginId, getter_AddRefs(plugin));
--- a/dom/push/PushServiceHttp2.jsm
+++ b/dom/push/PushServiceHttp2.jsm
@@ -9,16 +9,17 @@ const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 const Cr = Components.results;
 
 const {PushDB} = Cu.import("resource://gre/modules/PushDB.jsm");
 const {PushRecord} = Cu.import("resource://gre/modules/PushRecord.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
 Cu.import("resource://gre/modules/Timer.jsm");
 Cu.import("resource://gre/modules/Preferences.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
 
 const {
   PushCrypto,
   concatArray,
@@ -98,17 +99,17 @@ PushSubscriptionListener.prototype = {
     this._pushService.connOnStop(aRequest,
                                  Components.isSuccessCode(aStatusCode),
                                  this.uri);
   },
 
   onPush: function(associatedChannel, pushChannel) {
     console.debug("PushSubscriptionListener: onPush()");
     var pushChannelListener = new PushChannelListener(this);
-    pushChannel.asyncOpen(pushChannelListener, pushChannel);
+    pushChannel.asyncOpen2(pushChannelListener);
   },
 
   disconnect: function() {
     this._pushService = null;
   }
 };
 
 /**
@@ -429,29 +430,18 @@ this.PushServiceHttp2 = {
     return this._mainPushService != null;
   },
 
   disconnect: function() {
     this._shutdownConnections(false);
   },
 
   _makeChannel: function(aUri) {
-
-    var ios = Cc["@mozilla.org/network/io-service;1"]
-                .getService(Ci.nsIIOService);
-
-    var chan = ios.newChannel2(aUri,
-                               null,
-                               null,
-                               null,      // aLoadingNode
-                               Services.scriptSecurityManager.getSystemPrincipal(),
-                               null,      // aTriggeringPrincipal
-                               Ci.nsILoadInfo.SEC_NORMAL,
-                               Ci.nsIContentPolicy.TYPE_OTHER)
-                 .QueryInterface(Ci.nsIHttpChannel);
+    var chan = NetUtil.newChannel({uri: aUri, loadUsingSystemPrincipal: true})
+                      .QueryInterface(Ci.nsIHttpChannel);
 
     var loadGroup = Cc["@mozilla.org/network/load-group;1"]
                       .createInstance(Ci.nsILoadGroup);
     chan.loadGroup = loadGroup;
     return chan;
   },
 
   /**
@@ -490,33 +480,33 @@ this.PushServiceHttp2 = {
       var listener = new SubscriptionListener(aSubInfo,
                                               resolve,
                                               reject,
                                               this._serverURI,
                                               this);
 
       var chan = this._makeChannel(this._serverURI.spec);
       chan.requestMethod = "POST";
-      chan.asyncOpen(listener, null);
+      chan.asyncOpen2(listener);
     })
     .catch(err => {
       if ("retry" in err) {
         return this._subscribeResourceInternal(err.subInfo);
       } else {
         throw err;
       }
     })
   },
 
   _deleteResource: function(aUri) {
 
     return new Promise((resolve,reject) => {
       var chan = this._makeChannel(aUri);
       chan.requestMethod = "DELETE";
-      chan.asyncOpen(new PushServiceDelete(resolve, reject), null);
+      chan.asyncOpen2(new PushServiceDelete(resolve, reject));
     });
   },
 
   /**
    * Unsubscribe the resource with a subscription uri aSubscriptionUri.
    * We can't do anything about it if it fails, so we don't listen for response.
    */
   _unsubscribeResource: function(aSubscriptionUri) {
@@ -540,20 +530,20 @@ this.PushServiceHttp2 = {
     var conn = {};
     conn.channel = chan;
     var listener = new PushSubscriptionListener(this, aSubscriptionUri);
     conn.listener = listener;
 
     chan.notificationCallbacks = listener;
 
     try {
-      chan.asyncOpen(listener, chan);
+      chan.asyncOpen2(listener);
     } catch (e) {
       console.error("listenForMsgs: Error connecting to push server.",
-        "asyncOpen failed", e);
+        "asyncOpen2 failed", e);
       conn.listener.disconnect();
       chan.cancel(Cr.NS_ERROR_ABORT);
       this._retryAfterBackoff(aSubscriptionUri, -1);
       return;
     }
 
     this._conns[aSubscriptionUri].lastStartListening = Date.now();
     this._conns[aSubscriptionUri].channel = conn.channel;
--- a/dom/security/test/mixedcontentblocker/file_frameNavigation_grandchild.html
+++ b/dom/security/test/mixedcontentblocker/file_frameNavigation_grandchild.html
@@ -18,17 +18,20 @@ https://bugzilla.mozilla.org/show_bug.cg
   var counter = 0;
 
   var child = document.getElementById("child");
   function navigationStatus(child)
   {
     // When the page is navigating, it goes through about:blank and we will get a permission denied for loc.
     // Catch that specific exception and return
     try {
-      var loc = child.contentDocument.location;
+      var loc;
+      if (child.contentDocument) {
+        loc = child.contentDocument.location;
+      }
     } catch(e) {
       if (e.message && e.message.indexOf("Permission denied to access property") == -1) {
         // We received an exception we didn't expect.
         throw e;
       }
       counter++;
       return;
     }
--- a/dom/storage/DOMStorageDBThread.cpp
+++ b/dom/storage/DOMStorageDBThread.cpp
@@ -149,16 +149,17 @@ DOMStorageDBThread::Shutdown()
   mThread = nullptr;
 
   return mStatus;
 }
 
 void
 DOMStorageDBThread::SyncPreload(DOMStorageCacheBridge* aCache, bool aForceSync)
 {
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::STORAGE);
   if (!aForceSync && aCache->LoadedCount()) {
     // Preload already started for this cache, just wait for it to finish.
     // LoadWait will exit after LoadDone on the cache has been called.
     SetHigherPriority();
     aCache->LoadWait();
     SetDefaultPriority();
     return;
   }
@@ -252,17 +253,17 @@ DOMStorageDBThread::InsertDBOp(DOMStorag
       // We need to do this to prevent load of the DB data before the scope has
       // actually been cleared from the database.  Preloads are processed
       // immediately before update and clear operations on the database that
       // are flushed periodically in batches.
       MonitorAutoUnlock unlock(mThreadObserver->GetMonitor());
       aOperation->Finalize(NS_OK);
       return NS_OK;
     }
-    // NO BREAK
+    MOZ_FALLTHROUGH;
 
   case DBOperation::opGetUsage:
     if (aOperation->Type() == DBOperation::opPreloadUrgent) {
       SetHigherPriority(); // Dropped back after urgent preload execution
       mPreloads.InsertElementAt(0, aOperation);
     } else {
       mPreloads.AppendElement(aOperation);
     }
--- a/dom/tests/mochitest/ajax/offline/offlineTests.js
+++ b/dom/tests/mochitest/ajax/offline/offlineTests.js
@@ -319,17 +319,17 @@ loadContextInfo: function()
 },
 
 getActiveCache: function(overload)
 {
   // Note that this is the current active cache in the cache stack, not the
   // one associated with this window.
   var serv = Cc["@mozilla.org/network/application-cache-service;1"]
              .getService(Ci.nsIApplicationCacheService);
-  var groupID = serv.buildGroupID(this.manifestURL(overload), this.loadContextInfo());
+  var groupID = serv.buildGroupIDForInfo(this.manifestURL(overload), this.loadContextInfo());
   return serv.getActiveCache(groupID);
 },
 
 getActiveStorage: function()
 {
   var cache = this.getActiveCache();
   if (!cache) {
     return null;
--- a/dom/tests/mochitest/ajax/offline/test_updateCheck.html
+++ b/dom/tests/mochitest/ajax/offline/test_updateCheck.html
@@ -29,31 +29,31 @@ var manifestURI = Cc["@mozilla.org/netwo
 var updateService = Cc['@mozilla.org/offlinecacheupdate-service;1']
                     .getService(Ci.nsIOfflineCacheUpdateService);
 
 var systemPrincipal = SpecialPowers.Services.scriptSecurityManager.getSystemPrincipal();
 
 function manifestCached()
 {
   // Run first check for an update
-  updateService.checkForUpdate(manifestURI, systemPrincipal, 0, false, {
+  updateService.checkForUpdate(manifestURI, systemPrincipal, {
     observe: function(subject, topic, data) {
       OfflineTest.is(topic, "offline-cache-update-unavailable", "No update avail");
 
       // Change the manifest content
       OfflineTest.setSJSState(manifest, "second");
 
       // Check we now get notification on update ready
-      updateService.checkForUpdate(manifestURI, systemPrincipal, 0, false, {
+      updateService.checkForUpdate(manifestURI, systemPrincipal, {
         observe: function(subject, topic, data) {
           OfflineTest.is(topic, "offline-cache-update-available", "Update avail (1)");
 
           // Do the check again.  We must get the same result.  Double check is here
           // to make sure we don't overwrite any data in the cache by the check it self.
-          updateService.checkForUpdate(manifestURI, systemPrincipal, 0, false, {
+          updateService.checkForUpdate(manifestURI, systemPrincipal, {
             observe: function(subject, topic, data) {
               OfflineTest.is(topic, "offline-cache-update-available", "Update avail (2)");
 
               // Update the manifest, invokes manifestUpdated()
               applicationCache.onupdateready = OfflineTest.priv(manifestUpdated);
               applicationCache.update();
             }
           });
@@ -61,17 +61,17 @@ function manifestCached()
       });
     }
   });
 }
 
 function manifestUpdated()
 {
   // Check for an update after manifest has been updated
-  updateService.checkForUpdate(manifestURI, systemPrincipal, 0, false, {
+  updateService.checkForUpdate(manifestURI, systemPrincipal, {
     observe: function(subject, topic, data) {
       OfflineTest.is(topic, "offline-cache-update-unavailable", "No update avail (2)");
 
       OfflineTest.teardownAndFinish();
     }
   });
 }
 
--- a/dom/tests/mochitest/general/mochitest.ini
+++ b/dom/tests/mochitest/general/mochitest.ini
@@ -122,8 +122,9 @@ skip-if = buildapp == 'b2g' # Bug 118442
 skip-if = buildapp == 'b2g' # Bug 1184427 - no SSL certs on b2g
 [test_storagePermissionsReject.html]
 skip-if = buildapp == 'b2g' # Bug 1184427 - no SSL certs on b2g
 [test_storagePermissionsLimitForeign.html]
 skip-if = buildapp == 'b2g' # Bug 1184427 - no SSL certs on b2g
 [test_selectevents.html]
 skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android' # Mouse doesn't select in the same way
 # Disabled on Android, see bug 1230232
+[test_WebKitCSSMatrix.html]
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/general/test_WebKitCSSMatrix.html
@@ -0,0 +1,306 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test for WebKitCSSMatrix</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+function RoughCompareMatrix(dm1, dm2)
+{
+  var m1 = dm1.toFloat32Array();
+  var m2 = dm2.toFloat32Array();
+
+  if (m1.length != m2.length) {
+    return false;
+  }
+
+  const tolerance = 1 / 65535;
+  for (var x = 0; x < m1.length; x++) {
+    if (Math.abs(m1[x] - m2[x]) > tolerance) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+function CompareMatrix(dm1, dm2)
+{
+  var m1 = dm1.toFloat32Array();
+  var m2 = dm2.toFloat32Array();
+
+  if (m1.length != m2.length) {
+    return false;
+  }
+
+  for (var x = 0; x < m1.length; x++) {
+    if (m1[x] != m2[x]) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+test(function() {
+  var m = new WebKitCSSMatrix();
+
+  assert_equals(m.m11, 1, "m11 should be 1");
+  assert_equals(m.m22, 1, "m22 should be 1");
+  assert_equals(m.m33, 1, "m33 should be 1");
+  assert_equals(m.m44, 1, "m44 should be 1");
+  assert_equals(m.m12, 0, "m12 should be 0");
+  assert_equals(m.m13, 0, "m13 should be 0");
+  assert_equals(m.m14, 0, "m14 should be 0");
+  assert_equals(m.m21, 0, "m21 should be 0");
+  assert_equals(m.m23, 0, "m23 should be 0");
+  assert_equals(m.m24, 0, "m24 should be 0");
+  assert_equals(m.m31, 0, "m31 should be 0");
+  assert_equals(m.m32, 0, "m32 should be 0");
+  assert_equals(m.m34, 0, "m34 should be 0");
+  assert_equals(m.m41, 0, "m41 should be 0");
+  assert_equals(m.m42, 0, "m42 should be 0");
+  assert_equals(m.m43, 0, "m43 should be 0");
+}, "Test constructor with no arguments.");
+
+test(function() {
+  var m = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+
+  assert_equals(m.m11, 1, "m11 should be 1");
+  assert_equals(m.m12, 2, "m12 should be 2");
+  assert_equals(m.m21, 3, "m21 should be 3");
+  assert_equals(m.m22, 4, "m22 should be 4");
+  assert_equals(m.m41, 5, "m41 should be 5");
+  assert_equals(m.m42, 6, "m42 should be 6");
+}, "Test constructor with transform list.");
+
+test(function() {
+  var m1 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+  var m2 = new WebKitCSSMatrix(m1);
+
+  assert_true(RoughCompareMatrix(m1, m2), "Matrix should be equal.");
+}, "Test constructor with other matrix.");
+
+test(function() {
+  var m = new WebKitCSSMatrix();
+  var mr = m.setMatrixValue("matrix(1,2,3,4,5,6)");
+
+  assert_equals(m.m11, 1, "m11 should be 1");
+  assert_equals(m.m12, 2, "m12 should be 2");
+  assert_equals(m.m21, 3, "m21 should be 3");
+  assert_equals(m.m22, 4, "m22 should be 4");
+  assert_equals(m.m41, 5, "m41 should be 5");
+  assert_equals(m.m42, 6, "m42 should be 6");
+
+  assert_equals(m, mr, "Return value of setMatrixValue should be the same matrix.");
+}, "Test setMatrixValue.");
+
+test(function() {
+  var m1 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+  var m2 = new DOMMatrix("matrix(1,2,3,4,5,6)");
+  var m3 = new WebKitCSSMatrix("matrix(6,5,4,3,2,1)");
+  var m4 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+
+  var m1r = m1.multiply(m3);
+  var m2r = m2.multiply(m3);
+
+  assert_true(RoughCompareMatrix(m1r, m2r), "multiply should return the same result as DOMMatrixReadOnly.");
+  assert_true(CompareMatrix(m1, m4), "Multiply should not mutate original matrix.");
+}, "Test multiply.");
+
+test(function() {
+  var m1 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+  var m2 = new DOMMatrix("matrix(1,2,3,4,5,6)");
+  var m3 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+
+  var m1r = m1.inverse();
+  var m2r = m2.inverse();
+
+  assert_true(RoughCompareMatrix(m1r, m2r), "inverse should return the same result as DOMMatrixReadOnly.");
+  assert_true(CompareMatrix(m1, m3), "inverse should not mutate original matrix.");
+}, "Test inverse.");
+
+test(function() {
+  var m1 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+  var m2 = new DOMMatrix("matrix(1,2,3,4,5,6)");
+  var m3 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+
+  var m1r = m1.translate(2, 3, 4);
+  var m2r = m2.translate(2, 3, 4);
+
+  assert_true(RoughCompareMatrix(m1r, m2r), "translate should return the same result as DOMMatrixReadOnly.");
+  assert_true(CompareMatrix(m1, m3), "translate should not mutate original matrix.");
+}, "Test inverse.");
+
+test(function() {
+  var m1 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+  var m2 = new DOMMatrix("matrix(1,2,3,4,5,6)");
+  var m3 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+
+  var m1r = m1.scale(2);
+  var m2r = m2.scaleNonUniform(2, 2, 1);
+
+  assert_true(RoughCompareMatrix(m1r, m2r), "scale should return the same result as DOMMatrixReadOnly.");
+  assert_true(CompareMatrix(m1, m3), "scale should not mutate original matrix.");
+}, "Test scale with 1 argument.");
+
+test(function() {
+  var m1 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+  var m2 = new DOMMatrix("matrix(1,2,3,4,5,6)");
+  var m3 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+
+  var m1r = m1.scale(2, 3);
+  var m2r = m2.scaleNonUniform(2, 3, 1);
+
+  assert_true(RoughCompareMatrix(m1r, m2r), "scale should return the same result as DOMMatrixReadOnly.");
+  assert_true(CompareMatrix(m1, m3), "scale should not mutate original matrix.");
+}, "Test scale with 2 arguments.");
+
+test(function() {
+  var m1 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+  var m2 = new DOMMatrix("matrix(1,2,3,4,5,6)");
+  var m3 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+
+  var m1r = m1.scale(2, 3, 4);
+  var m2r = m2.scaleNonUniform(2, 3, 4);
+
+  assert_true(RoughCompareMatrix(m1r, m2r), "scale should return the same result as DOMMatrixReadOnly.");
+  assert_true(CompareMatrix(m1, m3), "scale should not mutate original matrix.");
+}, "Test scale with 3 arguments.");
+
+test(function() {
+  var m1 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+  var m2 = new DOMMatrix("matrix(1,2,3,4,5,6)");
+  var m3 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+
+  var m1r = m1.scale(undefined, 3, 4);
+  var m2r = m2.scaleNonUniform(1, 3, 4);
+
+  assert_true(RoughCompareMatrix(m1r, m2r), "scale should return the same result as DOMMatrixReadOnly.");
+  assert_true(CompareMatrix(m1, m3), "scale should not mutate original matrix.");
+}, "Test scale with undefined scaleX argument.");
+
+test(function() {
+  var m1 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+  var m2 = new DOMMatrix("matrix(1,2,3,4,5,6)");
+  var m3 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+
+  var m1r = m1.scale(2, undefined, 4);
+  var m2r = m2.scaleNonUniform(2, 2, 4);
+
+  assert_true(RoughCompareMatrix(m1r, m2r), "scale should return the same result as DOMMatrixReadOnly.");
+  assert_true(CompareMatrix(m1, m3), "scale should not mutate original matrix.");
+}, "Test scale with undefined scaleY argument.");
+
+test(function() {
+  var m1 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+  var m2 = new DOMMatrix("matrix(1,2,3,4,5,6)");
+  var m3 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+
+  var m1r = m1.scale(2, 3, undefined);
+  var m2r = m2.scaleNonUniform(2, 3, 1);
+
+  assert_true(RoughCompareMatrix(m1r, m2r), "scale should return the same result as DOMMatrixReadOnly.");
+  assert_true(CompareMatrix(m1, m3), "scale should not mutate original matrix.");
+}, "Test scale with undefined scaleZ argument.");
+
+test(function() {
+  var m1 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+  var m2 = new DOMMatrix("matrix(1,2,3,4,5,6)");
+  var m3 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+
+  var m1r = m1.rotate(2);
+  var m2r = m2.rotateAxisAngle(0, 0, 1, 2); // Rotate around unit vector on z-axis.
+
+  assert_true(RoughCompareMatrix(m1r, m2r));
+  assert_true(CompareMatrix(m1, m3), "rotate should not mutate original matrix.");
+}, "Test rotate with 1 argument.");
+
+test(function() {
+  var m1 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+  var m2 = new DOMMatrix("matrix(1,2,3,4,5,6)");
+  var m3 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+
+  var m1r = m1.rotate(2, 3);
+  var m2r = m2.rotateAxisAngle(0, 1, 0, 3); // Rotate around unit vector on x-axis.
+  m2r = m2r.rotateAxisAngle(1, 0, 0, 2); // Rotate around unit vector on y-axis.
+
+  assert_true(RoughCompareMatrix(m1r, m2r));
+  assert_true(CompareMatrix(m1, m3), "rotate should not mutate original matrix.");
+}, "Test rotate with 2 arguments.");
+
+test(function() {
+  var m1 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+  var m2 = new DOMMatrix("matrix(1,2,3,4,5,6)");
+  var m3 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+
+  var m1r = m1.rotate(2, 3, 4);
+  var m2r = m2.rotateAxisAngle(0, 0, 1, 4); // Rotate around unit vector on z-axis.
+  m2r = m2r.rotateAxisAngle(0, 1, 0, 3); // Rotate around unit vector on y-axis.
+  m2r = m2r.rotateAxisAngle(1, 0, 0, 2); // Rotate around unit vector on x-axis.
+
+  assert_true(RoughCompareMatrix(m1r, m2r));
+  assert_true(CompareMatrix(m1, m3), "rotate should not mutate original matrix.");
+}, "Test rotate with 3 arguments.");
+
+test(function() {
+  var m1 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+  var m2 = new DOMMatrix("matrix(1,2,3,4,5,6)");
+  var m3 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+
+  var m1r = m1.rotate(2, undefined, undefined);
+  var m2r = m2.rotateAxisAngle(0, 0, 1, 2); // Rotate around unit vector on z-axis.
+
+  assert_true(RoughCompareMatrix(m1r, m2r));
+  assert_true(CompareMatrix(m1, m3), "rotate should not mutate original matrix.");
+}, "Test rotate with rotY and rotZ as undefined.");
+
+test(function() {
+  var m1 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+  var m2 = new DOMMatrix("matrix(1,2,3,4,5,6)");
+  var m3 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+
+  var m1r = m1.rotate(undefined, 3, 4);
+  var m2r = m2.rotateAxisAngle(0, 0, 1, 4); // Rotate around unit vector on z-axis.
+  m2r = m2r.rotateAxisAngle(0, 1, 0, 3); // Rotate around unit vector on y-axis.
+
+  assert_true(RoughCompareMatrix(m1r, m2r));
+  assert_true(CompareMatrix(m1, m3), "rotate should not mutate original matrix.");
+}, "Test rotate with rotX as undefined.");
+
+test(function() {
+  var m1 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+  var m2 = new DOMMatrix("matrix(1,2,3,4,5,6)");
+  var m3 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+
+  var m1r = m1.rotateAxisAngle(2, 3, 4, 5);
+  var m2r = m2.rotateAxisAngle(2, 3, 4, 5);
+
+  assert_true(RoughCompareMatrix(m1r, m2r), "rotateAxisAngle should return the same result as DOMMatrixReadOnly.");
+  assert_true(CompareMatrix(m1, m3), "rotateAxisAngle should not mutate original matrix.");
+}, "Test rotateAxisAngle.");
+
+test(function() {
+  var m1 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+  var m2 = new DOMMatrix("matrix(1,2,3,4,5,6)");
+  var m3 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+
+  var m1r = m1.skewX(2);
+  var m2r = m2.skewX(2);
+
+  assert_true(RoughCompareMatrix(m1r, m2r), "skewX should return the same result as DOMMatrixReadOnly.");
+  assert_true(CompareMatrix(m1, m3), "skewX should not mutate original matrix.");
+}, "Test skewX.");
+
+test(function() {
+  var m1 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+  var m2 = new DOMMatrix("matrix(1,2,3,4,5,6)");
+  var m3 = new WebKitCSSMatrix("matrix(1,2,3,4,5,6)");
+
+  var m1r = m1.skewY(2);
+  var m2r = m2.skewY(2);
+
+  assert_true(RoughCompareMatrix(m1r, m2r), "skewY should return the same result as DOMMatrixReadOnly.");
+  assert_true(CompareMatrix(m1, m3), "skewY should not mutate original matrix.");
+}, "Test skewY.");
+</script>
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -1437,16 +1437,18 @@ var interfaceNamesInGlobalScope =
     "WebGLTexture",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "WebGLTransformFeedback", nightly: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "WebGLUniformLocation",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "WebGLVertexArrayObject", nightly: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    "WebKitCSSMatrix",
+// IMPORTANT: Do not change this list without review from a DOM peer!
     "WebSocket",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "WheelEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Window",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Worker",
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/webidl/FormData.webidl
+++ b/dom/webidl/FormData.webidl
@@ -2,17 +2,17 @@
 /* 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/.
  *
  * The origin of this IDL file is
  * http://xhr.spec.whatwg.org
  */
 
-typedef (File or USVString) FormDataEntryValue;
+typedef (Blob or USVString) FormDataEntryValue;
 
 [Constructor(optional HTMLFormElement form),
  Exposed=(Window,Worker)]
 interface FormData {
   [Throws]
   void append(USVString name, Blob value, optional USVString filename);
   [Throws]
   void append(USVString name, USVString value);
new file mode 100644
--- /dev/null
+++ b/dom/webidl/WebKitCSSMatrix.webidl
@@ -0,0 +1,38 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://compat.spec.whatwg.org/#webkitcssmatrix-interface
+ */
+
+[Constructor,
+ Constructor(DOMString transformList),
+ Constructor(WebKitCSSMatrix other),
+ Exposed=Window,
+ Func="mozilla::dom::WebKitCSSMatrix::FeatureEnabled"]
+interface WebKitCSSMatrix : DOMMatrix {
+    // Mutable transform methods
+    [Throws]
+    WebKitCSSMatrix setMatrixValue(DOMString transformList);
+
+    // Immutable transform methods
+    WebKitCSSMatrix multiply(WebKitCSSMatrix other);
+    WebKitCSSMatrix inverse();
+    WebKitCSSMatrix translate(unrestricted double tx,
+                              unrestricted double ty,
+                              unrestricted double tz);
+    WebKitCSSMatrix scale(optional unrestricted double scaleX = 1,
+                          optional unrestricted double scaleY,
+                          optional unrestricted double scaleZ = 1);
+    WebKitCSSMatrix rotate(optional unrestricted double rotX = 0,
+                           optional unrestricted double rotY,
+                           optional unrestricted double rotZ);
+    WebKitCSSMatrix rotateAxisAngle(unrestricted double x,
+                                    unrestricted double y,
+                                    unrestricted double z,
+                                    unrestricted double angle);
+    WebKitCSSMatrix skewX(unrestricted double sx);
+    WebKitCSSMatrix skewY(unrestricted double sy);
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -585,16 +585,17 @@ WEBIDL_FILES = [
     'VideoTrackList.webidl',
     'VRDevice.webidl',
     'VTTCue.webidl',
     'VTTRegion.webidl',
     'WaveShaperNode.webidl',
     'WebComponents.webidl',
     'WebGL2RenderingContext.webidl',
     'WebGLRenderingContext.webidl',
+    'WebKitCSSMatrix.webidl',
     'WebSocket.webidl',
     'WheelEvent.webidl',
     'WifiOptions.webidl',
     'WindowRoot.webidl',
     'Worker.webidl',
     'WorkerDebuggerGlobalScope.webidl',
     'WorkerGlobalScope.webidl',
     'WorkerLocation.webidl',
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -1985,17 +1985,17 @@ void ReportLoadError(JSContext* aCx, nsr
 
     case NS_ERROR_FILE_NOT_FOUND:
     case NS_ERROR_NOT_AVAILABLE:
       Throw(aCx, NS_ERROR_DOM_NETWORK_ERR);
       break;
 
     case NS_ERROR_MALFORMED_URI:
       aLoadResult = NS_ERROR_DOM_SYNTAX_ERR;
-      // fall through
+      MOZ_FALLTHROUGH;
     case NS_ERROR_DOM_SECURITY_ERR:
     case NS_ERROR_DOM_SYNTAX_ERR:
       Throw(aCx, aLoadResult);
       break;
 
     default:
       JS_ReportError(aCx, "Failed to load script (nsresult = 0x%x)", aLoadResult);
   }
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/xpcshell/data/worker_fileReader.js
@@ -0,0 +1,8 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+
+self.onmessage = function(msg) {
+  var fr = new FileReader();
+  self.postMessage("OK");
+};
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/xpcshell/test_fileReader.js
@@ -0,0 +1,40 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+Components.utils.import("resource://gre/modules/Promise.jsm");
+
+// Worker must be loaded from a chrome:// uri, not a file://
+// uri, so we first need to load it.
+var WORKER_SOURCE_URI = "chrome://workers/content/worker_fileReader.js";
+do_load_manifest("data/chrome.manifest");
+
+function run_test() {
+  run_next_test();
+}
+
+function talk_with_worker(worker) {
+  let deferred = Promise.defer();
+  worker.onmessage = function(event) {
+    let success = true;
+    if (event.data == "OK") {
+      deferred.resolve();
+    } else {
+      success = false;
+      deferred.reject(event);
+    }
+    do_check_true(success);
+    worker.terminate();
+  };
+  worker.onerror = function(event) {
+    let error = new Error(event.message, event.filename, event.lineno);
+    worker.terminate();
+    deferred.reject(error);
+  };
+  worker.postMessage("START");
+  return deferred.promise;
+}
+
+
+add_task(function test_chrome_worker() {
+  return talk_with_worker(new ChromeWorker(WORKER_SOURCE_URI));
+});
--- a/dom/workers/test/xpcshell/xpcshell.ini
+++ b/dom/workers/test/xpcshell/xpcshell.ini
@@ -1,9 +1,11 @@
 [DEFAULT]
 head =
 tail =
 skip-if = toolkit == 'android' || toolkit == 'gonk'
 support-files =
   data/worker.js
+  data/worker_fileReader.js
   data/chrome.manifest
 
 [test_workers.js]
+[test_fileReader.js]
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -1234,16 +1234,18 @@ public:
    * within 8k limit.  The 8k value is chosen a bit randomly.
    */
   static bool ReasonableSurfaceSize(const IntSize &aSize);
 
   static bool AllowedSurfaceSize(const IntSize &aSize);
 
   static already_AddRefed<DrawTarget> CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat = nullptr);
 
+  static already_AddRefed<SourceSurface> CreateSourceSurfaceForCairoSurface(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat aFormat);
+
   static already_AddRefed<DrawTarget>
     CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat);
 
   static already_AddRefed<DrawTarget>
     CreateRecordingDrawTarget(DrawEventRecorder *aRecorder, DrawTarget *aDT);
 
   static already_AddRefed<DrawTarget>
     CreateDrawTargetForData(BackendType aBackend, unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat);
--- a/gfx/2d/DrawTargetCairo.cpp
+++ b/gfx/2d/DrawTargetCairo.cpp
@@ -1725,26 +1725,16 @@ DrawTargetCairo::OptimizeSourceSurface(S
 #endif
 
   return surface.forget();
 }
 
 already_AddRefed<SourceSurface>
 DrawTargetCairo::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const
 {
-  if (aSurface.mType == NativeSurfaceType::CAIRO_CONTEXT) {
-    if (aSurface.mSize.width <= 0 ||
-        aSurface.mSize.height <= 0) {
-      gfxWarning() << "Can't create a SourceSurface without a valid size";
-      return nullptr;
-    }
-    cairo_surface_t* surf = static_cast<cairo_surface_t*>(aSurface.mSurface);
-    return MakeAndAddRef<SourceSurfaceCairo>(surf, aSurface.mSize, aSurface.mFormat);
-  }
-
   return nullptr;
 }
 
 already_AddRefed<DrawTarget>
 DrawTargetCairo::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const
 {
   if (cairo_surface_status(mSurface)) {
     RefPtr<DrawTargetCairo> target = new DrawTargetCairo();
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -744,34 +744,26 @@ DrawTargetSkia::OptimizeSourceSurface(So
                                                              dataSurf->GetFormat());
   dataSurf->Unmap();
   return result.forget();
 }
 
 already_AddRefed<SourceSurface>
 DrawTargetSkia::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const
 {
-  if (aSurface.mType == NativeSurfaceType::CAIRO_CONTEXT) {
-    if (aSurface.mSize.width <= 0 ||
-        aSurface.mSize.height <= 0) {
-      gfxWarning() << "Can't create a SourceSurface without a valid size";
-      return nullptr;
-    }
-    cairo_surface_t* surf = static_cast<cairo_surface_t*>(aSurface.mSurface);
-    return MakeAndAddRef<SourceSurfaceCairo>(surf, aSurface.mSize, aSurface.mFormat);
 #if USE_SKIA_GPU
-  } else if (aSurface.mType == NativeSurfaceType::OPENGL_TEXTURE && UsingSkiaGPU()) {
+  if (aSurface.mType == NativeSurfaceType::OPENGL_TEXTURE && UsingSkiaGPU()) {
     RefPtr<SourceSurfaceSkia> newSurf = new SourceSurfaceSkia();
     unsigned int texture = (unsigned int)((uintptr_t)aSurface.mSurface);
     if (newSurf->InitFromTexture((DrawTargetSkia*)this, texture, aSurface.mSize, aSurface.mFormat)) {
       return newSurf.forget();
     }
     return nullptr;
+  }
 #endif
-  }
 
   return nullptr;
 }
 
 void
 DrawTargetSkia::CopySurface(SourceSurface *aSurface,
                             const IntRect& aSourceRect,
                             const IntPoint &aDestination)
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -3,16 +3,17 @@
  * 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 "2D.h"
 
 #ifdef USE_CAIRO
 #include "DrawTargetCairo.h"
 #include "ScaledFontCairo.h"
+#include "SourceSurfaceCairo.h"
 #endif
 
 #ifdef USE_SKIA
 #include "DrawTargetSkia.h"
 #include "ScaledFontBase.h"
 #ifdef MOZ_ENABLE_FREETYPE
 #define USE_SKIA_FREETYPE
 #include "ScaledFontCairo.h"
@@ -845,16 +846,31 @@ Factory::CreateDrawTargetForCairoSurface
 
   if (mRecorder && retVal) {
     return MakeAndAddRef<DrawTargetRecording>(mRecorder, retVal, true);
   }
 #endif
   return retVal.forget();
 }
 
+already_AddRefed<SourceSurface>
+Factory::CreateSourceSurfaceForCairoSurface(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat aFormat)
+{
+  if (aSize.width <= 0 || aSize.height <= 0) {
+    gfxWarning() << "Can't create a SourceSurface without a valid size";
+    return nullptr;
+  }
+
+#ifdef USE_CAIRO
+  return MakeAndAddRef<SourceSurfaceCairo>(aSurface, aSize, aFormat);
+#else
+  return nullptr;
+#endif
+}
+
 #ifdef XP_DARWIN
 already_AddRefed<DrawTarget>
 Factory::CreateDrawTargetForCairoCGContext(CGContextRef cg, const IntSize& aSize)
 {
   RefPtr<DrawTarget> retVal;
 
   RefPtr<DrawTargetCG> newTarget = new DrawTargetCG();
 
deleted file mode 100644
--- a/gfx/2d/moz-d2d1-1.h
+++ /dev/null
@@ -1,367 +0,0 @@
-//---------------------------------------------------------------------------
-// Copyright (c) Microsoft Corporation.  All rights reserved.
-//
-// This file is automatically generated.  Please do not edit it directly.
-//
-// File name: D2D1_1.h
-//---------------------------------------------------------------------------
-#pragma once
-
-#ifndef _D2D1_1_H_
-#ifndef _D2D1_H_
-#include <d2d1.h>
-#endif // #ifndef _D2D1_H_
-
-//+-----------------------------------------------------------------------------
-//
-//  Flag:
-//      D2D1_LAYER_OPTIONS1
-//
-//  Synopsis:
-//      Specifies how the layer contents should be prepared.
-//
-//------------------------------------------------------------------------------
-typedef enum D2D1_LAYER_OPTIONS1
-{
-        D2D1_LAYER_OPTIONS1_NONE = 0,
-        D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND = 1,
-        D2D1_LAYER_OPTIONS1_IGNORE_ALPHA = 2,
-        D2D1_LAYER_OPTIONS1_FORCE_DWORD = 0xffffffff
-
-} D2D1_LAYER_OPTIONS1;
-
-//+-----------------------------------------------------------------------------
-//
-//  Struct:
-//      D2D1_LAYER_PARAMETERS1
-//
-//  Synopsis:
-//      All parameters related to pushing a layer.
-//
-//------------------------------------------------------------------------------
-typedef struct D2D1_LAYER_PARAMETERS1
-{
-    D2D1_RECT_F contentBounds;
-    ID2D1Geometry *geometricMask;
-    D2D1_ANTIALIAS_MODE maskAntialiasMode;
-    D2D1_MATRIX_3X2_F maskTransform;
-    FLOAT opacity;
-    ID2D1Brush *opacityBrush;
-    D2D1_LAYER_OPTIONS1 layerOptions;
-
-} D2D1_LAYER_PARAMETERS1;
-
-DEFINE_ENUM_FLAG_OPERATORS(D2D1_LAYER_OPTIONS1);
-
-#ifndef DX_DECLARE_INTERFACE
-#define DX_DECLARE_INTERFACE(x) DECLSPEC_UUID(x) DECLSPEC_NOVTABLE
-#endif
-
-namespace D2D1
-{
-    D2D1FORCEINLINE
-    D2D1_LAYER_PARAMETERS1
-    LayerParameters1(
-        CONST D2D1_RECT_F &contentBounds = D2D1::InfiniteRect(),
-        ID2D1Geometry *geometricMask = NULL,
-        D2D1_ANTIALIAS_MODE maskAntialiasMode = D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
-        D2D1_MATRIX_3X2_F maskTransform = D2D1::IdentityMatrix(),
-        FLOAT opacity = 1.0,
-        ID2D1Brush *opacityBrush = NULL,
-        D2D1_LAYER_OPTIONS1 layerOptions = D2D1_LAYER_OPTIONS1_NONE
-        )
-    {
-        D2D1_LAYER_PARAMETERS1 layerParameters = { 0 };
-
-        layerParameters.contentBounds = contentBounds;
-        layerParameters.geometricMask = geometricMask;
-        layerParameters.maskAntialiasMode = maskAntialiasMode;
-        layerParameters.maskTransform = maskTransform;
-        layerParameters.opacity = opacity;
-        layerParameters.opacityBrush = opacityBrush;
-        layerParameters.layerOptions = layerOptions;
-
-        return layerParameters;
-    }
-}
-
-DEFINE_GUID(IID_ID2D1DeviceContext, 0xe8f7fe7a, 0x191c, 0x466d, 0xad, 0x95, 0x97, 0x56, 0x78, 0xbd, 0xa9, 0x98);
-
-//+-----------------------------------------------------------------------------
-//
-//  Interface:
-//      ID2D1DeviceContext
-//
-//  Synopsis:
-//      The device context represents a set of state and a command buffer that is used
-//      to render to a target bitmap.
-//
-//------------------------------------------------------------------------------
-interface DX_DECLARE_INTERFACE("e8f7fe7a-191c-466d-ad95-975678bda998") ID2D1DeviceContext  : public ID2D1RenderTarget
-{
-    
-    
-    //
-    // Creates a bitmap with extended bitmap properties, potentially from a block of
-    // memory.
-    //
-    STDMETHOD(CreateBitmap)() PURE;
-    
-    //
-    // Create a D2D bitmap by copying a WIC bitmap.
-    //
-    STDMETHOD(CreateBitmapFromWicBitmap)() PURE;    
-    
-    //
-    // Creates a color context from a color space.  If the space is Custom, the context
-    // is initialized from the profile/profileSize arguments.  Otherwise the context is
-    // initialized with the profile bytes associated with the space and
-    // profile/profileSize are ignored.
-    //
-    STDMETHOD(CreateColorContext)() PURE;
-    
-    STDMETHOD(CreateColorContextFromFilename)() PURE;
-    
-    STDMETHOD(CreateColorContextFromWicColorContext)() PURE;
-    
-    
-    //
-    // Creates a bitmap from a DXGI surface with a set of extended properties.
-    //
-    STDMETHOD(CreateBitmapFromDxgiSurface)() PURE;
-    
-    
-    //
-    // Create a new effect, the effect must either be built in or previously registered
-    // through ID2D1Factory1::RegisterEffectFromStream or
-    // ID2D1Factory1::RegisterEffectFromString.
-    //
-    STDMETHOD(CreateEffect)() PURE;
-    
-    
-    //
-    // A gradient stop collection represents a set of stops in an ideal unit length.
-    // This is the source resource for a linear gradient and radial gradient brush.
-    //
-    STDMETHOD(CreateGradientStopCollection)() PURE;
-    
-    //
-    // Creates an image brush, the input image can be any type of image, including a
-    // bitmap, effect and a command list.
-    //
-    STDMETHOD(CreateImageBrush)() PURE;
-    
-    STDMETHOD(CreateBitmapBrush)() PURE;
-
-    //
-    // Creates a new command list.
-    //
-    STDMETHOD(CreateCommandList)() PURE;
-    
-    
-    //
-    // Indicates whether the format is supported by D2D.
-    //
-    STDMETHOD_(BOOL, IsDxgiFormatSupported)() CONST PURE;
-    
-    
-    //
-    // Indicates whether the buffer precision is supported by D2D.
-    //
-    STDMETHOD_(BOOL, IsBufferPrecisionSupported)() CONST PURE;
-    
-    
-    //
-    // This retrieves the local-space bounds in DIPs of the current image using the
-    // device context DPI.
-    //
-    STDMETHOD(GetImageLocalBounds)() CONST PURE;
-    
-    
-    //
-    // This retrieves the world-space bounds in DIPs of the current image using the
-    // device context DPI.
-    //
-    STDMETHOD(GetImageWorldBounds)() CONST PURE;
-    
-    
-    //
-    // Retrieves the world-space bounds in DIPs of the glyph run using the device
-    // context DPI.
-    //
-    STDMETHOD(GetGlyphRunWorldBounds)() CONST PURE;
-    
-    
-    //
-    // Retrieves the device associated with this device context.
-    //
-    STDMETHOD_(void, GetDevice)() CONST PURE;
-    
-    
-    //
-    // Sets the target for this device context to point to the given image. The image
-    // can be a command list or a bitmap created with the D2D1_BITMAP_OPTIONS_TARGET
-    // flag.
-    //
-    STDMETHOD_(void, SetTarget)() PURE;
-    
-    
-    //
-    // Gets the target that this device context is currently pointing to.
-    //
-    STDMETHOD_(void, GetTarget)() CONST PURE;
-    
-    
-    //
-    // Sets tuning parameters for internal rendering inside the device context.
-    //
-    STDMETHOD_(void, SetRenderingControls)() PURE;
-    
-    
-    //
-    // This retrieves the rendering controls currently selected into the device
-    // context.
-    //
-    STDMETHOD_(void, GetRenderingControls)() CONST PURE;
-    
-    
-    //
-    // Changes the primitive blending mode for all of the rendering operations.
-    //
-    STDMETHOD_(void, SetPrimitiveBlend)() PURE;
-    
-    
-    //
-    // Returns the primitive blend currently selected into the device context.
-    //
-    STDMETHOD_(void, GetPrimitiveBlend)(
-        ) CONST PURE;
-    
-    
-    //
-    // Changes the units used for all of the rendering operations.
-    //
-    STDMETHOD_(void, SetUnitMode)() PURE;
-    
-    
-    //
-    // Returns the unit mode currently set on the device context.
-    //
-    STDMETHOD_(void, GetUnitMode)(
-        ) CONST PURE;
-    
-    
-    //
-    // Draws the glyph run with an extended description to describe the glyphs.
-    //
-    STDMETHOD_(void, DrawGlyphRun)() PURE;
-    
-    //
-    // Draw an image to the device context. The image represents either a concrete
-    // bitmap or the output of an effect graph.
-    //
-    STDMETHOD_(void, DrawImage)() PURE;
-    
-    
-    //
-    // Draw a metafile to the device context.
-    //
-    STDMETHOD_(void, DrawGdiMetafile)() PURE;
-    
-    STDMETHOD_(void, DrawBitmap)() PURE;
-    
-    
-    //
-    // Push a layer on the device context.
-    //
-    STDMETHOD_(void, PushLayer)(
-        _In_ CONST D2D1_LAYER_PARAMETERS1 *layerParameters,
-        _In_opt_ ID2D1Layer *layer 
-        ) PURE;
-    
-    using ID2D1RenderTarget::PushLayer;
-    
-    
-    //
-    // This indicates that a portion of an effect's input is invalid. This method can
-    // be called many times.
-    //
-    STDMETHOD(InvalidateEffectInputRectangle)() PURE;
-    
-    
-    //
-    // Gets the number of invalid ouptut rectangles that have accumulated at the
-    // effect.
-    //
-    STDMETHOD(GetEffectInvalidRectangleCount)() PURE;
-    
-    
-    //
-    // Gets the invalid rectangles that are at the output of the effect.
-    //
-    STDMETHOD(GetEffectInvalidRectangles)() PURE;
-    
-    
-    //
-    // Gets the maximum region of each specified input which would be used during a
-    // subsequent rendering operation
-    //
-    STDMETHOD(GetEffectRequiredInputRectangles)() PURE;
-    
-    
-    //
-    // Fill using the alpha channel of the supplied opacity mask bitmap. The brush
-    // opacity will be modulated by the mask. The render target antialiasing mode must
-    // be set to aliased.
-    //
-    STDMETHOD_(void, FillOpacityMask)() PURE;
-    
- 
-    HRESULT CreateBitmap1() { return S_OK; }
-    HRESULT CreateBitmap2() { return S_OK; }
-    HRESULT CreateBitmap3() { return S_OK; }
-    HRESULT CreateBitmap4() { return S_OK; }
-    
-    HRESULT CreateImageBrush1() { return S_OK; }
-    HRESULT CreateImageBrush2() { return S_OK; }
-    
-    HRESULT CreateBitmapBrush1() { return S_OK; }
-    HRESULT CreateBitmapBrush2() { return S_OK; }
-    HRESULT CreateBitmapBrush3() { return S_OK; }
-
-    //
-    // Draws the output of the effect as an image.
-    //
-    void DrawImage1() {}
-    void DrawImage2() {}
-    void DrawImage3() {}
-    void DrawImage4() {}
-    void DrawImage5() {}
-    void DrawImage6() {}
-    void DrawImage7() {}
-    
-    void
-    PushLayer(
-        CONST D2D1_LAYER_PARAMETERS1 &layerParameters,
-        _In_opt_ ID2D1Layer *layer 
-        )  
-    {
-        PushLayer(&layerParameters, layer);
-    }
-    
-    void DrawGdiMetafile1() {}
-    
-    void DrawBitmap1() {}
-    void DrawBitmap2() {}
-    void DrawBitmap3() {}
-    
-    void FillOpacityMask1() {}
-    void FillOpacityMask2() {}   
-    
-    //
-    // Sets tuning parameters for internal rendering inside the device context.
-    //
-    void SetRenderingControls1() {}
-}; // interface ID2D1DeviceContext
-
-#endif // #ifndef _D2D1_1_H_
--- a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
+++ b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
@@ -41,18 +41,17 @@
 
 #include "cairo-win32.h"
 #include "cairo-analysis-surface-private.h"
 #include "cairo-error-private.h"
 
 // Required for using placement new.
 #include <new>
 
-// HACK WARNING - Workaround for Windows 8 since we don't have the windows 8 SDK.
-#include "moz-d2d1-1.h"
+#include "d2d1_1.h"
 
 #define CAIRO_INT_STATUS_SUCCESS (cairo_int_status_t)CAIRO_STATUS_SUCCESS
 
 struct Vertex
 {
     float position[2];
 };
 
deleted file mode 100644
--- a/gfx/cairo/cairo/src/moz-d2d1-1.h
+++ /dev/null
@@ -1,367 +0,0 @@
-//---------------------------------------------------------------------------
-// Copyright (c) Microsoft Corporation.  All rights reserved.
-//
-// This file is automatically generated.  Please do not edit it directly.
-//
-// File name: D2D1_1.h
-//---------------------------------------------------------------------------
-#pragma once
-
-#ifndef _D2D1_1_H_
-#ifndef _D2D1_H_
-#include <d2d1.h>
-#endif // #ifndef _D2D1_H_
-
-//+-----------------------------------------------------------------------------
-//
-//  Flag:
-//      D2D1_LAYER_OPTIONS1
-//
-//  Synopsis:
-//      Specifies how the layer contents should be prepared.
-//
-//------------------------------------------------------------------------------
-typedef enum D2D1_LAYER_OPTIONS1
-{
-        D2D1_LAYER_OPTIONS1_NONE = 0,
-        D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND = 1,
-        D2D1_LAYER_OPTIONS1_IGNORE_ALPHA = 2,
-        D2D1_LAYER_OPTIONS1_FORCE_DWORD = 0xffffffff
-
-} D2D1_LAYER_OPTIONS1;
-
-//+-----------------------------------------------------------------------------
-//
-//  Struct:
-//      D2D1_LAYER_PARAMETERS1
-//
-//  Synopsis:
-//      All parameters related to pushing a layer.
-//
-//------------------------------------------------------------------------------
-typedef struct D2D1_LAYER_PARAMETERS1
-{
-    D2D1_RECT_F contentBounds;
-    ID2D1Geometry *geometricMask;
-    D2D1_ANTIALIAS_MODE maskAntialiasMode;
-    D2D1_MATRIX_3X2_F maskTransform;
-    FLOAT opacity;
-    ID2D1Brush *opacityBrush;
-    D2D1_LAYER_OPTIONS1 layerOptions;
-
-} D2D1_LAYER_PARAMETERS1;
-
-DEFINE_ENUM_FLAG_OPERATORS(D2D1_LAYER_OPTIONS1);
-
-#ifndef DX_DECLARE_INTERFACE
-#define DX_DECLARE_INTERFACE(x) DECLSPEC_UUID(x) DECLSPEC_NOVTABLE
-#endif
-
-namespace D2D1
-{
-    D2D1FORCEINLINE
-    D2D1_LAYER_PARAMETERS1
-    LayerParameters1(
-        CONST D2D1_RECT_F &contentBounds = D2D1::InfiniteRect(),
-        ID2D1Geometry *geometricMask = NULL,
-        D2D1_ANTIALIAS_MODE maskAntialiasMode = D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
-        D2D1_MATRIX_3X2_F maskTransform = D2D1::IdentityMatrix(),
-        FLOAT opacity = 1.0,
-        ID2D1Brush *opacityBrush = NULL,
-        D2D1_LAYER_OPTIONS1 layerOptions = D2D1_LAYER_OPTIONS1_NONE
-        )
-    {
-        D2D1_LAYER_PARAMETERS1 layerParameters = {{ 0 }};
-
-        layerParameters.contentBounds = contentBounds;
-        layerParameters.geometricMask = geometricMask;
-        layerParameters.maskAntialiasMode = maskAntialiasMode;
-        layerParameters.maskTransform = maskTransform;
-        layerParameters.opacity = opacity;
-        layerParameters.opacityBrush = opacityBrush;
-        layerParameters.layerOptions = layerOptions;
-
-        return layerParameters;
-    }
-}
-
-DEFINE_GUID(IID_ID2D1DeviceContext, 0xe8f7fe7a, 0x191c, 0x466d, 0xad, 0x95, 0x97, 0x56, 0x78, 0xbd, 0xa9, 0x98);
-
-//+-----------------------------------------------------------------------------
-//
-//  Interface:
-//      ID2D1DeviceContext
-//
-//  Synopsis:
-//      The device context represents a set of state and a command buffer that is used
-//      to render to a target bitmap.
-//
-//------------------------------------------------------------------------------
-interface DX_DECLARE_INTERFACE("e8f7fe7a-191c-466d-ad95-975678bda998") ID2D1DeviceContext  : public ID2D1RenderTarget
-{
-    
-    
-    //
-    // Creates a bitmap with extended bitmap properties, potentially from a block of
-    // memory.
-    //
-    STDMETHOD(CreateBitmap)() PURE;
-    
-    //
-    // Create a D2D bitmap by copying a WIC bitmap.
-    //
-    STDMETHOD(CreateBitmapFromWicBitmap)() PURE;    
-    
-    //
-    // Creates a color context from a color space.  If the space is Custom, the context
-    // is initialized from the profile/profileSize arguments.  Otherwise the context is
-    // initialized with the profile bytes associated with the space and
-    // profile/profileSize are ignored.
-    //
-    STDMETHOD(CreateColorContext)() PURE;
-    
-    STDMETHOD(CreateColorContextFromFilename)() PURE;
-    
-    STDMETHOD(CreateColorContextFromWicColorContext)() PURE;
-    
-    
-    //
-    // Creates a bitmap from a DXGI surface with a set of extended properties.
-    //
-    STDMETHOD(CreateBitmapFromDxgiSurface)() PURE;
-    
-    
-    //
-    // Create a new effect, the effect must either be built in or previously registered
-    // through ID2D1Factory1::RegisterEffectFromStream or
-    // ID2D1Factory1::RegisterEffectFromString.
-    //
-    STDMETHOD(CreateEffect)() PURE;
-    
-    
-    //
-    // A gradient stop collection represents a set of stops in an ideal unit length.
-    // This is the source resource for a linear gradient and radial gradient brush.
-    //
-    STDMETHOD(CreateGradientStopCollection)() PURE;
-    
-    //
-    // Creates an image brush, the input image can be any type of image, including a
-    // bitmap, effect and a command list.
-    //
-    STDMETHOD(CreateImageBrush)() PURE;
-    
-    STDMETHOD(CreateBitmapBrush)() PURE;
-
-    //
-    // Creates a new command list.
-    //
-    STDMETHOD(CreateCommandList)() PURE;
-    
-    
-    //
-    // Indicates whether the format is supported by D2D.
-    //
-    STDMETHOD_(BOOL, IsDxgiFormatSupported)() CONST PURE;
-    
-    
-    //
-    // Indicates whether the buffer precision is supported by D2D.
-    //
-    STDMETHOD_(BOOL, IsBufferPrecisionSupported)() CONST PURE;
-    
-    
-    //
-    // This retrieves the local-space bounds in DIPs of the current image using the
-    // device context DPI.
-    //
-    STDMETHOD(GetImageLocalBounds)() CONST PURE;
-    
-    
-    //
-    // This retrieves the world-space bounds in DIPs of the current image using the
-    // device context DPI.
-    //
-    STDMETHOD(GetImageWorldBounds)() CONST PURE;
-    
-    
-    //
-    // Retrieves the world-space bounds in DIPs of the glyph run using the device
-    // context DPI.
-    //
-    STDMETHOD(GetGlyphRunWorldBounds)() CONST PURE;
-    
-    
-    //
-    // Retrieves the device associated with this device context.
-    //
-    STDMETHOD_(void, GetDevice)() CONST PURE;
-    
-    
-    //
-    // Sets the target for this device context to point to the given image. The image
-    // can be a command list or a bitmap created with the D2D1_BITMAP_OPTIONS_TARGET
-    // flag.
-    //
-    STDMETHOD_(void, SetTarget)() PURE;
-    
-    
-    //
-    // Gets the target that this device context is currently pointing to.
-    //
-    STDMETHOD_(void, GetTarget)() CONST PURE;
-    
-    
-    //
-    // Sets tuning parameters for internal rendering inside the device context.
-    //
-    STDMETHOD_(void, SetRenderingControls)() PURE;
-    
-    
-    //
-    // This retrieves the rendering controls currently selected into the device
-    // context.
-    //
-    STDMETHOD_(void, GetRenderingControls)() CONST PURE;
-    
-    
-    //
-    // Changes the primitive blending mode for all of the rendering operations.
-    //
-    STDMETHOD_(void, SetPrimitiveBlend)() PURE;
-    
-    
-    //
-    // Returns the primitive blend currently selected into the device context.
-    //
-    STDMETHOD_(void, GetPrimitiveBlend)(
-        ) CONST PURE;
-    
-    
-    //
-    // Changes the units used for all of the rendering operations.
-    //
-    STDMETHOD_(void, SetUnitMode)() PURE;
-    
-    
-    //
-    // Returns the unit mode currently set on the device context.
-    //
-    STDMETHOD_(void, GetUnitMode)(
-        ) CONST PURE;
-    
-    
-    //
-    // Draws the glyph run with an extended description to describe the glyphs.
-    //
-    STDMETHOD_(void, DrawGlyphRun)() PURE;
-    
-    //
-    // Draw an image to the device context. The image represents either a concrete
-    // bitmap or the output of an effect graph.
-    //
-    STDMETHOD_(void, DrawImage)() PURE;
-    
-    
-    //
-    // Draw a metafile to the device context.
-    //
-    STDMETHOD_(void, DrawGdiMetafile)() PURE;
-    
-    STDMETHOD_(void, DrawBitmap)() PURE;
-    
-    
-    //
-    // Push a layer on the device context.
-    //
-    STDMETHOD_(void, PushLayer)(
-        _In_ CONST D2D1_LAYER_PARAMETERS1 *layerParameters,
-        _In_opt_ ID2D1Layer *layer 
-        ) PURE;
-    
-    using ID2D1RenderTarget::PushLayer;
-    
-    
-    //
-    // This indicates that a portion of an effect's input is invalid. This method can
-    // be called many times.
-    //
-    STDMETHOD(InvalidateEffectInputRectangle)() PURE;
-    
-    
-    //
-    // Gets the number of invalid ouptut rectangles that have accumulated at the
-    // effect.
-    //
-    STDMETHOD(GetEffectInvalidRectangleCount)() PURE;
-    
-    
-    //
-    // Gets the invalid rectangles that are at the output of the effect.
-    //
-    STDMETHOD(GetEffectInvalidRectangles)() PURE;
-    
-    
-    //
-    // Gets the maximum region of each specified input which would be used during a
-    // subsequent rendering operation
-    //
-    STDMETHOD(GetEffectRequiredInputRectangles)() PURE;
-    
-    
-    //
-    // Fill using the alpha channel of the supplied opacity mask bitmap. The brush
-    // opacity will be modulated by the mask. The render target antialiasing mode must
-    // be set to aliased.
-    //
-    STDMETHOD_(void, FillOpacityMask)() PURE;
-    
- 
-    HRESULT CreateBitmap1() { return S_OK; }
-    HRESULT CreateBitmap2() { return S_OK; }
-    HRESULT CreateBitmap3() { return S_OK; }
-    HRESULT CreateBitmap4() { return S_OK; }
-    
-    HRESULT CreateImageBrush1() { return S_OK; }
-    HRESULT CreateImageBrush2() { return S_OK; }
-    
-    HRESULT CreateBitmapBrush1() { return S_OK; }
-    HRESULT CreateBitmapBrush2() { return S_OK; }
-    HRESULT CreateBitmapBrush3() { return S_OK; }
-
-    //
-    // Draws the output of the effect as an image.
-    //
-    void DrawImage1() {}
-    void DrawImage2() {}
-    void DrawImage3() {}
-    void DrawImage4() {}
-    void DrawImage5() {}
-    void DrawImage6() {}
-    void DrawImage7() {}
-    
-    void
-    PushLayer(
-        CONST D2D1_LAYER_PARAMETERS1 &layerParameters,
-        _In_opt_ ID2D1Layer *layer 
-        )  
-    {
-        PushLayer(&layerParameters, layer);
-    }
-    
-    void DrawGdiMetafile1() {}
-    
-    void DrawBitmap1() {}
-    void DrawBitmap2() {}
-    void DrawBitmap3() {}
-    
-    void FillOpacityMask1() {}
-    void FillOpacityMask2() {}   
-    
-    //
-    // Sets tuning parameters for internal rendering inside the device context.
-    //
-    void SetRenderingControls1() {}
-}; // interface ID2D1DeviceContext
-
-#endif // #ifndef _D2D1_1_H_
--- a/gfx/gl/GLContextEGL.h
+++ b/gfx/gl/GLContextEGL.h
@@ -99,19 +99,16 @@ public:
         return sEGLLibrary.Display();
     }
 
     bool BindTex2DOffscreen(GLContext *aOffscreen);
     void UnbindTex2DOffscreen(GLContext *aOffscreen);
     void BindOffscreenFramebuffer();
 
     static already_AddRefed<GLContextEGL>
-    CreateEGLPixmapOffscreenContext(const gfx::IntSize& size);
-
-    static already_AddRefed<GLContextEGL>
     CreateEGLPBufferOffscreenContext(CreateContextFlags flags,
                                      const gfx::IntSize& size,
                                      const SurfaceCaps& minCaps);
 
 protected:
     friend class GLContextProviderEGL;
 
 public:
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -960,56 +960,16 @@ GLContextEGL::CreateEGLPBufferOffscreenC
         NS_WARNING("Failed to initialize GLContext!");
         // GLContextEGL::dtor will destroy |surface| for us.
         return nullptr;
     }
 
     return gl.forget();
 }
 
-/*static*/ already_AddRefed<GLContextEGL>
-GLContextEGL::CreateEGLPixmapOffscreenContext(const mozilla::gfx::IntSize& size)
-{
-    gfxASurface *thebesSurface = nullptr;
-    EGLNativePixmapType pixmap = 0;
-
-    if (!pixmap) {
-        return nullptr;
-    }
-
-    EGLSurface surface = 0;
-    EGLConfig config = 0;
-
-    if (!config) {
-        return nullptr;
-    }
-    MOZ_ASSERT(surface);
-
-    SurfaceCaps dummyCaps = SurfaceCaps::Any();
-    RefPtr<GLContextEGL> glContext =
-        GLContextEGL::CreateGLContext(CreateContextFlags::NONE, dummyCaps,
-                                      nullptr, true,
-                                      config, surface);
-    if (!glContext) {
-        NS_WARNING("Failed to create GLContext from XSurface");
-        sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface);
-        return nullptr;
-    }
-
-    if (!glContext->Init()) {
-        NS_WARNING("Failed to initialize GLContext!");
-        // GLContextEGL::dtor will destroy |surface| for us.
-        return nullptr;
-    }
-
-    glContext->HoldSurface(thebesSurface);
-
-    return glContext.forget();
-}
-
 /*static*/ already_AddRefed<GLContext>
 GLContextProviderEGL::CreateHeadless(CreateContextFlags flags)
 {
     bool forceEnableHardware = bool(flags & CreateContextFlags::FORCE_ENABLE_HARDWARE);
     if (!sEGLLibrary.EnsureInitialized(forceEnableHardware))
         return nullptr;
 
     mozilla::gfx::IntSize dummySize = mozilla::gfx::IntSize(16, 16);
--- a/gfx/gl/GLLibraryEGL.h
+++ b/gfx/gl/GLLibraryEGL.h
@@ -103,19 +103,62 @@ namespace gl {
 class GLContext;
 
 class GLLibraryEGL
 {
 public:
     GLLibraryEGL()
         : mInitialized(false),
           mEGLLibrary(nullptr),
+          mEGLDisplay(EGL_NO_DISPLAY),
           mIsANGLE(false),
           mIsWARP(false)
     {
+        ClearSymbols();
+    }
+
+    void ClearSymbols() {
+        mSymbols.fGetDisplay = nullptr;
+        mSymbols.fGetPlatformDisplayEXT = nullptr;
+        mSymbols.fTerminate = nullptr;
+        mSymbols.fGetCurrentSurface = nullptr;
+        mSymbols.fGetCurrentContext = nullptr;
+        mSymbols.fMakeCurrent = nullptr;
+        mSymbols.fDestroyContext = nullptr;
+        mSymbols.fCreateContext = nullptr;
+        mSymbols.fDestroySurface = nullptr;
+        mSymbols.fCreateWindowSurface = nullptr;
+        mSymbols.fCreatePbufferSurface = nullptr;
+        mSymbols.fCreatePixmapSurface = nullptr;
+        mSymbols.fBindAPI = nullptr;
+        mSymbols.fInitialize = nullptr;
+        mSymbols.fChooseConfig = nullptr;
+        mSymbols.fGetError = nullptr;
+        mSymbols.fGetConfigAttrib = nullptr;
+        mSymbols.fGetConfigs = nullptr;
+        mSymbols.fWaitNative = nullptr;
+        mSymbols.fGetProcAddress = nullptr;
+        mSymbols.fSwapBuffers = nullptr;
+        mSymbols.fCopyBuffers = nullptr;
+        mSymbols.fQueryString = nullptr;
+        mSymbols.fQueryStringImplementationANDROID = nullptr;
+        mSymbols.fQueryContext = nullptr;
+        mSymbols.fBindTexImage = nullptr;
+        mSymbols.fReleaseTexImage = nullptr;
+        mSymbols.fCreateImage = nullptr;
+        mSymbols.fDestroyImage = nullptr;
+        mSymbols.fLockSurface = nullptr;
+        mSymbols.fUnlockSurface = nullptr;
+        mSymbols.fQuerySurface = nullptr;
+        mSymbols.fQuerySurfacePointerANGLE = nullptr;
+        mSymbols.fCreateSync = nullptr;
+        mSymbols.fDestroySync = nullptr;
+        mSymbols.fClientWaitSync = nullptr;
+        mSymbols.fGetSyncAttrib = nullptr;
+        mSymbols.fDupNativeFenceFDANDROID = nullptr;
     }
 
     void InitClientExtensions();
     void InitDisplayExtensions();
 
     /**
      * Known GL extensions that can be queried by
      * IsExtensionSupported.  The results of this are cached, and as
--- a/gfx/gl/GLXLibrary.h
+++ b/gfx/gl/GLXLibrary.h
@@ -27,23 +27,46 @@ struct PRLibrary;
 class gfxASurface;
 
 namespace mozilla {
 namespace gl {
 
 class GLXLibrary
 {
 public:
-    GLXLibrary() : mInitialized(false), mTriedInitializing(false),
-                   mUseTextureFromPixmap(false), mDebug(false),
-                   mHasRobustness(false), mHasCreateContextAttribs(false),
-                   mIsATI(false), mIsNVIDIA(false),
-                   mClientIsMesa(false), mGLXMajorVersion(0),
-                   mGLXMinorVersion(0),
-                   mOGLLibrary(nullptr) {}
+    GLXLibrary()
+    : xDestroyContextInternal(nullptr)
+    , xMakeCurrentInternal(nullptr)
+    , xGetCurrentContextInternal(nullptr)
+    , xGetProcAddressInternal(nullptr)
+    , xChooseFBConfigInternal(nullptr)
+    , xGetFBConfigsInternal(nullptr)
+    , xCreateNewContextInternal(nullptr)
+    , xGetFBConfigAttribInternal(nullptr)
+    , xSwapBuffersInternal(nullptr)
+    , xQueryExtensionsStringInternal(nullptr)
+    , xGetClientStringInternal(nullptr)
+    , xQueryServerStringInternal(nullptr)
+    , xCreatePixmapInternal(nullptr)
+    , xCreateGLXPixmapWithConfigInternal(nullptr)
+    , xDestroyPixmapInternal(nullptr)
+    , xQueryVersionInternal(nullptr)
+    , xBindTexImageInternal(nullptr)
+    , xReleaseTexImageInternal(nullptr)
+    , xWaitGLInternal(nullptr)
+    , xWaitXInternal(nullptr)
+    , xCreateContextAttribsInternal(nullptr)
+    , mInitialized(false), mTriedInitializing(false)
+    , mUseTextureFromPixmap(false), mDebug(false)
+    , mHasRobustness(false), mHasCreateContextAttribs(false)
+    , mIsATI(false), mIsNVIDIA(false)
+    , mClientIsMesa(false), mGLXMajorVersion(0)
+    , mGLXMinorVersion(0)
+    , mOGLLibrary(nullptr)
+    {}
 
     void xDestroyContext(Display* display, GLXContext context);
     Bool xMakeCurrent(Display* display, 
                       GLXDrawable drawable, 
                       GLXContext context);
 
     GLXContext xGetCurrentContext();
     static void* xGetProcAddress(const char *procName);
--- a/gfx/layers/ImageContainer.h
+++ b/gfx/layers/ImageContainer.h
@@ -862,17 +862,17 @@ public:
   void SetData(const SidebandStreamData& aData)
   {
     mSidebandStream = aData.mStream;
     mSize = aData.mSize;
   }
 
   already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() { return nullptr; } ;
   int32_t GetOverlayId() { return mOverlayId; }
-  const GonkNativeHandle& GetSidebandStream() { return mSidebandStream; }
+  GonkNativeHandle& GetSidebandStream() { return mSidebandStream; }
 
   gfx::IntSize GetSize() { return mSize; }
 
 private:
   int32_t mOverlayId;
   GonkNativeHandle mSidebandStream;
   gfx::IntSize mSize;
 };
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -1133,21 +1133,22 @@ APZCTreeManager::ReceiveInputEvent(Widge
     default: {
       return ProcessEvent(aEvent, aOutTargetGuid, aOutInputBlockId);
     }
   }
 }
 
 void
 APZCTreeManager::ZoomToRect(const ScrollableLayerGuid& aGuid,
-                            const CSSRect& aRect)
+                            const CSSRect& aRect,
+                            const uint32_t aFlags)
 {
   RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
   if (apzc) {
-    apzc->ZoomToRect(aRect);
+    apzc->ZoomToRect(aRect, aFlags);
   }
 }
 
 void
 APZCTreeManager::ContentReceivedInputBlock(uint64_t aInputBlockId, bool aPreventDefault)
 {
   APZThreadUtils::AssertOnControllerThread();
 
--- a/gfx/layers/apz/src/APZCTreeManager.h
+++ b/gfx/layers/apz/src/APZCTreeManager.h
@@ -36,16 +36,22 @@ enum AllowedTouchBehavior {
   NONE =               0,
   VERTICAL_PAN =       1 << 0,
   HORIZONTAL_PAN =     1 << 1,
   PINCH_ZOOM =         1 << 2,
   DOUBLE_TAP_ZOOM =    1 << 3,
   UNKNOWN =            1 << 4
 };
 
+enum ZoomToRectBehavior : uint32_t {
+  DEFAULT_BEHAVIOR =   0,
+  DISABLE_ZOOM_OUT =   1 << 0,
+  PAN_INTO_VIEW_ONLY = 1 << 1
+};
+
 class Layer;
 class AsyncDragMetrics;
 class AsyncPanZoomController;
 class CompositorParent;
 class OverscrollHandoffChain;
 struct OverscrollHandoffState;
 struct FlingHandoffState;
 class LayerMetricsWrapper;
@@ -200,19 +206,21 @@ public:
   nsEventStatus ReceiveInputEvent(WidgetInputEvent& aEvent,
                                   ScrollableLayerGuid* aOutTargetGuid,
                                   uint64_t* aOutInputBlockId);
 
   /**
    * Kicks an animation to zoom to a rect. This may be either a zoom out or zoom
    * in. The actual animation is done on the compositor thread after being set
    * up. |aRect| must be given in CSS pixels, relative to the document.
+   * |aFlags| is a combination of the ZoomToRectBehavior enum values.
    */
   void ZoomToRect(const ScrollableLayerGuid& aGuid,
-                  const CSSRect& aRect);
+                  const CSSRect& aRect,
+                  const uint32_t aFlags = DEFAULT_BEHAVIOR);
 
   /**
    * If we have touch listeners, this should always be called when we know
    * definitively whether or not content has preventDefaulted any touch events
    * that have come in. If |aPreventDefault| is true, any touch events in the
    * queue will be discarded. This function must be called on the controller
    * thread.
    */
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -3367,17 +3367,17 @@ const FrameMetrics& AsyncPanZoomControll
   return mFrameMetrics;
 }
 
 APZCTreeManager* AsyncPanZoomController::GetApzcTreeManager() const {
   mMonitor.AssertNotCurrentThreadIn();
   return mTreeManager;
 }
 
-void AsyncPanZoomController::ZoomToRect(CSSRect aRect) {
+void AsyncPanZoomController::ZoomToRect(CSSRect aRect, const uint32_t aFlags) {
   if (!aRect.IsFinite()) {
     NS_WARNING("ZoomToRect got called with a non-finite rect; ignoring...");
     return;
   }
 
   // Only the root APZC is zoomable, and the root APZC is not allowed to have
   // different x and y scales. If it did, the calculations in this function
   // would have to be adjusted (as e.g. it would no longer be valid to take
@@ -3408,26 +3408,32 @@ void AsyncPanZoomController::ZoomToRect(
     CSSToParentLayerScale localMaxZoom = mZoomConstraints.mMaxZoom;
 
     if (!aRect.IsEmpty()) {
       // Intersect the zoom-to-rect to the CSS rect to make sure it fits.
       aRect = aRect.Intersect(cssPageRect);
       targetZoom = CSSToParentLayerScale(std::min(compositionBounds.width / aRect.width,
                                                   compositionBounds.height / aRect.height));
     }
+
     // 1. If the rect is empty, the content-side logic for handling a double-tap
     //    requested that we zoom out.
     // 2. currentZoom is equal to mZoomConstraints.mMaxZoom and user still double-tapping it
     // 3. currentZoom is equal to localMinZoom and user still double-tapping it
     // Treat these three cases as a request to zoom out as much as possible.
-    bool zoomOut = false;
-    if (aRect.IsEmpty() ||
+    bool zoomOut;
+    if (aFlags & DISABLE_ZOOM_OUT) {
+      zoomOut = false;
+    } else {
+      zoomOut = aRect.IsEmpty() ||
         (currentZoom == localMaxZoom && targetZoom >= localMaxZoom) ||
-        (currentZoom == localMinZoom && targetZoom <= localMinZoom)) {
-      zoomOut = true;
+        (currentZoom == localMinZoom && targetZoom <= localMinZoom);
+    }
+
+    if (zoomOut) {
       CSSSize compositedSize = mFrameMetrics.CalculateCompositedSizeInCssPixels();
       float y = scrollOffset.y;
       float newHeight =
         cssPageRect.width * (compositedSize.height / compositedSize.width);
       float dh = compositedSize.height - newHeight;
 
       aRect = CSSRect(0.0f,
                       y + dh/2,
@@ -3435,16 +3441,19 @@ void AsyncPanZoomController::ZoomToRect(
                       newHeight);
       aRect = aRect.Intersect(cssPageRect);
       targetZoom = CSSToParentLayerScale(std::min(compositionBounds.width / aRect.width,
                                                   compositionBounds.height / aRect.height));
     }
 
     targetZoom.scale = clamped(targetZoom.scale, localMinZoom.scale, localMaxZoom.scale);
     FrameMetrics endZoomToMetrics = mFrameMetrics;
+    if (aFlags & PAN_INTO_VIEW_ONLY) {
+      targetZoom = currentZoom;
+    }
     endZoomToMetrics.SetZoom(CSSToParentLayerScale2D(targetZoom));
 
     // Adjust the zoomToRect to a sensible position to prevent overscrolling.
     CSSSize sizeAfterZoom = endZoomToMetrics.CalculateCompositedSizeInCssPixels();
 
     // If either of these conditions are met, the page will be
     // overscrolled after zoomed
     if (aRect.y + sizeAfterZoom.height > cssPageRect.height) {
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -121,17 +121,17 @@ public:
   // These methods must only be called on the controller/UI thread.
   //
 
   /**
    * Kicks an animation to zoom to a rect. This may be either a zoom out or zoom
    * in. The actual animation is done on the compositor thread after being set
    * up.
    */
-  void ZoomToRect(CSSRect aRect);
+  void ZoomToRect(CSSRect aRect, const uint32_t aFlags);
 
   /**
    * Updates any zoom constraints contained in the <meta name="viewport"> tag.
    */
   void UpdateZoomConstraints(const ZoomConstraints& aConstraints);
 
   /**
    * Return the zoom constraints last set for this APZC (in the constructor
--- a/gfx/layers/apz/util/DoubleTapToZoom.cpp
+++ b/gfx/layers/apz/util/DoubleTapToZoom.cpp
@@ -65,57 +65,16 @@ ShouldZoomToElement(const nsCOMPtr<dom::
     }
   }
   if (aElement->IsAnyOfHTMLElements(nsGkAtoms::li, nsGkAtoms::q)) {
     return false;
   }
   return true;
 }
 
-// Calculate the bounding rect of |aElement|, relative to the origin
-// of the scrolled content of |aRootScrollFrame|.
-// The implementation of this calculation is adapted from
-// Element::GetBoundingClientRect().
-//
-// Where the element is contained inside a scrollable subframe, the
-// bounding rect is clipped to the bounds of the subframe.
-static CSSRect
-GetBoundingContentRect(const nsCOMPtr<dom::Element>& aElement,
-                       const nsIScrollableFrame* aRootScrollFrame) {
-
-  CSSRect result;
-  if (nsIFrame* frame = aElement->GetPrimaryFrame()) {
-    nsIFrame* relativeTo = aRootScrollFrame->GetScrolledFrame();
-    result = CSSRect::FromAppUnits(
-        nsLayoutUtils::GetAllInFlowRectsUnion(
-            frame,
-            relativeTo,
-            nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS));
-
-    // If the element is contained in a scrollable frame that is not
-    // the root scroll frame, make sure to clip the result so that it is
-    // not larger than the containing scrollable frame's bounds.
-    nsIScrollableFrame* scrollFrame = nsLayoutUtils::GetNearestScrollableFrame(frame);
-    if (scrollFrame && scrollFrame != aRootScrollFrame) {
-      nsIFrame* subFrame = do_QueryFrame(scrollFrame);
-      MOZ_ASSERT(subFrame);
-      // Get the bounds of the scroll frame in the same coordinate space
-      // as |result|.
-      CSSRect subFrameRect = CSSRect::FromAppUnits(
-          nsLayoutUtils::TransformFrameRectToAncestor(
-              subFrame,
-              subFrame->GetRectRelativeToSelf(),
-              relativeTo));
-
-      result = subFrameRect.Intersect(result);
-    }
-  }
-  return result;
-}
-
 static bool
 IsRectZoomedIn(const CSSRect& aRect, const CSSRect& aCompositedArea)
 {
   // This functions checks to see if the area of the rect visible in the
   // composition bounds (i.e. the overlapArea variable below) is approximately
   // the max area of the rect we can show.
   CSSRect overlap = aCompositedArea.Intersect(aRect);
   float overlapArea = overlap.width * overlap.height;
@@ -159,17 +118,17 @@ CalculateRectToZoomTo(const nsCOMPtr<nsI
 
   if (!element) {
     return zoomOut;
   }
 
   FrameMetrics metrics = nsLayoutUtils::CalculateBasicFrameMetrics(rootScrollFrame);
   CSSRect compositedArea(metrics.GetScrollOffset(), metrics.CalculateCompositedSizeInCssPixels());
   const CSSCoord margin = 15;
-  CSSRect rect = GetBoundingContentRect(element, rootScrollFrame);
+  CSSRect rect = nsLayoutUtils::GetBoundingContentRect(element, rootScrollFrame);
 
   // If the element is taller than the visible area of the page scale
   // the height of the |rect| so that it has the same aspect ratio as
   // the root frame.  The clipped |rect| is centered on the y value of
   // the touch point. This allows tall narrow elements to be zoomed.
   if (!rect.IsEmpty() && compositedArea.width > 0.0f) {
     const float widthRatio = rect.width / compositedArea.width;
     float targetHeight = compositedArea.height * widthRatio;
--- a/gfx/layers/basic/X11TextureSourceBasic.cpp
+++ b/gfx/layers/basic/X11TextureSourceBasic.cpp
@@ -30,22 +30,19 @@ X11TextureSourceBasic::GetFormat() const
   gfxContentType type = mSurface->GetContentType();
   return X11TextureSourceBasic::ContentTypeToSurfaceFormat(type);
 }
 
 SourceSurface*
 X11TextureSourceBasic::GetSurface(DrawTarget* aTarget)
 {
   if (!mSourceSurface) {
-    NativeSurface surf;
-    surf.mFormat = GetFormat();
-    surf.mType = NativeSurfaceType::CAIRO_CONTEXT;
-    surf.mSurface = mSurface->CairoSurface();
-    surf.mSize = GetSize();
-    mSourceSurface = aTarget->CreateSourceSurfaceFromNativeSurface(surf);
+    mSourceSurface =
+        Factory::CreateSourceSurfaceForCairoSurface(mSurface->CairoSurface(),
+                                                    GetSize(), GetFormat());
   }
   return mSourceSurface;
 }
 
 void
 X11TextureSourceBasic::SetCompositor(Compositor* aCompositor)
 {
   MOZ_ASSERT(aCompositor->GetBackendType() == LayersBackend::LAYERS_BASIC);
--- a/gfx/layers/client/ImageClient.cpp
+++ b/gfx/layers/client/ImageClient.cpp
@@ -1,22 +1,26 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ImageClient.h"
+
 #include <stdint.h>                     // for uint32_t
+
+#include "ClientLayerManager.h"         // for ClientLayer
 #include "ImageContainer.h"             // for Image, PlanarYCbCrImage, etc
 #include "ImageTypes.h"                 // for ImageFormat::PLANAR_YCBCR, etc
 #include "GLImages.h"                   // for SurfaceTextureImage::Data, etc
 #include "gfx2DGlue.h"                  // for ImageFormatToSurfaceFormat
 #include "gfxPlatform.h"                // for gfxPlatform
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/RefPtr.h"             // for RefPtr, already_AddRefed
+#include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat, etc
 #include "mozilla/layers/CompositableClient.h"  // for CompositableClient
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/layers/CompositorTypes.h"  // for CompositableType, etc
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor, etc
@@ -24,17 +28,17 @@
 #include "mozilla/layers/TextureClient.h"  // for TextureClient, etc
 #include "mozilla/layers/TextureClientOGL.h"  // for SurfaceTextureClient
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_WARNING, NS_ASSERTION
 #include "nsISupportsImpl.h"            // for Image::Release, etc
 #include "nsRect.h"                     // for mozilla::gfx::IntRect
-#include "mozilla/gfx/2D.h"
+
 #ifdef MOZ_WIDGET_GONK
 #include "GrallocImages.h"
 #endif
 
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gfx;
@@ -150,17 +154,25 @@ ImageClientSingle::UpdateImage(ImageCont
   for (auto& img : images) {
     Image* image = img.mImage;
 
 #ifdef MOZ_WIDGET_GONK
     if (image->GetFormat() == ImageFormat::OVERLAY_IMAGE) {
       OverlayImage* overlayImage = static_cast<OverlayImage*>(image);
       OverlaySource source;
       if (overlayImage->GetSidebandStream().IsValid()) {
-        source.handle() = OverlayHandle(overlayImage->GetSidebandStream());
+        // Duplicate GonkNativeHandle::NhObj for ipc,
+        // since ParamTraits<GonkNativeHandle>::Write() absorbs native_handle_t.
+        RefPtr<GonkNativeHandle::NhObj> nhObj = overlayImage->GetSidebandStream().GetDupNhObj();
+        GonkNativeHandle handle(nhObj);
+        if (!handle.IsValid()) {
+          gfxWarning() << "ImageClientSingle::UpdateImage failed in GetDupNhObj";
+          return false;
+        }
+        source.handle() = OverlayHandle(handle);
       } else {
         source.handle() = OverlayHandle(overlayImage->GetOverlayId());
       }
       source.size() = overlayImage->GetSize();
       GetForwarder()->UseOverlaySource(this, source, image->GetPictureRect());
       continue;
     }
 #endif
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -201,16 +201,17 @@ static void DestroyTextureData(TextureDa
     aTextureData->Forget(aAllocator);
   }
   delete aTextureData;
 }
 
 void
 TextureChild::ActorDestroy(ActorDestroyReason why)
 {
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::GRAPHICS);
   mWaitForRecycle = nullptr;
 
   if (mTextureData) {
     DestroyTextureData(mTextureData, GetAllocator(), mOwnsTextureData, mMainThreadOnly);
     mTextureData = nullptr;
   }
 }
 
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -70,16 +70,17 @@
 #include "mozilla/StaticPtr.h"
 #ifdef MOZ_ENABLE_PROFILER_SPS
 #include "ProfilerMarkers.h"
 #endif
 #include "mozilla/VsyncDispatcher.h"
 
 #ifdef MOZ_WIDGET_GONK
 #include "GeckoTouchDispatcher.h"
+#include "nsScreenManagerGonk.h"
 #endif
 
 #include "LayerScope.h"
 
 namespace mozilla {
 
 namespace gfx {
 // See VRManagerChild.cpp
@@ -281,30 +282,42 @@ CompositorVsyncScheduler::Observer::Dest
 {
   MutexAutoLock lock(mMutex);
   mOwner = nullptr;
 }
 
 CompositorVsyncScheduler::CompositorVsyncScheduler(CompositorParent* aCompositorParent, nsIWidget* aWidget)
   : mCompositorParent(aCompositorParent)
   , mLastCompose(TimeStamp::Now())
-  , mCurrentCompositeTask(nullptr)
   , mIsObservingVsync(false)
   , mNeedsComposite(0)
   , mVsyncNotificationsSkipped(0)
   , mCurrentCompositeTaskMonitor("CurrentCompositeTaskMonitor")
+  , mCurrentCompositeTask(nullptr)
   , mSetNeedsCompositeMonitor("SetNeedsCompositeMonitor")
   , mSetNeedsCompositeTask(nullptr)
+#ifdef MOZ_WIDGET_GONK
+#if ANDROID_VERSION >= 19
+  , mDisplayEnabled(false)
+  , mSetDisplayMonitor("SetDisplayMonitor")
+  , mSetDisplayTask(nullptr)
+#endif
+#endif
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aWidget != nullptr);
   mVsyncObserver = new Observer(this);
   mCompositorVsyncDispatcher = aWidget->GetCompositorVsyncDispatcher();
 #ifdef MOZ_WIDGET_GONK
   GeckoTouchDispatcher::GetInstance()->SetCompositorVsyncScheduler(this);
+
+#if ANDROID_VERSION >= 19
+  RefPtr<nsScreenManagerGonk> screenManager = nsScreenManagerGonk::GetInstance();
+  screenManager->SetCompositorVsyncScheduler(this);
+#endif
 #endif
 
   // mAsapScheduling is set on the main thread during init,
   // but is only accessed after on the compositor thread.
   mAsapScheduling = gfxPrefs::LayersCompositionFrameRate() == 0 ||
                     gfxPlatform::IsInLayoutAsapMode();
 }
 
@@ -312,23 +325,77 @@ CompositorVsyncScheduler::~CompositorVsy
 {
   MOZ_ASSERT(!mIsObservingVsync);
   MOZ_ASSERT(!mVsyncObserver);
   // The CompositorVsyncDispatcher is cleaned up before this in the nsBaseWidget, which stops vsync listeners
   mCompositorParent = nullptr;
   mCompositorVsyncDispatcher = nullptr;
 }
 
+#ifdef MOZ_WIDGET_GONK
+#if ANDROID_VERSION >= 19
+void
+CompositorVsyncScheduler::SetDisplay(bool aDisplayEnable)
+{
+  // SetDisplay() is usually called from nsScreenManager at main thread. Post
+  // to compositor thread if needs.
+  if (!CompositorParent::IsInCompositorThread()) {
+    MOZ_ASSERT(NS_IsMainThread());
+    MonitorAutoLock lock(mSetDisplayMonitor);
+    mSetDisplayTask = NewRunnableMethod(this,
+                                        &CompositorVsyncScheduler::SetDisplay,
+                                        aDisplayEnable);
+    ScheduleTask(mSetDisplayTask, 0);
+    return;
+  } else {
+    MonitorAutoLock lock(mSetDisplayMonitor);
+    mSetDisplayTask = nullptr;
+  }
+
+  if (mDisplayEnabled == aDisplayEnable) {
+    return;
+  }
+
+  mDisplayEnabled = aDisplayEnable;
+  if (!mDisplayEnabled) {
+    CancelCurrentSetNeedsCompositeTask();
+    CancelCurrentCompositeTask();
+  }
+}
+
+void
+CompositorVsyncScheduler::CancelSetDisplayTask()
+{
+  MOZ_ASSERT(CompositorParent::IsInCompositorThread());
+  MonitorAutoLock lock(mSetDisplayMonitor);
+  if (mSetDisplayTask) {
+    mSetDisplayTask->Cancel();
+    mSetDisplayTask = nullptr;
+  }
+
+  // CancelSetDisplayTask is only be called in clean-up process, so
+  // mDisplayEnabled could be false there.
+  mDisplayEnabled = false;
+}
+#endif //ANDROID_VERSION >= 19
+#endif //MOZ_WIDGET_GONK
+
 void
 CompositorVsyncScheduler::Destroy()
 {
   MOZ_ASSERT(CompositorParent::IsInCompositorThread());
   UnobserveVsync();
   mVsyncObserver->Destroy();
   mVsyncObserver = nullptr;
+
+#ifdef MOZ_WIDGET_GONK
+#if ANDROID_VERSION >= 19
+  CancelSetDisplayTask();
+#endif
+#endif
   CancelCurrentSetNeedsCompositeTask();
   CancelCurrentCompositeTask();
 }
 
 void
 CompositorVsyncScheduler::PostCompositeTask(TimeStamp aCompositeTimestamp)
 {
   // can be called from the compositor or vsync thread
@@ -391,16 +458,25 @@ CompositorVsyncScheduler::SetNeedsCompos
                                               &CompositorVsyncScheduler::SetNeedsComposite);
     ScheduleTask(mSetNeedsCompositeTask, 0);
     return;
   } else {
     MonitorAutoLock lock(mSetNeedsCompositeMonitor);
     mSetNeedsCompositeTask = nullptr;
   }
 
+#ifdef MOZ_WIDGET_GONK
+#if ANDROID_VERSION >= 19
+  // Skip composition when display off.
+  if (!mDisplayEnabled) {
+    return;
+  }
+#endif
+#endif
+
   mNeedsComposite++;
   if (!mIsObservingVsync && mNeedsComposite) {
     ObserveVsync();
   }
 }
 
 bool
 CompositorVsyncScheduler::NotifyVsync(TimeStamp aVsyncTimestamp)
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -95,16 +95,30 @@ private:
  * Turns vsync notifications into scheduled composites.
  **/
 class CompositorVsyncScheduler
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorVsyncScheduler)
 
 public:
   explicit CompositorVsyncScheduler(CompositorParent* aCompositorParent, nsIWidget* aWidget);
+
+#ifdef MOZ_WIDGET_GONK
+  // emulator-ics never trigger the display on/off, so compositor will always
+  // skip composition request at that device. Only check the display status
+  // with kk device and upon.
+#if ANDROID_VERSION >= 19
+  // SetDisplay() and CancelSetDisplayTask() are used for the display on/off.
+  // It will clear all composition related task and flag, and skip another
+  // composition task during the display off. That could prevent the problem
+  // that compositor might show the old content at the first frame of display on.
+  void SetDisplay(bool aDisplayEnable);
+#endif
+#endif
+
   bool NotifyVsync(TimeStamp aVsyncTimestamp);
   void SetNeedsComposite();
   void OnForceComposeToTarget();
 
   void ScheduleTask(CancelableTask*, int);
   void ResumeComposition();
   void ComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr);
   void PostCompositeTask(TimeStamp aCompositeTimestamp);
@@ -123,26 +137,31 @@ public:
   }
 
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
   const TimeStamp& GetExpectedComposeStartTime()
   {
     return mExpectedComposeStartTime;
   }
 #endif
- 
+
 private:
   virtual ~CompositorVsyncScheduler();
 
   void NotifyCompositeTaskExecuted();
   void ObserveVsync();
   void UnobserveVsync();
   void DispatchTouchEvents(TimeStamp aVsyncTimestamp);
   void DispatchVREvents(TimeStamp aVsyncTimestamp);
   void CancelCurrentSetNeedsCompositeTask();
+#ifdef MOZ_WIDGET_GONK
+#if ANDROID_VERSION >= 19
+  void CancelSetDisplayTask();
+#endif
+#endif
 
   class Observer final : public VsyncObserver
   {
   public:
     explicit Observer(CompositorVsyncScheduler* aOwner);
     virtual bool NotifyVsync(TimeStamp aVsyncTimestamp) override;
     void Destroy();
   private:
@@ -150,33 +169,41 @@ private:
 
     Mutex mMutex;
     // Hold raw pointer to avoid mutual reference.
     CompositorVsyncScheduler* mOwner;
   };
 
   CompositorParent* mCompositorParent;
   TimeStamp mLastCompose;
-  CancelableTask* mCurrentCompositeTask;
 
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
   TimeStamp mExpectedComposeStartTime;
 #endif
 
   bool mAsapScheduling;
   bool mIsObservingVsync;
   uint32_t mNeedsComposite;
   int32_t mVsyncNotificationsSkipped;
   RefPtr<CompositorVsyncDispatcher> mCompositorVsyncDispatcher;
   RefPtr<CompositorVsyncScheduler::Observer> mVsyncObserver;
 
   mozilla::Monitor mCurrentCompositeTaskMonitor;
+  CancelableTask* mCurrentCompositeTask;
 
   mozilla::Monitor mSetNeedsCompositeMonitor;
   CancelableTask* mSetNeedsCompositeTask;
+
+#ifdef MOZ_WIDGET_GONK
+#if ANDROID_VERSION >= 19
+  bool mDisplayEnabled;
+  mozilla::Monitor mSetDisplayMonitor;
+  CancelableTask* mSetDisplayTask;
+#endif
+#endif
 };
 
 class CompositorUpdateObserver
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorUpdateObserver);
 
   virtual void ObserveUpdate(uint64_t aLayersId, bool aActive) = 0;
--- a/gfx/layers/ipc/GonkNativeHandle.cpp
+++ b/gfx/layers/ipc/GonkNativeHandle.cpp
@@ -38,28 +38,41 @@ GonkNativeHandle::GetAndResetNhObj()
   RefPtr<NhObj> nhObj = mNhObj;
   mNhObj = new NhObj();
   return nhObj.forget();
 }
 
 already_AddRefed<GonkNativeHandle::NhObj>
 GonkNativeHandle::GetDupNhObj()
 {
+  if (!IsValid()) {
+    return GonkNativeHandle::CreateDupNhObj(nullptr);
+  }
+  return GonkNativeHandle::CreateDupNhObj(mNhObj->mHandle);
+}
+
+/* static */ already_AddRefed<GonkNativeHandle::NhObj>
+GonkNativeHandle::CreateDupNhObj(native_handle_t* aHandle)
+{
   RefPtr<NhObj> nhObj;
-  if (IsValid()) {
+  if (aHandle) {
     native_handle* nativeHandle =
-      native_handle_create(mNhObj->mHandle->numFds, mNhObj->mHandle->numInts);
+      native_handle_create(aHandle->numFds, aHandle->numInts);
+    if (!nativeHandle) {
+      nhObj = new GonkNativeHandle::NhObj();
+      return nhObj.forget();
+    }
 
-    for (int i = 0; i < mNhObj->mHandle->numFds; ++i) {
-        nativeHandle->data[i] = dup(mNhObj->mHandle->data[i]);
+    for (int i = 0; i < aHandle->numFds; ++i) {
+      nativeHandle->data[i] = dup(aHandle->data[i]);
     }
 
     memcpy(nativeHandle->data + nativeHandle->numFds,
-           mNhObj->mHandle->data + mNhObj->mHandle->numFds,
-           sizeof(int) * mNhObj->mHandle->numInts);
+           aHandle->data + aHandle->numFds,
+           sizeof(int) * aHandle->numInts);
 
     nhObj = new GonkNativeHandle::NhObj(nativeHandle);
   } else {
     nhObj = new GonkNativeHandle::NhObj();
   }
   return nhObj.forget();
 }
 
--- a/gfx/layers/ipc/GonkNativeHandle.h
+++ b/gfx/layers/ipc/GonkNativeHandle.h
@@ -66,16 +66,18 @@ public:
   }
 
   void TransferToAnother(GonkNativeHandle& aHandle);
 
   already_AddRefed<NhObj> GetAndResetNhObj();
 
   already_AddRefed<NhObj> GetDupNhObj();
 
+  static already_AddRefed<NhObj> CreateDupNhObj(native_handle_t* aHandle);
+
   // Return non owning handle.
   native_handle_t* GetRawNativeHandle() const
   {
     if (mNhObj) {
       return mNhObj->mHandle;
     }
     return nullptr;
   }
--- a/gfx/layers/opengl/OGLShaderProgram.cpp
+++ b/gfx/layers/opengl/OGLShaderProgram.cpp
@@ -3,16 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "OGLShaderProgram.h"
 #include <stdint.h>                     // for uint32_t
 #include <sstream>                      // for ostringstream
 #include "gfxEnv.h"
 #include "gfxRect.h"                    // for gfxRect
 #include "mozilla/DebugOnly.h"          // for DebugOnly
+#include "mozilla/layers/Compositor.h"  // for BlendOpIsMixBlendMode
 #include "nsAString.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsString.h"                   // for nsAutoCString
 #include "Layers.h"
 #include "GLContext.h"
 
 namespace mozilla {
 namespace layers {
@@ -157,30 +158,30 @@ ShaderConfigOGL::SetNoPremultipliedAlpha
 
 void
 ShaderConfigOGL::SetDEAA(bool aEnabled)
 {
   SetFeature(ENABLE_DEAA, aEnabled);
 }
 
 void
-ShaderConfigOGL::SetCompositionOp(CompositionOp aOp)
+ShaderConfigOGL::SetCompositionOp(gfx::CompositionOp aOp)
 {
   mCompositionOp = aOp;
 }
 
 /* static */ ProgramProfileOGL
 ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
 {
   ProgramProfileOGL result;
   ostringstream fs, vs;
 
   AddUniforms(result);
 
-  CompositionOp blendOp = aConfig.mCompositionOp;
+  gfx::CompositionOp blendOp = aConfig.mCompositionOp;
 
   vs << "#ifdef GL_ES" << endl;
   vs << "#define EDGE_PRECISION mediump" << endl;
   vs << "#else" << endl;
   vs << "#define EDGE_PRECISION" << endl;
   vs << "#endif" << endl;
   vs << "uniform mat4 uMatrixProj;" << endl;
   vs << "uniform vec4 uLayerRects[4];" << endl;
--- a/gfx/tests/gtest/TestVsync.cpp
+++ b/gfx/tests/gtest/TestVsync.cpp
@@ -17,17 +17,18 @@
 #include "mozilla/VsyncDispatcher.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 using ::testing::_;
 
 // Timeout for vsync events to occur in milliseconds
-const int kVsyncTimeoutMS = 50;
+// Windows 8.1 has intermittents at 50 ms. Raise limit to 5 vsync intervals.
+const int kVsyncTimeoutMS = 80;
 
 class TestVsyncObserver : public VsyncObserver {
 public:
   TestVsyncObserver()
     : mDidGetVsyncNotification(false)
     , mVsyncMonitor("VsyncMonitor")
   {
   }
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -519,16 +519,18 @@ gfxDWriteFontEntry::GetFontTable(uint32_
     }
 
     return nullptr;
 }
 
 nsresult
 gfxDWriteFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
 {
+    PROFILER_LABEL_FUNC(js::ProfileEntry::Category::GRAPHICS);
+
     // attempt this once, if errors occur leave a blank cmap
     if (mCharacterMap) {
         return NS_OK;
     }
 
     RefPtr<gfxCharacterMap> charmap;
     nsresult rv;
     bool symbolFont;
--- a/gfx/thebes/gfxGDIFontList.cpp
+++ b/gfx/thebes/gfxGDIFontList.cpp
@@ -19,16 +19,17 @@
 #include "nsUnicharUtils.h"
 
 #include "nsDirectoryServiceUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsISimpleEnumerator.h"
 #include "nsIWindowsRegKey.h"
 #include "gfxFontConstants.h"
+#include "GeckoProfiler.h"
 
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/WindowsVersion.h"
 
 #include <usp10.h>
 
 using namespace mozilla;
@@ -138,16 +139,18 @@ GDIFontEntry::GDIFontEntry(const nsAStri
     mIsDataUserFont = aUserFontData != nullptr;
 
     InitLogFont(aFaceName, aFontType);
 }
 
 nsresult
 GDIFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
 {
+    PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
+
     // attempt this once, if errors occur leave a blank cmap
     if (mCharacterMap) {
         return NS_OK;
     }
 
     // skip non-SFNT fonts completely
     if (mFontType != GFX_FONT_TYPE_PS_OPENTYPE && 
         mFontType != GFX_FONT_TYPE_TT_OPENTYPE &&
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -901,34 +901,31 @@ gfxPlatform::GetSourceSurfaceForSurface(
 
   if (aTarget->GetBackendType() == BackendType::CAIRO) {
     // If we're going to be used with a CAIRO DrawTarget, then just create a
     // SourceSurfaceCairo since we don't know the underlying type of the CAIRO
     // DrawTarget and can't pick a better surface type. Doing this also avoids
     // readback of aSurface's surface into memory if, for example, aSurface
     // wraps an xlib cairo surface (which can be important to avoid a major
     // slowdown).
-    NativeSurface surf;
-    surf.mFormat = format;
-    surf.mType = NativeSurfaceType::CAIRO_CONTEXT;
-    surf.mSurface = aSurface->CairoSurface();
-    surf.mSize = aSurface->GetSize();
+    //
     // We return here regardless of whether CreateSourceSurfaceFromNativeSurface
     // succeeds or not since we don't expect to be able to do any better below
     // if it fails.
     //
     // Note that the returned SourceSurfaceCairo holds a strong reference to
     // the cairo_surface_t* that it wraps, which essencially means it holds a
     // strong reference to aSurface since aSurface shares its
     // cairo_surface_t*'s reference count variable. As a result we can't cache
     // srcBuffer on aSurface (see below) since aSurface would then hold a
     // strong reference back to srcBuffer, creating a reference loop and a
     // memory leak. Not caching is fine since wrapping is cheap enough (no
     // copying) so we can just wrap again next time we're called.
-    return aTarget->CreateSourceSurfaceFromNativeSurface(surf);
+    return Factory::CreateSourceSurfaceForCairoSurface(aSurface->CairoSurface(),
+                                                       aSurface->GetSize(), format);
   }
 
   RefPtr<SourceSurface> srcBuffer;
 
   // Currently no other DrawTarget types implement CreateSourceSurfaceFromNativeSurface
 
   if (!srcBuffer) {
     // If aSurface wraps data, we can create a SourceSurfaceRawData that wraps
@@ -959,28 +956,18 @@ gfxPlatform::GetSourceSurfaceForSurface(
                "DrawTargetCairo above");
     // We've run out of performant options. We now try creating a SourceSurface
     // using a temporary DrawTargetCairo and then optimizing it to aTarget's
     // actual type. The CreateSourceSurfaceFromNativeSurface() call will
     // likely create a DataSourceSurface (possibly involving copying and/or
     // readback), and the OptimizeSourceSurface may well copy again and upload
     // to the GPU. So, while this code path is rarely hit, hitting it may be
     // very slow.
-    NativeSurface surf;
-    surf.mFormat = format;
-    surf.mType = NativeSurfaceType::CAIRO_CONTEXT;
-    surf.mSurface = aSurface->CairoSurface();
-    surf.mSize = aSurface->GetSize();
-    RefPtr<DrawTarget> drawTarget =
-      Factory::CreateDrawTarget(BackendType::CAIRO, IntSize(1, 1), format);
-    if (!drawTarget) {
-      gfxWarning() << "gfxPlatform::GetSourceSurfaceForSurface failed in CreateDrawTarget";
-      return nullptr;
-    }
-    srcBuffer = drawTarget->CreateSourceSurfaceFromNativeSurface(surf);
+    srcBuffer = Factory::CreateSourceSurfaceForCairoSurface(aSurface->CairoSurface(),
+                                                            aSurface->GetSize(), format);
     if (srcBuffer) {
       srcBuffer = aTarget->OptimizeSourceSurface(srcBuffer);
     }
   }
 
   if (!srcBuffer) {
     return nullptr;
   }
--- a/gfx/thebes/gfxScriptItemizer.cpp
+++ b/gfx/thebes/gfxScriptItemizer.cpp
@@ -170,17 +170,17 @@ gfxScriptItemizer::Next(uint32_t& aRunSt
              * if it's an open character, push it onto the stack.
              * if it's a close character, find the matching open on the
              * stack, and use that script code. Any non-matching open
              * characters above it on the stack will be popped.
              *
              * We only do this if the script is COMMON; for chars with
              * specific script assignments, we just use them as-is.
              */
-            GetGeneralCategory(ch);
+            gc = GetGeneralCategory(ch);
             if (gc == HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION) {
                 uint32_t endPairChar = mozilla::unicode::GetMirroredChar(ch);
                 if (endPairChar != ch) {
                     push(endPairChar, scriptCode);
                 }
             } else if (gc == HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION &&
                 HasMirroredChar(ch))
             {
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -16,16 +16,17 @@
 
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/Snprintf.h"
 #include "mozilla/WindowsVersion.h"
 #include "nsServiceManagerUtils.h"
 #include "nsTArray.h"
 #include "mozilla/Telemetry.h"
+#include "GeckoProfiler.h"
 
 #include "nsIWindowsRegKey.h"
 #include "nsIFile.h"
 #include "plbase64.h"
 #include "nsIXULRuntime.h"
 #include "imgLoader.h"
 
 #include "nsIGfxInfo.h"
@@ -1200,16 +1201,18 @@ InvalidateWindowForDeviceReset(HWND aWnd
     RedrawWindow(aWnd, nullptr, nullptr,
                  RDW_INVALIDATE|RDW_INTERNALPAINT|RDW_FRAME);
     return TRUE;
 }
 
 bool
 gfxWindowsPlatform::UpdateForDeviceReset()
 {
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::GRAPHICS);
+
   if (!DidRenderingDeviceReset()) {
     return false;
   }
 
   // Trigger an ::OnPaint for each window.
   ::EnumThreadWindows(GetCurrentThreadId(),
                       InvalidateWindowForDeviceReset,
                       0);
--- a/gfx/thebes/gfxXlibNativeRenderer.cpp
+++ b/gfx/thebes/gfxXlibNativeRenderer.cpp
@@ -570,23 +570,18 @@ gfxXlibNativeRenderer::Draw(gfxContext* 
         return;
     }
 
     SurfaceFormat moz2DFormat =
         cairo_surface_get_content(tempXlibSurface) == CAIRO_CONTENT_COLOR ?
             SurfaceFormat::B8G8R8A8 : SurfaceFormat::B8G8R8X8;
     if (method != eAlphaExtraction) {
         if (drawTarget) {
-            NativeSurface native;
-            native.mFormat = moz2DFormat;
-            native.mType = NativeSurfaceType::CAIRO_CONTEXT;
-            native.mSurface = tempXlibSurface;
-            native.mSize = size;
             RefPtr<SourceSurface> sourceSurface =
-                drawTarget->CreateSourceSurfaceFromNativeSurface(native);
+                Factory::CreateSourceSurfaceForCairoSurface(tempXlibSurface, size, moz2DFormat);
             if (sourceSurface) {
                 drawTarget->DrawSurface(sourceSurface,
                     Rect(offset.x, offset.y, size.width, size.height),
                     Rect(0, 0, size.width, size.height));
             }
         } else {
             RefPtr<gfxASurface> tmpSurf = gfxASurface::Wrap(tempXlibSurface);
             ctx->SetSource(tmpSurf, offset);
@@ -612,23 +607,19 @@ gfxXlibNativeRenderer::Draw(gfxContext* 
         whiteImage->CairoStatus() == CAIRO_STATUS_SUCCESS) {
         if (!gfxAlphaRecovery::RecoverAlpha(blackImage, whiteImage)) {
             cairo_surface_destroy(tempXlibSurface);
             return;
         }
 
         gfxASurface* paintSurface = blackImage;
         if (drawTarget) {
-            NativeSurface native;
-            native.mFormat = moz2DFormat;
-            native.mType = NativeSurfaceType::CAIRO_CONTEXT;
-            native.mSurface = paintSurface->CairoSurface();
-            native.mSize = size;
             RefPtr<SourceSurface> sourceSurface =
-                drawTarget->CreateSourceSurfaceFromNativeSurface(native);
+                Factory::CreateSourceSurfaceForCairoSurface(paintSurface->CairoSurface(),
+                                                            size, moz2DFormat);
             if (sourceSurface) {
                 drawTarget->DrawSurface(sourceSurface,
                     Rect(offset.x, offset.y, size.width, size.height),
                     Rect(0, 0, size.width, size.height));
             }
         } else {
             ctx->SetSource(paintSurface, offset);
             ctx->Paint();
--- a/image/FrameAnimator.cpp
+++ b/image/FrameAnimator.cpp
@@ -74,16 +74,17 @@ FrameAnimator::GetCurrentImgFrameEndTime
   return currentFrameEndTime;
 }
 
 FrameAnimator::RefreshResult
 FrameAnimator::AdvanceFrame(TimeStamp aTime)
 {
   NS_ASSERTION(aTime <= TimeStamp::Now(),
                "Given time appears to be in the future");
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::GRAPHICS);
 
   uint32_t currentFrameIndex = mCurrentAnimationFrameIndex;
   uint32_t nextFrameIndex = currentFrameIndex + 1;
   int32_t timeout = 0;
 
   RefreshResult ret;
   RawAccessFrameRef nextFrame = GetRawFrame(nextFrameIndex);
 
--- a/image/decoders/nsICODecoder.cpp
+++ b/image/decoders/nsICODecoder.cpp
@@ -230,18 +230,18 @@ nsICODecoder::ReadDirEntry(const char* a
     // Calculate the delta between this resource's size and the desired size, so
     // we can see if it is better than our current-best option.  In the case of
     // several equally-good resources, we use the last one. "Better" in this
     // case is determined by |delta|, a measure of the difference in size
     // between the entry we've found and the downscaler's target size. We will
     // choose the smallest resource that is >= the target size (i.e. we assume
     // it's better to downscale a larger icon than to upscale a smaller one).
     IntSize desiredSize = mDownscaler->TargetSize();
-    int32_t delta = entrySize.width - desiredSize.width +
-                    entrySize.height - desiredSize.height;
+    int32_t delta = std::min(entrySize.width - desiredSize.width,
+                             entrySize.height - desiredSize.height);
     if (e.mBitCount >= mBestResourceColorDepth &&
         ((mBestResourceDelta < 0 && delta >= mBestResourceDelta) ||
          (delta >= 0 && delta <= mBestResourceDelta))) {
       mBestResourceDelta = delta;
       mBestResourceColorDepth = e.mBitCount;
       mDirEntry = e;
     }
   }
--- a/ipc/chromium/src/base/rand_util.h
+++ b/ipc/chromium/src/base/rand_util.h
@@ -13,11 +13,18 @@ namespace base {
 uint64_t RandUint64();
 
 // Returns a random number between min and max (inclusive). Thread-safe.
 int RandInt(int min, int max);
 
 // Returns a random double in range [0, 1). Thread-safe.
 double RandDouble();
 
+// Fills |output_length| bytes of |output| with random data.
+//
+// WARNING:
+// Do not use for security-sensitive purposes.
+// See crypto/ for cryptographically secure random number generation APIs.
+void RandBytes(void* output, size_t output_length);
+
 }  // namespace base
 
 #endif // BASE_RAND_UTIL_H_
--- a/ipc/chromium/src/base/rand_util_win.cc
+++ b/ipc/chromium/src/base/rand_util_win.cc
@@ -1,30 +1,44 @@
-// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/rand_util.h"
+#include <windows.h>
+#include <stddef.h>
+#include <stdint.h>
 
-#include <stdlib.h>
+// #define needed to link in RtlGenRandom(), a.k.a. SystemFunction036.  See the
+// "Community Additions" comment on MSDN here:
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx
+#define SystemFunction036 NTAPI SystemFunction036
+#include <NTSecAPI.h>
+#undef SystemFunction036
 
-#include "base/basictypes.h"
+#include <algorithm>
+#include <limits>
+
 #include "base/logging.h"
 
-namespace {
+namespace base {
 
-uint32_t RandUint32() {
-  uint32_t number;
-  CHECK(rand_s(&number) == 0);
+// NOTE: This function must be cryptographically secure. http://crbug.com/140076
+uint64_t RandUint64() {
+  uint64_t number;
+  RandBytes(&number, sizeof(number));
   return number;
 }
 
-}  // namespace
-
-namespace base {
-
-uint64_t RandUint64() {
-  uint32_t first_half = RandUint32();
-  uint32_t second_half = RandUint32();
-  return (static_cast<uint64_t>(first_half) << 32) + second_half;
+void RandBytes(void* output, size_t output_length) {
+  char* output_ptr = static_cast<char*>(output);
+  while (output_length > 0) {
+    const ULONG output_bytes_this_pass = static_cast<ULONG>(std::min(
+        output_length, static_cast<size_t>(std::numeric_limits<ULONG>::max())));
+    const bool success =
+        RtlGenRandom(output_ptr, output_bytes_this_pass) != FALSE;
+    CHECK(success);
+    output_length -= output_bytes_this_pass;
+    output_ptr += output_bytes_this_pass;
+  }
 }
 
 }  // namespace base
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -376,16 +376,18 @@ GeckoChildProcessHost::AsyncLaunch(std::
   }
 
   return true;
 }
 
 bool
 GeckoChildProcessHost::WaitUntilConnected(int32_t aTimeoutMs)
 {
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
+
   // NB: this uses a different mechanism than the chromium parent
   // class.
   PRIntervalTime timeoutTicks = (aTimeoutMs > 0) ?
     PR_MillisecondsToInterval(aTimeoutMs) : PR_INTERVAL_NO_TIMEOUT;
 
   MonitorAutoLock lock(mMonitor);
   PRIntervalTime waitStart = PR_IntervalNow();
   PRIntervalTime current;
--- a/js/ipc/WrapperOwner.cpp
+++ b/js/ipc/WrapperOwner.cpp
@@ -140,16 +140,17 @@ class CPOWProxyHandler : public BaseProx
     static const char family;
     static const CPOWProxyHandler singleton;
 };
 
 const char CPOWProxyHandler::family = 0;
 const CPOWProxyHandler CPOWProxyHandler::singleton;
 
 #define FORWARD(call, args)                                             \
+    PROFILER_LABEL_FUNC(js::ProfileEntry::Category::JS);                \
     WrapperOwner* owner = OwnerOf(proxy);                               \
     if (!owner->active()) {                                             \
         JS_ReportError(cx, "cannot use a CPOW whose process is gone");  \
         return false;                                                   \
     }                                                                   \
     if (!owner->allowMessage(cx)) {                                     \
         return false;                                                   \
     }                                                                   \
--- a/js/public/HashTable.h
+++ b/js/public/HashTable.h
@@ -6,16 +6,17 @@
 
 #ifndef js_HashTable_h
 #define js_HashTable_h
 
 #include "mozilla/Alignment.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Casting.h"
+#include "mozilla/HashFunctions.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Move.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/ReentrancyGuard.h"
 #include "mozilla/TemplateLib.h"
 #include "mozilla/TypeTraits.h"
 #include "mozilla/UniquePtr.h"
 
@@ -650,16 +651,28 @@ struct DefaultHasher<float>
                       "subsequent code assumes a four-byte hash");
         return HashNumber(mozilla::BitwiseCast<uint32_t>(f));
     }
     static bool match(float lhs, float rhs) {
         return mozilla::BitwiseCast<uint32_t>(lhs) == mozilla::BitwiseCast<uint32_t>(rhs);
     }
 };
 
+// A hash policy that compares C strings.
+struct CStringHasher
+{
+    typedef const char* Lookup;
+    static js::HashNumber hash(Lookup l) {
+        return mozilla::HashString(l);
+    }
+    static bool match(const char* key, Lookup lookup) {
+        return strcmp(key, lookup) == 0;
+    }
+};
+
 /*****************************************************************************/
 
 // Both HashMap and HashSet are implemented by a single HashTable that is even
 // more heavily parameterized than the other two. This leaves HashTable gnarly
 // and extremely coupled to HashMap and HashSet; thus code should not use
 // HashTable directly.
 
 template <class Key, class Value>
--- a/js/public/Utility.h
+++ b/js/public/Utility.h
@@ -230,16 +230,21 @@ static inline void* js_calloc(size_t byt
 static inline void* js_calloc(size_t nmemb, size_t size)
 {
     JS_OOM_POSSIBLY_FAIL();
     return calloc(nmemb, size);
 }
 
 static inline void* js_realloc(void* p, size_t bytes)
 {
+    // realloc() with zero size is not portable, as some implementations may
+    // return nullptr on success and free |p| for this.  We assume nullptr
+    // indicates failure and that |p| is still valid.
+    MOZ_ASSERT(bytes != 0);
+
     JS_OOM_POSSIBLY_FAIL();
     return realloc(p, bytes);
 }
 
 static inline void js_free(void* p)
 {
     free(p);
 }
--- a/js/src/asmjs/AsmJS.cpp
+++ b/js/src/asmjs/AsmJS.cpp
@@ -51,16 +51,17 @@ using namespace js;
 using namespace js::frontend;
 using namespace js::jit;
 using namespace js::wasm;
 
 using mozilla::Compression::LZ4;
 using mozilla::HashGeneric;
 using mozilla::IsNaN;
 using mozilla::IsNegativeZero;
+using mozilla::Maybe;
 using mozilla::Move;
 using mozilla::PodCopy;
 using mozilla::PodEqual;
 using mozilla::PodZero;
 using mozilla::PositiveInfinity;
 using JS::AsmJSOption;
 using JS::GenericNaN;
 
@@ -392,30 +393,36 @@ class js::AsmJSModule final : public Mod
 
     const UniqueConstStaticLinkData link_;
     const UniqueConstAsmJSModuleData module_;
 
   public:
     AsmJSModule(UniqueModuleData base,
                 UniqueStaticLinkData link,
                 UniqueAsmJSModuleData module)
-      : Module(Move(base), AsmJSBool::IsAsmJS),
+      : Module(Move(base)),
         link_(Move(link)),
         module_(Move(module))
     {}
 
     virtual void trace(JSTracer* trc) override {
         Module::trace(trc);
         module_->trace(trc);
     }
     virtual void addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* code, size_t* data) override {
         Module::addSizeOfMisc(mallocSizeOf, code, data);
         *data += mallocSizeOf(link_.get()) + link_->sizeOfExcludingThis(mallocSizeOf);
         *data += mallocSizeOf(module_.get()) + module_->sizeOfExcludingThis(mallocSizeOf);
     }
+    virtual bool mutedErrors() const override {
+        return scriptSource()->mutedErrors();
+    }
+    virtual const char16_t* displayURL() const override {
+        return scriptSource()->hasDisplayURL() ? scriptSource()->displayURL() : nullptr;
+    }
 
     uint32_t minHeapLength() const { return module_->minHeapLength; }
     uint32_t numFFIs() const { return module_->numFFIs; }
     bool strict() const { return module_->strict; }
     ScriptSource* scriptSource() const { return module_->scriptSource.get(); }
     const AsmJSGlobalVector& asmJSGlobals() const { return module_->globals; }
     const AsmJSImportVector& asmJSImports() const { return module_->imports; }
     const AsmJSExportVector& asmJSExports() const { return module_->exports; }
@@ -1785,17 +1792,17 @@ class MOZ_STACK_CLASS ModuleValidator
         if (!genData ||
             !genData->sigs.resize(MaxSigs) ||
             !genData->funcSigs.resize(MaxFuncs) ||
             !genData->imports.resize(MaxImports))
         {
             return false;
         }
 
-        return mg_.init(Move(genData));
+        return mg_.init(Move(genData), ModuleKind::AsmJS);
     }
 
     ExclusiveContext* cx() const             { return cx_; }
     PropertyName* moduleFunctionName() const { return moduleFunctionName_; }
     PropertyName* globalArgumentName() const { return module_->globalArgumentName; }
     PropertyName* importArgumentName() const { return module_->importArgumentName; }
     PropertyName* bufferArgumentName() const { return module_->bufferArgumentName; }
     ModuleGenerator& mg()                    { return mg_; }
@@ -2222,52 +2229,43 @@ class MOZ_STACK_CLASS ModuleValidator
         }
         return false;
     }
 
     bool startFunctionBodies() {
         return true;
     }
     bool finishFunctionBodies() {
-        return mg_.finishFuncs();
+        return mg_.finishFuncDefs();
     }
     bool finish(MutableHandle<WasmModuleObject*> moduleObj, SlowFunctionVector* slowFuncs) {
         HeapUsage heap = arrayViews_.empty()
                               ? HeapUsage::None
                               : atomicsPresent_
                                 ? HeapUsage::Shared
                                 : HeapUsage::Unshared;
 
-        auto muted = MutedErrorsBool(parser_.ss->mutedErrors());
-
         CacheableChars filename;
         if (parser_.ss->filename()) {
             filename = DuplicateString(parser_.ss->filename());
             if (!filename)
                 return false;
         }
 
-        CacheableTwoByteChars displayURL;
-        if (parser_.ss->hasDisplayURL()) {
-            displayURL = DuplicateString(parser_.ss->displayURL());
-            if (!displayURL)
-                return false;
-        }
-
         uint32_t endBeforeCurly = tokenStream().currentToken().pos.end;
         module_->srcLength = endBeforeCurly - module_->srcStart;
 
         TokenPos pos;
         JS_ALWAYS_TRUE(tokenStream().peekTokenPos(&pos, TokenStream::Operand));
         uint32_t endAfterCurly = pos.end;
         module_->srcLengthWithRightBrace = endAfterCurly - module_->srcStart;
 
         UniqueModuleData base;
         UniqueStaticLinkData link;
-        if (!mg_.finish(heap, muted, Move(filename), Move(displayURL), &base, &link, slowFuncs))
+        if (!mg_.finish(heap, Move(filename), &base, &link, slowFuncs))
             return false;
 
         moduleObj.set(WasmModuleObject::create(cx_));
         if (!moduleObj)
             return false;
 
         return moduleObj->init(cx_->new_<AsmJSModule>(Move(base), Move(link), Move(module_)));
     }
@@ -2585,17 +2583,17 @@ class MOZ_STACK_CLASS FunctionValidator
   private:
     typedef HashMap<PropertyName*, Local> LocalMap;
     typedef HashMap<PropertyName*, uint32_t> LabelMap;
 
     ModuleValidator&  m_;
     ParseNode*        fn_;
 
     FunctionGenerator fg_;
-    Encoder           encoder_;
+    Maybe<Encoder>    encoder_;
 
     LocalMap          locals_;
     LabelMap          labels_;
 
     bool              hasAlreadyReturned_;
     ExprType          ret_;
 
   public:
@@ -2607,25 +2605,28 @@ class MOZ_STACK_CLASS FunctionValidator
         hasAlreadyReturned_(false)
     {}
 
     ModuleValidator& m() const        { return m_; }
     ExclusiveContext* cx() const      { return m_.cx(); }
     ParseNode* fn() const             { return fn_; }
 
     bool init(PropertyName* name, unsigned line, unsigned column) {
-        UniqueBytecode recycled;
-        return m_.mg().startFunc(name, line, column, &recycled, &fg_) &&
-               encoder_.init(Move(recycled)) &&
-               locals_.init() &&
-               labels_.init();
+        if (!locals_.init() || !labels_.init())
+            return false;
+
+        if (!m_.mg().startFuncDef(name, line, column, &fg_))
+            return false;
+
+        encoder_.emplace(fg_.bytecode());
+        return true;
     }
 
     bool finish(uint32_t funcIndex, unsigned generateTime) {
-        return m_.mg().finishFunc(funcIndex, encoder().finish(), generateTime, &fg_);
+        return m_.mg().finishFuncDef(funcIndex, generateTime, &fg_);
     }
 
     bool fail(ParseNode* pn, const char* str) {
         return m_.fail(pn, str);
     }
 
     bool failf(ParseNode* pn, const char* fmt, ...) {
         va_list ap;
@@ -2699,28 +2700,28 @@ class MOZ_STACK_CLASS FunctionValidator
         if (locals_.has(name))
             return nullptr;
         return m_.lookupGlobal(name);
     }
 
     size_t numLocals() const { return locals_.count(); }
 
     /************************************************* Packing interface */
-    Encoder& encoder() { return encoder_; }
+
+    Encoder& encoder() { return *encoder_; }
 
     bool noteLineCol(ParseNode* pn) {
         uint32_t line, column;
         m().tokenStream().srcCoords.lineNumAndColumnIndex(pn->pn_pos.begin, &line, &column);
         return fg_.addSourceCoords(encoder().bytecodeOffset(), line, column);
     }
 
     MOZ_WARN_UNUSED_RESULT
     bool writeOp(Expr op) {
-        static_assert(sizeof(Expr) == sizeof(uint8_t), "opcodes must be uint8");
-        return encoder().writeU8(uint8_t(op));
+        return encoder().writeExpr(op);
     }
 
     MOZ_WARN_UNUSED_RESULT
     bool writeDebugCheckPoint() {
 #ifdef DEBUG
         return writeOp(Expr::DebugCheckPoint);
 #endif
         return true;
@@ -2767,35 +2768,34 @@ class MOZ_STACK_CLASS FunctionValidator
             return writeOp(Expr::B32X4Const) && encoder().writeI32X4(lit.simdValue().asInt32x4());
           case NumLit::OutOfRangeInt:
             break;
         }
         MOZ_CRASH("unexpected literal type");
     }
 
     void patchOp(size_t pos, Expr stmt) {
-        static_assert(sizeof(Expr) == sizeof(uint8_t), "opcodes must be uint8");
-        encoder().patchU8(pos, uint8_t(stmt));
+        encoder().patchExpr(pos, stmt);
     }
     void patchU8(size_t pos, uint8_t u8) {
         encoder().patchU8(pos, u8);
     }
     template<class T>
     void patch32(size_t pos, T val) {
         static_assert(sizeof(T) == sizeof(uint32_t), "patch32 is used for 4-bytes long ops");
         encoder().patch32(pos, val);
     }
 
     MOZ_WARN_UNUSED_RESULT
     bool tempU8(size_t* offset) {
         return encoder().writeU8(uint8_t(Expr::Unreachable), offset);
     }
     MOZ_WARN_UNUSED_RESULT
     bool tempOp(size_t* offset) {
-        return tempU8(offset);
+        return encoder().writeExpr(Expr::Unreachable, offset);
     }
     MOZ_WARN_UNUSED_RESULT
     bool temp32(size_t* offset) {
         if (!encoder().writeU8(uint8_t(Expr::Unreachable), offset))
             return false;
         for (size_t i = 1; i < 4; i++) {
             if (!encoder().writeU8(uint8_t(Expr::Unreachable)))
                 return false;
--- a/js/src/asmjs/WasmBinary.h
+++ b/js/src/asmjs/WasmBinary.h
@@ -299,70 +299,80 @@ enum NeedsBoundsCheck : uint8_t
 {
     NO_BOUNDS_CHECK,
     NEEDS_BOUNDS_CHECK
 };
 
 typedef Vector<uint8_t, 0, SystemAllocPolicy> Bytecode;
 typedef UniquePtr<Bytecode> UniqueBytecode;
 
-// The Encoder class recycles (through its constructor) or creates a new Bytecode (through its
-// init() method). Its Bytecode is released when it's done building the wasm IR in finish().
+// The Encoder class appends bytes to the Bytecode object it is given during
+// construction. The client is responsible for the Bytecode's lifetime and must
+// keep the Bytecode alive as long as the Encoder is used.
 class Encoder
 {
-    UniqueBytecode bytecode_;
-    DebugOnly<bool> done_;
+    Bytecode& bytecode_;
 
-    template<class T>
+    template <class T>
     MOZ_WARN_UNUSED_RESULT
     bool write(T v, size_t* offset) {
         if (offset)
-            *offset = bytecode_->length();
-        return bytecode_->append(reinterpret_cast<uint8_t*>(&v), sizeof(T));
+            *offset = bytecode_.length();
+        return bytecode_.append(reinterpret_cast<uint8_t*>(&v), sizeof(T));
+    }
+
+    template <class T>
+    MOZ_WARN_UNUSED_RESULT
+    bool writeEnum(T v, size_t* offset) {
+        // For now, just write a u8 instead of a variable-length integer.
+        // Variable-length is somewhat annoying at the moment due to the
+        // pre-order encoding and back-patching; let's see if we switch to
+        // post-order first.
+        static_assert(mozilla::IsEnum<T>::value, "is an enum");
+        MOZ_ASSERT(uint64_t(v) < UINT8_MAX);
+        return writeU8(uint8_t(v), offset);
+    }
+
+    template <class T>
+    void patchEnum(size_t pc, T v) {
+        // See writeEnum comment.
+        static_assert(mozilla::IsEnum<T>::value, "is an enum");
+        MOZ_ASSERT(uint64_t(v) < UINT8_MAX);
+        bytecode_[pc] = uint8_t(v);
     }
 
   public:
-    Encoder()
-      : bytecode_(nullptr),
-        done_(false)
-    {}
-
-    bool init(UniqueBytecode bytecode = UniqueBytecode()) {
-        if (bytecode) {
-            bytecode_ = Move(bytecode);
-            bytecode_->clear();