Merge mozilla-central to inbound. a=merge CLOSED TREE
authorshindli <shindli@mozilla.com>
Sun, 07 Oct 2018 00:15:20 +0300
changeset 488254 6b1761e269846b394b18979fc86264f8cea81610
parent 488248 24d67618f6b943e45d6d1131c1bc442274f3d330 (current diff)
parent 488253 07c609fc8eb89140f602ef0c838b900c2964287a (diff)
child 488255 0db58037928d28a7b6eab44c94c5be3ac6b23b6d
push id246
push userfmarier@mozilla.com
push dateSat, 13 Oct 2018 00:15:40 +0000
reviewersmerge
milestone64.0a1
Merge mozilla-central to inbound. a=merge CLOSED TREE
--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -1248,16 +1248,31 @@ template
 void
 FetchBody<Request>::SetMimeType();
 
 template
 void
 FetchBody<Response>::SetMimeType();
 
 template <class Derived>
+const nsACString&
+FetchBody<Derived>::BodyBlobURISpec() const
+{
+  return DerivedClass()->BodyBlobURISpec();
+}
+
+template
+const nsACString&
+FetchBody<Request>::BodyBlobURISpec() const;
+
+template
+const nsACString&
+FetchBody<Response>::BodyBlobURISpec() const;
+
+template <class Derived>
 const nsAString&
 FetchBody<Derived>::BodyLocalPath() const
 {
   return DerivedClass()->BodyLocalPath();
 }
 
 template
 const nsAString&
--- a/dom/fetch/Fetch.h
+++ b/dom/fetch/Fetch.h
@@ -182,16 +182,19 @@ public:
     return ConsumeBody(aCx, CONSUME_TEXT, aRv);
   }
 
   void
   GetBody(JSContext* aCx,
           JS::MutableHandle<JSObject*> aBodyOut,
           ErrorResult& aRv);
 
+  const nsACString&
+  BodyBlobURISpec() const;
+
   const nsAString&
   BodyLocalPath() const;
 
   // If the body contains a ReadableStream body object, this method produces a
   // tee() of it.
   void
   MaybeTeeReadableStreamBody(JSContext* aCx,
                              JS::MutableHandle<JSObject*> aBodyOut,
--- a/dom/fetch/FetchConsumer.cpp
+++ b/dom/fetch/FetchConsumer.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Fetch.h"
 #include "FetchConsumer.h"
 
 #include "mozilla/dom/BlobBinding.h"
+#include "mozilla/dom/BlobURLProtocolHandler.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FileBinding.h"
 #include "mozilla/dom/FileCreatorHelper.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/WorkerCommon.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerRef.h"
 #include "mozilla/dom/WorkerRunnable.h"
@@ -429,16 +430,17 @@ FetchBodyConsumer<Derived>::FetchBodyCon
                                               FetchConsumeType aType)
   : mTargetThread(NS_GetCurrentThread())
   , mMainThreadEventTarget(aMainThreadEventTarget)
 #ifdef DEBUG
   , mBody(aBody)
 #endif
   , mBodyStream(aBodyStream)
   , mBlobStorageType(MutableBlobStorage::eOnlyInMemory)
