merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 18 Mar 2015 13:51:53 +0100
changeset 234208 41a61514461e055808ebaab3dbd2c1121e96bd15
parent 234155 097cad4009ca2681cb172941d6c524c9ae7c350c (current diff)
parent 234207 6799607b934eb6bd8e0004a7a7200f640a1335c8 (diff)
child 234209 2e2222a40262fbd848f59204e418ea05d7416274
child 234250 59420af48c846e36607eb06e1a54c0c8fdb243f0
child 234287 bf7bdaee348f4b3fc4c47523f60ea05fc64f25f1
child 234322 d95a33d3cda6ec8943b2f9baddc2db0e05d84a65
push id28436
push usercbook@mozilla.com
push dateWed, 18 Mar 2015 12:52:36 +0000
treeherdermozilla-central@41a61514461e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone39.0a1
first release with
nightly linux32
41a61514461e / 39.0a1 / 20150318055750 / files
nightly linux64
41a61514461e / 39.0a1 / 20150318055750 / files
nightly mac
41a61514461e / 39.0a1 / 20150318055750 / files
nightly win32
41a61514461e / 39.0a1 / 20150318055750 / files
nightly win64
41a61514461e / 39.0a1 / 20150318055750 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
testing/web-platform/meta/media-source/mediasource-removesourcebuffer.html.ini
testing/web-platform/meta/media-source/mediasource-sourcebufferlist.html.ini
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -317,16 +317,17 @@ pref("media.cache_readahead_limit", 30);
 // Enable/Disable Gonk Decoder Module
 pref("media.fragmented-mp4.gonk.enabled", true);
 #endif
 // The default number of decoded video frames that are enqueued in
 // MediaDecoderReader's mVideoQueue.
 pref("media.video-queue.default-size", 3);
 
 // optimize images' memory usage
+pref("image.downscale-during-decode.enabled", true);
 pref("image.mem.decodeondraw", true);
 pref("image.mem.allow_locking_in_content_processes", false); /* don't allow image locking */
 // Limit the surface cache to 1/8 of main memory or 128MB, whichever is smaller.
 // Almost everything that was factored into 'max_decoded_image_kb' is now stored
 // in the surface cache.  1/8 of main memory is 32MB on a 256MB device, which is
 // about the same as the old 'max_decoded_image_kb'.
 pref("image.mem.surfacecache.max_size_kb", 131072);  // 128MB
 pref("image.mem.surfacecache.size_factor", 8);  // 1/8 of main memory
--- a/dom/animation/test/chrome/test_running_on_compositor.html
+++ b/dom/animation/test/chrome/test_running_on_compositor.html
@@ -9,17 +9,17 @@
   src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
 <link rel="stylesheet" type="text/css"
   href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
 <style>
 @keyframes anim {
   to { transform: translate(100px) }
 }
 .target {
-  // Element needs geometry to be eligible for layerization
+  /* Element needs geometry to be eligible for layerization */
   width: 100px;
   height: 100px;
   background-color: white;
 }
 </style>
 </head>
 <body>
 <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1045994"
--- a/dom/animation/test/mochitest.ini
+++ b/dom/animation/test/mochitest.ini
@@ -17,9 +17,8 @@ skip-if = buildapp == 'mulet'
 [css-transitions/test_animation-effect-name.html]
 [css-transitions/test_animation-pausing.html]
 [css-transitions/test_animation-player-ready.html]
 [css-transitions/test_animation-target.html]
 [css-transitions/test_animation-player-starttime.html]
 [css-transitions/test_element-get-animation-players.html]
 skip-if = buildapp == 'mulet'
 [mozilla/test_deferred_start.html]
-skip-if = buildapp == 'mulet' || buildapp == 'b2g' # bug 1113425, 1119981
--- a/dom/animation/test/mozilla/test_deferred_start.html
+++ b/dom/animation/test/mozilla/test_deferred_start.html
@@ -6,17 +6,17 @@
 <div id="log"></div>
 <style>
 @keyframes empty { }
 @keyframes animTransform {
   from { transform: translate(0px); }
   to { transform: translate(100px); }
 }
 .target {
-  // Element needs geometry to be eligible for layerization
+  /* Element needs geometry to be eligible for layerization */
   width: 100px;
   height: 100px;
   background-color: white;
 }
 </style>
 <script>
 'use strict';
 
