merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 05 Jun 2015 15:25:08 +0200
changeset 247318 920ded6a1f77189943310aa1fda0f38a20e5f824
parent 247273 2bd39dd8c536f4856fec9379e5a0eaf6fefef41d (current diff)
parent 247317 4064fc7834989f7569261f346420ed07e9fec378 (diff)
child 247319 a60028c73618d3b385997b4910e3ae25481bc9d5
child 247402 bf7d8d969d9d2d8575309807c601498af0f2efd4
child 247431 ead0c29ea6f255827258e172ea0bba23149332da
child 247448 699f8b29348b1a3cac4eb17e36feb4bbbae216b8
push id28860
push usercbook@mozilla.com
push dateFri, 05 Jun 2015 13:25:48 +0000
treeherdermozilla-central@920ded6a1f77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
browser/app/profile/firefox.js
security/manager/ssl/tests/unit/test_certificate_usages.js
security/manager/ssl/tests/unit/test_certificate_usages/ca-1.der
security/manager/ssl/tests/unit/test_certificate_usages/ca-2.der
security/manager/ssl/tests/unit/test_certificate_usages/ca-3.der
security/manager/ssl/tests/unit/test_certificate_usages/ca-4.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-1-ca-1.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-1-ca-2.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-1-ca-3.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-1-ca-4.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-2-ca-1.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-2-ca-2.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-2-ca-3.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-2-ca-4.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-3-ca-1.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-3-ca-2.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-3-ca-3.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-3-ca-4.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-4-ca-1.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-4-ca-2.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-4-ca-3.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-4-ca-4.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-5-ca-1.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-5-ca-2.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-5-ca-3.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-5-ca-4.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-6-ca-1.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-6-ca-2.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-6-ca-3.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-6-ca-4.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-7-ca-1.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-7-ca-2.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-7-ca-3.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-7-ca-4.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-8-ca-1.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-8-ca-2.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-8-ca-3.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-8-ca-4.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-9-ca-1.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-9-ca-2.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-9-ca-3.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-9-ca-4.der
security/manager/ssl/tests/unit/test_certificate_usages/generate.pl
testing/web-platform/meta/XMLHttpRequest/interfaces.html.ini
testing/web-platform/meta/ambient-light/idlharness.html.ini
testing/web-platform/meta/animation-timing/idlharness.html.ini
testing/web-platform/meta/eventsource/eventsource-constructor-document-domain.htm.ini
testing/web-platform/meta/navigation-timing/test_navigation_type_reload.html.ini
testing/web-platform/meta/proximity/idlharness.html.ini
testing/web-platform/meta/service-workers/stub-3.1-service-worker-obj.html.ini
testing/web-platform/meta/service-workers/stub-3.1.1-service-worker-scope.html.ini
testing/web-platform/meta/service-workers/stub-3.1.2-service-worker-url.html.ini
testing/web-platform/meta/service-workers/stub-3.1.3-service-worker-state.html.ini
testing/web-platform/meta/service-workers/stub-3.1.4-service-worker-on-state-change.html.ini
testing/web-platform/meta/service-workers/stub-3.2-navigator-service-worker.html.ini
testing/web-platform/meta/service-workers/stub-3.2.1-navigator-service-worker-installing.html.ini
testing/web-platform/meta/service-workers/stub-3.2.10-navigator-service-worker-oncontrollerchange.html.ini
testing/web-platform/meta/service-workers/stub-3.2.11-navigator-service-worker-onreloadpage.html.ini
testing/web-platform/meta/service-workers/stub-3.2.12-navigator-service-worker-onerror.html.ini
testing/web-platform/meta/service-workers/stub-3.2.2-navigator-service-worker-waiting.html.ini
testing/web-platform/meta/service-workers/stub-3.2.3-navigator-service-worker-active.html.ini
testing/web-platform/meta/service-workers/stub-3.2.4-navigator-service-worker-controller.html.ini
testing/web-platform/meta/service-workers/stub-3.2.5-navigator-service-worker-ready.html.ini
testing/web-platform/meta/service-workers/stub-3.2.6-navigator-service-worker-getAll.html.ini
testing/web-platform/meta/service-workers/stub-3.2.7-navigator-service-worker-register.html.ini
testing/web-platform/meta/service-workers/stub-3.2.8-navigator-service-worker-unregister.html.ini
testing/web-platform/meta/service-workers/stub-3.2.9-navigator-service-worker-onupdatefound.html.ini
testing/web-platform/meta/service-workers/stub-4.1-service-worker-global-scope.html.ini
testing/web-platform/meta/service-workers/stub-4.1.1-service-worker-global-scope-caches.html.ini
testing/web-platform/meta/service-workers/stub-4.1.2-service-worker-global-scope-clients.html.ini
testing/web-platform/meta/service-workers/stub-4.1.3-service-worker-global-scope-scope.html.ini
testing/web-platform/meta/service-workers/stub-4.1.4-service-worker-global-scope-fetch.html.ini
testing/web-platform/meta/service-workers/stub-4.1.5-service-worker-global-scope-update.html.ini
testing/web-platform/meta/service-workers/stub-4.1.6-service-worker-global-scope-unregister.html.ini
testing/web-platform/meta/service-workers/stub-4.1.7-service-worker-global-scope-onmessage.html.ini
testing/web-platform/meta/service-workers/stub-4.2-client.html.ini
testing/web-platform/meta/service-workers/stub-4.3-service-worker-clients.html.ini
testing/web-platform/meta/service-workers/stub-4.3.1-get-serviced-method.html.ini
testing/web-platform/meta/service-workers/stub-4.3.2-reloadall-method.html.ini
testing/web-platform/meta/service-workers/stub-4.4-request-objects.html.ini
testing/web-platform/meta/service-workers/stub-4.5-response-objects.html.ini
testing/web-platform/meta/service-workers/stub-4.5.2-response.html.ini
testing/web-platform/meta/service-workers/stub-4.5.4-opaque-response.html.ini
testing/web-platform/meta/service-workers/stub-4.6-cache-objects.html.ini
testing/web-platform/meta/service-workers/stub-4.6.1-cache-lifetimes.html.ini
testing/web-platform/meta/service-workers/stub-4.6.2-cache.html.ini
testing/web-platform/meta/service-workers/stub-4.6.3-cache-storage.html.ini
testing/web-platform/meta/service-workers/stub-4.7.1-install-phase-event.html.ini
testing/web-platform/meta/service-workers/stub-4.7.1.1-wait-until-method.html.ini
testing/web-platform/meta/service-workers/stub-4.7.2-install-event.html.ini
testing/web-platform/meta/service-workers/stub-4.7.2.1-install-event-section.html.ini
testing/web-platform/meta/service-workers/stub-4.7.2.2-replace-method.html.ini
testing/web-platform/meta/service-workers/stub-4.7.3-activate-event.html.ini
testing/web-platform/meta/service-workers/stub-4.7.4.1-fetch-event-section.html.ini
testing/web-platform/meta/service-workers/stub-4.7.4.2-respond-with-method.html.ini
testing/web-platform/meta/service-workers/stub-4.7.4.3-default-method.html.ini
testing/web-platform/meta/service-workers/stub-4.7.4.4-is-reload-attribute.html.ini
testing/web-platform/meta/service-workers/stub-5.1-origin-relativity.html.ini
testing/web-platform/meta/service-workers/stub-5.2-cross-origin-resources.html.ini
testing/web-platform/tests/battery-status/prime.js
testing/web-platform/tests/referrer-policy/README.html
testing/web-platform/tests/referrer-policy/no-referrer-policy/no-referrer-policy.html
testing/web-platform/tests/referrer-policy/no-referrer-policy/no-referrer-policy.subresource.py
testing/web-platform/tests/referrer-policy/no-referrer-policy/no-referrer-policy.subresource.template.html
testing/web-platform/tests/subresource-integrity/loads-scripts-with-base64-encoded-sha-digests.js
testing/web-platform/tests/subresource-integrity/loads-scripts-with-correct-content-type.js
testing/web-platform/tests/subresource-integrity/loads-scripts-with-improper-integrity-uri-scheme.js
testing/web-platform/tests/subresource-integrity/loads-scripts-with-incorrect-content-type.js
testing/web-platform/tests/subresource-integrity/loads-scripts-with-matching-digest.js
testing/web-platform/tests/subresource-integrity/loads-scripts-with-non-matching-digest.js
testing/web-platform/tests/subresource-integrity/loads-scripts-with-unhyphenated-digest-name.js
testing/web-platform/tests/subresource-integrity/loads-scripts-with-weak-digest-algorithms.js
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1831,19 +1831,19 @@ pref("identity.fxaccounts.migrateToDevEd
 // On GTK, we now default to showing the menubar only when alt is pressed:
 #ifdef MOZ_WIDGET_GTK
 pref("ui.key.menuAccessKeyFocuses", true);
 #endif
 
 // Encrypted media extensions.
 pref("media.eme.enabled", true);
 pref("media.eme.apiVisible", true);
-pref("browser.eme.ui.enabled", true);
 
 #ifdef MOZ_ADOBE_EME
+pref("browser.eme.ui.enabled", true);
 pref("media.gmp-eme-adobe.enabled", true);
 #endif
 
 // Play with different values of the decay time and get telemetry,
 // 0 means to randomize (and persist) the experiment value in users' profiles,
 // -1 means no experiment is run and we use the preferred value for frecency (6h)
 pref("browser.cache.frecency_experiment", 0);
 
--- a/dom/base/test/csp/browser.ini
+++ b/dom/base/test/csp/browser.ini
@@ -1,4 +1,3 @@
 [DEFAULT]
-skip-if = e10s # Bug 1170385 - csp-on-violate-policy message not sent in browser tests with e10s
 [browser_test_web_manifest.js]
 [browser_test_web_manifest_mixed_content.js]
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -4665,16 +4665,17 @@ CanvasRenderingContext2D::DrawWindow(nsG
   // gfxContext-over-Azure may modify the DrawTarget's transform, so
   // save and restore it
   Matrix matrix = mTarget->GetTransform();
   double sw = matrix._11 * w;
   double sh = matrix._22 * h;
   if (!sw || !sh) {
     return;
   }
+
   nsRefPtr<gfxContext> thebes;
   RefPtr<DrawTarget> drawDT;
   // Rendering directly is faster and can be done if mTarget supports Azure
   // and does not need alpha blending.
   if (gfxPlatform::GetPlatform()->SupportsAzureContentForDrawTarget(mTarget) &&
       GlobalAlpha() == 1.0f)
   {
     thebes = new gfxContext(mTarget);
@@ -4813,16 +4814,61 @@ CanvasRenderingContext2D::AsyncDrawXULEl
     DocumentRendererParent *docrender =
       static_cast<DocumentRendererParent *>(pdocrender);
 
     docrender->SetCanvasContext(this, mThebes);
   }
 #endif
 }
 
+void
+CanvasRenderingContext2D::DrawWidgetAsOnScreen(nsGlobalWindow& aWindow,
+                                               mozilla::ErrorResult& error)
+{
+  EnsureTarget();
+
+  // This is an internal API.
+  if (!nsContentUtils::IsCallerChrome()) {
+    error.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return;
+  }
+
+  nsRefPtr<nsPresContext> presContext;
+  nsIDocShell* docshell = aWindow.GetDocShell();
+  if (docshell) {
+    docshell->GetPresContext(getter_AddRefs(presContext));
+  }
+  if (!presContext) {
+    error.Throw(NS_ERROR_FAILURE);
+    return;
+  }
+
+  nsIWidget* widget = presContext->GetRootWidget();
+  if (!widget) {
+    error.Throw(NS_ERROR_FAILURE);
+    return;
+  }
+  RefPtr<SourceSurface> snapshot = widget->SnapshotWidgetOnScreen();
+  if (!snapshot) {
+    error.Throw(NS_ERROR_FAILURE);
+    return;
+  }
+
+  mgfx::Rect sourceRect(mgfx::Point(0, 0), mgfx::Size(snapshot->GetSize()));
+  mTarget->DrawSurface(snapshot, sourceRect, sourceRect,
+                       DrawSurfaceOptions(mgfx::Filter::POINT),
+                       DrawOptions(GlobalAlpha(), CompositionOp::OP_OVER,
+                                   AntialiasMode::NONE));
+  mTarget->Flush();
+
+  RedrawUser(gfxRect(0, 0,
+                     std::min(mWidth, snapshot->GetSize().width),
+                     std::min(mHeight, snapshot->GetSize().height)));
+}
+
 //
 // device pixel getting/setting
 //
 
 already_AddRefed<ImageData>
 CanvasRenderingContext2D::GetImageData(JSContext* aCx, double aSx,
                                        double aSy, double aSw,
                                        double aSh, ErrorResult& error)
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -397,16 +397,17 @@ public:
     if (imageSmoothingEnabled != CurrentState().imageSmoothingEnabled) {
       CurrentState().imageSmoothingEnabled = imageSmoothingEnabled;
     }
   }
 
   void DrawWindow(nsGlobalWindow& window, double x, double y, double w, double h,
                   const nsAString& bgColor, uint32_t flags,
                   mozilla::ErrorResult& error);
+  void DrawWidgetAsOnScreen(nsGlobalWindow& aWindow, mozilla::ErrorResult& error);
   void AsyncDrawXULElement(nsXULElement& elem, double x, double y, double w,
                            double h, const nsAString& bgColor, uint32_t flags,
                            mozilla::ErrorResult& error);
 
   enum RenderingMode {
     SoftwareBackendMode,
     OpenGLBackendMode,
     DefaultBackendMode
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -1801,18 +1801,18 @@ WebGLContext::PixelStorei(GLenum pname, 
 // `width` in pixels.
 // `stride` in bytes.
 static bool
 SetFullAlpha(void* data, GLenum format, GLenum type, size_t width,
              size_t height, size_t stride)
 {
     if (format == LOCAL_GL_ALPHA && type == LOCAL_GL_UNSIGNED_BYTE) {
         // Just memset the rows.
+        uint8_t* row = static_cast<uint8_t*>(data);
         for (size_t j = 0; j < height; ++j) {
-            uint8_t* row = static_cast<uint8_t*>(data) + j*stride;
             memset(row, 0xff, width);
             row += stride;
         }
 
         return true;
     }
 
     if (format == LOCAL_GL_RGBA && type == LOCAL_GL_UNSIGNED_BYTE) {
--- a/dom/canvas/test/_webgl-conformance.ini
+++ b/dom/canvas/test/_webgl-conformance.ini
@@ -729,29 +729,26 @@ skip-if = os == 'android'
 [webgl-conformance/_wrappers/test_conformance__renderbuffers__renderbuffer-initialization.html]
 [webgl-conformance/_wrappers/test_conformance__rendering__draw-arrays-out-of-bounds.html]
 [webgl-conformance/_wrappers/test_conformance__rendering__draw-elements-out-of-bounds.html]
 [webgl-conformance/_wrappers/test_conformance__rendering__gl-clear.html]
 [webgl-conformance/_wrappers/test_conformance__rendering__gl-drawelements.html]
 [webgl-conformance/_wrappers/test_conformance__rendering__gl-scissor-test.html]
 [webgl-conformance/_wrappers/test_conformance__rendering__more-than-65536-indices.html]
 [webgl-conformance/_wrappers/test_conformance__rendering__point-size.html]
-fail-if = (os == 'mac' && os_version == '10.10')
 [webgl-conformance/_wrappers/test_conformance__rendering__triangle.html]
 [webgl-conformance/_wrappers/test_conformance__rendering__line-loop-tri-fan.html]
-fail-if = (os == 'mac' && os_version == '10.10')
 [webgl-conformance/_wrappers/test_conformance__state__gl-enable-enum-test.html]
 [webgl-conformance/_wrappers/test_conformance__state__gl-enum-tests.html]
 [webgl-conformance/_wrappers/test_conformance__state__gl-get-calls.html]
 [webgl-conformance/_wrappers/test_conformance__state__gl-geterror.html]
 [webgl-conformance/_wrappers/test_conformance__state__gl-getstring.html]
 [webgl-conformance/_wrappers/test_conformance__state__gl-object-get-calls.html]
 [webgl-conformance/_wrappers/test_conformance__textures__compressed-tex-image.html]
 [webgl-conformance/_wrappers/test_conformance__textures__copy-tex-image-and-sub-image-2d.html]
-fail-if = (os == 'mac' && os_version == '10.10')
 [webgl-conformance/_wrappers/test_conformance__textures__gl-pixelstorei.html]
 [webgl-conformance/_wrappers/test_conformance__textures__gl-teximage.html]
 skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux')
 [webgl-conformance/_wrappers/test_conformance__textures__origin-clean-conformance.html]
 [webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-array-buffer-view.html]
 [webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-canvas.html]
 [webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-image-data.html]
 [webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-image.html]
--- a/dom/canvas/test/webgl-conformance/mochitest-errata.ini
+++ b/dom/canvas/test/webgl-conformance/mochitest-errata.ini
@@ -103,20 +103,11 @@ skip-if = (os == 'b2g')
 # Failures after enabling color_buffer_[half_]float.
 fail-if = (os == 'linux')
 
 ########################################################################
 # Mac
 [_wrappers/test_conformance__canvas__drawingbuffer-static-canvas-test.html]
 # Intermittent crash on OSX.
 skip-if = os == 'mac'
-[_wrappers/test_conformance__rendering__line-loop-tri-fan.html]
-# Fails on OS X 10.10
-fail-if = (os == 'mac' && os_version == '10.10')
-[_wrappers/test_conformance__rendering__point-size.html]
-# Fails on OS X 10.10
-fail-if = (os == 'mac' && os_version == '10.10')
-[_wrappers/test_conformance__textures__copy-tex-image-and-sub-image-2d.html]
-# Fails on OS X 10.10
-fail-if = (os == 'mac' && os_version == '10.10')
 
 ########################################################################
 # Win
--- a/dom/media/TimeUnits.h
+++ b/dom/media/TimeUnits.h
@@ -135,16 +135,20 @@ public:
   bool IsInfinite() const {
     return mValue.value() == INT64_MAX;
   }
 
   bool operator == (const TimeUnit& aOther) const {
     MOZ_ASSERT(IsValid() && aOther.IsValid());
     return mValue.value() == aOther.mValue.value();
   }
+  bool operator != (const TimeUnit& aOther) const {
+    MOZ_ASSERT(IsValid() && aOther.IsValid());
+    return mValue.value() != aOther.mValue.value();
+  }
   bool operator >= (const TimeUnit& aOther) const {
     MOZ_ASSERT(IsValid() && aOther.IsValid());
     return mValue.value() >= aOther.mValue.value();
   }
   bool operator > (const TimeUnit& aOther) const {
     return !(*this <= aOther);
   }
   bool operator <= (const TimeUnit& aOther) const {
--- a/dom/media/mediasource/SourceBuffer.cpp
+++ b/dom/media/mediasource/SourceBuffer.cpp
@@ -36,17 +36,17 @@ extern PRLogModuleInfo* GetMediaSourceAP
 namespace mozilla {
 
 namespace dom {
 
 class AppendDataRunnable : public nsRunnable {
 public:
   AppendDataRunnable(SourceBuffer* aSourceBuffer,
                      MediaLargeByteBuffer* aData,
-                     double aTimestampOffset,
+                     TimeUnit aTimestampOffset,
                      uint32_t aUpdateID)
   : mSourceBuffer(aSourceBuffer)
   , mData(aData)
   , mTimestampOffset(aTimestampOffset)
   , mUpdateID(aUpdateID)
   {
   }
 
@@ -55,17 +55,17 @@ public:
     mSourceBuffer->AppendData(mData, mTimestampOffset, mUpdateID);
 
     return NS_OK;
   }
 
 private:
   nsRefPtr<SourceBuffer> mSourceBuffer;
   nsRefPtr<MediaLargeByteBuffer> mData;
-  double mTimestampOffset;
+  TimeUnit mTimestampOffset;
   uint32_t mUpdateID;
 };
 
 class RangeRemovalRunnable : public nsRunnable {
 public:
   RangeRemovalRunnable(SourceBuffer* aSourceBuffer,
                        double aStart,
                        double aEnd)
@@ -135,20 +135,17 @@ SourceBuffer::SetTimestampOffset(double 
 already_AddRefed<TimeRanges>
 SourceBuffer::GetBuffered(ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!IsAttached()) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
-  // We only manage a single trackbuffer in our source buffer.
-  // As such, there's no need to adjust the end of the trackbuffers as per
-  // Step 4: http://w3c.github.io/media-source/index.html#widl-SourceBuffer-buffered
-  media::TimeIntervals ranges = mTrackBuffer->Buffered();
+  TimeIntervals ranges = mContentManager->Buffered();
   MSE_DEBUGV("ranges=%s", DumpTimeRanges(ranges).get());
   nsRefPtr<dom::TimeRanges> tr = new dom::TimeRanges();
   ranges.ToTimeRanges(tr);
   return tr.forget();
 }
 
 void
 SourceBuffer::SetAppendWindowStart(double aAppendWindowStart, ErrorResult& aRv)
@@ -170,18 +167,17 @@ void
 SourceBuffer::SetAppendWindowEnd(double aAppendWindowEnd, ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MSE_API("SetAppendWindowEnd(aAppendWindowEnd=%f)", aAppendWindowEnd);
   if (!IsAttached() || mUpdating) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
-  if (IsNaN(aAppendWindowEnd) ||
-      aAppendWindowEnd <= mAppendWindowStart) {
+  if (IsNaN(aAppendWindowEnd) || aAppendWindowEnd <= mAppendWindowStart) {
     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     return;
   }
   mAppendWindowEnd = aAppendWindowEnd;
 }
 
 void
 SourceBuffer::AppendBuffer(const ArrayBuffer& aData, ErrorResult& aRv)
@@ -210,32 +206,29 @@ SourceBuffer::Abort(ErrorResult& aRv)
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
   if (mMediaSource->ReadyState() != MediaSourceReadyState::Open) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
   AbortBufferAppend();
-  mTrackBuffer->ResetParserState();
+  mContentManager->ResetParserState();
   mAppendWindowStart = 0;
   mAppendWindowEnd = PositiveInfinity<double>();
-  // Discard the current decoder so no new data will be added to it.
-  MSE_DEBUG("Discarding decoder");
-  mTrackBuffer->DiscardCurrentDecoder();
 }
 
 void
 SourceBuffer::AbortBufferAppend()
 {
   if (mUpdating) {
     mPendingAppend.DisconnectIfExists();
     // TODO: Abort segment parser loop, and stream append loop algorithms.
     // cancel any pending buffer append.
-    mTrackBuffer->AbortAppendData();
+    mContentManager->AbortAppendData();
     AbortUpdating();
   }
 }
 
 void
 SourceBuffer::Remove(double aStart, double aEnd, ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -272,42 +265,42 @@ SourceBuffer::RangeRemoval(double aStart
     NS_NewRunnableMethod(this, &SourceBuffer::StopUpdating);
   NS_DispatchToMainThread(task);
 }
 
 void
 SourceBuffer::DoRangeRemoval(double aStart, double aEnd)
 {
   MSE_DEBUG("DoRangeRemoval(%f, %f)", aStart, aEnd);
-  if (mTrackBuffer && !IsInfinite(aStart)) {
-    mTrackBuffer->RangeRemoval(media::TimeUnit::FromSeconds(aStart),
-                               media::TimeUnit::FromSeconds(aEnd));
+  if (mContentManager && !IsInfinite(aStart)) {
+    mContentManager->RangeRemoval(TimeUnit::FromSeconds(aStart),
+                                  TimeUnit::FromSeconds(aEnd));
   }
 }
 
 void
 SourceBuffer::Detach()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MSE_DEBUG("Detach");
   AbortBufferAppend();
-  if (mTrackBuffer) {
-    mTrackBuffer->Detach();
+  if (mContentManager) {
+    mContentManager->Detach();
   }
-  mTrackBuffer = nullptr;
+  mContentManager = nullptr;
   mMediaSource = nullptr;
 }
 
 void
 SourceBuffer::Ended()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(IsAttached());
   MSE_DEBUG("Ended");
-  mTrackBuffer->EndCurrentDecoder();
+  mContentManager->Ended();
 }
 
 SourceBuffer::SourceBuffer(MediaSource* aMediaSource, const nsACString& aType)
   : DOMEventTargetHelper(aMediaSource->GetParentObject())
   , mMediaSource(aMediaSource)
   , mAppendWindowStart(0)
   , mAppendWindowEnd(PositiveInfinity<double>())
   , mTimestampOffset(0)
@@ -316,19 +309,19 @@ SourceBuffer::SourceBuffer(MediaSource* 
   , mActive(false)
   , mUpdateID(0)
   , mType(aType)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aMediaSource);
   mEvictionThreshold = Preferences::GetUint("media.mediasource.eviction_threshold",
                                             75 * (1 << 20));
-  mTrackBuffer = new TrackBuffer(aMediaSource->GetDecoder(), aType);
-  MSE_DEBUG("Create mTrackBuffer=%p",
-            mTrackBuffer.get());
+  mContentManager = SourceBufferContentManager::CreateManager(aMediaSource->GetDecoder(), aType);
+  MSE_DEBUG("Create mContentManager=%p",
+            mContentManager.get());
 }
 
 SourceBuffer::~SourceBuffer()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!mMediaSource);
   MSE_DEBUG("");
 }
@@ -420,22 +413,22 @@ SourceBuffer::AppendData(const uint8_t* 
   if (!data) {
     return;
   }
   StartUpdating();
 
   MOZ_ASSERT(mAppendMode == SourceBufferAppendMode::Segments,
              "We don't handle timestampOffset for sequence mode yet");
   nsCOMPtr<nsIRunnable> task =
-    new AppendDataRunnable(this, data, mTimestampOffset, mUpdateID);
+    new AppendDataRunnable(this, data, TimeUnit::FromSeconds(mTimestampOffset), mUpdateID);
   NS_DispatchToMainThread(task);
 }
 
 void
-SourceBuffer::AppendData(MediaLargeByteBuffer* aData, double aTimestampOffset,
+SourceBuffer::AppendData(MediaLargeByteBuffer* aData, TimeUnit aTimestampOffset,
                          uint32_t aUpdateID)
 {
   if (!mUpdating || aUpdateID != mUpdateID) {
     // The buffer append algorithm has been interrupted by abort().
     //
     // If the sequence appendBuffer(), abort(), appendBuffer() occurs before
     // the first StopUpdating() runnable runs, then a second StopUpdating()
     // runnable will be scheduled, but still only one (the first) will queue
@@ -446,42 +439,40 @@ SourceBuffer::AppendData(MediaLargeByteB
   MOZ_ASSERT(mMediaSource);
   MOZ_ASSERT(!mPendingAppend.Exists());
 
   if (!aData->Length()) {
     StopUpdating();
     return;
   }
 
-  mPendingAppend.Begin(mTrackBuffer->AppendData(aData, aTimestampOffset * USECS_PER_S)
+  mPendingAppend.Begin(mContentManager->AppendData(aData, aTimestampOffset)
                        ->Then(AbstractThread::MainThread(), __func__, this,
                               &SourceBuffer::AppendDataCompletedWithSuccess,
                               &SourceBuffer::AppendDataErrored));
 }
 
 void
-SourceBuffer::AppendDataCompletedWithSuccess(bool aGotMedia)
+SourceBuffer::AppendDataCompletedWithSuccess(bool aHasActiveTracks)
 {
   mPendingAppend.Complete();
   if (!mUpdating) {
     // The buffer append algorithm has been interrupted by abort().
     return;
   }
 
-  if (mTrackBuffer->HasInitSegment()) {
+  if (aHasActiveTracks) {
     if (!mActive) {
       mActive = true;
       mMediaSource->SourceBufferIsActive(this);
       mMediaSource->QueueInitializationEvent();
     }
   }
 
-  if (aGotMedia) {
-    CheckEndTime();
-  }
+  CheckEndTime();
 
   StopUpdating();
 }
 
 void
 SourceBuffer::AppendDataErrored(nsresult aError)
 {
   mPendingAppend.Complete();
@@ -499,17 +490,17 @@ SourceBuffer::AppendDataErrored(nsresult
 void
 SourceBuffer::AppendError(bool aDecoderError)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!mUpdating) {
     // The buffer append algorithm has been interrupted by abort().
     return;
   }
-  mTrackBuffer->ResetParserState();
+  mContentManager->ResetParserState();
 
   mUpdating = false;
 
   QueueAsyncSimpleEvent("error");
   QueueAsyncSimpleEvent("updateend");
 
   if (aDecoderError) {
     Optional<MediaSourceEndOfStreamError> decodeError(
@@ -517,55 +508,57 @@ SourceBuffer::AppendError(bool aDecoderE
     ErrorResult dummy;
     mMediaSource->EndOfStream(decodeError, dummy);
   }
 }
 
 already_AddRefed<MediaLargeByteBuffer>
 SourceBuffer::PrepareAppend(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv)
 {
+  typedef SourceBufferContentManager::EvictDataResult Result;
+
   if (!IsAttached() || mUpdating) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
   if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) {
     mMediaSource->SetReadyState(MediaSourceReadyState::Open);
   }
 
   // Eviction uses a byte threshold. If the buffer is greater than the
   // number of bytes then data is evicted. The time range for this
   // eviction is reported back to the media source. It will then
   // evict data before that range across all SourceBuffers it knows
   // about.
   // TODO: Make the eviction threshold smaller for audio-only streams.
   // TODO: Drive evictions off memory pressure notifications.
   // TODO: Consider a global eviction threshold  rather than per TrackBuffer.
-  double newBufferStartTime = 0.0;
+  TimeUnit newBufferStartTime;
   // Attempt to evict the amount of data we are about to add by lowering the
   // threshold.
   uint32_t toEvict =
     (mEvictionThreshold > aLength) ? mEvictionThreshold - aLength : aLength;
-  bool evicted =
-    mTrackBuffer->EvictData(mMediaSource->GetDecoder()->GetCurrentTime(),
-                            toEvict, &newBufferStartTime);
-  if (evicted) {
+  Result evicted =
+    mContentManager->EvictData(TimeUnit::FromSeconds(mMediaSource->GetDecoder()->GetCurrentTime()),
+                               toEvict, &newBufferStartTime);
+  if (evicted == Result::DATA_EVICTED) {
     MSE_DEBUG("AppendData Evict; current buffered start=%f",
               GetBufferedStart());
 
     // We notify that we've evicted from the time range 0 through to
     // the current start point.
-    mMediaSource->NotifyEvicted(0.0, newBufferStartTime);
+    mMediaSource->NotifyEvicted(0.0, newBufferStartTime.ToSeconds());
   }
 
   // See if we have enough free space to append our new data.
   // As we can only evict once we have playable data, we must give a chance
   // to the DASH player to provide a complete media segment.
   if (aLength > mEvictionThreshold ||
-      ((mTrackBuffer->GetSize() > mEvictionThreshold - aLength) &&
-       !mTrackBuffer->HasOnlyIncompleteMedia())) {
+      ((mContentManager->GetSize() > mEvictionThreshold - aLength) &&
+       evicted != Result::CANT_EVICT)) {
     aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
     return nullptr;
   }
 
   nsRefPtr<MediaLargeByteBuffer> data = new MediaLargeByteBuffer();
   if (!data->AppendElements(aData, aLength, fallible)) {
     aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
     return nullptr;
@@ -598,36 +591,36 @@ SourceBuffer::Evict(double aStart, doubl
   MOZ_ASSERT(NS_IsMainThread());
   MSE_DEBUG("Evict(aStart=%f, aEnd=%f)", aStart, aEnd);
   double currentTime = mMediaSource->GetDecoder()->GetCurrentTime();
   double evictTime = aEnd;
   const double safety_threshold = 5;
   if (currentTime + safety_threshold >= evictTime) {
     evictTime -= safety_threshold;
   }
-  mTrackBuffer->EvictBefore(evictTime);
+  mContentManager->EvictBefore(TimeUnit::FromSeconds(evictTime));
 }
 
 #if defined(DEBUG)
 void
 SourceBuffer::Dump(const char* aPath)
 {
-  if (mTrackBuffer) {
-    mTrackBuffer->Dump(aPath);
+  if (mContentManager) {
+    mContentManager->Dump(aPath);
   }
 }
 #endif
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(SourceBuffer)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(SourceBuffer)
   // Tell the TrackBuffer to end its current SourceBufferResource.
-  TrackBuffer* track = tmp->mTrackBuffer;
-  if (track) {
-    track->Detach();
+  SourceBufferContentManager* manager = tmp->mContentManager;
+  if (manager) {
+    manager->Detach();
   }
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mMediaSource)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DOMEventTargetHelper)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SourceBuffer,
                                                   DOMEventTargetHelper)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaSource)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
--- a/dom/media/mediasource/SourceBuffer.h
+++ b/dom/media/mediasource/SourceBuffer.h
@@ -18,30 +18,33 @@
 #include "mozilla/mozalloc.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionNoteChild.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsISupports.h"
 #include "nsString.h"
 #include "nscore.h"
+#include "SourceBufferContentManager.h"
 
 class JSObject;
 struct JSContext;
 
 namespace mozilla {
 
 class ErrorResult;
 class MediaLargeByteBuffer;
 class TrackBuffer;
 template <typename T> class AsyncEventRunner;
-typedef MediaPromise<bool, nsresult, /* IsExclusive = */ true> TrackBufferAppendPromise;
 
 namespace dom {
 
+using media::TimeUnit;
+using media::TimeIntervals;
+
 class TimeRanges;
 
 class SourceBuffer final : public DOMEventTargetHelper
 {
 public:
   /** WebIDL Methods. */
   SourceBufferAppendMode Mode() const
   {
@@ -142,55 +145,55 @@ private:
 
   // If the media segment contains data beyond the current duration,
   // then run the duration change algorithm with new duration set to the
   // maximum of the current duration and the group end timestamp.
   void CheckEndTime();
 
   // Shared implementation of AppendBuffer overloads.
   void AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv);
-  void AppendData(MediaLargeByteBuffer* aData, double aTimestampOffset,
+  void AppendData(MediaLargeByteBuffer* aData, TimeUnit aTimestampOffset,
                   uint32_t aAppendID);
 
   // Implement the "Append Error Algorithm".
   // Will call endOfStream() with "decode" error if aDecodeError is true.
   // 3.5.3 Append Error Algorithm
   // http://w3c.github.io/media-source/#sourcebuffer-append-error
   void AppendError(bool aDecoderError);
 
   // Implements the "Prepare Append Algorithm". Returns MediaLargeByteBuffer object
   // on success or nullptr (with aRv set) on error.
   already_AddRefed<MediaLargeByteBuffer> PrepareAppend(const uint8_t* aData,
                                                        uint32_t aLength,
                                                        ErrorResult& aRv);
 
-  void AppendDataCompletedWithSuccess(bool aValue);
+  void AppendDataCompletedWithSuccess(bool aHasActiveTracks);
   void AppendDataErrored(nsresult aError);
 
   nsRefPtr<MediaSource> mMediaSource;
 
   uint32_t mEvictionThreshold;
 
-  nsRefPtr<TrackBuffer> mTrackBuffer;
+  nsRefPtr<SourceBufferContentManager> mContentManager;
 
   double mAppendWindowStart;
   double mAppendWindowEnd;
 
   double mTimestampOffset;
 
   SourceBufferAppendMode mAppendMode;
   bool mUpdating;
 
   bool mActive;
 
   // Each time mUpdating is set to true, mUpdateID will be incremented.
   // This allows for a queued AppendData task to identify if it was earlier
   // aborted and another AppendData queued.
   uint32_t mUpdateID;
 
-  MediaPromiseRequestHolder<TrackBufferAppendPromise> mPendingAppend;
+  MediaPromiseRequestHolder<SourceBufferContentManager::AppendPromise> mPendingAppend;
   const nsCString mType;
 };
 
 } // namespace dom
 
 } // namespace mozilla
 #endif /* mozilla_dom_SourceBuffer_h_ */
new file mode 100644
--- /dev/null
+++ b/dom/media/mediasource/SourceBufferContentManager.cpp
@@ -0,0 +1,20 @@
+/* -*- 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 "SourceBufferContentManager.h"
+
+namespace mozilla {
+
+already_AddRefed<SourceBufferContentManager>
+SourceBufferContentManager::CreateManager(MediaSourceDecoder* aParentDecoder,
+                                          const nsACString &aType)
+{
+  nsRefPtr<SourceBufferContentManager> manager;
+  manager = new TrackBuffer(aParentDecoder, aType);
+  return  manager.forget();
+}
+
+}
new file mode 100644
--- /dev/null
+++ b/dom/media/mediasource/SourceBufferContentManager.h
@@ -0,0 +1,89 @@
+/* -*- 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_SOURCEBUFFERCONTENTMANAGER_H_
+#define MOZILLA_SOURCEBUFFERCONTENTMANAGER_H_
+
+#include "MediaData.h"
+#include "MediaPromise.h"
+#include "MediaSourceDecoder.h"
+#include "SourceBuffer.h"
+#include "TimeUnits.h"
+#include "nsString.h"
+
+namespace mozilla {
+
+using media::TimeUnit;
+using media::TimeIntervals;
+
+class SourceBufferContentManager {
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SourceBufferContentManager);
+
+  typedef MediaPromise<bool, nsresult, /* IsExclusive = */ true> AppendPromise;
+
+  static already_AddRefed<SourceBufferContentManager>
+  CreateManager(MediaSourceDecoder* aParentDecoder, const nsACString& aType);
+
+  // Append data to the current decoder.  Also responsible for calling
+  // NotifyDataArrived on the decoder to keep buffered range computation up
+  // to date.  Returns false if the append failed.
+  virtual nsRefPtr<AppendPromise>
+  AppendData(MediaLargeByteBuffer* aData, TimeUnit aTimestampOffset /* microseconds */) = 0;
+
+  // Abort any pending AppendData.
+  virtual void AbortAppendData() = 0;
+
+  // Run MSE Reset Parser State Algorithm.
+  // 3.5.2 Reset Parser State
+  // http://w3c.github.io/media-source/#sourcebuffer-reset-parser-state
+  virtual void ResetParserState() = 0;
+
+  // Runs MSE range removal algorithm.
+  // http://w3c.github.io/media-source/#sourcebuffer-coded-frame-removal
+  virtual bool RangeRemoval(TimeUnit aStart, TimeUnit aEnd) = 0;
+
+  enum class EvictDataResult : int8_t
+  {
+    NO_DATA_EVICTED,
+    DATA_EVICTED,
+    CANT_EVICT,
+  };
+
+  // Evicts data up to aPlaybackTime. aThreshold is used to
+  // bound the data being evicted. It will not evict more than aThreshold
+  // bytes. aBufferStartTime contains the new start time of the data after the
+  // eviction.
+  virtual EvictDataResult
+  EvictData(TimeUnit aPlaybackTime, uint32_t aThreshold, TimeUnit* aBufferStartTime) = 0;
+
+  // Evicts data up to aTime.
+  virtual void EvictBefore(TimeUnit aTime) = 0;
+
+  // Returns the buffered range currently managed.
+  // This may be called on any thread.
+  // Buffered must conform to http://w3c.github.io/media-source/index.html#widl-SourceBuffer-buffered
+  virtual media::TimeIntervals Buffered() = 0;
+
+  // Return the size of the data managed by this SourceBufferContentManager.
+  virtual int64_t GetSize() = 0;
+
+  // Indicate that the MediaSource parent object got into "ended" state.
+  virtual void Ended() = 0;
+
+  // The parent SourceBuffer is about to be destroyed.
+  virtual void Detach() = 0;
+
+#if defined(DEBUG)
+  virtual void Dump(const char* aPath) { }
+#endif
+
+protected:
+  virtual ~SourceBufferContentManager() { }
+};
+
+} // namespace mozilla
+#endif /* MOZILLA_SOURCEBUFFERCONTENTMANAGER_H_ */
--- a/dom/media/mediasource/TrackBuffer.cpp
+++ b/dom/media/mediasource/TrackBuffer.cpp
@@ -37,18 +37,16 @@ extern PRLogModuleInfo* GetMediaSourceLo
 #define EOS_FUZZ_US 125000
 
 namespace mozilla {
 
 TrackBuffer::TrackBuffer(MediaSourceDecoder* aParentDecoder, const nsACString& aType)
   : mParentDecoder(aParentDecoder)
   , mType(aType)
   , mLastStartTimestamp(0)
-  , mLastTimestampOffset(0)
-  , mAdjustedTimestamp(0)
   , mIsWaitingOnCDM(false)
   , mShutdown(false)
 {
   MOZ_COUNT_CTOR(TrackBuffer);
   mParser = ContainerParser::CreateForMIMEType(aType);
   mTaskQueue =
     new MediaTaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK));
   aParentDecoder->AddTrackBuffer(this);
@@ -70,17 +68,17 @@ public:
 
   ~DecodersToInitialize()
   {
     for (size_t i = 0; i < mDecoders.Length(); i++) {
       mOwner->QueueInitializeDecoder(mDecoders[i]);
     }
   }
 
-  bool NewDecoder(int64_t aTimestampOffset)
+  bool NewDecoder(TimeUnit aTimestampOffset)
   {
     nsRefPtr<SourceBufferDecoder> decoder = mOwner->NewDecoder(aTimestampOffset);
     if (!decoder) {
       return false;
     }
     mDecoders.AppendElement(decoder);
     return true;
   }
@@ -135,24 +133,24 @@ TrackBuffer::ContinueShutdown()
 
   MOZ_ASSERT(!mCurrentDecoder, "Detach() should have been called");
   mInitializedDecoders.Clear();
   mParentDecoder = nullptr;
 
   mShutdownPromise.Resolve(true, __func__);
 }
 
-nsRefPtr<TrackBufferAppendPromise>
-TrackBuffer::AppendData(MediaLargeByteBuffer* aData, int64_t aTimestampOffset)
+nsRefPtr<TrackBuffer::AppendPromise>
+TrackBuffer::AppendData(MediaLargeByteBuffer* aData, TimeUnit aTimestampOffset)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mInitializationPromise.IsEmpty());
 
   DecodersToInitialize decoders(this);
-  nsRefPtr<TrackBufferAppendPromise> p = mInitializationPromise.Ensure(__func__);
+  nsRefPtr<AppendPromise> p = mInitializationPromise.Ensure(__func__);
   bool hadInitData = mParser->HasInitData();
   bool hadCompleteInitData = mParser->HasCompleteInitData();
   nsRefPtr<MediaLargeByteBuffer> oldInit = mParser->InitData();
   bool newInitData = mParser->IsInitSegmentPresent(aData);
 
   // TODO: Run more of the buffer append algorithm asynchronously.
   if (newInitData) {
     MSE_DEBUG("New initialization segment.");
@@ -216,21 +214,23 @@ TrackBuffer::AppendData(MediaLargeByteBu
       MSE_DEBUG("Segment last=[%lld, %lld] [%lld, %lld]",
                 mLastStartTimestamp,
                 mLastEndTimestamp ? mLastEndTimestamp.value() : 0, start, end);
     }
     mLastEndTimestamp.reset();
     mLastEndTimestamp.emplace(end);
   }
 
-  if (gotMedia && start != mAdjustedTimestamp &&
-      ((start < 0 && -start < FUZZ_TIMESTAMP_OFFSET && start < mAdjustedTimestamp) ||
-       (start > 0 && (start < FUZZ_TIMESTAMP_OFFSET || start < mAdjustedTimestamp)))) {
-    AdjustDecodersTimestampOffset(mAdjustedTimestamp - start);
-    mAdjustedTimestamp = start;
+  TimeUnit starttu{TimeUnit::FromMicroseconds(start)};
+
+  if (gotMedia && starttu != mAdjustedTimestamp &&
+      ((start < 0 && -start < FUZZ_TIMESTAMP_OFFSET && starttu < mAdjustedTimestamp) ||
+       (start > 0 && (start < FUZZ_TIMESTAMP_OFFSET || starttu < mAdjustedTimestamp)))) {
+    AdjustDecodersTimestampOffset(mAdjustedTimestamp - starttu);
+    mAdjustedTimestamp = starttu;
   }
 
   if (!AppendDataToCurrentResource(aData, end - start)) {
     mInitializationPromise.Reject(NS_ERROR_FAILURE, __func__);
     return p;
   }
 
   if (decoders.Length()) {
@@ -238,17 +238,17 @@ TrackBuffer::AppendData(MediaLargeByteBu
     // will be resolved once initialization completes.
     return p;
   }
 
   // Tell our reader that we have more data to ensure that playback starts if
   // required when data is appended.
   NotifyTimeRangesChanged();
 
-  mInitializationPromise.Resolve(gotMedia, __func__);
+  mInitializationPromise.Resolve(HasInitSegment(), __func__);
   return p;
 }
 
 bool
 TrackBuffer::AppendDataToCurrentResource(MediaLargeByteBuffer* aData, uint32_t aDuration)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!mCurrentDecoder) {
@@ -277,93 +277,93 @@ TrackBuffer::NotifyTimeRangesChanged()
   mParentDecoder->GetReader()->GetTaskQueue()->Dispatch(task.forget());
 }
 
 class DecoderSorter
 {
 public:
   bool LessThan(SourceBufferDecoder* aFirst, SourceBufferDecoder* aSecond) const
   {
-    media::TimeIntervals first = aFirst->GetBuffered();
-    media::TimeIntervals second = aSecond->GetBuffered();
+    TimeIntervals first = aFirst->GetBuffered();
+    TimeIntervals second = aSecond->GetBuffered();
 
     return first.GetStart() < second.GetStart();
   }
 
   bool Equals(SourceBufferDecoder* aFirst, SourceBufferDecoder* aSecond) const
   {
-    media::TimeIntervals first = aFirst->GetBuffered();
-    media::TimeIntervals second = aSecond->GetBuffered();
+    TimeIntervals first = aFirst->GetBuffered();
+    TimeIntervals second = aSecond->GetBuffered();
 
     return first.GetStart() == second.GetStart();
   }
 };
 
-bool
-TrackBuffer::EvictData(double aPlaybackTime,
+TrackBuffer::EvictDataResult
+TrackBuffer::EvictData(TimeUnit aPlaybackTime,
                        uint32_t aThreshold,
-                       double* aBufferStartTime)
+                       TimeUnit* aBufferStartTime)
 {
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
 
-  if (!mCurrentDecoder) {
-    return false;
+  if (!mCurrentDecoder || mInitializedDecoders.IsEmpty()) {
+    return EvictDataResult::CANT_EVICT;
   }
 
   int64_t totalSize = GetSize();
 
   int64_t toEvict = totalSize - aThreshold;
-  if (toEvict <= 0 || mInitializedDecoders.IsEmpty()) {
-    return false;
+  if (toEvict <= 0) {
+    return EvictDataResult::NO_DATA_EVICTED;
   }
 
   // Get a list of initialized decoders.
   nsTArray<SourceBufferDecoder*> decoders;
   decoders.AppendElements(mInitializedDecoders);
+  const TimeUnit evictThresholdTime{TimeUnit::FromSeconds(MSE_EVICT_THRESHOLD_TIME)};
 
   // First try to evict data before the current play position, starting
   // with the oldest decoder.
   for (uint32_t i = 0; i < decoders.Length() && toEvict > 0; ++i) {
-    media::TimeIntervals buffered = decoders[i]->GetBuffered();
+    TimeIntervals buffered = decoders[i]->GetBuffered();
 
     MSE_DEBUG("Step1. decoder=%u/%u threshold=%u toEvict=%lld",
               i, decoders.Length(), aThreshold, toEvict);
 
     // To ensure we don't evict data past the current playback position
     // we apply a threshold of a few seconds back and evict data up to
     // that point.
-    if (aPlaybackTime > MSE_EVICT_THRESHOLD_TIME) {
-      media::TimeUnit time = media::TimeUnit::FromSeconds(aPlaybackTime) -
-        media::TimeUnit::FromSeconds(MSE_EVICT_THRESHOLD_TIME);
+    if (aPlaybackTime > evictThresholdTime) {
+      TimeUnit time = aPlaybackTime - evictThresholdTime;
       bool isActive = decoders[i] == mCurrentDecoder ||
         mParentDecoder->IsActiveReader(decoders[i]->GetReader());
       if (!isActive && buffered.GetEnd() < time) {
         // The entire decoder is contained before our current playback time.
         // It can be fully evicted.
         MSE_DEBUG("evicting all bufferedEnd=%f "
                   "aPlaybackTime=%f time=%f, size=%lld",
-                  buffered.GetEnd().ToSeconds(), aPlaybackTime, time,
-                  decoders[i]->GetResource()->GetSize());
+                  buffered.GetEnd().ToSeconds(), aPlaybackTime.ToSeconds(),
+                  time, decoders[i]->GetResource()->GetSize());
         toEvict -= decoders[i]->GetResource()->EvictAll();
       } else {
         int64_t playbackOffset =
           decoders[i]->ConvertToByteOffset(time.ToSeconds());
         MSE_DEBUG("evicting some bufferedEnd=%f "
                   "aPlaybackTime=%f time=%f, playbackOffset=%lld size=%lld",
-                  buffered.GetEnd().ToSeconds(), aPlaybackTime, time,
-                  playbackOffset, decoders[i]->GetResource()->GetSize());
+                  buffered.GetEnd().ToSeconds(), aPlaybackTime.ToSeconds(),
+                  time, playbackOffset, decoders[i]->GetResource()->GetSize());
         if (playbackOffset > 0) {
           ErrorResult rv;
           toEvict -= decoders[i]->GetResource()->EvictData(playbackOffset,
                                                            playbackOffset,
                                                            rv);
           if (NS_WARN_IF(rv.Failed())) {
             rv.SuppressException();
-            return false;
+            return EvictDataResult::CANT_EVICT;
           }
         }
       }
       decoders[i]->GetReader()->NotifyDataRemoved();
     }
   }
 
   // Evict all data from decoders we've likely already read from.
@@ -371,17 +371,17 @@ TrackBuffer::EvictData(double aPlaybackT
     MSE_DEBUG("Step2. decoder=%u/%u threshold=%u toEvict=%lld",
               i, decoders.Length(), aThreshold, toEvict);
     if (mParentDecoder->IsActiveReader(decoders[i]->GetReader())) {
       break;
     }
     if (decoders[i] == mCurrentDecoder) {
       continue;
     }
-    media::TimeIntervals buffered = decoders[i]->GetBuffered();
+    TimeIntervals buffered = decoders[i]->GetBuffered();
 
     // Remove data from older decoders than the current one.
     MSE_DEBUG("evicting all "
               "bufferedStart=%f bufferedEnd=%f aPlaybackTime=%f size=%lld",
               buffered.GetStart().ToSeconds(), buffered.GetEnd().ToSeconds(),
               aPlaybackTime, decoders[i]->GetResource()->GetSize());
     toEvict -= decoders[i]->GetResource()->EvictAll();
     decoders[i]->GetReader()->NotifyDataRemoved();
@@ -401,72 +401,74 @@ TrackBuffer::EvictData(double aPlaybackT
     if (mParentDecoder->IsActiveReader(decoders[i]->GetReader())) {
       playingDecoder = decoders[i];
       break;
     }
   }
   // Find the next decoder we're likely going to play with.
   nsRefPtr<SourceBufferDecoder> nextPlayingDecoder = nullptr;
   if (playingDecoder) {
-    media::TimeIntervals buffered = playingDecoder->GetBuffered();
+    TimeIntervals buffered = playingDecoder->GetBuffered();
     nextPlayingDecoder =
       mParentDecoder->SelectDecoder(buffered.GetEnd().ToMicroseconds() + 1,
                                     EOS_FUZZ_US,
                                     mInitializedDecoders);
   }
 
   // Sort decoders by their start times.
   decoders.Sort(DecoderSorter());
 
   for (int32_t i = int32_t(decoders.Length()) - 1; i >= 0 && toEvict > 0; --i) {
     MSE_DEBUG("Step3. decoder=%u/%u threshold=%u toEvict=%lld",
               i, decoders.Length(), aThreshold, toEvict);
     if (decoders[i] == playingDecoder || decoders[i] == nextPlayingDecoder ||
         decoders[i] == mCurrentDecoder) {
       continue;
     }
-    media::TimeIntervals buffered = decoders[i]->GetBuffered();
+    TimeIntervals buffered = decoders[i]->GetBuffered();
 
     MSE_DEBUG("evicting all "
               "bufferedStart=%f bufferedEnd=%f aPlaybackTime=%f size=%lld",
               buffered.GetStart().ToSeconds(), buffered.GetEnd().ToSeconds(),
               aPlaybackTime, decoders[i]->GetResource()->GetSize());
     toEvict -= decoders[i]->GetResource()->EvictAll();
     decoders[i]->GetReader()->NotifyDataRemoved();
   }
 
   RemoveEmptyDecoders(decoders);
 
   bool evicted = toEvict < (totalSize - aThreshold);
   if (evicted) {
     if (playingDecoder) {
-      media::TimeIntervals ranges = playingDecoder->GetBuffered();
-      *aBufferStartTime = std::max(0.0, ranges.GetStart().ToSeconds());
+      TimeIntervals ranges = playingDecoder->GetBuffered();
+      *aBufferStartTime = std::max(TimeUnit::FromSeconds(0), ranges.GetStart());
     } else {
       // We do not currently have data to play yet.
       // Avoid evicting anymore data to minimize rebuffering time.
-      *aBufferStartTime = 0.0;
+      *aBufferStartTime = TimeUnit::FromSeconds(0.0);
     }
   }
 
   if (evicted) {
     NotifyTimeRangesChanged();
   }
 
-  return evicted;
+  return evicted ?
+    EvictDataResult::DATA_EVICTED :
+    (HasOnlyIncompleteMedia() ? EvictDataResult::CANT_EVICT : EvictDataResult::NO_DATA_EVICTED);
 }
 
 void
 TrackBuffer::RemoveEmptyDecoders(nsTArray<mozilla::SourceBufferDecoder*>& aDecoders)
 {
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
 
   // Remove decoders that have no data in them
   for (uint32_t i = 0; i < aDecoders.Length(); ++i) {
-    media::TimeIntervals buffered = aDecoders[i]->GetBuffered();
+    TimeIntervals buffered = aDecoders[i]->GetBuffered();
     MSE_DEBUG("maybe remove empty decoders=%d "
               "size=%lld start=%f end=%f",
               i, aDecoders[i]->GetResource()->GetSize(),
               buffered.GetStart().ToSeconds(), buffered.GetEnd().ToSeconds());
     if (aDecoders[i] == mCurrentDecoder ||
         mParentDecoder->IsActiveReader(aDecoders[i]->GetReader())) {
       continue;
     }
@@ -490,74 +492,74 @@ TrackBuffer::GetSize()
 }
 
 bool
 TrackBuffer::HasOnlyIncompleteMedia()
 {
   if (!mCurrentDecoder) {
     return false;
   }
-  media::TimeIntervals buffered = mCurrentDecoder->GetBuffered();
+  TimeIntervals buffered = mCurrentDecoder->GetBuffered();
   MSE_DEBUG("mCurrentDecoder.size=%lld, start=%f end=%f",
             mCurrentDecoder->GetResource()->GetSize(),
             buffered.GetStart(), buffered.GetEnd());
   return mCurrentDecoder->GetResource()->GetSize() && !buffered.Length();
 }
 
 void
-TrackBuffer::EvictBefore(double aTime)
+TrackBuffer::EvictBefore(TimeUnit aTime)
 {
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
   for (uint32_t i = 0; i < mInitializedDecoders.Length(); ++i) {
-    int64_t endOffset = mInitializedDecoders[i]->ConvertToByteOffset(aTime);
+    int64_t endOffset = mInitializedDecoders[i]->ConvertToByteOffset(aTime.ToSeconds());
     if (endOffset > 0) {
       MSE_DEBUG("decoder=%u offset=%lld",
                 i, endOffset);
       ErrorResult rv;
       mInitializedDecoders[i]->GetResource()->EvictBefore(endOffset, rv);
       if (NS_WARN_IF(rv.Failed())) {
         rv.SuppressException();
         return;
       }
       mInitializedDecoders[i]->GetReader()->NotifyDataRemoved();
     }
   }
   NotifyTimeRangesChanged();
 }
 
-media::TimeIntervals
+TimeIntervals
 TrackBuffer::Buffered()
 {
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
 
-  media::TimeIntervals buffered;
+  TimeIntervals buffered;
 
   for (auto& decoder : mInitializedDecoders) {
     buffered += decoder->GetBuffered();
   }
   // mParser may not be initialized yet, and will only be so if we have a
   // buffered range.
   if (buffered.Length()) {
-    buffered.SetFuzz(media::TimeUnit::FromMicroseconds(mParser->GetRoundingError()));
+    buffered.SetFuzz(TimeUnit::FromMicroseconds(mParser->GetRoundingError()));
   }
 
   return buffered;
 }
 
 already_AddRefed<SourceBufferDecoder>
-TrackBuffer::NewDecoder(int64_t aTimestampOffset)
+TrackBuffer::NewDecoder(TimeUnit aTimestampOffset)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mParentDecoder);
 
   DiscardCurrentDecoder();
 
   nsRefPtr<SourceBufferDecoder> decoder =
-    mParentDecoder->CreateSubDecoder(mType, aTimestampOffset - mAdjustedTimestamp);
+    mParentDecoder->CreateSubDecoder(mType, (aTimestampOffset - mAdjustedTimestamp).ToMicroseconds());
   if (!decoder) {
     return nullptr;
   }
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
   mCurrentDecoder = decoder;
   mDecoders.AppendElement(decoder);
 
   mLastStartTimestamp = 0;
@@ -815,17 +817,17 @@ TrackBuffer::CompleteInitializeDecoder(S
   mParentDecoder->SetInitialDuration(duration);
 
   // Tell our reader that we have more data to ensure that playback starts if
   // required when data is appended.
   NotifyTimeRangesChanged();
 
   MSE_DEBUG("Reader %p activated",
             aDecoder->GetReader());
-  mInitializationPromise.ResolveIfExists(aDecoder->GetRealMediaDuration() > 0, __func__);
+  mInitializationPromise.ResolveIfExists(true, __func__);
 }
 
 bool
 TrackBuffer::ValidateTrackFormats(const MediaInfo& aInfo)
 {
   if (mInfo.HasAudio() != aInfo.HasAudio() ||
       mInfo.HasVideo() != aInfo.HasVideo()) {
     MSE_DEBUG("audio/video track mismatch");
@@ -909,20 +911,20 @@ TrackBuffer::IsWaitingOnCDMResource()
 {
   return mIsWaitingOnCDM;
 }
 
 bool
 TrackBuffer::ContainsTime(int64_t aTime, int64_t aTolerance)
 {
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
-  media::TimeUnit time{media::TimeUnit::FromMicroseconds(aTime)};
+  TimeUnit time{TimeUnit::FromMicroseconds(aTime)};
   for (auto& decoder : mInitializedDecoders) {
-    media::TimeIntervals r = decoder->GetBuffered();
-    r.SetFuzz(media::TimeUnit::FromMicroseconds(aTolerance));
+    TimeIntervals r = decoder->GetBuffered();
+    r.SetFuzz(TimeUnit::FromMicroseconds(aTolerance));
     if (r.Contains(time)) {
       return true;
     }
   }
 
   return false;
 }
 
@@ -1068,25 +1070,24 @@ TrackBuffer::RemoveDecoder(SourceBufferD
     MOZ_ASSERT(!mParentDecoder->IsActiveReader(aDecoder->GetReader()));
     mInitializedDecoders.RemoveElement(aDecoder);
     mDecoders.RemoveElement(aDecoder);
   }
   aDecoder->GetReader()->GetTaskQueue()->Dispatch(task.forget());
 }
 
 bool
-TrackBuffer::RangeRemoval(media::TimeUnit aStart,
-                          media::TimeUnit aEnd)
+TrackBuffer::RangeRemoval(TimeUnit aStart, TimeUnit aEnd)
 {
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
 
-  media::TimeIntervals buffered = Buffered();
-  media::TimeUnit bufferedStart = buffered.GetStart();
-  media::TimeUnit bufferedEnd = buffered.GetEnd();
+  TimeIntervals buffered = Buffered();
+  TimeUnit bufferedStart = buffered.GetStart();
+  TimeUnit bufferedEnd = buffered.GetEnd();
 
   if (!buffered.Length() || aStart > bufferedEnd || aEnd < bufferedStart) {
     // Nothing to remove.
     return false;
   }
 
   if (aStart > bufferedStart && aEnd < bufferedEnd) {
     // TODO. We only handle trimming and removal from the start.
@@ -1096,17 +1097,17 @@ TrackBuffer::RangeRemoval(media::TimeUni
   }
 
   nsTArray<SourceBufferDecoder*> decoders;
   decoders.AppendElements(mInitializedDecoders);
 
   if (aStart <= bufferedStart && aEnd < bufferedEnd) {
     // Evict data from beginning.
     for (size_t i = 0; i < decoders.Length(); ++i) {
-      media::TimeIntervals buffered = decoders[i]->GetBuffered();
+      TimeIntervals buffered = decoders[i]->GetBuffered();
       if (buffered.GetEnd() < aEnd) {
         // Can be fully removed.
         MSE_DEBUG("remove all bufferedEnd=%f size=%lld",
                   buffered.GetEnd().ToSeconds(),
                   decoders[i]->GetResource()->GetSize());
         decoders[i]->GetResource()->EvictAll();
       } else {
         int64_t offset = decoders[i]->ConvertToByteOffset(aEnd.ToSeconds());
@@ -1139,19 +1140,19 @@ TrackBuffer::RangeRemoval(media::TimeUni
 
   RemoveEmptyDecoders(decoders);
 
   NotifyTimeRangesChanged();
   return true;
 }
 
 void
-TrackBuffer::AdjustDecodersTimestampOffset(int32_t aOffset)
+TrackBuffer::AdjustDecodersTimestampOffset(TimeUnit aOffset)
 {
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
   for (uint32_t i = 0; i < mDecoders.Length(); i++) {
-    mDecoders[i]->SetTimestampOffset(mDecoders[i]->GetTimestampOffset() + aOffset);
+    mDecoders[i]->SetTimestampOffset(mDecoders[i]->GetTimestampOffset() + aOffset.ToMicroseconds());
   }
 }
 
 #undef MSE_DEBUG
 
 } // namespace mozilla
--- a/dom/media/mediasource/TrackBuffer.h
+++ b/dom/media/mediasource/TrackBuffer.h
@@ -19,116 +19,107 @@
 #include "TimeUnits.h"
 
 namespace mozilla {
 
 class ContainerParser;
 class MediaSourceDecoder;
 class MediaLargeByteBuffer;
 
-class TrackBuffer final {
+class TrackBuffer final : public SourceBufferContentManager {
 public:
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TrackBuffer);
-
   TrackBuffer(MediaSourceDecoder* aParentDecoder, const nsACString& aType);
 
   nsRefPtr<ShutdownPromise> Shutdown();
 
   // Append data to the current decoder.  Also responsible for calling
   // NotifyDataArrived on the decoder to keep buffered range computation up
   // to date.  Returns false if the append failed.
-  nsRefPtr<TrackBufferAppendPromise> AppendData(MediaLargeByteBuffer* aData,
-                                                int64_t aTimestampOffset /* microseconds */);
+  nsRefPtr<AppendPromise> AppendData(MediaLargeByteBuffer* aData,
+                                     TimeUnit aTimestampOffset /* microseconds */) override;
 
   // Evicts data held in the current decoders SourceBufferResource from the
   // start of the buffer through to aPlaybackTime. aThreshold is used to
   // bound the data being evicted. It will not evict more than aThreshold
   // bytes. aBufferStartTime contains the new start time of the current
-  // decoders buffered data after the eviction. Returns true if data was
-  // evicted.
-  bool EvictData(double aPlaybackTime, uint32_t aThreshold, double* aBufferStartTime);
+  // decoders buffered data after the eviction.
+  EvictDataResult EvictData(TimeUnit aPlaybackTime, uint32_t aThreshold, TimeUnit* aBufferStartTime) override;
 
   // Evicts data held in all the decoders SourceBufferResource from the start
   // of the buffer through to aTime.
-  void EvictBefore(double aTime);
+  void EvictBefore(TimeUnit aTime) override;
+
+  bool RangeRemoval(TimeUnit aStart, TimeUnit aEnd) override;
+
+  void AbortAppendData() override;
+
+  int64_t GetSize() override;
+
+  void ResetParserState() override;
 
   // Returns the union of the decoders buffered ranges in aRanges.
   // This may be called on any thread.
-  media::TimeIntervals Buffered();
+  media::TimeIntervals Buffered() override;
+
+  void Ended() override
+  {
+    EndCurrentDecoder();
+  }
+
+  void Detach() override;
 
   // Mark the current decoder's resource as ended, clear mCurrentDecoder and
   // reset mLast{Start,End}Timestamp.  Main thread only.
   void DiscardCurrentDecoder();
   // Mark the current decoder's resource as ended.
   void EndCurrentDecoder();
 
-  void Detach();
-
   // Returns true if an init segment has been appended.
   bool HasInitSegment();
 
   // Returns true iff mParser->HasInitData() and the decoder using that init
   // segment has successfully initialized by setting mHas{Audio,Video}..
   bool IsReady();
 
   bool IsWaitingOnCDMResource();
 
   // Returns true if any of the decoders managed by this track buffer
   // contain aTime in their buffered ranges.
   bool ContainsTime(int64_t aTime, int64_t aTolerance);
 
   void BreakCycles();
 
-  // Run MSE Reset Parser State Algorithm.
-  // 3.5.2 Reset Parser State
-  // http://w3c.github.io/media-source/#sourcebuffer-reset-parser-state
-  void ResetParserState();
-
   // Returns a reference to mInitializedDecoders, used by MediaSourceReader
   // to select decoders.
   // TODO: Refactor to a cleaner interface between TrackBuffer and MediaSourceReader.
   const nsTArray<nsRefPtr<SourceBufferDecoder>>& Decoders();
 
-  // Runs MSE range removal algorithm.
-  // http://w3c.github.io/media-source/#sourcebuffer-coded-frame-removal
-  // Implementation is only partial, we can only trim a buffer.
-  // Returns true if data was evicted.
-  // Times are in microseconds.
-  bool RangeRemoval(mozilla::media::TimeUnit aStart,
-                    mozilla::media::TimeUnit aEnd);
-
-  // Abort any pending appendBuffer by rejecting any pending promises.
-  void AbortAppendData();
-
-  // Return the size used by all decoders managed by this TrackBuffer.
-  int64_t GetSize();
-
   // Return true if we have a partial media segment being appended that is
   // currently not playable.
   bool HasOnlyIncompleteMedia();
 
 #ifdef MOZ_EME
   nsresult SetCDMProxy(CDMProxy* aProxy);
 #endif
 
 #if defined(DEBUG)
   void Dump(const char* aPath);
 #endif
 
 private:
   friend class DecodersToInitialize;
   friend class MetadataRecipient;
-  ~TrackBuffer();
+  virtual ~TrackBuffer();
 
   // Create a new decoder, set mCurrentDecoder to the new decoder and
   // returns it. The new decoder must be queued using QueueInitializeDecoder
   // for initialization.
   // The decoder is not considered initialized until it is added to
   // mInitializedDecoders.
-  already_AddRefed<SourceBufferDecoder> NewDecoder(int64_t aTimestampOffset /* microseconds */);
+  already_AddRefed<SourceBufferDecoder> NewDecoder(TimeUnit aTimestampOffset);
 
   // Helper for AppendData, ensures NotifyDataArrived is called whenever
   // data is appended to the current decoder's SourceBufferResource.
   bool AppendDataToCurrentResource(MediaLargeByteBuffer* aData,
                                    uint32_t aDuration /* microseconds */);
   // Queue on the parent's decoder task queue a call to NotifyTimeRangesChanged.
   void NotifyTimeRangesChanged();
 
@@ -196,33 +187,33 @@ private:
 
   nsRefPtr<MediaSourceDecoder> mParentDecoder;
   const nsCString mType;
 
   // The last start and end timestamps added to the TrackBuffer via
   // AppendData.  Accessed on the main thread only.
   int64_t mLastStartTimestamp;
   Maybe<int64_t> mLastEndTimestamp;
-  void AdjustDecodersTimestampOffset(int32_t aOffset);
+  void AdjustDecodersTimestampOffset(TimeUnit aOffset);
 
-  // The timestamp offset used by our current decoder, in microseconds.
-  int64_t mLastTimestampOffset;
-  int64_t mAdjustedTimestamp;
+  // The timestamp offset used by our current decoder.
+  TimeUnit mLastTimestampOffset;
+  TimeUnit mAdjustedTimestamp;
 
   // True if at least one of our decoders has encrypted content.
   bool mIsWaitingOnCDM;
 
   // Set when the first decoder used by this TrackBuffer is initialized.
   // Protected by mParentDecoder's monitor.
   MediaInfo mInfo;
 
   void ContinueShutdown();
   MediaPromiseHolder<ShutdownPromise> mShutdownPromise;
   bool mDecoderPerSegment;
   bool mShutdown;
 
-  MediaPromiseHolder<TrackBufferAppendPromise> mInitializationPromise;
+  MediaPromiseHolder<AppendPromise> mInitializationPromise;
   // Track our request for metadata from the reader.
   MediaPromiseRequestHolder<MediaDecoderReader::MetadataPromise> mMetadataRequest;
 };
 
 } // namespace mozilla
 #endif /* MOZILLA_TRACKBUFFER_H_ */
--- a/dom/media/mediasource/moz.build
+++ b/dom/media/mediasource/moz.build
@@ -4,32 +4,34 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MOCHITEST_MANIFESTS += ['test/mochitest.ini']
 
 EXPORTS += [
     'AsyncEventRunner.h',
     'MediaSourceDecoder.h',
     'MediaSourceReader.h',
+    'SourceBufferContentManager.h',
 ]
 
 EXPORTS.mozilla.dom += [
     'MediaSource.h',
     'SourceBuffer.h',
     'SourceBufferList.h',
 ]
 
 UNIFIED_SOURCES += [
     'ContainerParser.cpp',
     'MediaSource.cpp',
     'MediaSourceDecoder.cpp',
     'MediaSourceReader.cpp',
     'MediaSourceUtils.cpp',
     'ResourceQueue.cpp',
     'SourceBuffer.cpp',
+    'SourceBufferContentManager.cpp',
     'SourceBufferDecoder.cpp',
     'SourceBufferList.cpp',
     'SourceBufferResource.cpp',
     'TrackBuffer.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
--- a/dom/media/tests/mochitest/head.js
+++ b/dom/media/tests/mochitest/head.js
@@ -130,21 +130,27 @@ function setupEnvironment() {
   window.finish = () => SimpleTest.finish();
   SpecialPowers.pushPrefEnv({
     'set': [
       ['canvas.capturestream.enabled', true],
       ['dom.messageChannel.enabled', true],
       ['media.peerconnection.enabled', true],
       ['media.peerconnection.identity.enabled', true],
       ['media.peerconnection.identity.timeout', 12000],
+      ['media.peerconnection.ice.stun_client_maximum_transmits', 14],
+      ['media.peerconnection.ice.trickle_grace_period', 30000],
       ['media.navigator.permission.disabled', true],
       ['media.getusermedia.screensharing.enabled', true],
       ['media.getusermedia.screensharing.allowed_domains', "mochi.test"]
     ]
   }, setTestOptions);
+
+  // We don't care about waiting for this to complete, we just want to ensure
+  // that we don't build up a huge backlog of GC work.
+  SpecialPowers.exactGC(window);
 }
 
 // This is called by steeplechase; which provides the test configuration options
 // directly to the test through this function.  If we're not on steeplechase,
 // the test is configured directly and immediately.
 function run_test(is_initiator) {
   var options = { is_local: is_initiator,
                   is_remote: !is_initiator };
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -1,12 +1,12 @@
 [DEFAULT]
 # strictContentSandbox - bug 1042735, Android 2.3 - bug 981881
 tags = msg webrtc
-skip-if = (os == 'win' && strictContentSandbox) || android_version == '10' || android_version == '18' || (buildapp == 'mulet')
+skip-if = (os == 'win' && strictContentSandbox) || android_version == '10' || android_version == '18' || (buildapp == 'mulet') || (toolkit == 'gonk' && debug) # b2g(Either bug 1171118 or bug 1169838, take your pick)
 support-files =
   head.js
   dataChannel.js
   mediaStreamPlayback.js
   network.js
   nonTrickleIce.js
   pc.js
   templates.js
@@ -18,187 +18,160 @@ support-files =
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # Bug 962984 for debug, bug 963244 for opt
 [test_dataChannel_basicAudioVideo.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_dataChannel_basicAudioVideoNoBundle.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_dataChannel_basicAudioVideoCombined.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_dataChannel_basicDataOnly.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
 [test_dataChannel_basicVideo.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_dataChannel_bug1013809.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g emulator seems to be too slow (Bug 1016498 and 1008080)
 [test_dataChannel_noOffer.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
 [test_enumerateDevices.html]
 skip-if = buildapp == 'mulet'
 [test_getUserMedia_basicAudio.html]
 skip-if = (toolkit == 'gonk' || buildapp == 'mulet' && debug) # debug-only failure
 [test_getUserMedia_basicVideo.html]
 skip-if = (toolkit == 'gonk' || buildapp == 'mulet' && debug) # debug-only failure
 [test_getUserMedia_basicVideo_playAfterLoadedmetadata.html]
 skip-if = (toolkit == 'gonk' || buildapp == 'mulet' && debug) # debug-only failure
 [test_getUserMedia_basicScreenshare.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' # no screenshare on b2g/android # Bug 1141029 Mulet parity with B2G Desktop for TC
 [test_getUserMedia_basicWindowshare.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' # no windowshare on b2g/android # Bug 1141029 Mulet parity with B2G Desktop for TC
 [test_getUserMedia_basicVideoAudio.html]
 skip-if = (toolkit == 'gonk' || buildapp == 'mulet' && debug) # debug-only failure, turned an intermittent (bug 962579) into a permanant orange
 [test_getUserMedia_constraints.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' # Bug 1063290, intermittent timeout
 [test_getUserMedia_callbacks.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' || buildapp == 'mulet' # Bug 1063290, intermittent timeout # TC: Bug 1144079 - Re-enable Mulet mochitests and reftests taskcluster-specific disables.
 [test_getUserMedia_gumWithinGum.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' # Bug 1063290, intermittent timeout
 [test_getUserMedia_playAudioTwice.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' # Bug 1063290, intermittent timeout
 [test_getUserMedia_playVideoAudioTwice.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' # Bug 1063290, intermittent timeout # bug 926558, debug-only failure
 [test_getUserMedia_playVideoTwice.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' # Bug 1063290, intermittent timeout
 [test_getUserMedia_stopAudioStream.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' # Bug 1063290, intermittent timeout
 [test_getUserMedia_stopAudioStreamWithFollowupAudio.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' # Bug 1063290, intermittent timeout
 [test_getUserMedia_stopVideoAudioStream.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' # Bug 1063290, intermittent timeout # bug 926558, debug-only failure
 [test_getUserMedia_stopVideoAudioStreamWithFollowupVideoAudio.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' # Bug 1063290, intermittent timeout
 [test_getUserMedia_stopVideoStream.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' # Bug 1063290, intermittent timeout
 [test_getUserMedia_stopVideoStreamWithFollowupVideo.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' # Bug 1063290, intermittent timeout
 [test_getUserMedia_peerIdentity.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 1021776, too --ing slow on b2g)
 [test_peerConnection_addIceCandidate.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
 [test_peerConnection_basicAudio.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
+skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio call reliably
 [test_peerConnection_basicAudioVideo.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_basicAudioVideoCombined.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_basicAudioVideoNoBundle.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
+skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_basicVideo.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_basicScreenshare.html]
 # no screenshare on b2g/android
 # frequent timeouts/crashes on e10s (bug 1048455)
 skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android' || e10s # Bug 1141029 Mulet parity with B2G Desktop for TC
 [test_peerConnection_basicWindowshare.html]
 # no screenshare on b2g/android
 # frequent timeouts/crashes on e10s (bug 1048455)
 skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android' || e10s # Bug 1141029 Mulet parity with B2G Desktop for TC
 [test_peerConnection_basicH264Video.html]
 skip-if = buildapp == 'b2g' || buildapp == 'mulet' || os == 'android' # bug 1043403 # Bug 1141029 Mulet parity with B2G Desktop for TC
 [test_peerConnection_bug822674.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
 [test_peerConnection_bug825703.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
 [test_peerConnection_bug827843.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_bug834153.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
 [test_peerConnection_bug1013809.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g emulator seems to be too slow (Bug 1016498 and 1008080)
+skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio call reliably
 [test_peerConnection_bug1042791.html]
 skip-if = buildapp == 'b2g' || buildapp == 'mulet' || os == 'android' # bug 1043403 # Bug 1141029 Mulet parity with B2G Desktop for TC
 [test_peerConnection_capturedVideo.html]
 tags=capturestream
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_captureStream_canvas_2d.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_captureStream_canvas_webgl.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_close.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
 [test_peerConnection_errorCallbacks.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
 [test_peerConnection_forwarding_basicAudioVideoCombined.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_noTrickleAnswer.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
+skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio call reliably
 [test_peerConnection_noTrickleOffer.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
+skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio call reliably
 [test_peerConnection_noTrickleOfferAnswer.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
+skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio call reliably
 [test_peerConnection_offerRequiresReceiveAudio.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_offerRequiresReceiveVideo.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_offerRequiresReceiveVideoAudio.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_promiseSendOnly.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_callbacks.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_replaceTrack.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_syncSetDescription.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_setLocalAnswerInHaveLocalOffer.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
 [test_peerConnection_setLocalAnswerInStable.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
 [test_peerConnection_setLocalOfferInHaveRemoteOffer.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
 [test_peerConnection_setRemoteAnswerInHaveRemoteOffer.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
 [test_peerConnection_setRemoteAnswerInStable.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
 [test_peerConnection_setRemoteOfferInHaveLocalOffer.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
 [test_peerConnection_throwInCallbacks.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_toJSON.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
 
 [test_peerConnection_twoAudioStreams.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
 [test_peerConnection_twoAudioTracksInOneStream.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
 [test_peerConnection_twoAudioVideoStreams.html]
-skip-if = (toolkit == 'gonk' || buildapp == 'mulet') # b2g (Bug 1059867)
+skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_twoAudioVideoStreamsCombined.html]
-skip-if = (toolkit == 'gonk' || buildapp == 'mulet') # b2g (Bug 1059867)
+skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_twoVideoStreams.html]
-skip-if = (toolkit == 'gonk' || buildapp == 'mulet') # b2g (Bug 1059867)
+skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_twoVideoTracksInOneStream.html]
-skip-if = (toolkit == 'gonk' || buildapp == 'mulet') # b2g (Bug 1059867)
+skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_addSecondAudioStream.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
+skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
 [test_peerConnection_answererAddSecondAudioStream.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
+skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
 [test_peerConnection_removeAudioTrack.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
+skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
 [test_peerConnection_removeThenAddAudioTrack.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
+skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
 [test_peerConnection_addSecondVideoStream.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
+skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
 [test_peerConnection_removeVideoTrack.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
+skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
 [test_peerConnection_removeThenAddVideoTrack.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
+skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
 [test_peerConnection_replaceVideoThenRenegotiate.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
+skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
 [test_peerConnection_addSecondAudioStreamNoBundle.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
+skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
 [test_peerConnection_removeThenAddAudioTrackNoBundle.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
+skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
 [test_peerConnection_addSecondVideoStreamNoBundle.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
+skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
 [test_peerConnection_removeThenAddVideoTrackNoBundle.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
+skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
 [test_peerConnection_addDataChannel.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
+skip-if = toolkit == 'gonk' # B2G emulator seems to be so slow that DTLS cannot establish properly
 [test_peerConnection_addDataChannelNoBundle.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
+skip-if = toolkit == 'gonk' # B2G emulator seems to be so slow that DTLS cannot establish properly
 [test_peerConnection_webAudio.html]
 tags = webaudio webrtc
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
 [test_peerConnection_localRollback.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
 [test_peerConnection_localReofferRollback.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
 [test_peerConnection_remoteRollback.html]
--- a/dom/media/tests/mochitest/pc.js
+++ b/dom/media/tests/mochitest/pc.js
@@ -610,17 +610,17 @@ function DataChannelWrapper(dataChannel,
   createOneShotEventWrapper(this, this._channel, 'message');
 
   this.opened = timerGuard(new Promise(resolve => {
     this._channel.onopen = () => {
       this._channel.onopen = unexpectedEvent(this, 'onopen');
       is(this.readyState, "open", "data channel is 'open' after 'onopen'");
       resolve(this);
     };
-  }), 60000, "channel didn't open in time");
+  }), 180000, "channel didn't open in time");
 }
 
 DataChannelWrapper.prototype = {
   /**
    * Returns the binary type of the channel
    *
    * @returns {String} The binary type
    */
--- a/dom/webidl/CanvasRenderingContext2D.webidl
+++ b/dom/webidl/CanvasRenderingContext2D.webidl
@@ -219,16 +219,28 @@ interface CanvasRenderingContext2D {
    */
   [Throws, ChromeOnly]
   void drawWindow(Window window, double x, double y, double w, double h,
                   DOMString bgColor, optional unsigned long flags = 0);
   [Throws, ChromeOnly]
   void asyncDrawXULElement(XULElement elem, double x, double y, double w,
                            double h, DOMString bgColor,
                            optional unsigned long flags = 0);
+
+  /**
+   * Render the root widget of a window into the canvas. Unlike drawWindow,
+   * this uses the operating system to snapshot the widget on-screen, rather
+   * than reading from our own compositor.
+   *
+   * Currently, this is only supported on Windows, and only on widgets that
+   * use OMTC, and only from within the chrome process.
+   */
+  [Throws, ChromeOnly]
+  void drawWidgetAsOnScreen(Window window);
+
   /**
    * This causes a context that is currently using a hardware-accelerated
    * backend to fallback to a software one. All state should be preserved.
    */
   [ChromeOnly]
   void demote();
 };
 CanvasRenderingContext2D implements CanvasDrawingStyles;
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -2560,20 +2560,19 @@ GLContext::Readback(SharedSurface* src, 
         src->LockProd();
     }
 
     GLuint tempFB = 0;
 
     {
         ScopedBindFramebuffer autoFB(this);
 
-        // Even though we're reading. We're doing it on
-        // the producer side. So we call ProducerAcquire
-        // instead of ConsumerAcquire.
-        src->ProducerAcquire();
+        // We're consuming from the producer side, so which do we use?
+        // Really, we just want a read-only lock, so ConsumerAcquire is the best match.
+        src->ProducerReadAcquire();
 
         if (src->mAttachType == AttachmentType::Screen) {
             fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
         } else {
             fGenFramebuffers(1, &tempFB);
             fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, tempFB);
 
             switch (src->mAttachType) {
@@ -2590,17 +2589,17 @@ GLContext::Readback(SharedSurface* src, 
             }
 
             DebugOnly<GLenum> status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
             MOZ_ASSERT(status == LOCAL_GL_FRAMEBUFFER_COMPLETE);
         }
 
         ReadPixelsIntoDataSurface(this, dest);
 
-        src->ProducerRelease();
+        src->ProducerReadRelease();
     }
 
     if (tempFB)
         fDeleteFramebuffers(1, &tempFB);
 
     if (needsSwap) {
         src->UnlockProd();
         if (prev)
--- a/gfx/gl/GLScreenBuffer.cpp
+++ b/gfx/gl/GLScreenBuffer.cpp
@@ -16,16 +16,17 @@
 #include "nsXULAppAPI.h"
 #endif
 #ifdef XP_MACOSX
 #include "SharedSurfaceIO.h"
 #endif
 #include "ScopedGLHelpers.h"
 #include "gfx2DGlue.h"
 #include "../layers/ipc/ShadowLayers.h"
+#include "mozilla/layers/TextureClientSharedSurface.h"
 
 namespace mozilla {
 namespace gl {
 
 using gfx::SurfaceFormat;
 
 UniquePtr<GLScreenBuffer>
 GLScreenBuffer::Create(GLContext* gl,
@@ -34,65 +35,53 @@ GLScreenBuffer::Create(GLContext* gl,
 {
     UniquePtr<GLScreenBuffer> ret;
     if (caps.antialias &&
         !gl->IsSupported(GLFeature::framebuffer_multisample))
     {
         return Move(ret);
     }
 
-    UniquePtr<SurfaceFactory> factory;
-
-#ifdef MOZ_WIDGET_GONK
-    /* On B2G, we want a Gralloc factory, and we want one right at the start */
-    layers::ISurfaceAllocator* allocator = caps.surfaceAllocator;
-    if (!factory &&
-        allocator &&
-        XRE_GetProcessType() != GeckoProcessType_Default)
-    {
-        layers::TextureFlags flags = layers::TextureFlags::DEALLOCATE_CLIENT |
-                                     layers::TextureFlags::ORIGIN_BOTTOM_LEFT;
-        if (!caps.premultAlpha) {
-            flags |= layers::TextureFlags::NON_PREMULTIPLIED;
-        }
 
-        factory = MakeUnique<SurfaceFactory_Gralloc>(gl, caps, flags,
-                                                     allocator);
+    layers::TextureFlags flags = layers::TextureFlags::ORIGIN_BOTTOM_LEFT;
+    if (!caps.premultAlpha) {
+        flags |= layers::TextureFlags::NON_PREMULTIPLIED;
     }
-#endif
-#ifdef XP_MACOSX
-    /* On OSX, we want an IOSurface factory, and we want one right at the start */
-    if (!factory) {
-        factory = SurfaceFactory_IOSurface::Create(gl, caps);
-    }
-#endif
 
-    if (!factory) {
-        factory = MakeUnique<SurfaceFactory_Basic>(gl, caps);
-    }
+    UniquePtr<SurfaceFactory> factory = MakeUnique<SurfaceFactory_Basic>(gl, caps, flags);
 
     ret.reset( new GLScreenBuffer(gl, caps, Move(factory)) );
     return Move(ret);
 }
 
+GLScreenBuffer::GLScreenBuffer(GLContext* gl,
+                               const SurfaceCaps& caps,
+                               UniquePtr<SurfaceFactory> factory)
+    : mGL(gl)
+    , mCaps(caps)
+    , mFactory(Move(factory))
+    , mNeedsBlit(true)
+    , mUserReadBufferMode(LOCAL_GL_BACK)
+    , mUserDrawFB(0)
+    , mUserReadFB(0)
+    , mInternalDrawFB(0)
+    , mInternalReadFB(0)
+#ifdef DEBUG
+    , mInInternalMode_DrawFB(true)
+    , mInInternalMode_ReadFB(true)
+#endif
+{ }
+
 GLScreenBuffer::~GLScreenBuffer()
 {
+    mFactory = nullptr;
     mDraw = nullptr;
     mRead = nullptr;
-
-    // bug 914823: it is crucial to destroy the Factory _after_ we destroy
-    // the SharedSurfaces around here! Reason: the shared surfaces will want
-    // to ask the Allocator (e.g. the ClientLayerManager) to destroy their
-    // buffers, but that Allocator may be kept alive by the Factory,
-    // as it currently the case in SurfaceFactory_Gralloc holding a nsRefPtr
-    // to the Allocator!
-    mFactory = nullptr;
 }
 
-
 void
 GLScreenBuffer::BindAsFramebuffer(GLContext* const gl, GLenum target) const
 {
     GLuint drawFB = DrawFB();
     GLuint readFB = ReadFB();
 
     if (!gl->IsSupported(GLFeature::framebuffer_blit)) {
         MOZ_ASSERT(drawFB == readFB);
@@ -460,17 +449,17 @@ GLScreenBuffer::Attach(SharedSurface* su
     RequireBlit();
 
     return true;
 }
 
 bool
 GLScreenBuffer::Swap(const gfx::IntSize& size)
 {
-    RefPtr<ShSurfHandle> newBack = mFactory->NewShSurfHandle(size);
+    RefPtr<SharedSurfaceTextureClient> newBack = mFactory->NewTexClient(size);
     if (!newBack)
         return false;
 
     if (!Attach(newBack->Surf(), size))
         return false;
     // Attach was successful.
 
     mFront = mBack;
@@ -517,17 +506,17 @@ GLScreenBuffer::PublishFrame(const gfx::
 
     bool good = Swap(size);
     return good;
 }
 
 bool
 GLScreenBuffer::Resize(const gfx::IntSize& size)
 {
-    RefPtr<ShSurfHandle> newBack = mFactory->NewShSurfHandle(size);
+    RefPtr<SharedSurfaceTextureClient> newBack = mFactory->NewTexClient(size);
     if (!newBack)
         return false;
 
     if (!Attach(newBack->Surf(), size))
         return false;
 
     if (mBack)
         mBack->Surf()->ProducerRelease();
--- a/gfx/gl/GLScreenBuffer.h
+++ b/gfx/gl/GLScreenBuffer.h
@@ -19,16 +19,20 @@
 #include "GLDefs.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Point.h"
 #include "mozilla/UniquePtr.h"
 #include "SharedSurface.h"
 #include "SurfaceTypes.h"
 
 namespace mozilla {
+namespace layers {
+class SharedSurfaceTextureClient;
+}
+
 namespace gl {
 
 class GLContext;
 class SharedSurface;
 class ShSurfHandle;
 class SurfaceFactory;
 
 class DrawBuffer
@@ -131,18 +135,18 @@ public:
 
 protected:
     GLContext* const mGL; // Owns us.
 public:
     const SurfaceCaps mCaps;
 protected:
     UniquePtr<SurfaceFactory> mFactory;
 
-    RefPtr<ShSurfHandle> mBack;
-    RefPtr<ShSurfHandle> mFront;
+    RefPtr<layers::SharedSurfaceTextureClient> mBack;
+    RefPtr<layers::SharedSurfaceTextureClient> mFront;
 
     UniquePtr<DrawBuffer> mDraw;
     UniquePtr<ReadBuffer> mRead;
 
     bool mNeedsBlit;
 
     GLenum mUserReadBufferMode;
 
@@ -154,40 +158,26 @@ protected:
 
 #ifdef DEBUG
     bool mInInternalMode_DrawFB;
     bool mInInternalMode_ReadFB;
 #endif
 
     GLScreenBuffer(GLContext* gl,
                    const SurfaceCaps& caps,
-                   UniquePtr<SurfaceFactory> factory)
-        : mGL(gl)
-        , mCaps(caps)
-        , mFactory(Move(factory))
-        , mNeedsBlit(true)
-        , mUserReadBufferMode(LOCAL_GL_BACK)
-        , mUserDrawFB(0)
-        , mUserReadFB(0)
-        , mInternalDrawFB(0)
-        , mInternalReadFB(0)
-#ifdef DEBUG
-        , mInInternalMode_DrawFB(true)
-        , mInInternalMode_ReadFB(true)
-#endif
-    {}
+                   UniquePtr<SurfaceFactory> factory);
 
 public:
     virtual ~GLScreenBuffer();
 
     SurfaceFactory* Factory() const {
         return mFactory.get();
     }
 
-    ShSurfHandle* Front() const {
+    const RefPtr<layers::SharedSurfaceTextureClient>& Front() const {
         return mFront;
     }
 
     SharedSurface* SharedSurf() const {
         MOZ_ASSERT(mRead);
         return mRead->SharedSurf();
     }
 
--- a/gfx/gl/SharedSurface.cpp
+++ b/gfx/gl/SharedSurface.cpp
@@ -7,16 +7,19 @@
 
 #include "../2d/2D.h"
 #include "GLBlitHelper.h"
 #include "GLContext.h"
 #include "GLReadTexImageHelper.h"
 #include "nsThreadUtils.h"
 #include "ScopedGLHelpers.h"
 #include "SharedSurfaceGL.h"
+#include "mozilla/layers/CompositorTypes.h"
+#include "mozilla/layers/TextureClientSharedSurface.h"
+#include "mozilla/unused.h"
 
 namespace mozilla {
 namespace gl {
 
 /*static*/ void
 SharedSurface::ProdCopy(SharedSurface* src, SharedSurface* dest,
                         SurfaceFactory* factory)
 {
@@ -27,22 +30,19 @@ SharedSurface::ProdCopy(SharedSurface* s
     MOZ_ASSERT((src == gl->GetLockedSurface()) == src->IsLocked());
 
     gl->MakeCurrent();
 
     if (src->mAttachType  == AttachmentType::Screen &&
         dest->mAttachType == AttachmentType::Screen)
     {
         // Here, we actually need to blit through a temp surface, so let's make one.
-        UniquePtr<SharedSurface_GLTexture> tempSurf;
-        tempSurf = SharedSurface_GLTexture::Create(gl,
-                                                   gl,
-                                                   factory->mFormats,
-                                                   src->mSize,
-                                                   factory->mCaps.alpha);
+        UniquePtr<SharedSurface_Basic> tempSurf;
+        tempSurf = SharedSurface_Basic::Create(gl, factory->mFormats, src->mSize,
+                                               factory->mCaps.alpha);
 
         ProdCopy(src, tempSurf.get(), factory);
         ProdCopy(tempSurf.get(), dest, factory);
         return;
     }
 
     if (src->mAttachType == AttachmentType::Screen) {
         SharedSurface* origLocked = gl->GetLockedSurface();
@@ -198,30 +198,31 @@ SharedSurface::ProdCopy(SharedSurface* s
 ////////////////////////////////////////////////////////////////////////
 // SharedSurface
 
 
 SharedSurface::SharedSurface(SharedSurfaceType type,
                              AttachmentType attachType,
                              GLContext* gl,
                              const gfx::IntSize& size,
-                             bool hasAlpha)
+                             bool hasAlpha,
+                             bool canRecycle)
     : mType(type)
     , mAttachType(attachType)
     , mGL(gl)
     , mSize(size)
     , mHasAlpha(hasAlpha)
+    , mCanRecycle(canRecycle)
     , mIsLocked(false)
     , mIsProducerAcquired(false)
     , mIsConsumerAcquired(false)
 #ifdef DEBUG
     , mOwningThread(NS_GetCurrentThread())
 #endif
-{
-}
+{ }
 
 void
 SharedSurface::LockProd()
 {
     MOZ_ASSERT(!mIsLocked);
 
     LockProdImpl();
 
@@ -257,18 +258,16 @@ SharedSurface::WaitSync_ContentThread()
 
 bool
 SharedSurface::PollSync_ContentThread()
 {
     MOZ_ASSERT(NS_GetCurrentThread() == mOwningThread);
     return PollSync_ContentThread_Impl();
 }
 
-
-
 ////////////////////////////////////////////////////////////////////////
 // SurfaceFactory
 
 static void
 ChooseBufferBits(const SurfaceCaps& caps,
                  SurfaceCaps* const out_drawCaps,
                  SurfaceCaps* const out_readCaps)
 {
@@ -296,74 +295,121 @@ ChooseBufferBits(const SurfaceCaps& caps
         out_readCaps->alpha = caps.alpha;
         out_readCaps->bpp16 = caps.bpp16;
     } else {
         out_drawCaps->Clear();
         *out_readCaps = screenCaps;
     }
 }
 
-SurfaceFactory::SurfaceFactory(GLContext* gl,
-                               SharedSurfaceType type,
-                               const SurfaceCaps& caps)
-    : mGL(gl)
+SurfaceFactory::SurfaceFactory(SharedSurfaceType type, GLContext* gl,
+                               const SurfaceCaps& caps,
+                               const RefPtr<layers::ISurfaceAllocator>& allocator,
+                               const layers::TextureFlags& flags)
+    : mType(type)
+    , mGL(gl)
     , mCaps(caps)
-    , mType(type)
+    , mAllocator(allocator)
+    , mFlags(flags)
     , mFormats(gl->ChooseGLFormats(caps))
 {
     ChooseBufferBits(mCaps, &mDrawCaps, &mReadCaps);
 }
 
 SurfaceFactory::~SurfaceFactory()
 {
-    while (!mScraps.Empty()) {
-        mScraps.Pop();
+    while (!mRecycleTotalPool.empty()) {
+        StopRecycling(*mRecycleTotalPool.begin());
     }
+
+    MOZ_RELEASE_ASSERT(mRecycleTotalPool.empty());
+
+    // If we mRecycleFreePool.clear() before StopRecycling(), we may try to recycle it,
+    // fail, call StopRecycling(), then return here and call it again.
+    mRecycleFreePool.clear();
 }
 
-UniquePtr<SharedSurface>
-SurfaceFactory::NewSharedSurface(const gfx::IntSize& size)
+TemporaryRef<layers::SharedSurfaceTextureClient>
+SurfaceFactory::NewTexClient(const gfx::IntSize& size)
 {
-    // Attempt to reuse an old surface.
-    while (!mScraps.Empty()) {
-        UniquePtr<SharedSurface> cur = mScraps.Pop();
+    while (!mRecycleFreePool.empty()) {
+        RefPtr<layers::SharedSurfaceTextureClient> cur = mRecycleFreePool.front();
+        mRecycleFreePool.pop();
 
-        if (cur->mSize == size)
-            return Move(cur);
+        if (cur->Surf()->mSize == size) {
+            return cur.forget();
+        }
 
-        // Let `cur` be destroyed as it falls out of scope, if it wasn't
-        // moved.
+        StopRecycling(cur);
     }
 
-    return CreateShared(size);
-}
-
-TemporaryRef<ShSurfHandle>
-SurfaceFactory::NewShSurfHandle(const gfx::IntSize& size)
-{
-    auto surf = NewSharedSurface(size);
+    UniquePtr<SharedSurface> surf = Move(CreateShared(size));
     if (!surf)
         return nullptr;
 
-    // Before next use, wait until SharedSurface's buffer
-    // is no longer being used.
-    surf->WaitForBufferOwnership();
+    RefPtr<layers::SharedSurfaceTextureClient> ret;
+    ret = new layers::SharedSurfaceTextureClient(mAllocator, mFlags, Move(surf), this);
+
+    StartRecycling(ret);
+
+    return ret.forget();
+}
+
+void
+SurfaceFactory::StartRecycling(layers::SharedSurfaceTextureClient* tc)
+{
+    tc->SetRecycleCallback(&SurfaceFactory::RecycleCallback, static_cast<void*>(this));
 
-    return MakeAndAddRef<ShSurfHandle>(this, Move(surf));
+    bool didInsert = mRecycleTotalPool.insert(tc);
+    MOZ_RELEASE_ASSERT(didInsert);
+    mozilla::unused << didInsert;
+}
+
+void
+SurfaceFactory::StopRecycling(layers::SharedSurfaceTextureClient* tc)
+{
+    // Must clear before releasing ref.
+    tc->ClearRecycleCallback();
+
+    bool didErase = mRecycleTotalPool.erase(tc);
+    MOZ_RELEASE_ASSERT(didErase);
+    mozilla::unused << didErase;
 }
 
-// Auto-deletes surfs of the wrong type.
-void
-SurfaceFactory::Recycle(UniquePtr<SharedSurface> surf)
+/*static*/ void
+SurfaceFactory::RecycleCallback(layers::TextureClient* rawTC, void* rawFactory)
 {
-    MOZ_ASSERT(surf);
+    MOZ_ASSERT(NS_IsMainThread());
+
+    RefPtr<layers::SharedSurfaceTextureClient> tc;
+    tc = static_cast<layers::SharedSurfaceTextureClient*>(rawTC);
+
+    SurfaceFactory* factory = static_cast<SurfaceFactory*>(rawFactory);
+
+    if (tc->mSurf->mCanRecycle) {
+        if (factory->Recycle(tc))
+            return;
+    }
 
-    if (surf->mType == mType) {
-        mScraps.Push(Move(surf));
+    // Did not recover the tex client. End the (re)cycle!
+    factory->StopRecycling(tc);
+}
+
+bool
+SurfaceFactory::Recycle(layers::SharedSurfaceTextureClient* texClient)
+{
+    MOZ_ASSERT(texClient);
+
+    if (mRecycleFreePool.size() >= 2) {
+        return false;
     }
+
+    RefPtr<layers::SharedSurfaceTextureClient> texClientRef = texClient;
+    mRecycleFreePool.push(texClientRef);
+    return true;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // ScopedReadbackFB
 
 ScopedReadbackFB::ScopedReadbackFB(SharedSurface* src)
     : mGL(src->mGL)
     , mAutoFB(mGL)
--- a/gfx/gl/SharedSurface.h
+++ b/gfx/gl/SharedSurface.h
@@ -11,16 +11,17 @@
  *     SharedSurface_EGLImage
  *     SharedSurface_ANGLEShareHandle
  */
 
 #ifndef SHARED_SURFACE_H_
 #define SHARED_SURFACE_H_
 
 #include <queue>
+#include <set>
 #include <stdint.h>
 
 #include "GLContextTypes.h"
 #include "GLDefs.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/gfx/Point.h"
 #include "mozilla/UniquePtr.h"
@@ -29,16 +30,25 @@
 #include "SurfaceTypes.h"
 
 class nsIThread;
 
 namespace mozilla {
 namespace gfx {
 class DrawTarget;
 }
+
+namespace layers {
+class ISurfaceAllocator;
+class SharedSurfaceTextureClient;
+enum class TextureFlags : uint32_t;
+class SurfaceDescriptor;
+class TextureClient;
+}
+
 namespace gl {
 
 class GLContext;
 class SurfaceFactory;
 class ShSurfHandle;
 
 class SharedSurface
 {
@@ -46,27 +56,29 @@ public:
     static void ProdCopy(SharedSurface* src, SharedSurface* dest,
                          SurfaceFactory* factory);
 
     const SharedSurfaceType mType;
     const AttachmentType mAttachType;
     GLContext* const mGL;
     const gfx::IntSize mSize;
     const bool mHasAlpha;
+    const bool mCanRecycle;
 protected:
     bool mIsLocked;
     bool mIsProducerAcquired;
     bool mIsConsumerAcquired;
     DebugOnly<nsIThread* const> mOwningThread;
 
     SharedSurface(SharedSurfaceType type,
                   AttachmentType attachType,
                   GLContext* gl,
                   const gfx::IntSize& size,
-                  bool hasAlpha);
+                  bool hasAlpha,
+                  bool canRecycle);
 
 public:
     virtual ~SharedSurface() {
     }
 
     bool IsLocked() const {
         return mIsLocked;
     }
@@ -81,32 +93,44 @@ public:
 protected:
     virtual void LockProdImpl() = 0;
     virtual void UnlockProdImpl() = 0;
 
     virtual void ProducerAcquireImpl() {}
     virtual void ProducerReleaseImpl() {
         Fence();
     }
+    virtual void ProducerReadAcquireImpl() {}
+    virtual void ProducerReadReleaseImpl() {}
     virtual void ConsumerAcquireImpl() {
         WaitSync();
     }
     virtual void ConsumerReleaseImpl() {}
 
 public:
     void ProducerAcquire() {
         MOZ_ASSERT(!mIsProducerAcquired);
         ProducerAcquireImpl();
         mIsProducerAcquired = true;
     }
     void ProducerRelease() {
         MOZ_ASSERT(mIsProducerAcquired);
         ProducerReleaseImpl();
         mIsProducerAcquired = false;
     }
+    void ProducerReadAcquire() {
+        MOZ_ASSERT(!mIsProducerAcquired);
+        ProducerReadAcquireImpl();
+        mIsProducerAcquired = true;
+    }
+    void ProducerReadRelease() {
+        MOZ_ASSERT(mIsProducerAcquired);
+        ProducerReadReleaseImpl();
+        mIsProducerAcquired = false;
+    }
     void ConsumerAcquire() {
         MOZ_ASSERT(!mIsConsumerAcquired);
         ConsumerAcquireImpl();
         mIsConsumerAcquired = true;
     }
     void ConsumerRelease() {
         MOZ_ASSERT(mIsConsumerAcquired);
         ConsumerReleaseImpl();
@@ -168,121 +192,154 @@ public:
                             GLvoid* pixels)
     {
         return false;
     }
 
     virtual bool NeedsIndirectReads() const {
         return false;
     }
+
+    virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) = 0;
 };
 
 template<typename T>
-class UniquePtrQueue
+class RefSet
+{
+    std::set<T*> mSet;
+
+public:
+    ~RefSet() {
+        clear();
+    }
+
+    auto begin() -> decltype(mSet.begin()) {
+        return mSet.begin();
+    }
+
+    void clear() {
+        for (auto itr = mSet.begin(); itr != mSet.end(); ++itr) {
+            (*itr)->Release();
+        }
+        mSet.clear();
+    }
+
+    bool empty() const {
+        return mSet.empty();
+    }
+
+    bool insert(T* x) {
+        if (mSet.insert(x).second) {
+            x->AddRef();
+            return true;
+        }
+
+        return false;
+    }
+
+    bool erase(T* x) {
+        if (mSet.erase(x)) {
+            x->Release();
+            return true;
+        }
+
+        return false;
+    }
+};
+
+template<typename T>
+class RefQueue
 {
     std::queue<T*> mQueue;
 
 public:
-    ~UniquePtrQueue() {
-        MOZ_ASSERT(Empty());
+    ~RefQueue() {
+        clear();
     }
 
-    bool Empty() const {
+    void clear() {
+        while (!empty()) {
+            pop();
+        }
+    }
+
+    bool empty() const {
         return mQueue.empty();
     }
 
-    void Push(UniquePtr<T> up) {
-        T* p = up.release();
-        mQueue.push(p);
+    size_t size() const {
+        return mQueue.size();
+    }
+
+    void push(T* x) {
+        mQueue.push(x);
+        x->AddRef();
     }
 
-    UniquePtr<T> Pop() {
-        UniquePtr<T> ret;
+    T* front() const {
+        return mQueue.front();
+    }
 
-        if (!mQueue.empty()) {
-            ret.reset(mQueue.front());
-            mQueue.pop();
-        }
-
-        return Move(ret);
+    void pop() {
+        T* x = mQueue.front();
+        x->Release();
+        mQueue.pop();
     }
 };
 
 class SurfaceFactory : public SupportsWeakPtr<SurfaceFactory>
 {
 public:
     // Should use the VIRTUAL version, but it's currently incompatible
     // with SupportsWeakPtr. (bug 1049278)
     MOZ_DECLARE_WEAKREFERENCE_TYPENAME(SurfaceFactory)
 
+    const SharedSurfaceType mType;
     GLContext* const mGL;
     const SurfaceCaps mCaps;
-    const SharedSurfaceType mType;
+    const RefPtr<layers::ISurfaceAllocator> mAllocator;
+    const layers::TextureFlags mFlags;
     const GLFormats mFormats;
-
 protected:
     SurfaceCaps mDrawCaps;
     SurfaceCaps mReadCaps;
+    RefQueue<layers::SharedSurfaceTextureClient> mRecycleFreePool;
+    RefSet<layers::SharedSurfaceTextureClient> mRecycleTotalPool;
 
-    SurfaceFactory(GLContext* gl,
-                   SharedSurfaceType type,
-                   const SurfaceCaps& caps);
+    SurfaceFactory(SharedSurfaceType type, GLContext* gl, const SurfaceCaps& caps,
+                   const RefPtr<layers::ISurfaceAllocator>& allocator,
+                   const layers::TextureFlags& flags);
 
 public:
     virtual ~SurfaceFactory();
 
     const SurfaceCaps& DrawCaps() const {
         return mDrawCaps;
     }
 
     const SurfaceCaps& ReadCaps() const {
         return mReadCaps;
     }
 
 protected:
     virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) = 0;
 
-    UniquePtrQueue<SharedSurface> mScraps;
+    void StartRecycling(layers::SharedSurfaceTextureClient* tc);
+    void SetRecycleCallback(layers::SharedSurfaceTextureClient* tc);
+    void StopRecycling(layers::SharedSurfaceTextureClient* tc);
 
 public:
     UniquePtr<SharedSurface> NewSharedSurface(const gfx::IntSize& size);
-    TemporaryRef<ShSurfHandle> NewShSurfHandle(const gfx::IntSize& size);
+    //TemporaryRef<ShSurfHandle> NewShSurfHandle(const gfx::IntSize& size);
+    TemporaryRef<layers::SharedSurfaceTextureClient> NewTexClient(const gfx::IntSize& size);
+
+    static void RecycleCallback(layers::TextureClient* tc, void* /*closure*/);
 
     // Auto-deletes surfs of the wrong type.
-    void Recycle(UniquePtr<SharedSurface> surf);
-};
-
-class ShSurfHandle : public RefCounted<ShSurfHandle>
-{
-public:
-    MOZ_DECLARE_REFCOUNTED_TYPENAME(ShSurfHandle)
-
-private:
-    const WeakPtr<SurfaceFactory> mFactory;
-    UniquePtr<SharedSurface> mSurf;
-
-public:
-    ShSurfHandle(SurfaceFactory* factory, UniquePtr<SharedSurface> surf)
-        : mFactory(factory)
-        , mSurf(Move(surf))
-    {
-        MOZ_ASSERT(mFactory);
-        MOZ_ASSERT(mSurf);
-    }
-
-    ~ShSurfHandle() {
-        if (mFactory) {
-            mFactory->Recycle(Move(mSurf));
-        }
-    }
-
-    SharedSurface* Surf() const {
-        MOZ_ASSERT(mSurf.get());
-        return mSurf.get();
-    }
+    bool Recycle(layers::SharedSurfaceTextureClient* texClient);
 };
 
 class ScopedReadbackFB
 {
     GLContext* const mGL;
     ScopedBindFramebuffer mAutoFB;
     GLuint mTempFB;
     GLuint mTempTex;
--- a/gfx/gl/SharedSurfaceANGLE.cpp
+++ b/gfx/gl/SharedSurfaceANGLE.cpp
@@ -1,19 +1,20 @@
 /* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
 /* 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 "SharedSurfaceANGLE.h"
-#include "GLContextEGL.h"
-#include "GLLibraryEGL.h"
 
 #include <d3d11.h>
 #include "gfxWindowsPlatform.h"
+#include "GLContextEGL.h"
+#include "GLLibraryEGL.h"
+#include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor, etc
 
 namespace mozilla {
 namespace gl {
 
 // Returns `EGL_NO_SURFACE` (`0`) on error.
 static EGLSurface
 CreatePBufferSurface(GLLibraryEGL* egl,
                      EGLDisplay display,
@@ -100,17 +101,18 @@ SharedSurface_ANGLEShareHandle::SharedSu
                                                                EGLSurface pbuffer,
                                                                HANDLE shareHandle,
                                                                const RefPtr<IDXGIKeyedMutex>& keyedMutex,
                                                                GLuint fence)
     : SharedSurface(SharedSurfaceType::EGLSurfaceANGLE,
                     AttachmentType::Screen,
                     gl,
                     size,
-                    hasAlpha)
+                    hasAlpha,
+                    true)
     , mEGL(egl)
     , mContext(context)
     , mPBuffer(pbuffer)
     , mShareHandle(shareHandle)
     , mKeyedMutex(keyedMutex)
     , mFence(fence)
 {
 }
@@ -178,16 +180,31 @@ SharedSurface_ANGLEShareHandle::Producer
         // For now, we'll just do it
         mKeyedMutex->ReleaseSync(0);
         return;
     }
     Fence();
 }
 
 void
+SharedSurface_ANGLEShareHandle::ProducerReadAcquireImpl()
+{
+    ProducerAcquireImpl();
+}
+
+void
+SharedSurface_ANGLEShareHandle::ProducerReadReleaseImpl()
+{
+    if (mKeyedMutex) {
+        mKeyedMutex->ReleaseSync(0);
+        return;
+    }
+}
+
+void
 SharedSurface_ANGLEShareHandle::ConsumerAcquireImpl()
 {
     if (!mConsumerTexture) {
         RefPtr<ID3D11Texture2D> tex;
         HRESULT hr = gfxWindowsPlatform::GetPlatform()->GetD3D11Device()->OpenSharedResource(mShareHandle,
                                                                                              __uuidof(ID3D11Texture2D),
                                                                                              (void**)(ID3D11Texture2D**)byRef(tex));
         if (SUCCEEDED(hr)) {
@@ -248,16 +265,26 @@ SharedSurface_ANGLEShareHandle::PollSync
     if (mFence) {
         mGL->MakeCurrent();
         return mGL->fTestFence(mFence);
     }
 
     return PollSync();
 }
 
+bool
+SharedSurface_ANGLEShareHandle::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor)
+{
+    gfx::SurfaceFormat format = mHasAlpha ? gfx::SurfaceFormat::B8G8R8A8
+                                          : gfx::SurfaceFormat::B8G8R8X8;
+    *out_descriptor = layers::SurfaceDescriptorD3D10((WindowsHandle)mShareHandle, format,
+                                                     mSize);
+    return true;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Factory
 
 static void
 FillPBufferAttribs_ByBits(nsTArray<EGLint>& aAttrs,
                           int redBits, int greenBits,
                           int blueBits, int alphaBits,
                           int depthBits, int stencilBits)
@@ -383,42 +410,45 @@ ChooseConfig(GLContext* gl, GLLibraryEGL
     if (gl->DebugMode()) {
         egl->DumpEGLConfig(config);
     }
 
     return config;
 }
 
 /*static*/ UniquePtr<SurfaceFactory_ANGLEShareHandle>
-SurfaceFactory_ANGLEShareHandle::Create(GLContext* gl,
-                                        const SurfaceCaps& caps)
+SurfaceFactory_ANGLEShareHandle::Create(GLContext* gl, const SurfaceCaps& caps,
+                                        const RefPtr<layers::ISurfaceAllocator>& allocator,
+                                        const layers::TextureFlags& flags)
 {
     GLLibraryEGL* egl = &sEGLLibrary;
     if (!egl)
         return nullptr;
 
     auto ext = GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle;
     if (!egl->IsExtensionSupported(ext))
         return nullptr;
 
     bool success;
     typedef SurfaceFactory_ANGLEShareHandle ptrT;
-    UniquePtr<ptrT> ret( new ptrT(gl, egl, caps, &success) );
+    UniquePtr<ptrT> ret( new ptrT(gl, caps, allocator, flags, egl, &success) );
 
     if (!success)
         return nullptr;
 
     return Move(ret);
 }
 
 SurfaceFactory_ANGLEShareHandle::SurfaceFactory_ANGLEShareHandle(GLContext* gl,
+                                                                 const SurfaceCaps& caps,
+                                                                 const RefPtr<layers::ISurfaceAllocator>& allocator,
+                                                                 const layers::TextureFlags& flags,
                                                                  GLLibraryEGL* egl,
-                                                                 const SurfaceCaps& caps,
                                                                  bool* const out_success)
-    : SurfaceFactory(gl, SharedSurfaceType::EGLSurfaceANGLE, caps)
+    : SurfaceFactory(SharedSurfaceType::EGLSurfaceANGLE, gl, caps, allocator, flags)
     , mProdGL(gl)
     , mEGL(egl)
 {
     MOZ_ASSERT(out_success);
     *out_success = false;
 
     mContext = GLContextEGL::Cast(mProdGL)->GetEGLContext();
     mConfig = ChooseConfig(mProdGL, mEGL, mReadCaps);
--- a/gfx/gl/SharedSurfaceANGLE.h
+++ b/gfx/gl/SharedSurfaceANGLE.h
@@ -33,17 +33,19 @@ public:
 
         return (SharedSurface_ANGLEShareHandle*)surf;
     }
 
 protected:
     GLLibraryEGL* const mEGL;
     const EGLContext mContext;
     const EGLSurface mPBuffer;
+public:
     const HANDLE mShareHandle;
+protected:
     RefPtr<IDXGIKeyedMutex> mKeyedMutex;
     RefPtr<IDXGIKeyedMutex> mConsumerKeyedMutex;
     RefPtr<ID3D11Texture2D> mConsumerTexture;
 
     const GLuint mFence;
 
     SharedSurface_ANGLEShareHandle(GLContext* gl,
                                    GLLibraryEGL* egl,
@@ -61,54 +63,55 @@ public:
     virtual ~SharedSurface_ANGLEShareHandle();
 
     virtual void LockProdImpl() override;
     virtual void UnlockProdImpl() override;
 
     virtual void Fence() override;
     virtual void ProducerAcquireImpl() override;
     virtual void ProducerReleaseImpl() override;
+    virtual void ProducerReadAcquireImpl() override;
+    virtual void ProducerReadReleaseImpl() override;
     virtual void ConsumerAcquireImpl() override;
     virtual void ConsumerReleaseImpl() override;
     virtual bool WaitSync() override;
     virtual bool PollSync() override;
 
     virtual void Fence_ContentThread_Impl() override;
     virtual bool WaitSync_ContentThread_Impl() override;
     virtual bool PollSync_ContentThread_Impl() override;
 
-    // Implementation-specific functions below:
-    HANDLE GetShareHandle() {
-        return mShareHandle;
-    }
-
     const RefPtr<ID3D11Texture2D>& GetConsumerTexture() const {
         return mConsumerTexture;
     }
+
+    virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
 };
 
 
 
 class SurfaceFactory_ANGLEShareHandle
     : public SurfaceFactory
 {
 protected:
     GLContext* const mProdGL;
     GLLibraryEGL* const mEGL;
     EGLContext mContext;
     EGLConfig mConfig;
 
 public:
     static UniquePtr<SurfaceFactory_ANGLEShareHandle> Create(GLContext* gl,
-                                                             const SurfaceCaps& caps);
+                                                             const SurfaceCaps& caps,
+                                                             const RefPtr<layers::ISurfaceAllocator>& allocator,
+                                                             const layers::TextureFlags& flags);
 
 protected:
-    SurfaceFactory_ANGLEShareHandle(GLContext* gl,
-                                    GLLibraryEGL* egl,
-                                    const SurfaceCaps& caps,
+    SurfaceFactory_ANGLEShareHandle(GLContext* gl, const SurfaceCaps& caps,
+                                    const RefPtr<layers::ISurfaceAllocator>& allocator,
+                                    const layers::TextureFlags& flags, GLLibraryEGL* egl,
                                     bool* const out_success);
 
     virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) override {
         bool hasAlpha = mReadCaps.alpha;
         return SharedSurface_ANGLEShareHandle::Create(mProdGL,
                                                       mContext, mConfig,
                                                       size, hasAlpha);
     }
--- a/gfx/gl/SharedSurfaceEGL.cpp
+++ b/gfx/gl/SharedSurfaceEGL.cpp
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SharedSurfaceEGL.h"
 
 #include "GLBlitHelper.h"
 #include "GLContextEGL.h"
 #include "GLLibraryEGL.h"
 #include "GLReadTexImageHelper.h"
+#include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor, etc
 #include "ScopedGLHelpers.h"
 #include "SharedSurface.h"
 #include "TextureGarbageBin.h"
 
 namespace mozilla {
 namespace gl {
 
 /*static*/ UniquePtr<SharedSurface_EGLImage>
@@ -67,17 +68,18 @@ SharedSurface_EGLImage::SharedSurface_EG
                                                bool hasAlpha,
                                                const GLFormats& formats,
                                                GLuint prodTex,
                                                EGLImage image)
     : SharedSurface(SharedSurfaceType::EGLImageShare,
                     AttachmentType::GLTexture,
                     gl,
                     size,
-                    hasAlpha)
+                    hasAlpha,
+                    false) // Can't recycle, as mSync changes never update TextureHost.
     , mMutex("SharedSurface_EGLImage mutex")
     , mEGL(egl)
     , mFormats(formats)
     , mProdTex(prodTex)
     , mImage(image)
     , mCurConsGL(nullptr)
     , mConsTex(0)
     , mSync(0)
@@ -110,16 +112,17 @@ SharedSurface_EGLImage::Fence()
 {
     MutexAutoLock lock(mMutex);
     mGL->MakeCurrent();
 
     if (mEGL->IsExtensionSupported(GLLibraryEGL::KHR_fence_sync) &&
         mGL->IsExtensionSupported(GLContext::OES_EGL_sync))
     {
         if (mSync) {
+            MOZ_RELEASE_ASSERT(false, "Non-recycleable should not Fence twice.");
             MOZ_ALWAYS_TRUE( mEGL->fDestroySync(Display(), mSync) );
             mSync = 0;
         }
 
         mSync = mEGL->fCreateSync(Display(),
                                   LOCAL_EGL_SYNC_FENCE,
                                   nullptr);
         if (mSync) {
@@ -147,24 +150,17 @@ SharedSurface_EGLImage::WaitSync()
     // else than FOREVER.
     //
     // FIXME: should we try to use a finite timeout delay where possible?
     EGLint status = mEGL->fClientWaitSync(Display(),
                                           mSync,
                                           0,
                                           LOCAL_EGL_FOREVER);
 
-    if (status != LOCAL_EGL_CONDITION_SATISFIED) {
-        return false;
-    }
-
-    MOZ_ALWAYS_TRUE( mEGL->fDestroySync(Display(), mSync) );
-    mSync = 0;
-
-    return true;
+    return status == LOCAL_EGL_CONDITION_SATISFIED;
 }
 
 bool
 SharedSurface_EGLImage::PollSync()
 {
     MutexAutoLock lock(mMutex);
     if (!mSync) {
         // We must not be needed.
@@ -172,24 +168,18 @@ SharedSurface_EGLImage::PollSync()
     }
     MOZ_ASSERT(mEGL->IsExtensionSupported(GLLibraryEGL::KHR_fence_sync));
 
     EGLint status = 0;
     MOZ_ALWAYS_TRUE( mEGL->fGetSyncAttrib(mEGL->Display(),
                                          mSync,
                                          LOCAL_EGL_SYNC_STATUS_KHR,
                                          &status) );
-    if (status != LOCAL_EGL_SIGNALED_KHR) {
-        return false;
-    }
 
-    MOZ_ALWAYS_TRUE( mEGL->fDestroySync(mEGL->Display(), mSync) );
-    mSync = 0;
-
-    return true;
+    return status == LOCAL_EGL_SIGNALED_KHR;
 }
 
 EGLDisplay
 SharedSurface_EGLImage::Display() const
 {
     return mEGL->Display();
 }
 
@@ -210,28 +200,38 @@ SharedSurface_EGLImage::AcquireConsumerT
         mGarbageBin = consGL->TexGarbageBin();
     }
 
     MOZ_ASSERT(consGL == mCurConsGL);
     *out_texture = mConsTex;
     *out_target = LOCAL_GL_TEXTURE_EXTERNAL;
 }
 
+bool
+SharedSurface_EGLImage::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor)
+{
+    *out_descriptor = layers::EGLImageDescriptor((uintptr_t)mImage, (uintptr_t)mSync,
+                                                 mSize, mHasAlpha);
+    return true;
+}
+
+////////////////////////////////////////////////////////////////////////
 
 /*static*/ UniquePtr<SurfaceFactory_EGLImage>
-SurfaceFactory_EGLImage::Create(GLContext* prodGL,
-                                const SurfaceCaps& caps)
+SurfaceFactory_EGLImage::Create(GLContext* prodGL, const SurfaceCaps& caps,
+                                const RefPtr<layers::ISurfaceAllocator>& allocator,
+                                const layers::TextureFlags& flags)
 {
     EGLContext context = GLContextEGL::Cast(prodGL)->GetEGLContext();
 
     typedef SurfaceFactory_EGLImage ptrT;
     UniquePtr<ptrT> ret;
 
     GLLibraryEGL* egl = &sEGLLibrary;
     if (SharedSurface_EGLImage::HasExtensions(egl, prodGL)) {
-        ret.reset( new ptrT(prodGL, context, caps) );
+        ret.reset( new ptrT(prodGL, caps, allocator, flags, context) );
     }
 
     return Move(ret);
 }
 
 } /* namespace gfx */
 } /* namespace mozilla */
--- a/gfx/gl/SharedSurfaceEGL.h
+++ b/gfx/gl/SharedSurfaceEGL.h
@@ -72,37 +72,42 @@ public:
 
     virtual GLuint ProdTexture() override {
       return mProdTex;
     }
 
     // Implementation-specific functions below:
     // Returns texture and target
     void AcquireConsumerTexture(GLContext* consGL, GLuint* out_texture, GLuint* out_target);
+
+    virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
 };
 
 
 
 class SurfaceFactory_EGLImage
     : public SurfaceFactory
 {
 public:
     // Fallible:
     static UniquePtr<SurfaceFactory_EGLImage> Create(GLContext* prodGL,
-                                                     const SurfaceCaps& caps);
+                                                     const SurfaceCaps& caps,
+                                                     const RefPtr<layers::ISurfaceAllocator>& allocator,
+                                                     const layers::TextureFlags& flags);
 
 protected:
     const EGLContext mContext;
 
-    SurfaceFactory_EGLImage(GLContext* prodGL,
-                            EGLContext context,
-                            const SurfaceCaps& caps)
-        : SurfaceFactory(prodGL, SharedSurfaceType::EGLImageShare, caps)
+    SurfaceFactory_EGLImage(GLContext* prodGL, const SurfaceCaps& caps,
+                            const RefPtr<layers::ISurfaceAllocator>& allocator,
+                            const layers::TextureFlags& flags,
+                            EGLContext context)
+        : SurfaceFactory(SharedSurfaceType::EGLImageShare, prodGL, caps, allocator, flags)
         , mContext(context)
-    {}
+    { }
 
 public:
     virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) override {
         bool hasAlpha = mReadCaps.alpha;
         return SharedSurface_EGLImage::Create(mGL, mFormats, size, hasAlpha, mContext);
     }
 };
 
--- a/gfx/gl/SharedSurfaceGL.cpp
+++ b/gfx/gl/SharedSurfaceGL.cpp
@@ -34,50 +34,47 @@ SharedSurface_Basic::Create(GLContext* g
 
     GLenum err = localError.GetError();
     MOZ_ASSERT_IF(err != LOCAL_GL_NO_ERROR, err == LOCAL_GL_OUT_OF_MEMORY);
     if (err) {
         gl->fDeleteTextures(1, &tex);
         return Move(ret);
     }
 
-    SurfaceFormat format = SurfaceFormat::B8G8R8X8;
-    switch (formats.color_texInternalFormat) {
-    case LOCAL_GL_RGB:
-    case LOCAL_GL_RGB8:
-        if (formats.color_texType == LOCAL_GL_UNSIGNED_SHORT_5_6_5)
-            format = SurfaceFormat::R5G6B5;
-        else
-            format = SurfaceFormat::B8G8R8X8;
-        break;
-    case LOCAL_GL_RGBA:
-    case LOCAL_GL_RGBA8:
-    case LOCAL_GL_BGRA:
-    case LOCAL_GL_BGRA8_EXT:
-        format = SurfaceFormat::B8G8R8A8;
-        break;
-    default:
-        MOZ_CRASH("Unhandled Tex format.");
-    }
+    bool ownsTex = true;
+    ret.reset( new SharedSurface_Basic(gl, size, hasAlpha, tex, ownsTex) );
+    return Move(ret);
+}
+
 
-    ret.reset( new SharedSurface_Basic(gl, size, hasAlpha, format, tex) );
+/*static*/ UniquePtr<SharedSurface_Basic>
+SharedSurface_Basic::Wrap(GLContext* gl,
+                          const IntSize& size,
+                          bool hasAlpha,
+                          GLuint tex)
+{
+    bool ownsTex = false;
+    UniquePtr<SharedSurface_Basic> ret( new SharedSurface_Basic(gl, size, hasAlpha, tex,
+                                                                ownsTex) );
     return Move(ret);
 }
 
 SharedSurface_Basic::SharedSurface_Basic(GLContext* gl,
                                          const IntSize& size,
                                          bool hasAlpha,
-                                         SurfaceFormat format,
-                                         GLuint tex)
+                                         GLuint tex,
+                                         bool ownsTex)
     : SharedSurface(SharedSurfaceType::Basic,
                     AttachmentType::GLTexture,
                     gl,
                     size,
-                    hasAlpha)
+                    hasAlpha,
+                    true)
     , mTex(tex)
+    , mOwnsTex(ownsTex)
     , mFB(0)
 {
     mGL->MakeCurrent();
     mGL->fGenFramebuffers(1, &mFB);
 
     ScopedBindFramebuffer autoFB(mGL, mFB);
     mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
                               LOCAL_GL_COLOR_ATTACHMENT0,
@@ -92,155 +89,21 @@ SharedSurface_Basic::SharedSurface_Basic
 SharedSurface_Basic::~SharedSurface_Basic()
 {
     if (!mGL->MakeCurrent())
         return;
 
     if (mFB)
         mGL->fDeleteFramebuffers(1, &mFB);
 
-    mGL->fDeleteTextures(1, &mTex);
+    if (mOwnsTex)
+        mGL->fDeleteTextures(1, &mTex);
 }
 
 ////////////////////////////////////////////////////////////////////////
-// SharedSurface_GLTexture
 
-/*static*/ UniquePtr<SharedSurface_GLTexture>
-SharedSurface_GLTexture::Create(GLContext* prodGL,
-                                GLContext* consGL,
-                                const GLFormats& formats,
-                                const IntSize& size,
-                                bool hasAlpha,
-                                GLuint texture)
-{
-    MOZ_ASSERT(prodGL);
-    MOZ_ASSERT(!consGL || prodGL->SharesWith(consGL));
-
-    prodGL->MakeCurrent();
-
-    GLuint tex = texture;
-
-    bool ownsTex = false;
-
-    UniquePtr<SharedSurface_GLTexture> ret;
-
-    if (!tex) {
-        GLContext::LocalErrorScope localError(*prodGL);
-
-        tex = CreateTextureForOffscreen(prodGL, formats, size);
-
-        GLenum err = localError.GetError();
-        MOZ_ASSERT_IF(err != LOCAL_GL_NO_ERROR, err == LOCAL_GL_OUT_OF_MEMORY);
-        if (err) {
-            prodGL->fDeleteTextures(1, &tex);
-            return Move(ret);
-        }
-
-        ownsTex = true;
-    }
-
-    ret.reset( new SharedSurface_GLTexture(prodGL, consGL, size,
-                                           hasAlpha, tex, ownsTex) );
-    return Move(ret);
-}
-
-SharedSurface_GLTexture::~SharedSurface_GLTexture()
-{
-    if (!mGL->MakeCurrent())
-        return;
-
-    if (mOwnsTex) {
-        mGL->fDeleteTextures(1, &mTex);
-    }
-
-    if (mSync) {
-        mGL->fDeleteSync(mSync);
-    }
-}
-
-void
-SharedSurface_GLTexture::Fence()
-{
-    MutexAutoLock lock(mMutex);
-    mGL->MakeCurrent();
-
-    if (mConsGL && mGL->IsExtensionSupported(GLContext::ARB_sync)) {
-        if (mSync) {
-            mGL->fDeleteSync(mSync);
-            mSync = 0;
-        }
-
-        mSync = mGL->fFenceSync(LOCAL_GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
-        if (mSync) {
-            mGL->fFlush();
-            return;
-        }
-    }
-    MOZ_ASSERT(!mSync);
-
-    mGL->fFinish();
-}
-
-bool
-SharedSurface_GLTexture::WaitSync()
-{
-    MutexAutoLock lock(mMutex);
-    if (!mSync) {
-        // We either used glFinish, or we passed this fence already.
-        // (PollSync/WaitSync returned true previously)
-        return true;
-    }
-
-    mConsGL->MakeCurrent();
-    MOZ_ASSERT(mConsGL->IsExtensionSupported(GLContext::ARB_sync));
-
-    mConsGL->fWaitSync(mSync,
-                       0,
-                       LOCAL_GL_TIMEOUT_IGNORED);
-    mConsGL->fDeleteSync(mSync);
-    mSync = 0;
-
-    return true;
-}
-
-bool
-SharedSurface_GLTexture::PollSync()
-{
-    MutexAutoLock lock(mMutex);
-    if (!mSync) {
-        // We either used glFinish, or we passed this fence already.
-        // (PollSync/WaitSync returned true previously)
-        return true;
-    }
-
-    mConsGL->MakeCurrent();
-    MOZ_ASSERT(mConsGL->IsExtensionSupported(GLContext::ARB_sync));
-
-    GLint status = 0;
-    mConsGL->fGetSynciv(mSync,
-                        LOCAL_GL_SYNC_STATUS,
-                        1,
-                        nullptr,
-                        &status);
-    if (status != LOCAL_GL_SIGNALED)
-        return false;
-
-    mConsGL->fDeleteSync(mSync);
-    mSync = 0;
-
-    return true;
-}
-
-GLuint
-SharedSurface_GLTexture::ConsTexture(GLContext* consGL)
-{
-    MutexAutoLock lock(mMutex);
-    MOZ_ASSERT(consGL);
-    MOZ_ASSERT(mGL->SharesWith(consGL));
-    MOZ_ASSERT_IF(mConsGL, consGL == mConsGL);
-
-    mConsGL = consGL;
-
-    return mTex;
-}
+SurfaceFactory_Basic::SurfaceFactory_Basic(GLContext* gl, const SurfaceCaps& caps,
+                                           const layers::TextureFlags& flags)
+    : SurfaceFactory(SharedSurfaceType::Basic, gl, caps, nullptr, flags)
+{ }
 
 } /* namespace gfx */
 } /* namespace mozilla */
--- a/gfx/gl/SharedSurfaceGL.h
+++ b/gfx/gl/SharedSurfaceGL.h
@@ -33,150 +33,67 @@ class SharedSurface_Basic
     : public SharedSurface
 {
 public:
     static UniquePtr<SharedSurface_Basic> Create(GLContext* gl,
                                                  const GLFormats& formats,
                                                  const gfx::IntSize& size,
                                                  bool hasAlpha);
 
+    static UniquePtr<SharedSurface_Basic> Wrap(GLContext* gl,
+                                               const gfx::IntSize& size,
+                                               bool hasAlpha,
+                                               GLuint tex);
+
     static SharedSurface_Basic* Cast(SharedSurface* surf) {
         MOZ_ASSERT(surf->mType == SharedSurfaceType::Basic);
 
         return (SharedSurface_Basic*)surf;
     }
 
 protected:
     const GLuint mTex;
+    const bool mOwnsTex;
     GLuint mFB;
 
     SharedSurface_Basic(GLContext* gl,
                         const gfx::IntSize& size,
                         bool hasAlpha,
-                        gfx::SurfaceFormat format,
-                        GLuint tex);
+                        GLuint tex,
+                        bool ownsTex);
 
 public:
     virtual ~SharedSurface_Basic();
 
     virtual void LockProdImpl() override {}
     virtual void UnlockProdImpl() override {}
 
     virtual void Fence() override {}
     virtual bool WaitSync() override { return true; }
     virtual bool PollSync() override { return true; }
 
     virtual GLuint ProdTexture() override {
         return mTex;
     }
+
+    virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override {
+        MOZ_CRASH("don't do this");
+        return false;
+    }
 };
 
 class SurfaceFactory_Basic
     : public SurfaceFactory
 {
 public:
-    SurfaceFactory_Basic(GLContext* gl, const SurfaceCaps& caps)
-        : SurfaceFactory(gl, SharedSurfaceType::Basic, caps)
-    {}
+    SurfaceFactory_Basic(GLContext* gl, const SurfaceCaps& caps,
+                         const layers::TextureFlags& flags);
 
     virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) override {
         bool hasAlpha = mReadCaps.alpha;
         return SharedSurface_Basic::Create(mGL, mFormats, size, hasAlpha);
     }
 };
 
-
-// Using shared GL textures:
-class SharedSurface_GLTexture
-    : public SharedSurface
-{
-public:
-    static UniquePtr<SharedSurface_GLTexture> Create(GLContext* prodGL,
-                                                     GLContext* consGL,
-                                                     const GLFormats& formats,
-                                                     const gfx::IntSize& size,
-                                                     bool hasAlpha,
-                                                     GLuint texture = 0);
-
-    static SharedSurface_GLTexture* Cast(SharedSurface* surf) {
-        MOZ_ASSERT(surf->mType == SharedSurfaceType::GLTextureShare);
-
-        return (SharedSurface_GLTexture*)surf;
-    }
-
-protected:
-    GLContext* mConsGL;
-    const GLuint mTex;
-    const bool mOwnsTex;
-    GLsync mSync;
-    mutable Mutex mMutex;
-
-    SharedSurface_GLTexture(GLContext* prodGL,
-                            GLContext* consGL,
-                            const gfx::IntSize& size,
-                            bool hasAlpha,
-                            GLuint tex,
-                            bool ownsTex)
-        : SharedSurface(SharedSurfaceType::GLTextureShare,
-                        AttachmentType::GLTexture,
-                        prodGL,
-                        size,
-                        hasAlpha)
-        , mConsGL(consGL)
-        , mTex(tex)
-        , mOwnsTex(ownsTex)
-        , mSync(0)
-        , mMutex("SharedSurface_GLTexture mutex")
-    {
-    }
-
-public:
-    virtual ~SharedSurface_GLTexture();
-
-    virtual void LockProdImpl() override {}
-    virtual void UnlockProdImpl() override {}
-
-    virtual void Fence() override;
-    virtual bool WaitSync() override;
-    virtual bool PollSync() override;
-
-    virtual GLuint ProdTexture() override {
-        return mTex;
-    }
-
-    // Custom:
-
-    GLuint ConsTexture(GLContext* consGL);
-
-    GLenum ConsTextureTarget() const {
-        return ProdTextureTarget();
-    }
-};
-
-class SurfaceFactory_GLTexture
-    : public SurfaceFactory
-{
-protected:
-    GLContext* const mConsGL;
-
-public:
-    // If we don't know `consGL` at construction time, use `nullptr`, and call
-    // `SetConsumerGL()` on each `SharedSurface_GLTexture` before calling its
-    // `WaitSync()`.
-    SurfaceFactory_GLTexture(GLContext* prodGL,
-                             GLContext* consGL,
-                             const SurfaceCaps& caps)
-        : SurfaceFactory(prodGL, SharedSurfaceType::GLTextureShare, caps)
-        , mConsGL(consGL)
-    {
-        MOZ_ASSERT(consGL != prodGL);
-    }
-
-    virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) override {
-        bool hasAlpha = mReadCaps.alpha;
-        return SharedSurface_GLTexture::Create(mGL, mConsGL, mFormats, size, hasAlpha);
-    }
-};
-
 } /* namespace gfx */
 } /* namespace mozilla */
 
 #endif /* SHARED_SURFACE_GL_H_ */
--- a/gfx/gl/SharedSurfaceGralloc.cpp
+++ b/gfx/gl/SharedSurfaceGralloc.cpp
@@ -30,23 +30,20 @@
 #endif
 
 namespace mozilla {
 namespace gl {
 
 using namespace mozilla::layers;
 using namespace android;
 
-SurfaceFactory_Gralloc::SurfaceFactory_Gralloc(GLContext* prodGL,
-                                               const SurfaceCaps& caps,
-                                               layers::TextureFlags flags,
-                                               layers::ISurfaceAllocator* allocator)
-    : SurfaceFactory(prodGL, SharedSurfaceType::Gralloc, caps)
-    , mFlags(flags)
-    , mAllocator(allocator)
+SurfaceFactory_Gralloc::SurfaceFactory_Gralloc(GLContext* prodGL, const SurfaceCaps& caps,
+                                               const RefPtr<layers::ISurfaceAllocator>& allocator,
+                                               const layers::TextureFlags& flags)
+    : SurfaceFactory(SharedSurfaceType::Gralloc, prodGL, caps, allocator, flags)
 {
     MOZ_ASSERT(mAllocator);
 }
 
 /*static*/ UniquePtr<SharedSurface_Gralloc>
 SharedSurface_Gralloc::Create(GLContext* prodGL,
                               const GLFormats& formats,
                               const gfx::IntSize& size,
@@ -127,17 +124,18 @@ SharedSurface_Gralloc::SharedSurface_Gra
                                              GLLibraryEGL* egl,
                                              layers::ISurfaceAllocator* allocator,
                                              layers::GrallocTextureClientOGL* textureClient,
                                              GLuint prodTex)
     : SharedSurface(SharedSurfaceType::Gralloc,
                     AttachmentType::GLTexture,
                     prodGL,
                     size,
-                    hasAlpha)
+                    hasAlpha,
+                    true)
     , mEGL(egl)
     , mSync(0)
     , mAllocator(allocator)
     , mTextureClient(textureClient)
     , mProdTex(prodTex)
 {
 }
 
@@ -277,10 +275,17 @@ SharedSurface_Gralloc::PollSync()
 }
 
 void
 SharedSurface_Gralloc::WaitForBufferOwnership()
 {
     mTextureClient->WaitForBufferOwnership();
 }
 
+bool
+SharedSurface_Gralloc::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor)
+{
+    mTextureClient->MarkShared();
+    return mTextureClient->ToSurfaceDescriptor(*out_descriptor);
 }
-}
+
+} // namespace gl
+} // namespace mozilla
--- a/gfx/gl/SharedSurfaceGralloc.h
+++ b/gfx/gl/SharedSurfaceGralloc.h
@@ -68,30 +68,27 @@ public:
 
     virtual GLuint ProdTexture() override {
         return mProdTex;
     }
 
     layers::GrallocTextureClientOGL* GetTextureClient() {
         return mTextureClient;
     }
+
+    virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
 };
 
 class SurfaceFactory_Gralloc
     : public SurfaceFactory
 {
-protected:
-    const layers::TextureFlags mFlags;
-    RefPtr<layers::ISurfaceAllocator> mAllocator;
-
 public:
-    SurfaceFactory_Gralloc(GLContext* prodGL,
-                           const SurfaceCaps& caps,
-                           layers::TextureFlags flags,
-                           layers::ISurfaceAllocator* allocator);
+    SurfaceFactory_Gralloc(GLContext* prodGL, const SurfaceCaps& caps,
+                           const RefPtr<layers::ISurfaceAllocator>& allocator,
+                           const layers::TextureFlags& flags);
 
     virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) override {
         bool hasAlpha = mReadCaps.alpha;
 
         UniquePtr<SharedSurface> ret;
         if (mAllocator) {
             ret = SharedSurface_Gralloc::Create(mGL, mFormats, size, hasAlpha,
                                                 mFlags, mAllocator);
--- a/gfx/gl/SharedSurfaceIO.cpp
+++ b/gfx/gl/SharedSurfaceIO.cpp
@@ -1,18 +1,19 @@
 /* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
 /* 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 "SharedSurfaceIO.h"
 
 #include "GLContextCGL.h"
+#include "mozilla/DebugOnly.h"
 #include "mozilla/gfx/MacIOSurface.h"
-#include "mozilla/DebugOnly.h"
+#include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor, etc
 #include "ScopedGLHelpers.h"
 
 namespace mozilla {
 namespace gl {
 
 /*static*/ UniquePtr<SharedSurface_IOSurface>
 SharedSurface_IOSurface::Create(const RefPtr<MacIOSurface>& ioSurf,
                                 GLContext* gl,
@@ -147,17 +148,18 @@ BackTextureWithIOSurf(GLContext* gl, GLu
 SharedSurface_IOSurface::SharedSurface_IOSurface(const RefPtr<MacIOSurface>& ioSurf,
                                                  GLContext* gl,
                                                  const gfx::IntSize& size,
                                                  bool hasAlpha)
   : SharedSurface(SharedSurfaceType::IOSurface,
                   AttachmentType::GLTexture,
                   gl,
                   size,
-                  hasAlpha)
+                  hasAlpha,
+                  true)
   , mIOSurf(ioSurf)
 {
     gl->MakeCurrent();
     mProdTex = 0;
     gl->fGenTextures(1, &mProdTex);
     BackTextureWithIOSurf(gl, mProdTex, mIOSurf);
 }
 
@@ -165,28 +167,39 @@ SharedSurface_IOSurface::~SharedSurface_
 {
     if (mProdTex) {
         DebugOnly<bool> success = mGL->MakeCurrent();
         MOZ_ASSERT(success);
         mGL->fDeleteTextures(1, &mProdTex);
     }
 }
 
+bool
+SharedSurface_IOSurface::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor)
+{
+    bool isOpaque = !mHasAlpha;
+    *out_descriptor = layers::SurfaceDescriptorMacIOSurface(mIOSurf->GetIOSurfaceID(),
+                                                            mIOSurf->GetContentsScaleFactor(),
+                                                            isOpaque);
+    return true;
+}
+
 ////////////////////////////////////////////////////////////////////////
 // SurfaceFactory_IOSurface
 
 /*static*/ UniquePtr<SurfaceFactory_IOSurface>
-SurfaceFactory_IOSurface::Create(GLContext* gl,
-                                 const SurfaceCaps& caps)
+SurfaceFactory_IOSurface::Create(GLContext* gl, const SurfaceCaps& caps,
+                                 const RefPtr<layers::ISurfaceAllocator>& allocator,
+                                 const layers::TextureFlags& flags)
 {
     gfx::IntSize maxDims(MacIOSurface::GetMaxWidth(),
                          MacIOSurface::GetMaxHeight());
 
     typedef SurfaceFactory_IOSurface ptrT;
-    UniquePtr<ptrT> ret( new ptrT(gl, caps, maxDims) );
+    UniquePtr<ptrT> ret( new ptrT(gl, caps, allocator, flags, maxDims) );
     return Move(ret);
 }
 
 UniquePtr<SharedSurface>
 SurfaceFactory_IOSurface::CreateShared(const gfx::IntSize& size)
 {
     if (size.width > mMaxDims.width ||
         size.height > mMaxDims.height)
--- a/gfx/gl/SharedSurfaceIO.h
+++ b/gfx/gl/SharedSurfaceIO.h
@@ -11,21 +11,31 @@
 
 class MacIOSurface;
 
 namespace mozilla {
 namespace gl {
 
 class SharedSurface_IOSurface : public SharedSurface
 {
+private:
+    const RefPtr<MacIOSurface> mIOSurf;
+    GLuint mProdTex;
+
 public:
     static UniquePtr<SharedSurface_IOSurface> Create(const RefPtr<MacIOSurface>& ioSurf,
                                                      GLContext* gl,
                                                      bool hasAlpha);
 
+private:
+    SharedSurface_IOSurface(const RefPtr<MacIOSurface>& ioSurf,
+                            GLContext* gl, const gfx::IntSize& size,
+                            bool hasAlpha);
+
+public:
     ~SharedSurface_IOSurface();
 
     virtual void LockProdImpl() override { }
     virtual void UnlockProdImpl() override { }
 
     virtual void Fence() override;
     virtual bool WaitSync() override { return true; }
     virtual bool PollSync() override { return true; }
@@ -52,41 +62,37 @@ public:
     MacIOSurface* GetIOSurface() const {
         return mIOSurf;
     }
 
     virtual bool NeedsIndirectReads() const override {
         return true;
     }
 
-private:
-    SharedSurface_IOSurface(const RefPtr<MacIOSurface>& ioSurf,
-                            GLContext* gl, const gfx::IntSize& size,
-                            bool hasAlpha);
-
-    RefPtr<MacIOSurface> mIOSurf;
-    GLuint mProdTex;
+    virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
 };
 
 class SurfaceFactory_IOSurface : public SurfaceFactory
 {
 public:
     // Infallible.
     static UniquePtr<SurfaceFactory_IOSurface> Create(GLContext* gl,
-                                                      const SurfaceCaps& caps);
+                                                      const SurfaceCaps& caps,
+                                                      const RefPtr<layers::ISurfaceAllocator>& allocator,
+                                                      const layers::TextureFlags& flags);
 protected:
     const gfx::IntSize mMaxDims;
 
-    SurfaceFactory_IOSurface(GLContext* gl,
-                             const SurfaceCaps& caps,
+    SurfaceFactory_IOSurface(GLContext* gl, const SurfaceCaps& caps,
+                             const RefPtr<layers::ISurfaceAllocator>& allocator,
+                             const layers::TextureFlags& flags,
                              const gfx::IntSize& maxDims)
-        : SurfaceFactory(gl, SharedSurfaceType::IOSurface, caps)
+        : SurfaceFactory(SharedSurfaceType::IOSurface, gl, caps, allocator, flags)
         , mMaxDims(maxDims)
-    {
-    }
+    { }
 
     virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) override;
 };
 
 } /* namespace gfx */
 } /* namespace mozilla */
 
 #endif /* SHARED_SURFACEIO_H_ */
--- a/gfx/gl/SurfaceTypes.h
+++ b/gfx/gl/SurfaceTypes.h
@@ -65,17 +65,16 @@ struct SurfaceCaps final
         return caps;
     }
 };
 
 enum class SharedSurfaceType : uint8_t {
     Unknown = 0,
 
     Basic,
-    GLTextureShare,
     EGLImageShare,
     EGLSurfaceANGLE,
     DXGLInterop,
     DXGLInterop2,
     Gralloc,
     IOSurface,
 
     Max
--- a/gfx/layers/AtomicRefCountedWithFinalize.h
+++ b/gfx/layers/AtomicRefCountedWithFinalize.h
@@ -8,26 +8,45 @@
 
 #include "mozilla/RefPtr.h"
 #include "mozilla/Likely.h"
 #include "MainThreadUtils.h"
 #include "base/message_loop.h"
 #include "base/task.h"
 #include "mozilla/gfx/Logging.h"
 
+#define ADDREF_MANUALLY(obj)  (obj)->AddRefManually(__FUNCTION__, __FILE__, __LINE__)
+#define RELEASE_MANUALLY(obj)  (obj)->ReleaseManually(__FUNCTION__, __FILE__, __LINE__)
+
 namespace mozilla {
 
+template<class U>
+class StaticRefPtr;
+
+namespace gl {
+template<typename T>
+class RefSet;
+
+template<typename T>
+class RefQueue;
+}
+
 template<typename T>
 class AtomicRefCountedWithFinalize
 {
-  protected:
+protected:
     AtomicRefCountedWithFinalize()
       : mRecycleCallback(nullptr)
       , mRefCount(0)
       , mMessageLoopToPostDestructionTo(nullptr)
+#ifdef DEBUG
+      , mSpew(false)
+      , mManualAddRefs(0)
+      , mManualReleases(0)
+#endif
     {}
 
     ~AtomicRefCountedWithFinalize() {
       if (mRefCount >= 0) {
         gfxCriticalError() << "Deleting referenced object? " << mRefCount;
       }
     }
 
@@ -36,22 +55,79 @@ class AtomicRefCountedWithFinalize
       mMessageLoopToPostDestructionTo = l;
     }
 
     static void DestroyToBeCalledOnMainThread(T* ptr) {
       MOZ_ASSERT(NS_IsMainThread());
       delete ptr;
     }
 
-  public:
+public:
+    // Mark user classes that are considered flawless.
+    template<typename U>
+    friend class RefPtr;
+
+    template<class U>
+    friend class ::mozilla::StaticRefPtr;
+
+    template<typename U>
+    friend class TemporaryRef;
+
+    template<class U>
+    friend class ::nsRefPtr;
+
+    template<class U>
+    friend struct ::RunnableMethodTraits;
+
+    template<typename U>
+    friend class ::mozilla::gl::RefSet;
+
+    template<typename U>
+    friend class ::mozilla::gl::RefQueue;
+
+    //friend class mozilla::gl::SurfaceFactory;
+
+    void AddRefManually(const char* funcName, const char* fileName, uint32_t lineNum) {
+#ifdef DEBUG
+      uint32_t count = ++mManualAddRefs;
+      if (mSpew) {
+        printf_stderr("AddRefManually() #%u in %s at %s:%u\n", count, funcName,
+                      fileName, lineNum);
+      }
+#else
+      (void)funcName;
+      (void)fileName;
+      (void)lineNum;
+#endif
+      AddRef();
+    }
+
+    void ReleaseManually(const char* funcName, const char* fileName, uint32_t lineNum) {
+#ifdef DEBUG
+      uint32_t count = ++mManualReleases;
+      if (mSpew) {
+        printf_stderr("ReleaseManually() #%u in %s at %s:%u\n", count, funcName,
+                      fileName, lineNum);
+      }
+#else
+      (void)funcName;
+      (void)fileName;
+      (void)lineNum;
+#endif
+      Release();
+    }
+
+private:
     void AddRef() {
+      MOZ_ASSERT(mRefCount >= 0, "AddRef() during/after Finalize()/dtor.");
       ++mRefCount;
     }
 
     void Release() {
+      MOZ_ASSERT(mRefCount > 0, "Release() during/after Finalize()/dtor.");
       // Read mRecycleCallback early so that it does not get set to
       // deleted memory, if the object is goes away.  See bug 994903.
       // This saves us in the case where there is no callback, so that
       // we can do the "else if" below.
       RecycleCallback recycleCallback = mRecycleCallback;
       int currCount = --mRefCount;
       if (currCount < 0) {
         gfxCriticalError() << "Invalid reference count release" << currCount;
@@ -65,16 +141,18 @@ class AtomicRefCountedWithFinalize
 
         // Recycle listeners must call ClearRecycleCallback
         // before releasing their strong reference.
         if (mRecycleCallback) {
           gfxCriticalError() << "About to release with valid callback";
           mRecycleCallback = nullptr;
         }
 
+        MOZ_ASSERT(mManualAddRefs == mManualReleases);
+
         T* derived = static_cast<T*>(this);
         derived->Finalize();
         if (MOZ_LIKELY(!mMessageLoopToPostDestructionTo)) {
           delete derived;
         } else {
           if (MOZ_LIKELY(NS_IsMainThread())) {
             delete derived;
           } else {
@@ -88,16 +166,17 @@ class AtomicRefCountedWithFinalize
         // are being careful to never let the reference count go down if there
         // is a callback.
         MOZ_ASSERT(!IsDead());
         T* derived = static_cast<T*>(this);
         recycleCallback(derived, mClosure);
       }
     }
 
+public:
     typedef void (*RecycleCallback)(T* aObject, void* aClosure);
     /**
      * Set a callback responsible for recycling this object
      * before it is finalized.
      */
     void SetRecycleCallback(RecycleCallback aCallback, void* aClosure)
     {
       MOZ_ASSERT(!IsDead());
@@ -121,13 +200,20 @@ class AtomicRefCountedWithFinalize
       return mRefCount < 0;
     }
 
 private:
     RecycleCallback mRecycleCallback;
     void *mClosure;
     Atomic<int> mRefCount;
     MessageLoop *mMessageLoopToPostDestructionTo;
+#ifdef DEBUG
+public:
+    bool mSpew;
+private:
+    Atomic<uint32_t> mManualAddRefs;
+    Atomic<uint32_t> mManualReleases;
+#endif
 };
 
-}
+} // namespace mozilla
 
 #endif
--- a/gfx/layers/CopyableCanvasLayer.cpp
+++ b/gfx/layers/CopyableCanvasLayer.cpp
@@ -1,31 +1,33 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "CopyableCanvasLayer.h"
+
 #include "BasicLayersImpl.h"            // for FillWithMask, etc
-#include "CopyableCanvasLayer.h"
 #include "GLContext.h"                  // for GLContext
 #include "GLScreenBuffer.h"             // for GLScreenBuffer
 #include "SharedSurface.h"              // for SharedSurface
 #include "SharedSurfaceGL.h"              // for SharedSurface
 #include "gfxPattern.h"                 // for gfxPattern, etc
 #include "gfxPlatform.h"                // for gfxPlatform, gfxImageFormat
 #include "gfxRect.h"                    // for gfxRect
 #include "gfxUtils.h"                   // for gfxUtils
 #include "gfx2DGlue.h"                  // for thebes --> moz2d transition
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/gfx/Tools.h"
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING, etc
 #include "nsISupportsImpl.h"            // for gfxContext::AddRef, etc
 #include "nsRect.h"                     // for mozilla::gfx::IntRect
 #include "gfxUtils.h"
+#include "client/TextureClientSharedSurface.h"
 
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gfx;
 using namespace mozilla::gl;
 
 CopyableCanvasLayer::CopyableCanvasLayer(LayerManager* aLayerManager, void *aImplData) :
@@ -51,21 +53,18 @@ CopyableCanvasLayer::Initialize(const Da
     mGLContext = aData.mGLContext;
     mIsAlphaPremultiplied = aData.mIsGLAlphaPremult;
     mOriginPos = gl::OriginPos::BottomLeft;
 
     MOZ_ASSERT(mGLContext->IsOffscreen(), "canvas gl context isn't offscreen");
 
     if (aData.mFrontbufferGLTex) {
       gfx::IntSize size(aData.mSize.width, aData.mSize.height);
-      mGLFrontbuffer = SharedSurface_GLTexture::Create(aData.mGLContext,
-                                                       nullptr,
-                                                       aData.mGLContext->GetGLFormats(),
-                                                       size, aData.mHasAlpha,
-                                                       aData.mFrontbufferGLTex);
+      mGLFrontbuffer = SharedSurface_Basic::Wrap(aData.mGLContext, size, aData.mHasAlpha,
+                                                 aData.mFrontbufferGLTex);
     }
   } else if (aData.mDrawTarget) {
     mDrawTarget = aData.mDrawTarget;
     mSurface = mDrawTarget->Snapshot();
   } else {
     MOZ_CRASH("CanvasLayer created without mSurface, mDrawTarget or mGLContext?");
   }
 
@@ -103,17 +102,17 @@ CopyableCanvasLayer::UpdateTarget(DrawTa
 
   MOZ_ASSERT(mGLContext);
 
   SharedSurface* frontbuffer = nullptr;
   if (mGLFrontbuffer) {
     frontbuffer = mGLFrontbuffer.get();
   } else {
     GLScreenBuffer* screen = mGLContext->Screen();
-    ShSurfHandle* front = screen->Front();
+    const auto& front = screen->Front();
     if (front) {
       frontbuffer = front->Surf();
     }
   }
 
   if (!frontbuffer) {
     NS_WARNING("Null frame received.");
     return;
@@ -132,17 +131,17 @@ CopyableCanvasLayer::UpdateTarget(DrawTa
     int32_t destStride;
     SurfaceFormat destFormat;
     if (aDestTarget->LockBits(&destData, &destSize, &destStride, &destFormat)) {
       if (destSize == readSize && destFormat == format) {
         RefPtr<DataSourceSurface> data =
           Factory::CreateWrappingDataSourceSurface(destData, destStride, destSize, destFormat);
         mGLContext->Readback(frontbuffer, data);
         if (needsPremult) {
-            gfxUtils::PremultiplyDataSurface(data, data);
+          gfxUtils::PremultiplyDataSurface(data, data);
         }
         aDestTarget->ReleaseBits(destData);
         return;
       }
       aDestTarget->ReleaseBits(destData);
     }
   }
 
--- a/gfx/layers/basic/MacIOSurfaceTextureHostBasic.cpp
+++ b/gfx/layers/basic/MacIOSurfaceTextureHostBasic.cpp
@@ -34,17 +34,17 @@ MacIOSurfaceTextureSourceBasic::GetForma
 }
 
 MacIOSurfaceTextureHostBasic::MacIOSurfaceTextureHostBasic(
     TextureFlags aFlags,
     const SurfaceDescriptorMacIOSurface& aDescriptor
 )
   : TextureHost(aFlags)
 {
-  mSurface = MacIOSurface::LookupSurface(aDescriptor.surface(),
+  mSurface = MacIOSurface::LookupSurface(aDescriptor.surfaceId(),
                                          aDescriptor.scaleFactor(),
                                          !aDescriptor.isOpaque());
 }
 
 gfx::SourceSurface*
 MacIOSurfaceTextureSourceBasic::GetSurface(gfx::DrawTarget* aTarget)
 {
   if (!mSourceSurface) {
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -17,38 +17,29 @@
 #include "mozilla/layers/CompositorChild.h" // for CompositorChild
 #include "mozilla/layers/GrallocTextureClient.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/layers/TextureClient.h"  // for TextureClient, etc
 #include "mozilla/layers/TextureClientOGL.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsDebug.h"                    // for printf_stderr, NS_ASSERTION
 #include "nsXULAppAPI.h"                // for XRE_GetProcessType, etc
-#ifdef MOZ_WIDGET_GONK
-#include "SharedSurfaceGralloc.h"
-#endif
+#include "TextureClientSharedSurface.h"
 
 using namespace mozilla::gfx;
 using namespace mozilla::gl;
 
 namespace mozilla {
 namespace layers {
 
 /* static */ TemporaryRef<CanvasClient>
 CanvasClient::CreateCanvasClient(CanvasClientType aType,
                                  CompositableForwarder* aForwarder,
                                  TextureFlags aFlags)
 {
-#ifndef MOZ_WIDGET_GONK
-  if (XRE_GetProcessType() != GeckoProcessType_Default) {
-    NS_WARNING("Most platforms still need an optimized way to share GL cross process.");
-    return MakeAndAddRef<CanvasClient2D>(aForwarder, aFlags);
-  }
-#endif
-
   switch (aType) {
   case CanvasClientTypeShSurf:
     return MakeAndAddRef<CanvasClientSharedSurface>(aForwarder, aFlags);
     break;
 
   default:
     return MakeAndAddRef<CanvasClient2D>(aForwarder, aFlags);
     break;
@@ -144,38 +135,21 @@ CanvasClient2D::CreateTextureClientForCa
 #endif
 }
 
 ////////////////////////////////////////////////////////////////////////
 
 CanvasClientSharedSurface::CanvasClientSharedSurface(CompositableForwarder* aLayerForwarder,
                                                      TextureFlags aFlags)
   : CanvasClient(aLayerForwarder, aFlags)
-{
-}
+{ }
 
-////////////////////////////////////////
-// Accelerated backends
-
-static TemporaryRef<TextureClient>
-TexClientFromShSurf(ISurfaceAllocator* aAllocator, SharedSurface* surf,
-                    TextureFlags flags)
+CanvasClientSharedSurface::~CanvasClientSharedSurface()
 {
-  switch (surf->mType) {
-    case SharedSurfaceType::Basic:
-      return nullptr;
-
-#ifdef MOZ_WIDGET_GONK
-    case SharedSurfaceType::Gralloc:
-      return GrallocTextureClientOGL::FromSharedSurface(surf, flags);
-#endif
-
-    default:
-      return MakeAndAddRef<SharedSurfaceTextureClient>(aAllocator, flags, surf);
-  }
+  ClearSurfaces();
 }
 
 ////////////////////////////////////////
 // Readback
 
 // For formats compatible with R8G8B8A8.
 static inline void SwapRB_R8G8B8A8(uint8_t* pixel) {
   // [RR, GG, BB, AA]
@@ -325,96 +299,97 @@ TexClientFromReadback(SharedSurface* src
     texClient->Unlock();
   }
 
   return texClient.forget();
 }
 
 ////////////////////////////////////////
 
-static TemporaryRef<gl::ShSurfHandle>
+static TemporaryRef<SharedSurfaceTextureClient>
 CloneSurface(gl::SharedSurface* src, gl::SurfaceFactory* factory)
 {
-    RefPtr<gl::ShSurfHandle> dest = factory->NewShSurfHandle(src->mSize);
+    RefPtr<SharedSurfaceTextureClient> dest = factory->NewTexClient(src->mSize);
     if (!dest) {
-        return nullptr;
+      return nullptr;
     }
     SharedSurface::ProdCopy(src, dest->Surf(), factory);
+    dest->Surf()->Fence();
     return dest.forget();
 }
 
 void
 CanvasClientSharedSurface::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
 {
-  if (mFront) {
-    mPrevFront = mFront;
-    mFront = nullptr;
-  }
-
   auto gl = aLayer->mGLContext;
   gl->MakeCurrent();
 
+  RefPtr<TextureClient> newFront;
+
   if (aLayer->mGLFrontbuffer) {
-    mFront = CloneSurface(aLayer->mGLFrontbuffer.get(), aLayer->mFactory.get());
-    if (mFront)
-      mFront->Surf()->Fence();
+    mShSurfClient = CloneSurface(aLayer->mGLFrontbuffer.get(), aLayer->mFactory.get());
+    if (!mShSurfClient) {
+      gfxCriticalError() << "Invalid canvas front buffer";
+      return;
+    }
   } else {
-    mFront = gl->Screen()->Front();
+    mShSurfClient = gl->Screen()->Front();
+    if (!mShSurfClient) {
+      return;
+    }
   }
-  if (!mFront) {
-    gfxCriticalError() << "Invalid canvas front buffer";
-    return;
-  }
+  MOZ_ASSERT(mShSurfClient);
+
+  newFront = mShSurfClient;
+
+  SharedSurface* surf = mShSurfClient->Surf();
 
-  // Alright, now sort out the IPC goop.
-  SharedSurface* surf = mFront->Surf();
+  // Readback if needed.
+  mReadbackClient = nullptr;
+
   auto forwarder = GetForwarder();
-  auto flags = GetTextureFlags() | TextureFlags::IMMUTABLE;
 
-  // Get a TexClient from our surf.
-  RefPtr<TextureClient> newTex = TexClientFromShSurf(GetForwarder(), surf, flags);
-  if (!newTex) {
+  bool needsReadback = (surf->mType == SharedSurfaceType::Basic);
+  if (needsReadback) {
+    TextureFlags flags = aLayer->Flags() |
+                         TextureFlags::IMMUTABLE;
+
     auto manager = aLayer->ClientManager();
     auto shadowForwarder = manager->AsShadowForwarder();
     auto layersBackend = shadowForwarder->GetCompositorBackendType();
+    mReadbackClient = TexClientFromReadback(surf, forwarder, flags, layersBackend);
 
-    newTex = TexClientFromReadback(surf, forwarder, flags, layersBackend);
+    newFront = mReadbackClient;
+  } else {
+    mReadbackClient = nullptr;
   }
 
-  if (!newTex) {
+  MOZ_ASSERT(newFront);
+  if (!newFront) {
     // May happen in a release build in case of memory pressure.
-    gfxCriticalError() << "Failed to allocate a TextureClient for SharedSurface Canvas. size: " << aSize;
+    gfxCriticalError() << "Failed to allocate a TextureClient for SharedSurface Canvas. Size: " << aSize;
     return;
   }
 
-  // Add the new TexClient.
-  MOZ_ALWAYS_TRUE( AddTextureClient(newTex) );
-
-  // Remove the old TexClient.
-  if (mFrontTex) {
-    // remove old buffer from CompositableHost
-    RefPtr<AsyncTransactionTracker> tracker = new RemoveTextureFromCompositableTracker();
-    // Hold TextureClient until transaction complete.
-    tracker->SetTextureClient(mFrontTex);
-    mFrontTex->SetRemoveFromCompositableTracker(tracker);
-    // RemoveTextureFromCompositableAsync() expects CompositorChild's presence.
-    GetForwarder()->RemoveTextureFromCompositableAsync(tracker, this, mFrontTex);
-
-    mFrontTex = nullptr;
+  if (mFront) {
+    if (mFront->GetFlags() & TextureFlags::RECYCLE) {
+      mFront->WaitForCompositorRecycle();
+    }
   }
 
-  // Use the new TexClient.
-  mFrontTex = newTex;
+  mFront = newFront;
 
-  forwarder->UseTexture(this, mFrontTex);
+  // Add the new TexClient.
+  MOZ_ALWAYS_TRUE( AddTextureClient(mFront) );
+
+  forwarder->UseTexture(this, mFront);
 }
 
 void
 CanvasClientSharedSurface::ClearSurfaces()
 {
-  mFrontTex = nullptr;
-  // It is important to destroy the SharedSurface *after* the TextureClient.
   mFront = nullptr;
-  mPrevFront = nullptr;
+  mShSurfClient = nullptr;
+  mReadbackClient = nullptr;
 }
 
-}
-}
+} // namespace layers
+} // namespace mozilla
--- a/gfx/layers/client/CanvasClient.h
+++ b/gfx/layers/client/CanvasClient.h
@@ -14,27 +14,21 @@
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 #include "mozilla/layers/TextureClient.h"  // for TextureClient, etc
 #include "mozilla/mozalloc.h"           // for operator delete
 
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat
 
 namespace mozilla {
-namespace gl {
-class SharedSurface;
-class ShSurfHandle;
-}
-}
-
-namespace mozilla {
 namespace layers {
 
 class ClientCanvasLayer;
 class CompositableForwarder;
+class SharedSurfaceTextureClient;
 
 /**
  * Compositable client for 2d and webgl canvas.
  */
 class CanvasClient : public CompositableClient
 {
 public:
   /**
@@ -109,31 +103,27 @@ private:
   RefPtr<TextureClient> mBuffer;
 };
 
 // Used for GL canvases where we don't need to do any readback, i.e., with a
 // GL backend.
 class CanvasClientSharedSurface : public CanvasClient
 {
 private:
-  RefPtr<gl::ShSurfHandle> mFront;
-  RefPtr<gl::ShSurfHandle> mPrevFront;
-
-  RefPtr<TextureClient> mFrontTex;
+  RefPtr<SharedSurfaceTextureClient> mShSurfClient;
+  RefPtr<TextureClient> mReadbackClient;
+  RefPtr<TextureClient> mFront;
 
   void ClearSurfaces();
 
 public:
   CanvasClientSharedSurface(CompositableForwarder* aLayerForwarder,
                             TextureFlags aFlags);
 
-  ~CanvasClientSharedSurface()
-  {
-    ClearSurfaces();
-  }
+  ~CanvasClientSharedSurface();
 
   virtual TextureInfo GetTextureInfo() const override {
     return TextureInfo(CompositableType::IMAGE);
   }
 
   virtual void Clear() override {
     ClearSurfaces();
   }
--- a/gfx/layers/client/ClientCanvasLayer.cpp
+++ b/gfx/layers/client/ClientCanvasLayer.cpp
@@ -65,74 +65,66 @@ ClientCanvasLayer::Initialize(const Data
     caps = mGLFrontbuffer->mHasAlpha ? SurfaceCaps::ForRGBA()
                                      : SurfaceCaps::ForRGB();
   } else {
     MOZ_ASSERT(screen);
     caps = screen->mCaps;
   }
   MOZ_ASSERT(caps.alpha == aData.mHasAlpha);
 
+  auto forwarder = ClientManager()->AsShadowForwarder();
+
+  mFlags = TextureFlags::ORIGIN_BOTTOM_LEFT;
+  if (!aData.mIsGLAlphaPremult) {
+    mFlags |= TextureFlags::NON_PREMULTIPLIED;
+  }
+
   UniquePtr<SurfaceFactory> factory;
 
   if (!gfxPrefs::WebGLForceLayersReadback()) {
-    switch (ClientManager()->AsShadowForwarder()->GetCompositorBackendType()) {
+    switch (forwarder->GetCompositorBackendType()) {
       case mozilla::layers::LayersBackend::LAYERS_OPENGL: {
+#if defined(XP_MACOSX)
+        factory = SurfaceFactory_IOSurface::Create(mGLContext, caps, forwarder, mFlags);
+#elif defined(MOZ_WIDGET_GONK)
+        factory = MakeUnique<SurfaceFactory_Gralloc>(mGLContext, caps, forwarder, mFlags);
+#else
         if (mGLContext->GetContextType() == GLContextType::EGL) {
-#ifdef MOZ_WIDGET_GONK
-          TextureFlags flags = TextureFlags::DEALLOCATE_CLIENT |
-                               TextureFlags::ORIGIN_BOTTOM_LEFT;
-          if (!aData.mIsGLAlphaPremult) {
-            flags |= TextureFlags::NON_PREMULTIPLIED;
-          }
-          factory = MakeUnique<SurfaceFactory_Gralloc>(mGLContext,
-                                                       caps,
-                                                       flags,
-                                                       ClientManager()->AsShadowForwarder());
-#else
-          bool isCrossProcess = !(XRE_GetProcessType() == GeckoProcessType_Default);
+          bool isCrossProcess = (XRE_GetProcessType() != GeckoProcessType_Default);
           if (!isCrossProcess) {
-            // [Basic/OGL Layers, OMTC] WebGL layer init.
-            factory = SurfaceFactory_EGLImage::Create(mGLContext, caps);
-          } else {
-            // we could do readback here maybe
-            NS_NOTREACHED("isCrossProcess but not on native B2G!");
+            factory = SurfaceFactory_EGLImage::Create(mGLContext, caps, forwarder,
+                                                      mFlags);
           }
+        }
 #endif
-        } else {
-          // [Basic Layers, OMTC] WebGL layer init.
-          // Well, this *should* work...
-#ifdef XP_MACOSX
-          factory = SurfaceFactory_IOSurface::Create(mGLContext, caps);
-#else
-          GLContext* nullConsGL = nullptr; // Bug 1050044.
-          factory = MakeUnique<SurfaceFactory_GLTexture>(mGLContext, nullConsGL, caps);
-#endif
-        }
         break;
       }
       case mozilla::layers::LayersBackend::LAYERS_D3D11: {
 #ifdef XP_WIN
-        if (mGLContext->IsANGLE() && DoesD3D11TextureSharingWork(gfxWindowsPlatform::GetPlatform()->GetD3D11Device())) {
-          factory = SurfaceFactory_ANGLEShareHandle::Create(mGLContext, caps);
+        if (mGLContext->IsANGLE() &&
+            DoesD3D11TextureSharingWork(gfxWindowsPlatform::GetPlatform()->GetD3D11Device()))
+        {
+          factory = SurfaceFactory_ANGLEShareHandle::Create(mGLContext, caps, forwarder,
+                                                            mFlags);
         }
 #endif
         break;
       }
       default:
         break;
     }
   }
 
   if (mGLFrontbuffer) {
     // We're using a source other than the one in the default screen.
     // (SkiaGL)
     mFactory = Move(factory);
     if (!mFactory) {
       // Absolutely must have a factory here, so create a basic one
-      mFactory = MakeUnique<SurfaceFactory_Basic>(mGLContext, caps);
+      mFactory = MakeUnique<SurfaceFactory_Basic>(mGLContext, caps, mFlags);
     }
   } else {
     if (factory)
       screen->Morph(Move(factory));
   }
 }
 
 void
--- a/gfx/layers/client/ClientCanvasLayer.h
+++ b/gfx/layers/client/ClientCanvasLayer.h
@@ -1,32 +1,31 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_CLIENTCANVASLAYER_H
 #define GFX_CLIENTCANVASLAYER_H
 
-#include "mozilla/layers/CanvasClient.h"  // for CanvasClient, etc
+#include "CanvasClient.h"               // for CanvasClient, etc
 #include "ClientLayerManager.h"         // for ClientLayerManager, etc
 #include "CopyableCanvasLayer.h"        // for CopyableCanvasLayer
 #include "Layers.h"                     // for CanvasLayer, etc
 #include "mozilla/Attributes.h"         // for override
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/layers/LayersMessages.h"  // for CanvasLayerAttributes, etc
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsRegion.h"                   // for nsIntRegion
 
 namespace mozilla {
 namespace gl {
-class SharedSurface;
 class SurfaceFactory;
 }
 
 namespace layers {
 
 class CompositableClient;
 class ShadowableLayer;
 
@@ -76,28 +75,33 @@ public:
     mCanvasClient = nullptr;
     ClientLayer::Disconnect();
   }
 
   virtual CompositableClient* GetCompositableClient() override
   {
     return mCanvasClient;
   }
+
+  const TextureFlags& Flags() const { return mFlags; }
+
 protected:
   ClientLayerManager* ClientManager()
   {
     return static_cast<ClientLayerManager*>(mManager);
   }
 
   CanvasClientType GetCanvasClientType();
 
   RefPtr<CanvasClient> mCanvasClient;
 
   UniquePtr<gl::SurfaceFactory> mFactory;
 
+  TextureFlags mFlags;
+
   friend class DeprecatedCanvasClient2D;
   friend class CanvasClient2D;
   friend class CanvasClientSharedSurface;
 };
 }
 }
 
 #endif
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -15,18 +15,16 @@
 #include "mozilla/layers/YCbCrImageDataSerializer.h"
 #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING, etc
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "ImageContainer.h"             // for PlanarYCbCrData, etc
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Logging.h"        // for gfxDebug
 #include "mozilla/layers/TextureClientOGL.h"
 #include "mozilla/layers/PTextureChild.h"
-#include "SharedSurface.h"
-#include "GLContext.h"
 #include "mozilla/gfx/DataSurfaceHelpers.h" // for CreateDataSourceSurfaceByCloning
 #include "nsPrintfCString.h"            // for nsPrintfCString
 #include "LayersLogging.h"              // for AppendToString
 #include "gfxUtils.h"                   // for gfxUtils::GetAsLZ4Base64Str
 
 #ifdef XP_WIN
 #include "mozilla/layers/TextureD3D9.h"
 #include "mozilla/layers/TextureD3D11.h"
@@ -108,25 +106,25 @@ public:
   , mIPCOpen(false)
   {
   }
 
   bool Recv__delete__() override;
 
   bool RecvCompositorRecycle() override
   {
-    RECYCLE_LOG("Receive recycle %p (%p)\n", mTextureClient, mWaitForRecycle.get());
+    RECYCLE_LOG("[CLIENT] Receive recycle %p (%p)\n", mTextureClient, mWaitForRecycle.get());
     mWaitForRecycle = nullptr;
     return true;
   }
 
   void WaitForCompositorRecycle()
   {
     mWaitForRecycle = mTextureClient;
-    RECYCLE_LOG("Wait for recycle %p\n", mWaitForRecycle.get());
+    RECYCLE_LOG("[CLIENT] Wait for recycle %p\n", mWaitForRecycle.get());
     SendClientRecycle();
   }
 
   CompositableForwarder* GetForwarder() { return mForwarder; }
 
   ISurfaceAllocator* GetAllocator() { return mForwarder; }
 
   void ActorDestroy(ActorDestroyReason why) override;
@@ -582,16 +580,20 @@ TextureClient::Finalize()
   // in case TextureChild::ActorDestroy might null mActor concurrently.
   RefPtr<TextureChild> actor = mActor;
 
   if (actor) {
     // The actor has a raw pointer to us, actor->mTextureClient.
     // Null it before RemoveTexture calls to avoid invalid actor->mTextureClient
     // when calling TextureChild::ActorDestroy()
     actor->mTextureClient = nullptr;
+
+    // `actor->mWaitForRecycle` may not be null, as we may be being called from setting
+    // this RefPtr to null! Clearing it here will double-Release() it.
+
     // this will call ForceRemove in the right thread, using a sync proxy if needed
     if (actor->GetForwarder()) {
       actor->GetForwarder()->RemoveTexture(this);
     }
   }
 }
 
 bool
@@ -910,42 +912,16 @@ BufferTextureClient::GetLockedData() con
   MOZ_ASSERT(IsLocked());
 
   ImageDataSerializer serializer(GetBuffer(), GetBufferSize());
   MOZ_ASSERT(serializer.IsValid());
 
   return serializer.GetData();
 }
 
-////////////////////////////////////////////////////////////////////////
-// SharedSurfaceTextureClient
-
-SharedSurfaceTextureClient::SharedSurfaceTextureClient(ISurfaceAllocator* aAllocator,
-                                                       TextureFlags aFlags,
-                                                       gl::SharedSurface* surf)
-  : TextureClient(aAllocator, aFlags)
-  , mIsLocked(false)
-  , mSurf(surf)
-  , mGL(mSurf->mGL)
-{
-  AddFlags(TextureFlags::DEALLOCATE_CLIENT);
-}
-
-SharedSurfaceTextureClient::~SharedSurfaceTextureClient()
-{
-  // the data is owned externally.
-}
-
-bool
-SharedSurfaceTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
-{
-  aOutDescriptor = SharedSurfaceDescriptor((uintptr_t)mSurf);
-  return true;
-}
-
 TemporaryRef<SyncObject>
 SyncObject::CreateSyncObject(SyncHandle aHandle)
 {
   if (!aHandle) {
     return nullptr;
   }
 
 #ifdef XP_WIN
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -3,17 +3,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_TEXTURECLIENT_H
 #define MOZILLA_GFX_TEXTURECLIENT_H
 
 #include <stddef.h>                     // for size_t
 #include <stdint.h>                     // for uint32_t, uint8_t, uint64_t
-#include "GLContextTypes.h"             // for GLContext (ptr only), etc
 #include "GLTextureImage.h"             // for TextureImage
 #include "ImageTypes.h"                 // for StereoMode
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/Attributes.h"         // for override
 #include "mozilla/RefPtr.h"             // for RefPtr, RefCounted
 #include "mozilla/gfx/2D.h"             // for DrawTarget
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat
@@ -27,20 +26,16 @@
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsISupportsImpl.h"            // for TextureImage::AddRef, etc
 #include "GfxTexturesReporter.h"
 
 class gfxImageSurface;
 
 namespace mozilla {
-namespace gl {
-class GLContext;
-class SharedSurface;
-}
 
 // When defined, we track which pool the tile came from and test for
 // any inconsistencies.  This can be defined in release build as well.
 #ifdef DEBUG
 #define GFX_DEBUG_TRACK_CLIENTS_IN_POOL 1
 #endif
 
 namespace layers {
@@ -471,19 +466,23 @@ public:
    /**
     * This sets the readback sink that this texture is to use. This will
     * receive the data for this texture as soon as it becomes available after
     * texture unlock.
     */
    virtual void SetReadbackSink(TextureReadbackSink* aReadbackSink) {
      mReadbackSink = aReadbackSink;
    }
-   
+
    virtual void SyncWithObject(SyncObject* aSyncObject) { }
 
+   void MarkShared() {
+     mShared = true;
+   }
+
 private:
   /**
    * Called once, just before the destructor.
    *
    * Here goes the shut-down code that uses virtual methods.
    * Must only be called by Release().
    */
   void Finalize();
@@ -685,76 +684,16 @@ public:
 
   virtual bool HasInternalBuffer() const override { return true; }
 
 protected:
   uint8_t* mBuffer;
   size_t mBufSize;
 };
 
-/**
- * A TextureClient implementation to share SharedSurfaces.
- */
-class SharedSurfaceTextureClient : public TextureClient
-{
-public:
-  SharedSurfaceTextureClient(ISurfaceAllocator* aAllocator, TextureFlags aFlags,
-                             gl::SharedSurface* surf);
-
-protected:
-  ~SharedSurfaceTextureClient();
-
-public:
-  // Boilerplate start
-  virtual bool IsAllocated() const override { return true; }
-
-  virtual bool Lock(OpenMode) override {
-    MOZ_ASSERT(!mIsLocked);
-    mIsLocked = true;
-    return true;
-  }
-
-  virtual void Unlock() override {
-    MOZ_ASSERT(mIsLocked);
-    mIsLocked = false;
-  }
-
-  virtual bool IsLocked() const override { return mIsLocked; }
-
-  virtual bool HasInternalBuffer() const override { return false; }
-
-  virtual gfx::SurfaceFormat GetFormat() const override {
-    return gfx::SurfaceFormat::UNKNOWN;
-  }
-
-  virtual gfx::IntSize GetSize() const override { return gfx::IntSize(); }
-
-  // This TextureClient should not be used in a context where we use CreateSimilar
-  // (ex. component alpha) because the underlying texture data is always created by
-  // an external producer.
-  virtual TemporaryRef<TextureClient>
-  CreateSimilar(TextureFlags, TextureAllocationFlags) const override {
-    return nullptr;
-  }
-
-  virtual bool AllocateForSurface(gfx::IntSize,
-                                  TextureAllocationFlags) override {
-    MOZ_CRASH("Should never hit this.");
-    return false;
-  }
-  // Boilerplate end
-
-  virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) override;
-
-protected:
-  bool mIsLocked;
-  gl::SharedSurface* const mSurf;
-  RefPtr<gl::GLContext> mGL; // Just for reference holding.
-};
-
 struct TextureClientAutoUnlock
 {
   TextureClient* mTexture;
 
   explicit TextureClientAutoUnlock(TextureClient* aTexture)
   : mTexture(aTexture) {}
 
   ~TextureClientAutoUnlock()
new file mode 100644
--- /dev/null
+++ b/gfx/layers/client/TextureClientSharedSurface.cpp
@@ -0,0 +1,45 @@
+/* -*- 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 "TextureClientSharedSurface.h"
+
+#include "GLContext.h"
+#include "mozilla/gfx/2D.h"
+#include "mozilla/gfx/Logging.h"        // for gfxDebug
+#include "mozilla/layers/ISurfaceAllocator.h"
+#include "mozilla/unused.h"
+#include "nsThreadUtils.h"
+#include "SharedSurface.h"
+
+namespace mozilla {
+namespace layers {
+
+SharedSurfaceTextureClient::SharedSurfaceTextureClient(ISurfaceAllocator* aAllocator,
+                                                       TextureFlags aFlags,
+                                                       UniquePtr<gl::SharedSurface> surf,
+                                                       gl::SurfaceFactory* factory)
+  : TextureClient(aAllocator, aFlags | TextureFlags::RECYCLE)
+  , mSurf(Move(surf))
+{ }
+
+SharedSurfaceTextureClient::~SharedSurfaceTextureClient()
+{
+  // Free the ShSurf implicitly.
+}
+
+gfx::IntSize
+SharedSurfaceTextureClient::GetSize() const
+{
+  return mSurf->mSize;
+}
+
+bool
+SharedSurfaceTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
+{
+  return mSurf->ToSurfaceDescriptor(&aOutDescriptor);
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/client/TextureClientSharedSurface.h
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZILLA_GFX_TEXTURECLIENT_SHAREDSURFACE_H
+#define MOZILLA_GFX_TEXTURECLIENT_SHAREDSURFACE_H
+
+#include <cstddef>                      // for size_t
+#include <stdint.h>                     // for uint32_t, uint8_t, uint64_t
+#include "GLContextTypes.h"             // for GLContext (ptr only), etc
+#include "TextureClient.h"
+#include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
+#include "mozilla/RefPtr.h"             // for RefPtr, RefCounted
+#include "mozilla/gfx/Point.h"          // for IntSize
+#include "mozilla/gfx/Types.h"          // for SurfaceFormat
+#include "mozilla/layers/CompositorTypes.h"  // for TextureFlags, etc
+#include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
+
+namespace mozilla {
+namespace gl {
+class GLContext;
+class SharedSurface;
+class SurfaceFactory;
+}
+
+namespace layers {
+
+class SharedSurfaceTextureClient : public TextureClient
+{
+protected:
+  const UniquePtr<gl::SharedSurface> mSurf;
+
+  friend class gl::SurfaceFactory;
+
+  SharedSurfaceTextureClient(ISurfaceAllocator* aAllocator, TextureFlags aFlags,
+                             UniquePtr<gl::SharedSurface> surf,
+                             gl::SurfaceFactory* factory);
+
+  ~SharedSurfaceTextureClient();
+
+public:
+  virtual bool IsAllocated() const override { return true; }
+  virtual bool Lock(OpenMode) override { return false; }
+  virtual bool IsLocked() const override { return false; }
+  virtual bool HasInternalBuffer() const override { return false; }
+
+  virtual gfx::SurfaceFormat GetFormat() const override {
+    return gfx::SurfaceFormat::UNKNOWN;
+  }
+
+  virtual TemporaryRef<TextureClient>
+  CreateSimilar(TextureFlags, TextureAllocationFlags) const override {
+    return nullptr;
+  }
+
+  virtual bool AllocateForSurface(gfx::IntSize,
+                                  TextureAllocationFlags) override {
+    MOZ_CRASH("Should never hit this.");
+    return false;
+  }
+
+  virtual gfx::IntSize GetSize() const override;
+
+  virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) override;
+
+  gl::SharedSurface* Surf() const {
+    return mSurf.get();
+  }
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // MOZILLA_GFX_TEXTURECLIENT_SHAREDSURFACE_H
--- a/gfx/layers/composite/FPSCounter.cpp
+++ b/gfx/layers/composite/FPSCounter.cpp
@@ -20,17 +20,16 @@
 #include "nsDirectoryServiceDefs.h"     // for NS_OS_TMP_DIR
 #include "prprf.h"                      // for PR_snprintf
 #include "FPSCounter.h"
 
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gfx;
-using namespace mozilla::gl;
 
 FPSCounter::FPSCounter(const char* aName)
   : mWriteIndex(0)
   , mIteratorIndex(-1)
   , mFPSName(aName)
 {
   Init();
 }
@@ -391,17 +390,17 @@ static void DrawDigits(unsigned int aVal
     divisor /= 10;
 
     RefPtr<TexturedEffect> texturedEffect = static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
     texturedEffect->mTextureCoords = Rect(float(digit * FontWidth) / textureWidth, 0, FontWidth / textureWidth, 1.0f);
 
     Rect drawRect = Rect(aOffsetX + n * FontWidth, aOffsetY, FontWidth, FontHeight);
     Rect clipRect = Rect(0, 0, 300, 100);
     aCompositor->DrawQuad(drawRect, clipRect,
-	aEffectChain, opacity, transform);
+  aEffectChain, opacity, transform);
   }
 }
 
 void FPSState::DrawFPS(TimeStamp aNow,
                        int aOffsetX, int aOffsetY,
                        unsigned int aFillRatio,
                        Compositor* aCompositor)
 {
--- a/gfx/layers/composite/ImageHost.cpp
+++ b/gfx/layers/composite/ImageHost.cpp
@@ -29,18 +29,17 @@ class ISurfaceAllocator;
 
 ImageHost::ImageHost(const TextureInfo& aTextureInfo)
   : CompositableHost(aTextureInfo)
   , mHasPictureRect(false)
   , mLocked(false)
 {}
 
 ImageHost::~ImageHost()
-{
-}
+{}
 
 void
 ImageHost::UseTextureHost(TextureHost* aTexture)
 {
   CompositableHost::UseTextureHost(aTexture);
   mFrontBuffer = aTexture;
   if (mFrontBuffer) {
     mFrontBuffer->Updated();
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -17,43 +17,37 @@
 #include "mozilla/layers/TextureHostOGL.h"  // for TextureHostOGL
 #include "mozilla/layers/YCbCrImageDataSerializer.h"
 #include "nsAString.h"
 #include "nsRefPtr.h"                   // for nsRefPtr
 #include "nsPrintfCString.h"            // for nsPrintfCString
 #include "mozilla/layers/PTextureParent.h"
 #include "mozilla/unused.h"
 #include <limits>
-#include "SharedSurface.h"
-#include "SharedSurfaceEGL.h"
-#include "SharedSurfaceGL.h"
 #include "../opengl/CompositorOGL.h"
 #include "gfxUtils.h"
 
 #ifdef MOZ_ENABLE_D3D10_LAYER
 #include "../d3d11/CompositorD3D11.h"
 #endif
 
 #ifdef MOZ_WIDGET_GONK
 #include "../opengl/GrallocTextureClient.h"
 #include "../opengl/GrallocTextureHost.h"
-#include "SharedSurfaceGralloc.h"
 #endif
 
 #ifdef MOZ_X11
 #include "mozilla/layers/X11TextureHost.h"
 #endif
 
 #ifdef XP_MACOSX
-#include "SharedSurfaceIO.h"
 #include "../opengl/MacIOSurfaceTextureHostOGL.h"
 #endif
 
 #ifdef XP_WIN
-#include "SharedSurfaceANGLE.h"
 #include "mozilla/layers/TextureDIB.h"
 #endif
 
 #if 0
 #define RECYCLE_LOG(...) printf_stderr(__VA_ARGS__)
 #else
 #define RECYCLE_LOG(...) do { } while (0)
 #endif
@@ -91,16 +85,18 @@ public:
 
   void ClearTextureHost();
 
   CompositableParentManager* mCompositableManager;
   RefPtr<TextureHost> mWaitForClientRecycle;
   RefPtr<TextureHost> mTextureHost;
 };
 
+////////////////////////////////////////////////////////////////////////////////
+
 // static
 PTextureParent*
 TextureHost::CreateIPDLActor(CompositableParentManager* aManager,
                              const SurfaceDescriptor& aSharedData,
                              TextureFlags aFlags)
 {
   if (aSharedData.type() == SurfaceDescriptor::TSurfaceDescriptorMemory &&
       !aManager->IsSameProcess())
@@ -212,19 +208,16 @@ TextureHost::Create(const SurfaceDescrip
     case SurfaceDescriptor::TSurfaceDescriptorFileMapping:
       return CreateBackendIndependentTextureHost(aDesc, aDeallocator, aFlags);
 
     case SurfaceDescriptor::TEGLImageDescriptor:
     case SurfaceDescriptor::TNewSurfaceDescriptorGralloc:
     case SurfaceDescriptor::TSurfaceTextureDescriptor:
       return CreateTextureHostOGL(aDesc, aDeallocator, aFlags);
 
-    case SurfaceDescriptor::TSharedSurfaceDescriptor:
-      return MakeAndAddRef<SharedSurfaceTextureHost>(aFlags, aDesc.get_SharedSurfaceDescriptor());
-
     case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface:
       if (Compositor::GetBackend() == LayersBackend::LAYERS_OPENGL) {
         return CreateTextureHostOGL(aDesc, aDeallocator, aFlags);
       } else {
         return CreateTextureHostBasic(aDesc, aDeallocator, aFlags);
       }
 
 #ifdef MOZ_X11
@@ -872,157 +865,10 @@ TextureParent::RecvRecycleTexture(const 
     return true;
   }
   mTextureHost->RecycleTexture(aTextureFlags);
   return true;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
-static RefPtr<TextureSource>
-SharedSurfaceToTexSource(gl::SharedSurface* abstractSurf, Compositor* compositor)
-{
-  MOZ_ASSERT(abstractSurf);
-  MOZ_ASSERT(abstractSurf->mType != gl::SharedSurfaceType::Basic);
-  MOZ_ASSERT(abstractSurf->mType != gl::SharedSurfaceType::Gralloc);
-
-  if (!compositor) {
-    return nullptr;
-  }
-
-  gfx::SurfaceFormat format = abstractSurf->mHasAlpha ? gfx::SurfaceFormat::R8G8B8A8
-                                                      : gfx::SurfaceFormat::R8G8B8X8;
-
-  RefPtr<TextureSource> texSource;
-  switch (abstractSurf->mType) {
-#ifdef XP_WIN
-    case gl::SharedSurfaceType::EGLSurfaceANGLE: {
-      auto surf = gl::SharedSurface_ANGLEShareHandle::Cast(abstractSurf);
-
-      MOZ_ASSERT(compositor->GetBackendType() == LayersBackend::LAYERS_D3D11);
-      CompositorD3D11* compositorD3D11 = static_cast<CompositorD3D11*>(compositor);
-      RefPtr<ID3D11Texture2D> tex = surf->GetConsumerTexture();
-
-      if (!tex) {
-        NS_WARNING("Failed to open shared resource.");
-        break;
-      }
-      texSource = new DataTextureSourceD3D11(format, compositorD3D11, tex);
-      break;
-    }
-#endif
-    case gl::SharedSurfaceType::GLTextureShare: {
-      auto surf = gl::SharedSurface_GLTexture::Cast(abstractSurf);
-
-      MOZ_ASSERT(compositor->GetBackendType() == LayersBackend::LAYERS_OPENGL);
-      CompositorOGL* compositorOGL = static_cast<CompositorOGL*>(compositor);
-      gl::GLContext* gl = compositorOGL->gl();
-
-      GLenum target = surf->ConsTextureTarget();
-      GLuint tex = surf->ConsTexture(gl);
-      texSource = new GLTextureSource(compositorOGL, tex, target,
-                                      surf->mSize, format,
-                                      true/*externally owned*/);
-      break;
-    }
-    case gl::SharedSurfaceType::EGLImageShare: {
-      auto surf = gl::SharedSurface_EGLImage::Cast(abstractSurf);
-
-      MOZ_ASSERT(compositor->GetBackendType() == LayersBackend::LAYERS_OPENGL);
-      CompositorOGL* compositorOGL = static_cast<CompositorOGL*>(compositor);
-      gl::GLContext* gl = compositorOGL->gl();
-      MOZ_ASSERT(gl->IsCurrent());
-
-      GLenum target = 0;
-      GLuint tex = 0;
-      surf->AcquireConsumerTexture(gl, &tex, &target);
-
-      texSource = new GLTextureSource(compositorOGL, tex, target,
-                                      surf->mSize, format,
-                                      true/*externally owned*/);
-      break;
-    }
-#ifdef XP_MACOSX
-    case gl::SharedSurfaceType::IOSurface: {
-      auto surf = gl::SharedSurface_IOSurface::Cast(abstractSurf);
-      MacIOSurface* ioSurf = surf->GetIOSurface();
-
-      MOZ_ASSERT(compositor->GetBackendType() == LayersBackend::LAYERS_OPENGL);
-      CompositorOGL* compositorOGL = static_cast<CompositorOGL*>(compositor);
-
-      texSource = new MacIOSurfaceTextureSourceOGL(compositorOGL, ioSurf);
-      break;
-    }
-#endif
-    default:
-      break;
-  }
-
-  MOZ_ASSERT(texSource.get(), "TextureSource creation failed.");
-  return texSource;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// SharedSurfaceTextureHost
-
-SharedSurfaceTextureHost::SharedSurfaceTextureHost(TextureFlags aFlags,
-                                                   const SharedSurfaceDescriptor& aDesc)
-  : TextureHost(aFlags)
-  , mIsLocked(false)
-  , mSurf((gl::SharedSurface*)aDesc.surf())
-  , mCompositor(nullptr)
-{
-  MOZ_ASSERT(mSurf);
-}
-
-gfx::SurfaceFormat
-SharedSurfaceTextureHost::GetFormat() const
-{
-  MOZ_ASSERT(mTexSource);
-  return mTexSource->GetFormat();
-}
-
-gfx::IntSize
-SharedSurfaceTextureHost::GetSize() const
-{
-  MOZ_ASSERT(mTexSource);
-  return mTexSource->GetSize();
-}
-
-void
-SharedSurfaceTextureHost::EnsureTexSource()
-{
-  MOZ_ASSERT(mIsLocked);
-
-  if (mTexSource)
-    return;
-
-  mTexSource = SharedSurfaceToTexSource(mSurf, mCompositor);
-  MOZ_ASSERT(mTexSource);
-}
-
-bool
-SharedSurfaceTextureHost::Lock()
-{
-  MOZ_ASSERT(!mIsLocked);
-
-  mSurf->ConsumerAcquire();
-
-  mIsLocked = true;
-
-  EnsureTexSource();
-
-  return true;
-}
-
-void
-SharedSurfaceTextureHost::Unlock()
-{
-  MOZ_ASSERT(mIsLocked);
-  mSurf->ConsumerRelease();
-  mIsLocked = false;
-}
-
-
-////////////////////////////////////////////////////////////////////////////////
-
 } // namespace
 } // namespace
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -26,29 +26,25 @@
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "nscore.h"                     // for nsACString
 #include "mozilla/layers/AtomicRefCountedWithFinalize.h"
 #include "mozilla/gfx/Rect.h"
 
 namespace mozilla {
-namespace gl {
-class SharedSurface;
-}
 namespace ipc {
 class Shmem;
 }
 
 namespace layers {
 
 class Compositor;
 class CompositableParentManager;
 class SurfaceDescriptor;
-class SharedSurfaceDescriptor;
 class ISurfaceAllocator;
 class TextureHostOGL;
 class TextureSourceOGL;
 class TextureSourceD3D9;
 class TextureSourceD3D11;
 class TextureSourceBasic;
 class DataTextureSource;
 class PTextureParent;
@@ -676,74 +672,16 @@ public:
   virtual size_t GetBufferSize() override;
 
   virtual const char *Name() override { return "MemoryTextureHost"; }
 
 protected:
   uint8_t* mBuffer;
 };
 
-/**
- * A TextureHost for SharedSurfaces
- */
-class SharedSurfaceTextureHost : public TextureHost
-{
-public:
-  SharedSurfaceTextureHost(TextureFlags aFlags,
-                           const SharedSurfaceDescriptor& aDesc);
-
-  virtual ~SharedSurfaceTextureHost() {
-    MOZ_ASSERT(!mIsLocked);
-  }
-
-  virtual void DeallocateDeviceData() override {};
-
-  virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() override {
-    return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
-  }
-
-  virtual void SetCompositor(Compositor* aCompositor) override {
-    MOZ_ASSERT(!mIsLocked);
-
-    if (aCompositor == mCompositor)
-      return;
-
-    mTexSource = nullptr;
-    mCompositor = aCompositor;
-  }
-
-public:
-
-  virtual bool Lock() override;
-  virtual void Unlock() override;
-
-  virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override {
-    MOZ_ASSERT(mIsLocked);
-    MOZ_ASSERT(mTexSource);
-    aTexture = mTexSource;
-    return !!aTexture;
-  }
-
-  virtual gfx::SurfaceFormat GetFormat() const override;
-
-  virtual gfx::IntSize GetSize() const override;
-
-#ifdef MOZ_LAYERS_HAVE_LOG
-  virtual const char* Name() override { return "SharedSurfaceTextureHost"; }
-#endif
-
-protected:
-  void EnsureTexSource();
-
-  bool mIsLocked;
-  gl::SharedSurface* const mSurf;
-  RefPtr<Compositor> mCompositor;
-  RefPtr<TextureSource> mTexSource;
-};
-
 class MOZ_STACK_CLASS AutoLockTextureHost
 {
 public:
   explicit AutoLockTextureHost(TextureHost* aTexture)
     : mTexture(aTexture)
   {
     mLocked = mTexture ? mTexture->Lock() : false;
   }
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -798,16 +798,28 @@ CompositorParent::RecvMakeSnapshot(const
                                    const gfx::IntRect& aRect)
 {
   RefPtr<DrawTarget> target = GetDrawTargetForDescriptor(aInSnapshot, gfx::BackendType::CAIRO);
   ForceComposeToTarget(target, &aRect);
   return true;
 }
 
 bool
+CompositorParent::RecvMakeWidgetSnapshot(const SurfaceDescriptor& aInSnapshot)
+{
+  if (!mCompositor || !mCompositor->GetWidget()) {
+    return false;
+  }
+
+  RefPtr<DrawTarget> target = GetDrawTargetForDescriptor(aInSnapshot, gfx::BackendType::CAIRO);
+  mCompositor->GetWidget()->CaptureWidgetOnScreen(target);
+  return true;
+}
+
+bool
 CompositorParent::RecvFlushRendering()
 {
   if (mCompositorScheduler->NeedsComposite())
   {
     CancelCurrentCompositeTask();
     ForceComposeToTarget(nullptr);
   }
   return true;
@@ -1683,16 +1695,18 @@ public:
   virtual bool RecvResume() override { return true; }
   virtual bool RecvNotifyHidden(const uint64_t& id) override;
   virtual bool RecvNotifyVisible(const uint64_t& id) override;
   virtual bool RecvNotifyChildCreated(const uint64_t& child) override;
   virtual bool RecvAdoptChild(const uint64_t& child) override { return false; }
   virtual bool RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
                                 const gfx::IntRect& aRect) override
   { return true; }
+  virtual bool RecvMakeWidgetSnapshot(const SurfaceDescriptor& aInSnapshot) override
+  { return true; }
   virtual bool RecvFlushRendering() override { return true; }
   virtual bool RecvNotifyRegionInvalidated(const nsIntRegion& aRegion) override { return true; }
   virtual bool RecvStartFrameTimeRecording(const int32_t& aBufferSize, uint32_t* aOutStartIndex) override { return true; }
   virtual bool RecvStopFrameTimeRecording(const uint32_t& aStartIndex, InfallibleTArray<float>* intervals) override  { return true; }
   virtual bool RecvGetTileSize(int32_t* aWidth, int32_t* aHeight) override
   {
     *aWidth = gfxPlatform::GetPlatform()->GetTileWidth();
     *aHeight = gfxPlatform::GetPlatform()->GetTileHeight();
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -235,16 +235,17 @@ public:
   virtual bool RecvPause() override;
   virtual bool RecvResume() override;
   virtual bool RecvNotifyHidden(const uint64_t& id) override { return true; }
   virtual bool RecvNotifyVisible(const uint64_t& id) override { return true; }
   virtual bool RecvNotifyChildCreated(const uint64_t& child) override;
   virtual bool RecvAdoptChild(const uint64_t& child) override;
   virtual bool RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
                                 const gfx::IntRect& aRect) override;
+  virtual bool RecvMakeWidgetSnapshot(const SurfaceDescriptor& aInSnapshot) override;
   virtual bool RecvFlushRendering() override;
 
   virtual bool RecvGetTileSize(int32_t* aWidth, int32_t* aHeight) override;
 
   virtual bool RecvNotifyRegionInvalidated(const nsIntRegion& aRegion) override;
   virtual bool RecvStartFrameTimeRecording(const int32_t& aBufferSize, uint32_t* aOutStartIndex) override;
   virtual bool RecvStopFrameTimeRecording(const uint32_t& aStartIndex, InfallibleTArray<float>* intervals) override;
 
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -346,34 +346,34 @@ void ImageBridgeChild::DispatchReleaseIm
   sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
     FROM_HERE,
     NewRunnableFunction(&ReleaseImageClientNow, aClient));
 }
 
 static void ReleaseTextureClientNow(TextureClient* aClient)
 {
   MOZ_ASSERT(InImageBridgeChildThread());
-  aClient->Release();
+  RELEASE_MANUALLY(aClient);
 }
 
 // static
 void ImageBridgeChild::DispatchReleaseTextureClient(TextureClient* aClient)
 {
   if (!aClient) {
     return;
   }
 
   if (!IsCreated()) {
     // TextureClient::Release should normally happen in the ImageBridgeChild
     // thread because it usually generate some IPDL messages.
     // However, if we take this branch it means that the ImageBridgeChild
     // has already shut down, along with the TextureChild, which means no
     // message will be sent and it is safe to run this code from any thread.
     MOZ_ASSERT(aClient->GetIPDLActor() == nullptr);
-    aClient->Release();
+    RELEASE_MANUALLY(aClient);
     return;
   }
 
   sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
     FROM_HERE,
     NewRunnableFunction(&ReleaseTextureClientNow, aClient));
 }
 
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -201,29 +201,29 @@ bool ImageBridgeParent::RecvWillStop()
     tex->DeallocateDeviceData();
   }
   return true;
 }
 
 static void
 ReleaseImageBridgeParent(ImageBridgeParent* aImageBridgeParent)
 {
-  aImageBridgeParent->Release();
+  RELEASE_MANUALLY(aImageBridgeParent);
 }
 
 bool ImageBridgeParent::RecvStop()
 {
   // This message just serves as synchronization between the
   // child and parent threads during shutdown.
 
   // There is one thing that we need to do here: temporarily addref, so that
   // the handling of this sync message can't race with the destruction of
   // the ImageBridgeParent, which would trigger the dreaded "mismatched CxxStackFrames"
   // assertion of MessageChannel.
-  AddRef();
+  ADDREF_MANUALLY(this);
   MessageLoop::current()->PostTask(
     FROM_HERE,
     NewRunnableFunction(&ReleaseImageBridgeParent, this));
   return true;
 }
 
 static  uint64_t GenImageContainerID() {
   static uint64_t sNextImageID = 1;
--- a/gfx/layers/ipc/LayerTransactionParent.h
+++ b/gfx/layers/ipc/LayerTransactionParent.h
@@ -157,22 +157,22 @@ protected:
 
   bool Attach(ShadowLayerParent* aLayerParent,
               CompositableHost* aCompositable,
               bool aIsAsyncVideo);
 
   void AddIPDLReference() {
     MOZ_ASSERT(mIPCOpen == false);
     mIPCOpen = true;
-    AddRef();
+    ADDREF_MANUALLY(this);
   }
   void ReleaseIPDLReference() {
     MOZ_ASSERT(mIPCOpen == true);
     mIPCOpen = false;
-    Release();
+    RELEASE_MANUALLY(this);
   }
   friend class CompositorParent;
   friend class CrossProcessCompositorParent;
   friend class layout::RenderFrameParent;
 
 private:
   nsRefPtr<LayerManagerComposite> mLayerManager;
   ShadowLayersManager* mShadowLayersManager;
--- a/gfx/layers/ipc/LayersSurfaces.ipdlh
+++ b/gfx/layers/ipc/LayersSurfaces.ipdlh
@@ -60,59 +60,56 @@ struct SurfaceDescriptorDXGIYCbCr {
   WindowsHandle handleCb;
   WindowsHandle handleCr;
   IntSize size;
   IntSize sizeY;
   IntSize sizeCbCr;
 };
 
 struct SurfaceDescriptorMacIOSurface {
-  uint32_t surface;
+  uint32_t surfaceId;
   double scaleFactor;
   bool isOpaque;
 };
 
 struct SurfaceTextureDescriptor {
   uintptr_t surfTex;
   IntSize size;
 };
 
 struct EGLImageDescriptor {
   uintptr_t image; // `EGLImage` is a `void*`.
   uintptr_t fence;
   IntSize size;
+  bool hasAlpha;
 };
 
 struct NewSurfaceDescriptorGralloc {
   MaybeMagicGrallocBufferHandle buffer;
   /**
    * android::GraphicBuffer has a size information. But there are cases
    * that GraphicBuffer's size and actual video's size are different.
    * Extra size member is necessary. See Bug 850566.
    */
   IntSize size;
   bool isOpaque;
 };
 
-struct SharedSurfaceDescriptor {
-  uintptr_t surf;
-};
-
 /**
  * Used for shmem-backed YCbCr and (flavors of) RGBA textures
  */
 struct SurfaceDescriptorShmem {
   Shmem data;
   SurfaceFormat format;
 };
 
 /**
  * Used for "raw memory"-backed YCbCr and (flavors of) RGBA textures
  */
- struct SurfaceDescriptorMemory {
+struct SurfaceDescriptorMemory {
   uintptr_t data;
   SurfaceFormat format;
 };
 
 union SurfaceDescriptor {
   SurfaceDescriptorShmem;
   SurfaceDescriptorMemory;
   SurfaceDescriptorD3D9;
@@ -120,14 +117,13 @@ union SurfaceDescriptor {
   SurfaceDescriptorD3D10;
   SurfaceDescriptorFileMapping;
   SurfaceDescriptorDXGIYCbCr;
   SurfaceDescriptorX11;
   SurfaceTextureDescriptor;
   EGLImageDescriptor;
   SurfaceDescriptorMacIOSurface;
   NewSurfaceDescriptorGralloc;
-  SharedSurfaceDescriptor;
   null_t;
 };
 
 } // namespace
 } // namespace
--- a/gfx/layers/ipc/PCompositor.ipdl
+++ b/gfx/layers/ipc/PCompositor.ipdl
@@ -106,16 +106,24 @@ parent:
   // render target at the time this message is received.  If the size
   // or format of |inSnapshot| doesn't match our render target,
   // results are undefined.
   //
   // NB: this message will result in animations, transforms, effects,
   // and so forth being interpolated.  That's what we want to happen.
   sync MakeSnapshot(SurfaceDescriptor inSnapshot, IntRect dirtyRect);
 
+  // Same as Makesnapshot(), except the snapshot is read from the underlying
+  // operating system desktop rather than the compositor's backbuffer. This
+  // is intended for testing whether hardware acceleration works.
+  //
+  // This call is part of IPDL, even though it simply wraps an nsIWidget
+  // call, to make sure it does not occur in the middle of a composite.
+  sync MakeWidgetSnapshot(SurfaceDescriptor inSnapshot);
+
   // Make sure any pending composites are started immediately and
   // block until they are completed.
   sync FlushRendering();
 
   // Get the size of the tiles. This number should not change at runtime.
   sync GetTileSize()
     returns (int32_t tileWidth, int32_t tileHeight);
 
--- a/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
+++ b/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
@@ -32,17 +32,20 @@ SharedPlanarYCbCrImage::SharedPlanarYCbC
   MOZ_COUNT_CTOR(SharedPlanarYCbCrImage);
 }
 
 SharedPlanarYCbCrImage::~SharedPlanarYCbCrImage() {
   MOZ_COUNT_DTOR(SharedPlanarYCbCrImage);
 
   if (mCompositable->GetAsyncID() != 0 &&
       !InImageBridgeChildThread()) {
-    ImageBridgeChild::DispatchReleaseTextureClient(mTextureClient.forget().take());
+    ADDREF_MANUALLY(mTextureClient);
+    ImageBridgeChild::DispatchReleaseTextureClient(mTextureClient);
+    mTextureClient = nullptr;
+
     ImageBridgeChild::DispatchReleaseImageClient(mCompositable.forget().take());
   }
 }
 
 size_t
 SharedPlanarYCbCrImage::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
 {
   // NB: Explicitly skipping mTextureClient, the memory is already reported
--- a/gfx/layers/ipc/SharedRGBImage.cpp
+++ b/gfx/layers/ipc/SharedRGBImage.cpp
@@ -64,17 +64,20 @@ SharedRGBImage::SharedRGBImage(ImageClie
 }
 
 SharedRGBImage::~SharedRGBImage()
 {
   MOZ_COUNT_DTOR(SharedRGBImage);
 
   if (mCompositable->GetAsyncID() != 0 &&
       !InImageBridgeChildThread()) {
-    ImageBridgeChild::DispatchReleaseTextureClient(mTextureClient.forget().take());
+    ADDREF_MANUALLY(mTextureClient);
+    ImageBridgeChild::DispatchReleaseTextureClient(mTextureClient);
+    mTextureClient = nullptr;
+
     ImageBridgeChild::DispatchReleaseImageClient(mCompositable.forget().take());
   }
 }
 
 bool
 SharedRGBImage::Allocate(gfx::IntSize aSize, gfx::SurfaceFormat aFormat)
 {
   mSize = aSize;
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -113,16 +113,17 @@ EXPORTS.mozilla.layers += [
     'basic/TextureHostBasic.h',
     'client/CanvasClient.h',
     'client/CompositableClient.h',
     'client/ContentClient.h',
     'client/ImageClient.h',
     'client/TextureClient.h',
     'client/TextureClientPool.h',
     'client/TextureClientRecycleAllocator.h',
+    'client/TextureClientSharedSurface.h',
     'client/TiledContentClient.h',
     'composite/AsyncCompositionManager.h',
     'composite/CanvasLayerComposite.h',
     'composite/ColorLayerComposite.h',
     'composite/ContainerLayerComposite.h',
     'composite/ContentHost.h',
     'composite/ImageHost.h',
     'composite/ImageLayerComposite.h',
@@ -262,16 +263,17 @@ UNIFIED_SOURCES += [
     'client/ClientPaintedLayer.cpp',
     'client/ClientTiledPaintedLayer.cpp',
     'client/CompositableClient.cpp',
     'client/ContentClient.cpp',
     'client/ImageClient.cpp',
     'client/TextureClient.cpp',
     'client/TextureClientPool.cpp',
     'client/TextureClientRecycleAllocator.cpp',
+    'client/TextureClientSharedSurface.cpp',
     'client/TiledContentClient.cpp',
     'composite/AsyncCompositionManager.cpp',
     'composite/CanvasLayerComposite.cpp',
     'composite/ColorLayerComposite.cpp',
     'composite/CompositableHost.cpp',
     'composite/ContainerLayerComposite.cpp',
     'composite/ContentHost.cpp',
     'composite/FPSCounter.cpp',
--- a/gfx/layers/opengl/GrallocTextureClient.h
+++ b/gfx/layers/opengl/GrallocTextureClient.h
@@ -14,16 +14,20 @@
 #include <ui/GraphicBuffer.h>
 
 
 namespace android {
 class MediaBuffer;
 };
 
 namespace mozilla {
+namespace gl {
+class SharedSurface;
+}
+
 namespace layers {
 
 /**
  * A TextureClient implementation based on android::GraphicBuffer (also referred to
  * as "gralloc").
  *
  * Gralloc lets us map texture data in memory (accessible through pointers)
  * and also use it directly as an OpenGL texture without the cost of texture
--- a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp
+++ b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp
@@ -9,17 +9,17 @@
 
 namespace mozilla {
 namespace layers {
 
 MacIOSurfaceTextureHostOGL::MacIOSurfaceTextureHostOGL(TextureFlags aFlags,
                                                        const SurfaceDescriptorMacIOSurface& aDescriptor)
   : TextureHost(aFlags)
 {
-  mSurface = MacIOSurface::LookupSurface(aDescriptor.surface(),
+  mSurface = MacIOSurface::LookupSurface(aDescriptor.surfaceId(),
                                          aDescriptor.scaleFactor(),
                                          !aDescriptor.isOpaque());
 }
 
 bool
 MacIOSurfaceTextureHostOGL::Lock()
 {
   if (!mCompositor || !mSurface) {
--- a/gfx/layers/opengl/TextureClientOGL.cpp
+++ b/gfx/layers/opengl/TextureClientOGL.cpp
@@ -41,17 +41,19 @@ EGLImageTextureClient::EGLImageTextureCl
 
 bool
 EGLImageTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
 {
   MOZ_ASSERT(IsValid());
   MOZ_ASSERT(IsAllocated());
 
   const EGLImageImage::Data* data = mImage->GetData();
-  aOutDescriptor = EGLImageDescriptor((uintptr_t)data->mImage, (uintptr_t)data->mSync, mSize);
+  const bool hasAlpha = true;
+  aOutDescriptor = EGLImageDescriptor((uintptr_t)data->mImage, (uintptr_t)data->mSync,
+                                      mSize, hasAlpha);
   return true;
 }
 
 bool
 EGLImageTextureClient::Lock(OpenMode mode)
   {
     MOZ_ASSERT(!mIsLocked);
     if (!IsValid() || !IsAllocated()) {
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -10,32 +10,34 @@
 #include "GLLibraryEGL.h"               // for GLLibraryEGL
 #include "GLUploadHelpers.h"
 #include "GLReadTexImageHelper.h"
 #include "gfx2DGlue.h"                  // for ContentForFormat, etc
 #include "gfxReusableSurfaceWrapper.h"  // for gfxReusableSurfaceWrapper
 #include "mozilla/gfx/2D.h"             // for DataSourceSurface
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/gfx/Logging.h"        // for gfxCriticalError
-#ifdef MOZ_WIDGET_GONK
-# include "GrallocImages.h"  // for GrallocImage
-# include "EGLImageHelpers.h"
-#endif
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/layers/YCbCrImageDataSerializer.h"
 #include "mozilla/layers/GrallocTextureHost.h"
 #include "nsRegion.h"                   // for nsIntRegion
 #include "AndroidSurfaceTexture.h"
 #include "GfxTexturesReporter.h"        // for GfxTexturesReporter
 #include "GLBlitTextureImageHelper.h"
+#include "GeckoProfiler.h"
+
+#ifdef MOZ_WIDGET_GONK
+# include "GrallocImages.h"  // for GrallocImage
+# include "EGLImageHelpers.h"
+#endif
+
 #ifdef XP_MACOSX
-#include "SharedSurfaceIO.h"
 #include "mozilla/layers/MacIOSurfaceTextureHostOGL.h"
 #endif
-#include "GeckoProfiler.h"
+
 
 using namespace mozilla::gl;
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 class Compositor;
@@ -64,17 +66,18 @@ CreateTextureHostOGL(const SurfaceDescri
     }
 #endif
 
     case SurfaceDescriptor::TEGLImageDescriptor: {
       const EGLImageDescriptor& desc = aDesc.get_EGLImageDescriptor();
       result = new EGLImageTextureHost(aFlags,
                                        (EGLImage)desc.image(),
                                        (EGLSync)desc.fence(),
-                                       desc.size());
+                                       desc.size(),
+                                       desc.hasAlpha());
       break;
     }
 
 #ifdef XP_MACOSX
     case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: {
       const SurfaceDescriptorMacIOSurface& desc =
         aDesc.get_SurfaceDescriptorMacIOSurface();
       result = new MacIOSurfaceTextureHostOGL(aFlags, desc);
@@ -489,36 +492,37 @@ EGLImageTextureSource::EGLImageTextureSo
                                              gfx::IntSize aSize)
   : mCompositor(aCompositor)
   , mImage(aImage)
   , mFormat(aFormat)
   , mTextureTarget(aTarget)
   , mWrapMode(aWrapMode)
   , mSize(aSize)
 {
+  MOZ_ASSERT(mTextureTarget == LOCAL_GL_TEXTURE_2D ||
+             mTextureTarget == LOCAL_GL_TEXTURE_EXTERNAL);
 }
 
 void
 EGLImageTextureSource::BindTexture(GLenum aTextureUnit, gfx::Filter aFilter)
 {
   if (!gl()) {
     NS_WARNING("Trying to bind a texture without a GLContext");
     return;
   }
 
   MOZ_ASSERT(DoesEGLContextSupportSharingWithEGLImage(gl()),
              "EGLImage not supported or disabled in runtime");
 
-  GLuint tex = mCompositor->GetTemporaryTexture(GetTextureTarget(), aTextureUnit);
+  GLuint tex = mCompositor->GetTemporaryTexture(mTextureTarget, aTextureUnit);
 
   gl()->fActiveTexture(aTextureUnit);
   gl()->fBindTexture(mTextureTarget, tex);
 
-  MOZ_ASSERT(mTextureTarget == LOCAL_GL_TEXTURE_2D);
-  gl()->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, mImage);
+  gl()->fEGLImageTargetTexture2D(mTextureTarget, mImage);
 
   ApplyFilterToBoundTexture(gl(), aFilter, mTextureTarget);
 }
 
 void
 EGLImageTextureSource::SetCompositor(Compositor* aCompositor)
 {
   MOZ_ASSERT(aCompositor);
@@ -544,50 +548,59 @@ EGLImageTextureSource::GetTextureTransfo
   return ret;
 }
 
 ////////////////////////////////////////////////////////////////////////
 
 EGLImageTextureHost::EGLImageTextureHost(TextureFlags aFlags,
                                          EGLImage aImage,
                                          EGLSync aSync,
-                                         gfx::IntSize aSize)
+                                         gfx::IntSize aSize,
+                                         bool hasAlpha)
   : TextureHost(aFlags)
   , mImage(aImage)
   , mSync(aSync)
   , mSize(aSize)
+  , mHasAlpha(hasAlpha)
   , mCompositor(nullptr)
-{
-}
+{}
 
 EGLImageTextureHost::~EGLImageTextureHost()
-{
-}
+{}
 
 gl::GLContext*
 EGLImageTextureHost::gl() const
 {
   return mCompositor ? mCompositor->gl() : nullptr;
 }
 
 bool
 EGLImageTextureHost::Lock()
 {
   if (!mCompositor) {
     return false;
   }
 
-  EGLint status = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(), mSync, 0, LOCAL_EGL_FOREVER);
+  EGLint status = LOCAL_EGL_CONDITION_SATISFIED;
+
+  if (mSync) {
+    MOZ_ASSERT(sEGLLibrary.IsExtensionSupported(GLLibraryEGL::KHR_fence_sync));
+    status = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(), mSync, 0, LOCAL_EGL_FOREVER);
+  }
+
   if (status != LOCAL_EGL_CONDITION_SATISFIED) {
+    MOZ_ASSERT(status != 0,
+               "ClientWaitSync generated an error. Has mSync already been destroyed?");
     return false;
   }
 
   if (!mTextureSource) {
-    gfx::SurfaceFormat format = gfx::SurfaceFormat::R8G8B8A8;
-    GLenum target = LOCAL_GL_TEXTURE_2D;
+    gfx::SurfaceFormat format = mHasAlpha ? gfx::SurfaceFormat::R8G8B8A8
+                                          : gfx::SurfaceFormat::R8G8B8X8;
+    GLenum target = LOCAL_GL_TEXTURE_EXTERNAL;
     GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE;
     mTextureSource = new EGLImageTextureSource(mCompositor,
                                                mImage,
                                                format,
                                                target,
                                                wrapMode,
                                                mSize);
   }
--- a/gfx/layers/opengl/TextureHostOGL.h
+++ b/gfx/layers/opengl/TextureHostOGL.h
@@ -420,17 +420,18 @@ protected:
 };
 
 class EGLImageTextureHost : public TextureHost
 {
 public:
   EGLImageTextureHost(TextureFlags aFlags,
                      EGLImage aImage,
                      EGLSync aSync,
-                     gfx::IntSize aSize);
+                     gfx::IntSize aSize,
+                     bool hasAlpha);
 
   virtual ~EGLImageTextureHost();
 
   // We don't own anything.
   virtual void DeallocateDeviceData() override {}
 
   virtual void SetCompositor(Compositor* aCompositor) override;
 
@@ -456,16 +457,17 @@ public:
   virtual gfx::IntSize GetSize() const override { return mSize; }
 
   virtual const char* Name() override { return "EGLImageTextureHost"; }
 
 protected:
   const EGLImage mImage;
   const EGLSync mSync;
   const gfx::IntSize mSize;
+  const bool mHasAlpha;
   RefPtr<CompositorOGL> mCompositor;
   RefPtr<EGLImageTextureSource> mTextureSource;
 };
 
 } // namespace
 } // namespace
 
 #endif /* MOZILLA_GFX_TEXTUREOGL_H */
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -386,17 +386,17 @@ gfxUtils::ConvertBGRAtoRGBA(uint8_t* aDa
 }
 
 static bool
 IsSafeImageTransformComponent(gfxFloat aValue)
 {
   return aValue >= -32768 && aValue <= 32767;
 }
 
-#if !defined(MOZ_GFX_OPTIMIZE_MOBILE) && !defined(MOZ_WIDGET_COCOA)
+#ifndef MOZ_GFX_OPTIMIZE_MOBILE
 /**
  * This returns the fastest operator to use for solid surfaces which have no
  * alpha channel or their alpha channel is uniformly opaque.
  * This differs per render mode.
  */
 static gfxContext::GraphicsOperator
 OptimalFillOperator()
 {
@@ -452,17 +452,17 @@ CreateSamplingRestrictedDrawable(gfxDraw
     tmpCtx->SetOperator(OptimalFillOperator());
     aDrawable->Draw(tmpCtx, needed - needed.TopLeft(), true,
                     GraphicsFilter::FILTER_FAST, 1.0, gfxMatrix::Translation(needed.TopLeft()));
     RefPtr<SourceSurface> surface = target->Snapshot();
 
     nsRefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(surface, size, gfxMatrix::Translation(-needed.TopLeft()));
     return drawable.forget();
 }
-#endif // !MOZ_GFX_OPTIMIZE_MOBILE && !MOZ_WIDGET_COCOA
+#endif // !MOZ_GFX_OPTIMIZE_MOBILE
 
 // working around cairo/pixman bug (bug 364968)
 // Our device-space-to-image-space transform may not be acceptable to pixman.
 struct MOZ_STACK_CLASS AutoCairoPixmanBugWorkaround
 {
     AutoCairoPixmanBugWorkaround(gfxContext*      aContext,
                                  const gfxMatrix& aDeviceSpaceToImageSpace,
                                  const gfxRect&   aFill,
@@ -647,17 +647,17 @@ gfxUtils::DrawPixelSnapped(gfxContext*  
             if (drawable->DrawWithSamplingRect(aContext, aRegion.Rect(), aRegion.Restriction(),
                                                doTile, aFilter, aOpacity)) {
               return;
             }
 
             // On Mobile, we don't ever want to do this; it has the potential for
             // allocating very large temporary surfaces, especially since we'll
             // do full-page snapshots often (see bug 749426).
-#if !defined(MOZ_GFX_OPTIMIZE_MOBILE) && !defined(MOZ_WIDGET_COCOA)
+#ifndef MOZ_GFX_OPTIMIZE_MOBILE
             nsRefPtr<gfxDrawable> restrictedDrawable =
               CreateSamplingRestrictedDrawable(aDrawable, aContext,
                                                aRegion, aFormat);
             if (restrictedDrawable) {
                 drawable.swap(restrictedDrawable);
             }
 
             // We no longer need to tile: Either we never needed to, or we already
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -696,94 +696,129 @@ js::CreateRegExpPrototype(JSContext* cx,
     HandlePropertyName empty = cx->names().empty;
     RegExpObjectBuilder builder(cx, proto);
     if (!builder.build(empty, RegExpFlag(0)))
         return nullptr;
 
     return proto;
 }
 
+static bool
+ReportLastIndexNonwritable(JSContext* cx)
+{
+    JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_READ_ONLY, "\"lastIndex\"");
+    return false;
+}
+
+static bool
+SetLastIndex(JSContext* cx, Handle<RegExpObject*> reobj, double lastIndex)
+{
+    if (!reobj->lookup(cx, cx->names().lastIndex)->writable())
+        return ReportLastIndexNonwritable(cx);
+
+    reobj->setLastIndex(lastIndex);
+    return true;
+}
+
+/* ES6 final draft 21.2.5.2.2. */
 RegExpRunStatus
 js::ExecuteRegExp(JSContext* cx, HandleObject regexp, HandleString string,
                   MatchPairs* matches, RegExpStaticsUpdate staticsUpdate)
 {
-    /* Step 1 (b) was performed by CallNonGenericMethod. */
+    /*
+     * WARNING: Despite the presence of spec step comment numbers, this
+     *          algorithm isn't consistent with any ES6 version, draft or
+     *          otherwise.  YOU HAVE BEEN WARNED.
+     */
+
+    /* Steps 1-2 performed by the caller. */
     Rooted<RegExpObject*> reobj(cx, &regexp->as<RegExpObject>());
 
     RegExpGuard re(cx);
     if (!reobj->getShared(cx, &re))
         return RegExpRunStatus_Error;
 
     RegExpStatics* res;
     if (staticsUpdate == UpdateRegExpStatics) {
         res = cx->global()->getRegExpStatics(cx);
         if (!res)
             return RegExpRunStatus_Error;
     } else {
         res = nullptr;
     }
 
-    /* Step 3. */
     RootedLinearString input(cx, string->ensureLinear(cx));
     if (!input)
         return RegExpRunStatus_Error;
 
-    /* Step 4. */
-    RootedValue lastIndex(cx, reobj->getLastIndex());
+    /* Step 3. */
     size_t length = input->length();
 
-    /* Step 5. */
+    /* Steps 4-5. */
+    RootedValue lastIndex(cx, reobj->getLastIndex());
     int searchIndex;
     if (lastIndex.isInt32()) {
         /* Aggressively avoid doubles. */
         searchIndex = lastIndex.toInt32();
     } else {
         double d;
         if (!ToInteger(cx, lastIndex, &d))
             return RegExpRunStatus_Error;
 
-        /* Inlined steps 6, 7, 9a with doubles to detect failure case. */
+        /* Inlined steps 6-10, 15.a with doubles to detect failure case. */
         if (reobj->needUpdateLastIndex() && (d < 0 || d > length)) {
-            reobj->zeroLastIndex();
+            /* Steps 15.a.i-ii. */
+            if (!SetLastIndex(cx, reobj, 0))
+                return RegExpRunStatus_Error;
+
+            /* Step 15.a.iii. */
             return RegExpRunStatus_Success_NotFound;
         }
 
         searchIndex = int(d);
     }
 
     /*
-     * Steps 6-7 (with sticky extension).
+     * Steps 6-10.
      *
      * Also make sure that we have a MatchPairs for regexps which update their
      * last index, as we won't compute the last index otherwise.
      */
     Maybe<ScopedMatchPairs> alternateMatches;
     if (!reobj->needUpdateLastIndex()) {
         searchIndex = 0;
     } else if (!matches) {
         alternateMatches.emplace(&cx->tempLifoAlloc());
         matches = &alternateMatches.ref();
     }
 
-    /* Step 9a. */
+    /* Step 15.a. */
     if (searchIndex < 0 || size_t(searchIndex) > length) {
-        reobj->zeroLastIndex();
+        /* Steps 15.a.i-ii. */
+        if (!SetLastIndex(cx, reobj, 0))
+            return RegExpRunStatus_Error;
+
+        /* Step 15.a.iii. */
         return RegExpRunStatus_Success_NotFound;
     }
 
-    /* Steps 8-21. */
+    /* Step 14-29. */
     RegExpRunStatus status = ExecuteRegExpImpl(cx, res, *re, input, searchIndex, matches);
     if (status == RegExpRunStatus_Error)
         return RegExpRunStatus_Error;
 
-    /* Steps 9a and 11 (with sticky extension). */
-    if (status == RegExpRunStatus_Success_NotFound)
-        reobj->zeroLastIndex();
-    else if (reobj->needUpdateLastIndex())
-        reobj->setLastIndex((*matches)[0].limit);
+    if (status == RegExpRunStatus_Success_NotFound) {
+        /* Steps 15.a.i-ii. */
+        if (!SetLastIndex(cx, reobj, 0))
+            return RegExpRunStatus_Error;
+    } else if (reobj->needUpdateLastIndex()) {
+        /* Steps 18.a-b. */
+        if (!SetLastIndex(cx, reobj, (*matches)[0].limit))
+            return RegExpRunStatus_Error;
+    }
 
     return status;
 }
 
 /* ES5 15.10.6.2 (and 15.10.6.3, which calls 15.10.6.2). */
 static RegExpRunStatus
 ExecuteRegExp(JSContext* cx, CallArgs args, MatchPairs* matches)
 {
--- a/js/src/devtools/rootAnalysis/annotations.js
+++ b/js/src/devtools/rootAnalysis/annotations.js
@@ -61,16 +61,17 @@ var ignoreClasses = {
     "SprintfState" : true,
     "SprintfStateStr" : true,
     "JSLocaleCallbacks" : true,
     "JSC::ExecutableAllocator" : true,
     "PRIOMethods": true,
     "XPCOMFunctions" : true, // I'm a little unsure of this one
     "_MD_IOVector" : true,
     "malloc_table_t": true, // replace_malloc
+    "malloc_hook_table_t": true, // replace_malloc
 };
 
 // Ignore calls through TYPE.FIELD, where TYPE is the class or struct name containing
 // a function pointer field named FIELD.
 var ignoreCallees = {
     "js::Class.trace" : true,
     "js::Class.finalize" : true,
     "JSRuntime.destroyPrincipals" : true,
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -362,17 +362,18 @@ Statistics::formatCompactSummaryMessage(
     const double mmu50 = computeMMU(50 * PRMJ_USEC_PER_MSEC);
 
     char buffer[1024];
     if (!nonincrementalReason_) {
         JS_snprintf(buffer, sizeof(buffer),
                     "Max Pause: %.3fms; MMU 20ms: %.1f%%; MMU 50ms: %.1f%%; Total: %.3fms; ",
                     t(longest), mmu20 * 100., mmu50 * 100., t(total));
     } else {
-        JS_snprintf(buffer, sizeof(buffer), "Non-Incremental: %.3fms; ", t(total));
+        JS_snprintf(buffer, sizeof(buffer), "Non-Incremental: %.3fms (%s); ",
+                    t(total), nonincrementalReason_);
     }
     if (!fragments.append(make_string_copy(buffer)))
         return UniqueChars(nullptr);
 
     JS_snprintf(buffer, sizeof(buffer),
                 "Zones: %d of %d; Compartments: %d of %d; HeapSize: %.3f MiB; "\
                 "HeapChange (abs): %+d (%d); ",
                 zoneStats.collectedZoneCount, zoneStats.zoneCount,
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/RegExp/lastIndex-nonwritable.js
@@ -0,0 +1,27 @@
+var BUGNUMBER = 1168416;
+var summary = "Regexp.prototype.test/exec shouldn't change lastIndex if not writable.";
+
+print(BUGNUMBER + ": " + summary);
+
+var regex = /0/g;
+Object.freeze(regex);
+var str = "abc000";
+
+var desc = Object.getOwnPropertyDescriptor(regex, "lastIndex");
+assertEq(desc.writable, false);
+assertEq(desc.value, 0);
+
+assertThrowsInstanceOf(() => regex.test(str), TypeError);
+
+desc = Object.getOwnPropertyDescriptor(regex, "lastIndex");
+assertEq(desc.writable, false);
+assertEq(desc.value, 0);
+
+assertThrowsInstanceOf(() => regex.exec(str), TypeError);
+
+desc = Object.getOwnPropertyDescriptor(regex, "lastIndex");
+assertEq(desc.writable, false);
+assertEq(desc.value, 0);
+
+if (typeof reportCompare === "function")
+    reportCompare(true, true);
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1555,19 +1555,18 @@ DetachedWrappedNativeProtoShutdownMarker
 void XPCJSRuntime::DestroyJSContextStack()
 {
     delete mJSContextStack;
     mJSContextStack = nullptr;
 }
 
 void XPCJSRuntime::SystemIsBeingShutDown()
 {
-    if (mDetachedWrappedNativeProtoMap)
-        mDetachedWrappedNativeProtoMap->
-            Enumerate(DetachedWrappedNativeProtoShutdownMarker, nullptr);
+    mDetachedWrappedNativeProtoMap->
+        Enumerate(DetachedWrappedNativeProtoShutdownMarker, nullptr);
 }
 
 #define JS_OPTIONS_DOT_STR "javascript.options."
 
 static void
 ReloadPrefsCallback(const char* pref, void* data)
 {
     XPCJSRuntime* runtime = reinterpret_cast<XPCJSRuntime*>(data);
@@ -1639,61 +1638,43 @@ XPCJSRuntime::~XPCJSRuntime()
     if (mCallContext)
         mCallContext->SystemIsBeingShutDown();
 
     auto rtPrivate = static_cast<PerThreadAtomCache*>(JS_GetRuntimePrivate(Runtime()));
     delete rtPrivate;
     JS_SetRuntimePrivate(Runtime(), nullptr);
 
     // clean up and destroy maps...
-    if (mWrappedJSMap) {
-        mWrappedJSMap->ShutdownMarker();
-        delete mWrappedJSMap;
-        mWrappedJSMap = nullptr;
-    }
-
-    if (mWrappedJSClassMap) {
-        delete mWrappedJSClassMap;
-        mWrappedJSClassMap = nullptr;
-    }
-
-    if (mIID2NativeInterfaceMap) {
-        delete mIID2NativeInterfaceMap;
-        mIID2NativeInterfaceMap = nullptr;
-    }
-
-    if (mClassInfo2NativeSetMap) {
-        delete mClassInfo2NativeSetMap;
-        mClassInfo2NativeSetMap = nullptr;
-    }
-
-    if (mNativeSetMap) {
-        delete mNativeSetMap;
-        mNativeSetMap = nullptr;
-    }
-
-    if (mThisTranslatorMap) {
-        delete mThisTranslatorMap;
-        mThisTranslatorMap = nullptr;
-    }
-
-    if (mNativeScriptableSharedMap) {
-        delete mNativeScriptableSharedMap;
-        mNativeScriptableSharedMap = nullptr;
-    }
-
-    if (mDyingWrappedNativeProtoMap) {
-        delete mDyingWrappedNativeProtoMap;
-        mDyingWrappedNativeProtoMap = nullptr;
-    }
-
-    if (mDetachedWrappedNativeProtoMap) {
-        delete mDetachedWrappedNativeProtoMap;
-        mDetachedWrappedNativeProtoMap = nullptr;
-    }
+    mWrappedJSMap->ShutdownMarker();
+    delete mWrappedJSMap;
+    mWrappedJSMap = nullptr;
+
+    delete mWrappedJSClassMap;
+    mWrappedJSClassMap = nullptr;
+
+    delete mIID2NativeInterfaceMap;
+    mIID2NativeInterfaceMap = nullptr;
+
+    delete mClassInfo2NativeSetMap;
+    mClassInfo2NativeSetMap = nullptr;
+
+    delete mNativeSetMap;
+    mNativeSetMap = nullptr;
+
+    delete mThisTranslatorMap;
+    mThisTranslatorMap = nullptr;
+
+    delete mNativeScriptableSharedMap;
+    mNativeScriptableSharedMap = nullptr;
+
+    delete mDyingWrappedNativeProtoMap;
+    mDyingWrappedNativeProtoMap = nullptr;
+
+    delete mDetachedWrappedNativeProtoMap;
+    mDetachedWrappedNativeProtoMap = nullptr;
 
 #ifdef MOZ_ENABLE_PROFILER_SPS
     // Tell the profiler that the runtime is gone
     if (PseudoStack* stack = mozilla_get_pseudo_stack())
         stack->sampleRuntime(nullptr);
 #endif
 
     Preferences::UnregisterCallback(ReloadPrefsCallback, JS_OPTIONS_DOT_STR, this);
@@ -3669,17 +3650,17 @@ void
 XPCJSRuntime::DebugDump(int16_t depth)
 {
 #ifdef DEBUG
     depth--;
     XPC_LOG_ALWAYS(("XPCJSRuntime @ %x", this));
         XPC_LOG_INDENT();
         XPC_LOG_ALWAYS(("mJSRuntime @ %x", Runtime()));
 
-        XPC_LOG_ALWAYS(("mWrappedJSToReleaseArray @ %x with %d wrappers(s)", \
+        XPC_LOG_ALWAYS(("mWrappedJSToReleaseArray @ %x with %d wrappers(s)",
                         &mWrappedJSToReleaseArray,
                         mWrappedJSToReleaseArray.Length()));
 
         int cxCount = 0;
         JSContext* iter = nullptr;
         while (JS_ContextIterator(Runtime(), &iter))
             ++cxCount;
         XPC_LOG_ALWAYS(("%d JS context(s)", cxCount));
@@ -3687,53 +3668,49 @@ XPCJSRuntime::DebugDump(int16_t depth)
         iter = nullptr;
         while (JS_ContextIterator(Runtime(), &iter)) {
             XPCContext* xpc = XPCContext::GetXPCContext(iter);
             XPC_LOG_INDENT();
             xpc->DebugDump(depth);
             XPC_LOG_OUTDENT();
         }
 
-        XPC_LOG_ALWAYS(("mWrappedJSClassMap @ %x with %d wrapperclasses(s)",  \
-                        mWrappedJSClassMap, mWrappedJSClassMap ?              \
-                        mWrappedJSClassMap->Count() : 0));
+        XPC_LOG_ALWAYS(("mWrappedJSClassMap @ %x with %d wrapperclasses(s)",
+                        mWrappedJSClassMap, mWrappedJSClassMap->Count()));
         // iterate wrappersclasses...
-        if (depth && mWrappedJSClassMap && mWrappedJSClassMap->Count()) {
+        if (depth && mWrappedJSClassMap->Count()) {
             XPC_LOG_INDENT();
             mWrappedJSClassMap->Enumerate(WrappedJSClassMapDumpEnumerator, &depth);
             XPC_LOG_OUTDENT();
         }
-        XPC_LOG_ALWAYS(("mWrappedJSMap @ %x with %d wrappers(s)",             \
-                        mWrappedJSMap, mWrappedJSMap ?                        \
-                        mWrappedJSMap->Count() : 0));
+        XPC_LOG_ALWAYS(("mWrappedJSMap @ %x with %d wrappers(s)",
+                        mWrappedJSMap, mWrappedJSMap->Count()));
         // iterate wrappers...
-        if (depth && mWrappedJSMap && mWrappedJSMap->Count()) {
+        if (depth && mWrappedJSMap->Count()) {
             XPC_LOG_INDENT();
             mWrappedJSMap->Dump(depth);
             XPC_LOG_OUTDENT();
         }
 
-        XPC_LOG_ALWAYS(("mIID2NativeInterfaceMap @ %x with %d interface(s)",  \
-                        mIID2NativeInterfaceMap, mIID2NativeInterfaceMap ?    \
-                        mIID2NativeInterfaceMap->Count() : 0));
-
-        XPC_LOG_ALWAYS(("mClassInfo2NativeSetMap @ %x with %d sets(s)",       \
-                        mClassInfo2NativeSetMap, mClassInfo2NativeSetMap ?    \
-                        mClassInfo2NativeSetMap->Count() : 0));
-
-        XPC_LOG_ALWAYS(("mThisTranslatorMap @ %x with %d translator(s)",      \
-                        mThisTranslatorMap, mThisTranslatorMap ?              \
-                        mThisTranslatorMap->Count() : 0));
-
-        XPC_LOG_ALWAYS(("mNativeSetMap @ %x with %d sets(s)",                 \
-                        mNativeSetMap, mNativeSetMap ?                        \
-                        mNativeSetMap->Count() : 0));
+        XPC_LOG_ALWAYS(("mIID2NativeInterfaceMap @ %x with %d interface(s)",
+                        mIID2NativeInterfaceMap,
+                        mIID2NativeInterfaceMap->Count()));
+
+        XPC_LOG_ALWAYS(("mClassInfo2NativeSetMap @ %x with %d sets(s)",
+                        mClassInfo2NativeSetMap,
+                        mClassInfo2NativeSetMap->Count()));
+
+        XPC_LOG_ALWAYS(("mThisTranslatorMap @ %x with %d translator(s)",
+                        mThisTranslatorMap, mThisTranslatorMap->Count()));
+
+        XPC_LOG_ALWAYS(("mNativeSetMap @ %x with %d sets(s)",
+                        mNativeSetMap, mNativeSetMap->Count()));
 
         // iterate sets...
-        if (depth && mNativeSetMap && mNativeSetMap->Count()) {
+        if (depth && mNativeSetMap->Count()) {
             XPC_LOG_INDENT();
             mNativeSetMap->Enumerate(NativeSetDumpEnumerator, &depth);
             XPC_LOG_OUTDENT();
         }
 
         XPC_LOG_OUTDENT();
 #endif
 }
--- a/js/xpconnect/src/XPCMaps.cpp
+++ b/js/xpconnect/src/XPCMaps.cpp
@@ -168,31 +168,31 @@ JSObject2WrappedJSMap::SizeOfWrappedJS(m
 // static
 Native2WrappedNativeMap*
 Native2WrappedNativeMap::newMap(int length)
 {
     return new Native2WrappedNativeMap(length);
 }
 
 Native2WrappedNativeMap::Native2WrappedNativeMap(int length)
+  : mTable(new PLDHashTable(PL_DHashGetStubOps(), sizeof(Entry), length))
 {
-    mTable = new PLDHashTable(PL_DHashGetStubOps(), sizeof(Entry), length);
 }
 
 Native2WrappedNativeMap::~Native2WrappedNativeMap()
 {
     delete mTable;
 }
 
 size_t
 Native2WrappedNativeMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
 {
     size_t n = 0;
     n += mallocSizeOf(this);
-    n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf) : 0;
+    n += PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf);
     return n;
 }
 
 /* static */ size_t
 Native2WrappedNativeMap::SizeOfEntryExcludingThis(PLDHashEntryHdr* hdr,
                                                   mozilla::MallocSizeOf mallocSizeOf, void*)
 {
     return mallocSizeOf(((Native2WrappedNativeMap::Entry*)hdr)->value);
@@ -208,72 +208,63 @@ const struct PLDHashTableOps IID2Wrapped
     PL_DHashMoveEntryStub,
     PL_DHashClearEntryStub
 };
 
 // static
 IID2WrappedJSClassMap*
 IID2WrappedJSClassMap::newMap(int length)
 {
-    IID2WrappedJSClassMap* map = new IID2WrappedJSClassMap(length);
-    if (map && map->mTable)
-        return map;
-    delete map;
-    return nullptr;
+    return new IID2WrappedJSClassMap(length);
 }
 
 IID2WrappedJSClassMap::IID2WrappedJSClassMap(int length)
+  : mTable(new PLDHashTable(&Entry::sOps, sizeof(Entry), length))
 {
-    mTable = new PLDHashTable(&Entry::sOps, sizeof(Entry), length);
 }
 
 IID2WrappedJSClassMap::~IID2WrappedJSClassMap()
 {
     delete mTable;
 }
 
-
 /***************************************************************************/
 // implement IID2NativeInterfaceMap...
 
 const struct PLDHashTableOps IID2NativeInterfaceMap::Entry::sOps =
 {
     HashIIDPtrKey,
     MatchIIDPtrKey,
     PL_DHashMoveEntryStub,
     PL_DHashClearEntryStub
 };
 
 // static
 IID2NativeInterfaceMap*
 IID2NativeInterfaceMap::newMap(int length)
 {
-    IID2NativeInterfaceMap* map = new IID2NativeInterfaceMap(length);
-    if (map && map->mTable)
-        return map;
-    delete map;
-    return nullptr;
+    return new IID2NativeInterfaceMap(length);
 }
 
 IID2NativeInterfaceMap::IID2NativeInterfaceMap(int length)
+  : mTable(new PLDHashTable(&Entry::sOps, sizeof(Entry), length))
 {
-    mTable = new PLDHashTable(&Entry::sOps, sizeof(Entry), length);
 }
 
 IID2NativeInterfaceMap::~IID2NativeInterfaceMap()
 {
     delete mTable;
 }
 
 size_t
 IID2NativeInterfaceMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
 {
     size_t n = 0;
     n += mallocSizeOf(this);
-    n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf) : 0;
+    n += PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf);
     return n;
 }
 
 /* static */ size_t
 IID2NativeInterfaceMap::SizeOfEntryExcludingThis(PLDHashEntryHdr* hdr,
                                                  mozilla::MallocSizeOf mallocSizeOf, void*)
 {
     XPCNativeInterface* iface = ((IID2NativeInterfaceMap::Entry*)hdr)->value;
@@ -282,69 +273,65 @@ IID2NativeInterfaceMap::SizeOfEntryExclu
 
 /***************************************************************************/
 // implement ClassInfo2NativeSetMap...
 
 // static
 ClassInfo2NativeSetMap*
 ClassInfo2NativeSetMap::newMap(int length)
 {
-    ClassInfo2NativeSetMap* map = new ClassInfo2NativeSetMap(length);
-    if (map && map->mTable)
-        return map;
-    delete map;
-    return nullptr;
+    return new ClassInfo2NativeSetMap(length);
 }
 
 ClassInfo2NativeSetMap::ClassInfo2NativeSetMap(int length)
+  : mTable(new PLDHashTable(PL_DHashGetStubOps(), sizeof(Entry), length))
 {
-    mTable = new PLDHashTable(PL_DHashGetStubOps(), sizeof(Entry), length);
 }
 
 ClassInfo2NativeSetMap::~ClassInfo2NativeSetMap()
 {
     delete mTable;
 }
 
 size_t
 ClassInfo2NativeSetMap::ShallowSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
 {
     size_t n = 0;
     n += mallocSizeOf(this);
     // The second arg is nullptr because this is a "shallow" measurement of the map.
-    n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, nullptr, mallocSizeOf) : 0;
+    n += PL_DHashTableSizeOfIncludingThis(mTable, nullptr, mallocSizeOf);
     return n;
 }
 
 /***************************************************************************/
 // implement ClassInfo2WrappedNativeProtoMap...
 
 // static
 ClassInfo2WrappedNativeProtoMap*
 ClassInfo2WrappedNativeProtoMap::newMap(int length)
 {
     return new ClassInfo2WrappedNativeProtoMap(length);
 }
 
 ClassInfo2WrappedNativeProtoMap::ClassInfo2WrappedNativeProtoMap(int length)
+  : mTable(new PLDHashTable(PL_DHashGetStubOps(), sizeof(Entry), length))
 {
-    mTable = new PLDHashTable(PL_DHashGetStubOps(), sizeof(Entry), length);
 }
 
 ClassInfo2WrappedNativeProtoMap::~ClassInfo2WrappedNativeProtoMap()
 {
     delete mTable;
 }
 
 size_t
 ClassInfo2WrappedNativeProtoMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
 {
     size_t n = 0;
     n += mallocSizeOf(this);
-    n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf) : 0;
+    n += PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf);
     return n;
 }
 
 /* static */ size_t
 ClassInfo2WrappedNativeProtoMap::SizeOfEntryExcludingThis(PLDHashEntryHdr* hdr,
                                                           mozilla::MallocSizeOf mallocSizeOf, void*)
 {
     return mallocSizeOf(((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value);
@@ -432,39 +419,35 @@ const struct PLDHashTableOps NativeSetMa
     PL_DHashMoveEntryStub,
     PL_DHashClearEntryStub
 };
 
 // static
 NativeSetMap*
 NativeSetMap::newMap(int length)
 {
-    NativeSetMap* map = new NativeSetMap(length);
-    if (map && map->mTable)
-        return map;
-    delete map;
-    return nullptr;
+    return new NativeSetMap(length);
 }
 
 NativeSetMap::NativeSetMap(int length)
+  : mTable(new PLDHashTable(&Entry::sOps, sizeof(Entry), length))
 {
-    mTable = new PLDHashTable(&Entry::sOps, sizeof(Entry), length);
 }
 
 NativeSetMap::~NativeSetMap()
 {
     delete mTable;
 }
 
 size_t
 NativeSetMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
 {
     size_t n = 0;
     n += mallocSizeOf(this);
-    n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf) : 0;
+    n += PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf);
     return n;
 }
 
 /* static */ size_t
 NativeSetMap::SizeOfEntryExcludingThis(PLDHashEntryHdr* hdr, mozilla::MallocSizeOf mallocSizeOf, void*)
 {
     XPCNativeSet* set = ((NativeSetMap::Entry*)hdr)->key_value;
     return set->SizeOfIncludingThis(mallocSizeOf);
@@ -495,26 +478,22 @@ const struct PLDHashTableOps IID2ThisTra
     PL_DHashMoveEntryStub,
     Clear
 };
 
 // static
 IID2ThisTranslatorMap*
 IID2ThisTranslatorMap::newMap(int length)
 {
-    IID2ThisTranslatorMap* map = new IID2ThisTranslatorMap(length);
-    if (map && map->mTable)
-        return map;
-    delete map;
-    return nullptr;
+    return new IID2ThisTranslatorMap(length);
 }
 
 IID2ThisTranslatorMap::IID2ThisTranslatorMap(int length)
+  : mTable(new PLDHashTable(&Entry::sOps, sizeof(Entry), length))
 {
-    mTable = new PLDHashTable(&Entry::sOps, sizeof(Entry), length);
 }
 
 IID2ThisTranslatorMap::~IID2ThisTranslatorMap()
 {
     delete mTable;
 }
 
 /***************************************************************************/
@@ -570,27 +549,22 @@ const struct PLDHashTableOps XPCNativeSc
     PL_DHashMoveEntryStub,
     PL_DHashClearEntryStub
 };
 
 // static
 XPCNativeScriptableSharedMap*
 XPCNativeScriptableSharedMap::newMap(int length)
 {
-    XPCNativeScriptableSharedMap* map =
-        new XPCNativeScriptableSharedMap(length);
-    if (map && map->mTable)
-        return map;
-    delete map;
-    return nullptr;
+    return new XPCNativeScriptableSharedMap(length);
 }
 
 XPCNativeScriptableSharedMap::XPCNativeScriptableSharedMap(int length)
+  : mTable(new PLDHashTable(&Entry::sOps, sizeof(Entry), length))
 {
-    mTable = new PLDHashTable(&Entry::sOps, sizeof(Entry), length);
 }
 
 XPCNativeScriptableSharedMap::~XPCNativeScriptableSharedMap()
 {
     delete mTable;
 }
 
 bool
@@ -622,27 +596,23 @@ XPCNativeScriptableSharedMap::GetNewOrUs
 
 /***************************************************************************/
 // implement XPCWrappedNativeProtoMap...
 
 // static
 XPCWrappedNativeProtoMap*
 XPCWrappedNativeProtoMap::newMap(int length)
 {
-    XPCWrappedNativeProtoMap* map = new XPCWrappedNativeProtoMap(length);
-    if (map && map->mTable)
-        return map;
-    delete map;
-    return nullptr;
+    return new XPCWrappedNativeProtoMap(length);
 }
 
 XPCWrappedNativeProtoMap::XPCWrappedNativeProtoMap(int length)
+  : mTable(new PLDHashTable(PL_DHashGetStubOps(), sizeof(PLDHashEntryStub),
+                            length))
 {
-    mTable = new PLDHashTable(PL_DHashGetStubOps(),
-                              sizeof(PLDHashEntryStub), length);
 }
 
 XPCWrappedNativeProtoMap::~XPCWrappedNativeProtoMap()
 {
     delete mTable;
 }
 
 /***************************************************************************/
--- a/js/xpconnect/src/XPCMaps.h
+++ b/js/xpconnect/src/XPCMaps.h
@@ -27,20 +27,23 @@
 class JSObject2WrappedJSMap
 {
     typedef js::HashMap<JSObject*, nsXPCWrappedJS*, js::PointerHasher<JSObject*, 3>,
                         js::SystemAllocPolicy> Map;
 
 public:
     static JSObject2WrappedJSMap* newMap(int length) {
         JSObject2WrappedJSMap* map = new JSObject2WrappedJSMap();
-        if (map && map->mTable.init(length))
-            return map;
-        delete map;
-        return nullptr;
+        if (!map->mTable.init(length)) {
+            // This is a decent estimate of the size of the hash table's
+            // entry storage. The |2| is because on average the capacity is
+            // twice the requested length.
+            NS_ABORT_OOM(length * 2 * sizeof(Map::Entry));
+        }
+        return map;
     }
 
     inline nsXPCWrappedJS* Find(JSObject* Obj) {
         NS_PRECONDITION(Obj,"bad param");
         Map::Ptr p = mTable.lookup(Obj);
         return p ? p->value() : nullptr;
     }
 
@@ -594,20 +597,23 @@ private:
 class JSObject2JSObjectMap
 {
     typedef js::HashMap<JSObject*, JS::Heap<JSObject*>, js::PointerHasher<JSObject*, 3>,
                         js::SystemAllocPolicy> Map;
 
 public:
     static JSObject2JSObjectMap* newMap(int length) {
         JSObject2JSObjectMap* map = new JSObject2JSObjectMap();
-        if (map && map->mTable.init(length))
-            return map;
-        delete map;
-        return nullptr;
+        if (!map->mTable.init(length)) {
+            // This is a decent estimate of the size of the hash table's
+            // entry storage. The |2| is because on average the capacity is
+            // twice the requested length.
+            NS_ABORT_OOM(length * 2 * sizeof(Map::Entry));
+        }
+        return map;
     }
 
     inline JSObject* Find(JSObject* key) {
         NS_PRECONDITION(key, "bad param");
         if (Map::Ptr p = mTable.lookup(key))
             return p->value();
         return nullptr;
     }
--- a/js/xpconnect/src/XPCWrappedNativeScope.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp
@@ -423,25 +423,21 @@ xpc::GetAddonScope(JSContext* cx, JS::Ha
 }
 
 XPCWrappedNativeScope::~XPCWrappedNativeScope()
 {
     MOZ_COUNT_DTOR(XPCWrappedNativeScope);
 
     // We can do additional cleanup assertions here...
 
-    if (mWrappedNativeMap) {
-        MOZ_ASSERT(0 == mWrappedNativeMap->Count(), "scope has non-empty map");
-        delete mWrappedNativeMap;
-    }
+    MOZ_ASSERT(0 == mWrappedNativeMap->Count(), "scope has non-empty map");
+    delete mWrappedNativeMap;
 
-    if (mWrappedNativeProtoMap) {
-        MOZ_ASSERT(0 == mWrappedNativeProtoMap->Count(), "scope has non-empty map");
-        delete mWrappedNativeProtoMap;
-    }
+    MOZ_ASSERT(0 == mWrappedNativeProtoMap->Count(), "scope has non-empty map");
+    delete mWrappedNativeProtoMap;
 
     // This should not be necessary, since the Components object should die
     // with the scope but just in case.
     if (mComponents)
         mComponents->mScope = nullptr;
 
     // XXX we should assert that we are dead or that xpconnect has shutdown
     // XXX might not want to do this at xpconnect shutdown time???
@@ -828,31 +824,30 @@ XPCWrappedNativeScope::DebugDump(int16_t
 #ifdef DEBUG
     depth-- ;
     XPC_LOG_ALWAYS(("XPCWrappedNativeScope @ %x", this));
     XPC_LOG_INDENT();
         XPC_LOG_ALWAYS(("mNext @ %x", mNext));
         XPC_LOG_ALWAYS(("mComponents @ %x", mComponents.get()));
         XPC_LOG_ALWAYS(("mGlobalJSObject @ %x", mGlobalJSObject.get()));
 
-        XPC_LOG_ALWAYS(("mWrappedNativeMap @ %x with %d wrappers(s)",         \
-                        mWrappedNativeMap,                                    \
-                        mWrappedNativeMap ? mWrappedNativeMap->Count() : 0));
+        XPC_LOG_ALWAYS(("mWrappedNativeMap @ %x with %d wrappers(s)",
+                        mWrappedNativeMap, mWrappedNativeMap->Count()));
         // iterate contexts...
-        if (depth && mWrappedNativeMap && mWrappedNativeMap->Count()) {
+        if (depth && mWrappedNativeMap->Count()) {
             XPC_LOG_INDENT();
             mWrappedNativeMap->Enumerate(WrappedNativeMapDumpEnumerator, &depth);
             XPC_LOG_OUTDENT();
         }
 
-        XPC_LOG_ALWAYS(("mWrappedNativeProtoMap @ %x with %d protos(s)",      \
-                        mWrappedNativeProtoMap,                               \
-                        mWrappedNativeProtoMap ? mWrappedNativeProtoMap->Count() : 0));
+        XPC_LOG_ALWAYS(("mWrappedNativeProtoMap @ %x with %d protos(s)",
+                        mWrappedNativeProtoMap,
+                        mWrappedNativeProtoMap->Count()));
         // iterate contexts...
-        if (depth && mWrappedNativeProtoMap && mWrappedNativeProtoMap->Count()) {
+        if (depth && mWrappedNativeProtoMap->Count()) {
             XPC_LOG_INDENT();
             mWrappedNativeProtoMap->Enumerate(WrappedNativeProtoMapDumpEnumerator, &depth);
             XPC_LOG_OUTDENT();
         }
     XPC_LOG_OUTDENT();
 #endif
 }
 
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -82,17 +82,16 @@ WrapperFactory::CreateXrayWaiver(JSConte
     if (!waiver)
         return nullptr;
 
     // Add the new waiver to the map. It's important that we only ever have
     // one waiver for the lifetime of the target object.
     if (!scope->mWaiverWrapperMap) {
         scope->mWaiverWrapperMap =
           JSObject2JSObjectMap::newMap(XPC_WRAPPER_MAP_LENGTH);
-        MOZ_ASSERT(scope->mWaiverWrapperMap);
     }
     if (!scope->mWaiverWrapperMap->Add(cx, obj, waiver))
         return nullptr;
     return waiver;
 }
 
 JSObject*
 WrapperFactory::WaiveXray(JSContext* cx, JSObject* objArg)
--- a/layout/generic/nsFrameList.h
+++ b/layout/generic/nsFrameList.h
@@ -68,17 +68,17 @@ public:
   }
 
   nsFrameList(const nsFrameList& aOther) :
     mFirstChild(aOther.mFirstChild), mLastChild(aOther.mLastChild)
   {
   }
 
   /**
-   * Allocate a nsFrameList from the shell arena.
+   * Infallibly allocate a nsFrameList from the shell arena.
    */
   void* operator new(size_t sz, nsIPresShell* aPresShell) CPP_THROW_NEW;
 
   /**
    * Deallocate this list that was allocated from the shell arena.
    * The list is required to be empty.
    */
   void Delete(nsIPresShell* aPresShell);
--- a/layout/generic/nsLineBox.cpp
+++ b/layout/generic/nsLineBox.cpp
@@ -140,18 +140,16 @@ nsLineBox::NoteFramesMovedFrom(nsLineBox
       // This line needs a hash table, but it's fewer hash ops to steal
       // aFromLine's hash table and allocate a new hash table for that line.
       StealHashTableFrom(aFromLine, fromNewCount); // fromNewCount RemoveEntry
       aFromLine->SwitchToHashtable(); // fromNewCount PutEntry
     }
   }
 }
 
-// Overloaded new operator. Uses an arena (which comes from the presShell)
-// to perform the allocation.
 void*
 nsLineBox::operator new(size_t sz, nsIPresShell* aPresShell) CPP_THROW_NEW
 {
   return aPresShell->AllocateByObjectID(nsPresArena::nsLineBox_id, sz);
 }
 
 void
 nsLineBox::Destroy(nsIPresShell* aPresShell)
--- a/layout/generic/nsLineBox.h
+++ b/layout/generic/nsLineBox.h
@@ -201,18 +201,18 @@ class nsLineLink {
  * enough state to support incremental reflow of the frames, event handling
  * for the frames, and rendering of the frames.
  */
 class nsLineBox final : public nsLineLink {
 private:
   nsLineBox(nsIFrame* aFrame, int32_t aCount, bool aIsBlock);
   ~nsLineBox();
   
-  // Overloaded new operator. Uses an arena (which comes from the presShell)
-  // to perform the allocation.
+  // Infallible overloaded new operator. Uses an arena (which comes from the
+  // presShell) to perform the allocation.
   void* operator new(size_t sz, nsIPresShell* aPresShell) CPP_THROW_NEW;
   void operator delete(void* aPtr, size_t sz) = delete;
 
 public:
   // Use these functions to allocate and destroy line boxes
   friend nsLineBox* NS_NewLineBox(nsIPresShell* aPresShell, nsIFrame* aFrame,
                                   bool aIsBlock);
   friend nsLineBox* NS_NewLineBox(nsIPresShell* aPresShell, nsLineBox* aFromLine,
--- a/layout/reftests/backgrounds/reftest.list
+++ b/layout/reftests/backgrounds/reftest.list
@@ -111,17 +111,17 @@ random-if(OSX==1010) == background-size-
 random-if(OSX==1010) == background-size-monster-px.html background-size-monster-ref.html # bug 1129300
 random-if(OSX==1010) == background-size-monster-rem.html background-size-monster-ref.html # bug 1129300
 
 # There seems to be a pixel-snapping problem here, where the repeated background
 # image isn't being snapped at its boundaries.  Note that the boundaries within
 # the image aren't the issue, because they're being obscured to avoid sampling
 # algorithm dependencies (at least assuming the sampling algorithm in use
 # doesn't sample too far astray from the boundaries).
-fails-if(supportsRepeatResampling) == background-size-zoom-repeat.html background-size-zoom-repeat-ref.html
+fails == background-size-zoom-repeat.html background-size-zoom-repeat-ref.html
 
 # -moz-default-background-color and -moz-default-color (bug 591341)
 == background-moz-default-background-color.html background-moz-default-background-color-ref.html
 
 random-if(B2G||Mulet) == fixed-bg-with-transform-outside-viewport-1.html fixed-bg-with-transform-outside-viewport-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 
 HTTP == root-background-1.html root-background-ref.html
 HTTP != root-background-1.html about:blank
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1009,17 +1009,17 @@ skip-if((B2G&&browserIsRemote)||Mulet) =
 skip-if(B2G||Mulet) == 421234-1.html 421234-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 == 421239-1.html 421239-1-ref.html
 == 421239-2.html 421239-2-ref.html
 == 421419-1.html 421419-1-ref.html
 == 421436-1a.html 421436-1-ref.html
 == 421436-1b.html 421436-1-ref.html
 == 421632-1.html 421632-1-ref.html
 != 421710-1.html about:blank
-skip-if(B2G||Mulet) fails-if(Android) fails-if(!supportsRepeatResampling) == 421885-1.xml 421885-1-ref.xml # Initial mulet triage: parity with B2G/B2G Desktop
+skip-if(B2G||Mulet) fails-if(Android) == 421885-1.xml 421885-1-ref.xml # Initial mulet triage: parity with B2G/B2G Desktop
 == 421955-1.html 421955-1-ref.html
 skip-if(B2G||Mulet) == 422249-1.html 422249-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 == 422394-1.html 422394-1-ref.html
 == 422678-1.html 422678-1-ref.html
 == 423130-1.html 423130-1-ref.html
 == 423385-1.html 423385-1-ref.html
 == 423599-1.html 423599-1-ref.html
 == 423676-1.html 423676-1-ref.html
@@ -1159,23 +1159,23 @@ fails == 441259-2.html 441259-2-ref.html
 == 444928-2.html 444928-2-ref.html
 != 444928-3.html 444928-3-notref.html
 random == 445004-1.html 445004-1-ref.html # bug 472268
 == 445142-1a.html 445142-1-ref.html
 == 445142-1b.html 445142-1-ref.html
 == 445142-1c.html 445142-1-ref.html
 == 445142-2a.html 445142-2-ref.html
 == 445142-2b.html 445142-2-ref.html
-fails-if(!supportsRepeatResampling) == 446100-1a.html about:blank
-skip-if(B2G||Mulet) fails-if(Android) fails-if(!supportsRepeatResampling) == 446100-1b.html about:blank # Initial mulet triage: parity with B2G/B2G Desktop
-skip-if(B2G||Mulet) fails-if(Android) fails-if(!supportsRepeatResampling) == 446100-1c.html about:blank # Initial mulet triage: parity with B2G/B2G Desktop
-fails-if(!supportsRepeatResampling) == 446100-1d.html about:blank
+== 446100-1a.html about:blank
+skip-if(B2G||Mulet) fails-if(Android) == 446100-1b.html about:blank # Initial mulet triage: parity with B2G/B2G Desktop
+skip-if(B2G||Mulet) fails-if(Android) == 446100-1c.html about:blank # Initial mulet triage: parity with B2G/B2G Desktop
+== 446100-1d.html about:blank
 == 446100-1e.html about:blank
 == 446100-1f.html about:blank
-skip-if(B2G||Mulet) fails-if(Android) fails-if(!supportsRepeatResampling) == 446100-1g.html about:blank # Initial mulet triage: parity with B2G/B2G Desktop
+skip-if(B2G||Mulet) fails-if(Android) == 446100-1g.html about:blank # Initial mulet triage: parity with B2G/B2G Desktop
 == 446100-1h.html about:blank
 skip-if(B2G||Mulet) == 447749-1.html 447749-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 fuzzy(127,2) == 448193.html 448193-ref.html
 != 449149-1a.html about:blank
 != 449149-1b.html about:blank
 # Retry the above with XBL scopes
 test-pref(dom.use_xbl_scopes_for_remote_xul,true) != 449149-1a.html about:blank
 test-pref(dom.use_xbl_scopes_for_remote_xul,true) != 449149-1b.html about:blank
--- a/layout/reftests/image-element/reftest.list
+++ b/layout/reftests/image-element/reftest.list
@@ -13,17 +13,17 @@ skip-if(B2G||Mulet) fails-if(azureSkia) 
 skip-if(B2G||Mulet) HTTP(..) == element-paint-continuation.html element-paint-continuation-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 == element-paint-transform-01.html element-paint-transform-01-ref.html
 random-if(d2d) == element-paint-transform-02.html element-paint-transform-02-ref.html # bug 587133
 fuzzy-if(d2d&&/^Windows\x20NT\x206\.1/.test(http.oscpu),16,90) == element-paint-background-size-01.html element-paint-background-size-01-ref.html
 == element-paint-background-size-02.html element-paint-background-size-02-ref.html
 == element-paint-transform-repeated.html element-paint-transform-repeated-ref.html
 fuzzy-if(d2d,255,24) == element-paint-transform-03.html element-paint-transform-03-ref.html
 == element-paint-native-widget.html element-paint-native-widget-ref.html
-fails-if(!supportsRepeatResampling) == element-paint-subimage-sampling-restriction.html about:blank
+== element-paint-subimage-sampling-restriction.html about:blank
 == element-paint-clippath.html element-paint-clippath-ref.html
 == element-paint-sharpness-01a.html element-paint-sharpness-01b.html
 == element-paint-sharpness-01b.html element-paint-sharpness-01c.html
 == element-paint-sharpness-01c.html element-paint-sharpness-01d.html
 == element-paint-sharpness-02a.html element-paint-sharpness-02b.html
 fuzzy-if(B2G,11,4) == element-paint-sharpness-02b.html element-paint-sharpness-02c.html
 == element-paint-paintserversize-rounding-01.html element-paint-paintserversize-rounding-01-ref.html
 == element-paint-paintserversize-rounding-02.html element-paint-paintserversize-rounding-02-ref.html
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -1389,17 +1389,16 @@ SetFactor(const nsCSSValue& aValue, floa
 
   default:
     break;
   }
 
   NS_NOTREACHED("SetFactor: inappropriate unit");
 }
 
-// Overloaded new operator that allocates from a presShell arena.
 void*
 nsRuleNode::operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW
 {
   // Check the recycle list first.
   return aPresContext->PresShell()->AllocateByObjectID(nsPresArena::nsRuleNode_id, sz);
 }
 
 /* static */ PLDHashOperator
@@ -1549,30 +1548,21 @@ nsRuleNode::Transition(nsIStyleRule* aRu
       NS_WARNING("out of memory");
       return this;
     }
     if (entry->mRuleNode)
       next = entry->mRuleNode;
     else {
       next = entry->mRuleNode = new (mPresContext)
         nsRuleNode(mPresContext, this, aRule, aLevel, aIsImportantRule);
-      if (!next) {
-        PL_DHashTableRawRemove(ChildrenHash(), entry);
-        NS_WARNING("out of memory");
-        return this;
-      }
     }
   } else if (!next) {
     // Create the new entry in our list.
     next = new (mPresContext)
       nsRuleNode(mPresContext, this, aRule, aLevel, aIsImportantRule);
-    if (!next) {
-      NS_WARNING("out of memory");
-      return this;
-    }
     next->mNextSibling = ChildrenList();
     SetChildrenList(next);
   }
 
   return next;
 }
 
 nsRuleNode*
--- a/layout/style/nsRuleNode.h
+++ b/layout/style/nsRuleNode.h
@@ -389,17 +389,17 @@ private:
   // only used to determine when it's worth running GC on the ruletree, and
   // this setup makes it so we only count unused ruletree leaves for purposes
   // of deciding when to GC.  We could more accurately count unused rulenodes
   // by releasing/addrefing our parent when our refcount transitions to or from
   // 0, but it doesn't seem worth it to do that.
   uint32_t mRefCnt;
 
 public:
-  // Overloaded new operator that allocates from a presShell arena.
+  // Infallible overloaded new operator that allocates from a presShell arena.
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW;
   void Destroy() { DestroyInternal(nullptr); }
 
   // Implemented in nsStyleSet.h, since it needs to know about nsStyleSet.
   inline void AddRef();
 
   // Implemented in nsStyleSet.h, since it needs to know about nsStyleSet.
   inline void Release();
@@ -646,16 +646,17 @@ protected:
                                   bool& aCanStoreInRuleTree);
 
 private:
   nsRuleNode(nsPresContext* aPresContext, nsRuleNode* aParent,
              nsIStyleRule* aRule, uint8_t aLevel, bool aIsImportant);
   ~nsRuleNode();
 
 public:
+  // This is infallible; it will never return nullptr.
   static nsRuleNode* CreateRootNode(nsPresContext* aPresContext);
 
   static void EnsureBlockDisplay(uint8_t& display,
                                  bool aConvertListItem = false);
   static void EnsureInlineDisplay(uint8_t& display);
 
   // Transition never returns null; on out of memory it'll just return |this|.
   nsRuleNode* Transition(nsIStyleRule* aRule, uint8_t aLevel,
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -213,20 +213,17 @@ nsStyleSet::Init(nsPresContext *aPresCon
 
 nsresult
 nsStyleSet::BeginReconstruct()
 {
   NS_ASSERTION(!mInReconstruct, "Unmatched begin/end?");
   NS_ASSERTION(mRuleTree, "Reconstructing before first construction?");
 
   // Create a new rule tree root
-  nsRuleNode* newTree =
-    nsRuleNode::CreateRootNode(mRuleTree->PresContext());
-  if (!newTree)
-    return NS_ERROR_OUT_OF_MEMORY;
+  nsRuleNode* newTree = nsRuleNode::CreateRootNode(mRuleTree->PresContext());
 
   // Save the old rule tree so we can destroy it later
   if (!mOldRuleTrees.AppendElement(mRuleTree)) {
     newTree->Destroy();
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   // We need to keep mRoots so that the rule tree GC will only free the
--- a/layout/tools/reftest/reftest.js
+++ b/layout/tools/reftest/reftest.js
@@ -750,19 +750,16 @@ function BuildConditionSandbox(aURL) {
         sandbox.asyncPanZoom = false;
     }
 
     if (!gDumpedConditionSandbox) {
         dump("REFTEST INFO | Dumping JSON representation of sandbox \n");
         dump("REFTEST INFO | " + JSON.stringify(CU.waiveXrays(sandbox)) + " \n");
         gDumpedConditionSandbox = true;
     }
-
-    // Graphics features
-    sandbox.supportsRepeatResampling = !sandbox.cocoaWidget;
     return sandbox;
 }
 
 function AddPrefSettings(aWhere, aPrefName, aPrefValExpression, aSandbox, aTestPrefSettings, aRefPrefSettings)
 {
     var prefVal = Components.utils.evalInSandbox("(" + aPrefValExpression + ")", aSandbox);
     var prefType;
     var valType = typeof(prefVal);
--- a/media/mtransport/nricectx.cpp
+++ b/media/mtransport/nricectx.cpp
@@ -56,16 +56,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 #include "nsComponentManagerUtils.h"
 #include "nsError.h"
 #include "nsIEventTarget.h"
 #include "nsNetCID.h"
 #include "nsComponentManagerUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "ScopedNSSTypes.h"
 #include "runnable_utils.h"
+#include "nsIPrefService.h"
+#include "nsIPrefBranch.h"
 
 // nICEr includes
 extern "C" {
 #include "nr_api.h"
 #include "registry.h"
 #include "async_timer.h"
 #include "r_crc32.h"
 #include "r_memory.h"
@@ -429,18 +431,39 @@ RefPtr<NrIceCtx> NrIceCtx::Create(const 
       NR_reg_set_uchar((char *)"ice.pref.interface.vmnet5", 237);
       NR_reg_set_uchar((char *)"ice.pref.interface.vmnet6", 236);
       NR_reg_set_uchar((char *)"ice.pref.interface.vmnet7", 235);
       NR_reg_set_uchar((char *)"ice.pref.interface.vmnet8", 234);
       NR_reg_set_uchar((char *)"ice.pref.interface.virbr0", 233);
       NR_reg_set_uchar((char *)"ice.pref.interface.wlan0", 232);
     }
 
-    NR_reg_set_uint4((char *)"stun.client.maximum_transmits",7);
-    NR_reg_set_uint4((char *)NR_ICE_REG_TRICKLE_GRACE_PERIOD, 5000);
+    int32_t stun_client_maximum_transmits = 7;
+    int32_t ice_trickle_grace_period = 5000;
+#ifndef MOZILLA_XPCOMRT_API
+    nsresult res;
+    nsCOMPtr<nsIPrefService> prefs =
+      do_GetService("@mozilla.org/preferences-service;1", &res);
+
+    if (NS_SUCCEEDED(res)) {
+      nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
+      if (branch) {
+        branch->GetIntPref(
+            "media.peerconnection.ice.stun_client_maximum_transmits",
+            &stun_client_maximum_transmits);
+        branch->GetIntPref(
+            "media.peerconnection.ice.trickle_grace_period",
+            &ice_trickle_grace_period);
+      }
+    }
+#endif
+    NR_reg_set_uint4((char *)"stun.client.maximum_transmits",
+                     stun_client_maximum_transmits);
+    NR_reg_set_uint4((char *)NR_ICE_REG_TRICKLE_GRACE_PERIOD,
+                     ice_trickle_grace_period);
 
     if (allow_loopback) {
       NR_reg_set_char((char *)NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS, 1);
     }
   }
 
   // Create the ICE context
   int r;
--- a/memory/build/malloc_decls.h
+++ b/memory/build/malloc_decls.h
@@ -30,35 +30,41 @@ typedef MALLOC_USABLE_SIZE_CONST_PTR voi
 
 #endif /* malloc_decls_h */
 
 #ifndef MALLOC_FUNCS
 #  define MALLOC_FUNCS (MALLOC_FUNCS_MALLOC | MALLOC_FUNCS_JEMALLOC)
 #endif
 
 #ifdef MALLOC_DECL
+#  ifndef MALLOC_DECL_VOID
+#    define MALLOC_DECL_VOID(func, ...) MALLOC_DECL(func, void, __VA_ARGS__)
+#  endif
+
 #  if MALLOC_FUNCS & MALLOC_FUNCS_INIT
 MALLOC_DECL(init, void, const malloc_table_t *)
 #  endif
 #  if MALLOC_FUNCS & MALLOC_FUNCS_BRIDGE
 MALLOC_DECL(get_bridge, struct ReplaceMallocBridge*, void)
 #  endif
 #  if MALLOC_FUNCS & MALLOC_FUNCS_MALLOC
 MALLOC_DECL(malloc, void *, size_t)
 MALLOC_DECL(posix_memalign, int, void **, size_t, size_t)
 MALLOC_DECL(aligned_alloc, void *, size_t, size_t)
 MALLOC_DECL(calloc, void *, size_t, size_t)
 MALLOC_DECL(realloc, void *, void *, size_t)
-MALLOC_DECL(free, void, void *)
+MALLOC_DECL_VOID(free, void *)
 MALLOC_DECL(memalign, void *, size_t, size_t)
 MALLOC_DECL(valloc, void *, size_t)
 MALLOC_DECL(malloc_usable_size, size_t, usable_ptr_t)
 MALLOC_DECL(malloc_good_size, size_t, size_t)
 #  endif
 #  if MALLOC_FUNCS & MALLOC_FUNCS_JEMALLOC
-MALLOC_DECL(jemalloc_stats, void, jemalloc_stats_t *)
-MALLOC_DECL(jemalloc_purge_freed_pages, void, void)
-MALLOC_DECL(jemalloc_free_dirty_pages, void, void)
+MALLOC_DECL_VOID(jemalloc_stats, jemalloc_stats_t *)
+MALLOC_DECL_VOID(jemalloc_purge_freed_pages, void)
+MALLOC_DECL_VOID(jemalloc_free_dirty_pages, void)
 #  endif
+
+#  undef MALLOC_DECL_VOID
 #endif /* MALLOC_DECL */
 
 #undef MALLOC_DECL
 #undef MALLOC_FUNCS
--- a/memory/build/replace_malloc.h
+++ b/memory/build/replace_malloc.h
@@ -69,29 +69,16 @@
 
 /* Implementing a replace-malloc library is incompatible with using mozalloc. */
 #define MOZ_NO_MOZALLOC 1
 
 #include "mozilla/Types.h"
 
 MOZ_BEGIN_EXTERN_C
 
-#define MALLOC_DECL(name, return_type, ...) \
-  typedef return_type(name ## _impl_t)(__VA_ARGS__);
-
-#include "malloc_decls.h"
-
-#define MALLOC_DECL(name, return_type, ...) \
-  name ## _impl_t * name;
-
-typedef struct {
-#include "malloc_decls.h"
-} malloc_table_t;
-
-
 /* MOZ_NO_REPLACE_FUNC_DECL and MOZ_REPLACE_WEAK are only defined in
  * replace_malloc.c. Normally including this header will add function
  * definitions. */
 #ifndef MOZ_NO_REPLACE_FUNC_DECL
 
 #  ifndef MOZ_REPLACE_WEAK
 #    define MOZ_REPLACE_WEAK
 #  endif
--- a/memory/build/replace_malloc_bridge.h
+++ b/memory/build/replace_malloc_bridge.h
@@ -43,25 +43,69 @@
  *
  * Parts that are not relevant to the replace-malloc library end of the
  * bridge are hidden when REPLACE_MALLOC_IMPL is not defined, which is
  * the case when including replace_malloc.h.
  */
 
 struct ReplaceMallocBridge;
 
-#ifdef __cplusplus
+#include "mozilla/Types.h"
 
-#include "mozilla/Types.h"
+MOZ_BEGIN_EXTERN_C
 
 #ifndef REPLACE_MALLOC_IMPL
 /* Returns the replace-malloc bridge if there is one to be returned. */
-extern "C" MFBT_API ReplaceMallocBridge* get_bridge();
+MFBT_API ReplaceMallocBridge* get_bridge();
 #endif
 
+/* Table of malloc functions.
+ *   e.g. void* (*malloc)(size_t), etc.
+ */
+#define MALLOC_DECL(name, return_type, ...) \
+  typedef return_type(name ## _impl_t)(__VA_ARGS__);
+
+#include "malloc_decls.h"
+
+#define MALLOC_DECL(name, return_type, ...) \
+  name ## _impl_t * name;
+
+typedef struct {
+#include "malloc_decls.h"
+} malloc_table_t;
+
+
+/* Table of malloc hook functions.
+ * Those functions are called with the arguments and results of malloc
+ * functions after they are called.
+ *   e.g. void* (*malloc_hook)(void*, size_t), etc.
+ * They can either return the result they're given, or alter it before
+ * returning it.
+ * The hooks corresponding to functions, like free(void*), that return no
+ * value, don't take an extra argument.
+ * The table must at least contain a pointer for malloc_hook and free_hook
+ * functions. They will be used as fallback if no pointer is given for
+ * other allocation functions, like calloc_hook.
+ */
+#define MALLOC_DECL(name, return_type, ...) \
+  return_type (*name ## _hook)(return_type, __VA_ARGS__);
+#define MALLOC_DECL_VOID(name, ...) \
+  void (*name ## _hook)(__VA_ARGS__);
+
+typedef struct {
+#include "malloc_decls.h"
+  /* Like free_hook, but called before realloc_hook. free_hook is called
+   * instead of not given. */
+  void (*realloc_hook_before)(void* aPtr);
+} malloc_hook_table_t;
+
+MOZ_END_EXTERN_C
+
+#ifdef __cplusplus
+
 namespace mozilla {
 namespace dmd {
 struct DMDFuncs;
 }
 
 /* Callbacks to register debug file handles for Poison IO interpose.
  * See Mozilla(|Un)RegisterDebugHandle in xpcom/build/PoisonIOInterposer.h */
 struct DebugFdRegistry
@@ -70,27 +114,44 @@ struct DebugFdRegistry
 
   virtual void UnRegisterHandle(intptr_t aFd);
 };
 
 } // namespace mozilla
 
 struct ReplaceMallocBridge
 {
-  ReplaceMallocBridge() : mVersion(2) {}
+  ReplaceMallocBridge() : mVersion(3) {}
 
   /* This method was added in version 1 of the bridge. */
   virtual mozilla::dmd::DMDFuncs* GetDMDFuncs() { return nullptr; }
 
   /* Send a DebugFdRegistry instance to the replace-malloc library so that
    * it can register/unregister file descriptors whenever needed. The
    * instance is valid until the process dies.
    * This method was added in version 2 of the bridge. */
   virtual void InitDebugFd(mozilla::DebugFdRegistry&) {}
 
+  /* Register a list of malloc functions and hook functions to the
+   * replace-malloc library so that it can choose to dispatch to them
+   * when needed. The details of what is dispatched when is left to the
+   * replace-malloc library.
+   * Passing a nullptr for either table will unregister a previously
+   * registered table under the same name.
+   * Returns nullptr if registration failed.
+   * If registration succeeded, a table of "pure" malloc functions is
+   * returned. Those "pure" malloc functions won't call hooks.
+   * /!\ Do not rely on registration/unregistration to be instantaneous.
+   * Functions from a previously registered table may still be called for
+   * a brief time after RegisterHook returns.
+   * This method was added in version 3 of the bridge. */
+  virtual const malloc_table_t*
+  RegisterHook(const char* aName, const malloc_table_t* aTable,
+               const malloc_hook_table_t* aHookTable) { return nullptr; }
+
 #ifndef REPLACE_MALLOC_IMPL
   /* Returns the replace-malloc bridge if its version is at least the
    * requested one. */
   static ReplaceMallocBridge* Get(int aMinimumVersion) {
     static ReplaceMallocBridge* sSingleton = get_bridge();
     return (sSingleton && sSingleton->mVersion >= aMinimumVersion)
       ? sSingleton : nullptr;
   }
@@ -119,14 +180,23 @@ struct ReplaceMalloc
 
   static void InitDebugFd(mozilla::DebugFdRegistry& aRegistry)
   {
     auto singleton = ReplaceMallocBridge::Get(/* minimumVersion */ 2);
     if (singleton) {
       singleton->InitDebugFd(aRegistry);
     }
   }
+
+  static const malloc_table_t*
+  RegisterHook(const char* aName, const malloc_table_t* aTable,
+               const malloc_hook_table_t* aHookTable)
+  {
+    auto singleton = ReplaceMallocBridge::Get(/* minimumVersion */ 3);
+    return singleton ? singleton->RegisterHook(aName, aTable, aHookTable)
+                     : nullptr;
+  }
 };
 #endif
 
 #endif /* __cplusplus */
 
 #endif /* replace_malloc_bridge_h */
--- a/memory/replace/moz.build
+++ b/memory/replace/moz.build
@@ -1,15 +1,18 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-DIRS += ['logalloc']
+DIRS += [
+    'logalloc',
+    'replace',
+]
 
 # Build jemalloc3 as a replace-malloc lib when building with mozjemalloc
 if not CONFIG['MOZ_JEMALLOC3']:
     DIRS += ['jemalloc']
 
 if CONFIG['MOZ_REPLACE_MALLOC_LINKAGE'] == 'dummy library':
     DIRS += ['dummy']
 
new file mode 100644
--- /dev/null
+++ b/memory/replace/replace/ReplaceMalloc.cpp
@@ -0,0 +1,255 @@
+/* -*- 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 "replace_malloc.h"
+#include <errno.h>
+#include "mozilla/CheckedInt.h"
+#include "mozilla/Atomics.h"
+
+/* Replace-malloc library allowing different kinds of dispatch.
+ * The long term goal is to allow multiple replace-malloc libraries
+ * to be loaded and coexist properly.
+ * This is however a limited version to fulfil more immediate needs.
+ */
+static const malloc_table_t* gFuncs = nullptr;
+/* This should normally be a mozilla::Atomic<const malloc_hook_table_t*>
+ * but MSVC 2013's atomic type doesn't like it. */
+static mozilla::Atomic<malloc_hook_table_t*> gHookTable(nullptr);
+
+class GenericReplaceMallocBridge : public ReplaceMallocBridge
+{
+  virtual const malloc_table_t*
+  RegisterHook(const char* aName, const malloc_table_t* aTable,
+               const malloc_hook_table_t* aHookTable) override
+  {
+    // Can't register a hook before replace_init is called.
+    if (!gFuncs) {
+      return nullptr;
+    }
+
+    // Expect a name to be given.
+    if (!aName) {
+      return nullptr;
+    }
+
+    // Giving a malloc_table_t is not supported yet.
+    if (aTable) {
+      return nullptr;
+    }
+
+    if (aHookTable) {
+      // Expect at least a malloc and a free hook.
+      if (!aHookTable->malloc_hook || !aHookTable->free_hook) {
+        return nullptr;
+      }
+      gHookTable = const_cast<malloc_hook_table_t*>(aHookTable);
+      return gFuncs;
+    }
+    gHookTable = nullptr;
+
+    return nullptr;
+  }
+};
+
+void
+replace_init(const malloc_table_t* aTable)
+{
+  gFuncs = aTable;
+}
+
+ReplaceMallocBridge*
+replace_get_bridge()
+{
+  static GenericReplaceMallocBridge bridge;
+  return &bridge;
+}
+
+void*
+replace_malloc(size_t aSize)
+{
+  void* ptr = gFuncs->malloc(aSize);
+  const malloc_hook_table_t* hook_table = gHookTable;
+  if (hook_table) {
+    return hook_table->malloc_hook(ptr, aSize);
+  }
+  return ptr;
+}
+
+int
+replace_posix_memalign(void** aPtr, size_t aAlignment, size_t aSize)
+{
+  int ret = gFuncs->posix_memalign(aPtr, aAlignment, aSize);
+  const malloc_hook_table_t* hook_table = gHookTable;
+  if (hook_table) {
+    if (hook_table->posix_memalign_hook) {
+      return hook_table->posix_memalign_hook(ret, aPtr, aAlignment, aSize);
+    }
+    void* ptr = hook_table->malloc_hook(*aPtr, aSize);
+    if (!ptr && *aPtr) {
+      *aPtr = ptr;
+      ret = ENOMEM;
+    }
+  }
+  return ret;
+}
+
+void*
+replace_aligned_alloc(size_t aAlignment, size_t aSize)
+{
+  void* ptr = gFuncs->aligned_alloc(aAlignment, aSize);
+  const malloc_hook_table_t* hook_table = gHookTable;
+  if (hook_table) {
+    if (hook_table->aligned_alloc_hook) {
+      return hook_table->aligned_alloc_hook(ptr, aAlignment, aSize);
+    }
+    return hook_table->malloc_hook(ptr, aSize);
+  }
+  return ptr;
+}
+
+void*
+replace_calloc(size_t aNum, size_t aSize)
+{
+  void* ptr = gFuncs->calloc(aNum, aSize);
+  const malloc_hook_table_t* hook_table = gHookTable;
+  if (hook_table) {
+    if (hook_table->calloc_hook) {
+      return hook_table->calloc_hook(ptr, aNum, aSize);
+    }
+    mozilla::CheckedInt<size_t> size = mozilla::CheckedInt<size_t>(aNum) * aSize;
+    if (size.isValid()) {
+      return hook_table->malloc_hook(ptr, size.value());
+    }
+    /* If the multiplication above overflows, calloc will have failed, so ptr
+     * is null. But the hook might still be interested in knowing about the
+     * allocation attempt. The choice made is to indicate the overflow with
+     * the biggest value of a size_t, which is not that bad an indicator:
+     * there are only 5 prime factors to 2^32 - 1 and 7 prime factors to
+     * 2^64 - 1 and none of them is going to come directly out of sizeof().
+     * IOW, the likelyhood of aNum * aSize being exactly SIZE_MAX is low
+     * enough, and SIZE_MAX still conveys that the attempted allocation was
+     * too big anyways. */
+    return hook_table->malloc_hook(ptr, SIZE_MAX);
+  }
+  return ptr;
+}
+
+void*
+replace_realloc(void* aPtr, size_t aSize)
+{
+  const malloc_hook_table_t* hook_table = gHookTable;
+  if (hook_table) {
+    if (hook_table->realloc_hook_before) {
+      hook_table->realloc_hook_before(aPtr);
+    } else {
+      hook_table->free_hook(aPtr);
+    }
+  }
+  void* new_ptr = gFuncs->realloc(aPtr, aSize);
+  /* The hook table might have changed since before realloc was called,
+   * either because of unregistration or registration of a new table.
+   * We however go with consistency and use the same hook table as the
+   * one that was used before the call to realloc. */
+  if (hook_table) {
+    if (hook_table->realloc_hook) {
+      /* aPtr is likely invalid when reaching here, it is only given for
+       * tracking purposes, and should not be dereferenced. */
+      return hook_table->realloc_hook(new_ptr, aPtr, aSize);
+    }
+    return hook_table->malloc_hook(new_ptr, aSize);
+  }
+  return new_ptr;
+}
+
+void
+replace_free(void* aPtr)
+{
+  const malloc_hook_table_t* hook_table = gHookTable;
+  if (hook_table) {
+    hook_table->free_hook(aPtr);
+  }
+  gFuncs->free(aPtr);
+}
+
+void*
+replace_memalign(size_t aAlignment, size_t aSize)
+{
+  void* ptr = gFuncs->memalign(aAlignment, aSize);
+  const malloc_hook_table_t* hook_table = gHookTable;
+  if (hook_table) {
+    if (hook_table->memalign_hook) {
+      return hook_table->memalign_hook(ptr, aAlignment, aSize);
+    }
+    return hook_table->malloc_hook(ptr, aSize);
+  }
+  return ptr;
+}
+
+void*
+replace_valloc(size_t aSize)
+{
+  void* ptr = gFuncs->valloc(aSize);
+  const malloc_hook_table_t* hook_table = gHookTable;
+  if (hook_table) {
+    if (hook_table->valloc_hook) {
+      return hook_table->valloc_hook(ptr, aSize);
+    }
+    return hook_table->malloc_hook(ptr, aSize);
+  }
+  return ptr;
+}
+
+size_t
+replace_malloc_usable_size(usable_ptr_t aPtr)
+{
+  size_t ret = gFuncs->malloc_usable_size(aPtr);
+  const malloc_hook_table_t* hook_table = gHookTable;
+  if (hook_table && hook_table->malloc_usable_size_hook) {
+    return hook_table->malloc_usable_size_hook(ret, aPtr);
+  }
+  return ret;
+}
+
+size_t
+replace_malloc_good_size(size_t aSize)
+{
+  size_t ret = gFuncs->malloc_good_size(aSize);
+  const malloc_hook_table_t* hook_table = gHookTable;
+  if (hook_table && hook_table->malloc_good_size_hook) {
+    return hook_table->malloc_good_size_hook(ret, aSize);
+  }
+  return ret;
+}
+
+void
+replace_jemalloc_stats(jemalloc_stats_t* aStats)
+{
+  gFuncs->jemalloc_stats(aStats);
+  const malloc_hook_table_t* hook_table = gHookTable;
+  if (hook_table && hook_table->jemalloc_stats_hook) {
+    hook_table->jemalloc_stats_hook(aStats);
+  }
+}
+
+void
+replace_jemalloc_purge_freed_pages(void)
+{
+  gFuncs->jemalloc_purge_freed_pages();
+  const malloc_hook_table_t* hook_table = gHookTable;
+  if (hook_table && hook_table->jemalloc_purge_freed_pages_hook) {
+    hook_table->jemalloc_purge_freed_pages_hook();
+  }
+}
+
+void
+replace_jemalloc_free_dirty_pages(void)
+{
+  gFuncs->jemalloc_free_dirty_pages();
+  const malloc_hook_table_t* hook_table = gHookTable;
+  if (hook_table && hook_table->jemalloc_free_dirty_pages_hook) {
+    hook_table->jemalloc_free_dirty_pages_hook();
+  }
+}
new file mode 100644
--- /dev/null
+++ b/memory/replace/replace/moz.build
@@ -0,0 +1,13 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+SharedLibrary('replace_malloc')
+
+SOURCES += [
+    'ReplaceMalloc.cpp',
+]
+
+DISABLE_STL_WRAPPING = True
--- a/modules/libpref/Preferences.cpp
+++ b/modules/libpref/Preferences.cpp
@@ -518,18 +518,17 @@ NS_INTERFACE_MAP_END
  * nsIPrefService Implementation
  */
 
 nsresult
 Preferences::Init()
 {
   nsresult rv;
 
-  rv = PREF_Init();
-  NS_ENSURE_SUCCESS(rv, rv);
+  PREF_Init();
 
   rv = pref_InitInitialObjects();
   NS_ENSURE_SUCCESS(rv, rv);
 
   using mozilla::dom::ContentChild;
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
     InfallibleTArray<PrefSetting> prefs;
     ContentChild::GetSingleton()->SendReadPrefsArray(&prefs);
@@ -639,18 +638,17 @@ Preferences::ResetPrefs()
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
     NS_ERROR("cannot reset prefs from content process");
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   NotifyServiceObservers(NS_PREFSERVICE_RESET_TOPIC_ID);
   PREF_CleanupPrefs();
 
-  nsresult rv = PREF_Init();
-  NS_ENSURE_SUCCESS(rv, rv);
+  PREF_Init();
 
   return pref_InitInitialObjects();
 }
 
 NS_IMETHODIMP
 Preferences::ResetUserPrefs()
 {
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -370,17 +370,18 @@ pref("media.peerconnection.video.start_b
 pref("media.peerconnection.video.max_bitrate", 2000);
 #endif
 pref("media.navigator.permission.disabled", false);
 pref("media.peerconnection.default_iceservers", "[]");
 pref("media.peerconnection.ice.loopback", false); // Set only for testing in offline environments.
 pref("media.peerconnection.use_document_iceservers", true);
 pref("media.peerconnection.identity.enabled", true);
 pref("media.peerconnection.identity.timeout", 10000);
-pref("media.peerconnection.ice.loopback", false); // Set only for testing in offline environments.
+pref("media.peerconnection.ice.stun_client_maximum_transmits", 7);
+pref("media.peerconnection.ice.trickle_grace_period", 5000);
 // These values (aec, agc, and noice) are from media/webrtc/trunk/webrtc/common_types.h
 // kXxxUnchanged = 0, kXxxDefault = 1, and higher values are specific to each
 // setting (for Xxx = Ec, Agc, or Ns).  Defaults are all set to kXxxDefault here.
 pref("media.peerconnection.turn.disable", false);
 #if defined(MOZ_WEBRTC_HARDWARE_AEC_NS)
 pref("media.getusermedia.aec_enabled", false);
 pref("media.getusermedia.noise_enabled", false);
 #else
--- a/modules/libpref/prefapi.cpp
+++ b/modules/libpref/prefapi.cpp
@@ -142,27 +142,26 @@ enum {
     kPrefSetDefault = 1,
     kPrefForceSet = 2,
     kPrefStickyDefault = 4,
 };
 static nsresult pref_HashPref(const char *key, PrefValue value, PrefType type, uint32_t flags);
 
 #define PREF_HASHTABLE_INITIAL_LENGTH   1024
 
-nsresult PREF_Init()
+void PREF_Init()
 {
     if (!gHashTable) {
         gHashTable = new PLDHashTable(&pref_HashTableOps,
                                       sizeof(PrefHashEntry),
                                       PREF_HASHTABLE_INITIAL_LENGTH);
 
         PL_INIT_ARENA_POOL(&gPrefNameArena, "PrefNameArena",
                            PREFNAME_ARENA_SIZE);
     }
-    return NS_OK;
 }
 
 /* Frees the callback list. */
 void PREF_Cleanup()
 {
     NS_ASSERTION(!gCallbacksInProgress,
         "PREF_Cleanup was called while gCallbacksInProgress is true!");
     struct CallbackNode* node = gCallbacks;
--- a/modules/libpref/prefapi.h
+++ b/modules/libpref/prefapi.h
@@ -37,17 +37,17 @@ struct PrefHashEntry : PLDHashEntryHdr
 };
 
 /*
 // <font color=blue>
 // The Init function initializes the preference context and creates
 // the preference hashtable.
 // </font>
 */
-nsresult    PREF_Init();
+void        PREF_Init();
 
 /*
 // Cleanup should be called at program exit to free the 
 // list of registered callbacks.
 */
 void        PREF_Cleanup();
 void        PREF_CleanupPrefs();
 
--- a/security/manager/ssl/tests/unit/head_psm.js
+++ b/security/manager/ssl/tests/unit/head_psm.js
@@ -125,20 +125,24 @@ function addCertFromFile(certdb, filenam
   if (!successful) {
     // It might be PEM instead of DER.
     certdb.addCertFromBase64(pemToBase64(certBytes), trustString, null);
   }
 }
 
 function constructCertFromFile(filename) {
   let certFile = do_get_file(filename, false);
-  let certDER = readFile(certFile);
+  let certBytes = readFile(certFile);
   let certdb = Cc["@mozilla.org/security/x509certdb;1"]
-                  .getService(Ci.nsIX509CertDB);
-  return certdb.constructX509(certDER, certDER.length);
+                 .getService(Ci.nsIX509CertDB);
+  try {
+    return certdb.constructX509(certBytes, certBytes.length);
+  } catch (e) {}
+  // It might be PEM instead of DER.
+  return certdb.constructX509FromBase64(pemToBase64(certBytes));
 }
 
 function setCertTrust(cert, trustString) {
   let certdb = Cc["@mozilla.org/security/x509certdb;1"]
                   .getService(Ci.nsIX509CertDB);
   certdb.setCertTrustFromString(cert, trustString);
 }
 
--- a/security/manager/ssl/tests/unit/moz.build
+++ b/security/manager/ssl/tests/unit/moz.build
@@ -1,11 +1,14 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DIRS += ['tlsserver']
-TEST_DIRS += ['test_intermediate_basic_usage_constraints']
+TEST_DIRS += [
+    'test_cert_keyUsage',
+    'test_intermediate_basic_usage_constraints',
+]
 
 if not CONFIG['MOZ_NO_SMART_CARDS']:
     DIRS += ['pkcs11testmodule']
rename from security/manager/ssl/tests/unit/test_certificate_usages.js
rename to security/manager/ssl/tests/unit/test_cert_keyUsage.js
--- a/security/manager/ssl/tests/unit/test_certificate_usages.js
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage.js
@@ -1,126 +1,61 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 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/. */
+
 "use strict";
 
-/* To regenerate the certificates and apps for this test:
+do_get_profile(); // must be called before getting nsIX509CertDB
+let certdb = Cc["@mozilla.org/security/x509certdb;1"]
+               .getService(Ci.nsIX509CertDB);
 
-        cd security/manager/ssl/tests/unit/test_certificate_usages
-        PATH=$NSS/bin:$NSS/lib:$PATH ./generate.pl
-        cd ../../../../../..
-        make -C $OBJDIR/security/manager/ssl/tests
+let caList = ["ca-no-keyUsage-extension", "ca-missing-keyCertSign",
+              "ca-all-usages"];
+let eeList = ["ee-no-keyUsage-extension", "ee-keyCertSign-only",
+              "ee-keyEncipherment-only", "ee-keyCertSign-and-keyEncipherment"];
+
+let caUsage = "SSL CA";
+let allEEUsages = "Client,Server,Sign,Encrypt,Object Signer";
+let serverEEUsages = "Server,Encrypt";
 
-   $NSS is the path to NSS binaries and libraries built for the host platform.
-   If you get error messages about "CertUtil" on Windows, then it means that
-   the Windows CertUtil.exe is ahead of the NSS certutil.exe in $PATH.
+let expectedUsagesMap = {
+  "ca-no-keyUsage-extension": caUsage,
+  "ca-missing-keyCertSign": "",
+  "ca-all-usages": caUsage,
+
+  "ee-no-keyUsage-extension-ca-no-keyUsage-extension": allEEUsages,
+  "ee-no-keyUsage-extension-ca-missing-keyCertSign": "",
+  "ee-no-keyUsage-extension-ca-all-usages": allEEUsages,
 
-   Check in the generated files. These steps are not done as part of the build
-   because we do not want to add a build-time dependency on the OpenSSL or NSS
-   tools or libraries built for the host platform.
-*/
+  "ee-keyCertSign-only-ca-no-keyUsage-extension": "",
+  "ee-keyCertSign-only-ca-missing-keyCertSign": "",
+  "ee-keyCertSign-only-ca-all-usages": "",
 
-do_get_profile(); // must be called before getting nsIX509CertDB
-const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(Ci.nsIX509CertDB);
+  "ee-keyEncipherment-only-ca-no-keyUsage-extension": serverEEUsages,
+  "ee-keyEncipherment-only-ca-missing-keyCertSign": "",
+  "ee-keyEncipherment-only-ca-all-usages": serverEEUsages,
 
-const gNumCAs = 4;
+  "ee-keyCertSign-and-keyEncipherment-ca-no-keyUsage-extension": serverEEUsages,
+  "ee-keyCertSign-and-keyEncipherment-ca-missing-keyCertSign": "",
+  "ee-keyCertSign-and-keyEncipherment-ca-all-usages": serverEEUsages,
+};
 
 function run_test() {
-  //ca's are one based!
-  for (var i = 0; i < gNumCAs; i++) {
-    var ca_name = "ca-" + (i + 1);
-    var ca_filename = ca_name + ".der";
-    addCertFromFile(certdb, "test_certificate_usages/" + ca_filename, "CTu,CTu,CTu");
-    var cert = certdb.findCertByNickname(null, ca_name);
-  }
-
-  // mozilla::pkix doesn't allow CA certificates to have the Status Responder
-  // EKU.
-  var ca_usages = ['SSL CA',
-                   'SSL CA',
-                   'SSL CA',
-                   ''];
-
-  // mozilla::pkix doesn't implement the Netscape Object Signer restriction.
-  var basicEndEntityUsages = 'Client,Server,Sign,Encrypt,Object Signer';
-
-  // mozilla::pkix won't let a certificate with the 'Status Responder' EKU get
-  // validated for any other usage.
-  var ee_usages = [
-    [ basicEndEntityUsages,
-      basicEndEntityUsages,
-      basicEndEntityUsages,
-      basicEndEntityUsages,
-      '',
-      'Status Responder',
-      'Client,Server',
-      'Sign,Encrypt,Object Signer',
-      'Status Responder'
-    ],
-
-    [ basicEndEntityUsages,
-      basicEndEntityUsages,
-      basicEndEntityUsages,
-      basicEndEntityUsages,
-      '',
-      'Status Responder',
-      'Client,Server',
-      'Sign,Encrypt,Object Signer',
-      'Status Responder'
-    ],
-
-    [ basicEndEntityUsages,
-      basicEndEntityUsages,
-      basicEndEntityUsages,
-      basicEndEntityUsages,
-      '',
-      'Status Responder',
-      'Client,Server',
-      'Sign,Encrypt,Object Signer',
-      'Status Responder'
-    ],
-
-    // The CA has isCA=true without keyCertSign.
-    //
-    // The 'classic' NSS mode uses the 'union' of the
-    // capabilites so the cert is considered a CA.
-    // mozilla::pkix and libpkix use the intersection of
-    // capabilites, so the cert is NOT considered a CA.
-    [ '',
-      '',
-      '',
-      '',
-      '',
-      '',
-      '',
-      '',
-      ''
-     ]
-  ];
-
-  equal(gNumCAs, ca_usages.length,
-        "Number of CAs and length of ca_usages array should match");
-
-  for (var i = 0; i < gNumCAs; i++) {
-    var ca_name = "ca-" + (i + 1);
-    var verified = {};
-    var usages = {};
-    var cert = certdb.findCertByNickname(null, ca_name);
-    cert.getUsagesString(true, verified, usages);
-    equal(ca_usages[i], usages.value,
-          "Expected and actual CA usages string should match");
-    if (ca_usages[i].indexOf('SSL CA') != -1) {
-      checkCertErrorGeneric(certdb, cert, PRErrorCodeSuccess,
-                            certificateUsageVerifyCA);
-    }
-    //now the ee, names also one based
-    for (var j = 0; j < ee_usages[i].length; j++) {
-      var ee_name = "ee-" + (j + 1) + "-" + ca_name;
-      var ee_filename = ee_name + ".der";
-      addCertFromFile(certdb, "test_certificate_usages/" + ee_filename, ",,");
-      var ee_cert;
-      ee_cert = certdb.findCertByNickname(null, ee_name);
-      var verified = {};
-      var usages = {};
-      ee_cert.getUsagesString(true, verified, usages);
-      equal(ee_usages[i][j], usages.value,
-            "Expected and actual EE usages string should match");
-    }
-  }
+  caList.forEach(function(ca) {
+    addCertFromFile(certdb, "test_cert_keyUsage/" + ca + ".pem",
+                    "CTu,CTu,CTu");
+    let caCert = certdb.findCertByNickname(null, ca);
+    let usages = {};
+    caCert.getUsagesString(true, {}, usages); // true indicates local-only
+    equal(usages.value, expectedUsagesMap[ca],
+          "Actual and expected CA usages should match");
+    eeList.forEach(function(ee) {
+      let eeFullName = ee + "-" + ca;
+      let cert = constructCertFromFile(
+        "test_cert_keyUsage/" + eeFullName + ".pem");
+      cert.getUsagesString(true, {}, usages); // true indicates local-only
+      equal(usages.value, expectedUsagesMap[eeFullName],
+            "Actual and expected EE usages should match");
+    });
+  });
 }
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ca-all-usages.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca-all-usages
+subject:ca-all-usages
+extension:basicConstraints:cA,
+extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ca-missing-keyCertSign.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca-missing-keyCertSign
+subject:ca-missing-keyCertSign
+extension:basicConstraints:cA,
+extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,cRLSign
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ca-no-keyUsage-extension.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca-no-keyUsage-extension
+subject:ca-no-keyUsage-extension
+extension:basicConstraints:cA,
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-all-usages.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca-all-usages
+subject:ee-keyCertSign-and-keyEncipherment
+extension:keyUsage:keyEncipherment,keyCertSign
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-missing-keyCertSign.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca-missing-keyCertSign
+subject:ee-keyCertSign-and-keyEncipherment
+extension:keyUsage:keyEncipherment,keyCertSign
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-no-keyUsage-extension.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca-no-keyUsage-extension
+subject:ee-keyCertSign-and-keyEncipherment
+extension:keyUsage:keyEncipherment,keyCertSign
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-all-usages.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca-all-usages
+subject:ee-keyCertSign-only
+extension:keyUsage:keyCertSign
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-missing-keyCertSign.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca-missing-keyCertSign
+subject:ee-keyCertSign-only
+extension:keyUsage:keyCertSign
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-no-keyUsage-extension.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca-no-keyUsage-extension
+subject:ee-keyCertSign-only
+extension:keyUsage:keyCertSign
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-all-usages.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca-all-usages
+subject:ee-keyEncipherment-only
+extension:keyUsage:keyEncipherment
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-missing-keyCertSign.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca-missing-keyCertSign
+subject:ee-keyEncipherment-only
+extension:keyUsage:keyEncipherment
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-no-keyUsage-extension.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca-no-keyUsage-extension
+subject:ee-keyEncipherment-only
+extension:keyUsage:keyEncipherment
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-all-usages.pem.certspec
@@ -0,0 +1,2 @@
+issuer:ca-all-usages
+subject:ee-no-keyUsage-extension
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-missing-keyCertSign.pem.certspec
@@ -0,0 +1,2 @@
+issuer:ca-missing-keyCertSign
+subject:ee-no-keyUsage-extension
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-no-keyUsage-extension.pem.certspec
@@ -0,0 +1,2 @@
+issuer:ca-no-keyUsage-extension
+subject:ee-no-keyUsage-extension
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/moz.build
@@ -0,0 +1,31 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+test_certificates = (
+    'ca-all-usages.pem',
+    'ca-missing-keyCertSign.pem',
+    'ca-no-keyUsage-extension.pem',
+    'ee-keyCertSign-and-keyEncipherment-ca-all-usages.pem',
+    'ee-keyCertSign-and-keyEncipherment-ca-missing-keyCertSign.pem',
+    'ee-keyCertSign-and-keyEncipherment-ca-no-keyUsage-extension.pem',
+    'ee-keyCertSign-only-ca-all-usages.pem',
+    'ee-keyCertSign-only-ca-missing-keyCertSign.pem',
+    'ee-keyCertSign-only-ca-no-keyUsage-extension.pem',
+    'ee-keyEncipherment-only-ca-all-usages.pem',
+    'ee-keyEncipherment-only-ca-missing-keyCertSign.pem',
+    'ee-keyEncipherment-only-ca-no-keyUsage-extension.pem',
+    'ee-no-keyUsage-extension-ca-all-usages.pem',
+    'ee-no-keyUsage-extension-ca-missing-keyCertSign.pem',
+    'ee-no-keyUsage-extension-ca-no-keyUsage-extension.pem',
+)
+
+for test_certificate in test_certificates:
+    input_file = test_certificate + '.certspec'
+    GENERATED_FILES += [test_certificate]
+    props = GENERATED_FILES[test_certificate]
+    props.script = '../pycert.py'
+    props.inputs = [input_file, '!/config/buildid']
+    TEST_HARNESS_FILES.xpcshell.security.manager.ssl.tests.unit.test_cert_keyUsage += ['!%s' % test_certificate]
deleted file mode 100644
index 0cc4977fb0c8b3c16c03b07dfe0e50abc25059e3..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 4ac92f45c9a34e32bcd7add188596d70a286af17..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index cfc35a40ee79f426cff616aa697dcb305c2179bb..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 9bceda43f6af139640be7e6c68d8dff96ecb4902..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 2926df942283926efc3eb0bd31212b21b0ed0c13..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 9104409e9a1975b243757c9b3e2f0e7b34cad15e..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 8f30faa9b2b28b71e9d2e83bbd8791849fe444d3..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 468c3c4c91f8ca804f946feb91905b41fcea5f76..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 3ae1cbecb88a563ba3e2d8c00269b9d26391d8a7..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 72acb14e7f15bdc201450dc4488038e227749a32..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 4658d18fa76619777b4ddf972199df97b46d809d..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index a739f44b4aee53754ab920fae12a3c3980481c17..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 1254d1032f63764475702b1f00eabe252f8bbf94..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 09370517236ca0fe9b1d1d4452e86a041c5f54d3..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index f6bd1f82d75aa8a0cf6076cb1b3a43e2c80dc87a..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 43a8e39c49e2130145d6e37e1386f01c7132937e..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 7aa2ff99f3a28152e1f2d3f66bb631dc0b00e462..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index f8dadbe7db95964eb4cb6e8d7bb756f5974bc73a..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 0758913276826a8903848e984926a913c899f47f..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index b461755a58bbdb397c18be0bb0fd4fe17570837f..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 6e088d150383539d75723e850432ed9416196ab3..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 236bb923ce13243c296f77d57971d4e682e3b6b6..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 19f93e8b549de0cd6df20f37ceec233f80c444a1..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index e71cc02701f1e5bc6b4bc9757fa95db9ebffc8b0..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 45b89c00f2b540b9a07e9e8bc2a418b8bdfb4ef6..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 3454cd9d9ef3613cf97765533917e93845015f2d..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 8b83671e60180d246029a9eb9b22f7466e1950fa..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 336e250082da4bd86048b22c4e7f1f308b30b5be..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 45a486cc4688deba9dc0cee41bf38c686d4fcb0f..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index ea31ad0a98fbd8d87b72787aef6f5fe608a9e59e..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index f42042be4706ebe63fd78b9b041baa3e3779a718..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 95a089113513848b8d59ee0b972a8292b6bb43ad..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index caa2616577958dd38cb4bc6fb2f52661632f8047..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index ce57e0c65db01ac8cffac270778b5971e22be6d2..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 9d6db4ec7cb0bcadac345e42604d99c5451509de..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index bbf23877bd31bc6629ed117b924b860457f92d31..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 6c863efd4166385f7815e93e416b98ea0bd1a9d6..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 98fb14acfa041976b41b31ab9f097703635b1a2f..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index c1566ec6e8803d097b6f0b3a1168d8de7782763e..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 495aee8822320fdd445c04993329db57cda14189..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100755
--- a/security/manager/ssl/tests/unit/test_certificate_usages/generate.pl
+++ /dev/null
@@ -1,109 +0,0 @@
-#!/usr/bin/perl
-# Usage:
-# PATH=$NSS_PREFIX/bin:$NSS_PREFIX/lib:$PATH ./generate.pl
-
-use Cwd;
-use File::Temp qw/ tempfile tempdir /;
-
-use strict;
-
-my $srcdir=getcwd();
-my $db = tempdir( CLEANUP => 1 );
-my $noisefile=$db."/noise";
-my $passwordfile=$db."/passwordfile";
-my $ca_responses=$srcdir."/ca_responses";
-my $ee_responses=$srcdir."/ee_responses";
-
-#my $db=$tmpdir;
-
-my @base_usages=("",
-                 "certSigning,crlSigning",
-                 "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,certSigning,crlSigning",
-                 "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,crlSigning");
-
-my @ee_usages=("",
-               "digitalSignature,keyEncipherment,dataEncipherment",
-               "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement",
-               "digitalSignature,keyEncipherment,dataEncipherment,certSigning",
-               "certSigning");
-my @eku_usages=("serverAuth,clientAuth,codeSigning,emailProtection,timeStamp,ocspResponder,stepUp,msTrustListSign",
-                "serverAuth,clientAuth",
-                "codeSigning,emailProtection",
-                "timeStamp,ocspResponder,stepUp,msTrustListSign"
-               );
-
-sub dsystem{
-    my @args = @_;
-    system(@args) == 0
-    or die "system @args failed: $?";
-}
-
-sub generate_certs(){
-   for (my $i = 1; $i < scalar(@base_usages) + 1; $i++) {
-     my $ca_name = "ca-$i";
-     my $ca_key_usage = $base_usages[$i - 1];
-     if (length($ca_key_usage) > 1) {
-       $ca_key_usage = " --keyUsage $ca_key_usage,critical";
-     }
-     my $ca_email = "$ca_name\@example.com";
-     my $ca_subject = "CN=$ca_name, E=$ca_email";
-     print "key_usage=$ca_key_usage\n";
-     dsystem("certutil -S -s '$ca_name' -s '$ca_subject' -t 'C,,' -x -m $i -v 120 -n '$ca_name' $ca_key_usage -Z SHA256 -2 -d $db -f $passwordfile -z $noisefile < $ca_responses");
-
-     #and now export
-     dsystem("certutil -d $db -f $passwordfile -L -n $ca_name -r -o $srcdir/$ca_name.der");
-
-     for (my $j = 1; $j < scalar(@ee_usages) + 1; $j++) {
-       ##do ee certs
-       my $ee_name = "ee-$j-ca-$i";
-       my $ee_key_usage = $ee_usages[$j - 1];
-       if (length($ee_key_usage) > 1) {
-         $ee_key_usage=" --keyUsage $ee_key_usage,critical";
-       }
-       my $serial = (scalar(@base_usages) + 1) * $j + $i;
-       dsystem("certutil -S -n '$ee_name' -s 'CN=$ee_name' -c '$ca_name' $ee_key_usage -t 'P,,' -k rsa -g 1024 -Z SHA256 -m $serial -v 120 -d $db -f $passwordfile -z $noisefile < $ee_responses");
-       #and export
-       dsystem("certutil -d $db -f $passwordfile -L -n $ee_name -r -o $srcdir/$ee_name.der");
-     }
-     for (my $j = 1; $j < scalar(@eku_usages) + 1; $j++){
-       my $ee_name = "ee-" . ($j + scalar(@ee_usages)) . "-ca-$i";
-       my $eku_key_usage = $eku_usages[$j - 1];
-       $eku_key_usage = " --extKeyUsage $eku_key_usage,critical";
-       my $serial = 10000 + (scalar(@base_usages) + 1) * $j + $i;
-       dsystem("certutil -S -n '$ee_name' -s 'CN=$ee_name' -c '$ca_name' $eku_key_usage -t 'P,,' -k rsa -g 1024 -Z SHA256 -m $serial -v 120 -d $db -f $passwordfile -z $noisefile < $ee_responses");
-       #and export
-       dsystem("certutil -d $db -f $passwordfile -L -n $ee_name -r -o $srcdir/$ee_name.der");
-
-     }
-   }
-}
-
-
-sub main(){
-
-  ##setup
-  dsystem("echo password1 > $passwordfile");
-  dsystem("head --bytes 32 /dev/urandom > $noisefile");
-
-  ##why no include this in the source dir?
-# XXX: certutil cannot generate basic constraints without interactive prompts,
-#      so we need to build response files to answer its questions
-# XXX: certutil cannot generate AKI/SKI without interactive prompts so we just
-#      skip them.
-  dsystem("echo y >  $ca_responses"); # Is this a CA?
-  dsystem("echo >>   $ca_responses");# Accept default path length constraint (no constraint)
-  dsystem("echo y >> $ca_responses"); # Is this a critical constraint?
-  dsystem("echo n >  $ee_responses"); # Is this a CA?
-  dsystem("echo >>   $ee_responses"); # Accept default path length constraint (no constraint)
-  dsystem("echo y >> $ee_responses"); # Is this a critical constraint?
-
-  dsystem("certutil -d $db -N -f $passwordfile");
-
-  generate_certs();
-
-  print "Done\n";
-
-}
-
-
-main();
--- a/security/manager/ssl/tests/unit/xpcshell.ini
+++ b/security/manager/ssl/tests/unit/xpcshell.ini
@@ -1,14 +1,14 @@
 [DEFAULT]
 head = head_psm.js
 tail =
 tags = psm
 support-files =
-  test_certificate_usages/**
+  test_cert_keyUsage/**
   test_signed_apps/**
   tlsserver/**
   test_cert_signatures/**
   test_client_cert/**
   test_ev_certs/**
   test_getchain/**
   test_intermediate_basic_usage_constraints/**
   test_name_constraints/**
@@ -39,17 +39,17 @@ skip-if = toolkit == 'android' || toolki
 [test_sss_readstate_empty.js]
 [test_sss_readstate_garbage.js]
 [test_sss_readstate_huge.js]
 [test_sss_savestate.js]
 
 [test_pinning_dynamic.js]
 [test_pinning_header_parsing.js]
 
-[test_certificate_usages.js]
+[test_cert_keyUsage.js]
 [test_ocsp_stapling.js]
 run-sequentially = hardcoded ports
 [test_cert_blocklist.js]
 skip-if = buildapp == "b2g"
 [test_ocsp_stapling_expired.js]
 run-sequentially = hardcoded ports
 [test_ocsp_stapling_with_intermediate.js]
 run-sequentially = hardcoded ports
new file mode 100644
--- /dev/null
+++ b/testing/runtimes/linux-debug/mochitest-e10s-browser-chrome.runtimes.json
@@ -0,0 +1,1 @@
+{"excluded_test_average": 3298, "runtimes": {"browser/components/preferences/in-content/tests/browser_privacypane_1.js": 13532, "browser/components/sessionstore/test/browser_394759_behavior.js": 33796, "toolkit/mozapps/extensions/test/browser/browser_cancelCompatCheck.js": 36153, "browser/components/sessionstore/test/browser_522545.js": 46348, "browser/components/customizableui/test/browser_876926_customize_mode_wrapping.js": 16493, "browser/components/sessionstore/test/browser_595601-restore_hidden.js": 21551, "toolkit/components/thumbnails/test/browser_thumbnails_privacy.js": 22711, "browser/components/sessionstore/test/browser_cleaner.js": 14907, "browser/base/content/test/social/browser_social_window.js": 26467, "toolkit/mozapps/extensions/test/browser/test-window/browser_searching.js": 39991, "browser/base/content/test/general/browser_e10s_switchbrowser.js": 20911, "browser/base/content/test/general/browser_e10s_chrome_process.js": 17712, "toolkit/mozapps/extensions/test/browser/test-window/browser_recentupdates.js": 15006, "browser/base/content/test/general/browser_sanitizeDialog.js": 22714, "toolkit/mozapps/extensions/test/browser/browser_manualupdates.js": 13113, "browser/components/customizableui/test/browser_938980_navbar_collapsed.js": 25867, "browser/components/sessionstore/test/browser_frame_history.js": 12177, "browser/base/content/test/general/browser_mcb_redirect.js": 13471, "browser/components/sessionstore/test/browser_async_remove_tab.js": 13836, "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_toggle.js": 15247, "toolkit/mozapps/extensions/test/browser/test-window/browser_bug572561.js": 11907, "browser/base/content/test/general/browser_tabMatchesInAwesomebar.js": 26107, "toolkit/mozapps/extensions/test/browser/test-window/browser_inlinesettings_info.js": 15103, "browser/components/sessionstore/test/browser_cookies.js": 37877, "browser/components/customizableui/test/browser_880164_customization_context_menus.js": 28818, "toolkit/mozapps/extensions/test/browser/browser_dragdrop.js": 13416, "browser/base/content/test/general/browser_bug1025195_switchToTabHavingURI_aOpenParams.js": 14686, "toolkit/components/startup/tests/browser/browser_crash_detection.js": 35104, "dom/manifest/test/browser_ManifestObtainer_obtain.js": 55239, "browser/components/sessionstore/test/browser_sessionHistory.js": 18281, "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_sidebar.js": 15393, "browser/base/content/test/plugins/browser_blocking.js": 14798, "toolkit/components/passwordmgr/test/browser/browser_notifications.js": 22847, "toolkit/mozapps/extensions/test/browser/test-window/browser_details.js": 43088, "browser/base/content/test/general/browser_fxa_oauth.js": 11617, "browser/base/content/test/social/browser_aboutHome_activation.js": 10192, "browser/components/preferences/in-content/tests/browser_bug1020245_openPreferences_to_paneContent.js": 12068, "dom/ipc/tests/browser_domainPolicy.js": 25785, "browser/components/sessionstore/test/browser_586068-window_state.js": 13703, "browser/components/preferences/in-content/tests/browser_privacypane_3.js": 12588, "toolkit/mozapps/extensions/test/browser/test-window/browser_bug567137.js": 12712, "testing/mochitest/tests/browser/browser_fail_timeout.js": 40138, "toolkit/mozapps/extensions/test/browser/test-window/browser_sorting.js": 14784, "browser/components/preferences/in-content/tests/browser_privacypane_4.js": 24169, "browser/components/sessionstore/test/browser_formdata.js": 14378, "browser/base/content/test/general/browser_no_mcb_on_http_site.js": 13252, "toolkit/mozapps/extensions/test/browser/browser_list.js": 19312, "toolkit/mozapps/extensions/test/browser/browser_updatessl.js": 51353, "toolkit/mozapps/extensions/test/browser/test-window/browser_bug591465.js": 11408, "browser/base/content/test/general/browser_bug902156.js": 10024, "toolkit/mozapps/extensions/test/browser/browser_bug562899.js": 10363, "browser/components/customizableui/test/browser_880382_drag_wide_widgets_in_panel.js": 17767, "browser/base/content/test/general/browser_bug561636.js": 18054, "browser/components/sessionstore/test/browser_backup_recovery.js": 15414, "browser/components/sessionstore/test/browser_formdata_cc.js": 49974, "browser/components/sessionstore/test/browser_600545.js": 18051, "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_popupblocker.js": 12404, "dom/html/test/browser_bug1108547.js": 33069, "browser/components/sessionstore/test/browser_354894_perwindowpb.js": 41672, "toolkit/mozapps/extensions/test/browser/browser_details.js": 41871, "browser/base/content/test/general/browser_bug822367.js": 16967, "toolkit/mozapps/extensions/test/browser/browser_inlinesettings.js": 22567, "browser/components/places/tests/browser/browser_library_views_liveupdate.js": 12976, "toolkit/mozapps/extensions/test/browser/browser_bug572561.js": 13066, "browser/components/customizableui/test/browser_978084_dragEnd_after_move.js": 12640, "browser/base/content/test/general/browser_domFullscreen_fullscreenMode.js": 13219, "browser/components/sessionstore/test/browser_590268.js": 19633, "browser/base/content/test/general/browser_bug422590.js": 10213, "browser/base/content/test/general/browser_bug767836_perwindowpb.js": 12151, "browser/components/customizableui/test/browser_890140_orphaned_placeholders.js": 29374, "browser/components/customizableui/test/browser_885530_showInPrivateBrowsing.js": 22478, "browser/base/content/test/referrer/browser_referrer_simple_click.js": 15821, "browser/components/customizableui/test/browser_1008559_anchor_undo_restore.js": 18428, "browser/components/customizableui/test/browser_995164_registerArea_during_customize_mode.js": 21727, "toolkit/mozapps/extensions/test/browser/browser_bug591663.js": 12728, "toolkit/mozapps/extensions/test/browser/browser_bug591465.js": 17702, "browser/components/sessionstore/test/browser_586068-cascade.js": 10994, "toolkit/mozapps/extensions/test/browser/browser_gmpProvider.js": 68229, "browser/components/customizableui/test/browser_975719_customtoolbars_behaviour.js": 23286, "browser/components/sessionstore/test/browser_formdata_format.js": 21423, "browser/components/customizableui/test/browser_bootstrapped_custom_toolbar.js": 18607, "browser/components/sessionstore/test/browser_586068-browser_state_interrupted.js": 40431, "toolkit/mozapps/extensions/test/browser/browser_bug608316.js": 11953, "browser/base/content/test/general/browser_bug1045809.js": 12748, "toolkit/components/addoncompat/tests/browser/browser_addonShims.js": 20491, "browser/base/content/test/general/browser_plainTextLinks.js": 10374, "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_DownloadLastDirWithCPS.js": 10443, "toolkit/mozapps/extensions/test/browser/browser_recentupdates.js": 15631, "browser/components/sessionstore/test/browser_broadcast.js": 15815, "browser/components/sessionstore/test/browser_sessionStorage.js": 12740, "browser/components/sessionstore/test/browser_crashedTabs.js": 38315, "toolkit/mozapps/extensions/test/browser/browser_inlinesettings_info.js": 15851, "browser/base/content/test/referrer/browser_referrer_open_link_in_window.js": 28479, "browser/components/sessionstore/test/browser_586068-reload.js": 15799, "toolkit/mozapps/extensions/test/browser/browser_bug596336.js": 11953, "browser/base/content/test/general/browser_bug553455.js": 61943, "toolkit/mozapps/extensions/test/browser/test-window/browser_install.js": 35621, "security/manager/ssl/tests/mochitest/browser/browser_bug627234_perwindowpb.js": 11329, "browser/base/content/test/referrer/browser_referrer_middle_click.js": 18609, "toolkit/mozapps/extensions/test/browser/test-window/browser_manualupdates.js": 18246, "toolkit/components/passwordmgr/test/browser/browser_passwordmgrdlg.js": 15399, "browser/base/content/test/general/browser_remoteTroubleshoot.js": 10349, "netwerk/test/browser/browser_child_resource.js": 19611, "toolkit/mozapps/extensions/test/browser/browser_bug577990.js": 29931, "browser/base/content/test/referrer/browser_referrer_open_link_in_tab.js": 19424, "toolkit/mozapps/extensions/test/browser/browser_bug581076.js": 25377, "toolkit/mozapps/extensions/test/browser/browser_bug567137.js": 12797, "browser/base/content/test/general/browser_bug590206.js": 15642, "toolkit/mozapps/extensions/test/browser/test-window/browser_debug_button.js": 19047, "toolkit/mozapps/extensions/test/browser/test-window/browser_inlinesettings.js": 22053, "testing/mochitest/tests/browser/browser_async.js": 10121, "browser/base/content/test/general/browser_restore_isAppTab.js": 12140, "browser/components/sessionstore/test/browser_586068-multi_window.js": 13987, "browser/components/search/test/browser_webapi.js": 23110, "toolkit/modules/tests/browser/browser_RemotePageManager.js": 20545, "toolkit/mozapps/extensions/test/browser/browser_installssl.js": 50668, "browser/components/sessionstore/test/browser_pageStyle.js": 13441, "browser/base/content/test/social/browser_social_chatwindow.js": 14138, "toolkit/mozapps/extensions/test/browser/browser_inlinesettings_custom.js": 10106, "toolkit/mozapps/extensions/test/browser/browser_searching.js": 43435, "toolkit/modules/tests/browser/browser_WebRequest.js": 10556, "browser/base/content/test/general/browser_bug676619.js": 23929, "browser/base/content/test/social/browser_social_chatwindow_resize.js": 12293, "browser/components/sessionstore/test/browser_615394-SSWindowState_events.js": 58565, "browser/base/content/test/referrer/browser_referrer_open_link_in_private.js": 29841, "browser/components/customizableui/test/browser_970511_undo_restore_default.js": 31563, "testing/mochitest/tests/browser/browser_fail_unexpectedTimeout.js": 40121, "browser/base/content/test/general/browser_bug575561.js": 23834, "toolkit/components/perfmonitoring/tests/browser/browser_AddonWatcher.js": 14704, "browser/base/content/test/general/browser_testOpenNewRemoteTabsFromNonRemoteBrowsers.js": 25385, "browser/base/content/test/general/browser_urlbarSearchSingleWordNotification.js": 21363, "toolkit/mozapps/extensions/test/browser/test-window/browser_bug596336.js": 12916, "toolkit/mozapps/extensions/test/browser/test-window/browser_bug577990.js": 25209, "toolkit/mozapps/extensions/test/browser/browser_install.js": 38862, "browser/base/content/test/general/browser_ssl_error_reports.js": 11637, "toolkit/mozapps/extensions/test/browser/browser_sorting.js": 14447, "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_geoprompt.js": 12539, "toolkit/mozapps/extensions/test/browser/browser_debug_button.js": 15444, "toolkit/mozapps/extensions/test/browser/test-window/browser_list.js": 19665, "browser/components/loop/test/mochitest/browser_fxa_login.js": 19772, "toolkit/mozapps/extensions/test/browser/test-window/browser_bug581076.js": 15636, "browser/components/preferences/in-content/tests/browser_privacypane_5.js": 12143, "browser/components/sessionstore/test/browser_586068-window_state_override.js": 12832, "browser/base/content/test/plugins/browser_pluginnotification.js": 15986, "browser/base/content/test/general/browser_tab_drag_drop_perwindow.js": 23077, "browser/base/content/test/general/browser_pageInfo.js": 14349, "browser/components/customizableui/test/browser_1089591_still_customizable_after_reset.js": 10771}}
new file mode 100644
--- /dev/null
+++ b/testing/runtimes/linux64-asan/mochitest-browser-chrome.runtimes.json
@@ -0,0 +1,1 @@
+{"excluded_test_average": 2678, "runtimes": {"browser/base/content/test/newtab/browser_newtab_drag_drop.js": 17473, "browser/components/preferences/in-content/tests/browser_privacypane_1.js": 11522, "browser/components/sessionstore/test/browser_394759_behavior.js": 23933, "toolkit/mozapps/extensions/test/browser/browser_cancelCompatCheck.js": 21277, "browser/components/sessionstore/test/browser_522545.js": 16442, "toolkit/mozapps/extensions/test/browser/test-window/browser_types.js": 28435, "browser/components/customizableui/test/browser_876926_customize_mode_wrapping.js": 13456, "browser/components/sessionstore/test/browser_595601-restore_hidden.js": 15186, "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle.js": 32733, "browser/components/sessionstore/test/browser_cleaner.js": 12464, "browser/base/content/test/social/browser_social_window.js": 35352, "toolkit/mozapps/extensions/test/browser/test-window/browser_searching.js": 23960, "browser/base/content/test/general/browser_aboutHome.js": 21515, "toolkit/mozapps/extensions/test/browser/browser_experiments.js": 12461, "browser/components/customizableui/test/browser_938980_navbar_collapsed.js": 21195, "toolkit/mozapps/extensions/test/browser/browser_bug577990.js": 13695, "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_toggle.js": 11637, "browser/components/tabview/test/browser_tabview_bug624847.js": 10248, "browser/base/content/test/general/browser_tabMatchesInAwesomebar.js": 17716, "toolkit/mozapps/extensions/test/browser/browser_CTP_plugins.js": 11848, "browser/base/content/test/general/browser_overflowScroll.js": 12313, "browser/components/customizableui/test/browser_880164_customization_context_menus.js": 22372, "toolkit/components/startup/tests/browser/browser_crash_detection.js": 35051, "dom/manifest/test/browser_ManifestObtainer_obtain.js": 23743, "toolkit/mozapps/extensions/test/browser/test-window/browser_bug562797.js": 33271, "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_sidebar.js": 16009, "browser/components/sessionstore/test/browser_broadcast.js": 12328, "toolkit/components/passwordmgr/test/browser/browser_notifications.js": 11098, "browser/components/tabview/test/browser_tabview_bug626791.js": 18244, "toolkit/mozapps/extensions/test/browser/test-window/browser_details.js": 25393, "toolkit/mozapps/extensions/test/browser/test-window/browser_discovery.js": 47168, "browser/components/sessionstore/test/browser_586068-window_state.js": 10397, "browser/components/preferences/in-content/tests/browser_privacypane_3.js": 11120, "testing/mochitest/tests/browser/browser_fail_timeout.js": 40055, "browser/components/preferences/in-content/tests/browser_privacypane_4.js": 18716, "browser/components/sessionstore/test/browser_formdata.js": 10025, "toolkit/mozapps/extensions/test/browser/browser_list.js": 12187, "toolkit/mozapps/extensions/test/browser/browser_updatessl.js": 34148, "toolkit/components/passwordmgr/test/browser/browser_passwordmgrdlg.js": 10601, "browser/components/customizableui/test/browser_995164_registerArea_during_customize_mode.js": 13175, "browser/base/content/test/general/browser_bug561636.js": 10946, "browser/components/sessionstore/test/browser_sessionHistory.js": 11868, "browser/components/sessionstore/test/browser_cookies.js": 27126, "browser/components/tabview/test/browser_tabview_bug610208.js": 13507, "browser/components/tabview/test/browser_tabview_bug650280_perwindowpb.js": 12505, "browser/base/content/test/general/browser_sanitizeDialog.js": 20163, "browser/base/content/test/newtab/browser_newtab_block.js": 15738, "browser/components/sessionstore/test/browser_354894_perwindowpb.js": 37726, "toolkit/mozapps/extensions/test/browser/browser_details.js": 26651, "browser/base/content/test/newtab/browser_newtab_drag_drop_ext.js": 13578, "browser/base/content/test/general/browser_bug822367.js": 12663, "toolkit/mozapps/extensions/test/browser/browser_inlinesettings.js": 12219, "toolkit/mozapps/extensions/test/browser/test-window/browser_CTP_plugins.js": 12005, "browser/components/places/tests/browser/browser_library_views_liveupdate.js": 10564, "toolkit/mozapps/extensions/test/browser/browser_uninstalling.js": 24221, "browser/components/sessionstore/test/browser_590268.js": 11175, "toolkit/mozapps/extensions/test/browser/browser_bug562797.js": 57030, "toolkit/mozapps/extensions/test/browser/browser_installssl.js": 28188, "browser/components/customizableui/test/browser_885530_showInPrivateBrowsing.js": 13002, "browser/components/customizableui/test/browser_1008559_anchor_undo_restore.js": 13916, "browser/base/content/test/social/browser_social_activation.js": 15461, "toolkit/mozapps/extensions/test/browser/browser_gmpProvider.js": 31653, "browser/components/customizableui/test/browser_975719_customtoolbars_behaviour.js": 16225, "browser/base/content/test/social/browser_social_marks.js": 21936, "browser/components/sessionstore/test/browser_formdata_format.js": 14643, "browser/base/content/test/newtab/browser_newtab_perwindow_private_browsing.js": 12422, "browser/components/customizableui/test/browser_bootstrapped_custom_toolbar.js": 13686, "browser/components/sessionstore/test/browser_586068-browser_state_interrupted.js": 10192, "browser/base/content/test/chat/browser_chatwindow.js": 12664, "browser/components/tabview/test/browser_tabview_bug589324.js": 11438, "toolkit/mozapps/extensions/test/browser/browser_bug557956.js": 26461, "browser/base/content/test/referrer/browser_referrer_open_link_in_window.js": 20801, "dom/ipc/tests/browser_domainPolicy.js": 10039, "browser/base/content/test/newtab/browser_newtab_enhanced.js": 13208, "browser/base/content/test/general/browser_devices_get_user_media.js": 29965, "browser/base/content/test/general/browser_bug553455.js": 39088, "browser/base/content/test/general/browser_identity_UI.js": 21983, "toolkit/mozapps/extensions/test/browser/test-window/browser_install.js": 16271, "browser/components/customizableui/test/browser_890140_orphaned_placeholders.js": 22816, "browser/base/content/test/referrer/browser_referrer_middle_click.js": 13347, "browser/components/loop/test/mochitest/browser_fxa_login.js": 14578, "browser/components/tabview/test/browser_tabview_bug656778.js": 13833, "browser/base/content/test/referrer/browser_referrer_open_link_in_tab.js": 12334, "browser/components/tabview/test/browser_tabview_expander.js": 15755, "browser/components/sessionstore/test/browser_backup_recovery.js": 10409, "browser/components/sessionstore/test/browser_formdata_cc.js": 36359, "toolkit/mozapps/extensions/test/browser/browser_types.js": 26389, "browser/base/content/test/general/browser_bug906190.js": 27723, "browser/base/content/test/social/browser_addons.js": 20364, "browser/components/tabview/test/browser_tabview_bug613541.js": 18975, "toolkit/mozapps/extensions/test/browser/test-window/browser_inlinesettings.js": 11959, "testing/mochitest/tests/browser/browser_async.js": 10052, "browser/base/content/test/chat/browser_focus.js": 10054, "browser/components/search/test/browser_webapi.js": 15353, "toolkit/mozapps/extensions/test/browser/browser_discovery.js": 48225, "browser/base/content/test/social/browser_social_chatwindow.js": 13310, "toolkit/mozapps/extensions/test/browser/browser_searching.js": 24850, "browser/base/content/test/general/browser_bug676619.js": 17247, "browser/base/content/test/social/browser_social_chatwindow_resize.js": 12327, "browser/components/sessionstore/test/browser_615394-SSWindowState_events.js": 29370, "browser/base/content/test/referrer/browser_referrer_open_link_in_private.js": 18594, "browser/components/customizableui/test/browser_970511_undo_restore_default.js": 18748, "testing/mochitest/tests/browser/browser_fail_unexpectedTimeout.js": 40054, "browser/base/content/test/general/browser_bug575561.js": 11972, "browser/components/customizableui/test/browser_880382_drag_wide_widgets_in_panel.js": 13254, "browser/base/content/test/general/browser_urlbarSearchSingleWordNotification.js": 14291, "dom/html/test/browser_bug1108547.js": 13444, "toolkit/mozapps/extensions/test/browser/test-window/browser_uninstalling.js": 22517, "toolkit/mozapps/extensions/test/browser/test-window/browser_bug577990.js": 13759, "toolkit/mozapps/extensions/test/browser/browser_install.js": 16054, "browser/base/content/test/referrer/browser_referrer_simple_click.js": 11756, "browser/components/translation/test/browser_translation_fhr.js": 14966, "browser/components/uitour/test/browser_UITour_heartbeat.js": 18877, "toolkit/mozapps/extensions/test/browser/test-window/browser_list.js": 13764, "browser/extensions/pdfjs/test/browser_pdfjs_zoom.js": 13378, "browser/components/preferences/in-content/tests/browser_privacypane_5.js": 10146, "browser/base/content/test/plugins/browser_pluginnotification.js": 11529, "dom/tests/browser/browser_test_new_window_from_content.js": 26874, "browser/components/search/test/browser_426329.js": 10340}}
new file mode 100644
--- /dev/null
+++ b/testing/runtimes/linux64-asan/mochitest-e10s-browser-chrome.runtimes.json
@@ -0,0 +1,1 @@
+{"excluded_test_average": 2808, "runtimes": {"browser/components/preferences/in-content/tests/browser_privacypane_1.js": 11964, "browser/components/sessionstore/test/browser_394759_behavior.js": 30043, "toolkit/mozapps/extensions/test/browser/browser_cancelCompatCheck.js": 22687, "browser/components/sessionstore/test/browser_522545.js": 35011, "browser/components/customizableui/test/browser_876926_customize_mode_wrapping.js": 15592, "browser/components/sessionstore/test/browser_595601-restore_hidden.js": 16862, "toolkit/components/thumbnails/test/browser_thumbnails_privacy.js": 11962, "browser/components/sessionstore/test/browser_cleaner.js": 13139, "browser/base/content/test/social/browser_social_window.js": 22656, "toolkit/mozapps/extensions/test/browser/test-window/browser_searching.js": 21979, "browser/base/content/test/general/browser_e10s_switchbrowser.js": 18407, "browser/base/content/test/general/browser_e10s_chrome_process.js": 11500, "browser/base/content/test/general/browser_sanitizeDialog.js": 21065, "browser/components/customizableui/test/browser_938980_navbar_collapsed.js": 21276, "toolkit/mozapps/extensions/test/browser/browser_bug577990.js": 13300, "browser/components/sessionstore/test/browser_async_remove_tab.js": 11030, "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_toggle.js": 13063, "browser/base/content/test/general/browser_tabMatchesInAwesomebar.js": 20558, "browser/components/sessionstore/test/browser_cookies.js": 27918, "browser/components/customizableui/test/browser_880164_customization_context_menus.js": 23871, "toolkit/components/startup/tests/browser/browser_crash_detection.js": 35051, "dom/manifest/test/browser_ManifestObtainer_obtain.js": 33477, "browser/components/sessionstore/test/browser_sessionHistory.js": 12383, "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_sidebar.js": 14842, "browser/components/sessionstore/test/browser_broadcast.js": 13242, "toolkit/components/passwordmgr/test/browser/browser_notifications.js": 13900, "toolkit/mozapps/extensions/test/browser/test-window/browser_details.js": 23424, "browser/components/preferences/in-content/tests/browser_bug1020245_openPreferences_to_paneContent.js": 11139, "dom/ipc/tests/browser_domainPolicy.js": 16345, "browser/components/sessionstore/test/browser_586068-window_state.js": 10393, "browser/components/preferences/in-content/tests/browser_privacypane_3.js": 11265, "testing/mochitest/tests/browser/browser_fail_timeout.js": 40047, "browser/components/preferences/in-content/tests/browser_privacypane_4.js": 19209, "browser/base/content/test/general/browser_bug822367.js": 12390, "toolkit/mozapps/extensions/test/browser/browser_list.js": 11084, "toolkit/mozapps/extensions/test/browser/browser_updatessl.js": 30702, "browser/components/sessionstore/test/browser_586068-multi_window.js": 10284, "browser/components/customizableui/test/browser_880382_drag_wide_widgets_in_panel.js": 15055, "browser/base/content/test/general/browser_bug561636.js": 11904, "browser/base/content/test/general/browser_bug590206.js": 10553, "browser/components/sessionstore/test/browser_600545.js": 12357, "browser/components/sessionstore/test/browser_354894_perwindowpb.js": 37610, "toolkit/mozapps/extensions/test/browser/browser_details.js": 24098, "browser/components/sessionstore/test/browser_formdata.js": 11416, "toolkit/mozapps/extensions/test/browser/browser_inlinesettings.js": 12015, "browser/components/places/tests/browser/browser_library_views_liveupdate.js": 10379, "browser/components/customizableui/test/browser_978084_dragEnd_after_move.js": 12237, "browser/components/sessionstore/test/browser_590268.js": 12991, "browser/components/customizableui/test/browser_885530_showInPrivateBrowsing.js": 13990, "browser/base/content/test/referrer/browser_referrer_simple_click.js": 10969, "browser/components/customizableui/test/browser_1008559_anchor_undo_restore.js": 15010, "browser/components/customizableui/test/browser_995164_registerArea_during_customize_mode.js": 18580, "browser/base/content/test/social/browser_social_activation.js": 12349, "browser/components/sessionstore/test/browser_586068-reload.js": 10959, "toolkit/mozapps/extensions/test/browser/browser_gmpProvider.js": 34198, "browser/base/content/test/social/browser_social_marks.js": 22826, "browser/components/sessionstore/test/browser_formdata_format.js": 18566, "browser/components/customizableui/test/browser_bootstrapped_custom_toolbar.js": 15284, "browser/components/sessionstore/test/browser_586068-browser_state_interrupted.js": 13611, "toolkit/mozapps/extensions/test/browser/browser_inlinesettings_info.js": 10237, "browser/base/content/test/referrer/browser_referrer_open_link_in_window.js": 25455, "browser/base/content/test/general/browser_bug553455.js": 42951, "toolkit/mozapps/extensions/test/browser/test-window/browser_install.js": 15936, "browser/components/customizableui/test/browser_890140_orphaned_placeholders.js": 22714, "browser/base/content/test/referrer/browser_referrer_middle_click.js": 17660, "browser/components/loop/test/mochitest/browser_fxa_login.js": 14887, "netwerk/test/browser/browser_child_resource.js": 21206, "browser/base/content/test/referrer/browser_referrer_open_link_in_tab.js": 15079, "browser/components/sessionstore/test/browser_backup_recovery.js": 11871, "browser/components/sessionstore/test/browser_formdata_cc.js": 36117, "toolkit/mozapps/extensions/test/browser/test-window/browser_inlinesettings.js": 11463, "testing/mochitest/tests/browser/browser_async.js": 10048, "browser/base/content/test/general/browser_identity_UI.js": 22565, "browser/components/search/test/browser_webapi.js": 17686, "toolkit/modules/tests/browser/browser_RemotePageManager.js": 12657, "toolkit/mozapps/extensions/test/browser/browser_installssl.js": 25243, "toolkit/mozapps/extensions/test/browser/browser_searching.js": 23318, "browser/base/content/test/general/browser_bug676619.js": 17314, "browser/components/sessionstore/test/browser_615394-SSWindowState_events.js": 46556, "browser/base/content/test/referrer/browser_referrer_open_link_in_private.js": 24915, "browser/components/customizableui/test/browser_970511_undo_restore_default.js": 22305, "testing/mochitest/tests/browser/browser_fail_unexpectedTimeout.js": 40040, "browser/base/content/test/general/browser_bug575561.js": 17779, "toolkit/components/perfmonitoring/tests/browser/browser_AddonWatcher.js": 14951, "browser/base/content/test/general/browser_testOpenNewRemoteTabsFromNonRemoteBrowsers.js": 24902, "browser/base/content/test/general/browser_urlbarSearchSingleWordNotification.js": 17084, "dom/html/test/browser_bug1108547.js": 19425, "toolkit/mozapps/extensions/test/browser/test-window/browser_bug577990.js": 11766, "toolkit/mozapps/extensions/test/browser/browser_install.js": 16680, "browser/base/content/test/general/browser_ssl_error_reports.js": 10188, "browser/base/content/test/general/browser_trackingUI.js": 12944, "browser/base/content/test/general/browser_URLBarSetURI.js": 12803, "toolkit/mozapps/extensions/test/browser/test-window/browser_list.js": 11942, "browser/components/customizableui/test/browser_975719_customtoolbars_behaviour.js": 27245, "browser/components/preferences/in-content/tests/browser_privacypane_5.js": 10968, "browser/base/content/test/plugins/browser_pluginnotification.js": 12291, "browser/base/content/test/general/browser_tab_drag_drop_perwindow.js": 16950}}
new file mode 100644
--- /dev/null
+++ b/testing/runtimes/linux64-debug/mochitest-e10s-browser-chrome.runtimes.json
@@ -0,0 +1,1 @@
+{"excluded_test_average": 3147, "runtimes": {"browser/components/preferences/in-content/tests/browser_privacypane_1.js": 12192, "browser/components/sessionstore/test/browser_394759_behavior.js": 32570, "toolkit/mozapps/extensions/test/browser/browser_cancelCompatCheck.js": 35596, "browser/components/sessionstore/test/browser_522545.js": 43196, "browser/components/customizableui/test/browser_876926_customize_mode_wrapping.js": 15439, "browser/components/sessionstore/test/browser_595601-restore_hidden.js": 21453, "toolkit/components/thumbnails/test/browser_thumbnails_privacy.js": 22273, "browser/components/sessionstore/test/browser_cleaner.js": 13984, "browser/base/content/test/social/browser_social_window.js": 26599, "toolkit/mozapps/extensions/test/browser/test-window/browser_searching.js": 40374, "browser/base/content/test/general/browser_e10s_switchbrowser.js": 23527, "browser/base/content/test/general/browser_e10s_chrome_process.js": 14728, "toolkit/mozapps/extensions/test/browser/test-window/browser_recentupdates.js": 10653, "browser/base/content/test/general/browser_sanitizeDialog.js": 21422, "toolkit/mozapps/extensions/test/browser/browser_manualupdates.js": 10447, "browser/components/customizableui/test/browser_938980_navbar_collapsed.js": 23591, "browser/components/sessionstore/test/browser_frame_history.js": 10845, "browser/base/content/test/general/browser_mcb_redirect.js": 13769, "browser/components/sessionstore/test/browser_async_remove_tab.js": 13955, "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_toggle.js": 14797, "browser/base/content/test/general/browser_tabMatchesInAwesomebar.js": 23909, "toolkit/mozapps/extensions/test/browser/test-window/browser_inlinesettings_info.js": 13560, "browser/components/sessionstore/test/browser_cookies.js": 35992, "browser/components/customizableui/test/browser_880164_customization_context_menus.js": 25809, "toolkit/mozapps/extensions/test/browser/browser_dragdrop.js": 11696, "browser/base/content/test/general/browser_bug1025195_switchToTabHavingURI_aOpenParams.js": 13949, "toolkit/components/startup/tests/browser/browser_crash_detection.js": 35108, "dom/manifest/test/browser_ManifestObtainer_obtain.js": 39242, "browser/components/sessionstore/test/browser_sessionHistory.js": 15433, "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_sidebar.js": 15133, "browser/base/content/test/plugins/browser_blocking.js": 13550, "toolkit/components/passwordmgr/test/browser/browser_notifications.js": 21670, "toolkit/mozapps/extensions/test/browser/test-window/browser_details.js": 34529, "browser/components/sessionstore/test/browser_586068-browser_state_interrupted.js": 39091, "browser/components/preferences/in-content/tests/browser_bug1020245_openPreferences_to_paneContent.js": 11527, "dom/ipc/tests/browser_domainPolicy.js": 19564, "browser/components/sessionstore/test/browser_586068-window_state.js": 13293, "browser/components/preferences/in-content/tests/browser_privacypane_3.js": 12665, "toolkit/mozapps/extensions/test/browser/test-window/browser_bug567137.js": 10242, "testing/mochitest/tests/browser/browser_fail_timeout.js": 40106, "toolkit/mozapps/extensions/test/browser/test-window/browser_sorting.js": 10945, "browser/components/preferences/in-content/tests/browser_privacypane_4.js": 24725, "browser/base/content/test/general/browser_bug822367.js": 17121, "toolkit/mozapps/extensions/test/browser/browser_list.js": 16572, "toolkit/mozapps/extensions/test/browser/browser_updatessl.js": 42371, "toolkit/mozapps/extensions/test/browser/test-window/browser_bug591465.js": 12874, "browser/components/sessionstore/test/browser_586068-multi_window.js": 10665, "browser/components/customizableui/test/browser_880382_drag_wide_widgets_in_panel.js": 16829, "browser/base/content/test/general/browser_bug561636.js": 17365, "browser/components/sessionstore/test/browser_backup_recovery.js": 12152, "browser/components/sessionstore/test/browser_formdata_cc.js": 46645, "browser/components/sessionstore/test/browser_600545.js": 15874, "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_popupblocker.js": 11614, "dom/html/test/browser_bug1108547.js": 24645, "browser/components/sessionstore/test/browser_354894_perwindowpb.js": 39802, "toolkit/mozapps/extensions/test/browser/browser_details.js": 36188, "browser/components/sessionstore/test/browser_formdata.js": 15307, "toolkit/mozapps/extensions/test/browser/browser_inlinesettings.js": 18111, "browser/components/sessionstore/test/browser_privatetabs.js": 10931, "browser/components/places/tests/browser/browser_library_views_liveupdate.js": 12943, "toolkit/mozapps/extensions/test/browser/browser_bug572561.js": 10486, "browser/components/customizableui/test/browser_978084_dragEnd_after_move.js": 13748, "browser/base/content/test/general/browser_domFullscreen_fullscreenMode.js": 10197, "browser/components/sessionstore/test/browser_590268.js": 17849, "browser/base/content/test/social/browser_aboutHome_activation.js": 10244, "browser/base/content/test/general/browser_bug422590.js": 10425, "browser/components/customizableui/test/browser_885530_showInPrivateBrowsing.js": 15498, "browser/base/content/test/referrer/browser_referrer_simple_click.js": 14484, "browser/components/customizableui/test/browser_1008559_anchor_undo_restore.js": 16933, "browser/components/customizableui/test/browser_995164_registerArea_during_customize_mode.js": 19209, "toolkit/mozapps/extensions/test/browser/browser_bug591465.js": 14099, "browser/components/sessionstore/test/browser_586068-cascade.js": 10463, "toolkit/mozapps/extensions/test/browser/browser_gmpProvider.js": 64585, "browser/components/customizableui/test/browser_975719_customtoolbars_behaviour.js": 24054, "browser/components/sessionstore/test/browser_formdata_format.js": 21954, "browser/components/customizableui/test/browser_bootstrapped_custom_toolbar.js": 23760, "browser/base/content/test/general/browser_urlbarCopying.js": 11212, "toolkit/components/addoncompat/tests/browser/browser_addonShims.js": 20387, "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_DownloadLastDirWithCPS.js": 10184, "toolkit/mozapps/extensions/test/browser/browser_recentupdates.js": 10485, "browser/components/sessionstore/test/browser_broadcast.js": 17669, "browser/components/sessionstore/test/browser_sessionStorage.js": 14043, "browser/components/sessionstore/test/browser_crashedTabs.js": 33882, "toolkit/mozapps/extensions/test/browser/browser_inlinesettings_info.js": 15568, "browser/base/content/test/referrer/browser_referrer_open_link_in_window.js": 27429, "browser/components/sessionstore/test/browser_586068-reload.js": 14665, "toolkit/mozapps/extensions/test/browser/browser_bug596336.js": 11743, "browser/base/content/test/general/browser_bug553455.js": 57461, "toolkit/mozapps/extensions/test/browser/test-window/browser_install.js": 33282, "browser/components/customizableui/test/browser_890140_orphaned_placeholders.js": 26931, "browser/base/content/test/referrer/browser_referrer_middle_click.js": 17525, "toolkit/mozapps/extensions/test/browser/test-window/browser_manualupdates.js": 10695, "browser/components/sessionstore/test/browser_394759_perwindowpb.js": 11315, "toolkit/components/passwordmgr/test/browser/browser_passwordmgrdlg.js": 14485, "browser/base/content/test/general/browser_remoteTroubleshoot.js": 15050, "netwerk/test/browser/browser_child_resource.js": 15420, "toolkit/mozapps/extensions/test/browser/browser_bug577990.js": 32750, "browser/base/content/test/referrer/browser_referrer_open_link_in_tab.js": 18650, "toolkit/mozapps/extensions/test/browser/browser_bug581076.js": 21050, "toolkit/mozapps/extensions/test/browser/browser_bug567137.js": 11916, "browser/base/content/test/general/browser_bug590206.js": 13077, "toolkit/mozapps/extensions/test/browser/test-window/browser_dragdrop.js": 10773, "toolkit/mozapps/extensions/test/browser/test-window/browser_debug_button.js": 13320, "toolkit/mozapps/extensions/test/browser/test-window/browser_inlinesettings.js": 15626, "testing/mochitest/tests/browser/browser_async.js": 10115, "browser/base/content/test/general/browser_restore_isAppTab.js": 12016, "browser/components/search/test/browser_webapi.js": 21193, "toolkit/modules/tests/browser/browser_RemotePageManager.js": 18153, "toolkit/mozapps/extensions/test/browser/browser_installssl.js": 42036, "browser/components/sessionstore/test/browser_pageStyle.js": 13497, "browser/base/content/test/social/browser_social_chatwindow.js": 12708, "toolkit/mozapps/extensions/test/browser/browser_searching.js": 39514, "browser/base/content/test/general/browser_bug676619.js": 21875, "browser/base/content/test/social/browser_social_chatwindow_resize.js": 10481, "browser/components/sessionstore/test/browser_615394-SSWindowState_events.js": 53943, "browser/base/content/test/referrer/browser_referrer_open_link_in_private.js": 27391, "browser/components/customizableui/test/browser_970511_undo_restore_default.js": 31992, "testing/mochitest/tests/browser/browser_fail_unexpectedTimeout.js": 40110, "browser/base/content/test/general/browser_bug575561.js": 24300, "toolkit/components/perfmonitoring/tests/browser/browser_AddonWatcher.js": 14302, "browser/base/content/test/general/browser_testOpenNewRemoteTabsFromNonRemoteBrowsers.js": 26109, "browser/base/content/test/general/browser_urlbarSearchSingleWordNotification.js": 17842, "toolkit/mozapps/extensions/test/browser/test-window/browser_bug596336.js": 11123, "toolkit/mozapps/extensions/test/browser/test-window/browser_bug577990.js": 23710, "toolkit/mozapps/extensions/test/browser/browser_install.js": 37676, "browser/base/content/test/general/browser_ssl_error_reports.js": 11401, "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_geoprompt.js": 11424, "toolkit/mozapps/extensions/test/browser/browser_debug_button.js": 14304, "toolkit/mozapps/extensions/test/browser/test-window/browser_list.js": 18157, "browser/components/loop/test/mochitest/browser_fxa_login.js": 18352, "toolkit/mozapps/extensions/test/browser/test-window/browser_bug581076.js": 14696, "browser/components/preferences/in-content/tests/browser_privacypane_5.js": 12166, "browser/components/sessionstore/test/browser_586068-window_state_override.js": 11095, "browser/base/content/test/plugins/browser_pluginnotification.js": 13806, "browser/base/content/test/general/browser_tab_drag_drop_perwindow.js": 21357, "browser/base/content/test/general/browser_pageInfo.js": 14153}}
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/harness/test/metadata/testharness/firefox/__dir__.ini
@@ -0,0 +1,2 @@
+prefs: ["browser.display.foreground_color:#FF0000",
+        "browser.display.background_color:#000000"]
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/harness/test/metadata/testharness/firefox/subdir/test_pref_reset.html.ini
@@ -0,0 +1,2 @@
+[test_pref_reset.html]
+  prefs: [@Reset]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/harness/test/metadata/testharness/subdir/__dir__.ini
@@ -0,0 +1,1 @@
+disabled: true
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/harness/test/metadata/testharness/subdir/testharness_1.html.ini
@@ -0,0 +1,2 @@
+[testharness_1.html]
+  disabled: @False
\ No newline at end of file
--- a/testing/web-platform/harness/test/test.py
+++ b/testing/web-platform/harness/test/test.py
@@ -96,16 +96,18 @@ def settings_to_argv(settings):
                 rv.extend([key, item])
         else:
             rv.extend([key, value])
     return rv
 
 def set_from_args(settings, args):
     if args.test:
         settings["include"] = args.test
+    if args.tags:
+        settings["tags"] = args.tags
 
 def run(config, args):
     logger = structuredlog.StructuredLogger("web-platform-tests")
     logger.add_handler(ResultHandler(logger=logger, verbose=args.verbose))
     setup_wptrunner_logging(logger)
 
     parser = wptcommandline.create_parser()
 
@@ -134,16 +136,18 @@ def run(config, args):
 def get_parser():
     parser = argparse.ArgumentParser()
     parser.add_argument("-v", "--verbose", action="store_true", default=False,
                         help="verbose log output")
     parser.add_argument("--product", action="append",
                         help="Specific product to include in test run")
     parser.add_argument("--pdb", action="store_true",
                         help="Invoke pdb on uncaught exception")
+    parser.add_argument("--tag", action="append", dest="tags",
+                        help="tags to select tests")
     parser.add_argument("test", nargs="*",
                         help="Specific tests to include in test run")
     return parser
 
 def main():
     config = read_config()
 
     args = get_parser().parse_args()
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/harness/test/testdata/testharness/firefox/subdir/test_pref_inherit.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<title>Example pref test</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<p>Test requires the pref browser.display.foreground_color to be set to #00FF00</p>
+<script>
+test(function() {
+  assert_equals(getComputedStyle(document.body).color, "rgb(255, 0, 0)");
+}, "Test that pref was set");
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/harness/test/testdata/testharness/firefox/subdir/test_pref_reset.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<title>Example pref test</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<p>Test requires the pref browser.display.foreground_color to be set to #00FF00</p>
+<script>
+test(function() {
+  assert_equals(getComputedStyle(document.body).color, "rgb(0, 0, 0)");
+}, "Test that pref was reset");
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/harness/test/testdata/testharness/firefox/test_pref_dir.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<title>Example pref test</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<p>Test requires the pref browser.display.foreground_color to be set to #FF0000</p>
+<script>
+test(function() {
+  assert_equals(getComputedStyle(document.body).color, "rgb(255, 0, 0)");
+}, "Test that pref was set");
+</script>
--- a/testing/web-platform/harness/test/testdata/testharness/firefox/test_pref_set.html
+++ b/testing/web-platform/harness/test/testdata/testharness/firefox/test_pref_set.html
@@ -1,10 +1,10 @@
 <!doctype html>
-<title>Example https test</title>
+<title>Example pref test</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <p>Test requires the pref browser.display.foreground_color to be set to #00FF00</p>
 <script>
 test(function() {
   assert_equals(getComputedStyle(document.body).color, "rgb(0, 255, 0)");
 }, "Test that pref was set");
-</script>
\ No newline at end of file
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/harness/test/testdata/testharness/subdir/testharness_1.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<title>Test should be enabled</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(function() {
+  assert_true(true);
+}, "Test that should pass");
+</script>
--- a/testing/web-platform/harness/test/testdata/testharness/testharness_0.html
+++ b/testing/web-platform/harness/test/testdata/testharness/testharness_0.html
@@ -1,13 +1,9 @@
 <!doctype html>
-<title>Simple testharness.js usage</title>
+<title>Test should be disabled</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script>
 test(function() {
-  assert_true(true);
-}, "Test that should pass");
-
-test(function() {
   assert_true(false);
 }, "Test that should fail");
-</script>
\ No newline at end of file
+</script>
--- a/testing/web-platform/harness/wptrunner/browsers/__init__.py
+++ b/testing/web-platform/harness/wptrunner/browsers/__init__.py
@@ -24,9 +24,10 @@ a dictionary with the fields
 
 All classes and functions named in the above dict must be imported into the
 module global scope.
 """
 
 product_list = ["b2g",
                 "chrome",
                 "firefox",
-                "servo"]
+                "servo",
+                "servodriver"]
--- a/testing/web-platform/harness/wptrunner/browsers/b2g.py
+++ b/testing/web-platform/harness/wptrunner/browsers/b2g.py
@@ -37,17 +37,18 @@ def check_args(**kwargs):
     pass
 
 
 def browser_kwargs(test_environment, **kwargs):
     return {"prefs_root": kwargs["prefs_root"],
             "no_backup": kwargs.get("b2g_no_backup", False)}
 
 
-def executor_kwargs(test_type, server_config, cache_manager, **kwargs):
+def executor_kwargs(test_type, server_config, cache_manager, run_info_data,
+                    **kwargs):
     timeout_multiplier = kwargs["timeout_multiplier"]
     if timeout_multiplier is None:
         timeout_multiplier = 2
 
     executor_kwargs = {"server_config": server_config,
                        "timeout_multiplier": timeout_multiplier,
                        "close_after_done": False}
 
--- a/testing/web-platform/harness/wptrunner/browsers/chrome.py
+++ b/testing/web-platform/harness/wptrunner/browsers/chrome.py
@@ -15,33 +15,34 @@ from ..executors.executorselenium import
                  "executor": {"testharness": "SeleniumTestharnessExecutor",
                               "reftest": "SeleniumRefTestExecutor"},
                  "browser_kwargs": "browser_kwargs",
                  "executor_kwargs": "executor_kwargs",
                  "env_options": "env_options"}
 
 
 def check_args(**kwargs):
-    require_arg(kwargs, "binary")
+    require_arg(kwargs, "webdriver_binary")
 
 
 def browser_kwargs(**kwargs):
     return {"binary": kwargs["binary"],
             "webdriver_binary": kwargs["webdriver_binary"]}
 
 
-def executor_kwargs(test_type, server_config, cache_manager, **kwargs):
+def executor_kwargs(test_type, server_config, cache_manager, run_info_data,
+                    **kwargs):
     from selenium.webdriver import DesiredCapabilities
 
     executor_kwargs = base_executor_kwargs(test_type, server_config,
                                            cache_manager, **kwargs)
     executor_kwargs["close_after_done"] = True
-    executor_kwargs["capabilities"] = dict(DesiredCapabilities.CHROME.items() +
-                                           {"chromeOptions":
-                                            {"binary": kwargs["binary"]}}.items())
+    executor_kwargs["capabilities"] = dict(DesiredCapabilities.CHROME.items())
+    if kwargs["binary"] is not None:
+        executor_kwargs["capabilities"]["chromeOptions"] = {"binary": kwargs["binary"]}
 
     return executor_kwargs
 
 
 def env_options():
     return {"host": "web-platform.test",
             "bind_hostname": "true"}
 
--- a/testing/web-platform/harness/wptrunner/browsers/firefox.py
+++ b/testing/web-platform/harness/wptrunner/browsers/firefox.py
@@ -41,20 +41,23 @@ def browser_kwargs(**kwargs):
             "prefs_root": kwargs["prefs_root"],
             "debug_info": kwargs["debug_info"],
             "symbols_path": kwargs["symbols_path"],
             "stackwalk_binary": kwargs["stackwalk_binary"],
             "certutil_binary": kwargs["certutil_binary"],
             "ca_certificate_path": kwargs["ssl_env"].ca_cert_path()}
 
 
-def executor_kwargs(test_type, server_config, cache_manager, **kwargs):
+def executor_kwargs(test_type, server_config, cache_manager, run_info_data,
+                    **kwargs):
     executor_kwargs = base_executor_kwargs(test_type, server_config,
                                            cache_manager, **kwargs)
     executor_kwargs["close_after_done"] = True
+    if run_info_data["debug"] and kwargs["timeout_multiplier"] is None:
+        executor_kwargs["timeout_multiplier"] = 3
     return executor_kwargs
 
 
 def env_options():
     return {"host": "127.0.0.1",
             "external_host": "web-platform.test",
             "bind_hostname": "false",
             "certificate_domain": "web-platform.test",
@@ -66,27 +69,27 @@ class FirefoxBrowser(Browser):
 
     def __init__(self, logger, binary, prefs_root, debug_info=None,
                  symbols_path=None, stackwalk_binary=None, certutil_binary=None,
                  ca_certificate_path=None):
         Browser.__init__(self, logger)
         self.binary = binary
         self.prefs_root = prefs_root
         self.marionette_port = None
-        self.used_ports.add(self.marionette_port)
         self.runner = None
         self.debug_info = debug_info
         self.profile = None
         self.symbols_path = symbols_path
         self.stackwalk_binary = stackwalk_binary
         self.ca_certificate_path = ca_certificate_path
         self.certutil_binary = certutil_binary
 
     def start(self):
         self.marionette_port = get_free_port(2828, exclude=self.used_ports)
+        self.used_ports.add(self.marionette_port)
 
         env = os.environ.copy()
         env["MOZ_DISABLE_NONLOCAL_CONNECTIONS"] = "1"
 
         locations = ServerLocations(filename=os.path.join(here, "server-locations.txt"))
 
         preferences = self.load_prefs()
 
--- a/testing/web-platform/harness/wptrunner/browsers/servo.py
+++ b/testing/web-platform/harness/wptrunner/browsers/servo.py
@@ -24,17 +24,18 @@ def check_args(**kwargs):
     require_arg(kwargs, "binary")
 
 
 def browser_kwargs(**kwargs):
     return {"binary": kwargs["binary"],
             "debug_info": kwargs["debug_info"]}
 
 
-def executor_kwargs(test_type, server_config, cache_manager, **kwargs):
+def executor_kwargs(test_type, server_config, cache_manager, run_info_data,
+                    **kwargs):
     rv = base_executor_kwargs(test_type, server_config,
                               cache_manager, **kwargs)
     rv["pause_after_test"] = kwargs["pause_after_test"]
     return rv
 
 def env_options():
     return {"host": "localhost",
             "bind_hostname": "true",
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/harness/wptrunner/browsers/servodriver.py
@@ -0,0 +1,141 @@
+# 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/.
+
+import os
+import subprocess
+import tempfile
+
+from mozprocess import ProcessHandler
+
+from .base import Browser, require_arg, get_free_port, browser_command, ExecutorBrowser
+from ..executors import executor_kwargs as base_executor_kwargs
+from ..executors.executorservodriver import (ServoWebDriverTestharnessExecutor,
+                                             ServoWebDriverRefTestExecutor)
+
+here = os.path.join(os.path.split(__file__)[0])
+
+__wptrunner__ = {"product": "servodriver",
+                 "check_args": "check_args",
+                 "browser": "ServoWebDriverBrowser",
+                 "executor": {"testharness": "ServoWebDriverTestharnessExecutor",
+                              "reftest": "ServoWebDriverRefTestExecutor"},
+                 "browser_kwargs": "browser_kwargs",
+                 "executor_kwargs": "executor_kwargs",
+                 "env_options": "env_options"}
+
+hosts_text = """127.0.0.1 web-platform.test
+127.0.0.1 www.web-platform.test
+127.0.0.1 www1.web-platform.test
+127.0.0.1 www2.web-platform.test
+127.0.0.1 xn--n8j6ds53lwwkrqhv28a.web-platform.test
+127.0.0.1 xn--lve-6lad.web-platform.test
+"""
+
+
+def check_args(**kwargs):
+    require_arg(kwargs, "binary")
+
+
+def browser_kwargs(**kwargs):
+    return {"binary": kwargs["binary"],
+            "debug_info": kwargs["debug_info"]}
+
+
+def executor_kwargs(test_type, server_config, cache_manager, **kwargs):
+    rv = base_executor_kwargs(test_type, server_config,
+                              cache_manager, **kwargs)
+    return rv
+
+
+def env_options():
+    return {"host": "web-platform.test",
+            "bind_hostname": "true",
+            "testharnessreport": "testharnessreport-servodriver.js",
+            "supports_debugger": True}
+
+
+def make_hosts_file():
+    hosts_fd, hosts_path = tempfile.mkstemp()
+    with os.fdopen(hosts_fd, "w") as f:
+        f.write(hosts_text)
+    return hosts_path
+
+
+class ServoWebDriverBrowser(Browser):
+    used_ports = set()
+
+    def __init__(self, logger, binary, debug_info=None, webdriver_host="127.0.0.1"):
+        Browser.__init__(self, logger)
+        self.binary = binary
+        self.webdriver_host = webdriver_host
+        self.webdriver_port = None
+        self.proc = None
+        self.debug_info = debug_info
+        self.hosts_path = make_hosts_file()
+        self.command = None
+
+    def start(self):
+        self.webdriver_port = get_free_port(4444, exclude=self.used_ports)
+        self.used_ports.add(self.webdriver_port)
+
+        env = os.environ.copy()
+        env["HOST_FILE"] = self.hosts_path
+
+        debug_args, command = browser_command(self.binary,
+                                              ["--cpu", "--hard-fail",
+                                               "--webdriver", str(self.webdriver_port),
+                                               "about:blank"],
+                                              self.debug_info)
+
+        self.command = command
+
+        self.command = debug_args + self.command
+
+        if not self.debug_info or not self.debug_info.interactive:
+            self.proc = ProcessHandler(self.command,
+                                       processOutputLine=[self.on_output],
+                                       env=env,
+                                       storeOutput=False)
+            self.proc.run()
+        else:
+            self.proc = subprocess.Popen(self.command, env=env)
+
+        self.logger.debug("Servo Started")
+
+    def stop(self):
+        self.logger.debug("Stopping browser")
+        if self.proc is not None:
+            try:
+                self.proc.kill()
+            except OSError:
+                # This can happen on Windows if the process is already dead
+                pass
+
+    def pid(self):
+        if self.proc is None:
+            return None
+
+        try:
+            return self.proc.pid
+        except AttributeError:
+            return None
+
+    def on_output(self, line):
+        """Write a line of output from the process to the log"""
+        self.logger.process_output(self.pid(),
+                                   line.decode("utf8", "replace"),
+                                   command=" ".join(self.command))
+
+    def is_alive(self):
+        if self.runner:
+            return self.runner.is_running()
+        return False
+
+    def cleanup(self):
+        self.stop()
+
+    def executor_browser(self):
+        assert self.webdriver_port is not None
+        return ExecutorBrowser, {"webdriver_host": self.webdriver_host,
+                                 "webdriver_port": self.webdriver_port}
--- a/testing/web-platform/harness/wptrunner/executors/base.py
+++ b/testing/web-platform/harness/wptrunner/executors/base.py
@@ -94,17 +94,17 @@ class TestExecutor(object):
                                    when setting test timeout.
         """
         self.runner = None
         self.browser = browser
         self.server_config = server_config
         self.timeout_multiplier = timeout_multiplier
         self.debug_info = debug_info
         self.last_environment = {"protocol": "http",
-                                 "prefs": []}
+                                 "prefs": {}}
         self.protocol = None # This must be set in subclasses
 
     @property
     def logger(self):
         """StructuredLogger for this executor"""
         if self.runner is not None:
             return self.runner.logger
 
--- a/testing/web-platform/harness/wptrunner/executors/executormarionette.py
+++ b/testing/web-platform/harness/wptrunner/executors/executormarionette.py
@@ -134,81 +134,89 @@ class MarionetteProtocol(Protocol):
             except (socket.timeout, IOError):
                 break
             except Exception as e:
                 self.logger.error(traceback.format_exc(e))
                 break
 
     def on_environment_change(self, old_environment, new_environment):
         #Unset all the old prefs
-        for name, _ in old_environment.get("prefs", []):
+        for name in old_environment.get("prefs", {}).iterkeys():
             value = self.executor.original_pref_values[name]
             if value is None:
                 self.clear_user_pref(name)
             else:
                 self.set_pref(name, value)
 
-        for name, value in new_environment.get("prefs", []):
+        for name, value in new_environment.get("prefs", {}).iteritems():
             self.executor.original_pref_values[name] = self.get_pref(name)
             self.set_pref(name, value)
 
     def set_pref(self, name, value):
+        if value.lower() not in ("true", "false"):
+            try:
+                int(value)
+            except ValueError:
+                value = "'%s'" % value
+        else:
+            value = value.lower()
+
         self.logger.info("Setting pref %s (%s)" % (name, value))
-        self.marionette.set_context(self.marionette.CONTEXT_CHROME)
+
         script = """
             let prefInterface = Components.classes["@mozilla.org/preferences-service;1"]
                                           .getService(Components.interfaces.nsIPrefBranch);
             let pref = '%s';
             let type = prefInterface.getPrefType(pref);
+            let value = %s;
             switch(type) {
                 case prefInterface.PREF_STRING:
-                    prefInterface.setCharPref(pref, '%s');
+                    prefInterface.setCharPref(pref, value);
                     break;
                 case prefInterface.PREF_BOOL:
-                    prefInterface.setBoolPref(pref, %s);
+                    prefInterface.setBoolPref(pref, value);
                     break;
                 case prefInterface.PREF_INT:
-                    prefInterface.setIntPref(pref, %s);
+                    prefInterface.setIntPref(pref, value);
                     break;
             }
-            """ % (name, value, value, value)
-        self.marionette.execute_script(script)
-        self.marionette.set_context(self.marionette.CONTEXT_CONTENT)
+            """ % (name, value)
+        with self.marionette.using_context(self.marionette.CONTEXT_CHROME):
+            self.marionette.execute_script(script)
 
     def clear_user_pref(self, name):
         self.logger.info("Clearing pref %s" % (name))
-        self.marionette.set_context(self.marionette.CONTEXT_CHROME)
         script = """
             let prefInterface = Components.classes["@mozilla.org/preferences-service;1"]
                                           .getService(Components.interfaces.nsIPrefBranch);
             let pref = '%s';
             prefInterface.clearUserPref(pref);
             """ % name
-        self.marionette.execute_script(script)
-        self.marionette.set_context(self.marionette.CONTEXT_CONTENT)
+        with self.marionette.using_context(self.marionette.CONTEXT_CHROME):
+            self.marionette.execute_script(script)
 
     def get_pref(self, name):
-        self.marionette.set_context(self.marionette.CONTEXT_CHROME)
-        self.marionette.execute_script("""
+        script = """
             let prefInterface = Components.classes["@mozilla.org/preferences-service;1"]
                                           .getService(Components.interfaces.nsIPrefBranch);
             let pref = '%s';
             let type = prefInterface.getPrefType(pref);
             switch(type) {
                 case prefInterface.PREF_STRING:
                     return prefInterface.getCharPref(pref);
                 case prefInterface.PREF_BOOL:
                     return prefInterface.getBoolPref(pref);
                 case prefInterface.PREF_INT:
                     return prefInterface.getIntPref(pref);
                 case prefInterface.PREF_INVALID:
                     return null;
             }
-            """ % (name))
-        self.marionette.set_context(self.marionette.CONTEXT_CONTENT)
+            """ % name
+        with self.marionette.using_context(self.marionette.CONTEXT_CHROME):
+            self.marionette.execute_script(script)
 
 class MarionetteRun(object):
     def __init__(self, logger, func, marionette, url, timeout):
         self.logger = logger
         self.result = None
         self.marionette = marionette
         self.func = func
         self.url = url
@@ -378,20 +386,17 @@ class MarionetteRefTestExecutor(RefTestE
 
         return MarionetteRun(self.logger,
                              self._screenshot,
                              self.protocol.marionette,
                              test_url,
                              timeout).run()
 
     def _screenshot(self, marionette, url, timeout):
-        try:
-            marionette.navigate(url)
-        except errors.MarionetteException:
-            raise ExecutorException("ERROR", "Failed to load url %s" % (url,))
+        marionette.navigate(url)
 
         marionette.execute_async_script(self.wait_script)
 
         screenshot = marionette.screenshot()
         # strip off the data:img/png, part of the url
         if screenshot.startswith("data:image/png;base64,"):
             screenshot = screenshot.split(",", 1)[1]
 
--- a/testing/web-platform/harness/wptrunner/executors/executorservo.py
+++ b/testing/web-platform/harness/wptrunner/executors/executorservo.py
@@ -193,17 +193,18 @@ class ServoRefTestExecutor(ProcessTestEx
             env["HOST_FILE"] = self.hosts_path
 
             self.proc = ProcessHandler(self.command,
                                        processOutputLine=[self.on_output],
                                        env=env)
 
             try:
                 self.proc.run()
-                rv = self.proc.wait(timeout=test.timeout)
+                timeout = test.timeout * self.timeout_multiplier + 5
+                rv = self.proc.wait(timeout=timeout)
             except KeyboardInterrupt:
                 self.proc.kill()
                 raise
 
             if rv is None:
                 self.proc.kill()
                 return False, ("EXTERNAL-TIMEOUT", None)
 
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/harness/wptrunner/executors/executorservodriver.py
@@ -0,0 +1,243 @@
+# 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/.
+
+import json
+import os
+import socket
+import threading
+import time
+import traceback
+
+from .base import (Protocol,
+                   RefTestExecutor,
+                   RefTestImplementation,
+                   TestharnessExecutor,
+                   strip_server)
+import webdriver
+from ..testrunner import Stop
+
+here = os.path.join(os.path.split(__file__)[0])
+
+extra_timeout = 5
+
+
+class ServoWebDriverProtocol(Protocol):
+    def __init__(self, executor, browser, capabilities, **kwargs):
+        Protocol.__init__(self, executor, browser)
+        self.capabilities = capabilities
+        self.host = browser.webdriver_host
+        self.port = browser.webdriver_port
+        self.session = None
+
+    def setup(self, runner):
+        """Connect to browser via WebDriver."""
+        self.runner = runner
+
+        session_started = False
+        try:
+            self.session = webdriver.Session(self.host, self.port)
+            self.session.start()
+        except:
+            self.logger.warning(
+                "Connecting with WebDriver failed:\n%s" % traceback.format_exc())
+        else:
+            self.logger.debug("session started")
+            session_started = True
+
+        if not session_started:
+            self.logger.warning("Failed to connect via WebDriver")
+            self.executor.runner.send_message("init_failed")
+        else:
+            self.executor.runner.send_message("init_succeeded")
+
+    def teardown(self):
+        self.logger.debug("Hanging up on WebDriver session")
+        try:
+            self.session.end()
+        except:
+            pass
+
+    def is_alive(self):
+        try:
+            # Get a simple property over the connection
+            self.session.handle
+        # TODO what exception?
+        except Exception:
+            return False
+        return True
+
+    def after_connect(self):
+        pass
+
+    def wait(self):
+        while True:
+            try:
+                self.session.execute_async_script("")
+            except webdriver.TimeoutException:
+                pass
+            except (socket.timeout, IOError):
+                break
+            except Exception as e:
+                self.logger.error(traceback.format_exc(e))
+                break
+
+
+class ServoWe