+  , mBodyBlobURISpec(aBody ? aBody->BodyBlobURISpec() : VoidCString())
   , mBodyLocalPath(aBody ? aBody->BodyLocalPath() : VoidString())
   , mGlobal(aGlobalObject)
   , mConsumeType(aType)
   , mConsumePromise(aPromise)
   , mBodyConsumed(false)
   , mShuttingDown(false)
 {
   MOZ_ASSERT(aMainThreadEventTarget);
@@ -592,21 +594,36 @@ FetchBodyConsumer<Derived>::BeginConsume
   AutoFailConsumeBody<Derived> autoReject(this, aWorkerRef);
 
   if (mShuttingDown) {
     // We haven't started yet, but we have been terminated. AutoFailConsumeBody
     // will dispatch a runnable to release resources.
     return;
   }
 
-  // If we're trying to consume a blob, and the request was for a local
-  // file, then generate and return a File blob.
   if (mConsumeType == CONSUME_BLOB) {
+    nsresult rv;
+
+    // If we're trying to consume a blob, and the request was for a blob URI,
+    // then just consume that URI's blob instance.
+    if (!mBodyBlobURISpec.IsEmpty()) {
+      RefPtr<BlobImpl> blobImpl;
+      rv = NS_GetBlobForBlobURISpec(mBodyBlobURISpec, getter_AddRefs(blobImpl));
+      if (NS_WARN_IF(NS_FAILED(rv)) || !blobImpl) {
+        return;
+      }
+      autoReject.DontFail();
+      ContinueConsumeBlobBody(blobImpl);
+      return;
+    }
+
+    // If we're trying to consume a blob, and the request was for a local
+    // file, then generate and return a File blob.
     nsCOMPtr<nsIFile> file;
-    nsresult rv = GetBodyLocalFile(getter_AddRefs(file));
+    rv = GetBodyLocalFile(getter_AddRefs(file));
     if (!NS_WARN_IF(NS_FAILED(rv)) && file) {
       ChromeFilePropertyBag bag;
       bag.mType = NS_ConvertUTF8toUTF16(mBodyMimeType);
 
       ErrorResult error;
       RefPtr<Promise> promise =
         FileCreatorHelper::CreateFile(mGlobal, file, bag, true, error);
       if (NS_WARN_IF(error.Failed())) {
--- a/dom/fetch/FetchConsumer.h
+++ b/dom/fetch/FetchConsumer.h
@@ -97,16 +97,17 @@ private:
 #endif
 
   // This is nullified when the consuming of the body starts.
   nsCOMPtr<nsIInputStream> mBodyStream;
 
   MutableBlobStorage::MutableBlobStorageType mBlobStorageType;
   nsCString mBodyMimeType;
 
+  nsCString mBodyBlobURISpec;
   nsString mBodyLocalPath;
 
   nsCOMPtr<nsIGlobalObject> mGlobal;
 
   // Touched on the main-thread only.
   nsCOMPtr<nsIInputStreamPump> mConsumeBodyPump;
 
   // Only ever set once, always on target thread.
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -43,16 +43,41 @@
 #include "InternalRequest.h"
 #include "InternalResponse.h"
 
 namespace mozilla {
 namespace dom {
 
 namespace {
 
+void
+GetBlobURISpecFromChannel(nsIRequest* aRequest, nsCString& aBlobURISpec)
+{
+  MOZ_ASSERT(aRequest);
+
+  aBlobURISpec.SetIsVoid(true);
+
+  nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
+  if (!channel) {
+    return;
+  }
+
+  nsCOMPtr<nsIURI> uri;
+  nsresult rv = channel->GetURI(getter_AddRefs(uri));
+  if (NS_FAILED(rv)) {
+    return;
+  }
+
+  if (!dom::IsBlobURI(uri)) {
+    return;
+  }
+
+  uri->GetSpec(aBlobURISpec);
+}
+
 bool
 ShouldCheckSRI(const InternalRequest* const aRequest,
                const InternalResponse* const aResponse)
 {
   MOZ_DIAGNOSTIC_ASSERT(aRequest);
   MOZ_DIAGNOSTIC_ASSERT(aResponse);
 
   return !aRequest->GetIntegrity().IsEmpty() &&
@@ -957,16 +982,24 @@ FetchDriver::OnStartRequest(nsIRequest* 
   if (fc) {
     nsCOMPtr<nsIFile> file;
     rv = fc->GetFile(getter_AddRefs(file));
     if (!NS_WARN_IF(NS_FAILED(rv))) {
       nsAutoString path;
       file->GetPath(path);
       response->SetBodyLocalPath(path);
     }
+  } else {
+    // If the request is a blob URI, then remember that URI so that we
+    // can later just use that blob instance instead of cloning it.
+    nsCString blobURISpec;
+    GetBlobURISpecFromChannel(aRequest, blobURISpec);
+    if (!blobURISpec.IsVoid()) {
+      response->SetBodyBlobURISpec(blobURISpec);
+    }
   }
 
   response->InitChannelInfo(channel);
 
   nsCOMPtr<nsIURI> channelURI;
   rv = channel->GetURI(getter_AddRefs(channelURI));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     FailWithNetworkError(rv);
--- a/dom/fetch/InternalRequest.h
+++ b/dom/fetch/InternalRequest.h
@@ -486,16 +486,28 @@ public:
     s.forget(aStream);
 
     if (aBodyLength) {
       *aBodyLength = mBodyLength;
     }
   }
 
   void
+  SetBodyBlobURISpec(nsACString& aBlobURISpec)
+  {
+    mBodyBlobURISpec = aBlobURISpec;
+  }
+
+  const nsACString&
+  BodyBlobURISpec() const
+  {
+    return mBodyBlobURISpec;
+  }
+
+  void
   SetBodyLocalPath(nsAString& aLocalPath)
   {
     mBodyLocalPath = aLocalPath;
   }
 
   const nsAString&
   BodyLocalPath() const
   {
@@ -603,16 +615,17 @@ private:
     mURLList.LastElement() = aURL;
     mFragment.Assign(aFragment);
   }
 
   nsCString mMethod;
   // mURLList: a list of one or more fetch URLs
   nsTArray<nsCString> mURLList;
   RefPtr<InternalHeaders> mHeaders;
+  nsCString mBodyBlobURISpec;
   nsString mBodyLocalPath;
   nsCOMPtr<nsIInputStream> mBodyStream;
   int64_t mBodyLength;
 
   nsCString mPreferredAlternativeDataType;
 
   nsContentPolicyType mContentPolicyType;
 
--- a/dom/fetch/InternalResponse.h
+++ b/dom/fetch/InternalResponse.h
@@ -215,16 +215,31 @@ public:
       }
       return;
     }
 
     GetUnfilteredBody(aStream, aBodySize);
   }
 
   void
+  SetBodyBlobURISpec(nsACString& aBlobURISpec)
+  {
+    mBodyBlobURISpec = aBlobURISpec;
+  }
+
+  const nsACString&
+  BodyBlobURISpec() const
+  {
+    if (mWrappedResponse) {
+      return mWrappedResponse->BodyBlobURISpec();
+    }
+    return mBodyBlobURISpec;
+  }
+
+  void
   SetBodyLocalPath(nsAString& aLocalPath)
   {
     mBodyLocalPath = aLocalPath;
   }
 
   const nsAString&
   BodyLocalPath() const
   {
@@ -383,16 +398,17 @@ private:
   // A response has an associated url list (a list of zero or more fetch URLs).
   // Unless stated otherwise, it is the empty list. The current url is the last
   // element in mURLlist
   nsTArray<nsCString> mURLList;
   const uint16_t mStatus;
   const nsCString mStatusText;
   RefPtr<InternalHeaders> mHeaders;
   nsCOMPtr<nsIInputStream> mBody;
+  nsCString mBodyBlobURISpec;
   nsString mBodyLocalPath;
   int64_t mBodySize;
   // It's used to passed to the CacheResponse to generate padding size. Once, we
   // generate the padding size for resposne, we don't need it anymore.
   Maybe<uint32_t> mPaddingInfo;
   int64_t mPaddingSize;
   nsresult mErrorCode;
 
--- a/dom/fetch/Request.h
+++ b/dom/fetch/Request.h
@@ -138,16 +138,24 @@ public:
   }
 
   void
   SetBody(nsIInputStream* aStream, int64_t aBodyLength)
   {
     mRequest->SetBody(aStream, aBodyLength);
   }
 
+  using FetchBody::BodyBlobURISpec;
+
+  const nsACString&
+  BodyBlobURISpec() const
+  {
+    return mRequest->BodyBlobURISpec();
+  }
+
   using FetchBody::BodyLocalPath;
 
   const nsAString&
   BodyLocalPath() const
   {
     return mRequest->BodyLocalPath();
   }
 
--- a/dom/fetch/Response.h
+++ b/dom/fetch/Response.h
@@ -107,16 +107,24 @@ public:
   void
   GetBody(nsIInputStream** aStream, int64_t* aBodyLength = nullptr)
   {
     mInternalResponse->GetBody(aStream, aBodyLength);
   }
 
   using FetchBody::GetBody;
 
+  using FetchBody::BodyBlobURISpec;
+
+  const nsACString&
+  BodyBlobURISpec() const
+  {
+    return mInternalResponse->BodyBlobURISpec();
+  }
+
   using FetchBody::BodyLocalPath;
 
   const nsAString&
   BodyLocalPath() const
   {
     return mInternalResponse->BodyLocalPath();
   }
 
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -8,16 +8,17 @@
 
 #include <algorithm>
 #ifndef XP_WIN
 #include <unistd.h>
 #endif
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/dom/BlobBinding.h"
+#include "mozilla/dom/BlobURLProtocolHandler.h"
 #include "mozilla/dom/DocGroup.h"
 #include "mozilla/dom/DOMString.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FileBinding.h"
 #include "mozilla/dom/FileCreatorHelper.h"
 #include "mozilla/dom/FetchUtil.h"
 #include "mozilla/dom/FormData.h"
 #include "mozilla/dom/MutableBlobStorage.h"
@@ -1180,21 +1181,23 @@ XMLHttpRequestMainThread::GetResponseHea
     // return null and terminate these steps.
     if (mState == XMLHttpRequest_Binding::UNSENT ||
         mState == XMLHttpRequest_Binding::OPENED) {
       return;
     }
 
     // Even non-http channels supply content type and content length.
     // Remember we don't leak header information from denied cross-site
-    // requests.
+    // requests. However, we handle file: and blob: URLs for blob response
+    // types by canceling them with a specific error, so we have to allow
+    // them to pass through this check.
     nsresult status;
     if (!mChannel ||
         NS_FAILED(mChannel->GetStatus(&status)) ||
-        NS_FAILED(status)) {
+        (NS_FAILED(status) && status != NS_ERROR_FILE_ALREADY_EXISTS)) {
       return;
     }
 
     // Content Type:
     if (header.LowerCaseEqualsASCII("content-type")) {
       if (NS_FAILED(mChannel->GetContentType(_retval))) {
         // Means no content type
         _retval.SetIsVoid(true);
@@ -1650,16 +1653,42 @@ XMLHttpRequestMainThread::StreamReaderFu
     *writeCount = 0;
   }
 
   return rv;
 }
 
 namespace {
 
+void
+GetBlobURIFromChannel(nsIRequest* aRequest, nsIURI** aURI)
+{
+  MOZ_ASSERT(aRequest);
+  MOZ_ASSERT(aURI);
+
+  *aURI = nullptr;
+
+  nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
+  if (!channel) {
+    return;
+  }
+
+  nsCOMPtr<nsIURI> uri;
+  nsresult rv = channel->GetURI(getter_AddRefs(uri));
+  if (NS_FAILED(rv)) {
+    return;
+  }
+
+  if (!dom::IsBlobURI(uri)) {
+    return;
+  }
+
+  uri.forget(aURI);
+}
+
 nsresult
 GetLocalFileFromChannel(nsIRequest* aRequest, nsIFile** aFile)
 {
   MOZ_ASSERT(aRequest);
   MOZ_ASSERT(aFile);
 
   *aFile = nullptr;
 
@@ -1766,24 +1795,39 @@ XMLHttpRequestMainThread::OnDataAvailabl
 
   MOZ_ASSERT(mContext.get() == ctxt,"start context different from OnDataAvailable context");
 
   mProgressSinceLastProgressEvent = true;
   XMLHttpRequest_Binding::ClearCachedResponseTextValue(this);
 
   nsresult rv;
 
-  nsCOMPtr<nsIFile> localFile;
   if (mResponseType == XMLHttpRequestResponseType::Blob) {
-    rv = GetLocalFileFromChannel(request, getter_AddRefs(localFile));
+    nsCOMPtr<nsIFile> localFile;
+    nsCOMPtr<nsIURI> blobURI;
+    GetBlobURIFromChannel(request, getter_AddRefs(blobURI));
+    if (blobURI) {
+      RefPtr<BlobImpl> blobImpl;
+      rv = NS_GetBlobForBlobURI(blobURI, getter_AddRefs(blobImpl));
+      if (NS_SUCCEEDED(rv)) {
+        if (blobImpl) {
+          mResponseBlob = Blob::Create(GetOwner(), blobImpl);
+        }
+        if (!mResponseBlob) {
+          rv = NS_ERROR_FILE_NOT_FOUND;
+        }
+      }
+    } else {
+      rv = GetLocalFileFromChannel(request, getter_AddRefs(localFile));
+    }
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
-    if (localFile) {
+    if (mResponseBlob || localFile) {
       mBlobStorage = nullptr;
       NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty");
 
       // The nsIStreamListener contract mandates us to read from the stream
       // before returning.
       uint32_t totalRead;
       rv =
         inStr->ReadSegments(DummyStreamReaderFunc, nullptr, count, &totalRead);
@@ -2136,22 +2180,28 @@ XMLHttpRequestMainThread::OnStopRequest(
   // If window.stop() or other aborts were issued, handle as an abort
   if (status == NS_BINDING_ABORTED) {
     mFlagParseBody = false;
     IgnoredErrorResult rv;
     RequestErrorSteps(ProgressEventType::abort, NS_OK, rv);
     return NS_OK;
   }
 
+  // If we were just reading a blob URL, we're already done
+  if (status == NS_ERROR_FILE_ALREADY_EXISTS && mResponseBlob) {
+    ChangeStateToDone();
+    return NS_OK;
+  }
+
   bool waitingForBlobCreation = false;
 
   // If we have this error, we have to deal with a file: URL + responseType =
   // blob. We have this error because we canceled the channel. The status will
   // be set to NS_OK.
-  if (status == NS_ERROR_FILE_ALREADY_EXISTS &&
+  if (!mResponseBlob && status == NS_ERROR_FILE_ALREADY_EXISTS &&
       mResponseType == XMLHttpRequestResponseType::Blob) {
     nsCOMPtr<nsIFile> file;
     nsresult rv = GetLocalFileFromChannel(request, getter_AddRefs(file));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     if (file) {
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -1708,27 +1708,27 @@ PaintByLayer(nsDisplayItem* aItem,
   aManager->SetDefaultTarget(nullptr);
 
   return isInvalidated;
 }
 
 static bool
 PaintItemByDrawTarget(nsDisplayItem* aItem,
                       gfx::DrawTarget* aDT,
-                      const LayerRect& aImageRect,
                       const LayoutDevicePoint& aOffset,
                       nsDisplayListBuilder* aDisplayListBuilder,
                       const RefPtr<BasicLayerManager>& aManager,
                       const gfx::Size& aScale,
                       Maybe<gfx::Color>& aHighlight)
 {
   MOZ_ASSERT(aDT);
 
   bool isInvalidated = false;
-  aDT->ClearRect(aImageRect.ToUnknownRect());
+  // XXX Why is this ClearRect() needed?
+  aDT->ClearRect(Rect(aDT->GetRect()));
   RefPtr<gfxContext> context = gfxContext::CreateOrNull(aDT);
   MOZ_ASSERT(context);
 
   switch (aItem->GetType()) {
   case DisplayItemType::TYPE_MASK:
     context->SetMatrix(context->CurrentMatrix().PreScale(aScale.width, aScale.height).PreTranslate(-aOffset.x, -aOffset.y));
     static_cast<nsDisplayMasksAndClipPaths*>(aItem)->
       PaintMask(aDisplayListBuilder, context, &isInvalidated);
@@ -1763,24 +1763,24 @@ PaintItemByDrawTarget(nsDisplayItem* aIt
   }
 
   if (aItem->GetType() != DisplayItemType::TYPE_MASK) {
     // Apply highlight fills, if the appropriate prefs are set.
     // We don't do this for masks because we'd be filling the A8 mask surface,
     // which isn't very useful.
     if (aHighlight) {
       aDT->SetTransform(gfx::Matrix());
-      aDT->FillRect(gfx::Rect(0, 0, aImageRect.Width(), aImageRect.Height()), gfx::ColorPattern(aHighlight.value()));
+      aDT->FillRect(Rect(aDT->GetRect()), gfx::ColorPattern(aHighlight.value()));
     }
     if (aItem->Frame()->PresContext()->GetPaintFlashing() && isInvalidated) {
       aDT->SetTransform(gfx::Matrix());
       float r = float(rand()) / RAND_MAX;
       float g = float(rand()) / RAND_MAX;
       float b = float(rand()) / RAND_MAX;
-      aDT->FillRect(gfx::Rect(0, 0, aImageRect.Width(), aImageRect.Height()), gfx::ColorPattern(gfx::Color(r, g, b, 0.5)));
+      aDT->FillRect(Rect(aDT->GetRect()), gfx::ColorPattern(gfx::Color(r, g, b, 0.5)));
     }
   }
 
   return isInvalidated;
 }
 
 already_AddRefed<WebRenderFallbackData>
 WebRenderCommandBuilder::GenerateFallbackData(nsDisplayItem* aItem,
@@ -1818,52 +1818,42 @@ WebRenderCommandBuilder::GenerateFallbac
   // So we should call ComputeVisibility() before painting. e.g.: nsDisplayBoxShadowInner
   // uses mPaintRect in Paint() and mPaintRect is computed in
   // nsDisplayBoxShadowInner::ComputeVisibility().
   nsRegion visibleRegion(paintBounds);
   aItem->SetPaintRect(paintBounds);
   aItem->ComputeVisibility(aDisplayListBuilder, &visibleRegion);
 
   const int32_t appUnitsPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
-  LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(paintBounds, appUnitsPerDevPixel);
+  auto bounds = LayoutDeviceRect::FromAppUnits(paintBounds, appUnitsPerDevPixel);
+  if (bounds.IsEmpty()) {
+    return nullptr;
+  }
 
   gfx::Size scale = aSc.GetInheritedScale();
   gfx::Size oldScale = fallbackData->GetScale();
   // This scale determination should probably be done using
   // ChooseScaleAndSetTransform but for now we just fake it.
   // We tolerate slight changes in scale so that we don't, for example,
   // rerasterize on MotionMark
   bool differentScale = gfx::FuzzyEqual(scale.width, oldScale.width, 1e-6f) &&
                         gfx::FuzzyEqual(scale.height, oldScale.height, 1e-6f);
 
-  // XXX not sure if paintSize should be in layer or layoutdevice pixels, it
-  // has some sort of scaling applied.
-  LayerIntSize paintSize = RoundedToInt(LayerSize(bounds.Width() * scale.width, bounds.Height() * scale.height));
-  if (paintSize.width == 0 || paintSize.height == 0) {
-    return nullptr;
-  }
+  LayoutDeviceToLayerScale2D layerScale(scale.width, scale.height);
+  auto scaledBounds = bounds * layerScale;
+  auto dtRect = RoundedOut(scaledBounds);
+  auto dtSize = dtRect.Size();
 
-  // Some display item may draw exceed the paintSize, we need prepare a larger
-  // draw target to contain the result.
-  auto scaledBounds = bounds * LayoutDeviceToLayerScale(1);
-  scaledBounds.Scale(scale.width, scale.height);
-  LayerIntSize dtSize = RoundedToInt(scaledBounds).Size();
+  aImageRect = dtRect / layerScale;
 
-  // TODO Rounding a rect to integers and then taking the size gives a different behavior than
-  // just rounding the size of the rect to integers. This can cause a crash, but fixing the
-  // difference causes some test failures so this is a quick fix
-  if (dtSize.width <= 0 || dtSize.height <= 0) {
-    return nullptr;
-  }
+  auto offset = aImageRect.TopLeft();
+
+  nsDisplayItemGeometry* geometry = fallbackData->GetGeometry();
 
   bool needPaint = true;
-  LayoutDeviceIntPoint offset = RoundedToInt(bounds.TopLeft());
-  aImageRect = LayoutDeviceRect(offset, LayoutDeviceSize(RoundedToInt(bounds).Size()));
-  LayerRect paintRect = LayerRect(LayerPoint(0, 0), LayerSize(paintSize));
-  nsDisplayItemGeometry* geometry = fallbackData->GetGeometry();
 
   // nsDisplayFilters is rendered via BasicLayerManager which means the invalidate
   // region is unknown until we traverse the displaylist contained by it.
   if (geometry && !fallbackData->IsInvalid() &&
       aItem->GetType() != DisplayItemType::TYPE_FILTER &&
       aItem->GetType() != DisplayItemType::TYPE_SVG_WRAPPER &&
       differentScale) {
     nsRect invalid;
@@ -1917,19 +1907,19 @@ WebRenderCommandBuilder::GenerateFallbac
           fonts = std::move(aScaledFonts);
         });
       RefPtr<gfx::DrawTarget> dummyDt =
         gfx::Factory::CreateDrawTarget(gfx::BackendType::SKIA, gfx::IntSize(1, 1), format);
       RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateRecordingDrawTarget(recorder, dummyDt, dtSize.ToUnknownSize());
       if (!fallbackData->mBasicLayerManager) {
         fallbackData->mBasicLayerManager = new BasicLayerManager(BasicLayerManager::BLM_INACTIVE);
       }
-      bool isInvalidated = PaintItemByDrawTarget(aItem, dt, paintRect, offset, aDisplayListBuilder,
+      bool isInvalidated = PaintItemByDrawTarget(aItem, dt, offset, aDisplayListBuilder,
                                                  fallbackData->mBasicLayerManager, scale, highlight);
-      recorder->FlushItem(IntRect(0, 0, paintSize.width, paintSize.height));
+      recorder->FlushItem(IntRect({ 0, 0 }, dtSize.ToUnknownSize()));
       TakeExternalSurfaces(recorder, fallbackData->mExternalSurfaces, mManager, aResources);
       recorder->Finish();
 
       if (isInvalidated) {
         Range<uint8_t> bytes((uint8_t *)recorder->mOutputStream.mData, recorder->mOutputStream.mLength);
         wr::ImageKey key = mManager->WrBridge()->GetNextImageKey();
         wr::ImageDescriptor descriptor(dtSize.ToUnknownSize(), 0, dt->GetFormat(), opacity);
         if (!aResources.AddBlobImage(key, descriptor, bytes)) {
@@ -1955,17 +1945,17 @@ WebRenderCommandBuilder::GenerateFallbac
         {
           RefPtr<gfx::DrawTarget> dt = helper.GetDrawTarget();
           if (!dt) {
             return nullptr;
           }
           if (!fallbackData->mBasicLayerManager) {
             fallbackData->mBasicLayerManager = new BasicLayerManager(mManager->GetWidget());
           }
-          isInvalidated = PaintItemByDrawTarget(aItem, dt, paintRect, offset,
+          isInvalidated = PaintItemByDrawTarget(aItem, dt, offset,
                                                 aDisplayListBuilder,
                                                 fallbackData->mBasicLayerManager, scale,
                                                 highlight);
         }
 
         if (isInvalidated) {
           // Update image if there it's invalidated.
           if (!helper.UpdateImage()) {
@@ -2013,17 +2003,17 @@ WebRenderCommandBuilder::BuildWrMaskImag
                                                                     aSc, aDisplayListBuilder,
                                                                     imageRect);
   if (!fallbackData) {
     return Nothing();
   }
 
   wr::WrImageMask imageMask;
   imageMask.image = fallbackData->GetKey().value();
-  imageMask.rect = wr::ToRoundedLayoutRect(aBounds);
+  imageMask.rect = wr::ToRoundedLayoutRect(imageRect);
   imageMask.repeat = false;
   return Some(imageMask);
 }
 
 bool
 WebRenderCommandBuilder::PushItemAsImage(nsDisplayItem* aItem,
                                          wr::DisplayListBuilder& aBuilder,
                                          wr::IpcResourceUpdateQueue& aResources,
--- a/js/src/builtin/Stream.cpp
+++ b/js/src/builtin/Stream.cpp
@@ -835,17 +835,17 @@ ReadableStream_cancel(JSContext* cx, uns
     }
 
     Rooted<ReadableStream*> stream(cx, &args.thisv().toObject().as<ReadableStream>());
 
     // Step 2: If ! IsReadableStreamLocked(this) is true, return a promise
     //         rejected with a TypeError exception.
     if (stream->locked()) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
-                                  JSMSG_READABLESTREAM_NOT_LOCKED, "cancel");
+                                  JSMSG_READABLESTREAM_LOCKED_METHOD, "cancel");
         return ReturnPromiseRejectedWithPendingError(cx, args);
     }
 
     // Step 3: Return ! ReadableStreamCancel(this, reason).
     RootedObject cancelPromise(cx, ReadableStream::cancel(cx, stream, args.get(0)));
     if (!cancelPromise) {
         return false;
     }
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -635,17 +635,17 @@ MSG_DEF(JSMSG_GET_ASYNC_ITER_RETURNED_PR
 
 // ReadableStream
 MSG_DEF(JSMSG_READABLESTREAM_UNDERLYINGSOURCE_TYPE_WRONG,0, JSEXN_RANGEERR,"'underlyingSource.type' must be \"bytes\" or undefined.")
 MSG_DEF(JSMSG_READABLESTREAM_INVALID_READER_MODE,        0, JSEXN_RANGEERR,"'mode' must be \"byob\" or undefined.")
 MSG_DEF(JSMSG_NUMBER_MUST_BE_FINITE_NON_NEGATIVE, 1, JSEXN_RANGEERR, "'{0}' must be a finite, non-negative number.")
 MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_INVALID_BYTESWRITTEN, 0, JSEXN_RANGEERR, "'bytesWritten' exceeds remaining length.")
 MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_INVALID_VIEW_SIZE, 0, JSEXN_RANGEERR, "view size does not match requested data.")
 MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_INVALID_VIEW_OFFSET, 0, JSEXN_RANGEERR, "view offset does not match requested position.")
-MSG_DEF(JSMSG_READABLESTREAM_NOT_LOCKED,                 1, JSEXN_TYPEERR, "'{0}' may only be called on a locked stream.")
+MSG_DEF(JSMSG_READABLESTREAM_LOCKED_METHOD,              1, JSEXN_TYPEERR, "'{0}' can't be called on a locked stream.")
 MSG_DEF(JSMSG_READABLESTREAM_LOCKED,                     0, JSEXN_TYPEERR, "A Reader may only be created for an unlocked ReadableStream.")
 MSG_DEF(JSMSG_READABLESTREAM_NOT_BYTE_STREAM_CONTROLLER, 1, JSEXN_TYPEERR, "{0} requires a ReadableByteStreamController.")
 MSG_DEF(JSMSG_READABLESTREAM_NOT_DEFAULT_CONTROLLER,     1, JSEXN_TYPEERR, "{0} requires a ReadableStreamDefaultController.")
 MSG_DEF(JSMSG_READABLESTREAM_CONTROLLER_SET,             0, JSEXN_TYPEERR, "The ReadableStream already has a controller defined.")
 MSG_DEF(JSMSG_READABLESTREAMREADER_NOT_OWNED,            1, JSEXN_TYPEERR, "The ReadableStream reader method '{0}' may only be called on a reader owned by a stream.")
 MSG_DEF(JSMSG_READABLESTREAMREADER_NOT_EMPTY,            1, JSEXN_TYPEERR, "The ReadableStream reader method '{0}' may not be called on a reader with read requests.")
 MSG_DEF(JSMSG_READABLESTREAMBYOBREADER_READ_EMPTY_VIEW,  0, JSEXN_TYPEERR, "ReadableStreamBYOBReader.read() was passed an empty TypedArrayBuffer view.")
 MSG_DEF(JSMSG_READABLESTREAMREADER_RELEASED,             0, JSEXN_TYPEERR, "The ReadableStream reader was released.")
--- a/layout/reftests/border-image/reftest.list
+++ b/layout/reftests/border-image/reftest.list
@@ -7,17 +7,17 @@
 # clipping on Windows. (Any other fix would have a significant perf cost.)
 fuzzy-if(winWidget,0-1,0-1) == multicolor-image-2.html multicolor-image-2-ref.html
 == multicolor-image-3.html multicolor-image-3-ref.html
 == multicolor-image-4.html multicolor-image-4-ref.html
 == multicolor-image-5.html multicolor-image-5-ref.html
 == transparent-image-1.html transparent-image-1-ref.html
 != repeat-image-1.html repeat-image-1-ref.html
 fuzzy-if(webrender,15-15,975-986) == 470250-1.html 470250-1-ref.html
-fuzzy-if(webrender,15-15,975-986) == 470250-2.html 470250-2-ref.html
+fuzzy-if(webrender,15-233,975-1073) == 470250-2.html 470250-2-ref.html
 != different-h-v-1.html different-h-v-ref.html
 != different-h-v-2.html different-h-v-ref.html
 != different-h-v-1.html different-h-v-2.html
 == center-scaling-1.html center-scaling-1-ref.html
 fails-if(Android) fails-if(usesRepeatResampling) fuzzy-if(webrender&&cocoaWidget,1-1,3280-3280) == center-scaling-2.html center-scaling-2-ref.html # Android: very different scaling (blurriness) on some sides
 fails-if(Android) fails-if(usesRepeatResampling) fuzzy-if(webrender&&cocoaWidget,1-1,4752-4752) == center-scaling-3.html center-scaling-3-ref.html # Android: very different scaling (blurriness) on some sides
 == center-scaling-4t.html center-scaling-4t-ref.html
 == center-scaling-4r.html center-scaling-4r-ref.html
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1415,18 +1415,18 @@ random == 508816-1.xul 508816-1-ref.xul 
 pref(layout.css.xul-box-display-values.content.enabled,true) == 508816-2.html 508816-2-ref.html
 skip-if(isDebugBuild) == 508908-1.xul 508908-1-ref.xul
 == 508919-1.xhtml 508919-1-ref.xhtml
 == 509155-1.xhtml 509155-1-ref.xhtml
 fuzzy-if(Android,0-5,0-1656) fuzzy-if(skiaContent,0-1,0-1200) == 512410.html 512410-ref.html
 == 512631-1.html 512631-1-ref.html
 == 513153-1a.html 513153-1-ref.html
 == 513153-1b.html 513153-1-ref.html
-== 513153-2a.html 513153-2-ref.html
-fuzzy-if(webrender&&cocoaWidget,5-5,106-106) == 513153-2b.html 513153-2-ref.html
+fuzzy-if(webrender&&winWidget,82-82,76-76) == 513153-2a.html 513153-2-ref.html
+fuzzy-if(webrender&&cocoaWidget,34-34,103-103) == 513153-2b.html 513153-2-ref.html
 == 513318-1.xul 513318-1-ref.xul
 fails-if(Android&&(!asyncPan)) != 513318-2.xul 513318-2-ref.xul
 == 514917-1.html 514917-1-ref.html
 == 518172-1a.html 518172-a-ref.html
 fuzzy-if(winWidget,0-73,0-133) fuzzy-if(cocoaWidget,0-103,0-133) == 518172-1b.html 518172-b-ref.html
 == 518172-2a.html 518172-a-ref.html
 fuzzy-if(winWidget,0-73,0-133) fuzzy-if(cocoaWidget,0-103,0-133) == 518172-2b.html 518172-b-ref.html
 == 520421-1.html 520421-1-ref.html
--- a/layout/reftests/forms/input/range/reftest.list
+++ b/layout/reftests/forms/input/range/reftest.list
@@ -9,23 +9,23 @@ fuzzy-if(skiaContent,0-1,0-40) == to-ran
 == from-range-to-other-type-unthemed-1.html from-range-to-other-type-unthemed-1-ref.html
 
 # for different values:
 != different-fraction-of-range-unthemed-1.html different-fraction-of-range-unthemed-1-notref.html
 == same-fraction-of-range-unthemed-1.html same-fraction-of-range-unthemed-1-ref.html
 
 # dynamic value changes:
 fuzzy-if(skiaContent,0-1,0-40) == value-prop-unthemed.html 75pct-unthemed-common-ref.html
-== value-prop.html 75pct-common-ref.html
+fuzzy-if(webrender&&gtkWidget,96-96,163-163) == value-prop.html 75pct-common-ref.html
 fuzzy-if(skiaContent,0-1,0-40) == valueAsNumber-prop-unthemed.html 75pct-unthemed-common-ref.html
-== valueAsNumber-prop.html 75pct-common-ref.html
+fuzzy-if(webrender&&gtkWidget,96-96,163-163) == valueAsNumber-prop.html 75pct-common-ref.html
 fuzzy-if(skiaContent,0-1,0-40) == stepDown-unthemed.html 75pct-unthemed-common-ref.html
-== stepDown.html 75pct-common-ref.html
+fuzzy-if(webrender&&gtkWidget,96-96,163-163) == stepDown.html 75pct-common-ref.html
 fuzzy-if(skiaContent,0-1,0-40) == stepUp-unthemed.html 75pct-unthemed-common-ref.html
-== stepUp.html 75pct-common-ref.html
+fuzzy-if(webrender&&gtkWidget,96-96,163-163) == stepUp.html 75pct-common-ref.html
 == max-prop.html 100pct-common-ref.html
 == reset-value.html reset-value-ref.html
 
 # 'direction' property:
 == direction-unthemed-1.html direction-unthemed-1-ref.html
 
 # ::-moz-range-progress pseudo-element:
 == moz-range-progress-1.html moz-range-progress-1-ref.html
--- a/layout/reftests/mathml/reftest.list
+++ b/layout/reftests/mathml/reftest.list
@@ -369,17 +369,17 @@ fuzzy-if(OSX,0-1,0-100) fuzzy-if(skiaCon
 == mfrac-E-1.html mfrac-E-1-ref.html
 test-pref(dom.webcomponents.shadowdom.enabled,true) == shadow-dom-1.html shadow-dom-1-ref.html
 pref(dom.meta-viewport.enabled,true) pref(font.size.inflation.emPerLine,25) fuzzy-if(webrender&&!gtkWidget,0-255,0-244) == font-inflation-1.html font-inflation-1-ref.html
 test-pref(font.minimum-size.x-math,40) == default-font.html default-font-ref.html
 != radicalbar-1.html about:blank
 != radicalbar-1a.html about:blank
 != radicalbar-1b.html about:blank
 != radicalbar-1c.html about:blank
-fails-if(webrender&&gtkWidget) != radicalbar-1d.html about:blank
+!= radicalbar-1d.html about:blank
 != radicalbar-2.html about:blank
 != radicalbar-2a.html about:blank
 != radicalbar-2b.html about:blank
 != radicalbar-2c.html about:blank
 != radicalbar-2d.html about:blank
 != radicalbar-3.html about:blank
 != radicalbar-3a.html about:blank
 != radicalbar-3b.html about:blank
--- a/layout/reftests/text-overflow/reftest.list
+++ b/layout/reftests/text-overflow/reftest.list
@@ -1,14 +1,14 @@
 == ellipsis-font-fallback.html ellipsis-font-fallback-ref.html
 == line-clipping.html line-clipping-ref.html
 fuzzy-if(Android,0-16,0-244) fuzzy-if(webrender,0-47,0-6) == marker-basic.html marker-basic-ref.html  # Bug 1128229
 == marker-string.html marker-string-ref.html
 skip-if(Android) fuzzy-if(webrender,0-47,0-18) == bidi-simple.html bidi-simple-ref.html # Fails on Android due to anti-aliasing
-skip-if(!gtkWidget) fuzzy-if(gtkWidget,0-2,0-289) == bidi-simple-scrolled.html bidi-simple-scrolled-ref.html # Fails on Windows and OSX due to anti-aliasing
+skip-if(!gtkWidget) fuzzy-if(gtkWidget,0-124,0-289) == bidi-simple-scrolled.html bidi-simple-scrolled-ref.html # Fails on Windows and OSX due to anti-aliasing
 fuzzy-if(Android,0-24,0-4000) fuzzy-if(cocoaWidget,0-1,0-40) fuzzy-if(asyncPan&&!layersGPUAccelerated,0-149,0-1836) == scroll-rounding.html scroll-rounding-ref.html # bug 760264
 fuzzy(0-16,0-454) fails-if(gtkWidget) fuzzy-if(webrender&&!gtkWidget,50-85,459-499) skip-if(OSX&&!isDebugBuild&&verify) == anonymous-block.html anonymous-block-ref.html # gtkWidget:bug 1309103, fuzzy: subpixel aa
 fuzzy-if(webrender,0-47,0-3) == false-marker-overlap.html false-marker-overlap-ref.html
 == visibility-hidden.html visibility-hidden-ref.html
 fuzzy-if(asyncPan&&!layersGPUAccelerated,0-102,0-1724) fuzzy-if(gtkWidget,0-10,0-8) fuzzy-if(webrender,0-47,0-24) == block-padding.html block-padding-ref.html
 fuzzy-if(webrender,0-3,0-825) == quirks-decorations.html quirks-decorations-ref.html
 == quirks-line-height.html quirks-line-height-ref.html
 == standards-decorations.html standards-decorations-ref.html
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -715,41 +715,29 @@ VARCACHE_PREF(
 VARCACHE_PREF(
   "layout.css.xul-display-values.content.enabled",
    layout_css_xul_display_values_content_enabled,
   bool, false
 )
 
 // Pref to control whether display: -moz-box and display: -moz-inline-box are
 // parsed in content pages.
-#ifdef EARLY_BETA_OR_EARLIER
-#define PREF_VALUE false
-#else
-#define PREF_VALUE true
-#endif
 VARCACHE_PREF(
   "layout.css.xul-box-display-values.content.enabled",
    layout_css_xul_box_display_values_content_enabled,
-  bool, PREF_VALUE
+  bool, false
 )
-#undef PREF_VALUE
 
 // Pref to control whether ::xul-tree-* pseudo-elements are parsed in content
 // pages.
-#ifdef EARLY_BETA_OR_EARLIER
-#define PREF_VALUE false
-#else
-#define PREF_VALUE true
-#endif
 VARCACHE_PREF(
   "layout.css.xul-tree-pseudos.content.enabled",
    layout_css_xul_tree_pseudos_content_enabled,
-  bool, PREF_VALUE
+  bool, false
 )
-#undef PREF_VALUE
 
 // Is support for CSS "grid-template-{columns,rows}: subgrid X" enabled?
 VARCACHE_PREF(
   "layout.css.grid-template-subgrid-value.enabled",
    layout_css_grid_template_subgrid_value_enabled,
   bool, false
 )