@@ -55,23 +55,28 @@ async_test(function(t) {
     var player = div.getAnimationPlayers()[0];
 
     player.ready.then(function() {
       promiseCallbackDone = true;
     }).catch(function() {
       assert_unreached('ready promise was rejected');
     });
 
-  // We need to wait for up to two frames since the animation may not start
-  // until the beginning of the next refresh driver tick and it won't queue
-  // the ready Promise callback until that point.
-  }).then(waitForFrame).then(waitForFrame).then(t.step_func(function() {
+  // We need to wait for up to three frames. This is because in some
+  // cases it can take up to two frames for the initial layout
+  // to take place. Even after that happens we don't actually resolve the
+  // ready promise until the following tick.
+  })
+  .then(waitForFrame)
+  .then(waitForFrame)
+  .then(waitForFrame)
+  .then(t.step_func(function() {
     assert_true(promiseCallbackDone,
-                'ready promise callback was called before the next'
-                + ' requestAnimationFrame callback');
+                'ready promise for an empty animation was resolved'
+                + ' within three animation frames');
     t.done();
   }));
 }, 'AnimationPlayer.ready is resolved for an empty animation');
 
 // Test that compositor animations with delays get synced correctly
 //
 // NOTE: It is important that we DON'T use
 // SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh here since that takes
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -1827,17 +1827,17 @@ Element::SetSMILOverrideStyleRule(css::S
 
 bool
 Element::IsLabelable() const
 {
   return false;
 }
 
 bool
-Element::IsInteractiveHTMLContent() const
+Element::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
 {
   return false;
 }
 
 css::StyleRule*
 Element::GetInlineStyleRule()
 {
   return nullptr;
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -271,17 +271,17 @@ public:
   /**
    * Returns if the element is labelable as per HTML specification.
    */
   virtual bool IsLabelable() const;
 
   /**
    * Returns if the element is interactive content as per HTML specification.
    */
-  virtual bool IsInteractiveHTMLContent() const;
+  virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const;
 
   /**
    * Is the attribute named stored in the mapped attributes?
    *
    * // XXXbz we use this method in HasAttributeDependentStyle, so svg
    *    returns true here even though it stores nothing in the mapped
    *    attributes.
    */
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -69,16 +69,17 @@ EXPORTS += [
     'nsDOMAttributeMap.h',
     'nsDOMCID.h',
     'nsDOMClassInfoClasses.h',
     'nsDOMClassInfoID.h',
     'nsDOMJSUtils.h',
     'nsDOMNavigationTiming.h',
     'nsDOMString.h',
     'nsFocusManager.h',
+    'nsFormData.h',
     'nsFrameMessageManager.h',
     'nsGenericDOMDataNode.h',
     'nsGkAtomList.h',
     'nsGkAtoms.h',
     'nsHostObjectProtocolHandler.h',
     'nsHostObjectURI.h',
     'nsIAnimationObserver.h',
     'nsIAttribute.h',
--- a/dom/cache/TypeUtils.cpp
+++ b/dom/cache/TypeUtils.cpp
@@ -224,17 +224,17 @@ TypeUtils::ToPCacheResponseWithoutBody(P
     ProcessURL(aOut.url(), nullptr, nullptr, aRv);
     if (aRv.Failed()) {
       return;
     }
   }
 
   aOut.status() = aIn.GetStatus();
   aOut.statusText() = aIn.GetStatusText();
-  nsRefPtr<InternalHeaders> headers = aIn.Headers();
+  nsRefPtr<InternalHeaders> headers = aIn.UnfilteredHeaders();
   MOZ_ASSERT(headers);
   headers->GetPHeaders(aOut.headers());
   aOut.headersGuard() = headers->Guard();
   aOut.securityInfo() = aIn.GetSecurityInfo();
 }
 
 void
 TypeUtils::ToPCacheResponse(PCacheResponse& aOut, Response& aIn, ErrorResult& aRv)
@@ -273,62 +273,57 @@ TypeUtils::ToPCacheQueryParams(PCacheQue
   } else {
     aOut.cacheName() = NS_LITERAL_STRING("");
   }
 }
 
 already_AddRefed<Response>
 TypeUtils::ToResponse(const PCacheResponse& aIn)
 {
-  nsRefPtr<InternalResponse> ir;
-  switch (aIn.type())
-  {
-    case ResponseType::Error:
-      ir = InternalResponse::NetworkError();
-      break;
-    case ResponseType::Opaque:
-      ir = InternalResponse::OpaqueResponse();
-      break;
-    case ResponseType::Default:
-      ir = new InternalResponse(aIn.status(), aIn.statusText());
-      break;
-    case ResponseType::Basic:
-    {
-      nsRefPtr<InternalResponse> inner = new InternalResponse(aIn.status(),
-                                                              aIn.statusText());
-      ir = InternalResponse::BasicResponse(inner);
-      break;
-    }
-    case ResponseType::Cors:
-    {
-      nsRefPtr<InternalResponse> inner = new InternalResponse(aIn.status(),
-                                                              aIn.statusText());
-      ir = InternalResponse::CORSResponse(inner);
-      break;
-    }
-    default:
-      MOZ_CRASH("Unexpected ResponseType!");
+  if (aIn.type() == ResponseType::Error) {
+    nsRefPtr<InternalResponse> error = InternalResponse::NetworkError();
+    nsRefPtr<Response> r = new Response(GetGlobalObject(), error);
+    return r.forget();
   }
-  MOZ_ASSERT(ir);
 
+  nsRefPtr<InternalResponse> ir = new InternalResponse(aIn.status(),
+                                                       aIn.statusText());
   ir->SetUrl(NS_ConvertUTF16toUTF8(aIn.url()));
 
   nsRefPtr<InternalHeaders> internalHeaders =
     new InternalHeaders(aIn.headers(), aIn.headersGuard());
   ErrorResult result;
   ir->Headers()->SetGuard(aIn.headersGuard(), result);
   MOZ_ASSERT(!result.Failed());
   ir->Headers()->Fill(*internalHeaders, result);
   MOZ_ASSERT(!result.Failed());
 
   ir->SetSecurityInfo(aIn.securityInfo());
 
   nsCOMPtr<nsIInputStream> stream = ReadStream::Create(aIn.body());
   ir->SetBody(stream);
 
+  switch (aIn.type())
+  {
+    case ResponseType::Default:
+      break;
+    case ResponseType::Opaque:
+      ir = ir->OpaqueResponse();
+      break;
+    case ResponseType::Basic:
+      ir = ir->BasicResponse();
+      break;
+    case ResponseType::Cors:
+      ir = ir->CORSResponse();
+      break;
+    default:
+      MOZ_CRASH("Unexpected ResponseType!");
+  }
+  MOZ_ASSERT(ir);
+
   nsRefPtr<Response> ref = new Response(GetGlobalObject(), ir);
   return ref.forget();
 }
 
 already_AddRefed<InternalRequest>
 TypeUtils::ToInternalRequest(const PCacheRequest& aIn)
 {
   nsRefPtr<InternalRequest> internalRequest = new InternalRequest();
--- a/dom/cache/test/mochitest/driver.js
+++ b/dom/cache/test/mochitest/driver.js
@@ -76,18 +76,17 @@ function runTests(testFile, order) {
       };
       document.body.appendChild(iframe);
     });
   }
 
   SimpleTest.waitForExplicitFinish();
 
   if (typeof order == "undefined") {
-    order = "sequential"; // sequential by default, see bug 1143222.
-    // TODO: Make this "both".
+    order = "both"; // both by default
   }
 
   ok(order == "parallel" || order == "sequential" || order == "both",
      "order argument should be valid");
 
   if (order == "both") {
     info("Running tests in both modes; first: sequential");
     return runTests(testFile, "sequential")
--- a/dom/cache/test/mochitest/test_cache_matchAll_request.js
+++ b/dom/cache/test/mochitest/test_cache_matchAll_request.js
@@ -13,17 +13,20 @@ function checkResponse(r, response, resp
   is(r.url, response.url.replace("#fragment", ""),
      "The URLs should be the same");
   is(r.status, response.status, "The status codes should be the same");
   is(r.type, response.type, "The response types should be the same");
   is(r.ok, response.ok, "Both responses should have succeeded");
   is(r.statusText, response.statusText,
      "Both responses should have the same status text");
   return r.text().then(function(text) {
-    is(text, responseText, "The response body should be correct");
+    // Avoid dumping out the large response text to the log if they're equal.
+    if (text !== responseText) {
+      is(text, responseText, "The response body should be correct");
+    }
   });
 }
 
 fetch(new Request(request1)).then(function(r) {
   response1 = r;
   return response1.text();
 }).then(function(text) {
   response1Text = text;
--- a/dom/cache/test/mochitest/test_cache_match_request.js
+++ b/dom/cache/test/mochitest/test_cache_match_request.js
@@ -11,17 +11,20 @@ function checkResponse(r) {
   is(r.url, response.url.replace("#fragment", ""),
      "The URLs should be the same");
   is(r.status, response.status, "The status codes should be the same");
   is(r.type, response.type, "The response types should be the same");
   is(r.ok, response.ok, "Both responses should have succeeded");
   is(r.statusText, response.statusText,
      "Both responses should have the same status text");
   return r.text().then(function(text) {
-    is(text, responseText, "The response body should be correct");
+    // Avoid dumping out the large response text to the log if they're equal.
+    if (text !== responseText) {
+      is(text, responseText, "The response body should be correct");
+    }
   });
 }
 
 fetch(new Request(request)).then(function(r) {
   response = r;
   return response.text();
 }).then(function(text) {
   responseText = text;
--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -27,16 +27,17 @@
 #include "mozilla/dom/Request.h"
 #include "mozilla/dom/Response.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/URLSearchParams.h"
 
 #include "InternalRequest.h"
 #include "InternalResponse.h"
 
+#include "nsFormData.h"
 #include "WorkerPrivate.h"
 #include "WorkerRunnable.h"
 #include "WorkerScope.h"
 #include "Workers.h"
 
 namespace mozilla {
 namespace dom {
 
@@ -448,16 +449,26 @@ ExtractFromBlob(const File& aFile, nsIIn
 
   nsAutoString type;
   impl->GetType(type);
   aContentType = NS_ConvertUTF16toUTF8(type);
   return NS_OK;
 }
 
 nsresult
+ExtractFromFormData(nsFormData& aFormData, nsIInputStream** aStream,
+                    nsCString& aContentType)
+{
+  uint64_t unusedContentLength;
+  nsAutoCString unusedCharset;
+  return aFormData.GetSendInfo(aStream, &unusedContentLength,
+                               aContentType, unusedCharset);
+}
+
+nsresult
 ExtractFromUSVString(const nsString& aStr,
                      nsIInputStream** aStream,
                      nsCString& aContentType)
 {
   nsCOMPtr<nsIUnicodeEncoder> encoder = EncodingUtils::EncoderForEncoding("UTF-8");
   if (!encoder) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
@@ -497,60 +508,66 @@ ExtractFromURLSearchParams(const URLSear
   nsAutoString serialized;
   aParams.Stringify(serialized);
   aContentType = NS_LITERAL_CSTRING("application/x-www-form-urlencoded;charset=UTF-8");
   return NS_NewStringInputStream(aStream, serialized);
 }
 } // anonymous namespace
 
 nsresult
-ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams& aBodyInit,
+ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& aBodyInit,
                           nsIInputStream** aStream,
                           nsCString& aContentType)
 {
   MOZ_ASSERT(aStream);
 
   if (aBodyInit.IsArrayBuffer()) {
     const ArrayBuffer& buf = aBodyInit.GetAsArrayBuffer();
     return ExtractFromArrayBuffer(buf, aStream);
   } else if (aBodyInit.IsArrayBufferView()) {
     const ArrayBufferView& buf = aBodyInit.GetAsArrayBufferView();
     return ExtractFromArrayBufferView(buf, aStream);
   } else if (aBodyInit.IsBlob()) {
     const File& blob = aBodyInit.GetAsBlob();
     return ExtractFromBlob(blob, aStream, aContentType);
+  } else if (aBodyInit.IsFormData()) {
+    nsFormData& form = aBodyInit.GetAsFormData();
+    return ExtractFromFormData(form, aStream, aContentType);
   } else if (aBodyInit.IsUSVString()) {
     nsAutoString str;
     str.Assign(aBodyInit.GetAsUSVString());
     return ExtractFromUSVString(str, aStream, aContentType);
   } else if (aBodyInit.IsURLSearchParams()) {
     URLSearchParams& params = aBodyInit.GetAsURLSearchParams();
     return ExtractFromURLSearchParams(params, aStream, aContentType);
   }
 
   NS_NOTREACHED("Should never reach here");
   return NS_ERROR_FAILURE;
 }
 
 nsresult
-ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams& aBodyInit,
+ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& aBodyInit,
                           nsIInputStream** aStream,
                           nsCString& aContentType)
 {
   MOZ_ASSERT(aStream);
 
   if (aBodyInit.IsArrayBuffer()) {
     const ArrayBuffer& buf = aBodyInit.GetAsArrayBuffer();
     return ExtractFromArrayBuffer(buf, aStream);
   } else if (aBodyInit.IsArrayBufferView()) {
     const ArrayBufferView& buf = aBodyInit.GetAsArrayBufferView();
     return ExtractFromArrayBufferView(buf, aStream);
   } else if (aBodyInit.IsBlob()) {
     const File& blob = aBodyInit.GetAsBlob();
     return ExtractFromBlob(blob, aStream, aContentType);
+  } else if (aBodyInit.IsFormData()) {
+    nsFormData& form = aBodyInit.GetAsFormData();
+    return ExtractFromFormData(form, aStream, aContentType);
   } else if (aBodyInit.IsUSVString()) {
     nsAutoString str;
     str.Assign(aBodyInit.GetAsUSVString());
     return ExtractFromUSVString(str, aStream, aContentType);
   } else if (aBodyInit.IsURLSearchParams()) {
     URLSearchParams& params = aBodyInit.GetAsURLSearchParams();
     return ExtractFromURLSearchParams(params, aStream, aContentType);
   }
--- a/dom/fetch/Fetch.h
+++ b/dom/fetch/Fetch.h
@@ -21,19 +21,19 @@
 #include "mozilla/dom/workers/bindings/WorkerFeature.h"
 
 class nsIOutputStream;
 class nsIGlobalObject;
 
 namespace mozilla {
 namespace dom {
 
-class ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams;
+class ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams;
 class InternalRequest;
-class OwningArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams;
+class OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams;
 class RequestOrUSVString;
 
 namespace workers {
 class WorkerPrivate;
 } // namespace workers
 
 already_AddRefed<Promise>
 FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
@@ -43,25 +43,25 @@ nsresult
 UpdateRequestReferrer(nsIGlobalObject* aGlobal, InternalRequest* aRequest);
 
 /*
  * Creates an nsIInputStream based on the fetch specifications 'extract a byte
  * stream algorithm' - http://fetch.spec.whatwg.org/#concept-bodyinit-extract.
  * Stores content type in out param aContentType.
  */
 nsresult
-ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams& aBodyInit,
+ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& aBodyInit,
                           nsIInputStream** aStream,
                           nsCString& aContentType);
 
 /*
  * Non-owning version.
  */
 nsresult
-ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams& aBodyInit,
+ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& aBodyInit,
                           nsIInputStream** aStream,
                           nsCString& aContentType);
 
 template <class Derived> class FetchBodyFeature;
 
 /*
  * FetchBody's body consumption uses nsIInputStreamPump to read from the
  * underlying stream to a block of memory, which is then adopted by
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -480,44 +480,52 @@ FetchDriver::HttpFetch(bool aCORSFlag, b
   // Set skip serviceworker flag.
   // While the spec also gates on the client being a ServiceWorker, we can't
   // infer that here. Instead we rely on callers to set the flag correctly.
   if (mRequest->SkipServiceWorker()) {
     nsCOMPtr<nsIHttpChannelInternal> internalChan = do_QueryInterface(httpChan);
     internalChan->ForceNoIntercept();
   }
 
-  // Set up a CORS proxy that will handle the various requirements of the CORS
-  // protocol. It handles the preflight cache and CORS response headers.
-  // If the request is allowed, it will start our original request
-  // and our observer will be notified. On failure, our observer is notified
-  // directly.
-  nsRefPtr<nsCORSListenerProxy> corsListener =
-    new nsCORSListenerProxy(this, mPrincipal, useCredentials);
-  rv = corsListener->Init(chan, true /* allow data uri */);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return FailWithNetworkError();
+  nsCOMPtr<nsIStreamListener> listener = this;
+
+  // Unless the cors mode is explicitly no-cors, we set up a cors proxy even in
+  // the same-origin case, since the proxy does not enforce cors header checks
+  // in the same-origin case.
+  if (mRequest->Mode() != RequestMode::No_cors) {
+    // Set up a CORS proxy that will handle the various requirements of the CORS
+    // protocol. It handles the preflight cache and CORS response headers.
+    // If the request is allowed, it will start our original request
+    // and our observer will be notified. On failure, our observer is notified
+    // directly.
+    nsRefPtr<nsCORSListenerProxy> corsListener =
+      new nsCORSListenerProxy(this, mPrincipal, useCredentials);
+    rv = corsListener->Init(chan, true /* allow data uri */);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return FailWithNetworkError();
+    }
+    listener = corsListener.forget();
   }
 
   // If preflight is required, start a "CORS preflight fetch"
   // https://fetch.spec.whatwg.org/#cors-preflight-fetch-0. All the
   // implementation is handled by NS_StartCORSPreflight, we just set up the
   // unsafeHeaders so they can be verified against the response's
   // "Access-Control-Allow-Headers" header.
   if (aCORSPreflightFlag) {
     nsCOMPtr<nsIChannel> preflightChannel;
     nsAutoTArray<nsCString, 5> unsafeHeaders;
     mRequest->Headers()->GetUnsafeHeaders(unsafeHeaders);
 
-    rv = NS_StartCORSPreflight(chan, corsListener, mPrincipal,
+    rv = NS_StartCORSPreflight(chan, listener, mPrincipal,
                                useCredentials,
                                unsafeHeaders,
                                getter_AddRefs(preflightChannel));
   } else {
-   rv = chan->AsyncOpen(corsListener, nullptr);
+   rv = chan->AsyncOpen(listener, nullptr);
   }
 
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return FailWithNetworkError();
   }
 
   // Step 4 onwards of "HTTP Fetch" is handled internally by Necko.
   return NS_OK;
@@ -543,23 +551,23 @@ FetchDriver::BeginAndGetFilteredResponse
     aResponse->SetUrl(reqURL);
   }
 
   // FIXME(nsm): Handle mixed content check, step 7 of fetch.
 
   nsRefPtr<InternalResponse> filteredResponse;
   switch (mRequest->GetResponseTainting()) {
     case InternalRequest::RESPONSETAINT_BASIC:
-      filteredResponse = InternalResponse::BasicResponse(aResponse);
+      filteredResponse = aResponse->BasicResponse();
       break;
     case InternalRequest::RESPONSETAINT_CORS:
-      filteredResponse = InternalResponse::CORSResponse(aResponse);
+      filteredResponse = aResponse->CORSResponse();
       break;
     case InternalRequest::RESPONSETAINT_OPAQUE:
-      filteredResponse = InternalResponse::OpaqueResponse();
+      filteredResponse = aResponse->OpaqueResponse();
       break;
     default:
       MOZ_CRASH("Unexpected case");
   }
 
   MOZ_ASSERT(filteredResponse);
   MOZ_ASSERT(mObserver);
   mObserver->OnResponseAvailable(filteredResponse);
@@ -770,17 +778,17 @@ FetchDriver::AsyncOnChannelRedirect(nsIC
   // The only thing we do is to check if the request requires a preflight (part
   // of step 4.9), in which case we abort. This part cannot be done by
   // nsCORSListenerProxy since it does not have access to mRequest.
   // which case. Step 4.10.3 is handled by OnRedirectVerifyCallback(), and all
   // the other steps are handled by nsCORSListenerProxy.
   if (!NS_IsInternalSameURIRedirect(aOldChannel, aNewChannel, aFlags)) {
     rv = DoesNotRequirePreflight(aNewChannel);
     if (NS_FAILED(rv)) {
-      NS_WARNING("nsXMLHttpRequest::OnChannelRedirect: "
+      NS_WARNING("FetchDriver::OnChannelRedirect: "
                  "DoesNotRequirePreflight returned failure");
       return rv;
     }
   }
 
   mRedirectCallback = aCallback;
   mOldRedirectChannel = aOldChannel;
   mNewRedirectChannel = aNewChannel;
--- a/dom/fetch/InternalResponse.cpp
+++ b/dom/fetch/InternalResponse.cpp
@@ -18,35 +18,27 @@ InternalResponse::InternalResponse(uint1
   : mType(ResponseType::Default)
   , mFinalURL(false)
   , mStatus(aStatus)
   , mStatusText(aStatusText)
   , mHeaders(new InternalHeaders(HeadersGuardEnum::Response))
 {
 }
 
-// Headers are not copied since BasicResponse and CORSResponse both need custom
-// header handling.  Body is not copied as it cannot be shared directly.
-InternalResponse::InternalResponse(const InternalResponse& aOther)
-  : mType(aOther.mType)
-  , mTerminationReason(aOther.mTerminationReason)
-  , mURL(aOther.mURL)
-  , mFinalURL(aOther.mFinalURL)
-  , mStatus(aOther.mStatus)
-  , mStatusText(aOther.mStatusText)
-  , mContentType(aOther.mContentType)
-  , mSecurityInfo(aOther.mSecurityInfo)
-{
-}
-
 already_AddRefed<InternalResponse>
 InternalResponse::Clone()
 {
-  nsRefPtr<InternalResponse> clone = new InternalResponse(*this);
+  nsRefPtr<InternalResponse> clone = CreateIncompleteCopy();
+
   clone->mHeaders = new InternalHeaders(*mHeaders);
+  if (mWrappedResponse) {
+    clone->mWrappedResponse = mWrappedResponse->Clone();
+    MOZ_ASSERT(!mBody);
+    return clone.forget();
+  }
 
   if (!mBody) {
     return clone.forget();
   }
 
   nsCOMPtr<nsIInputStream> clonedBody;
   nsCOMPtr<nsIInputStream> replacementBody;
 
@@ -57,37 +49,35 @@ InternalResponse::Clone()
   clone->mBody.swap(clonedBody);
   if (replacementBody) {
     mBody.swap(replacementBody);
   }
 
   return clone.forget();
 }
 
-// static
 already_AddRefed<InternalResponse>
-InternalResponse::BasicResponse(InternalResponse* aInner)
+InternalResponse::BasicResponse()
 {
-  MOZ_ASSERT(aInner);
-  nsRefPtr<InternalResponse> basic = new InternalResponse(*aInner);
+  MOZ_ASSERT(!mWrappedResponse, "Can't BasicResponse a already wrapped response");
+  nsRefPtr<InternalResponse> basic = CreateIncompleteCopy();
   basic->mType = ResponseType::Basic;
-  basic->mHeaders = InternalHeaders::BasicHeaders(aInner->mHeaders);
-  basic->mBody.swap(aInner->mBody);
+  basic->mHeaders = InternalHeaders::BasicHeaders(Headers());
+  basic->mWrappedResponse = this;
   return basic.forget();
 }
 
-// static
 already_AddRefed<InternalResponse>
-InternalResponse::CORSResponse(InternalResponse* aInner)
+InternalResponse::CORSResponse()
 {
-  MOZ_ASSERT(aInner);
-  nsRefPtr<InternalResponse> cors = new InternalResponse(*aInner);
+  MOZ_ASSERT(!mWrappedResponse, "Can't CORSResponse a already wrapped response");
+  nsRefPtr<InternalResponse> cors = CreateIncompleteCopy();
   cors->mType = ResponseType::Cors;
-  cors->mHeaders = InternalHeaders::CORSHeaders(aInner->mHeaders);
-  cors->mBody.swap(aInner->mBody);
+  cors->mHeaders = InternalHeaders::CORSHeaders(Headers());
+  cors->mWrappedResponse = this;
   return cors.forget();
 }
 
 void
 InternalResponse::SetSecurityInfo(nsISupports* aSecurityInfo)
 {
   MOZ_ASSERT(mSecurityInfo.IsEmpty(), "security info should only be set once");
   nsCOMPtr<nsISerializable> serializable = do_QueryInterface(aSecurityInfo);
--- a/dom/fetch/InternalResponse.h
+++ b/dom/fetch/InternalResponse.h
@@ -33,37 +33,44 @@ public:
     nsRefPtr<InternalResponse> response = new InternalResponse(0, EmptyCString());
     ErrorResult result;
     response->Headers()->SetGuard(HeadersGuardEnum::Immutable, result);
     MOZ_ASSERT(!result.Failed());
     response->mType = ResponseType::Error;
     return response.forget();
   }
 
-  static already_AddRefed<InternalResponse>
+  already_AddRefed<InternalResponse>
   OpaqueResponse()
   {
+    MOZ_ASSERT(!mWrappedResponse, "Can't OpaqueResponse a already wrapped response");
     nsRefPtr<InternalResponse> response = new InternalResponse(0, EmptyCString());
     response->mType = ResponseType::Opaque;
+    response->mTerminationReason = mTerminationReason;
+    response->mURL = mURL;
+    response->mFinalURL = mFinalURL;
+    response->mSecurityInfo = mSecurityInfo;
+    response->mWrappedResponse = this;
     return response.forget();
   }
 
-  // DO NOT use the inner response after filtering it since the filtered
-  // response will adopt the inner response's body.
-  static already_AddRefed<InternalResponse>
-  BasicResponse(InternalResponse* aInner);
+  already_AddRefed<InternalResponse>
+  BasicResponse();
 
-  // DO NOT use the inner response after filtering it since the filtered
-  // response will adopt the inner response's body.
-  static already_AddRefed<InternalResponse>
-  CORSResponse(InternalResponse* aInner);
+  already_AddRefed<InternalResponse>
+  CORSResponse();
 
   ResponseType
   Type() const
   {
+    MOZ_ASSERT_IF(mType == ResponseType::Error, !mWrappedResponse);
+    MOZ_ASSERT_IF(mType == ResponseType::Default, !mWrappedResponse);
+    MOZ_ASSERT_IF(mType == ResponseType::Basic, mWrappedResponse);
+    MOZ_ASSERT_IF(mType == ResponseType::Cors, mWrappedResponse);
+    MOZ_ASSERT_IF(mType == ResponseType::Opaque, mWrappedResponse);
     return mType;
   }
 
   bool
   IsError() const
   {
     return Type() == ResponseType::Error;
   }
@@ -106,26 +113,48 @@ public:
   }
 
   InternalHeaders*
   Headers()
   {
     return mHeaders;
   }
 
+  InternalHeaders*
+  UnfilteredHeaders()
+  {
+    if (mWrappedResponse) {
+      return mWrappedResponse->Headers();
+    };
+
+    return Headers();
+  }
+
   void
   GetBody(nsIInputStream** aStream)
   {
+    if (Type() == ResponseType::Opaque) {
+      *aStream = nullptr;
+      return;
+    }
+
+    if (mWrappedResponse) {
+      MOZ_ASSERT(!mBody);
+      return mWrappedResponse->GetBody(aStream);
+    }
     nsCOMPtr<nsIInputStream> stream = mBody;
     stream.forget(aStream);
   }
 
   void
   SetBody(nsIInputStream* aBody)
   {
+    if (mWrappedResponse) {
+      return mWrappedResponse->SetBody(aBody);
+    }
     // A request's body may not be reset once set.
     MOZ_ASSERT(!mBody);
     mBody = aBody;
   }
 
   const nsCString&
   GetSecurityInfo() const
   {
@@ -137,28 +166,46 @@ public:
 
   void
   SetSecurityInfo(const nsCString& aSecurityInfo);
 
 private:
   ~InternalResponse()
   { }
 
-  // Used to create filtered and cloned responses.
-  // Does not copy headers or body stream.
-  explicit InternalResponse(const InternalResponse& aOther);
+  explicit InternalResponse(const InternalResponse& aOther) = delete;
+  InternalResponse& operator=(const InternalResponse&) = delete;
+
+  // Returns an instance of InternalResponse which is a copy of this
+  // InternalResponse, except headers, body and wrapped response (if any) which
+  // are left uninitialized. Used for cloning and filtering.
+  already_AddRefed<InternalResponse> CreateIncompleteCopy()
+  {
+    nsRefPtr<InternalResponse> copy = new InternalResponse(mStatus, mStatusText);
+    copy->mType = mType;
+    copy->mTerminationReason = mTerminationReason;
+    copy->mURL = mURL;
+    copy->mFinalURL = mFinalURL;
+    copy->mSecurityInfo = mSecurityInfo;
+    return copy.forget();
+  }
 
   ResponseType mType;
   nsCString mTerminationReason;
   nsCString mURL;
   bool mFinalURL;
   const uint16_t mStatus;
   const nsCString mStatusText;
   nsRefPtr<InternalHeaders> mHeaders;
   nsCOMPtr<nsIInputStream> mBody;
-  nsCString mContentType;
   nsCString mSecurityInfo;
+
+  // For filtered responses.
+  // Cache, and SW interception should always serialize/access the underlying
+  // unfiltered headers and when deserializing, create an InternalResponse
+  // with the unfiltered headers followed by wrapping it.
+  nsRefPtr<InternalResponse> mWrappedResponse;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_InternalResponse_h
--- a/dom/fetch/Request.cpp
+++ b/dom/fetch/Request.cpp
@@ -223,17 +223,17 @@ Request::Constructor(const GlobalObject&
     nsAutoCString method;
     request->GetMethod(method);
     // method is guaranteed to be uppercase due to step 14.2 above.
     if (method.EqualsLiteral("HEAD") || method.EqualsLiteral("GET")) {
       aRv.ThrowTypeError(MSG_NO_BODY_ALLOWED_FOR_GET_AND_HEAD);
       return nullptr;
     }
 
-    const OwningArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams& bodyInit = aInit.mBody.Value();
+    const OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& bodyInit = aInit.mBody.Value();
     nsCOMPtr<nsIInputStream> stream;
     nsCString contentType;
     aRv = ExtractByteStreamFromBody(bodyInit,
                                     getter_AddRefs(stream), contentType);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
     request->SetBody(stream);
--- a/dom/fetch/Response.cpp
+++ b/dom/fetch/Response.cpp
@@ -94,17 +94,17 @@ Response::Redirect(const GlobalObject& a
     return nullptr;
   }
 
   if (aStatus != 301 && aStatus != 302 && aStatus != 303 && aStatus != 307 && aStatus != 308) {
     aRv.ThrowRangeError(MSG_INVALID_REDIRECT_STATUSCODE_ERROR);
     return nullptr;
   }
 
-  Optional<ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams> body;
+  Optional<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams> body;
   ResponseInit init;
   init.mStatus = aStatus;
   nsRefPtr<Response> r = Response::Constructor(aGlobal, body, init, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   r->GetInternalHeaders()->Set(NS_LITERAL_CSTRING("Location"),
@@ -115,17 +115,17 @@ Response::Redirect(const GlobalObject& a
   r->GetInternalHeaders()->SetGuard(HeadersGuardEnum::Immutable, aRv);
   MOZ_ASSERT(!aRv.Failed());
 
   return r.forget();
 }
 
 /*static*/ already_AddRefed<Response>
 Response::Constructor(const GlobalObject& aGlobal,
-                      const Optional<ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams>& aBody,
+                      const Optional<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>& aBody,
                       const ResponseInit& aInit, ErrorResult& aRv)
 {
   if (aInit.mStatus < 200 || aInit.mStatus > 599) {
     aRv.ThrowRangeError(MSG_INVALID_RESPONSE_STATUSCODE_ERROR);
     return nullptr;
   }
 
   nsCString statusText;
--- a/dom/fetch/Response.h
+++ b/dom/fetch/Response.h
@@ -98,17 +98,17 @@ public:
   static already_AddRefed<Response>
   Error(const GlobalObject& aGlobal);
 
   static already_AddRefed<Response>
   Redirect(const GlobalObject& aGlobal, const nsAString& aUrl, uint16_t aStatus, ErrorResult& aRv);
 
   static already_AddRefed<Response>
   Constructor(const GlobalObject& aGlobal,
-              const Optional<ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams>& aBody,
+              const Optional<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>& aBody,
               const ResponseInit& aInit, ErrorResult& rv);
 
   nsIGlobalObject* GetParentObject() const
   {
     return mOwner;
   }
 
   already_AddRefed<Response>
--- a/dom/html/HTMLAnchorElement.h
+++ b/dom/html/HTMLAnchorElement.h
@@ -38,17 +38,17 @@ public:
   // CC
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLAnchorElement,
                                            nsGenericHTMLElement)
 
   virtual int32_t TabIndexDefault() MOZ_OVERRIDE;
   virtual bool Draggable() const MOZ_OVERRIDE;
 
   // Element
-  virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE
+  virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const MOZ_OVERRIDE
   {
     return true;
   }
 
   // nsIDOMHTMLAnchorElement
   NS_DECL_NSIDOMHTMLANCHORELEMENT
 
   // DOM memory reporter participant
--- a/dom/html/HTMLAudioElement.cpp
+++ b/dom/html/HTMLAudioElement.cpp
@@ -36,17 +36,17 @@ HTMLAudioElement::HTMLAudioElement(alrea
 {
 }
 
 HTMLAudioElement::~HTMLAudioElement()
 {
 }
 
 bool
-HTMLAudioElement::IsInteractiveHTMLContent() const
+HTMLAudioElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
 {
   return HasAttr(kNameSpaceID_None, nsGkAtoms::controls);
 }
 
 already_AddRefed<HTMLAudioElement>
 HTMLAudioElement::Audio(const GlobalObject& aGlobal,
                         const Optional<nsAString>& aSrc,
                         ErrorResult& aRv)
--- a/dom/html/HTMLAudioElement.h
+++ b/dom/html/HTMLAudioElement.h
@@ -19,17 +19,17 @@ namespace dom {
 class HTMLAudioElement MOZ_FINAL : public HTMLMediaElement
 {
 public:
   typedef mozilla::dom::NodeInfo NodeInfo;
 
   explicit HTMLAudioElement(already_AddRefed<NodeInfo>& aNodeInfo);
 
   // Element
-  virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE;
+  virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const MOZ_OVERRIDE;
 
   // nsIDOMHTMLMediaElement
   using HTMLMediaElement::GetPaused;
 
   virtual nsresult Clone(NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
   virtual nsresult SetAcceptHeader(nsIHttpChannel* aChannel) MOZ_OVERRIDE;
 
   virtual nsIDOMNode* AsDOMNode() MOZ_OVERRIDE { return this; }
--- a/dom/html/HTMLButtonElement.h
+++ b/dom/html/HTMLButtonElement.h
@@ -32,17 +32,17 @@ public:
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual int32_t TabIndexDefault() MOZ_OVERRIDE;
 
   NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLButtonElement, button)
 
   // Element
-  virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE
+  virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const MOZ_OVERRIDE
   {
     return true;
   }
 
   // nsIDOMHTMLButtonElement
   NS_DECL_NSIDOMHTMLBUTTONELEMENT
 
   // overriden nsIFormControl methods
--- a/dom/html/HTMLIFrameElement.h
+++ b/dom/html/HTMLIFrameElement.h
@@ -22,17 +22,17 @@ public:
                              FromParser aFromParser = NOT_FROM_PARSER);
 
   NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLIFrameElement, iframe)
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // Element
-  virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE
+  virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const MOZ_OVERRIDE
   {
     return true;
   }
 
   // nsIDOMHTMLIFrameElement
   NS_DECL_NSIDOMHTMLIFRAMEELEMENT
 
   // nsIContent
--- a/dom/html/HTMLImageElement.cpp
+++ b/dom/html/HTMLImageElement.cpp
@@ -144,17 +144,17 @@ NS_IMPL_URI_ATTR(HTMLImageElement, LongD
 NS_IMPL_STRING_ATTR(HTMLImageElement, Sizes, sizes)
 NS_IMPL_STRING_ATTR(HTMLImageElement, Lowsrc, lowsrc)
 NS_IMPL_URI_ATTR(HTMLImageElement, Src, src)
 NS_IMPL_STRING_ATTR(HTMLImageElement, Srcset, srcset)
 NS_IMPL_STRING_ATTR(HTMLImageElement, UseMap, usemap)
 NS_IMPL_INT_ATTR(HTMLImageElement, Vspace, vspace)
 
 bool
-HTMLImageElement::IsInteractiveHTMLContent() const
+HTMLImageElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
 {
   return HasAttr(kNameSpaceID_None, nsGkAtoms::usemap);
 }
 
 bool
 HTMLImageElement::IsSrcsetEnabled()
 {
   return Preferences::GetBool(kPrefSrcsetEnabled, false);
--- a/dom/html/HTMLImageElement.h
+++ b/dom/html/HTMLImageElement.h
@@ -42,17 +42,17 @@ public:
                                            nsGenericHTMLElement)
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual bool Draggable() const MOZ_OVERRIDE;
 
   // Element
-  virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE;
+  virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const MOZ_OVERRIDE;
 
   // nsIDOMHTMLImageElement
   NS_DECL_NSIDOMHTMLIMAGEELEMENT
 
   NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLImageElement, img)
 
   // override from nsImageLoadingContent
   CORSMode GetCORSMode() MOZ_OVERRIDE;
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -3217,17 +3217,17 @@ HTMLInputElement::Focus(ErrorResult& aEr
       }
     }
   }
 
   return;
 }
 
 bool
-HTMLInputElement::IsInteractiveHTMLContent() const
+HTMLInputElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
 {
   return mType != NS_FORM_INPUT_HIDDEN;
 }
 
 NS_IMETHODIMP
 HTMLInputElement::Select()
 {
   if (mType == NS_FORM_INPUT_NUMBER) {
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -115,17 +115,17 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual int32_t TabIndexDefault() MOZ_OVERRIDE;
   using nsGenericHTMLElement::Focus;
   virtual void Blur(ErrorResult& aError) MOZ_OVERRIDE;
   virtual void Focus(ErrorResult& aError) MOZ_OVERRIDE;
 
   // Element
-  virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE;
+  virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const MOZ_OVERRIDE;
 
   // nsIDOMHTMLInputElement
   NS_DECL_NSIDOMHTMLINPUTELEMENT
 
   // nsIPhonetic
   NS_DECL_NSIPHONETIC
 
   // nsIDOMNSEditableElement
--- a/dom/html/HTMLLabelElement.cpp
+++ b/dom/html/HTMLLabelElement.cpp
@@ -83,17 +83,17 @@ HTMLLabelElement::Focus(ErrorResult& aEr
 }
 
 static bool
 InInteractiveHTMLContent(nsIContent* aContent, nsIContent* aStop)
 {
   nsIContent* content = aContent;
   while (content && content != aStop) {
     if (content->IsElement() &&
-        content->AsElement()->IsInteractiveHTMLContent()) {
+        content->AsElement()->IsInteractiveHTMLContent(true)) {
       return true;
     }
     content = content->GetParent();
   }
   return false;
 }
 
 nsresult
--- a/dom/html/HTMLLabelElement.h
+++ b/dom/html/HTMLLabelElement.h
@@ -28,17 +28,17 @@ public:
   }
 
   NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLLabelElement, label)
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // Element
-  virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE
+  virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const MOZ_OVERRIDE
   {
     return true;
   }
 
   // nsIDOMHTMLLabelElement
   NS_DECL_NSIDOMHTMLLABELELEMENT
 
   using nsGenericHTMLFormElement::GetForm;
--- a/dom/html/HTMLObjectElement.cpp
+++ b/dom/html/HTMLObjectElement.cpp
@@ -45,17 +45,17 @@ HTMLObjectElement::HTMLObjectElement(alr
 
 HTMLObjectElement::~HTMLObjectElement()
 {
   UnregisterActivityObserver();
   DestroyImageLoadingContent();
 }
 
 bool
-HTMLObjectElement::IsInteractiveHTMLContent() const
+HTMLObjectElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
 {
   return HasAttr(kNameSpaceID_None, nsGkAtoms::usemap);
 }
 
 bool
 HTMLObjectElement::IsDoneAddingChildren()
 {
   return mIsDoneAddingChildren;
--- a/dom/html/HTMLObjectElement.h
+++ b/dom/html/HTMLObjectElement.h
@@ -32,17 +32,17 @@ public:
 
 #ifdef XP_MACOSX
   // nsIDOMEventTarget
   NS_IMETHOD PostHandleEvent(EventChainPostVisitor& aVisitor) MOZ_OVERRIDE;
   static void HandleFocusBlurPlugin(Element* aElement, WidgetEvent* aEvent);
 #endif
 
   // Element
-  virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE;
+  virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const MOZ_OVERRIDE;
 
   // nsIDOMHTMLObjectElement
   NS_DECL_NSIDOMHTMLOBJECTELEMENT
 
   virtual nsresult BindToTree(nsIDocument *aDocument, nsIContent *aParent,
                               nsIContent *aBindingParent,
                               bool aCompileEventHandlers) MOZ_OVERRIDE;
   virtual void UnbindFromTree(bool aDeep = true,
--- a/dom/html/HTMLSelectElement.h
+++ b/dom/html/HTMLSelectElement.h
@@ -143,17 +143,17 @@ public:
   NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLSelectElement, select)
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual int32_t TabIndexDefault() MOZ_OVERRIDE;
 
   // Element
-  virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE
+  virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const MOZ_OVERRIDE
   {
     return true;
   }
 
   // nsIDOMHTMLSelectElement
   NS_DECL_NSIDOMHTMLSELECTELEMENT
 
   // WebIdl HTMLSelectElement
--- a/dom/html/HTMLTextAreaElement.h
+++ b/dom/html/HTMLTextAreaElement.h
@@ -49,17 +49,17 @@ public:
                                FromParser aFromParser = NOT_FROM_PARSER);
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual int32_t TabIndexDefault() MOZ_OVERRIDE;
 
   // Element
-  virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE
+  virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const MOZ_OVERRIDE
   {
     return true;
   }
 
   // nsIDOMHTMLTextAreaElement
   NS_DECL_NSIDOMHTMLTEXTAREAELEMENT
 
   // nsIDOMNSEditableElement
--- a/dom/html/HTMLVideoElement.cpp
+++ b/dom/html/HTMLVideoElement.cpp
@@ -122,17 +122,17 @@ nsresult HTMLVideoElement::SetAcceptHead
       "audio/*;q=0.6,*/*;q=0.5");
 
   return aChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
                                     value,
                                     false);
 }
 
 bool
-HTMLVideoElement::IsInteractiveHTMLContent() const
+HTMLVideoElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
 {
   return HasAttr(kNameSpaceID_None, nsGkAtoms::controls);
 }
 
 uint32_t HTMLVideoElement::MozParsedFrames() const
 {
   MOZ_ASSERT(NS_IsMainThread(), "Should be on main thread.");
   if (!sVideoStatsEnabled) {
--- a/dom/html/HTMLVideoElement.h
+++ b/dom/html/HTMLVideoElement.h
@@ -45,17 +45,17 @@ public:
 
   // Set size with the current video frame's height and width.
   // If there is no video frame, returns NS_ERROR_FAILURE.
   nsresult GetVideoSize(nsIntSize* size);
 
   virtual nsresult SetAcceptHeader(nsIHttpChannel* aChannel) MOZ_OVERRIDE;
 
   // Element
-  virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE;
+  virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const MOZ_OVERRIDE;
 
   // WebIDL
 
   uint32_t Width() const
   {
     return GetIntAttr(nsGkAtoms::width, 0);
   }
 
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -1789,21 +1789,21 @@ nsGenericHTMLElement::GetContextMenu(nsI
 
 bool
 nsGenericHTMLElement::IsLabelable() const
 {
   return IsAnyOfHTMLElements(nsGkAtoms::progress, nsGkAtoms::meter);
 }
 
 bool
-nsGenericHTMLElement::IsInteractiveHTMLContent() const
+nsGenericHTMLElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
 {
   return IsAnyOfHTMLElements(nsGkAtoms::details, nsGkAtoms::embed,
                              nsGkAtoms::keygen) ||
-         HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex);
+         (!aIgnoreTabindex && HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex));
 }
 
 already_AddRefed<UndoManager>
 nsGenericHTMLElement::GetUndoManager()
 {
   nsDOMSlots* slots = GetExistingDOMSlots();
   if (slots && slots->mUndoManager) {
     nsRefPtr<UndoManager> undoManager = slots->mUndoManager;
--- a/dom/html/nsGenericHTMLElement.h
+++ b/dom/html/nsGenericHTMLElement.h
@@ -918,17 +918,17 @@ public:
   }
 
   bool IsHidden() const
   {
     return HasAttr(kNameSpaceID_None, nsGkAtoms::hidden);
   }
 
   virtual bool IsLabelable() const MOZ_OVERRIDE;
-  virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE;
+  virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const MOZ_OVERRIDE;
 
   static bool TouchEventsEnabled(JSContext* /* unused */, JSObject* /* unused */);
 
   static inline bool
   CanHaveName(nsIAtom* aTag)
   {
     return aTag == nsGkAtoms::img ||
            aTag == nsGkAtoms::form ||
--- a/dom/html/test/forms/test_interactive_content_in_label.html
+++ b/dom/html/test/forms/test_interactive_content_in_label.html
@@ -27,23 +27,23 @@ https://bugzilla.mozilla.org/show_bug.cg
     <img id="yes7" src="data:image/png," usemap="#map">
     <input id="yes8" type="text" size="4">
     <keygen id="yes9">
     <label id="yes10">label</label>
     <object id="yes11" usemap="#map">object</object>
     <select id="yes12"><option>select</option></select>
     <textarea id="yes13" cols="1" rows="1"></textarea>
     <video id="yes14" controls></video>
-    <span id="yes15" tabindex="1">tabindex</span>
 
     <audio id="no1"></audio>
     <img id="no2" src="data:image/png,">
     <input id="no3" type="hidden">
     <object id="no4">object</object>
     <video id="no5"></video>
+    <span id="no6" tabindex="1">tabindex</span>
   </label>
 </form>
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 229925 **/
 
 var target = document.getElementById("target");
 
@@ -57,26 +57,26 @@ var yes_nodes = [
   document.getElementById("yes7"),
   document.getElementById("yes8"),
   document.getElementById("yes9"),
   document.getElementById("yes10"),
   document.getElementById("yes11"),
   document.getElementById("yes12"),
   document.getElementById("yes13"),
   document.getElementById("yes14"),
-  document.getElementById("yes15"),
 ];
 
 var no_nodes = [
   document.getElementById("text"),
   document.getElementById("no1"),
   document.getElementById("no2"),
   document.getElementById("no3"),
   document.getElementById("no4"),
   document.getElementById("no5"),
+  document.getElementById("no6"),
 ];
 
 var target_clicked = false;
 target.addEventListener("click", function() {
   target_clicked = true;
 });
 
 var node;
--- a/dom/media/VideoUtils.cpp
+++ b/dom/media/VideoUtils.cpp
@@ -228,16 +228,22 @@ ExtractH264CodecDetails(const nsAString&
   // Extract the profile_idc and level_idc.
   nsresult rv = NS_OK;
   aProfile = PromiseFlatString(Substring(aCodec, 5, 2)).ToInteger(&rv, 16);
   NS_ENSURE_SUCCESS(rv, false);
 
   aLevel = PromiseFlatString(Substring(aCodec, 9, 2)).ToInteger(&rv, 16);
   NS_ENSURE_SUCCESS(rv, false);
 
+  if (aLevel == 9) {
+    aLevel = H264_LEVEL_1_b;
+  } else if (aLevel <= 5) {
+    aLevel *= 10;
+  }
+
   // Capture the constraint_set flag value for the purpose of Telemetry.
   // We don't NS_ENSURE_SUCCESS here because ExtractH264CodecDetails doesn't
   // care about this, but we make sure constraints is above 4 (constraint_set5_flag)
   // otherwise collect 0 for unknown.
   uint8_t constraints = PromiseFlatString(Substring(aCodec, 7, 2)).ToInteger(&rv, 16);
   Telemetry::Accumulate(Telemetry::VIDEO_CANPLAYTYPE_H264_CONSTRAINT_SET_FLAG,
                         constraints >= 4 ? constraints : 0);
 
--- a/dom/media/fmp4/MP4Reader.cpp
+++ b/dom/media/fmp4/MP4Reader.cpp
@@ -481,19 +481,17 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo
   if (HasVideo()) {
     const VideoDecoderConfig& video = mDemuxer->VideoConfig();
     if (mInfo.mVideo.mHasVideo && !IsSupportedVideoMimeType(video.mime_type)) {
       return NS_ERROR_FAILURE;
     }
     mInfo.mVideo.mDisplay =
       nsIntSize(video.display_width, video.display_height);
     mVideo.mCallback = new DecoderCallback(this, kVideo);
-    if (!mIsEncrypted && mSharedDecoderManager) {
-      // Note: Don't use SharedDecoderManager in EME content, as it doesn't
-      // handle reiniting the decoder properly yet.
+    if (mSharedDecoderManager) {
       mVideo.mDecoder =
         mSharedDecoderManager->CreateVideoDecoder(mPlatform,
                                                   video,
                                                   mLayersBackendType,
                                                   mDecoder->GetImageContainer(),
                                                   mVideo.mTaskQueue,
                                                   mVideo.mCallback);
     } else {
@@ -575,17 +573,17 @@ MP4Reader::GetNextKeyframeTime()
 {
   MonitorAutoLock mon(mDemuxerMonitor);
   return mVideo.mTrackDemuxer->GetNextKeyframeTime();
 }
 
 void
 MP4Reader::DisableHardwareAcceleration()
 {
-  if (HasVideo() && !mIsEncrypted && mSharedDecoderManager) {
+  if (HasVideo() && mSharedDecoderManager) {
     mPlatform->DisableHardwareAcceleration();
 
     const VideoDecoderConfig& video = mDemuxer->VideoConfig();
     if (!mSharedDecoderManager->Recreate(mPlatform, video, mLayersBackendType, mDecoder->GetImageContainer())) {
       MonitorAutoLock mon(mVideo.mMonitor);
       mVideo.mError = true;
       if (mVideo.HasPromise()) {
         mVideo.RejectPromise(DECODE_ERROR, __func__);
@@ -1106,19 +1104,17 @@ void MP4Reader::NotifyResourcesStatusCha
   if (mDecoder) {
     mDecoder->NotifyWaitingForResourcesStatusChanged();
   }
 }
 
 void
 MP4Reader::SetIdle()
 {
-  if (!mIsEncrypted && mSharedDecoderManager && mVideo.mDecoder) {
-    // Note: Don't use SharedDecoderManager in EME content, as it doesn't
-    // handle reiniting the decoder properly yet.
+  if (mSharedDecoderManager && mVideo.mDecoder) {
     mSharedDecoderManager->SetIdle(mVideo.mDecoder);
     NotifyResourcesStatusChanged();
   }
 }
 
 void
 MP4Reader::SetSharedDecoderManager(SharedDecoderManager* aManager)
 {
--- a/dom/media/mediasource/MediaSource.cpp
+++ b/dom/media/mediasource/MediaSource.cpp
@@ -228,22 +228,38 @@ MediaSource::AddSourceBuffer(const nsASt
     return nullptr;
   }
   nsRefPtr<SourceBuffer> sourceBuffer = new SourceBuffer(this, NS_ConvertUTF16toUTF8(mimeType));
   if (!sourceBuffer) {
     aRv.Throw(NS_ERROR_FAILURE); // XXX need a better error here
     return nullptr;
   }
   mSourceBuffers->Append(sourceBuffer);
-  mActiveSourceBuffers->Append(sourceBuffer);
   MSE_DEBUG("sourceBuffer=%p", sourceBuffer.get());
   return sourceBuffer.forget();
 }
 
 void
+MediaSource::SourceBufferIsActive(SourceBuffer* aSourceBuffer)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  mActiveSourceBuffers->ClearSimple();
+  bool found = false;
+  for (uint32_t i = 0; i < mSourceBuffers->Length(); i++) {
+    SourceBuffer* sourceBuffer = mSourceBuffers->IndexedGetter(i, found);
+    MOZ_ALWAYS_TRUE(found);
+    if (sourceBuffer == aSourceBuffer) {
+      mActiveSourceBuffers->Append(aSourceBuffer);
+    } else if (sourceBuffer->IsActive()) {
+      mActiveSourceBuffers->AppendSimple(sourceBuffer);
+    }
+  }
+}
+
+void
 MediaSource::RemoveSourceBuffer(SourceBuffer& aSourceBuffer, ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
   SourceBuffer* sourceBuffer = &aSourceBuffer;
   MSE_API("RemoveSourceBuffer(aSourceBuffer=%p)", sourceBuffer);
   if (!mSourceBuffers->Contains(sourceBuffer)) {
     aRv.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
     return;
--- a/dom/media/mediasource/MediaSource.h
+++ b/dom/media/mediasource/MediaSource.h
@@ -117,17 +117,17 @@ public:
   // Returns a string describing the state of the MediaSource internal
   // buffered data. Used for debugging purposes.
   void GetMozDebugReaderData(nsAString& aString);
 
 private:
   // MediaSourceDecoder uses DurationChange to set the duration
   // without hitting the checks in SetDuration.
   friend class mozilla::MediaSourceDecoder;
-  // SourceBuffer uses SetDuration
+  // SourceBuffer uses SetDuration and SourceBufferIsActive
   friend class mozilla::dom::SourceBuffer;
 
   ~MediaSource();
 
   explicit MediaSource(nsPIDOMWindow* aWindow);
 
   friend class AsyncEventRunner<MediaSource>;
   void DispatchSimpleEvent(const char* aName);
@@ -135,16 +135,19 @@ private:
 
   void DurationChange(double aOldDuration, double aNewDuration);
 
   void InitializationEvent();
 
   // SetDuration with no checks.
   void SetDuration(double aDuration, MSRangeRemovalAction aAction);
 
+  // Mark SourceBuffer as active and rebuild ActiveSourceBuffers.
+  void SourceBufferIsActive(SourceBuffer* aSourceBuffer);
+
   nsRefPtr<SourceBufferList> mSourceBuffers;
   nsRefPtr<SourceBufferList> mActiveSourceBuffers;
 
   nsRefPtr<MediaSourceDecoder> mDecoder;
   // Ensures the media element remains alive to dispatch progress and
   // durationchanged events.
   nsRefPtr<HTMLMediaElement> mMediaElement;
 
--- a/dom/media/mediasource/MediaSourceReader.cpp
+++ b/dom/media/mediasource/MediaSourceReader.cpp
@@ -115,17 +115,17 @@ MediaSourceReader::SizeOfAudioQueueInFra
 
 nsRefPtr<MediaDecoderReader::AudioDataPromise>
 MediaSourceReader::RequestAudioData()
 {
   MOZ_ASSERT(OnDecodeThread());
   MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty(), "No sample requests allowed while seeking");
   MOZ_DIAGNOSTIC_ASSERT(mAudioPromise.IsEmpty(), "No duplicate sample requests");
   nsRefPtr<AudioDataPromise> p = mAudioPromise.Ensure(__func__);
-  MSE_DEBUGV("");
+  MSE_DEBUGV("mLastAudioTime=%lld", mLastAudioTime);
   if (!mAudioTrack) {
     MSE_DEBUG("called with no audio track");
     mAudioPromise.Reject(DECODE_ERROR, __func__);
     return p;
   }
   if (IsSeeking()) {
     MSE_DEBUG("called mid-seek. Rejecting.");
     mAudioPromise.Reject(CANCELED, __func__);
@@ -231,50 +231,66 @@ AdjustEndTime(int64_t* aEndTime, SourceB
 
 void
 MediaSourceReader::OnAudioNotDecoded(NotDecodedReason aReason)
 {
   MOZ_DIAGNOSTIC_ASSERT(!IsSeeking());
   mAudioRequest.Complete();
 
   MSE_DEBUG("aReason=%u IsEnded: %d", aReason, IsEnded());
-  if (aReason == DECODE_ERROR || aReason == CANCELED) {
-    mAudioPromise.Reject(aReason, __func__);
+  if (aReason == CANCELED) {
+    mAudioPromise.Reject(CANCELED, __func__);
     return;
   }
 
-  // End of stream. Force switching past this stream to another reader by
+  // If End of stream. Force switching past this stream to another reader by
   // switching to the end of the buffered range.
-  MOZ_ASSERT(aReason == END_OF_STREAM);
-  if (mAudioSourceDecoder) {
+  int64_t lastAudioTime = mLastAudioTime;
+  if (aReason == END_OF_STREAM && mAudioSourceDecoder) {
     AdjustEndTime(&mLastAudioTime, mAudioSourceDecoder);
   }
 
+  SwitchSourceResult result = SwitchAudioSource(&mLastAudioTime);
   // See if we can find a different source that can pick up where we left off.
-  if (SwitchAudioSource(&mLastAudioTime) == SOURCE_NEW) {
+  if (result == SOURCE_NEW) {
     GetAudioReader()->ResetDecode();
     mAudioSeekRequest.Begin(GetAudioReader()->Seek(GetReaderAudioTime(mLastAudioTime), 0)
                             ->RefableThen(GetTaskQueue(), __func__, this,
                                           &MediaSourceReader::CompleteAudioSeekAndDoRequest,
                                           &MediaSourceReader::CompleteAudioSeekAndRejectPromise));
     return;
   }
 
+  // If we got a DECODE_ERROR and we have buffered data in the requested range
+  // then it must be a genuine decoding error.
+  // Otherwise we can assume that the data was either evicted or explicitely
+  // removed from the source buffer and we should wait for new data.
+  if (aReason == DECODE_ERROR && result != SOURCE_NONE) {
+    mAudioPromise.Reject(DECODE_ERROR, __func__);
+    return;
+  }
+
   CheckForWaitOrEndOfStream(MediaData::AUDIO_DATA, mLastAudioTime);
+
+  if (mLastAudioTime - lastAudioTime >= EOS_FUZZ_US) {
+    // No decoders are available to switch to. We will re-attempt from the last
+    // failing position.
+    mLastAudioTime = lastAudioTime;
+  }
 }
 
 nsRefPtr<MediaDecoderReader::VideoDataPromise>
 MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold)
 {
   MOZ_ASSERT(OnDecodeThread());
   MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty(), "No sample requests allowed while seeking");
   MOZ_DIAGNOSTIC_ASSERT(mVideoPromise.IsEmpty(), "No duplicate sample requests");
   nsRefPtr<VideoDataPromise> p = mVideoPromise.Ensure(__func__);
-  MSE_DEBUGV("RequestVideoData(%d, %lld)",
-             aSkipToNextKeyframe, aTimeThreshold);
+  MSE_DEBUGV("RequestVideoData(%d, %lld), mLastVideoTime=%lld",
+             aSkipToNextKeyframe, aTimeThreshold, mLastVideoTime);
   if (!mVideoTrack) {
     MSE_DEBUG("called with no video track");
     mVideoPromise.Reject(DECODE_ERROR, __func__);
     return p;
   }
   if (aSkipToNextKeyframe) {
     mTimeThreshold = aTimeThreshold;
     mDropAudioBeforeThreshold = true;
@@ -362,39 +378,56 @@ MediaSourceReader::OnVideoDecoded(VideoD
 
 void
 MediaSourceReader::OnVideoNotDecoded(NotDecodedReason aReason)
 {
   MOZ_DIAGNOSTIC_ASSERT(!IsSeeking());
   mVideoRequest.Complete();
 
   MSE_DEBUG("aReason=%u IsEnded: %d", aReason, IsEnded());
-  if (aReason == DECODE_ERROR || aReason == CANCELED) {
-    mVideoPromise.Reject(aReason, __func__);
+
+  if (aReason == CANCELED) {
+    mVideoPromise.Reject(CANCELED, __func__);
     return;
   }
 
-  // End of stream. Force switching past this stream to another reader by
+  // if End of stream. Force switching past this stream to another reader by
   // switching to the end of the buffered range.
-  MOZ_ASSERT(aReason == END_OF_STREAM);
-  if (mVideoSourceDecoder) {
+  int64_t lastVideoTime = mLastVideoTime;
+  if (aReason == END_OF_STREAM && mVideoSourceDecoder) {
     AdjustEndTime(&mLastVideoTime, mVideoSourceDecoder);
   }
 
   // See if we can find a different reader that can pick up where we left off.
-  if (SwitchVideoSource(&mLastVideoTime) == SOURCE_NEW) {
+  SwitchSourceResult result = SwitchVideoSource(&mLastVideoTime);
+  if (result == SOURCE_NEW) {
     GetVideoReader()->ResetDecode();
     mVideoSeekRequest.Begin(GetVideoReader()->Seek(GetReaderVideoTime(mLastVideoTime), 0)
                            ->RefableThen(GetTaskQueue(), __func__, this,
                                          &MediaSourceReader::CompleteVideoSeekAndDoRequest,
                                          &MediaSourceReader::CompleteVideoSeekAndRejectPromise));
     return;
   }
 
+  // If we got a DECODE_ERROR and we have buffered data in the requested range
+  // then it must be a genuine decoding error.
+  // Otherwise we can assume that the data was either evicted or explicitely
+  // removed from the source buffer and we should wait for new data.
+  if (aReason == DECODE_ERROR && result != SOURCE_NONE) {
+    mVideoPromise.Reject(DECODE_ERROR, __func__);
+    return;
+  }
+
   CheckForWaitOrEndOfStream(MediaData::VIDEO_DATA, mLastVideoTime);
+
+  if (mLastVideoTime - lastVideoTime >= EOS_FUZZ_US) {
+    // No decoders are available to switch to. We will re-attempt from the last
+    // failing position.
+    mLastVideoTime = lastVideoTime;
+  }
 }
 
 void
 MediaSourceReader::CheckForWaitOrEndOfStream(MediaData::Type aType, int64_t aTime)
 {
   // If the entire MediaSource is done, generate an EndOfStream.
   if (IsNearEnd(aType, aTime)) {
     if (aType == MediaData::AUDIO_DATA) {
--- a/dom/media/mediasource/SourceBuffer.cpp
+++ b/dom/media/mediasource/SourceBuffer.cpp
@@ -317,16 +317,17 @@ SourceBuffer::Ended()
 SourceBuffer::SourceBuffer(MediaSource* aMediaSource, const nsACString& aType)
   : DOMEventTargetHelper(aMediaSource->GetParentObject())
   , mMediaSource(aMediaSource)
   , mAppendWindowStart(0)
   , mAppendWindowEnd(PositiveInfinity<double>())
   , mTimestampOffset(0)
   , mAppendMode(SourceBufferAppendMode::Segments)
   , mUpdating(false)
+  , 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);
@@ -470,17 +471,21 @@ SourceBuffer::AppendDataCompletedWithSuc
 {
   mPendingAppend.Complete();
   if (!mUpdating) {
     // The buffer append algorithm has been interrupted by abort().
     return;
   }
 
   if (mTrackBuffer->HasInitSegment()) {
-    mMediaSource->QueueInitializationEvent();
+    if (!mActive) {
+      mActive = true;
+      mMediaSource->SourceBufferIsActive(this);
+      mMediaSource->QueueInitializationEvent();
+    }
   }
 
   if (aGotMedia) {
     CheckEndTime();
   }
 
   StopUpdating();
 }
--- a/dom/media/mediasource/SourceBuffer.h
+++ b/dom/media/mediasource/SourceBuffer.h
@@ -112,16 +112,21 @@ public:
   double GetBufferedStart();
   double GetBufferedEnd();
 
   // Runs the range removal algorithm as defined by the MSE spec.
   void RangeRemoval(double aStart, double aEnd);
   // Actually remove data between aStart and aEnd
   void DoRangeRemoval(double aStart, double aEnd);
 
+  bool IsActive() const
+  {
+    return mActive;
+  }
+
 #if defined(DEBUG)
   void Dump(const char* aPath);
 #endif
 
 private:
   ~SourceBuffer();
 
   friend class AsyncEventRunner<SourceBuffer>;
@@ -169,16 +174,18 @@ private:
   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;
 
   MediaPromiseConsumerHolder<TrackBufferAppendPromise> mPendingAppend;
   const nsCString mType;
 };
--- a/dom/media/mediasource/SourceBufferList.cpp
+++ b/dom/media/mediasource/SourceBufferList.cpp
@@ -57,16 +57,23 @@ void
 SourceBufferList::Append(SourceBuffer* aSourceBuffer)
 {
   MOZ_ASSERT(NS_IsMainThread());
   mSourceBuffers.AppendElement(aSourceBuffer);
   QueueAsyncSimpleEvent("addsourcebuffer");
 }
 
 void
+SourceBufferList::AppendSimple(SourceBuffer* aSourceBuffer)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  mSourceBuffers.AppendElement(aSourceBuffer);
+}
+
+void
 SourceBufferList::Remove(SourceBuffer* aSourceBuffer)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ALWAYS_TRUE(mSourceBuffers.RemoveElement(aSourceBuffer));
   aSourceBuffer->Detach();
   QueueAsyncSimpleEvent("removesourcebuffer");
 }
 
@@ -83,16 +90,23 @@ SourceBufferList::Clear()
   MOZ_ASSERT(NS_IsMainThread());
   for (uint32_t i = 0; i < mSourceBuffers.Length(); ++i) {
     mSourceBuffers[i]->Detach();
   }
   mSourceBuffers.Clear();
   QueueAsyncSimpleEvent("removesourcebuffer");
 }
 
+void
+SourceBufferList::ClearSimple()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  mSourceBuffers.Clear();
+}
+
 bool
 SourceBufferList::IsEmpty()
 {
   MOZ_ASSERT(NS_IsMainThread());
   return mSourceBuffers.IsEmpty();
 }
 
 bool
--- a/dom/media/mediasource/SourceBufferList.h
+++ b/dom/media/mediasource/SourceBufferList.h
@@ -73,16 +73,23 @@ public:
   void Ended();
 
   // Evicts data for the given time range from each SourceBuffer in the list.
   void Evict(double aStart, double aEnd);
 
   // Returns the highest end time of any of the Sourcebuffers.
   double GetHighestBufferedEndTime();
 
+  // Append a SourceBuffer to the list. No event is fired.
+  void AppendSimple(SourceBuffer* aSourceBuffer);
+
+  // Remove all SourceBuffers from mSourceBuffers.
+  //  No event is fired and no action is performed on the sourcebuffers.
+  void ClearSimple();
+
 #if defined(DEBUG)
   void Dump(const char* aPath);
 #endif
 
 private:
   ~SourceBufferList();
 
   friend class AsyncEventRunner<SourceBufferList>;
--- a/dom/media/mediasource/test/test_MediaSource.html
+++ b/dom/media/mediasource/test/test_MediaSource.html
@@ -42,17 +42,18 @@ runWithMSE(function () {
 
   ms.addEventListener("sourceopen", function () {
     ok(true, "Receive a sourceopen event");
     is(ms.readyState, "open", "MediaSource must be in open state after sourceopen");
     var sb = ms.addSourceBuffer("video/webm");
     ok(sb, "Create a SourceBuffer");
     is(ms.sourceBuffers.length, 1, "MediaSource.sourceBuffers is expected length");
     is(ms.sourceBuffers[0], sb, "SourceBuffer in list matches our SourceBuffer");
-    is(ms.activeSourceBuffers[0], sb, "SourceBuffer in active list matches our SourceBuffer");
+    is(ms.activeSourceBuffers.length, 0, "MediaSource.activeSourceBuffers is expected length");
+
 
     fetchWithXHR("seek.webm", function (arrayBuffer) {
       sb.appendBuffer(new Uint8Array(arrayBuffer));
       is(sb.updating, true, "SourceBuffer.updating is expected value after appendBuffer");
     });
 
     sb.addEventListener("update", function () {
       is(sb.updating, false, "SourceBuffer.updating is expected value in update event");
@@ -65,16 +66,17 @@ runWithMSE(function () {
       }
     });
 
     sb.addEventListener("updatestart", function () {
       updatestartCount++;
     });
 
     sb.addEventListener("updateend", function () {
+      is(ms.activeSourceBuffers[0], sb, "SourceBuffer in active list matches our SourceBuffer");
       is(sb.updating, false, "SourceBuffer.updating is expected value in updateend event");
       updateendCount++;
       v.play();
     });
   });
 
   ms.addEventListener("sourceended", function () {
     ok(true, "Receive a sourceended event");
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -575,18 +575,19 @@ NS_IMETHODIMP nsPluginInstanceOwner::Sho
   rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT,
                                 aStatusMsg);
 
   return rv;
 }
 
 NS_IMETHODIMP nsPluginInstanceOwner::GetDocument(nsIDocument* *aDocument)
 {
-  if (!aDocument)
+  if (!aDocument || !mContent) {
     return NS_ERROR_NULL_POINTER;
+  }
 
   // XXX sXBL/XBL2 issue: current doc or owner doc?
   // But keep in mind bug 322414 comment 33
   NS_IF_ADDREF(*aDocument = mContent->OwnerDoc());
   return NS_OK;
 }
 
 NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRect(NPRect *invalidRect)
--- a/dom/tests/mochitest/fetch/test_fetch_basic_http.js
+++ b/dom/tests/mochitest/fetch/test_fetch_basic_http.js
@@ -129,17 +129,72 @@ function testBlob() {
           }
         }
         is(i, 65536, "wrong value at offset " + i);
       });
     });
   });
 }
 
+// This test is a copy of dom/html/test/formData_test.js testSend() modified to
+// use the fetch API. Please change this if you change that.
+function testFormDataSend() {
+  var file, blob = new Blob(['hey'], {type: 'text/plain'});
+
+  var fd = new FormData();
+  fd.append("string", "hey");
+  fd.append("empty", blob);
+  fd.append("explicit", blob, "explicit-file-name");
+  fd.append("explicit-empty", blob, "");
+  file = new File([blob], 'testname',  {type: 'text/plain'});
+  fd.append("file-name", file);
+  file = new File([blob], '',  {type: 'text/plain'});
+  fd.append("empty-file-name", file);
+  file = new File([blob], 'testname',  {type: 'text/plain'});
+  fd.append("file-name-overwrite", file, "overwrite");
+
+  var req = new Request("/tests/dom/html/test/form_submit_server.sjs", {
+                          method: 'POST',
+                          body: fd,
+                        });
+
+  return fetch(req).then((r) => {
+    ok(r.status, 200, "status should match");
+    return r.json().then((response) => {
+      for (var entry of response) {
+        if (entry.headers['Content-Disposition'] != 'form-data; name="string"') {
+          is(entry.headers['Content-Type'], 'text/plain');
+        }
+
+        is(entry.body, 'hey');
+      }
+
+      is(response[1].headers['Content-Disposition'],
+          'form-data; name="empty"; filename="blob"');
+
+      is(response[2].headers['Content-Disposition'],
+          'form-data; name="explicit"; filename="explicit-file-name"');
+
+      is(response[3].headers['Content-Disposition'],
+          'form-data; name="explicit-empty"; filename=""');
+
+      is(response[4].headers['Content-Disposition'],
+          'form-data; name="file-name"; filename="testname"');
+
+      is(response[5].headers['Content-Disposition'],
+          'form-data; name="empty-file-name"; filename=""');
+
+      is(response[6].headers['Content-Disposition'],
+          'form-data; name="file-name-overwrite"; filename="overwrite"');
+    });
+  });
+}
+
 function runTest() {
   return Promise.resolve()
     .then(testURL)
     .then(testURLFail)
     .then(testRequestGET)
     .then(testResponses)
     .then(testBlob)
+    .then(testFormDataSend)
     // Put more promise based tests here.
 }
--- a/dom/tests/mochitest/fetch/test_fetch_cors.js
+++ b/dom/tests/mochitest/fetch/test_fetch_cors.js
@@ -41,19 +41,21 @@ function testNoCorsCtor() {
   r.headers.append("DNT", "value");
   ok(!r.headers.has("DNT"), "Appending forbidden header should fail");
 }
 
 var corsServerPath = "/tests/dom/base/test/file_CrossSiteXHR_server.sjs?";
 function testModeNoCors() {
   // Fetch spec, section 4, step 4, response tainting should be set opaque, so
   // that fetching leads to an opaque filtered response in step 8.
-  var r = new Request("http://example.com" + corsServerPath + "status=200&allowOrigin=*", { mode: "no-cors" });
+  var r = new Request("http://example.com" + corsServerPath + "status=200", { mode: "no-cors" });
   return fetch(r).then(function(res) {
     ok(isOpaqueResponse(res), "no-cors Request fetch should result in opaque response");
+  }, function(e) {
+    ok(false, "no-cors Request fetch should not error");
   });
 }
 
 function testSameOriginCredentials() {
   var cookieStr = "type=chocolatechip";
   var tests = [
               {
                 // Initialize by setting a cookie.
@@ -1014,33 +1016,33 @@ function testRedirects() {
                     },
                     ],
            },
            { pass: 0,
              method: "GET",
              hops: [{ server: "http://example.com",
                       allowOrigin: origin
                     },
-                    { server: "http://test2.mochi.test:8000",
+                    { server: "http://test2.mochi.test:8888",
                       allowOrigin: origin
                     },
                     { server: "http://sub2.xn--lt-uia.mochi.test:8888",
                       allowOrigin: origin
                     },
                     { server: "http://sub1.test1.mochi.test:8888",
                       allowOrigin: origin
                     },
                     ],
            },
            { pass: 0,
              method: "GET",
              hops: [{ server: "http://example.com",
                       allowOrigin: origin
                     },
-                    { server: "http://test2.mochi.test:8000",
+                    { server: "http://test2.mochi.test:8888",
                       allowOrigin: origin
                     },
                     { server: "http://sub2.xn--lt-uia.mochi.test:8888",
                       allowOrigin: "*"
                     },
                     { server: "http://sub1.test1.mochi.test:8888",
                       allowOrigin: "*"
                     },
@@ -1062,49 +1064,49 @@ function testRedirects() {
                     },
                     ],
            },
            { pass: 0,
              method: "GET",
              hops: [{ server: "http://example.com",
                       allowOrigin: origin
                     },
-                    { server: "http://test2.mochi.test:8000",
+                    { server: "http://test2.mochi.test:8888",
                       allowOrigin: origin
                     },
                     { server: "http://sub2.xn--lt-uia.mochi.test:8888",
                       allowOrigin: "x"
                     },
                     { server: "http://sub1.test1.mochi.test:8888",
                       allowOrigin: origin
                     },
                     ],
            },
            { pass: 0,
              method: "GET",
              hops: [{ server: "http://example.com",
                       allowOrigin: origin
                     },
-                    { server: "http://test2.mochi.test:8000",
+                    { server: "http://test2.mochi.test:8888",
                       allowOrigin: origin
                     },
                     { server: "http://sub2.xn--lt-uia.mochi.test:8888",
                       allowOrigin: "*"
                     },
                     { server: "http://sub1.test1.mochi.test:8888",
                       allowOrigin: origin
                     },
                     ],
            },
            { pass: 0,
              method: "GET",
              hops: [{ server: "http://example.com",
                       allowOrigin: origin
                     },
-                    { server: "http://test2.mochi.test:8000",
+                    { server: "http://test2.mochi.test:8888",
                       allowOrigin: origin
                     },
                     { server: "http://sub2.xn--lt-uia.mochi.test:8888",
                       allowOrigin: "*"
                     },
                     { server: "http://sub1.test1.mochi.test:8888",
                     },
                     ],
--- a/dom/webidl/Fetch.webidl
+++ b/dom/webidl/Fetch.webidl
@@ -3,19 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
  * http://fetch.spec.whatwg.org/
  */
 
 typedef object JSON;
-// FIXME(nsm): Bug 739173: FormData is not available in workers.
-// typedef (ArrayBuffer or ArrayBufferView or Blob or FormData or USVString or URLSearchParams) BodyInit;
-typedef (ArrayBuffer or ArrayBufferView or Blob or USVString or URLSearchParams) BodyInit;
+typedef (ArrayBuffer or ArrayBufferView or Blob or FormData or USVString or URLSearchParams) BodyInit;
 
 [NoInterfaceObject, Exposed=(Window,Worker)]
 interface Body {
   readonly attribute boolean bodyUsed;
   [Throws]
   Promise<ArrayBuffer> arrayBuffer();
   [Throws]
   Promise<Blob> blob();
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -1130,32 +1130,18 @@ CompositorParent::ShadowLayersUpdated(La
   if (aScheduleComposite) {
     ScheduleComposition();
     if (mPaused) {
       DidComposite();
     }
     // When testing we synchronously update the shadow tree with the animated
     // values to avoid race conditions when calling GetAnimationTransform etc.
     // (since the above SetShadowProperties will remove animation effects).
-    // However, we only do this update when a composite operation is already
-    // scheduled in order to better match the behavior under regular sampling
-    // conditions.
-    bool needTestComposite = mIsTesting && root &&
-                             (mCurrentCompositeTask ||
-                             (mCompositorVsyncObserver &&
-                              mCompositorVsyncObserver->NeedsComposite()));
-    if (needTestComposite) {
-      AutoResolveRefLayers resolve(mCompositionManager);
-      bool requestNextFrame =
-        mCompositionManager->TransformShadowTree(mTestTime);
-      if (!requestNextFrame) {
-        CancelCurrentCompositeTask();
-        // Pretend we composited in case someone is waiting for this event.
-        DidComposite();
-      }
+    if (mIsTesting) {
+      ApplyAsyncProperties(aLayerTree);
     }
   }
   mLayerManager->NotifyShadowTreeTransaction();
 }
 
 void
 CompositorParent::ForceComposite(LayerTransactionParent* aLayerTree)
 {
@@ -1192,16 +1178,41 @@ CompositorParent::SetTestSampleTime(Laye
 }
 
 void
 CompositorParent::LeaveTestMode(LayerTransactionParent* aLayerTree)
 {
   mIsTesting = false;
 }
 
+void
+CompositorParent::ApplyAsyncProperties(LayerTransactionParent* aLayerTree)
+{
+  // NOTE: This should only be used for testing. For example, when mIsTesting is
+  // true or when called from test-only methods like
+  // LayerTransactionParent::RecvGetAnimationTransform.
+
+  // Synchronously update the layer tree, but only if a composite was already
+  // scehduled.
+  if (aLayerTree->GetRoot() &&
+      (mCurrentCompositeTask ||
+       (mCompositorVsyncObserver &&
+        mCompositorVsyncObserver->NeedsComposite()))) {
+    AutoResolveRefLayers resolve(mCompositionManager);
+    TimeStamp time = mIsTesting ? mTestTime : mLastCompose;
+    bool requestNextFrame =
+      mCompositionManager->TransformShadowTree(time);
+    if (!requestNextFrame) {
+      CancelCurrentCompositeTask();
+      // Pretend we composited in case someone is waiting for this event.
+      DidComposite();
+    }
+  }
+}
+
 bool
 CompositorParent::RecvRequestOverfill()
 {
   uint32_t overfillRatio = mCompositor->GetFillRatio();
   unused << SendOverfill(overfillRatio);
   return true;
 }
 
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -189,16 +189,18 @@ public:
                                    bool aIsFirstPaint,
                                    bool aScheduleComposite,
                                    uint32_t aPaintSequenceNumber,
                                    bool aIsRepeatTransaction) MOZ_OVERRIDE;
   virtual void ForceComposite(LayerTransactionParent* aLayerTree) MOZ_OVERRIDE;
   virtual bool SetTestSampleTime(LayerTransactionParent* aLayerTree,
                                  const TimeStamp& aTime) MOZ_OVERRIDE;
   virtual void LeaveTestMode(LayerTransactionParent* aLayerTree) MOZ_OVERRIDE;
+  virtual void ApplyAsyncProperties(LayerTransactionParent* aLayerTree)
+               MOZ_OVERRIDE;
   virtual void GetAPZTestData(const LayerTransactionParent* aLayerTree,
                               APZTestData* aOutData) MOZ_OVERRIDE;
   virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aLayerTree) MOZ_OVERRIDE { return mCompositionManager; }
 
   /**
    * This forces the is-first-paint flag to true. This is intended to
    * be called by the widget code when it loses its viewport information
    * (or for whatever reason wants to refresh the viewport information).
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -677,16 +677,22 @@ LayerTransactionParent::RecvGetAnimation
     return false;
   }
 
   Layer* layer = cast(aParent)->AsLayer();
   if (!layer) {
     return false;
   }
 
+  // Make sure we apply the latest animation style or else we can end up with
+  // a race between when we temporarily clear the animation transform (in
+  // CompositorParent::SetShadowProperties) and when animation recalculates
+  // the value.
+  mShadowLayersManager->ApplyAsyncProperties(this);
+
   // This method is specific to transforms applied by animation.
   // This is because this method uses the information stored with an animation
   // such as the origin of the reference frame corresponding to the layer, to
   // recover the untranslated transform from the shadow transform. For
   // transforms that are not set by animation we don't have this information
   // available.
   if (!layer->AsLayerComposite()->GetShadowTransformSetByAnimation()) {
     *aTransform = mozilla::void_t();
--- a/gfx/layers/ipc/ShadowLayersManager.h
+++ b/gfx/layers/ipc/ShadowLayersManager.h
@@ -30,16 +30,17 @@ public:
     virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aLayerTree) { return nullptr; }
 
     virtual void NotifyClearCachedResources(LayerTransactionParent* aLayerTree) { }
 
     virtual void ForceComposite(LayerTransactionParent* aLayerTree) { }
     virtual bool SetTestSampleTime(LayerTransactionParent* aLayerTree,
                                    const TimeStamp& aTime) { return true; }
     virtual void LeaveTestMode(LayerTransactionParent* aLayerTree) { }
+    virtual void ApplyAsyncProperties(LayerTransactionParent* aLayerTree) { }
     virtual void GetAPZTestData(const LayerTransactionParent* aLayerTree,
                                 APZTestData* aOutData) { }
 };
 
 } // layers
 } // mozilla
 
 #endif // mozilla_layers_ShadowLayersManager_h
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -227,17 +227,17 @@ private:
   DECL_GFX_PREF(Once, "gfx.touch.resample.vsync-adjust",       TouchVsyncSampleAdjust, int32_t, 5);
   DECL_GFX_PREF(Once, "gfx.touch.resample.delay-threshold",    TouchResampleVsyncDelayThreshold, int32_t, 20);
   DECL_GFX_PREF(Once, "gfx.touch.resample.old-touch-threshold",TouchResampleOldTouchThreshold, int32_t, 17);
 
   DECL_GFX_PREF(Live, "gl.msaa-level",                         MSAALevel, uint32_t, 2);
 
   DECL_GFX_PREF(Once, "image.cache.timeweight",                ImageCacheTimeWeight, int32_t, 500);
   DECL_GFX_PREF(Once, "image.cache.size",                      ImageCacheSize, int32_t, 5*1024*1024);
-  DECL_GFX_PREF(Live, "image.downscale-during-decode.enabled", ImageDownscaleDuringDecodeEnabled, bool, false);
+  DECL_GFX_PREF(Live, "image.downscale-during-decode.enabled", ImageDownscaleDuringDecodeEnabled, bool, true);
   DECL_GFX_PREF(Live, "image.high_quality_downscaling.enabled", ImageHQDownscalingEnabled, bool, false);
   DECL_GFX_PREF(Live, "image.high_quality_downscaling.min_factor", ImageHQDownscalingMinFactor, uint32_t, 1000);
   DECL_GFX_PREF(Live, "image.high_quality_upscaling.max_size", ImageHQUpscalingMaxSize, uint32_t, 20971520);
   DECL_GFX_PREF(Once, "image.mem.decode_bytes_at_a_time",      ImageMemDecodeBytesAtATime, uint32_t, 200000);
   DECL_GFX_PREF(Live, "image.mem.decodeondraw",                ImageMemDecodeOnDraw, bool, true);
   DECL_GFX_PREF(Live, "image.mem.discardable",                 ImageMemDiscardable, bool, false);
   DECL_GFX_PREF(Once, "image.mem.surfacecache.discard_factor", ImageMemSurfaceCacheDiscardFactor, uint32_t, 1);
   DECL_GFX_PREF(Once, "image.mem.surfacecache.max_size_kb",    ImageMemSurfaceCacheMaxSizeKB, uint32_t, 100 * 1024);
--- a/image/public/imgIContainer.idl
+++ b/image/public/imgIContainer.idl
@@ -93,17 +93,17 @@ native DrawResult(mozilla::image::DrawRe
 [ref] native gfxRect(gfxRect);
 [ref] native gfxSize(gfxSize);
 native gfxGraphicsFilter(GraphicsFilter);
 [ref] native nsIntRect(nsIntRect);
 native nsIntRectByVal(nsIntRect);
 [ref] native nsIntSize(nsIntSize);
 native nsSize(nsSize);
 [ptr] native nsIFrame(nsIFrame);
-[ptr] native ImageContainer(mozilla::layers::ImageContainer);
+native TempRefImageContainer(already_AddRefed<mozilla::layers::ImageContainer>);
 [ref] native ImageRegion(mozilla::image::ImageRegion);
 [ptr] native LayerManager(mozilla::layers::LayerManager);
 native Orientation(mozilla::image::Orientation);
 [ref] native TimeStamp(mozilla::TimeStamp);
 [ref] native MaybeSVGImageContext(mozilla::Maybe<mozilla::SVGImageContext>);
 native TempRefSourceSurface(mozilla::TemporaryRef<mozilla::gfx::SourceSurface>);
 native TempRefImgIContainer(already_AddRefed<imgIContainer>);
 native nsIntSizeByVal(nsIntSize);
@@ -111,17 +111,17 @@ native nsIntSizeByVal(nsIntSize);
 
 /**
  * imgIContainer is the interface that represents an image. It allows
  * access to frames as Thebes surfaces. It also allows drawing of images
  * onto Thebes contexts.
  *
  * Internally, imgIContainer also manages animation of images.
  */
-[scriptable, builtinclass, uuid(9a43298b-bf49-44fc-9abe-9ff702f1bd25)]
+[scriptable, builtinclass, uuid(44fbd7d5-e417-4d31-ae4a-8ad61d07eb3c)]
 interface imgIContainer : nsISupports
 {
   /**
    * The width of the container rectangle.  In the case of any error,
    * zero is returned, and an exception will be thrown.
    */
   readonly attribute int32_t width;
 
@@ -272,18 +272,27 @@ interface imgIContainer : nsISupports
   /**
    * Whether this image is opaque (i.e., needs a background painted behind it).
    */
   [notxpcom] boolean isOpaque();
 
   /**
    * Attempts to create an ImageContainer (and Image) containing the current
    * frame. Only valid for RASTER type images.
+   *
+   * @param aManager The LayerManager which will be used to create the
+   *                 ImageContainer.
+   * @param aFlags Decoding / drawing flags (in other words, FLAG_* flags).
+   *               Currently only FLAG_SYNC_DECODE and FLAG_SYNC_DECODE_IF_FAST
+   *               are supported.
+   * @return An ImageContainer for the current frame, or nullptr if one could
+   *         not be created.
    */
-  [noscript] ImageContainer getImageContainer(in LayerManager aManager);
+  [noscript, notxpcom] TempRefImageContainer getImageContainer(in LayerManager aManager,
+                                                               in uint32_t aFlags);
 
   /**
    * Draw the requested frame of this image onto the context specified.
    *
    * Drawing an image involves scaling it to a certain size (which may be
    * implemented as a "smart" scale by substituting an HQ-scaled frame or
    * rendering at a high DPI), and then selecting a region of that image to
    * draw. That region is drawn onto the graphics context and in the process
--- a/image/src/ClippedImage.cpp
+++ b/image/src/ClippedImage.cpp
@@ -261,31 +261,30 @@ ClippedImage::GetFrameInternal(const nsI
                                                    aSVGContext, frameToDraw,
                                                    aFlags);
   }
 
   MOZ_ASSERT(mCachedSurface, "Should have a cached surface now");
   return mCachedSurface->Surface();
 }
 
-NS_IMETHODIMP
-ClippedImage::GetImageContainer(LayerManager* aManager, ImageContainer** _retval)
+NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
+ClippedImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
 {
   // XXX(seth): We currently don't have a way of clipping the result of
   // GetImageContainer. We work around this by always returning null, but if it
   // ever turns out that ClippedImage is widely used on codepaths that can
   // actually benefit from GetImageContainer, it would be a good idea to fix
   // that method for performance reasons.
 
   if (!ShouldClip()) {
-    return InnerImage()->GetImageContainer(aManager, _retval);
+    return InnerImage()->GetImageContainer(aManager, aFlags);
   }
 
-  *_retval = nullptr;
-  return NS_OK;
+  return nullptr;
 }
 
 static bool
 MustCreateSurface(gfxContext* aContext,
                   const nsIntSize& aSize,
                   const ImageRegion& aRegion,
                   const uint32_t aFlags)
 {
--- a/image/src/ClippedImage.h
+++ b/image/src/ClippedImage.h
@@ -32,18 +32,19 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_IMETHOD GetWidth(int32_t* aWidth) MOZ_OVERRIDE;
   NS_IMETHOD GetHeight(int32_t* aHeight) MOZ_OVERRIDE;
   NS_IMETHOD GetIntrinsicSize(nsSize* aSize) MOZ_OVERRIDE;
   NS_IMETHOD GetIntrinsicRatio(nsSize* aRatio) MOZ_OVERRIDE;
   NS_IMETHOD_(TemporaryRef<SourceSurface>)
     GetFrame(uint32_t aWhichFrame, uint32_t aFlags) MOZ_OVERRIDE;
-  NS_IMETHOD GetImageContainer(layers::LayerManager* aManager,
-                               layers::ImageContainer** _retval) MOZ_OVERRIDE;
+  NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)
+    GetImageContainer(layers::LayerManager* aManager,
+                      uint32_t aFlags) MOZ_OVERRIDE;
   NS_IMETHOD_(DrawResult) Draw(gfxContext* aContext,
                                const nsIntSize& aSize,
                                const ImageRegion& aRegion,
                                uint32_t aWhichFrame,
                                GraphicsFilter aFilter,
                                const Maybe<SVGImageContext>& aSVGContext,
                                uint32_t aFlags) MOZ_OVERRIDE;
   NS_IMETHOD RequestDiscard() MOZ_OVERRIDE;
--- a/image/src/DynamicImage.cpp
+++ b/image/src/DynamicImage.cpp
@@ -200,22 +200,20 @@ DynamicImage::GetFrame(uint32_t aWhichFr
 NS_IMETHODIMP_(bool)
 DynamicImage::IsOpaque()
 {
   // XXX(seth): For performance reasons it'd be better to return true here, but
   // I'm not sure how we can guarantee it for an arbitrary gfxDrawable.
   return false;
 }
 
-NS_IMETHODIMP
-DynamicImage::GetImageContainer(LayerManager* aManager,
-                                ImageContainer** _retval)
+NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
+DynamicImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
 {
-  *_retval = nullptr;
-  return NS_OK;
+  return nullptr;
 }
 
 NS_IMETHODIMP_(DrawResult)
 DynamicImage::Draw(gfxContext* aContext,
                    const nsIntSize& aSize,
                    const ImageRegion& aRegion,
                    uint32_t aWhichFrame,
                    GraphicsFilter aFilter,
--- a/image/src/FrozenImage.cpp
+++ b/image/src/FrozenImage.cpp
@@ -39,28 +39,25 @@ FrozenImage::GetAnimated(bool* aAnimated
 
 NS_IMETHODIMP_(TemporaryRef<SourceSurface>)
 FrozenImage::GetFrame(uint32_t aWhichFrame,
                       uint32_t aFlags)
 {
   return InnerImage()->GetFrame(FRAME_FIRST, aFlags);
 }
 
-NS_IMETHODIMP
-FrozenImage::GetImageContainer(layers::LayerManager* aManager,
-                               layers::ImageContainer** _retval)
+NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
+FrozenImage::GetImageContainer(layers::LayerManager* aManager, uint32_t aFlags)
 {
   // XXX(seth): GetImageContainer does not currently support anything but the
   // current frame. We work around this by always returning null, but if it ever
   // turns out that FrozenImage is widely used on codepaths that can actually
   // benefit from GetImageContainer, it would be a good idea to fix that method
   // for performance reasons.
-
-  *_retval = nullptr;
-  return NS_OK;
+  return nullptr;
 }
 
 NS_IMETHODIMP_(DrawResult)
 FrozenImage::Draw(gfxContext* aContext,
                   const nsIntSize& aSize,
                   const ImageRegion& aRegion,
                   uint32_t /* aWhichFrame - ignored */,
                   GraphicsFilter aFilter,
--- a/image/src/FrozenImage.h
+++ b/image/src/FrozenImage.h
@@ -32,18 +32,19 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual void IncrementAnimationConsumers() MOZ_OVERRIDE;
   virtual void DecrementAnimationConsumers() MOZ_OVERRIDE;
 
   NS_IMETHOD GetAnimated(bool* aAnimated) MOZ_OVERRIDE;
   NS_IMETHOD_(TemporaryRef<SourceSurface>)
     GetFrame(uint32_t aWhichFrame, uint32_t aFlags) MOZ_OVERRIDE;
-  NS_IMETHOD GetImageContainer(layers::LayerManager* aManager,
-                               layers::ImageContainer** _retval) MOZ_OVERRIDE;
+  NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)
+    GetImageContainer(layers::LayerManager* aManager,
+                      uint32_t aFlags) MOZ_OVERRIDE;
   NS_IMETHOD_(DrawResult) Draw(gfxContext* aContext,
                                const nsIntSize& aSize,
                                const ImageRegion& aRegion,
                                uint32_t aWhichFrame,
                                GraphicsFilter aFilter,
                                const Maybe<SVGImageContext>& aSVGContext,
                                uint32_t aFlags) MOZ_OVERRIDE;
   NS_IMETHOD_(void) RequestRefresh(const TimeStamp& aTime) MOZ_OVERRIDE;
--- a/image/src/ImageWrapper.cpp
+++ b/image/src/ImageWrapper.cpp
@@ -187,21 +187,20 @@ ImageWrapper::GetFrame(uint32_t aWhichFr
 }
 
 NS_IMETHODIMP_(bool)
 ImageWrapper::IsOpaque()
 {
   return mInnerImage->IsOpaque();
 }
 
-NS_IMETHODIMP
-ImageWrapper::GetImageContainer(LayerManager* aManager,
-                                ImageContainer** _retval)
+NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
+ImageWrapper::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
 {
-  return mInnerImage->GetImageContainer(aManager, _retval);
+  return mInnerImage->GetImageContainer(aManager, aFlags);
 }
 
 NS_IMETHODIMP_(DrawResult)
 ImageWrapper::Draw(gfxContext* aContext,
                    const nsIntSize& aSize,
                    const ImageRegion& aRegion,
                    uint32_t aWhichFrame,
                    GraphicsFilter aFilter,
--- a/image/src/OrientedImage.cpp
+++ b/image/src/OrientedImage.cpp
@@ -117,32 +117,30 @@ OrientedImage::GetFrame(uint32_t aWhichF
   ctx->Multiply(OrientationMatrix(size));
   gfxUtils::DrawPixelSnapped(ctx, drawable, size,
                              ImageRegion::Create(size),
                              surfaceFormat, GraphicsFilter::FILTER_FAST);
 
   return target->Snapshot();
 }
 
-NS_IMETHODIMP
-OrientedImage::GetImageContainer(LayerManager* aManager,
-                                 ImageContainer** _retval)
+NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
+OrientedImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
 {
   // XXX(seth): We currently don't have a way of orienting the result of
   // GetImageContainer. We work around this by always returning null, but if it
   // ever turns out that OrientedImage is widely used on codepaths that can
   // actually benefit from GetImageContainer, it would be a good idea to fix
   // that method for performance reasons.
 
   if (mOrientation.IsIdentity()) {
-    return InnerImage()->GetImageContainer(aManager, _retval);
+    return InnerImage()->GetImageContainer(aManager, aFlags);
   }
 
-  *_retval = nullptr;
-  return NS_OK;
+  return nullptr;
 }
 
 struct MatrixBuilder
 {
   explicit MatrixBuilder(bool aInvert) : mInvert(aInvert) { }
 
   gfxMatrix Build() { return mMatrix; }
 
--- a/image/src/OrientedImage.h
+++ b/image/src/OrientedImage.h
@@ -29,18 +29,19 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_IMETHOD GetWidth(int32_t* aWidth) MOZ_OVERRIDE;
   NS_IMETHOD GetHeight(int32_t* aHeight) MOZ_OVERRIDE;
   NS_IMETHOD GetIntrinsicSize(nsSize* aSize) MOZ_OVERRIDE;
   NS_IMETHOD GetIntrinsicRatio(nsSize* aRatio) MOZ_OVERRIDE;
   NS_IMETHOD_(TemporaryRef<SourceSurface>)
     GetFrame(uint32_t aWhichFrame, uint32_t aFlags) MOZ_OVERRIDE;
-  NS_IMETHOD GetImageContainer(layers::LayerManager* aManager,
-                               layers::ImageContainer** _retval) MOZ_OVERRIDE;
+  NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)
+    GetImageContainer(layers::LayerManager* aManager,
+                      uint32_t aFlags) MOZ_OVERRIDE;
   NS_IMETHOD_(DrawResult) Draw(gfxContext* aContext,
                                const nsIntSize& aSize,
                                const ImageRegion& aRegion,
                                uint32_t aWhichFrame,
                                GraphicsFilter aFilter,
                                const Maybe<SVGImageContext>& aSVGContext,
                                uint32_t aFlags) MOZ_OVERRIDE;
   NS_IMETHOD_(nsIntRect) GetImageSpaceInvalidationRect(
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -251,16 +251,17 @@ NS_IMPL_ISUPPORTS(RasterImage, imgIConta
 //******************************************************************************
 RasterImage::RasterImage(ProgressTracker* aProgressTracker,
                          ImageURL* aURI /* = nullptr */) :
   ImageResource(aURI), // invoke superclass's constructor
   mSize(0,0),
   mLockCount(0),
   mDecodeCount(0),
   mRequestedSampleSize(0),
+  mLastImageContainerDrawResult(DrawResult::NOT_READY),
 #ifdef DEBUG
   mFramesNotified(0),
 #endif
   mSourceBuffer(new SourceBuffer()),
   mFrameCount(0),
   mHasSize(false),
   mDecodeOnDraw(false),
   mTransient(false),
@@ -320,16 +321,17 @@ RasterImage::Init(const char* aMimeType,
 
 #ifndef MOZ_ENABLE_SKIA
   // Downscale-during-decode requires Skia.
   mDownscaleDuringDecode = false;
 #endif
 
   // Lock this image's surfaces in the SurfaceCache if we're not discardable.
   if (!mDiscardable) {
+    mLockCount++;
     SurfaceCache::LockImage(ImageKey(this));
   }
 
   // Create the initial size decoder.
   nsresult rv = Decode(Nothing(), DECODE_FLAGS_DEFAULT);
   if (NS_FAILED(rv)) {
     return NS_ERROR_FAILURE;
   }
@@ -722,38 +724,40 @@ RasterImage::CopyFrame(uint32_t aWhichFr
 
 //******************************************************************************
 /* [noscript] SourceSurface getFrame(in uint32_t aWhichFrame,
  *                                   in uint32_t aFlags); */
 NS_IMETHODIMP_(TemporaryRef<SourceSurface>)
 RasterImage::GetFrame(uint32_t aWhichFrame,
                       uint32_t aFlags)
 {
-  return GetFrameInternal(aWhichFrame, aFlags);
+  return GetFrameInternal(aWhichFrame, aFlags).second().forget();
 }
 
-TemporaryRef<SourceSurface>
+Pair<DrawResult, RefPtr<SourceSurface>>
 RasterImage::GetFrameInternal(uint32_t aWhichFrame, uint32_t aFlags)
 {
   MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE);
 
-  if (aWhichFrame > FRAME_MAX_VALUE)
-    return nullptr;
+  if (aWhichFrame > FRAME_MAX_VALUE) {
+    return MakePair(DrawResult::BAD_ARGS, RefPtr<SourceSurface>());
+  }
 
-  if (mError)
-    return nullptr;
+  if (mError) {
+    return MakePair(DrawResult::BAD_IMAGE, RefPtr<SourceSurface>());
+  }
 
   // Get the frame. If it's not there, it's probably the caller's fault for
   // not waiting for the data to be loaded from the network or not passing
   // FLAG_SYNC_DECODE
   DrawableFrameRef frameRef =
     LookupFrame(GetRequestedFrameIndex(aWhichFrame), mSize, aFlags);
   if (!frameRef) {
     // The OS threw this frame away and we couldn't redecode it.
-    return nullptr;
+    return MakePair(DrawResult::TEMPORARY_ERROR, RefPtr<SourceSurface>());
   }
 
   // If this frame covers the entire image, we can just reuse its existing
   // surface.
   RefPtr<SourceSurface> frameSurf;
   nsIntRect frameRect = frameRef->GetRect();
   if (frameRect.x == 0 && frameRect.y == 0 &&
       frameRect.width == mSize.width &&
@@ -762,107 +766,122 @@ RasterImage::GetFrameInternal(uint32_t a
   }
 
   // The image doesn't have a usable surface because it's been optimized away or
   // because it's a partial update frame from an animation. Create one.
   if (!frameSurf) {
     frameSurf = CopyFrame(aWhichFrame, aFlags);
   }
 
-  return frameSurf;
+  if (!frameRef->IsImageComplete()) {
+    return MakePair(DrawResult::INCOMPLETE, Move(frameSurf));
+  }
+
+  return MakePair(DrawResult::SUCCESS, Move(frameSurf));
 }
 
-already_AddRefed<layers::Image>
-RasterImage::GetCurrentImage(ImageContainer* aContainer)
+Pair<DrawResult, nsRefPtr<layers::Image>>
+RasterImage::GetCurrentImage(ImageContainer* aContainer, uint32_t aFlags)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aContainer);
 
-  RefPtr<SourceSurface> surface =
-    GetFrameInternal(FRAME_CURRENT, FLAG_ASYNC_NOTIFY);
-  if (!surface) {
+  auto result = GetFrameInternal(FRAME_CURRENT, aFlags | FLAG_ASYNC_NOTIFY);
+  if (!result.second()) {
     // The OS threw out some or all of our buffer. We'll need to wait for the
     // redecode (which was automatically triggered by GetFrame) to complete.
-    return nullptr;
+    return MakePair(result.first(), nsRefPtr<layers::Image>());
   }
 
   CairoImage::Data cairoData;
   GetWidth(&cairoData.mSize.width);
   GetHeight(&cairoData.mSize.height);
-  cairoData.mSourceSurface = surface;
+  cairoData.mSourceSurface = result.second();
 
   nsRefPtr<layers::Image> image =
     aContainer->CreateImage(ImageFormat::CAIRO_SURFACE);
-  NS_ASSERTION(image, "Failed to create Image");
+  MOZ_ASSERT(image);
 
   static_cast<CairoImage*>(image.get())->SetData(cairoData);
 
-  return image.forget();
+  return MakePair(result.first(), Move(image));
 }
 
 
-NS_IMETHODIMP
-RasterImage::GetImageContainer(LayerManager* aManager, ImageContainer **_retval)
+NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
+RasterImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aManager);
+  MOZ_ASSERT((aFlags & ~(FLAG_SYNC_DECODE |
+                         FLAG_SYNC_DECODE_IF_FAST |
+                         FLAG_ASYNC_NOTIFY))
+               == FLAG_NONE,
+             "Unsupported flag passed to GetImageContainer");
 
   int32_t maxTextureSize = aManager->GetMaxTextureSize();
   if (!mHasSize ||
       mSize.width > maxTextureSize ||
       mSize.height > maxTextureSize) {
-    *_retval = nullptr;
-    return NS_OK;
+    return nullptr;
   }
 
   if (IsUnlocked() && mProgressTracker) {
     mProgressTracker->OnUnlockedDraw();
   }
 
   nsRefPtr<layers::ImageContainer> container = mImageContainer.get();
-  if (container) {
-    container.forget(_retval);
-    return NS_OK;
+
+  bool mustRedecode =
+    (aFlags & (FLAG_SYNC_DECODE | FLAG_SYNC_DECODE_IF_FAST)) &&
+    mLastImageContainerDrawResult != DrawResult::SUCCESS &&
+    mLastImageContainerDrawResult != DrawResult::BAD_IMAGE;
+
+  if (container && !mustRedecode) {
+    return container.forget();
   }
 
   // We need a new ImageContainer, so create one.
   container = LayerManager::CreateImageContainer();
 
-  nsRefPtr<layers::Image> image = GetCurrentImage(container);
-  if (!image) {
-    return NS_ERROR_NOT_AVAILABLE;
+  auto result = GetCurrentImage(container, aFlags);
+  if (!result.second()) {
+    // We couldn't get an Image.
+    return nullptr;
   }
 
-  // |image| holds a reference to a SourceSurface which in turn holds a lock on
-  // the current frame's VolatileBuffer, ensuring that it doesn't get freed as
-  // long as the layer system keeps this ImageContainer alive.
-  container->SetCurrentImageInTransaction(image);
+  // |result.second()| holds a reference to a SourceSurface which in turn holds
+  // a lock on the current frame's VolatileBuffer, ensuring that it doesn't get
+  // freed as long as the layer system keeps this ImageContainer alive.
+  container->SetCurrentImageInTransaction(result.second());
 
+  mLastImageContainerDrawResult = result.first();
   mImageContainer = container;
-  container.forget(_retval);
 
-  return NS_OK;
+  return container.forget();
 }
 
 void
 RasterImage::UpdateImageContainer()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsRefPtr<layers::ImageContainer> container = mImageContainer.get();
   if (!container) {
     return;
   }
 
-  nsRefPtr<layers::Image> image = GetCurrentImage(container);
-  if (!image) {
+  auto result = GetCurrentImage(container, FLAG_NONE);
+  if (!result.second()) {
+    // We couldn't get an Image.
     return;
   }
 
-  container->SetCurrentImage(image);
+  mLastImageContainerDrawResult = result.first();
+  container->SetCurrentImage(result.second());
 }
 
 size_t
 RasterImage::SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const
 {
   return mSourceBuffer->SizeOfIncludingThisWithComputedFallback(aMallocSizeOf);
 }
 
@@ -1483,33 +1502,33 @@ RasterImage::Decode(const Maybe<nsIntSiz
   }
 
   // If we don't have a size yet, we can't do any other decoding.
   if (!mHasSize && aSize) {
     mWantFullDecode = true;
     return NS_OK;
   }
 
-  // Create a decoder.
-  nsRefPtr<Decoder> decoder = CreateDecoder(aSize, aFlags);
-  if (!decoder) {
-    return NS_ERROR_FAILURE;
-  }
-
   if (mDownscaleDuringDecode && aSize) {
     // We're about to decode again, which may mean that some of the previous
     // sizes we've decoded at aren't useful anymore. We can allow them to
     // expire from the cache by unlocking them here. When the decode finishes,
     // it will send an invalidation that will cause all instances of this image
     // to redraw. If this image is locked, any surfaces that are still useful
     // will become locked again when LookupFrame touches them, and the remainder
     // will eventually expire.
     SurfaceCache::UnlockSurfaces(ImageKey(this));
   }
 
+  // Create a decoder.
+  nsRefPtr<Decoder> decoder = CreateDecoder(aSize, aFlags);
+  if (!decoder) {
+    return NS_ERROR_FAILURE;
+  }
+
   if (aSize) {
     // This isn't a size decode (which doesn't send any early notifications), so
     // send out notifications right away.
     NotifyProgress(decoder->TakeProgress(),
                    decoder->TakeInvalidRect(),
                    decoder->GetDecodeFlags());
   }
 
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -25,16 +25,17 @@
 #include "imgFrame.h"
 #include "nsThreadUtils.h"
 #include "DecodePool.h"
 #include "Orientation.h"
 #include "nsIObserver.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/Pair.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/WeakPtr.h"
 #include "mozilla/UniquePtr.h"
 #ifdef DEBUG
   #include "imgIContainerDebug.h"
 #endif
 
 class nsIInputStream;
@@ -292,35 +293,37 @@ private:
                                           gfxContext* aContext,
                                           const nsIntSize& aSize,
                                           const ImageRegion& aRegion,
                                           GraphicsFilter aFilter,
                                           uint32_t aFlags);
 
   TemporaryRef<gfx::SourceSurface> CopyFrame(uint32_t aWhichFrame,
                                              uint32_t aFlags);
-  TemporaryRef<gfx::SourceSurface> GetFrameInternal(uint32_t aWhichFrame,
-                                                    uint32_t aFlags);
+
+  Pair<DrawResult, RefPtr<gfx::SourceSurface>>
+    GetFrameInternal(uint32_t aWhichFrame, uint32_t aFlags);
 
   DrawableFrameRef LookupFrameInternal(uint32_t aFrameNum,
                                        const gfx::IntSize& aSize,
                                        uint32_t aFlags);
   DrawableFrameRef LookupFrame(uint32_t aFrameNum,
                                const nsIntSize& aSize,
                                uint32_t aFlags);
   uint32_t GetCurrentFrameIndex() const;
   uint32_t GetRequestedFrameIndex(uint32_t aWhichFrame) const;
 
   nsIntRect GetFirstFrameRect();
 
   size_t SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation,
                                                  MallocSizeOf aMallocSizeOf) const;
 
-  already_AddRefed<layers::Image>
-    GetCurrentImage(layers::ImageContainer* aContainer);
+  Pair<DrawResult, nsRefPtr<layers::Image>>
+    GetCurrentImage(layers::ImageContainer* aContainer, uint32_t aFlags);
+
   void UpdateImageContainer();
 
   // We would like to just check if we have a zero lock count, but we can't do
   // that for animated images because in EnsureAnimExists we lock the image and
   // never unlock so that animated images always have their lock count >= 1. In
   // that case we use our animation consumers count as a proxy for lock count.
   bool IsUnlocked() { return (mLockCount == 0 || (mAnim && mAnimationConsumers == 0)); }
 
@@ -376,16 +379,20 @@ private: // data
 
   // A hint for image decoder that directly scale the image to smaller buffer
   int                        mRequestedSampleSize;
 
   // A weak pointer to our ImageContainer, which stays alive only as long as
   // the layer system needs it.
   WeakPtr<layers::ImageContainer> mImageContainer;
 
+  // If mImageContainer is non-null, this contains the DrawResult we obtained
+  // the last time we updated it.
+  DrawResult mLastImageContainerDrawResult;
+
 #ifdef DEBUG
   uint32_t                       mFramesNotified;
 #endif
 
   // The source data for this image.
   nsRefPtr<SourceBuffer>     mSourceBuffer;
 
   // The number of frames this image has.
--- a/image/src/VectorImage.cpp
+++ b/image/src/VectorImage.cpp
@@ -692,22 +692,20 @@ VectorImage::GetFrame(uint32_t aWhichFra
                      aWhichFrame, GraphicsFilter::FILTER_NEAREST,
                      Nothing(), aFlags);
 
   return result == DrawResult::SUCCESS ? dt->Snapshot() : nullptr;
 }
 
 //******************************************************************************
 /* [noscript] ImageContainer getImageContainer(); */
-NS_IMETHODIMP
-VectorImage::GetImageContainer(LayerManager* aManager,
-                               layers::ImageContainer** _retval)
+NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
+VectorImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
 {
-  *_retval = nullptr;
-  return NS_OK;
+  return nullptr;
 }
 
 struct SVGDrawingParameters
 {
   SVGDrawingParameters(gfxContext* aContext,
                        const nsIntSize& aSize,
                        const ImageRegion& aRegion,
                        GraphicsFilter aFilter,
--- a/image/test/crashtests/crashtests.list
+++ b/image/test/crashtests/crashtests.list
@@ -41,9 +41,9 @@ load truncated-second-frame.png # bug 86
 # This icon's size is such that it leads to multiple writes to the PNG decoder
 # after we've gotten our size.
 load multiple-png-hassize.ico
 
 # Bug 856615
 # Asserts in the debug build
 load 856616.gif
 
-skip-if(AddressSanitizer) load 944353.jpg
+skip-if(AddressSanitizer) skip-if(B2G) load 944353.jpg
--- a/ipc/glue/MessageChannel.cpp
+++ b/ipc/glue/MessageChannel.cpp
@@ -702,16 +702,43 @@ MessageChannel::OnMessageReceivedFromLin
         if (!compress) {
             // If we compressed away the previous message, we'll re-use
             // its pending task.
             mWorkerLoop->PostTask(FROM_HERE, new DequeueTask(mDequeueOneTask));
         }
     }
 }
 
+void
+MessageChannel::ProcessPendingRequests()
+{
+    // Loop until there aren't any more priority messages to process.
+    for (;;) {
+        mozilla::Vector<Message> toProcess;
+
+        for (MessageQueue::iterator it = mPending.begin(); it != mPending.end(); ) {
+            Message &msg = *it;
+            if (!ShouldDeferMessage(msg)) {
+                toProcess.append(Move(msg));
+                it = mPending.erase(it);
+                continue;
+            }
+            it++;
+        }
+
+        if (toProcess.empty())
+            break;
+
+        // Processing these messages could result in more messages, so we
+        // loop around to check for more afterwards.
+        for (auto it = toProcess.begin(); it != toProcess.end(); it++)
+            ProcessPendingRequest(*it);
+    }
+}
+
 bool
 MessageChannel::Send(Message* aMsg, Message* aReply)
 {
     // See comment in DispatchSyncMessage.
     MaybeScriptBlocker scriptBlocker(this, true);
 
     // Sanity checks.
     AssertWorkerThread();
@@ -761,41 +788,22 @@ MessageChannel::Send(Message* aMsg, Mess
 
     AutoSetValue<bool> replies(mAwaitingSyncReply, true);
     AutoSetValue<int> prio(mAwaitingSyncReplyPriority, msg->priority());
     AutoEnterTransaction transact(this, seqno);
 
     int32_t transaction = mCurrentTransaction;
     msg->set_transaction_id(transaction);
 
+    ProcessPendingRequests();
+
     mLink->SendMessage(msg.forget());
 
     while (true) {
-        // Loop until there aren't any more priority messages to process.
-        for (;;) {
-            mozilla::Vector<Message> toProcess;
-
-            for (MessageQueue::iterator it = mPending.begin(); it != mPending.end(); ) {
-                Message &msg = *it;
-                if (!ShouldDeferMessage(msg)) {
-                    toProcess.append(Move(msg));
-                    it = mPending.erase(it);
-                    continue;
-                }
-                it++;
-            }
-
-            if (toProcess.empty())
-                break;
-
-            // Processing these messages could result in more messages, so we
-            // loop around to check for more afterwards.
-            for (auto it = toProcess.begin(); it != toProcess.end(); it++)
-                ProcessPendingRequest(*it);
-        }
+        ProcessPendingRequests();
 
         // See if we've received a reply.
         if (mRecvdErrors) {
             mRecvdErrors--;
             return false;
         }
 
         if (mRecvd) {
--- a/ipc/glue/MessageChannel.h
+++ b/ipc/glue/MessageChannel.h
@@ -222,16 +222,17 @@ class MessageChannel : HasResultCodes
     void Clear();
 
     // Send OnChannelConnected notification to listeners.
     void DispatchOnChannelConnected();
 
     bool InterruptEventOccurred();
     bool HasPendingEvents();
 
+    void ProcessPendingRequests();
     bool ProcessPendingRequest(const Message &aUrgent);
 
     void MaybeUndeferIncall();
     void EnqueuePendingMessages();
 
     // Executed on the worker thread. Dequeues one pending message.
     bool OnMaybeDequeueOne();
     bool DequeueOne(Message *recvd);
--- a/ipc/ipdl/test/cxx/PTestRPC.ipdl
+++ b/ipc/ipdl/test/cxx/PTestRPC.ipdl
@@ -2,25 +2,23 @@ namespace mozilla {
 namespace _ipdltest {
 
 prio(normal upto high) sync protocol PTestRPC
 {
 parent:
     prio(high) sync Test1_Start() returns (uint32_t result);
     prio(high) sync Test1_InnerEvent() returns (uint32_t result);
     async Test2_Start();
-    prio(high) sync Test2_Msg2();
-    prio(high) sync Test2_FirstUrgent();
-    prio(high) sync Test2_SecondUrgent();
+    prio(high) sync Test2_OutOfOrder();
     sync Test3_Start() returns (uint32_t result);
     prio(high) sync Test3_InnerEvent() returns (uint32_t result);
 
 child:
     async Start();
     prio(high) sync Test1_InnerQuery() returns (uint32_t result);
     prio(high) sync Test1_NoReenter() returns (uint32_t result);
-    prio(high) sync Test2_Msg1();
-    prio(high) sync Test2_Msg3();
+    prio(high) sync Test2_FirstUrgent();
+    prio(high) sync Test2_SecondUrgent();
     prio(high) sync Test3_WakeUp() returns (uint32_t result);
 };
 
 } // namespace _ipdltest
 } // namespace mozilla
--- a/ipc/ipdl/test/cxx/TestHangs.cpp
+++ b/ipc/ipdl/test/cxx/TestHangs.cpp
@@ -79,16 +79,18 @@ TestHangsParent::ShouldContinueFromReply
 
     PR_Sleep(5000);
 
     // reply should be here; we'll post a task to shut things down.
     // This must be after OnMaybeDequeueOne() in the event queue.
     MessageLoop::current()->PostTask(
         FROM_HERE, NewRunnableMethod(this, &TestHangsParent::CleanUp));
 
+    GetIPCChannel()->CloseWithTimeout();
+
     return false;
 }
 
 bool
 TestHangsParent::AnswerStackFrame()
 {
     if (PTestHangs::HANG != state()) {
         if (CallStackFrame())
--- a/ipc/ipdl/test/cxx/TestRPC.cpp
+++ b/ipc/ipdl/test/cxx/TestRPC.cpp
@@ -9,16 +9,18 @@
 
 namespace mozilla {
 namespace _ipdltest {
 
 //-----------------------------------------------------------------------------
 // parent
 
 TestRPCParent::TestRPCParent()
+ : reentered_(false),
+   resolved_first_cpow_(false)
 {
   MOZ_COUNT_CTOR(TestRPCParent);
 }
 
 TestRPCParent::~TestRPCParent()
 {
   MOZ_COUNT_DTOR(TestRPCParent);
 }
@@ -54,40 +56,35 @@ TestRPCParent::RecvTest1_InnerEvent(uint
 
   *aResult = 200;
   return true;
 }
 
 bool
 TestRPCParent::RecvTest2_Start()
 {
-  if (!SendTest2_Msg1())
-    fail("SendTest2_Msg1");
+  // Send a CPOW. During this time, we must NOT process the RPC message, as
+  // we could start receiving CPOW replies out-of-order.
+  if (!SendTest2_FirstUrgent())
+    fail("SendTest2_FirstUrgent");
 
+  MOZ_ASSERT(!reentered_);
+  resolved_first_cpow_ = true;
   return true;
 }
 
 bool
-TestRPCParent::RecvTest2_Msg2()
+TestRPCParent::RecvTest2_OutOfOrder()
 {
-  if (!SendTest2_Msg3())
-    fail("SendTest2_Msg3");
-
-  return true;
-}
+  // Send a CPOW. If this RPC call was initiated while waiting for the first
+  // CPOW to resolve, replies will be processed out of order, and we'll crash.
+  if (!SendTest2_SecondUrgent())
+    fail("SendTest2_SecondUrgent");
 
-bool
-TestRPCParent::RecvTest2_FirstUrgent()
-{
-  return true;
-}
-
-bool
-TestRPCParent::RecvTest2_SecondUrgent()
-{
+  reentered_ = true;
   return true;
 }
 
 bool
 TestRPCParent::RecvTest3_Start(uint32_t* aResult)
 {
   if (!SendTest3_WakeUp(aResult))
     fail("SendTest3_WakeUp");
@@ -102,18 +99,16 @@ TestRPCParent::RecvTest3_InnerEvent(uint
   return true;
 }
 
 //-----------------------------------------------------------------------------
 // child
 
 
 TestRPCChild::TestRPCChild()
- : reentered_(false),
-   resolved_first_cpow_(false)
 {
     MOZ_COUNT_CTOR(TestRPCChild);
 }
 
 TestRPCChild::~TestRPCChild()
 {
     MOZ_COUNT_DTOR(TestRPCChild);
 }
@@ -125,18 +120,18 @@ TestRPCChild::RecvStart()
   if (!SendTest1_Start(&result))
     fail("SendTest1_Start");
   if (result != 100)
     fail("Wrong result (expected 100)");
 
   if (!SendTest2_Start())
     fail("SendTest2_Start");
 
-  if (!SendTest2_Msg2())
-    fail("SendTest2_Msg2");
+  if (!SendTest2_OutOfOrder())
+    fail("SendTest2_OutOfOrder");
 
   result = 0;
   if (!SendTest3_Start(&result))
     fail("SendTest3_Start");
   if (result != 200)
     fail("Wrong result (expected 200)");
 
   Close();
@@ -158,39 +153,25 @@ TestRPCChild::RecvTest1_InnerQuery(uint3
 
 bool
 TestRPCChild::RecvTest1_NoReenter(uint32_t* aResult)
 {
   *aResult = 400;
   return true;
 }
 
-bool TestRPCChild::RecvTest2_Msg1()
+bool
+TestRPCChild::RecvTest2_FirstUrgent()
 {
-  MOZ_ASSERT(resolved_first_cpow_);
-
-  // Send a CPOW. If this RPC call was initiated while waiting for the first
-  // CPOW to resolve, replies will be processed out of order, and we'll crash.
-  if (!SendTest2_SecondUrgent())
-    fail("SendTest2_SecondUrgent");
-
-  reentered_ = true;
   return true;
 }
 
 bool
-TestRPCChild::RecvTest2_Msg3()
+TestRPCChild::RecvTest2_SecondUrgent()
 {
-  // Send a CPOW. During this time, we must NOT process the RPC message, as
-  // we could start receiving CPOW replies out-of-order.
-  if (!SendTest2_FirstUrgent())
-    fail("SendTest2_FirstUrgent");
-
-  MOZ_ASSERT(!reentered_);
-  resolved_first_cpow_ = true;
   return true;
 }
 
 bool
 TestRPCChild::RecvTest3_WakeUp(uint32_t* aResult)
 {
   if (!SendTest3_InnerEvent(aResult))
     fail("SendTest3_InnerEvent");
--- a/ipc/ipdl/test/cxx/TestRPC.h
+++ b/ipc/ipdl/test/cxx/TestRPC.h
@@ -20,56 +20,58 @@ public:
     static bool RunTestInProcesses() { return true; }
     static bool RunTestInThreads() { return false; }
 
     void Main();
 
     bool RecvTest1_Start(uint32_t* aResult) MOZ_OVERRIDE;
     bool RecvTest1_InnerEvent(uint32_t* aResult) MOZ_OVERRIDE;
     bool RecvTest2_Start() MOZ_OVERRIDE;
-    bool RecvTest2_Msg2() MOZ_OVERRIDE;
-    bool RecvTest2_FirstUrgent() MOZ_OVERRIDE;
-    bool RecvTest2_SecondUrgent() MOZ_OVERRIDE;
+    bool RecvTest2_OutOfOrder() MOZ_OVERRIDE;
     bool RecvTest3_Start(uint32_t* aResult) MOZ_OVERRIDE;
     bool RecvTest3_InnerEvent(uint32_t* aResult) MOZ_OVERRIDE;
 
     virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE
     {
         if (NormalShutdown != why)
             fail("unexpected destruction!");  
+        if (!reentered_)
+            fail("never processed raced RPC call!");
+        if (!resolved_first_cpow_)
+            fail("never resolved first CPOW!");
         passed("ok");
         QuitParent();
     }
+
+private:
+    bool reentered_;
+    bool resolved_first_cpow_;
 };
 
 
 class TestRPCChild :
     public PTestRPCChild
 {
 public:
     TestRPCChild();
     virtual ~TestRPCChild();
 
     bool RecvStart() MOZ_OVERRIDE;
     bool RecvTest1_InnerQuery(uint32_t* aResult) MOZ_OVERRIDE;
     bool RecvTest1_NoReenter(uint32_t* aResult) MOZ_OVERRIDE;
-    bool RecvTest2_Msg1() MOZ_OVERRIDE;
-    bool RecvTest2_Msg3() MOZ_OVERRIDE;
+    bool RecvTest2_FirstUrgent() MOZ_OVERRIDE;
+    bool RecvTest2_SecondUrgent() MOZ_OVERRIDE;
     bool RecvTest3_WakeUp(uint32_t* aResult) MOZ_OVERRIDE;
 
     virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE
     {
         if (NormalShutdown != why)
             fail("unexpected destruction!");
         QuitChild();
     }
-
-private:
-    bool reentered_;
-    bool resolved_first_cpow_;
 };
 
 
 } // namespace _ipdltest
 } // namespace mozilla
 
 
 #endif // ifndef mozilla__ipdltest_TestRPC_h
--- a/ipc/ipdl/test/cxx/TestUrgentHangs.cpp
+++ b/ipc/ipdl/test/cxx/TestUrgentHangs.cpp
@@ -133,19 +133,19 @@ TestUrgentHangsChild::RecvTest3()
     return true;
 }
 
 bool
 TestUrgentHangsChild::RecvTest4()
 {
     PR_Sleep(PR_SecondsToInterval(2));
 
-    // This should fail because Test4_1 timed out and hasn't gotten a response
-    // yet.
-    if (SendTestInner())
+    // This won't fail because we should handle Test4_1 here before actually
+    // sending TestInner to the parent.
+    if (!SendTestInner())
         fail("sending TestInner");
 
     return true;
 }
 
 bool
 TestUrgentHangsChild::RecvTest4_1()
 {
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -4119,16 +4119,107 @@ MLoadElement::foldsTo(TempAllocator &all
         return this;
 
     if (store->index() != index())
         return this;
 
     return foldsToStoredValue(alloc, store->value());
 }
 
+// Gets the MDefinition* representing the source/target object's storage.
+// Usually this is just an MElements*, but sometimes there are layers
+// of indirection or inlining, which are handled elsewhere.
+static inline const MElements *
+MaybeUnwrapElements(const MDefinition *elementsOrObj)
+{
+    // Sometimes there is a level of indirection for conversion.
+    if (elementsOrObj->isConvertElementsToDoubles())
+        return MaybeUnwrapElements(elementsOrObj->toConvertElementsToDoubles()->elements());
+
+    // For inline elements, the object may be passed directly, for example as MUnbox.
+    if (elementsOrObj->type() == MIRType_Object)
+        return nullptr;
+
+    return elementsOrObj->toElements();
+}
+
+// Gets the MDefinition of the target Object for the given store operation.
+static inline const MDefinition *
+GetStoreObject(const MDefinition *store)
+{
+    switch (store->op()) {
+      case MDefinition::Op_StoreElement: {
+        const MDefinition *elementsOrObj = store->toStoreElement()->elements();
+        const MDefinition *elements = MaybeUnwrapElements(elementsOrObj);
+        if (elements)
+            return elements->toElements()->input();
+
+        MOZ_ASSERT(elementsOrObj->type() == MIRType_Object);
+        return elementsOrObj;
+      }
+
+      case MDefinition::Op_StoreElementHole:
+        return store->toStoreElementHole()->object();
+
+      default:
+        return nullptr;
+    }
+}
+
+// Implements mightAlias() logic common to all load operations.
+static bool
+GenericLoadMightAlias(const MDefinition *elementsOrObj, const MDefinition *store)
+{
+    const MElements *elements = MaybeUnwrapElements(elementsOrObj);
+    if (elements)
+        return elements->mightAlias(store);
+
+    // If MElements couldn't be extracted, then storage must be inline.
+    // Refer to IsValidElementsType().
+    const MDefinition *object = elementsOrObj;
+    MOZ_ASSERT(object->type() == MIRType_Object);
+    if (!object->resultTypeSet())
+        return true;
+
+    const MDefinition *storeObject = GetStoreObject(store);
+    if (!storeObject)
+        return true;
+    if (!storeObject->resultTypeSet())
+        return true;
+
+    return object->resultTypeSet()->objectsIntersect(storeObject->resultTypeSet());
+}
+
+bool
+MElements::mightAlias(const MDefinition *store) const
+{
+    if (!input()->resultTypeSet())
+        return true;
+
+    const MDefinition *storeObj = GetStoreObject(store);
+    if (!storeObj)
+        return true;
+    if (!storeObj->resultTypeSet())
+        return true;
+
+    return input()->resultTypeSet()->objectsIntersect(storeObj->resultTypeSet());
+}
+
+bool
+MLoadElement::mightAlias(const MDefinition *store) const
+{
+    return GenericLoadMightAlias(elements(), store);
+}
+
+bool
+MInitializedLength::mightAlias(const MDefinition *store) const
+{
+    return GenericLoadMightAlias(elements(), store);
+}
+
 bool
 MGuardReceiverPolymorphic::congruentTo(const MDefinition *ins) const
 {
     if (!ins->isGuardReceiverPolymorphic())
         return false;
 
     const MGuardReceiverPolymorphic *other = ins->toGuardReceiverPolymorphic();
 
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -7489,16 +7489,17 @@ class MElements
         return getOperand(0);
     }
     bool congruentTo(const MDefinition *ins) const MOZ_OVERRIDE {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const MOZ_OVERRIDE {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
+    bool mightAlias(const MDefinition *store) const;
 
     ALLOW_CLONE(MElements)
 };
 
 // A constant value for some object's array elements or typed array elements.
 class MConstantElements : public MNullaryInstruction
 {
     void *value_;
@@ -7676,16 +7677,17 @@ class MInitializedLength
         return getOperand(0);
     }
     bool congruentTo(const MDefinition *ins) const MOZ_OVERRIDE {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const MOZ_OVERRIDE {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
+    bool mightAlias(const MDefinition *store) const;
 
     void computeRange(TempAllocator &alloc) MOZ_OVERRIDE;
 
     ALLOW_CLONE(MInitializedLength)
 };
 
 // Store to the initialized length in an elements header. Note the input is an
 // *index*, one less than the desired length.
@@ -8179,16 +8181,17 @@ class MLoadElement
         if (offsetAdjustment() != other->offsetAdjustment())
             return false;
         return congruentIfOperandsEqual(other);
     }
     MDefinition *foldsTo(TempAllocator &alloc) MOZ_OVERRIDE;
     AliasSet getAliasSet() const MOZ_OVERRIDE {
         return AliasSet::Load(AliasSet::Element);
     }
+    bool mightAlias(const MDefinition *store) const;
 
     ALLOW_CLONE(MLoadElement)
 };
 
 // Load a value from a dense array's element vector. If the index is
 // out-of-bounds, or the indexed slot has a hole, undefined is returned
 // instead.
 class MLoadElementHole
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -414,16 +414,33 @@ TypeSet::isSubset(const TypeSet *other) 
             if (!other->hasType(ObjectType(key)))
                 return false;
         }
     }
 
     return true;
 }
 
+bool
+TypeSet::objectsIntersect(const TypeSet *other) const
+{
+    if (unknownObject() || other->unknownObject())
+        return true;
+
+    for (unsigned i = 0; i < getObjectCount(); i++) {
+        ObjectKey *key = getObject(i);
+        if (!key)
+            continue;
+        if (other->hasType(ObjectType(key)))
+            return true;
+    }
+
+    return false;
+}
+
 template <class TypeListT>
 bool
 TypeSet::enumerateTypes(TypeListT *list) const
 {
     /* If any type is possible, there's no need to worry about specifics. */
     if (flags & TYPE_FLAG_UNKNOWN)
         return list->append(UnknownType());
 
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -487,16 +487,18 @@ class TypeSet
      */
     bool objectsAreSubset(TypeSet *other);
 
     /* Whether this TypeSet contains exactly the same types as other. */
     bool equals(const TypeSet *other) const {
         return this->isSubset(other) && other->isSubset(this);
     }
 
+    bool objectsIntersect(const TypeSet *other) const;
+
     /* Forward all types in this set to the specified constraint. */
     bool addTypesToConstraint(JSContext *cx, TypeConstraint *constraint);
 
     // Clone a type set into an arbitrary allocator.
     TemporaryTypeSet *clone(LifoAlloc *alloc) const;
     bool clone(LifoAlloc *alloc, TemporaryTypeSet *result) const;
 
     // Create a new TemporaryTypeSet where undefined and/or null has been filtered out.
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -3931,16 +3931,17 @@ ContainerState::Finish(uint32_t* aTextCo
     } else {
       // Build layers for all mNewChildLayers[i].mScrollInfoItems and insert
       // them after layer.
       for (nsDisplayScrollInfoLayer* item : mNewChildLayers[i].mScrollInfoItems) {
         LayerState layerState = item->GetLayerState(mBuilder, mManager, mParameters);
         MOZ_ASSERT(layerState == LAYER_ACTIVE_EMPTY);
         nsRefPtr<Layer> scrollInfoLayer = item->BuildLayer(mBuilder, mManager, mParameters);
         if (!scrollInfoLayer) {
+          item->~nsDisplayScrollInfoLayer();
           continue;
         }
 
         mLayerBuilder->AddLayerDisplayItem(scrollInfoLayer, item, layerState,
                                            nsPoint(), nullptr);
 
         const nsIFrame* animatedGeometryRoot =
           nsLayoutUtils::GetAnimatedGeometryRootFor(item, mBuilder, mManager);
@@ -3967,17 +3968,19 @@ ContainerState::Finish(uint32_t* aTextCo
           NS_ASSERTION(scrollInfoLayer->GetParent() == mContainerLayer,
                        "scrollInfoLayer shouldn't be the child of some other container");
           if (scrollInfoLayer->GetPrevSibling() != layer) {
             mContainerLayer->RepositionChild(scrollInfoLayer, layer);
           }
         }
 
         layer = scrollInfoLayer;
+        item->~nsDisplayScrollInfoLayer();
       }
+      mNewChildLayers[i].mScrollInfoItems.Clear();
     }
   }
 
   // Remove old layers that have become unused.
   if (!layer) {
     layer = mContainerLayer->GetFirstChild();
   } else {
     layer = layer->GetNextSibling();
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -5190,23 +5190,21 @@ nsImageRenderer::IsAnimatedImage()
     return true;
 
   return false;
 }
 
 already_AddRefed<mozilla::layers::ImageContainer>
 nsImageRenderer::GetContainer(LayerManager* aManager)
 {
-  if (mType != eStyleImageType_Image || !mImageContainer)
+  if (mType != eStyleImageType_Image || !mImageContainer) {
     return nullptr;
-
-  nsRefPtr<ImageContainer> container;
-  nsresult rv = mImageContainer->GetImageContainer(aManager, getter_AddRefs(container));
-  NS_ENSURE_SUCCESS(rv, nullptr);
-  return container.forget();
+  }
+
+  return mImageContainer->GetImageContainer(aManager, imgIContainer::FLAG_NONE);
 }
 
 #define MAX_BLUR_RADIUS 300
 #define MAX_SPREAD_RADIUS 50
 
 static inline gfxPoint ComputeBlurStdDev(nscoord aBlurRadius,
                                          int32_t aAppUnitsPerDevPixel,
                                          gfxFloat aScaleX,
--- a/layout/base/nsDisplayListInvalidation.h
+++ b/layout/base/nsDisplayListInvalidation.h
@@ -128,17 +128,18 @@ public:
       // We previously invalidated for sync decoding and haven't gotten painted
       // since them. This suggests that our display item is completely occluded
       // and there's no point in invalidating again - and because the reftest
       // harness takes a new snapshot every time we invalidate, doing so might
       // lead to an invalidation loop if we're in a reftest.
       return false;
     }
 
-    if (mLastDrawResult == mozilla::image::DrawResult::SUCCESS) {
+    if (mLastDrawResult == mozilla::image::DrawResult::SUCCESS ||
+        mLastDrawResult == mozilla::image::DrawResult::BAD_IMAGE) {
       return false;
     }
 
     return true;
   }
 
 private:
   mozilla::image::DrawResult mLastDrawResult;
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -1166,45 +1166,75 @@ struct nsRecessedBorder : public nsStyle
   }
 };
 
 class nsDisplayAltFeedback : public nsDisplayItem {
 public:
   nsDisplayAltFeedback(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
     : nsDisplayItem(aBuilder, aFrame) {}
 
+  virtual nsDisplayItemGeometry*
+  AllocateGeometry(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE
+  {
+    return new nsDisplayItemGenericImageGeometry(this, aBuilder);
+  }
+
+  virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
+                                         const nsDisplayItemGeometry* aGeometry,
+                                         nsRegion* aInvalidRegion) MOZ_OVERRIDE
+  {
+    auto geometry =
+      static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
+
+    if (aBuilder->ShouldSyncDecodeImages() &&
+        geometry->ShouldInvalidateToSyncDecodeImages()) {
+      bool snap;
+      aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
+    }
+
+    nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
+  }
+
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
                            bool* aSnap) MOZ_OVERRIDE
   {
     *aSnap = false;
     return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
   }
 
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) MOZ_OVERRIDE
   {
+    // Always sync decode, because these icons are UI, and since they're not
+    // discardable we'll pay the price of sync decoding at most once.
+    uint32_t flags = imgIContainer::FLAG_SYNC_DECODE;
+
     nsImageFrame* f = static_cast<nsImageFrame*>(mFrame);
     EventStates state = f->GetContent()->AsElement()->State();
-    f->DisplayAltFeedback(*aCtx,
-                          mVisibleRect,
-                          IMAGE_OK(state, true)
-                             ? nsImageFrame::gIconLoad->mLoadingImage
-                             : nsImageFrame::gIconLoad->mBrokenImage,
-                          ToReferenceFrame());
+    DrawResult result =
+      f->DisplayAltFeedback(*aCtx,
+                            mVisibleRect,
+                            IMAGE_OK(state, true)
+                               ? nsImageFrame::gIconLoad->mLoadingImage
+                               : nsImageFrame::gIconLoad->mBrokenImage,
+                            ToReferenceFrame(),
+                            flags);
 
+    nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
   }
 
   NS_DISPLAY_DECL_NAME("AltFeedback", TYPE_ALT_FEEDBACK)
 };
 
-void
+DrawResult
 nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext,
-                                 const nsRect&        aDirtyRect,
-                                 imgIRequest*         aRequest,
-                                 nsPoint              aPt)
+                                 const nsRect& aDirtyRect,
+                                 imgIRequest* aRequest,
+                                 nsPoint aPt,
+                                 uint32_t aFlags)
 {
   // We should definitely have a gIconLoad here.
   MOZ_ASSERT(gIconLoad, "How did we succeed in Init then?");
 
   // Calculate the inner area
   nsRect  inner = GetInnerArea() + aPt;
 
   // Display a recessed one pixel border
@@ -1214,78 +1244,78 @@ nsImageFrame::DisplayAltFeedback(nsRende
   if (inner.IsEmpty()){
     inner.SizeTo(2*(nsPresContext::CSSPixelsToAppUnits(ICON_SIZE+ICON_PADDING+ALT_BORDER_WIDTH)),
                  2*(nsPresContext::CSSPixelsToAppUnits(ICON_SIZE+ICON_PADDING+ALT_BORDER_WIDTH)));
   }
 
   // Make sure we have enough room to actually render the border within
   // our frame bounds
   if ((inner.width < 2 * borderEdgeWidth) || (inner.height < 2 * borderEdgeWidth)) {
-    return;
+    return DrawResult::SUCCESS;
   }
 
   // Paint the border
   nsRecessedBorder recessedBorder(borderEdgeWidth, PresContext());
   nsCSSRendering::PaintBorderWithStyleBorder(PresContext(), aRenderingContext,
                                              this, inner, inner,
                                              recessedBorder, mStyleContext);
 
   // Adjust the inner rect to account for the one pixel recessed border,
   // and a six pixel padding on each edge
   inner.Deflate(nsPresContext::CSSPixelsToAppUnits(ICON_PADDING+ALT_BORDER_WIDTH), 
                 nsPresContext::CSSPixelsToAppUnits(ICON_PADDING+ALT_BORDER_WIDTH));
   if (inner.IsEmpty()) {
-    return;
+    return DrawResult::SUCCESS;
   }
 
   DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
   gfxContext* gfx = aRenderingContext.ThebesContext();
 
   // Clip so we don't render outside the inner rect
   gfx->Save();
   gfx->Clip(NSRectToSnappedRect(inner, PresContext()->AppUnitsPerDevPixel(),
                                 *drawTarget));
 
+  DrawResult result = DrawResult::NOT_READY;
+
   // Check if we should display image placeholders
-  if (gIconLoad->mPrefShowPlaceholders) {
+  if (!gIconLoad->mPrefShowPlaceholders) {
+    result = DrawResult::SUCCESS;
+  } else {
     nscoord size = nsPresContext::CSSPixelsToAppUnits(ICON_SIZE);
 
-    bool iconUsed = false;
-
     // If we weren't previously displaying an icon, register ourselves
     // as an observer for load and animation updates and flag that we're
     // doing so now.
     if (aRequest && !mDisplayingIcon) {
       gIconLoad->AddIconObserver(this);
       mDisplayingIcon = true;
     }
 
     WritingMode wm = GetWritingMode();
     bool flushRight =
       (!wm.IsVertical() && !wm.IsBidiLTR()) || wm.IsVerticalRL();
 
-    // If the icon in question is loaded and decoded, draw it
+    // If the icon in question is loaded, draw it.
     uint32_t imageStatus = 0;
     if (aRequest)
       aRequest->GetImageStatus(&imageStatus);
     if (imageStatus & imgIRequest::STATUS_LOAD_COMPLETE) {
       nsCOMPtr<imgIContainer> imgCon;
       aRequest->GetImage(getter_AddRefs(imgCon));
       MOZ_ASSERT(imgCon, "Load complete, but no image container?");
       nsRect dest(flushRight ? inner.XMost() - size : inner.x,
                   inner.y, size, size);
-      nsLayoutUtils::DrawSingleImage(*gfx, PresContext(), imgCon,
+      result = nsLayoutUtils::DrawSingleImage(*gfx, PresContext(), imgCon,
         nsLayoutUtils::GetGraphicsFilterForFrame(this), dest, aDirtyRect,
-        nullptr, imgIContainer::FLAG_SYNC_DECODE);
-      iconUsed = true;
+        nullptr, aFlags);
     }
 
-    // if we could not draw the icon, flag that we're waiting for it and
-    // just draw some graffiti in the mean time
-    if (!iconUsed) {
+    // If we could not draw the icon, just draw some graffiti in the mean time.
+    if (result == DrawResult::NOT_READY) {
       ColorPattern color(ToDeviceColor(Color(1.f, 0.f, 0.f, 1.f)));
 
       nscoord iconXPos = flushRight ? inner.XMost() - size : inner.x;
 
       // stroked rect:
       nsRect rect(iconXPos, inner.y, size, size);
       Rect devPxRect =
         ToRect(nsLayoutUtils::RectToGfxRect(rect, PresContext()->AppUnitsPerDevPixel()));
@@ -1326,16 +1356,18 @@ nsImageFrame::DisplayAltFeedback(nsRende
       nsCSSFrameConstructor::GetAlternateTextFor(content,
                                                  content->NodeInfo()->NameAtom(),
                                                  altText);
       DisplayAltText(PresContext(), aRenderingContext, altText, inner);
     }
   }
 
   aRenderingContext.ThebesContext()->Restore();
+
+  return result;
 }
 
 #ifdef DEBUG
 static void PaintDebugImageMap(nsIFrame* aFrame, nsRenderingContext* aCtx,
                                const nsRect& aDirtyRect, nsPoint aPt)
 {
   nsImageFrame* f = static_cast<nsImageFrame*>(aFrame);
   nsRect inner = f->GetInnerArea() + aPt;
@@ -1390,19 +1422,21 @@ nsDisplayImage::ComputeInvalidationRegio
 
   nsDisplayImageContainer::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
 }
 
 already_AddRefed<ImageContainer>
 nsDisplayImage::GetContainer(LayerManager* aManager,
                              nsDisplayListBuilder* aBuilder)
 {
-  nsRefPtr<ImageContainer> container;
-  mImage->GetImageContainer(aManager, getter_AddRefs(container));
-  return container.forget();
+  uint32_t flags = aBuilder->ShouldSyncDecodeImages()
+                 ? imgIContainer::FLAG_SYNC_DECODE
+                 : imgIContainer::FLAG_NONE;
+
+  return mImage->GetImageContainer(aManager, flags);
 }
 
 gfxRect
 nsDisplayImage::GetDestRect()
 {
   int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
 
   bool snap;
@@ -1452,18 +1486,22 @@ nsDisplayImage::GetLayerState(nsDisplayL
     }
 
     // If the target size is pretty small, no point in using a layer.
     if (destRect.width * destRect.height < 64 * 64) {
       return LAYER_NONE;
     }
   }
 
-  nsRefPtr<ImageContainer> container;
-  mImage->GetImageContainer(aManager, getter_AddRefs(container));
+  uint32_t flags = aBuilder->ShouldSyncDecodeImages()
+                 ? imgIContainer::FLAG_SYNC_DECODE
+                 : imgIContainer::FLAG_NONE;
+
+  nsRefPtr<ImageContainer> container =
+    mImage->GetImageContainer(aManager, flags);
   if (!container) {
     return LAYER_NONE;
   }
 
   return LAYER_ACTIVE;
 }
 
 
@@ -1497,19 +1535,25 @@ nsDisplayImage::GetOpaqueRegion(nsDispla
   return nsRegion();
 }
 
 already_AddRefed<Layer>
 nsDisplayImage::BuildLayer(nsDisplayListBuilder* aBuilder,
                            LayerManager* aManager,
                            const ContainerLayerParameters& aParameters)
 {
-  nsRefPtr<ImageContainer> container;
-  nsresult rv = mImage->GetImageContainer(aManager, getter_AddRefs(container));
-  NS_ENSURE_SUCCESS(rv, nullptr);
+  uint32_t flags = aBuilder->ShouldSyncDecodeImages()
+                 ? imgIContainer::FLAG_SYNC_DECODE
+                 : imgIContainer::FLAG_NONE;
+
+  nsRefPtr<ImageContainer> container =
+    mImage->GetImageContainer(aManager, flags);
+  if (!container) {
+    return nullptr;
+  }
 
   nsRefPtr<ImageLayer> layer = static_cast<ImageLayer*>
     (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this));
   if (!layer) {
     layer = aManager->CreateImageLayer();
     if (!layer)
       return nullptr;
   }
--- a/layout/generic/nsImageFrame.h
+++ b/layout/generic/nsImageFrame.h
@@ -138,20 +138,21 @@ public:
   /**
    * Function to test whether aContent, which has aStyleContext as its style,
    * should get an image frame.  Note that this method is only used by the
    * frame constructor; it's only here because it uses gIconLoad for now.
    */
   static bool ShouldCreateImageFrameFor(mozilla::dom::Element* aElement,
                                           nsStyleContext* aStyleContext);
   
-  void DisplayAltFeedback(nsRenderingContext& aRenderingContext,
-                          const nsRect&        aDirtyRect,
-                          imgIRequest*         aRequest,
-                          nsPoint              aPt);
+  DrawResult DisplayAltFeedback(nsRenderingContext& aRenderingContext,
+                                const nsRect& aDirtyRect,
+                                imgIRequest* aRequest,
+                                nsPoint aPt,
+                                uint32_t aFlags);
 
   nsRect GetInnerArea() const;
 
   /**
    * Return a map element associated with this image.
    */
   mozilla::dom::Element* GetMapElement() const;
 
--- a/layout/xul/nsImageBoxFrame.cpp
+++ b/layout/xul/nsImageBoxFrame.cpp
@@ -428,38 +428,41 @@ nsDisplayXULImage::ConfigureLayer(ImageL
   gfxPoint p = destRect.TopLeft() + aOffset;
   Matrix transform = Matrix::Translation(p.x, p.y);
   transform.PreScale(destRect.Width() / imageWidth,
                      destRect.Height() / imageHeight);
   aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
 }
 
 already_AddRefed<ImageContainer>
-nsDisplayXULImage::GetContainer(LayerManager* aManager, nsDisplayListBuilder* aBuilder)
+nsDisplayXULImage::GetContainer(LayerManager* aManager,
+                                nsDisplayListBuilder* aBuilder)
 {
-  return static_cast<nsImageBoxFrame*>(mFrame)->GetContainer(aManager);
+  uint32_t flags = aBuilder->ShouldSyncDecodeImages()
+                 ? imgIContainer::FLAG_SYNC_DECODE
+                 : imgIContainer::FLAG_NONE;
+
+  return static_cast<nsImageBoxFrame*>(mFrame)->GetContainer(aManager, flags);
 }
 
 already_AddRefed<ImageContainer>
-nsImageBoxFrame::GetContainer(LayerManager* aManager)
+nsImageBoxFrame::GetContainer(LayerManager* aManager, uint32_t aFlags)
 {
   bool hasSubRect = !mUseSrcAttr && (mSubRect.width > 0 || mSubRect.height > 0);
   if (hasSubRect || !mImageRequest) {
     return nullptr;
   }
 
   nsCOMPtr<imgIContainer> imgCon;
   mImageRequest->GetImage(getter_AddRefs(imgCon));
   if (!imgCon) {
     return nullptr;
   }
   
-  nsRefPtr<ImageContainer> container;
-  imgCon->GetImageContainer(aManager, getter_AddRefs(container));
-  return container.forget();
+  return imgCon->GetImageContainer(aManager, aFlags);
 }
 
 
 //
 // DidSetStyleContext
 //
 // When the style context changes, make sure that all of our image is up to date.
 //
--- a/layout/xul/nsImageBoxFrame.h
+++ b/layout/xul/nsImageBoxFrame.h
@@ -36,16 +36,17 @@ private:
 
   nsImageBoxFrame *mFrame;
 };
 
 class nsImageBoxFrame MOZ_FINAL : public nsLeafBoxFrame
 {
 public:
   typedef mozilla::image::DrawResult DrawResult;
+  typedef mozilla::layers::ImageContainer ImageContainer;
   typedef mozilla::layers::LayerManager LayerManager;
 
   friend class nsDisplayXULImage;
   NS_DECL_FRAMEARENA_HELPERS
 
   virtual nsSize GetPrefSize(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE;
   virtual nsSize GetMinSize(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE;
   virtual nscoord GetBoxAscent(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE;
@@ -90,17 +91,19 @@ public:
                                 const nsDisplayListSet& aLists) MOZ_OVERRIDE;
 
   virtual ~nsImageBoxFrame();
 
   DrawResult PaintImage(nsRenderingContext& aRenderingContext,
                         const nsRect& aDirtyRect,
                         nsPoint aPt, uint32_t aFlags);
 
-  already_AddRefed<mozilla::layers::ImageContainer> GetContainer(LayerManager* aManager);
+  already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager,
+                                                uint32_t aFlags);
+
 protected:
   explicit nsImageBoxFrame(nsStyleContext* aContext);
 
   virtual void GetImageSize();
 
 private:
   nsresult OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage);
   nsresult OnDecodeComplete(imgIRequest* aRequest);
--- a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
@@ -1784,18 +1784,19 @@ status_t MPEG4Extractor::parseChunk(off6
                 uint32_t duration32;
                 if (mDataSource->readAt(
                             data_offset + 4, &duration32, sizeof(duration32))
                         < (ssize_t)sizeof(duration32)) {
                     return ERROR_IO;
                 }
                 duration = ntohl(duration32);
             }
-            if (duration) {
-              mFileMetaData->setInt64(kKeyMovieDuration, duration * 1000LL);
+            if (duration && mHeaderTimescale) {
+                mFileMetaData->setInt64(
+                        kKeyMovieDuration, (duration * 1000000) / mHeaderTimescale);
             }
 
             *offset += chunk_size;
             break;
         }
 
         case FOURCC('m', 'd', 'a', 't'):
         {
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -21,19 +21,21 @@
 #include "transportlayerice.h"
 #include "transportlayerdtls.h"
 #include "signaling/src/jsep/JsepSession.h"
 #include "signaling/src/jsep/JsepTransport.h"
 
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsICancelable.h"
+#include "nsIDocument.h"
+#include "nsILoadInfo.h"
+#include "nsIContentPolicy.h"
 #include "nsIProxyInfo.h"
 #include "nsIProtocolProxyService.h"
-#include "nsIIOService.h"
 
 #ifdef MOZILLA_INTERNAL_API
 #include "MediaStreamList.h"
 #include "nsIScriptGlobalObject.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/RTCStatsReportBinding.h"
 #include "MediaStreamTrack.h"
 #include "VideoStreamTrack.h"
@@ -222,25 +224,24 @@ PeerConnectionMedia::PeerConnectionMedia
   // "example.com" is guaranteed to be unallocated and should return the best default.
   nsCOMPtr<nsIURI> fakeHttpsLocation;
   rv = NS_NewURI(getter_AddRefs(fakeHttpsLocation), "https://example.com");
   if (NS_FAILED(rv)) {
     CSFLogError(logTag, "%s: Failed to set URI: %d", __FUNCTION__, (int)rv);
     return;
   }
 
-  nsCOMPtr<nsIIOService> ios = do_GetIOService(&rv);
-  if (NS_FAILED(rv)) {
-    CSFLogError(logTag, "%s: Failed to get IOService: %d",
-                __FUNCTION__, (int)rv);
-    return;
-  }
+  nsCOMPtr<nsIChannel> channel;
+  nsCOMPtr<nsIDocument> doc = mParent->GetWindow()->GetExtantDoc();
+  rv = NS_NewChannel(getter_AddRefs(channel),
+                     fakeHttpsLocation,
+                     doc,
+                     nsILoadInfo::SEC_NORMAL,
+                     nsIContentPolicy::TYPE_OTHER);
 
-  nsCOMPtr<nsIChannel> channel;
-  rv = ios->NewChannelFromURI(fakeHttpsLocation, getter_AddRefs(channel));
   if (NS_FAILED(rv)) {
     CSFLogError(logTag, "%s: Failed to get channel from URI: %d",
                 __FUNCTION__, (int)rv);
     return;
   }
 
   nsRefPtr<ProtocolProxyQueryHandler> handler = new ProtocolProxyQueryHandler(this);
   rv = pps->AsyncResolve(channel,
--- a/mfbt/Pair.h
+++ b/mfbt/Pair.h
@@ -161,16 +161,28 @@ public:
   {}
 
   Pair(Pair&& aOther)
     : Base(Move(aOther.first()), Move(aOther.second()))
   { }
 
   Pair(const Pair& aOther) = default;
 
+  Pair& operator=(Pair&& aOther)
+  {
+    MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
+
+    first() = Move(aOther.first());
+    second() = Move(aOther.second());
+
+    return *this;
+  }
+
+  Pair& operator=(const Pair& aOther) = default;
+
   /** The A instance. */
   using Base::first;
   /** The B instance. */
   using Base::second;
 
   /** Swap this pair with another pair. */
   void swap(Pair& aOther) { Base::swap(aOther); }
 };
--- a/mfbt/tests/TestPair.cpp
+++ b/mfbt/tests/TestPair.cpp
@@ -70,10 +70,14 @@ main()
   // Check that MakePair generates Pair objects of the correct types.
   static_assert(IsSame<decltype(MakePair(A(0), B(0))), Pair<A, B>>::value,
                 "MakePair should strip rvalue references");
   static_assert(IsSame<decltype(MakePair(a, b)), Pair<A, B>>::value,
                 "MakePair should strip lvalue references");
   static_assert(IsSame<decltype(MakePair(constA, constB)), Pair<A, B>>::value,
                 "MakePair should strip CV-qualifiers");
 
+  // Check that copy assignment and move assignment work.
+  a = constA;
+  a = A(0);
+
   return 0;
 }
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -561,16 +561,17 @@ pref("media.video-queue.default-size", 3
 
 // Enable the MediaCodec PlatformDecoderModule by default.
 pref("media.fragmented-mp4.exposed", true);
 pref("media.fragmented-mp4.enabled", true);
 pref("media.fragmented-mp4.android-media-codec.enabled", true);
 pref("media.fragmented-mp4.android-media-codec.preferred", true);
 
 // optimize images memory usage
+pref("image.downscale-during-decode.enabled", true);
 pref("image.mem.decodeondraw", true);
 
 #ifdef NIGHTLY_BUILD
 // Shumway component (SWF player) is disabled by default. Also see bug 904346.
 pref("shumway.disabled", true);
 #endif
 
 // enable touch events interfaces
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -422,20 +422,20 @@ pref("media.getusermedia.playout_delay",
 #endif
 #endif
 
 #if !defined(ANDROID)
 pref("media.getusermedia.screensharing.enabled", true);
 #endif
 
 #ifdef RELEASE_BUILD
-pref("media.getusermedia.screensharing.allowed_domains", "webex.com,*.webex.com,collaborate.com,*.collaborate.com,projectsquared.com,*.projectsquared.com,*.room.co,room.co,beta.talky.io,talky.io,*.clearslide.com,appear.in,*.appear.in,tokbox.com,*.tokbox.com,*.sso.francetelecom.fr,*.si.francetelecom.fr,*.sso.infra.ftgroup,*.multimedia-conference.orange-business.com,*.espacecollaboration.orange-business.com,free.gotomeeting.com,g2m.me,*.g2m.me,example.com");
+pref("media.getusermedia.screensharing.allowed_domains", "webex.com,*.webex.com,ciscospark.com,*.ciscospark.com,projectsquared.com,*.projectsquared.com,*.room.co,room.co,beta.talky.io,talky.io,*.clearslide.com,appear.in,*.appear.in,tokbox.com,*.tokbox.com,*.sso.francetelecom.fr,*.si.francetelecom.fr,*.sso.infra.ftgroup,*.multimedia-conference.orange-business.com,*.espacecollaboration.orange-business.com,free.gotomeeting.com,g2m.me,*.g2m.me,example.com");
 #else
  // temporary value, not intended for release - bug 1049087
-pref("media.getusermedia.screensharing.allowed_domains", "mozilla.github.io,webex.com,*.webex.com,collaborate.com,*.collaborate.com,projectsquared.com,*.projectsquared.com,*.room.co,room.co,beta.talky.io,talky.io,*.clearslide.com,appear.in,*.appear.in,tokbox.com,*.tokbox.com,*.sso.francetelecom.fr,*.si.francetelecom.fr,*.sso.infra.ftgroup,*.multimedia-conference.orange-business.com,*.espacecollaboration.orange-business.com,free.gotomeeting.com,g2m.me,*.g2m.me,example.com");
+pref("media.getusermedia.screensharing.allowed_domains", "mozilla.github.io,webex.com,*.webex.com,ciscospark.com,*.ciscospark.com,projectsquared.com,*.projectsquared.com,*.room.co,room.co,beta.talky.io,talky.io,*.clearslide.com,appear.in,*.appear.in,tokbox.com,*.tokbox.com,*.sso.francetelecom.fr,*.si.francetelecom.fr,*.sso.infra.ftgroup,*.multimedia-conference.orange-business.com,*.espacecollaboration.orange-business.com,free.gotomeeting.com,g2m.me,*.g2m.me,example.com");
 #endif
 // OS/X 10.6 and XP have screen/window sharing off by default due to various issues - Caveat emptor
 pref("media.getusermedia.screensharing.allow_on_old_platforms", false);
 
 // TextTrack support
 pref("media.webvtt.enabled", true);
 pref("media.webvtt.regions.enabled", false);
 
@@ -2996,17 +2996,17 @@ pref("plugin.allow.asyncdrawing", false)
 // when a network address is unreachable.
 pref("network.autodial-helper.enabled", true);
 
 // Switch the keyboard layout per window
 pref("intl.keyboard.per_window_layout", false);
 
 #ifdef NS_ENABLE_TSF
 // Enable/Disable TSF support on Vista or later.
-#ifdef NIGHTLY_BUILD
+#ifndef RELEASE_BUILD
 pref("intl.tsf.enable", true);
 #else
 pref("intl.tsf.enable", false);
 #endif
 // Force enable TSF even on WinXP or WinServer 2003.
 // Be aware, TSF framework on prior to Vista is not enough stable.
 pref("intl.tsf.force_enable", false);
 
@@ -3814,17 +3814,17 @@ pref("browser.zoom.reflowZoom.reflowText
 // The maximum size, in bytes, of the decoded images we cache
 pref("image.cache.size", 5242880);
 
 // A weight, from 0-1000, to place on time when comparing to size.
 // Size is given a weight of 1000 - timeweight.
 pref("image.cache.timeweight", 500);
 
 // Whether we attempt to downscale images during decoding.
-pref("image.downscale-during-decode.enabled", false);
+pref("image.downscale-during-decode.enabled", true);
 
 // The default Accept header sent for images loaded over HTTP(S)
 pref("image.http.accept", "image/png,image/*;q=0.8,*/*;q=0.5");
 
 pref("image.high_quality_downscaling.enabled", true);
 
 // The minimum percent downscaling we'll use high-quality downscaling on,
 // interpreted as a floating-point number / 1000.
@@ -4623,22 +4623,18 @@ pref("reader.toolbar.vertical", true);
 // Whether to allow, on a Linux system that doesn't support the necessary sandboxing
 // features, loading Gecko Media Plugins unsandboxed.  However, EME CDMs will not be
 // loaded without sandboxing even if this pref is changed.
 pref("media.gmp.insecure.allow", false);
 #endif
 
 // Use vsync aligned rendering. b2g prefs are in b2g.js
 // Only supported on windows, os x, and b2g
-#if defined(XP_MACOSX)
+#if defined(XP_MACOSX) || defined(XP_WIN)
 pref("gfx.vsync.hw-vsync.enabled", true);
 pref("gfx.vsync.compositor", true);
 pref("gfx.vsync.refreshdriver", false);
-#elif defined(XP_WIN)
-pref("gfx.vsync.hw-vsync.enabled", false);
-pref("gfx.vsync.compositor", false);
-pref("gfx.vsync.refreshdriver", false);
 #endif
 
 // Secure Element API
 #ifdef MOZ_SECUREELEMENT
 pref("dom.secureelement.enabled", false);
 #endif
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -3144,16 +3144,20 @@ nsHttpChannel::OnCacheEntryCheck(nsICach
         LOG(("Redirection-chain %s key %s\n",
              doValidation ? "contains" : "does not contain", cacheKey.get()));
 
         // Append cacheKey if not in the chain already
         if (!doValidation)
             mRedirectedCachekeys->AppendElement(cacheKey);
     }
 
+    if (doValidation && mInterceptCache == INTERCEPTED) {
+        doValidation = false;
+    }
+
     mCachedContentIsValid = !doValidation;
 
     if (doValidation) {
         //
         // now, we are definitely going to issue a HTTP request to the server.
         // make it conditional if possible.
         //
         // do not attempt to validate no-store content, since servers will not
--- a/testing/web-platform/meta/media-source/mediasource-addsourcebuffer.html.ini
+++ b/testing/web-platform/meta/media-source/mediasource-addsourcebuffer.html.ini
@@ -1,20 +1,12 @@
 [mediasource-addsourcebuffer.html]
   type: testharness
-  [Test addSourceBuffer() with Vorbis and VP8]
-    expected: FAIL
-
-  [Test addSourceBuffer() with Vorbis and VP8 in separate SourceBuffers]
-    expected: FAIL
-
   [Test addSourceBuffer() with AAC and H.264]
-    expected: FAIL
+    expected:
+      if os == "linux": FAIL
+      if (os == "win") and (version == "5.1.2600"): FAIL
 
   [Test addSourceBuffer() with AAC and H.264 in separate SourceBuffers]
-    expected: FAIL
+    expected:
+      if os == "linux": FAIL
+      if (os == "win") and (version == "5.1.2600"): FAIL
 
-  [Test addSourceBuffer() video only]
-    expected: FAIL
-
-  [Test addSourceBuffer() audio only]
-    expected: FAIL
-
--- a/testing/web-platform/meta/media-source/mediasource-append-buffer.html.ini
+++ b/testing/web-platform/meta/media-source/mediasource-append-buffer.html.ini
@@ -1,21 +1,5 @@
 [mediasource-append-buffer.html]
   type: testharness
   disabled:
-    if (os == "win") and (version != "5.1.2600"): https://bugzilla.mozilla.org/show_bug.cgi?id=1128332
-  [Test MediaSource.removeSourceBuffer() call during a pending appendBuffer().]
-    expected: FAIL
-
-  [Test appendBuffer with partial init segments.]
-    expected:
-      if (os == "win") and (version != "5.1.2600"): FAIL
-      if os == "mac": FAIL
-
-  [Test appendBuffer with partial media segments.]
-    expected:
-      if (os == "win") and (version != "5.1.2600"): FAIL
-      if os == "mac": FAIL
-
-  [Test abort in the middle of an initialization segment.]
-    disabled:
-      if (os == "win") and (version != "5.1.2600"): https://bugzilla.mozilla.org/show_bug.cgi?id=1128332
-
+    if (os == "win") and (version != "5.1.2600"): https://bugzilla.mozilla.org/show_bug.cgi?id=1143650
+    if os == "mac": https://bugzilla.mozilla.org/show_bug.cgi?id=1143650
--- a/testing/web-platform/meta/media-source/mediasource-buffered.html.ini
+++ b/testing/web-platform/meta/media-source/mediasource-buffered.html.ini
@@ -1,12 +1,14 @@
 [mediasource-buffered.html]
   type: testharness
   [Demuxed content with different lengths]
-    expected: FAIL
+    expected:
+      if os == "linux": FAIL
+      if (os == "win") and (version == "5.1.2600"): FAIL
 
   [Muxed tracks with different lengths]
     expected: FAIL
 
   [Demuxed content with an empty buffered range on one SourceBuffer]
     expected: FAIL
 
   [Muxed content empty buffered ranges.]
--- a/testing/web-platform/meta/media-source/mediasource-config-change-mp4-av-audio-bitrate.html.ini
+++ b/testing/web-platform/meta/media-source/mediasource-config-change-mp4-av-audio-bitrate.html.ini
@@ -1,5 +1,7 @@
 [mediasource-config-change-mp4-av-audio-bitrate.html]
   type: testharness
   [Tests mp4 audio bitrate changes in multiplexed content.]
-    expected: FAIL
+    expected:
+      if os == "linux": FAIL
+      if (os == "win") and (version == "5.1.2600"): FAIL
 
--- a/testing/web-platform/meta/media-source/mediasource-config-change-mp4-av-framesize.html.ini
+++ b/testing/web-platform/meta/media-source/mediasource-config-change-mp4-av-framesize.html.ini
@@ -1,5 +1,7 @@
 [mediasource-config-change-mp4-av-framesize.html]
   type: testharness
   [Tests mp4 frame size changes in multiplexed content.]
-    expected: FAIL
+    expected:
+      if os == "linux": FAIL
+      if (os == "win") and (version == "5.1.2600"): FAIL
 
--- a/testing/web-platform/meta/media-source/mediasource-config-change-mp4-av-video-bitrate.html.ini
+++ b/testing/web-platform/meta/media-source/mediasource-config-change-mp4-av-video-bitrate.html.ini
@@ -1,5 +1,7 @@
 [mediasource-config-change-mp4-av-video-bitrate.html]
   type: testharness
   [Tests mp4 video bitrate changes in multiplexed content.]
-    expected: FAIL
+    expected:
+      if os == "linux": FAIL
+      if (os == "win") and (version == "5.1.2600"): FAIL
 
--- a/testing/web-platform/meta/media-source/mediasource-config-change-mp4-v-bitrate.html.ini
+++ b/testing/web-platform/meta/media-source/mediasource-config-change-mp4-v-bitrate.html.ini
@@ -1,5 +1,7 @@
 [mediasource-config-change-mp4-v-bitrate.html]
   type: testharness
   [Tests mp4 video-only bitrate changes.]
-    expected: FAIL
+    expected:
+      if os == "linux": FAIL
+      if (os == "win") and (version == "5.1.2600"): FAIL
 
--- a/testing/web-platform/meta/media-source/mediasource-config-change-mp4-v-framerate.html.ini
+++ b/testing/web-platform/meta/media-source/mediasource-config-change-mp4-v-framerate.html.ini
@@ -1,5 +1,7 @@
 [mediasource-config-change-mp4-v-framerate.html]
   type: testharness
   [Tests mp4 video-only frame rate changes.]
-    expected: FAIL
+    expected:
+      if os == "linux": FAIL
+      if (os == "win") and (version == "5.1.2600"): FAIL
 
--- a/testing/web-platform/meta/media-source/mediasource-config-change-mp4-v-framesize.html.ini
+++ b/testing/web-platform/meta/media-source/mediasource-config-change-mp4-v-framesize.html.ini
@@ -1,5 +1,7 @@
 [mediasource-config-change-mp4-v-framesize.html]
   type: testharness
   [Tests mp4 video-only frame size changes.]
-    expected: FAIL
+    expected:
+      if os == "linux": FAIL
+      if (os == "win") and (version == "5.1.2600"): FAIL
 
--- a/testing/web-platform/meta/media-source/mediasource-duration.html.ini
+++ b/testing/web-platform/meta/media-source/mediasource-duration.html.ini
@@ -1,18 +1,20 @@
 [mediasource-duration.html]
   type: testharness
   disabled:
-    if (os == "win") and (version != "5.1.2600"): https://bugzilla.mozilla.org/show_bug.cgi?id=1128332
+    if (os == "win") and (version != "5.1.2600"): https://bugzilla.mozilla.org/show_bug.cgi?id=1143650
+    if os == "mac": https://bugzilla.mozilla.org/show_bug.cgi?id=1143650
   [Test seek starts on duration truncation below currentTime]
-    expected: FAIL
+    expected:
+      if (os == "win") and (version != "5.1.2600"): PASS
+      if os == "mac": PASS
+      FAIL
 
   [Test appendBuffer completes previous seek to truncated duration]
     expected: FAIL
 
   [Test endOfStream completes previous seek to truncated duration]
     expected: FAIL
 
   [Test setting same duration multiple times does not fire duplicate durationchange]
-    disabled:
-      if (os == "win") and (version != "5.1.2600"): https://bugzilla.mozilla.org/show_bug.cgi?id=1128332
     expected: FAIL
 
--- a/testing/web-platform/meta/media-source/mediasource-remove.html.ini
+++ b/testing/web-platform/meta/media-source/mediasource-remove.html.ini
@@ -7,13 +7,8 @@
     expected: FAIL
 
   [Test removing the middle of appended data.]
     expected: FAIL
 
   [Test removing the end of appended data.]
     expected: FAIL
 
-  [Test remove with a start at the duration.]
-    expected:
-      if (os == "win") and (version != "5.1.2600"): FAIL
-      if os == "mac": FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/media-source/mediasource-removesourcebuffer.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[mediasource-removesourcebuffer.html]
-  type: testharness
-  [Test removesourcebuffer event on activeSourceBuffers.]
-    expected:
-      if (os == "win") and (version != "5.1.2600"): FAIL
-      if os == "mac": FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/media-source/mediasource-sourcebufferlist.html.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[mediasource-sourcebufferlist.html]
-  type: testharness
-  [Test SourceBufferList event dispatching.]
-    expected: FAIL
-
-  [Test that only 1 removesourcebuffer event fires on each SourceBufferList when the MediaSource closes.]
-    expected: FAIL
-
--- a/toolkit/components/reader/JSDOMParser.js
+++ b/toolkit/components/reader/JSDOMParser.js
@@ -22,17 +22,17 @@
  *   2) Live NodeLists are not supported. DOM methods and properties such as
  *      getElementsByTagName() and childNodes return standard arrays. If you
  *      want these lists to be updated when nodes are removed or added to the
  *      document, you must take care to manually update them yourself.
  */
 (function (global) {
 
   function error(m) {
-    dump("JSDOMParser error: " + m);
+    dump("JSDOMParser error: " + m + "\n");
   }
 
   // When a style is set in JS, map it to the corresponding CSS attribute
   let styleMap = {
     "alignmentBaseline": "alignment-baseline",
     "background": "background",
     "backgroundAttachment": "background-attachment",
     "backgroundClip": "background-clip",
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -5572,17 +5572,17 @@ nsWindow::ClientMarginHitTestPoint(int32
       testResult = mCachedHitTestResult;
     } else {
       WidgetMouseEvent event(true, NS_MOUSE_MOZHITTEST, this,
                              WidgetMouseEvent::eReal,
                              WidgetMouseEvent::eNormal);
       event.refPoint = LayoutDeviceIntPoint(pt.x, pt.y);
       event.inputSource = MOUSE_INPUT_SOURCE();
       event.mFlags.mOnlyChromeDispatch = true;
-      bool result = DispatchInputEvent(&event);
+      bool result = ConvertStatus(DispatchInputEvent(&event));
       if (result) {
         // The mouse is over a blank area
         testResult = testResult == HTCLIENT ? HTCAPTION : testResult;
 
       } else {
         // There's content over the mouse pointer. Set HTCLIENT
         // to possibly override a resizer border.
         testResult = HTCLIENT;