Merge inbound to mozilla-central. a=merge
authorGurzau Raul <rgurzau@mozilla.com>
Fri, 16 Nov 2018 19:08:39 +0200
changeset 503207 d6ac0dc85306b753c1d1d5f3084f73f0d1286b86
parent 503189 8c5eaa1d4356ff8a4cd295f43d89f82d375bcc1b (current diff)
parent 503206 6c28ad7f98a7629f5a1b2f123aaad66f1f6233f0 (diff)
child 503208 71ba7cfafa54a4b458abd2b1962a0bee4011173b
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
toolkit/content/components.css
widget/windows/nsImageClipboard.cpp
widget/windows/nsImageClipboard.h
--- a/browser/extensions/formautofill/test/unit/xpcshell.ini
+++ b/browser/extensions/formautofill/test/unit/xpcshell.ini
@@ -1,11 +1,10 @@
 [DEFAULT]
 firefox-appdir = browser
-headless = true
 head = head.js
 support-files =
   ../fixtures/**
 
 [heuristics/test_basic.js]
 [heuristics/test_cc_exp.js]
 [heuristics/test_de_fields.js]
 [heuristics/test_multiple_section.js]
--- a/devtools/client/inspector/flexbox/flexbox.js
+++ b/devtools/client/inspector/flexbox/flexbox.js
@@ -337,16 +337,18 @@ class FlexboxInspector {
     this.store.dispatch(updateFlexboxColor(color));
 
     const { flexbox } = this.store.getState();
 
     if (flexbox.highlighted) {
       this.highlighters.showFlexboxHighlighter(flexbox.flexContainer.nodeFront);
     }
 
+    this._overlayColor = color;
+
     const currentUrl = this.inspector.target.url;
     // Get the hostname, if there is no hostname, fall back on protocol
     // ex: `data:` uri, and `about:` pages
     const hostname = parseURL(currentUrl).hostname || parseURL(currentUrl).protocol;
     const customColors = await this.getCustomHostColors();
     customColors[hostname] = color;
     this._customHostColors = customColors;
     await asyncStorage.setItem("flexboxInspectorHostColors", customColors);
--- a/dom/canvas/WebGLContextExtensions.cpp
+++ b/dom/canvas/WebGLContextExtensions.cpp
@@ -117,23 +117,19 @@ WebGLContext::IsExtensionSupported(WebGL
     if (mDisableExtensions)
         return false;
 
     // Extensions for both WebGL 1 and 2.
     switch (ext) {
     // In alphabetical order
     // EXT_
     case WebGLExtensionID::EXT_texture_compression_bptc:
-        if (!gfxPrefs::WebGLDraftExtensionsEnabled())
-            return false;
         return WebGLExtensionCompressedTextureBPTC::IsSupported(this);
 
     case WebGLExtensionID::EXT_texture_compression_rgtc:
-        if (!gfxPrefs::WebGLDraftExtensionsEnabled())
-            return false;
         return WebGLExtensionCompressedTextureRGTC::IsSupported(this);
 
     case WebGLExtensionID::EXT_texture_filter_anisotropic:
         return gl->IsExtensionSupported(gl::GLContext::EXT_texture_filter_anisotropic);
 
     // OES_
     case WebGLExtensionID::OES_texture_float_linear:
         return gl->IsSupported(gl::GLFeature::texture_float_linear);
--- a/dom/canvas/test/webgl-mochitest/ensure-exts/test_EXT_texture_compression_bptc.html
+++ b/dom/canvas/test/webgl-mochitest/ensure-exts/test_EXT_texture_compression_bptc.html
@@ -5,16 +5,13 @@
     <script src='/tests/SimpleTest/SimpleTest.js'></script>
     <link rel='stylesheet' href='/tests/SimpleTest/test.css'>
     <script src='ensure-ext.js'></script>
   </head>
   <body>
     <script>
 
 'use strict';
-EnsureExt('EXT_texture_compression_bptc', false);
+EnsureExt('EXT_texture_compression_bptc');
 
-Lastly_WithDraftExtsEnabled(() => {
-  EnsureExt('EXT_texture_compression_bptc', true);
-});
     </script>
   </body>
 </html>
--- a/dom/canvas/test/webgl-mochitest/ensure-exts/test_EXT_texture_compression_rgtc.html
+++ b/dom/canvas/test/webgl-mochitest/ensure-exts/test_EXT_texture_compression_rgtc.html
@@ -5,17 +5,13 @@
     <script src='/tests/SimpleTest/SimpleTest.js'></script>
     <link rel='stylesheet' href='/tests/SimpleTest/test.css'>
     <script src='ensure-ext.js'></script>
   </head>
   <body>
     <script>
 
 'use strict';
-EnsureExt('EXT_texture_compression_rgtc', false);
-
-Lastly_WithDraftExtsEnabled(() => {
-  EnsureExt('EXT_texture_compression_rgtc', true);
-});
+EnsureExt('EXT_texture_compression_rgtc');
 
     </script>
   </body>
 </html>
--- a/dom/canvas/test/webgl-mochitest/ensure-exts/test_common.html
+++ b/dom/canvas/test/webgl-mochitest/ensure-exts/test_common.html
@@ -36,28 +36,28 @@ var defaultExts = [
     ['WEBGL_draw_buffers'            , [MACHINE_SPECIFIC, FORBID          ]],
     ['WEBGL_lose_context'            , [ENSURE          , ENSURE          ]],
 
     // Community Approved
     ['EXT_color_buffer_float'            , [FORBID          , ENSURE          ]],
     ['EXT_color_buffer_half_float'       , [MACHINE_SPECIFIC, FORBID          ]],
     ['EXT_disjoint_timer_query'          , [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
     ['EXT_sRGB'                          , [MACHINE_SPECIFIC, FORBID          ]],
+    ['EXT_texture_compression_bptc'      , [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
+    ['EXT_texture_compression_rgtc'      , [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
     ['WEBGL_color_buffer_float'          , [MACHINE_SPECIFIC, FORBID          ]],
     ['WEBGL_compressed_texture_astc'     , [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
     ['WEBGL_compressed_texture_atc'      , [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
     ['WEBGL_compressed_texture_etc'      , [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
     ['WEBGL_compressed_texture_etc1'     , [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
     ['WEBGL_compressed_texture_pvrtc'    , [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
     ['WEBGL_compressed_texture_s3tc_srgb', [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
 ];
 
 var draftExts = [
-    ['EXT_texture_compression_bptc', [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
-    ['EXT_texture_compression_rgtc', [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
 ];
 
 var nonImplementedExts = [
     'OES_fbo_render_mipmap',
     'WEBGL_security_sensitive_resources',
     'WEBGL_shared_resources',
 ];
 
--- a/dom/indexedDB/test/mochitest.ini
+++ b/dom/indexedDB/test/mochitest.ini
@@ -23,16 +23,17 @@ support-files =
   unit/test_add_put.js
   unit/test_add_twice_failure.js
   unit/test_advance.js
   unit/test_autoIncrement.js
   unit/test_autoIncrement_indexes.js
   unit/test_blob_file_backed.js
   unit/test_blocked_order.js
   unit/test_clear.js
+  unit/test_clone_before_key_evaluation.js
   unit/test_complex_keyPaths.js
   unit/test_constraint_error_messages.js
   unit/test_count.js
   unit/test_create_index.js
   unit/test_create_index_with_integer_keys.js
   unit/test_create_locale_aware_index.js
   unit/test_create_objectStore.js
   unit/test_cursor_mutation.js
@@ -133,16 +134,17 @@ skip-if = e10s && os == 'win' && os_vers
 skip-if = (e10s && os == 'win' && os_version == '6.1') || (verify && (os == 'win')) # Bug 1342415
 [test_blob_worker_xhr_post_multifile.html]
 skip-if = e10s && os == 'win' && os_version == '6.1' # Bug 1342415
 [test_blob_worker_xhr_read.html]
 [test_blob_worker_xhr_read_slice.html]
 [test_blocked_order.html]
 [test_bug937006.html]
 [test_clear.html]
+[test_clone_before_key_evaluation.html]
 [test_complex_keyPaths.html]
 [test_constraint_error_messages.html]
 [test_count.html]
 [test_create_index.html]
 [test_create_index_with_integer_keys.html]
 [test_create_objectStore.html]
 [test_cursor_mutation.html]
 [test_cursor_update_updates_indexes.html]
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/test_clone_before_key_evaluation.html
@@ -0,0 +1,18 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>Indexed Database Test</title>
+
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+  <script type="text/javascript" src="unit/test_clone_before_key_evaluation.js"></script>
+  <script type="text/javascript" src="helpers.js"></script>
+</head>
+
+<body onload="runTest();"></body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/unit/test_clone_before_key_evaluation.js
@@ -0,0 +1,131 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var testGenerator = testSteps();
+
+function* testSteps()
+{
+  const name = this.window ? window.location.pathname
+                           : "test_clone_before_key_evaluation.js";
+  const objectStoreInfo = {
+    name: "customers",
+    options: { keyPath: "ssn" },
+  };
+  const indexInfo = {
+    name: "customerIndex",
+    keyPath: ["id", "email", "name"],
+    options: { unique: false },
+  };
+
+  for (let test of [1, 2]) {
+    info("Opening database");
+
+    let request = indexedDB.open(name);
+    request.onerror = errorHandler;
+    request.onupgradeneeded = continueToNextStepSync;
+    request.onsuccess = unexpectedSuccessHandler;
+    yield undefined;
+
+    // upgradeneeded
+
+    request.onupgradeneeded = unexpectedSuccessHandler;
+    request.onsuccess = continueToNextStepSync;
+
+    let db = request.result;
+    db.onerror = errorHandler;
+
+    info("Creating objectStore");
+
+    let objectStore = db.createObjectStore(objectStoreInfo.name,
+                                           objectStoreInfo.options);
+
+    info("Creating index");
+
+    objectStore.createIndex(indexInfo.name,
+                            indexInfo.keyPath,
+                            indexInfo.options);
+
+    switch (test) {
+      case 1: {
+        info("Adding data with a getter");
+
+        let idCount = 0;
+
+        const customerData = {
+          ssn: "444-44-4444", name: "Bill", age: 25, email: "bill@company.com",
+          get id()
+          {
+            idCount++;
+            objectStore.deleteIndex(indexInfo.name);
+            return "ID_001";
+          },
+        };
+
+        objectStore.add(customerData);
+
+        ok(idCount == 1, "Getter was called only once");
+
+        ok(objectStore.indexNames.length == 0, "Index was removed");
+
+        break;
+      }
+
+      case 2: {
+        info("Adding data with a prototype getter");
+
+        let idCount = 0;
+
+        const customerData = {
+          ssn: "555-55-5555", name: "Joe", age: 52, email: "joe@company.com",
+        };
+
+        Object.defineProperty(Object.prototype, "id", {
+          get() {
+            idCount++;
+            objectStore.deleteIndex(indexInfo.name);
+            return "ID_002";
+          },
+          enumerable: false,
+          configurable: true,
+        });
+
+        objectStore.add(customerData);
+
+        ok(idCount == 0, "Prototype getter was not called");
+
+        // Paranoid checks, just to be sure that the protype getter is called
+        // in standard JS.
+
+        let id = customerData.id;
+
+        ok(id == "ID_002", "Prototype getter returned correct value");
+        ok(idCount == 1, "Prototype getter was called only once");
+
+        delete Object.prototype.id;
+
+        id = customerData.id;
+
+        ok(id == undefined, "Prototype getter was removed");
+
+        ok(objectStore.indexNames.length == 0, "Index was removed");
+
+        break;
+      }
+    }
+
+    yield undefined;
+
+    // success
+
+    db.close();
+
+    request = indexedDB.deleteDatabase(name);
+    request.onerror = errorHandler;
+    request.onsuccess = continueToNextStepSync;
+    yield undefined;
+  }
+
+  finishTest();
+}
--- a/dom/indexedDB/test/unit/xpcshell-shared.ini
+++ b/dom/indexedDB/test/unit/xpcshell-shared.ini
@@ -6,16 +6,17 @@
 [test_abort_deleted_objectStore.js]
 [test_add_put.js]
 [test_add_twice_failure.js]
 [test_advance.js]
 [test_autoIncrement.js]
 [test_autoIncrement_indexes.js]
 [test_blocked_order.js]
 [test_clear.js]
+[test_clone_before_key_evaluation.js]
 [test_complex_keyPaths.js]
 [test_count.js]
 [test_create_index.js]
 [test_create_index_with_integer_keys.js]
 [test_create_locale_aware_index.js]
 skip-if = toolkit == 'android' # bug 864843
 [test_create_objectStore.js]
 [test_cursor_cycle.js]
--- a/gfx/layers/wr/AsyncImagePipelineManager.cpp
+++ b/gfx/layers/wr/AsyncImagePipelineManager.cpp
@@ -30,16 +30,24 @@ AsyncImagePipelineManager::ForwardingExt
 AsyncImagePipelineManager::AsyncImagePipeline::AsyncImagePipeline()
  : mInitialised(false)
  , mIsChanged(false)
  , mUseExternalImage(false)
  , mFilter(wr::ImageRendering::Auto)
  , mMixBlendMode(wr::MixBlendMode::Normal)
 {}
 
+AsyncImagePipelineManager::PipelineUpdates::PipelineUpdates(RefPtr<wr::WebRenderPipelineInfo> aPipelineInfo,
+                                                            const uint64_t aUpdatesCount,
+                                                            const bool aRendered)
+  : mPipelineInfo(aPipelineInfo)
+  , mUpdatesCount(aUpdatesCount)
+  , mRendered(aRendered)
+{}
+
 AsyncImagePipelineManager::AsyncImagePipelineManager(already_AddRefed<wr::WebRenderAPI>&& aApi)
  : mApi(aApi)
  , mIdNamespace(mApi->GetNamespace())
  , mUseTripleBuffering(mApi->GetUseTripleBuffering())
  , mResourceId(0)
  , mAsyncImageEpoch{0}
  , mWillGenerateFrame(false)
  , mDestroyed(false)
@@ -548,36 +556,25 @@ AsyncImagePipelineManager::HoldExternalI
     return;
   }
 
   auto image = MakeUnique<ForwardingExternalImage>(aEpoch, aImageId);
   holder->mExternalImages.push(std::move(image));
 }
 
 void
-AsyncImagePipelineManager::NotifyPipelinesUpdated(const wr::WrPipelineInfo& aInfo, bool aRender)
+AsyncImagePipelineManager::NotifyPipelinesUpdated(RefPtr<wr::WebRenderPipelineInfo> aInfo, bool aRender)
 {
   // This is called on the render thread, so we just stash the data into
   // UpdatesQueue and process it later on the compositor thread.
   MOZ_ASSERT(wr::RenderThread::IsInRenderThread());
 
   // Increment the count when render happens.
   uint64_t currCount = aRender ? ++mUpdatesCount : mUpdatesCount;
-  auto updates = MakeUnique<PipelineUpdates>(currCount, aRender);
-
-  for (uintptr_t i = 0; i < aInfo.epochs.length; i++) {
-    updates->mQueue.emplace(std::make_pair(
-        aInfo.epochs.data[i].pipeline_id,
-        Some(aInfo.epochs.data[i].epoch)));
-  }
-  for (uintptr_t i = 0; i < aInfo.removed_pipelines.length; i++) {
-    updates->mQueue.emplace(std::make_pair(
-        aInfo.removed_pipelines.data[i],
-        Nothing()));
-  }
+  auto updates = MakeUnique<PipelineUpdates>(aInfo, currCount, aRender);
 
   {
     // Scope lock to push UpdatesQueue to mUpdatesQueues.
     MutexAutoLock lock(mUpdatesLock);
     mUpdatesQueues.push(std::move(updates));
   }
 
   if (!aRender) {
@@ -599,23 +596,17 @@ AsyncImagePipelineManager::ProcessPipeli
 
   if (mDestroyed) {
     return;
   }
 
   UniquePtr<PipelineUpdates> updates;
 
   while (true) {
-    // Clear updates if it is empty. It is a preparation for next PipelineUpdates handling.
-    if (updates && updates->mQueue.empty()) {
-      updates = nullptr;
-    }
-
-    // Get new PipelineUpdates if necessary.
-    if (!updates) {
+    {
       // Scope lock to extract UpdatesQueue from mUpdatesQueues.
       MutexAutoLock lock(mUpdatesLock);
       if (mUpdatesQueues.empty()) {
         // No more PipelineUpdates to process for now.
         break;
       }
       // Check if PipelineUpdates is ready to process.
       uint64_t currCount = mUpdatesCount;
@@ -623,29 +614,26 @@ AsyncImagePipelineManager::ProcessPipeli
         // PipelineUpdates is not ready for processing for now.
         break;
       }
       updates = std::move(mUpdatesQueues.front());
       mUpdatesQueues.pop();
     }
     MOZ_ASSERT(updates);
 
-    if (updates->mQueue.empty()) {
-      // Try next PipelineUpdates.
-      continue;
-    }
+    auto& info = updates->mPipelineInfo->Raw();
 
-    wr::PipelineId pipelineId = updates->mQueue.front().first;
-    Maybe<wr::Epoch> epoch = updates->mQueue.front().second;
-    updates->mQueue.pop();
-
-    if (epoch.isSome()) {
-      ProcessPipelineRendered(pipelineId, *epoch, updates->mUpdatesCount);
-    } else {
-      ProcessPipelineRemoved(pipelineId, updates->mUpdatesCount);
+    for (uintptr_t i = 0; i < info.epochs.length; i++) {
+      ProcessPipelineRendered(info.epochs.data[i].pipeline_id,
+                              info.epochs.data[i].epoch,
+                              updates->mUpdatesCount);
+    }
+    for (uintptr_t i = 0; i < info.removed_pipelines.length; i++) {
+      ProcessPipelineRemoved(info.removed_pipelines.data[i],
+                             updates->mUpdatesCount);
     }
   }
   CheckForTextureHostsNotUsedByGPU();
 }
 
 void
 AsyncImagePipelineManager::ProcessPipelineRendered(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, const uint64_t aUpdatesCount)
 {
--- a/gfx/layers/wr/AsyncImagePipelineManager.h
+++ b/gfx/layers/wr/AsyncImagePipelineManager.h
@@ -18,16 +18,17 @@
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "nsClassHashtable.h"
 
 namespace mozilla {
 
 namespace wr {
 class DisplayListBuilder;
 class WebRenderAPI;
+class WebRenderPipelineInfo;
 }
 
 namespace layers {
 
 class CompositableHost;
 class CompositorVsyncScheduler;
 class WebRenderImageHost;
 class WebRenderTextureHost;
@@ -51,17 +52,17 @@ public:
 
   void HoldExternalImage(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, WebRenderTextureHost* aTexture);
   void HoldExternalImage(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, WebRenderTextureHostWrapper* aWrTextureWrapper);
   void HoldExternalImage(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, const wr::ExternalImageId& aImageId);
 
   // This is called from the Renderer thread to notify this class about the
   // pipelines in the most recently completed render. A copy of the update
   // information is put into mUpdatesQueue.
-  void NotifyPipelinesUpdated(const wr::WrPipelineInfo& aInfo, bool aRender);
+  void NotifyPipelinesUpdated(RefPtr<wr::WebRenderPipelineInfo> aInfo, bool aRender);
 
   // This is run on the compositor thread to process mUpdatesQueue. We make
   // this a public entry point because we need to invoke it from other places.
   void ProcessPipelineUpdates();
 
   TimeStamp GetCompositionTime() const {
     return mCompositionTime;
   }
@@ -242,36 +243,30 @@ private:
 
   nsTArray<ImageCompositeNotificationInfo> mImageCompositeNotifications;
 
   // The lock that protects mUpdatesQueue
   Mutex mUpdatesLock;
   // Used for checking if PipelineUpdates could be processed.
   Atomic<uint64_t> mUpdatesCount;
   struct PipelineUpdates {
-    PipelineUpdates(const uint64_t aUpdatesCount, const bool aRendered)
-      : mUpdatesCount(aUpdatesCount)
-      , mRendered(aRendered)
-    {}
+    PipelineUpdates(RefPtr<wr::WebRenderPipelineInfo> aPipelineInfo,
+                    const uint64_t aUpdatesCount,
+                    const bool aRendered);
     bool NeedsToWait(const uint64_t aUpdatesCount) {
       MOZ_ASSERT(mUpdatesCount <= aUpdatesCount);
       if (mUpdatesCount == aUpdatesCount && !mRendered) {
         // RenderTextureHosts related to this might be still used by GPU.
         return true;
       }
       return false;
     }
+    RefPtr<wr::WebRenderPipelineInfo> mPipelineInfo;
     const uint64_t mUpdatesCount;
     const bool mRendered;
-    // Queue to store rendered pipeline epoch information. This is populated from
-    // the Renderer thread after a render, and is read from the compositor thread
-    // to free resources (e.g. textures) that are no longer needed. Each entry
-    // in the queue is a pair that holds the pipeline id and Some(x) for
-    // a render of epoch x, or Nothing() for a removed pipeline.
-    std::queue<std::pair<wr::PipelineId, Maybe<wr::Epoch>>> mQueue;
   };
   std::queue<UniquePtr<PipelineUpdates>> mUpdatesQueues;
 
   // Queue to store TextureHosts that might still be used by GPU.
   std::queue<std::pair<uint64_t, CompositableTextureHostRef>> mTexturesInUseByGPU;
 };
 
 } // namespace layers
--- a/gfx/webrender_bindings/RenderThread.cpp
+++ b/gfx/webrender_bindings/RenderThread.cpp
@@ -420,17 +420,17 @@ RenderThread::UpdateAndRender(wr::Window
   RefPtr<layers::AsyncImagePipelineManager> pipelineMgr =
       renderer->GetCompositorBridge()->GetAsyncImagePipelineManager();
   // pipelineMgr should always be non-null here because it is only nulled out
   // after the WebRenderAPI instance for the CompositorBridgeParent is
   // destroyed, and that destruction blocks until the renderer thread has
   // removed the relevant renderer. And after that happens we should never reach
   // this code at all; it would bail out at the mRenderers.find check above.
   MOZ_ASSERT(pipelineMgr);
-  pipelineMgr->NotifyPipelinesUpdated(info->Raw(), aRender);
+  pipelineMgr->NotifyPipelinesUpdated(info, aRender);
 }
 
 void
 RenderThread::Pause(wr::WindowId aWindowId)
 {
   MOZ_ASSERT(IsInRenderThread());
 
   auto it = mRenderers.find(aWindowId);
--- a/image/DecoderFactory.cpp
+++ b/image/DecoderFactory.cpp
@@ -55,16 +55,20 @@ DecoderFactory::GetDecoderType(const cha
     type = DecoderType::JPEG;
 
   // BMP
   } else if (!strcmp(aMimeType, IMAGE_BMP)) {
     type = DecoderType::BMP;
   } else if (!strcmp(aMimeType, IMAGE_BMP_MS)) {
     type = DecoderType::BMP;
 
+  // BMP_CLIPBOARD
+  } else if (!strcmp(aMimeType, IMAGE_BMP_MS_CLIPBOARD)) {
+    type = DecoderType::BMP_CLIPBOARD;
+
   // ICO
   } else if (!strcmp(aMimeType, IMAGE_ICO)) {
     type = DecoderType::ICO;
   } else if (!strcmp(aMimeType, IMAGE_ICO_MS)) {
     type = DecoderType::ICO;
 
   // Icon
   } else if (!strcmp(aMimeType, IMAGE_ICON_MS)) {
@@ -98,16 +102,19 @@ DecoderFactory::GetDecoder(DecoderType a
       // a progressive decode.
       decoder = new nsJPEGDecoder(aImage,
                                   aIsRedecode ? Decoder::SEQUENTIAL
                                               : Decoder::PROGRESSIVE);
       break;
     case DecoderType::BMP:
       decoder = new nsBMPDecoder(aImage);
       break;
+    case DecoderType::BMP_CLIPBOARD:
+      decoder = new nsBMPDecoder(aImage, /* aForClipboard */ true);
+      break;
     case DecoderType::ICO:
       decoder = new nsICODecoder(aImage);
       break;
     case DecoderType::ICON:
       decoder = new nsIconDecoder(aImage);
       break;
     case DecoderType::WEBP:
       decoder = new nsWebPDecoder(aImage);
--- a/image/DecoderFactory.h
+++ b/image/DecoderFactory.h
@@ -30,16 +30,17 @@ class SourceBufferIterator;
  * DecoderFactory::GetDecoderType().
  */
 enum class DecoderType
 {
   PNG,
   GIF,
   JPEG,
   BMP,
+  BMP_CLIPBOARD,
   ICO,
   ICON,
   WEBP,
   UNKNOWN
 };
 
 class DecoderFactory
 {
--- a/image/decoders/nsBMPDecoder.cpp
+++ b/image/decoders/nsBMPDecoder.cpp
@@ -180,19 +180,21 @@ nsBMPDecoder::nsBMPDecoder(RasterImage* 
   , mPreGapLength(0)
   , mPixelRowSize(0)
   , mCurrentRow(0)
   , mCurrentPos(0)
   , mAbsoluteModeNumPixels(0)
 {
 }
 
-// Constructor for normal BMP files.
-nsBMPDecoder::nsBMPDecoder(RasterImage* aImage)
-  : nsBMPDecoder(aImage, State::FILE_HEADER, FILE_HEADER_LENGTH)
+// Constructor for normal BMP files or from the clipboard.
+nsBMPDecoder::nsBMPDecoder(RasterImage* aImage, bool aForClipboard)
+  : nsBMPDecoder(aImage,
+                 aForClipboard ? State::CLIPBOARD_HEADER : State::FILE_HEADER,
+                 aForClipboard ? BIHSIZE_FIELD_LENGTH : FILE_HEADER_LENGTH)
 {
 }
 
 // Constructor used for WinBMPv3-ICO files, which lack a file header.
 nsBMPDecoder::nsBMPDecoder(RasterImage* aImage, uint32_t aDataOffset)
   : nsBMPDecoder(aImage, State::INFO_HEADER_SIZE, BIHSIZE_FIELD_LENGTH)
 {
   SetIsWithinICO();
@@ -450,16 +452,17 @@ LexerResult
 nsBMPDecoder::DoDecode(SourceBufferIterator& aIterator, IResumable* aOnResume)
 {
   MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!");
 
   return mLexer.Lex(aIterator, aOnResume,
                     [=](State aState, const char* aData, size_t aLength) {
     switch (aState) {
       case State::FILE_HEADER:      return ReadFileHeader(aData, aLength);
+      case State::CLIPBOARD_HEADER: return ReadClipboardHeader(aData, aLength);
       case State::INFO_HEADER_SIZE: return ReadInfoHeaderSize(aData, aLength);
       case State::INFO_HEADER_REST: return ReadInfoHeaderRest(aData, aLength);
       case State::BITFIELDS:        return ReadBitfields(aData, aLength);
       case State::COLOR_TABLE:      return ReadColorTable(aData, aLength);
       case State::GAP:              return SkipGap();
       case State::AFTER_GAP:        return AfterGap();
       case State::PIXEL_ROW:        return ReadPixelRow(aData);
       case State::RLE_SEGMENT:      return ReadRLESegment(aData);
@@ -483,16 +486,24 @@ nsBMPDecoder::ReadFileHeader(const char*
 
   // We ignore the filesize (aData + 2) and reserved (aData + 6) fields.
 
   mH.mDataOffset = LittleEndian::readUint32(aData + 10);
 
   return Transition::To(State::INFO_HEADER_SIZE, BIHSIZE_FIELD_LENGTH);
 }
 
+LexerTransition<nsBMPDecoder::State>
+nsBMPDecoder::ReadClipboardHeader(const char* aData, size_t aLength)
+{
+  // With the clipboard, the data offset is the header length.
+  mH.mDataOffset = LittleEndian::readUint32(aData);
+  return ReadInfoHeaderSize(aData, aLength);
+}
+
 // We read the info header in two steps: (a) read the mBIHSize field to
 // determine how long the header is; (b) read the rest of the header.
 LexerTransition<nsBMPDecoder::State>
 nsBMPDecoder::ReadInfoHeaderSize(const char* aData, size_t aLength)
 {
   mPreGapLength += aLength;
 
   mH.mBIHSize = LittleEndian::readUint32(aData);
--- a/image/decoders/nsBMPDecoder.h
+++ b/image/decoders/nsBMPDecoder.h
@@ -152,44 +152,46 @@ public:
   nsresult BeforeFinishInternal() override;
   nsresult FinishInternal() override;
 
 private:
   friend class DecoderFactory;
 
   enum class State {
     FILE_HEADER,
+    CLIPBOARD_HEADER,
     INFO_HEADER_SIZE,
     INFO_HEADER_REST,
     BITFIELDS,
     COLOR_TABLE,
     GAP,
     AFTER_GAP,
     PIXEL_ROW,
     RLE_SEGMENT,
     RLE_DELTA,
     RLE_ABSOLUTE
   };
 
-  // This is the constructor used for normal BMP images.
-  explicit nsBMPDecoder(RasterImage* aImage);
+  // This is the constructor used for normal and clipboard BMP images.
+  explicit nsBMPDecoder(RasterImage* aImage, bool aForClipboard = false);
 
   // This is the constructor used for BMP resources in ICO images.
   nsBMPDecoder(RasterImage* aImage, uint32_t aDataOffset);
 
   // Helper constructor called by the other two.
   nsBMPDecoder(RasterImage* aImage, State aState, size_t aLength);
 
   int32_t AbsoluteHeight() const { return abs(mH.mHeight); }
 
   uint32_t* RowBuffer();
 
   void FinishRow();
 
   LexerTransition<State> ReadFileHeader(const char* aData, size_t aLength);
+  LexerTransition<State> ReadClipboardHeader(const char* aData, size_t aLength);
   LexerTransition<State> ReadInfoHeaderSize(const char* aData, size_t aLength);
   LexerTransition<State> ReadInfoHeaderRest(const char* aData, size_t aLength);
   LexerTransition<State> ReadBitfields(const char* aData, size_t aLength);
   LexerTransition<State> ReadColorTable(const char* aData, size_t aLength);
   LexerTransition<State> SkipGap();
   LexerTransition<State> AfterGap();
   LexerTransition<State> ReadPixelRow(const char* aData);
   LexerTransition<State> ReadRLESegment(const char* aData);
--- a/js/public/TraceKind.h
+++ b/js/public/TraceKind.h
@@ -63,16 +63,31 @@ enum class TraceKind
     Scope = 0x3F,
     RegExpShared = 0x4F,
 #ifdef ENABLE_BIGINT
     BigInt = 0x5F
 #endif
 };
 const static uintptr_t OutOfLineTraceKindMask = 0x07;
 
+// Returns true if the JS::TraceKind is one the cycle collector cares about.
+// Everything used as WeakMap key should be listed here, to represent the key
+// in cycle collector's graph, otherwise the key is considered to be pointed
+// from somewhere unknown, and results in leaking the subgraph which contains
+// the key.
+// See the comments in NoteWeakMapsTracer::trace for more details.
+inline constexpr bool IsCCTraceKind(JS::TraceKind aKind)
+{
+  return aKind == JS::TraceKind::Object ||
+         aKind == JS::TraceKind::Script ||
+         aKind == JS::TraceKind::LazyScript ||
+         aKind == JS::TraceKind::Scope ||
+         aKind == JS::TraceKind::RegExpShared;
+}
+
 #define ASSERT_TRACE_KIND(tk) \
     static_assert((uintptr_t(tk) & OutOfLineTraceKindMask) == OutOfLineTraceKindMask, \
         "mask bits are set")
 ASSERT_TRACE_KIND(JS::TraceKind::BaseShape);
 ASSERT_TRACE_KIND(JS::TraceKind::JitCode);
 ASSERT_TRACE_KIND(JS::TraceKind::LazyScript);
 ASSERT_TRACE_KIND(JS::TraceKind::Scope);
 ASSERT_TRACE_KIND(JS::TraceKind::RegExpShared);
@@ -84,17 +99,17 @@ ASSERT_TRACE_KIND(JS::TraceKind::RegExpS
 template <typename T>
 struct MapTypeToTraceKind {
     static const JS::TraceKind kind = T::TraceKind;
 };
 
 // When this header is used outside SpiderMonkey, the class definitions are not
 // available, so the following table containing all public GC types is used.
 #define JS_FOR_EACH_TRACEKIND(D) \
- /* PrettyName       TypeName           AddToCCKind */ \
+ /* PrettyName       TypeName           IsCCTraceKind */ \
     D(BaseShape,     js::BaseShape,     true) \
     D(JitCode,       js::jit::JitCode,  true) \
     D(LazyScript,    js::LazyScript,    true) \
     D(Scope,         js::Scope,         true) \
     D(Object,        JSObject,          true) \
     D(ObjectGroup,   js::ObjectGroup,   true) \
     D(Script,        JSScript,          true) \
     D(Shape,         js::Shape,         true) \
--- a/js/src/gc/WeakMap-inl.h
+++ b/js/src/gc/WeakMap-inl.h
@@ -4,16 +4,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/. */
 
 #ifndef gc_WeakMap_inl_h
 #define gc_WeakMap_inl_h
 
 #include "gc/WeakMap.h"
 
+#include "js/TraceKind.h"
 #include "vm/JSContext.h"
 
 namespace js {
 
 template <typename T>
 static T extractUnbarriered(const WriteBarrieredBase<T>& v)
 {
     return v.get();
@@ -23,16 +24,23 @@ static T* extractUnbarriered(T* v)
 {
     return v;
 }
 
 template <class K, class V>
 WeakMap<K, V>::WeakMap(JSContext* cx, JSObject* memOf)
   : Base(cx->zone()), WeakMapBase(memOf, cx->zone())
 {
+    using ElemType = typename K::ElementType;
+    using NonPtrType = typename mozilla::RemovePointer<ElemType>::Type;
+    // The object's TraceKind needs to be added to CC graph if this object is
+    // used as a WeakMap key. See the comments for IsCCTraceKind for details.
+    static_assert(JS::IsCCTraceKind(NonPtrType::TraceKind),
+                  "Object's TraceKind should be added to CC graph.");
+
     zone()->gcWeakMapList().insertFront(this);
     marked = JS::IsIncrementalGCInProgress(TlsContext.get());
 }
 
 // Trace a WeakMap entry based on 'markedCell' getting marked, where 'origKey'
 // is the key in the weakmap. These will probably be the same, but can be
 // different eg when markedCell is a delegate for origKey.
 //
--- a/js/src/jit-test/tests/wasm/memory.js
+++ b/js/src/jit-test/tests/wasm/memory.js
@@ -203,105 +203,114 @@ for (var foldOffsets = 0; foldOffsets <=
     testStore('f64', '', 1, 7, 8, 0.89012345);
 
     testStore('i32', '8', 0, 0, 0, 0x23);
     testStore('i32', '16', 0, 0, 0, 0x2345);
 
     wasmFailValidateText('(module (memory 2 1))', /maximum length 1 is less than initial length 2/);
 
     // Test bounds checks and edge cases.
-    const align = 0;
+
+    for (let align of [0,1,2,4]) {
 
-    for (let offset of [0, 1, 2, 3, 4, 8, 16, 41, 0xfff8]) {
-        // Accesses of 1 byte.
-        let lastValidIndex = 0x10000 - 1 - offset;
-
-        testLoad('i32', '8_s', lastValidIndex, offset, align, 0);
-        testLoadOOB('i32', '8_s', lastValidIndex + 1, offset, align);
+        for (let offset of [0, 1, 2, 3, 4, 8, 16, 41, 0xfff8]) {
+            // Accesses of 1 byte.
+            let lastValidIndex = 0x10000 - 1 - offset;
 
-        testLoad('i32', '8_u', lastValidIndex, offset, align, 0);
-        testLoadOOB('i32', '8_u', lastValidIndex + 1, offset, align);
+            if (align < 2) {
+                testLoad('i32', '8_s', lastValidIndex, offset, align, 0);
+                testLoadOOB('i32', '8_s', lastValidIndex + 1, offset, align);
 
-        testStore('i32', '8', lastValidIndex, offset, align, -42);
-        testStoreOOB('i32', '8', lastValidIndex + 1, offset, align, -42);
+                testLoad('i32', '8_u', lastValidIndex, offset, align, 0);
+                testLoadOOB('i32', '8_u', lastValidIndex + 1, offset, align);
 
-        // Accesses of 2 bytes.
-        lastValidIndex = 0x10000 - 2 - offset;
+                testStore('i32', '8', lastValidIndex, offset, align, -42);
+                testStoreOOB('i32', '8', lastValidIndex + 1, offset, align, -42);
+            }
 
-        testLoad('i32', '16_s', lastValidIndex, offset, align, 0);
-        testLoadOOB('i32', '16_s', lastValidIndex + 1, offset, align);
+            // Accesses of 2 bytes.
+            lastValidIndex = 0x10000 - 2 - offset;
 
-        testLoad('i32', '16_u', lastValidIndex, offset, align, 0);
-        testLoadOOB('i32', '16_u', lastValidIndex + 1, offset, align);
-
-        testStore('i32', '16', lastValidIndex, offset, align, -32768);
-        testStoreOOB('i32', '16', lastValidIndex + 1, offset, align, -32768);
+            if (align < 4) {
+                testLoad('i32', '16_s', lastValidIndex, offset, align, 0);
+                testLoadOOB('i32', '16_s', lastValidIndex + 1, offset, align);
 
-        // Accesses of 4 bytes.
-        lastValidIndex = 0x10000 - 4 - offset;
+                testLoad('i32', '16_u', lastValidIndex, offset, align, 0);
+                testLoadOOB('i32', '16_u', lastValidIndex + 1, offset, align);
 
-        testLoad('i32', '', lastValidIndex, offset, align, 0);
-        testLoadOOB('i32', '', lastValidIndex + 1, offset, align);
+                testStore('i32', '16', lastValidIndex, offset, align, -32768);
+                testStoreOOB('i32', '16', lastValidIndex + 1, offset, align, -32768);
+            }
 
-        testLoad('f32', '', lastValidIndex, offset, align, 0);
-        testLoadOOB('f32', '', lastValidIndex + 1, offset, align);
+            // Accesses of 4 bytes.
+            lastValidIndex = 0x10000 - 4 - offset;
 
-        testStore('i32', '', lastValidIndex, offset, align, 1337);
-        testStoreOOB('i32', '', lastValidIndex + 1, offset, align, 1337);
+            testLoad('i32', '', lastValidIndex, offset, align, 0);
+            testLoadOOB('i32', '', lastValidIndex + 1, offset, align);
 
-        testStore('f32', '', lastValidIndex, offset, align, Math.fround(13.37));
-        testStoreOOB('f32', '', lastValidIndex + 1, offset, align, Math.fround(13.37));
+            testLoad('f32', '', lastValidIndex, offset, align, 0);
+            testLoadOOB('f32', '', lastValidIndex + 1, offset, align);
 
-        // Accesses of 8 bytes.
-        lastValidIndex = 0x10000 - 8 - offset;
+            testStore('i32', '', lastValidIndex, offset, align, 1337);
+            testStoreOOB('i32', '', lastValidIndex + 1, offset, align, 1337);
+
+            testStore('f32', '', lastValidIndex, offset, align, Math.fround(13.37));
+            testStoreOOB('f32', '', lastValidIndex + 1, offset, align, Math.fround(13.37));
 
-        testLoad('f64', '', lastValidIndex, offset, align, 0);
-        testLoadOOB('f64', '', lastValidIndex + 1, offset, align);
+            // Accesses of 8 bytes.
+            lastValidIndex = 0x10000 - 8 - offset;
 
-        testStore('f64', '', lastValidIndex, offset, align, 1.23456789);
-        testStoreOOB('f64', '', lastValidIndex + 1, offset, align, 1.23456789);
-    }
+            testLoad('f64', '', lastValidIndex, offset, align, 0);
+            testLoadOOB('f64', '', lastValidIndex + 1, offset, align);
+
+            testStore('f64', '', lastValidIndex, offset, align, 1.23456789);
+            testStoreOOB('f64', '', lastValidIndex + 1, offset, align, 1.23456789);
+        }
 
-    // Ensure wrapping doesn't apply.
-    offset = 0x7fffffff; // maximum allowed offset that doesn't always throw.
-    for (let index of [0, 1, 2, 3, 0x7fffffff, 0x80000000, 0x80000001]) {
-        testLoadOOB('i32', '8_s', index, offset, align);
-        testLoadOOB('i32', '16_s', index, offset, align);
-        testLoadOOB('i32', '', index, offset, align);
-        testLoadOOB('f32', '', index, offset, align);
-        testLoadOOB('f64', '', index, offset, align);
-    }
+        // Ensure wrapping doesn't apply.
+        offset = 0x7fffffff; // maximum allowed offset that doesn't always throw.
+        for (let index of [0, 1, 2, 3, 0x7fffffff, 0x80000000, 0x80000001]) {
+            if (align < 2) {
+                testLoadOOB('i32', '8_s', index, offset, align);
+            }
+            if (align < 4) {
+                testLoadOOB('i32', '16_s', index, offset, align);
+            }
+            testLoadOOB('i32', '', index, offset, align);
+            testLoadOOB('f32', '', index, offset, align);
+            testLoadOOB('f64', '', index, offset, align);
+        }
 
-    // Ensure out of bounds when the offset is greater than the immediate range.
-    index = 0;
-    for (let offset of [0x80000000, 0xfffffffe, 0xffffffff]) {
-        testLoadOOB('i32', '8_s', index, offset, 1);
-        testLoadOOB('i32', '16_s', index, offset, 1);
-        testLoadOOB('i32', '16_s', index, offset, 2);
-        testLoadOOB('i32', '', index, offset, 1);
-        testLoadOOB('i32', '', index, offset, 4);
-        testLoadOOB('f32', '', index, offset, 1);
-        testLoadOOB('f32', '', index, offset, 4);
-        testLoadOOB('f64', '', index, offset, 1);
-        testLoadOOB('f64', '', index, offset, 8);
-    }
+        // Ensure out of bounds when the offset is greater than the immediate range.
+        index = 0;
+        for (let offset of [0x80000000, 0xfffffffe, 0xffffffff]) {
+            testLoadOOB('i32', '8_s', index, offset, 1);
+            testLoadOOB('i32', '16_s', index, offset, 1);
+            testLoadOOB('i32', '16_s', index, offset, 2);
+            testLoadOOB('i32', '', index, offset, 1);
+            testLoadOOB('i32', '', index, offset, 4);
+            testLoadOOB('f32', '', index, offset, 1);
+            testLoadOOB('f32', '', index, offset, 4);
+            testLoadOOB('f64', '', index, offset, 1);
+            testLoadOOB('f64', '', index, offset, 8);
+        }
 
-    wasmFailValidateText('(module (memory 1) (func (f64.store offset=0 (i32.const 0) (i32.const 0))))', mismatchError("i32", "f64"));
-    wasmFailValidateText('(module (memory 1) (func (f64.store offset=0 (i32.const 0) (f32.const 0))))', mismatchError("f32", "f64"));
+        wasmFailValidateText('(module (memory 1) (func (f64.store offset=0 (i32.const 0) (i32.const 0))))', mismatchError("i32", "f64"));
+        wasmFailValidateText('(module (memory 1) (func (f64.store offset=0 (i32.const 0) (f32.const 0))))', mismatchError("f32", "f64"));
 
-    wasmFailValidateText('(module (memory 1) (func (f32.store offset=0 (i32.const 0) (i32.const 0))))', mismatchError("i32", "f32"));
-    wasmFailValidateText('(module (memory 1) (func (f32.store offset=0 (i32.const 0) (f64.const 0))))', mismatchError("f64", "f32"));
+        wasmFailValidateText('(module (memory 1) (func (f32.store offset=0 (i32.const 0) (i32.const 0))))', mismatchError("i32", "f32"));
+        wasmFailValidateText('(module (memory 1) (func (f32.store offset=0 (i32.const 0) (f64.const 0))))', mismatchError("f64", "f32"));
 
-    wasmFailValidateText('(module (memory 1) (func (i32.store offset=0 (i32.const 0) (f32.const 0))))', mismatchError("f32", "i32"));
-    wasmFailValidateText('(module (memory 1) (func (i32.store offset=0 (i32.const 0) (f64.const 0))))', mismatchError("f64", "i32"));
+        wasmFailValidateText('(module (memory 1) (func (i32.store offset=0 (i32.const 0) (f32.const 0))))', mismatchError("f32", "i32"));
+        wasmFailValidateText('(module (memory 1) (func (i32.store offset=0 (i32.const 0) (f64.const 0))))', mismatchError("f64", "i32"));
 
-    // Test high number of registers.
-    function testRegisters() {
-        assertEq(wasmEvalText(
-            `(module
+        // Test high number of registers.
+        function testRegisters() {
+            assertEq(wasmEvalText(
+                `(module
               (memory 1)
               (data (i32.const 0) "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f")
               (data (i32.const 16) "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")
               (func (param i32) (local i32 i32 i32 i32 f32 f64) (result i32)
                (set_local 1 (i32.load8_s offset=4 (get_local 0)))
                (set_local 2 (i32.load16_s (get_local 1)))
                (i32.store8 offset=4 (get_local 0) (get_local 1))
                (set_local 3 (i32.load16_u (get_local 2)))
@@ -324,86 +333,91 @@ for (var foldOffsets = 0; foldOffsets <=
                  )
                  (i32.add
                   (get_local 4)
                   (i32.reinterpret/f32 (get_local 5))
                  )
                 )
                )
               ) (export "" 0))`
-        ).exports[""](1), 50464523);
-    }
+            ).exports[""](1), 50464523);
+        }
 
-    testRegisters();
+        testRegisters();
 
-    testLoad('i64', '', 0, 0, 0, '0x0706050403020100');
-    testLoad('i64', '', 1, 0, 0, '0x0807060504030201');
-    testLoad('i64', '', 0, 1, 0, '0x0807060504030201');
-    testLoad('i64', '', 1, 1, 4, '0x0908070605040302');
+        testLoad('i64', '', 0, 0, 0, '0x0706050403020100');
+        testLoad('i64', '', 1, 0, 0, '0x0807060504030201');
+        testLoad('i64', '', 0, 1, 0, '0x0807060504030201');
+        testLoad('i64', '', 1, 1, 4, '0x0908070605040302');
 
-    testLoad('i64', '8_s', 16, 0, 0, -0x10);
-    testLoad('i64', '8_u', 16, 0, 0, 0xf0);
-    testLoad('i64', '16_s', 16, 0, 0, -0xe10);
-    testLoad('i64', '16_u', 16, 0, 0, 0xf1f0);
-    testLoad('i64', '32_s', 16, 0, 0, 0xf3f2f1f0 | 0);
-    testLoad('i64', '32_u', 16, 0, 0, '0xf3f2f1f0');
+        testLoad('i64', '8_s', 16, 0, 0, -0x10);
+        testLoad('i64', '8_u', 16, 0, 0, 0xf0);
+        testLoad('i64', '16_s', 16, 0, 0, -0xe10);
+        testLoad('i64', '16_u', 16, 0, 0, 0xf1f0);
+        testLoad('i64', '32_s', 16, 0, 0, 0xf3f2f1f0 | 0);
+        testLoad('i64', '32_u', 16, 0, 0, '0xf3f2f1f0');
 
-    testStore('i64', '', 0, 0, 0, '0xc0c1d3d4e6e7090a');
-    testStore('i64', '', 1, 0, 0, '0xc0c1d3d4e6e7090a');
-    testStore('i64', '', 0, 1, 0, '0xc0c1d3d4e6e7090a');
-    testStore('i64', '', 1, 1, 4, '0xc0c1d3d4e6e7090a');
-    testStore('i64', '8', 0, 0, 0, 0x23);
-    testStore('i64', '16', 0, 0, 0, 0x23);
-    testStore('i64', '32', 0, 0, 0, 0x23);
+        testStore('i64', '', 0, 0, 0, '0xc0c1d3d4e6e7090a');
+        testStore('i64', '', 1, 0, 0, '0xc0c1d3d4e6e7090a');
+        testStore('i64', '', 0, 1, 0, '0xc0c1d3d4e6e7090a');
+        testStore('i64', '', 1, 1, 4, '0xc0c1d3d4e6e7090a');
+        testStore('i64', '8', 0, 0, 0, 0x23);
+        testStore('i64', '16', 0, 0, 0, 0x23);
+        testStore('i64', '32', 0, 0, 0, 0x23);
 
-    for (let offset of [0, 1, 2, 3, 4, 8, 16, 41, 0xfff8]) {
-        // Accesses of 1 byte.
-        let lastValidIndex = 0x10000 - 1 - offset;
+        for (let offset of [0, 1, 2, 3, 4, 8, 16, 41, 0xfff8]) {
+            // Accesses of 1 byte.
+            let lastValidIndex = 0x10000 - 1 - offset;
 
-        testLoad('i64', '8_s', lastValidIndex, offset, align, 0);
-        testLoadOOB('i64', '8_s', lastValidIndex + 1, offset, align);
+            if (align < 2) {
+                testLoad('i64', '8_s', lastValidIndex, offset, align, 0);
+                testLoadOOB('i64', '8_s', lastValidIndex + 1, offset, align);
 
-        testLoad('i64', '8_u', lastValidIndex, offset, align, 0);
-        testLoadOOB('i64', '8_u', lastValidIndex + 1, offset, align);
+                testLoad('i64', '8_u', lastValidIndex, offset, align, 0);
+                testLoadOOB('i64', '8_u', lastValidIndex + 1, offset, align);
 
-        testStore('i64', '8', lastValidIndex, offset, align, -42);
-        testStoreOOB('i64', '8', lastValidIndex + 1, offset, align, -42);
+                testStore('i64', '8', lastValidIndex, offset, align, -42);
+                testStoreOOB('i64', '8', lastValidIndex + 1, offset, align, -42);
+            }
 
-        // Accesses of 2 bytes.
-        lastValidIndex = 0x10000 - 2 - offset;
-
-        testLoad('i64', '16_s', lastValidIndex, offset, align, 0);
-        testLoadOOB('i64', '16_s', lastValidIndex + 1, offset, align);
+            // Accesses of 2 bytes.
+            lastValidIndex = 0x10000 - 2 - offset;
 
-        testLoad('i64', '16_u', lastValidIndex, offset, align, 0);
-        testLoadOOB('i64', '16_u', lastValidIndex + 1, offset, align);
+            if (align < 4) {
+                testLoad('i64', '16_s', lastValidIndex, offset, align, 0);
+                testLoadOOB('i64', '16_s', lastValidIndex + 1, offset, align);
 
-        testStore('i64', '16', lastValidIndex, offset, align, -32768);
-        testStoreOOB('i64', '16', lastValidIndex + 1, offset, align, -32768);
+                testLoad('i64', '16_u', lastValidIndex, offset, align, 0);
+                testLoadOOB('i64', '16_u', lastValidIndex + 1, offset, align);
 
-        // Accesses of 4 bytes.
-        lastValidIndex = 0x10000 - 4 - offset;
+                testStore('i64', '16', lastValidIndex, offset, align, -32768);
+                testStoreOOB('i64', '16', lastValidIndex + 1, offset, align, -32768);
+            }
 
-        testLoad('i64', '32_s', lastValidIndex, offset, align, 0);
-        testLoadOOB('i64', '32_s', lastValidIndex + 1, offset, align);
+            // Accesses of 4 bytes.
+            lastValidIndex = 0x10000 - 4 - offset;
 
-        testLoad('i64', '32_u', lastValidIndex, offset, align, 0);
-        testLoadOOB('i64', '32_u', lastValidIndex + 1, offset, align);
+            testLoad('i64', '32_s', lastValidIndex, offset, align, 0);
+            testLoadOOB('i64', '32_s', lastValidIndex + 1, offset, align);
 
-        testStore('i64', '32', lastValidIndex, offset, align, 0xf1231337 | 0);
-        testStoreOOB('i64', '32', lastValidIndex + 1, offset, align, 0xf1231337 | 0);
+            testLoad('i64', '32_u', lastValidIndex, offset, align, 0);
+            testLoadOOB('i64', '32_u', lastValidIndex + 1, offset, align);
 
-        // Accesses of 8 bytes.
-        lastValidIndex = 0x10000 - 8 - offset;
+            testStore('i64', '32', lastValidIndex, offset, align, 0xf1231337 | 0);
+            testStoreOOB('i64', '32', lastValidIndex + 1, offset, align, 0xf1231337 | 0);
+
+            // Accesses of 8 bytes.
+            lastValidIndex = 0x10000 - 8 - offset;
 
-        testLoad('i64', '', lastValidIndex, offset, align, 0);
-        testLoadOOB('i64', '', lastValidIndex + 1, offset, align);
+            testLoad('i64', '', lastValidIndex, offset, align, 0);
+            testLoadOOB('i64', '', lastValidIndex + 1, offset, align);
 
-        testStore('i64', '', lastValidIndex, offset, align, '0x1234567887654321');
-        testStoreOOB('i64', '', lastValidIndex + 1, offset, align, '0x1234567887654321');
+            testStore('i64', '', lastValidIndex, offset, align, '0x1234567887654321');
+            testStoreOOB('i64', '', lastValidIndex + 1, offset, align, '0x1234567887654321');
+        }
     }
 }
 
 setJitCompilerOption('wasm.fold-offsets', 1);
 
 // Test active segments with a memory index.
 
 {
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/regress/imul64-ion-negative-power-of-two.js
@@ -0,0 +1,11 @@
+new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(`
+(module
+    (func (param i64))
+    (func (export "f")
+        i64.const 2
+        i64.const -9223372036854775808
+        i64.mul
+        call 0
+    )
+)
+`))).exports.f();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/regress/unaligned-store64.js
@@ -0,0 +1,35 @@
+var ins = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
+    `(module
+       (memory (export "mem") 1 1)
+       (func (export "store_32_1") (param $ptr i32)
+         (i64.store32 align=1 (get_local $ptr) (i64.const 0xabba1337)))
+       (func (export "store_32_2") (param $ptr i32)
+         (i64.store32 align=2 (get_local $ptr) (i64.const 0xabba1337)))
+       (func (export "store_16") (param $ptr i32)
+         (i64.store16 align=1 (get_local $ptr) (i64.const 0x1337))))`))).exports;
+
+var mem = new Uint8Array(ins.mem.buffer);
+
+ins.store_16(1);
+assertEq(mem[1], 0x37);
+assertEq(mem[2], 0x13);
+
+ins.store_32_1(11);
+assertEq(mem[11], 0x37);
+assertEq(mem[12], 0x13);
+assertEq(mem[13], 0xba);
+assertEq(mem[14], 0xab);
+
+ins.store_32_2(18);
+assertEq(mem[18], 0x37);
+assertEq(mem[19], 0x13);
+assertEq(mem[20], 0xba);
+assertEq(mem[21], 0xab);
+
+// This must also work on all platforms even though we're lying about the
+// alignment.
+ins.store_32_2(29);
+assertEq(mem[29], 0x37);
+assertEq(mem[30], 0x13);
+assertEq(mem[31], 0xba);
+assertEq(mem[32], 0xab);
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -2170,25 +2170,25 @@ CodeGenerator::visitWasmStoreI64(LWasmSt
     emitWasmStore(lir);
 }
 
 template<typename T>
 void
 CodeGeneratorARM::emitWasmUnalignedStore(T* lir)
 {
     const MWasmStore* mir = lir->mir();
-    Scalar::Type accessType = mir->access().type();
-
+    MIRType valueType = mir->value()->type();
     Register ptr = ToRegister(lir->ptrCopy());
     Register valOrTmp = ToRegister(lir->valueHelper());
-    if (accessType == Scalar::Int64) {
+
+    if (valueType == MIRType::Int64) {
         masm.wasmUnalignedStoreI64(mir->access(),
                                    ToRegister64(lir->getInt64Operand(LWasmUnalignedStoreI64::ValueIndex)),
                                    HeapReg, ptr, ptr, valOrTmp);
-    } else if (accessType == Scalar::Float32 || accessType == Scalar::Float64) {
+    } else if (valueType == MIRType::Float32 || valueType == MIRType::Double) {
         FloatRegister value = ToFloatRegister(lir->getOperand(LWasmUnalignedStore::ValueIndex));
         masm.wasmUnalignedStoreFP(mir->access(), value, HeapReg, ptr, ptr, valOrTmp);
     } else {
         masm.wasmUnalignedStore(mir->access(), valOrTmp, HeapReg, ptr, ptr, Register::Invalid());
     }
 }
 
 void
--- a/js/src/jit/arm/Lowering-arm.cpp
+++ b/js/src/jit/arm/Lowering-arm.cpp
@@ -218,17 +218,17 @@ LIRGeneratorARM::lowerForMulInt64(LMulI6
 
     if (rhs->isConstant()) {
         int64_t constant = rhs->toConstant()->toInt64();
         int32_t shift = mozilla::FloorLog2(constant);
         // See special cases in CodeGeneratorARM::visitMulI64
         if (constant >= -1 && constant <= 2) {
             needsTemp = false;
         }
-        if (int64_t(1) << shift == constant) {
+        if (constant > 0 && int64_t(1) << shift == constant) {
             needsTemp = false;
         }
     }
 
     ins->setInt64Operand(0, useInt64RegisterAtStart(lhs));
     ins->setInt64Operand(INT64_PIECES, useInt64OrConstant(rhs));
     if (needsTemp) {
         ins->setTemp(0, temp());
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -6570,19 +6570,22 @@ MacroAssemblerARM::wasmUnalignedStoreImp
     ma_add(memoryBase, ptr);
 
     asMasm().memoryBarrierAfter(access.sync());
 
     // If it's a two-word store we must store the high word first to get signal
     // handling right.
 
     if (val64 != Register64::Invalid()) {
-        MOZ_ASSERT(byteSize == 8);
-        emitUnalignedStore(&access, /*size=*/4, ptr, val64.high, /*offset=*/4);
-        emitUnalignedStore(nullptr, /*size=*/4, ptr, val64.low);
+        if (byteSize == 8) {
+            emitUnalignedStore(&access, /*size=*/4, ptr, val64.high, /*offset=*/4);
+            emitUnalignedStore(nullptr, /*size=*/4, ptr, val64.low);
+        } else {
+            emitUnalignedStore(&access, byteSize, ptr, val64.low);
+        }
     } else if (!floatValue.isInvalid()) {
         if (floatValue.isDouble()) {
             MOZ_ASSERT(byteSize == 8);
             ScratchRegisterScope scratch(asMasm());
             ma_vxfer(floatValue, scratch, valOrTmp);
             emitUnalignedStore(&access, /*size=*/4, ptr, valOrTmp, /*offset=*/4);
             emitUnalignedStore(nullptr, /*size=*/4, ptr, scratch);
         } else {
--- a/js/src/jit/x86/Lowering-x86.cpp
+++ b/js/src/jit/x86/Lowering-x86.cpp
@@ -217,17 +217,17 @@ LIRGeneratorX86::lowerForMulInt64(LMulI6
 
     if (rhs->isConstant()) {
         int64_t constant = rhs->toConstant()->toInt64();
         int32_t shift = mozilla::FloorLog2(constant);
         // See special cases in CodeGeneratorX86Shared::visitMulI64.
         if (constant >= -1 && constant <= 2) {
             needsTemp = false;
         }
-        if (int64_t(1) << shift == constant) {
+        if (constant > 0 && int64_t(1) << shift == constant) {
             needsTemp = false;
         }
     }
 
     // MulI64 on x86 needs output to be in edx, eax;
     ins->setInt64Operand(0, useInt64Fixed(lhs, Register64(edx, eax), /*useAtStart = */ true));
     ins->setInt64Operand(INT64_PIECES, useInt64OrConstant(rhs));
     if (needsTemp) {
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -10449,33 +10449,31 @@ SetContextOptions(JSContext* cx, const O
     enableNativeRegExp = !op.getBoolOption("no-native-regexp");
     enableWasmBaseline = !op.getBoolOption("no-wasm-baseline");
     enableWasmIon = !op.getBoolOption("no-wasm-ion");
 #ifdef ENABLE_WASM_CRANELIFT
     wasmForceCranelift = op.getBoolOption("wasm-force-cranelift");
 #endif
 #ifdef ENABLE_WASM_GC
     enableWasmGc = op.getBoolOption("wasm-gc");
+# ifdef ENABLE_WASM_CRANELIFT
+    if (enableWasmGc && wasmForceCranelift) {
+        fprintf(stderr, "Do not combine --wasm-gc and --wasm-force-cranelift, they are "
+                        "incompatible.\n");
+    }
+    enableWasmGc = enableWasmGc && !wasmForceCranelift;
+# endif
 #endif
     enableTestWasmAwaitTier2 = op.getBoolOption("test-wasm-await-tier2");
     enableAsyncStacks = !op.getBoolOption("no-async-stacks");
     enableStreams = !op.getBoolOption("no-streams");
 #ifdef ENABLE_BIGINT
     enableBigInt = !op.getBoolOption("no-bigint");
 #endif
 
-#if defined ENABLE_WASM_GC && defined ENABLE_WASM_CRANELIFT
-    // Note, once we remove --wasm-gc this test will no longer make any sense
-    // and we'll need a better solution.
-    if (enableWasmGc && wasmForceCranelift) {
-        fprintf(stderr, "Do not combine --wasm-gc and --wasm-force-cranelift, they are incompatible.\n");
-        return false;
-    }
-#endif
-
     JS::ContextOptionsRef(cx).setBaseline(enableBaseline)
                              .setIon(enableIon)
                              .setAsmJS(enableAsmJS)
                              .setWasm(enableWasm)
                              .setWasmBaseline(enableWasmBaseline)
                              .setWasmIon(enableWasmIon)
 #ifdef ENABLE_WASM_CRANELIFT
                              .setWasmForceCranelift(wasmForceCranelift)
--- a/js/src/wasm/WasmTextToBinary.cpp
+++ b/js/src/wasm/WasmTextToBinary.cpp
@@ -7144,16 +7144,20 @@ EncodeMemorySection(Encoder& e, AstModul
 
     e.finishSection(offset);
     return true;
 }
 
 static bool
 EncodeGlobalSection(Encoder& e, AstModule& module)
 {
+    if (!module.globals().length()) {
+        return true;
+    }
+
     size_t offset;
     if (!e.startSection(SectionId::Global, &offset)) {
         return false;
     }
 
     const AstGlobalVector& globals = module.globals();
 
     if (!e.writeVarU32(globals.length())) {
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -2463,23 +2463,17 @@ nsDocumentViewer::CreateStyleSet(nsIDocu
     styleSet->PrependStyleSheet(SheetType::Agent, sheet);
   }
 
   sheet = cache->FormsSheet();
   if (sheet) {
     styleSet->PrependStyleSheet(SheetType::Agent, sheet);
   }
 
-  // This is the only place components.css / xul.css get loaded.
   if (aDocument->LoadsFullXULStyleSheetUpFront()) {
-    sheet = cache->XULComponentsSheet();
-    if (sheet) {
-      styleSet->PrependStyleSheet(SheetType::Agent, sheet);
-    }
-
     sheet = cache->XULSheet();
     if (sheet) {
       styleSet->PrependStyleSheet(SheetType::Agent, sheet);
     }
   }
 
   sheet = cache->MinimalXULSheet();
   if (sheet) {
--- a/layout/style/nsLayoutStylesheetCache.cpp
+++ b/layout/style/nsLayoutStylesheetCache.cpp
@@ -132,27 +132,16 @@ nsLayoutStylesheetCache::XULSheet()
     LoadSheetURL("chrome://global/content/xul.css",
                  &mXULSheet, eAgentSheetFeatures, eCrash);
   }
 
   return mXULSheet;
 }
 
 StyleSheet*
-nsLayoutStylesheetCache::XULComponentsSheet()
-{
-  if (!mXULComponentsSheet) {
-    LoadSheetURL("chrome://global/content/components.css",
-                 &mXULComponentsSheet, eAgentSheetFeatures, eCrash);
-  }
-
-  return mXULComponentsSheet;
-}
-
-StyleSheet*
 nsLayoutStylesheetCache::QuirkSheet()
 {
   return mQuirkSheet;
 }
 
 StyleSheet*
 nsLayoutStylesheetCache::SVGSheet()
 {
@@ -292,17 +281,16 @@ nsLayoutStylesheetCache::SizeOfIncluding
   MEASURE(mNoScriptSheet);
   MEASURE(mQuirkSheet);
   MEASURE(mSVGSheet);
   MEASURE(mScrollbarsSheet);
   MEASURE(mUASheet);
   MEASURE(mUserChromeSheet);
   MEASURE(mUserContentSheet);
   MEASURE(mXULSheet);
-  MEASURE(mXULComponentsSheet);
 
   // Measurement of the following members may be added later if DMD finds it is
   // worthwhile:
   // - gCSSLoader
 
   return n;
 }
 
@@ -331,17 +319,16 @@ nsLayoutStylesheetCache::nsLayoutStylesh
                &mMinimalXULSheet, eAgentSheetFeatures, eCrash);
   LoadSheetURL("resource://gre-resources/quirk.css",
                &mQuirkSheet, eAgentSheetFeatures, eCrash);
   LoadSheetURL("resource://gre/res/svg.css",
                &mSVGSheet, eAgentSheetFeatures, eCrash);
   if (XRE_IsParentProcess()) {
     // We know we need xul.css for the UI, so load that now too:
     XULSheet();
-    XULComponentsSheet();
   }
 
   if (gUserContentSheetURL) {
     MOZ_ASSERT(XRE_IsContentProcess(), "Only used in content processes.");
     LoadSheet(gUserContentSheetURL, &mUserContentSheet,
               eUserSheetFeatures, eLogToConsole);
     gUserContentSheetURL = nullptr;
   }
--- a/layout/style/nsLayoutStylesheetCache.h
+++ b/layout/style/nsLayoutStylesheetCache.h
@@ -46,17 +46,16 @@ class nsLayoutStylesheetCache final
   mozilla::StyleSheet* ScrollbarsSheet();
   mozilla::StyleSheet* FormsSheet();
   mozilla::StyleSheet* UserContentSheet();
   mozilla::StyleSheet* UserChromeSheet();
   mozilla::StyleSheet* UASheet();
   mozilla::StyleSheet* HTMLSheet();
   mozilla::StyleSheet* MinimalXULSheet();
   mozilla::StyleSheet* XULSheet();
-  mozilla::StyleSheet* XULComponentsSheet();
   mozilla::StyleSheet* QuirkSheet();
   mozilla::StyleSheet* SVGSheet();
   mozilla::StyleSheet* MathMLSheet();
   mozilla::StyleSheet* CounterStylesSheet();
   mozilla::StyleSheet* NoScriptSheet();
   mozilla::StyleSheet* NoFramesSheet();
   mozilla::StyleSheet* ChromePreferenceSheet(nsPresContext* aPresContext);
   mozilla::StyleSheet* ContentPreferenceSheet(nsPresContext* aPresContext);
@@ -107,12 +106,11 @@ private:
   RefPtr<mozilla::StyleSheet> mNoScriptSheet;
   RefPtr<mozilla::StyleSheet> mQuirkSheet;
   RefPtr<mozilla::StyleSheet> mSVGSheet;
   RefPtr<mozilla::StyleSheet> mScrollbarsSheet;
   RefPtr<mozilla::StyleSheet> mUASheet;
   RefPtr<mozilla::StyleSheet> mUserChromeSheet;
   RefPtr<mozilla::StyleSheet> mUserContentSheet;
   RefPtr<mozilla::StyleSheet> mXULSheet;
-  RefPtr<mozilla::StyleSheet> mXULComponentsSheet;
 };
 
 #endif
--- a/netwerk/mime/nsMimeTypes.h
+++ b/netwerk/mime/nsMimeTypes.h
@@ -103,16 +103,19 @@
 #define IMAGE_PPM                           "image/x-portable-pixmap"
 #define IMAGE_XBM                           "image/x-xbitmap"
 #define IMAGE_XBM2                          "image/x-xbm"
 #define IMAGE_XBM3                          "image/xbm"
 #define IMAGE_ART                           "image/x-jg"
 #define IMAGE_TIFF                          "image/tiff"
 #define IMAGE_BMP                           "image/bmp"
 #define IMAGE_BMP_MS                        "image/x-ms-bmp"
+// This is used internally to represent Windows clipboard BMPs which remove
+// part of the header.
+#define IMAGE_BMP_MS_CLIPBOARD              "image/x-ms-clipboard-bmp"
 #define IMAGE_ICO                           "image/x-icon"
 #define IMAGE_ICO_MS                        "image/vnd.microsoft.icon"
 #define IMAGE_ICON_MS                       "image/icon"
 #define IMAGE_MNG                           "video/x-mng"
 #define IMAGE_JNG                           "image/x-jng"
 #define IMAGE_SVG_XML                       "image/svg+xml"
 #define IMAGE_WEBP                          "image/webp"
 
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -6555,16 +6555,28 @@ nsHttpChannel::BeginConnect()
     }
     LOG(("host=%s port=%d\n", host.get(), port));
     LOG(("uri=%s\n", mSpec.get()));
 
     nsCOMPtr<nsProxyInfo> proxyInfo;
     if (mProxyInfo)
         proxyInfo = do_QueryInterface(mProxyInfo);
 
+    if (mCaps & NS_HTTP_CONNECT_ONLY) {
+        if (!proxyInfo) {
+            LOG(("return failure: no proxy for connect-only channel\n"));
+            return NS_ERROR_FAILURE;
+        }
+
+        if (!proxyInfo->IsHTTP() && !proxyInfo->IsHTTPS()) {
+            LOG(("return failure: non-http proxy for connect-only channel\n"));
+            return NS_ERROR_FAILURE;
+        }
+    }
+
     mRequestHead.SetHTTPS(isHttps);
     mRequestHead.SetOrigin(scheme, host, port);
 
     SetOriginHeader();
     SetDoNotTrack();
 
     OriginAttributes originAttributes;
     NS_GetOriginAttributes(this, originAttributes);
--- a/netwerk/protocol/http/nsHttpChunkedDecoder.h
+++ b/netwerk/protocol/http/nsHttpChunkedDecoder.h
@@ -15,17 +15,17 @@ namespace mozilla { namespace net {
 
 class nsHttpChunkedDecoder
 {
 public:
     nsHttpChunkedDecoder() : mTrailers(nullptr)
                            , mChunkRemaining(0)
                            , mReachedEOF(false)
                            , mWaitEOF(false) {}
-   ~nsHttpChunkedDecoder() { delete mTrailers; }
+   ~nsHttpChunkedDecoder() = default;
 
     bool ReachedEOF() { return mReachedEOF; }
 
     // called by the transaction to handle chunked content.
     MOZ_MUST_USE nsresult HandleChunkedContent(char *buf,
                                                uint32_t count,
                                                uint32_t *contentRead,
                                                uint32_t *contentRemaining);
--- a/netwerk/protocol/http/nsHttpConnection.cpp
+++ b/netwerk/protocol/http/nsHttpConnection.cpp
@@ -1901,17 +1901,18 @@ nsHttpConnection::OnSocketWritable()
     const uint32_t maxWriteAttempts = 128;
     uint32_t writeAttempts = 0;
 
     mForceSendDuringFastOpenPending = false;
 
     if (mTransactionCaps & NS_HTTP_CONNECT_ONLY) {
         if (!mCompletedProxyConnect && !mProxyConnectStream) {
             // A CONNECT has been requested for this connection but will never
-            // be performed. Fail here to let request callbacks happen.
+            // be performed. This should never happen.
+            MOZ_ASSERT(false, "proxy connect will never happen");
             LOG(("return failure because proxy connect will never happen\n"));
             return NS_ERROR_FAILURE;
         }
 
         if (mCompletedProxyConnect) {
             // Don't need to check this each write attempt since it is only
             // updated after OnSocketWritable completes.
             // We've already done primary tls (if needed) and sent our CONNECT.
@@ -2081,17 +2082,18 @@ nsHttpConnection::OnSocketReadable()
     PRIntervalTime delta = now - mLastReadTime;
 
     // Reset mResponseTimeoutEnabled to stop response timeout checks.
     mResponseTimeoutEnabled = false;
 
     if ((mTransactionCaps & NS_HTTP_CONNECT_ONLY) &&
         !mCompletedProxyConnect && !mProxyConnectStream) {
         // A CONNECT has been requested for this connection but will never
-        // be performed. Fail here to let request callbacks happen.
+        // be performed. This should never happen.
+        MOZ_ASSERT(false, "proxy connect will never happen");
         LOG(("return failure because proxy connect will never happen\n"));
         return NS_ERROR_FAILURE;
     }
 
     if (mKeepAliveMask && (delta >= mMaxHangTime)) {
         LOG(("max hang time exceeded!\n"));
         // give the handler a chance to create a new persistent connection to
         // this host if we've been busy for too long.
--- a/netwerk/test/unit/test_proxyconnect.js
+++ b/netwerk/test/unit/test_proxyconnect.js
@@ -9,16 +9,21 @@
 // 3. Write data to the tunnel (and read server-side)
 // 4. Read data from the tunnel (and write server-side)
 // 5. done
 // test_connectonly_noproxy tests an http channel with only connect set but
 // no proxy configured.
 // 1. OnTransportAvailable callback NOT called (checked in step 2)
 // 2. StopRequest callback called
 // 3. done
+// test_connectonly_nonhttp tests an http channel with only connect set with a
+// non-http proxy.
+// 1. OnTransportAvailable callback NOT called (checked in step 2)
+// 2. StopRequest callback called
+// 3. done
 
 ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 // -1 then initialized with an actual port from the serversocket
 var socketserver_port = -1;
 
 const CC = Components.Constructor;
@@ -66,16 +71,17 @@ var listener = {
 
   onDataAvailable: function test_ODA() {
     do_throw("Should not get any data!");
   },
 
   onStopRequest: function test_onStopR(request, ctx, status) {
     if (state === STATE_COMPLETED) {
       Assert.equal(transportAvailable, false, 'transport available not called');
+      Assert.equal(status, 0x80004005, 'error code matches');
 
       nextTest();
       return;
     }
 
     Assert.equal(accepted, true, 'socket accepted');
     accepted = false;
   }
@@ -289,36 +295,53 @@ function test_connectonly() {
 function test_connectonly_noproxy() {
   clearPrefs()
   var chan = makeChan();
   chan.asyncOpen2(listener);
 
   do_test_pending();
 }
 
+function test_connectonly_nonhttp() {
+  clearPrefs()
+
+  Services.prefs.setCharPref("network.proxy.socks", "localhost")
+  Services.prefs.setIntPref("network.proxy.socks_port", socketserver_port)
+  Services.prefs.setCharPref("network.proxy.no_proxies_on", "")
+  Services.prefs.setIntPref("network.proxy.type", 1)
+
+  var chan = makeChan()
+  chan.asyncOpen2(listener)
+
+  do_test_pending()
+}
+
 function nextTest() {
   transportAvailable = false;
 
   if (tests.length == 0) {
     do_test_finished();
     return;
   }
 
   (tests.shift())();
   do_test_finished();
 }
 
 var tests = [
   test_connectonly,
-  // test_connectonly_noproxy,
+  test_connectonly_noproxy,
+  test_connectonly_nonhttp
 ];
 
 function clearPrefs() {
   Services.prefs.clearUserPref("network.proxy.ssl");
   Services.prefs.clearUserPref("network.proxy.ssl_port");
+  Services.prefs.clearUserPref("network.proxy.socks");
+  Services.prefs.clearUserPref("network.proxy.socks_port");
   Services.prefs.clearUserPref("network.proxy.no_proxies_on");
   Services.prefs.clearUserPref("network.proxy.type");
 }
 
 function run_test() {
   createProxy();
 
   registerCleanupFunction(clearPrefs);
--- a/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/images3/object-position-svg-002e.html.ini
+++ b/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/images3/object-position-svg-002e.html.ini
@@ -1,4 +1,3 @@
 [object-position-svg-002e.html]
   expected:
-    if not debug and webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): PASS
     FAIL
deleted file mode 100644
--- a/toolkit/content/components.css
+++ /dev/null
@@ -1,14 +0,0 @@
-/* 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/. */
-
-/* ===== components.css ==================================================
-   ==
-   == THESE STYLES HAVE BEEN MOVED TO "widgets.css".
-   ==
-   == This file exists to allow debugging regressions more easily using
-   == just artifact builds, and will be removed in bug 1470873.
-   ==
-   ======================================================================= */
-
-
--- a/toolkit/content/jar.mn
+++ b/toolkit/content/jar.mn
@@ -1,14 +1,13 @@
 toolkit.jar:
 %  content global %content/global/ contentaccessible=yes
 *  content/global/license.html
    content/global/minimal-xul.css
 *  content/global/xul.css
-   content/global/components.css
    content/global/autocomplete.css
    content/global/aboutAbout.js
    content/global/aboutAbout.xhtml
 #ifdef MOZILLA_OFFICIAL
    content/global/aboutRights.xhtml
 #else
    content/global/aboutRights.xhtml           (aboutRights-unbranded.xhtml)
 #endif
--- a/widget/windows/moz.build
+++ b/widget/windows/moz.build
@@ -55,17 +55,16 @@ UNIFIED_SOURCES += [
     'LSPAnnotator.cpp',
     'nsAppShell.cpp',
     'nsClipboard.cpp',
     'nsColorPicker.cpp',
     'nsDataObj.cpp',
     'nsDataObjCollection.cpp',
     'nsDragService.cpp',
     'nsIdleServiceWin.cpp',
-    'nsImageClipboard.cpp',
     'nsLookAndFeel.cpp',
     'nsNativeDragSource.cpp',
     'nsNativeDragTarget.cpp',
     'nsNativeThemeWin.cpp',
     'nsSound.cpp',
     'nsToolkit.cpp',
     'nsUXThemeData.cpp',
     'nsWindow.cpp',
--- a/widget/windows/nsClipboard.cpp
+++ b/widget/windows/nsClipboard.cpp
@@ -20,26 +20,27 @@
 #include "nsIFormatConverter.h"
 #include "nsITransferable.h"
 #include "nsCOMPtr.h"
 #include "nsXPCOM.h"
 #include "nsISupportsPrimitives.h"
 #include "nsReadableUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsPrimitiveHelpers.h"
-#include "nsImageClipboard.h"
 #include "nsIWidget.h"
 #include "nsIComponentManager.h"
 #include "nsWidgetsCID.h"
 #include "nsCRT.h"
 #include "nsNetUtil.h"
 #include "nsIFileProtocolHandler.h"
 #include "nsIOutputStream.h"
 #include "nsEscape.h"
 #include "nsIObserverService.h"
+#include "nsMimeTypes.h"
+#include "imgITools.h"
 
 using mozilla::LogLevel;
 
 static mozilla::LazyLogModule gWin32ClipboardLog("nsClipboard");
 
 // oddly, this isn't in the MSVC headers anywhere.
 UINT nsClipboard::CF_HTML = ::RegisterClipboardFormatW(L"HTML Format");
 UINT nsClipboard::CF_CUSTOMTYPES = ::RegisterClipboardFormatW(L"application/x-moz-custom-clipdata");
@@ -469,27 +470,49 @@ nsresult nsClipboard::GetNativeDataOffCl
                   result = NS_OK;
                 }
               } break;
 
             case CF_DIBV5:
               if (aMIMEImageFormat)
               {
                 uint32_t allocLen = 0;
-                unsigned char * clipboardData;
+                const char* clipboardData;
                 if (NS_SUCCEEDED(GetGlobalData(stm.hGlobal, (void **)&clipboardData, &allocLen)))
                 {
-                  nsImageFromClipboard converter;
-                  nsIInputStream * inputStream;
-                  converter.GetEncodedImageStream(clipboardData, aMIMEImageFormat, &inputStream);   // addrefs for us, don't release
-                  if ( inputStream ) {
-                    *aData = inputStream;
-                    *aLen = sizeof(nsIInputStream*);
-                    result = NS_OK;
+                  nsCOMPtr<imgIContainer> container;
+                  nsCOMPtr<imgITools> imgTools = do_CreateInstance("@mozilla.org/image/tools;1");
+                  result = imgTools->DecodeImageFromBuffer(clipboardData, allocLen,
+                                                           NS_LITERAL_CSTRING(IMAGE_BMP_MS_CLIPBOARD),
+                                                           getter_AddRefs(container));
+                  if (NS_FAILED(result)) {
+                    break;
+                  }
+
+                  nsAutoCString mimeType;
+                  if (strcmp(aMIMEImageFormat, kJPGImageMime) == 0) {
+                    mimeType.Assign(IMAGE_JPEG);
+                  } else {
+                    mimeType.Assign(aMIMEImageFormat);
                   }
+
+                  nsCOMPtr<nsIInputStream> inputStream;
+                  result = imgTools->EncodeImage(container, mimeType, EmptyString(),
+                                                 getter_AddRefs(inputStream));
+                  if (NS_FAILED(result)) {
+                    break;
+                  }
+
+                  if (!inputStream) {
+                    result = NS_ERROR_FAILURE;
+                    break;
+                  }
+
+                  *aData = inputStream.forget().take();
+                  *aLen = sizeof(nsIInputStream*);
                 }
               } break;
 
             case CF_HDROP : 
               {
                 // in the case of a file drop, multiple files are stashed within a
                 // single data object. In order to match mozilla's D&D apis, we
                 // just pull out the file at the requested index, pretending as
--- a/widget/windows/nsDataObj.cpp
+++ b/widget/windows/nsDataObj.cpp
@@ -12,17 +12,16 @@
 #include "nsArrayUtils.h"
 #include "nsClipboard.h"
 #include "nsReadableUtils.h"
 #include "nsITransferable.h"
 #include "nsISupportsPrimitives.h"
 #include "IEnumFE.h"
 #include "nsPrimitiveHelpers.h"
 #include "nsString.h"
-#include "nsImageClipboard.h"
 #include "nsCRT.h"
 #include "nsPrintfCString.h"
 #include "nsIStringBundle.h"
 #include "nsEscape.h"
 #include "nsIURL.h"
 #include "nsNetUtil.h"
 #include "mozilla/Services.h"
 #include "nsIOutputStream.h"
@@ -30,25 +29,28 @@
 #include "nsDirectoryServiceDefs.h"
 #include "nsITimer.h"
 #include "nsThreadUtils.h"
 #include "mozilla/Preferences.h"
 #include "nsIContentPolicy.h"
 #include "nsContentUtils.h"
 #include "nsIPrincipal.h"
 #include "nsNativeCharsetUtils.h"
+#include "nsMimeTypes.h"
+#include "imgITools.h"
 
 #include "WinUtils.h"
 #include "mozilla/LazyIdleThread.h"
 #include <algorithm>
 
 
 using namespace mozilla;
 using namespace mozilla::widget;
 
+#define BFH_LENGTH 14
 #define DEFAULT_THREAD_TIMEOUT_MS 30000
 
 NS_IMPL_ISUPPORTS(nsDataObj::CStream, nsIStreamListener)
 
 //-----------------------------------------------------------------------------
 // CStream implementation
 nsDataObj::CStream::CStream() :
   mChannelRead(false),
@@ -897,30 +899,70 @@ nsDataObj::GetDib(const nsACString& inFl
                   STGMEDIUM & aSTG)
 {
   ULONG result = E_FAIL;
   uint32_t len = 0;
   nsCOMPtr<nsISupports> genericDataWrapper;
   mTransferable->GetTransferData(PromiseFlatCString(inFlavor).get(), getter_AddRefs(genericDataWrapper), &len);
   nsCOMPtr<imgIContainer> image ( do_QueryInterface(genericDataWrapper) );
   if ( image ) {
-    // use the |nsImageToClipboard| helper class to build up a bitmap. We now own
-    // the bits, and pass them back to the OS in |aSTG|.
-    nsImageToClipboard converter(image, aFormat.cfFormat == CF_DIBV5);
-    HANDLE bits = nullptr;
-    nsresult rv = converter.GetPicture ( &bits );
-    if ( NS_SUCCEEDED(rv) && bits ) {
-      aSTG.hGlobal = bits;
-      aSTG.tymed = TYMED_HGLOBAL;
-      result = S_OK;
+    nsCOMPtr<imgITools> imgTools = do_CreateInstance("@mozilla.org/image/tools;1");
+
+    nsAutoString options;
+    if (aFormat.cfFormat == CF_DIBV5) {
+      options.AppendLiteral("version=5");
+    } else {
+      options.AppendLiteral("version=3");
+    }
+
+    nsCOMPtr<nsIInputStream> inputStream;
+    nsresult rv = imgTools->EncodeImage(image, NS_LITERAL_CSTRING(IMAGE_BMP),
+                                        options, getter_AddRefs(inputStream));
+    if (NS_FAILED(rv) || !inputStream) {
+      return E_FAIL;
+    }
+
+    nsCOMPtr<imgIEncoder> encoder = do_QueryInterface(inputStream);
+    if (!encoder) {
+      return E_FAIL;
+    }
+
+    uint32_t size = 0;
+    rv = encoder->GetImageBufferUsed(&size);
+    if (NS_FAILED(rv) || size <= BFH_LENGTH) {
+      return E_FAIL;
     }
-  } // if we have an image
-  else  
+
+    char *src = nullptr;
+    rv = encoder->GetImageBuffer(&src);
+    if (NS_FAILED(rv) || !src) {
+      return E_FAIL;
+    }
+
+    // We don't want the file header.
+    src += BFH_LENGTH;
+    size -= BFH_LENGTH;
+
+    HGLOBAL glob = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, size);
+    if (!glob) {
+      DWORD err = ::GetLastError();
+      return E_FAIL;
+    }
+
+    char *dst = (char*) ::GlobalLock(glob);
+    ::CopyMemory(dst, src, size);
+    ::GlobalUnlock(glob);
+
+    aSTG.hGlobal = glob;
+    aSTG.tymed = TYMED_HGLOBAL;
+    result = S_OK;
+  } else {
     NS_WARNING ( "Definitely not an image on clipboard" );
-	return result;
+  }
+  return result;
 }
 
 
 
 //
 // GetFileDescriptor
 //
 
@@ -1499,89 +1541,81 @@ HRESULT nsDataObj::DropImage(FORMATETC& 
     uint32_t len = 0;
     nsCOMPtr<nsISupports> genericDataWrapper;
 
     mTransferable->GetTransferData(kNativeImageMime, getter_AddRefs(genericDataWrapper), &len);
     nsCOMPtr<imgIContainer> image(do_QueryInterface(genericDataWrapper));
     if (!image) 
       return E_FAIL;
 
-    // Use the clipboard helper class to build up a memory bitmap.
-    nsImageToClipboard converter(image);
-    HANDLE bits = nullptr;
-    rv = converter.GetPicture(&bits); // Clipboard routines return a global handle we own.
+    nsCOMPtr<imgITools> imgTools = do_CreateInstance("@mozilla.org/image/tools;1");
+    nsCOMPtr<nsIInputStream> inputStream;
+    rv = imgTools->EncodeImage(image, NS_LITERAL_CSTRING(IMAGE_BMP),
+                               NS_LITERAL_STRING("version=3"),
+                               getter_AddRefs(inputStream));
+    if (NS_FAILED(rv) || !inputStream) {
+      return E_FAIL;
+    }
 
-    if (NS_FAILED(rv) || !bits)
+    nsCOMPtr<imgIEncoder> encoder = do_QueryInterface(inputStream);
+    if (!encoder) {
       return E_FAIL;
+    }
 
-    // We now own these bits!
-    uint32_t bitmapSize = GlobalSize(bits);
-    if (!bitmapSize) {
-      GlobalFree(bits);
+    uint32_t size = 0;
+    rv = encoder->GetImageBufferUsed(&size);
+    if (NS_FAILED(rv)) {
+      return E_FAIL;
+    }
+
+    char *src = nullptr;
+    rv = encoder->GetImageBuffer(&src);
+    if (NS_FAILED(rv) || !src) {
       return E_FAIL;
     }
 
     // Save the bitmap to a temporary location.      
     nsCOMPtr<nsIFile> dropFile;
     rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(dropFile));
     if (!dropFile) {
-      GlobalFree(bits);
       return E_FAIL;
     }
 
     // Filename must be random so as not to confuse apps like
     // Photoshop which handle multiple drags into a single window.
     char buf[13];
     nsCString filename;
     NS_MakeRandomString(buf, 8);
     memcpy(buf+8, ".bmp", 5);
     filename.Append(nsDependentCString(buf, 12));
     dropFile->AppendNative(filename);
     rv = dropFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0660);
     if (NS_FAILED(rv)) { 
-      GlobalFree(bits);
       return E_FAIL;
     }
 
     // Cache the temp file so we can delete it later and so
     // it doesn't get recreated over and over on multiple calls
     // which does occur from windows shell.
     dropFile->Clone(getter_AddRefs(mCachedTempFile));
 
     // Write the data to disk.
     nsCOMPtr<nsIOutputStream> outStream;
     rv = NS_NewLocalFileOutputStream(getter_AddRefs(outStream), dropFile);
     if (NS_FAILED(rv)) { 
-      GlobalFree(bits);
       return E_FAIL;
     }
 
-    char * bm = (char *)GlobalLock(bits);
-
-    BITMAPFILEHEADER	fileHdr;
-    BITMAPINFOHEADER *bmpHdr = (BITMAPINFOHEADER*)bm;
-
-    fileHdr.bfType        = ((WORD) ('M' << 8) | 'B');
-    fileHdr.bfSize        = GlobalSize (bits) + sizeof(fileHdr);
-    fileHdr.bfReserved1   = 0;
-    fileHdr.bfReserved2   = 0;
-    fileHdr.bfOffBits     = (DWORD) (sizeof(fileHdr) + bmpHdr->biSize);
-
-    uint32_t writeCount = 0;
-    if (NS_FAILED(outStream->Write((const char *)&fileHdr, sizeof(fileHdr), &writeCount)) ||
-        NS_FAILED(outStream->Write((const char *)bm, bitmapSize, &writeCount)))
-      rv = NS_ERROR_FAILURE;
+    uint32_t written = 0;
+    rv = outStream->Write(src, size, &written);
+    if (NS_FAILED(rv) || written != size) {
+      return E_FAIL;
+    }
 
     outStream->Close();
-
-    GlobalUnlock(bits);
-    GlobalFree(bits);
-
-    if (NS_FAILED(rv))
-      return E_FAIL;
   }
   
   // Pass the file name back to the drop target so that it can access the file.
   nsAutoString path;
   rv = mCachedTempFile->GetPath(path);
   if (NS_FAILED(rv))
     return E_FAIL;
 
deleted file mode 100644
--- a/widget/windows/nsImageClipboard.cpp
+++ /dev/null
@@ -1,496 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- 
-#include "nsImageClipboard.h"
-
-#include "gfxUtils.h"
-#include "mozilla/gfx/2D.h"
-#include "mozilla/gfx/DataSurfaceHelpers.h"
-#include "mozilla/RefPtr.h"
-#include "nsITransferable.h"
-#include "nsGfxCIID.h"
-#include "nsMemory.h"
-#include "imgIEncoder.h"
-#include "nsLiteralString.h"
-#include "nsComponentManagerUtils.h"
-
-#define BFH_LENGTH 14
-
-using namespace mozilla;
-using namespace mozilla::gfx;
-
-/* Things To Do 11/8/00
-
-Check image metrics, can we support them? Do we need to?
-Any other render format? HTML?
-
-*/
-
-
-//
-// nsImageToClipboard ctor
-//
-// Given an imgIContainer, convert it to a DIB that is ready to go on the win32 clipboard
-//
-nsImageToClipboard::nsImageToClipboard(imgIContainer* aInImage, bool aWantDIBV5)
-  : mImage(aInImage)
-  , mWantDIBV5(aWantDIBV5)
-{
-  // nothing to do here
-}
-
-
-//
-// nsImageToClipboard dtor
-//
-// Clean up after ourselves. We know that we have created the bitmap
-// successfully if we still have a pointer to the header.
-//
-nsImageToClipboard::~nsImageToClipboard()
-{
-}
-
-
-//
-// GetPicture
-//
-// Call to get the actual bits that go on the clipboard. If an error 
-// ocurred during conversion, |outBits| will be null.
-//
-// NOTE: The caller owns the handle and must delete it with ::GlobalRelease()
-//
-nsresult
-nsImageToClipboard :: GetPicture ( HANDLE* outBits )
-{
-  NS_ASSERTION ( outBits, "Bad parameter" );
-
-  return CreateFromImage ( mImage, outBits );
-
-} // GetPicture
-
-
-//
-// CalcSize
-//
-// Computes # of bytes needed by a bitmap with the specified attributes.
-//
-int32_t 
-nsImageToClipboard :: CalcSize ( int32_t aHeight, int32_t aColors, WORD aBitsPerPixel, int32_t aSpanBytes )
-{
-  int32_t HeaderMem = sizeof(BITMAPINFOHEADER);
-
-  // add size of pallette to header size
-  if (aBitsPerPixel < 16)
-    HeaderMem += aColors * sizeof(RGBQUAD);
-
-  if (aHeight < 0)
-    aHeight = -aHeight;
-
-  return (HeaderMem + (aHeight * aSpanBytes));
-}
-
-
-//
-// CalcSpanLength
-//
-// Computes the span bytes for determining the overall size of the image
-//
-int32_t 
-nsImageToClipboard::CalcSpanLength(uint32_t aWidth, uint32_t aBitCount)
-{
-  int32_t spanBytes = (aWidth * aBitCount) >> 5;
-  
-  if ((aWidth * aBitCount) & 0x1F)
-    spanBytes++;
-  spanBytes <<= 2;
-
-  return spanBytes;
-}
-
-
-//
-// CreateFromImage
-//
-// Do the work to setup the bitmap header and copy the bits out of the
-// image. 
-//
-nsresult
-nsImageToClipboard::CreateFromImage ( imgIContainer* inImage, HANDLE* outBitmap )
-{
-    nsresult rv;
-    *outBitmap = nullptr;
-
-    RefPtr<SourceSurface> surface =
-      inImage->GetFrame(imgIContainer::FRAME_CURRENT,
-                        imgIContainer::FLAG_SYNC_DECODE);
-    NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE);
-
-    MOZ_ASSERT(surface->GetFormat() == SurfaceFormat::B8G8R8A8 ||
-               surface->GetFormat() == SurfaceFormat::B8G8R8X8);
-
-    RefPtr<DataSourceSurface> dataSurface;
-    if (surface->GetFormat() == SurfaceFormat::B8G8R8A8) {
-      dataSurface = surface->GetDataSurface();
-    } else {
-      // XXXjwatt Bug 995923 - get rid of this copy and handle B8G8R8X8
-      // directly below once bug 995807 is fixed.
-      dataSurface = gfxUtils::
-        CopySurfaceToDataSourceSurfaceWithFormat(surface,
-                                                 SurfaceFormat::B8G8R8A8);
-    }
-    NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
-
-    nsCOMPtr<imgIEncoder> encoder = do_CreateInstance("@mozilla.org/image/encoder;2?type=image/bmp", &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-    
-    uint32_t format;
-    nsAutoString options;
-    if (mWantDIBV5) {
-      options.AppendLiteral("version=5;bpp=");
-    } else {
-      options.AppendLiteral("version=3;bpp=");
-    }
-    switch (dataSurface->GetFormat()) {
-    case SurfaceFormat::B8G8R8A8:
-        format = imgIEncoder::INPUT_FORMAT_HOSTARGB;
-        options.AppendInt(32);
-        break;
-#if 0
-    // XXXjwatt Bug 995923 - fix |format| and reenable once bug 995807 is fixed.
-    case SurfaceFormat::B8G8R8X8:
-        format = imgIEncoder::INPUT_FORMAT_RGB;
-        options.AppendInt(24);
-        break;
-#endif
-    default:
-        MOZ_ASSERT_UNREACHABLE("Unexpected surface format");
-        return NS_ERROR_INVALID_ARG;  
-    }
-
-    DataSourceSurface::MappedSurface map;
-    bool mappedOK = dataSurface->Map(DataSourceSurface::MapType::READ, &map);
-    NS_ENSURE_TRUE(mappedOK, NS_ERROR_FAILURE);
-
-    rv = encoder->InitFromData(map.mData, 0,
-                               dataSurface->GetSize().width,
-                               dataSurface->GetSize().height,
-                               map.mStride,
-                               format, options);
-    dataSurface->Unmap();
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    uint32_t size;
-    encoder->GetImageBufferUsed(&size);
-    NS_ENSURE_TRUE(size > BFH_LENGTH, NS_ERROR_FAILURE);
-    HGLOBAL glob = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT,
-                                 size - BFH_LENGTH);
-    if (!glob)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    char *dst = (char*) ::GlobalLock(glob);
-    char *src;
-    rv = encoder->GetImageBuffer(&src);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    ::CopyMemory(dst, src + BFH_LENGTH, size - BFH_LENGTH);
-    ::GlobalUnlock(glob);
-    
-    *outBitmap = (HANDLE)glob;
-    return NS_OK;
-}
-
-nsImageFromClipboard :: nsImageFromClipboard ()
-{
-  // nothing to do here
-}
-
-nsImageFromClipboard :: ~nsImageFromClipboard ( )
-{
-}
-
-//
-// GetEncodedImageStream
-//
-// Take the raw clipboard image data and convert it to aMIMEFormat in the form of a nsIInputStream
-//
-nsresult 
-nsImageFromClipboard ::GetEncodedImageStream (unsigned char * aClipboardData, const char * aMIMEFormat, nsIInputStream** aInputStream )
-{
-  NS_ENSURE_ARG_POINTER (aInputStream);
-  NS_ENSURE_ARG_POINTER (aMIMEFormat);
-  nsresult rv;
-  *aInputStream = nullptr;
-
-  // pull the size information out of the BITMAPINFO header and
-  // initialize the image
-  BITMAPINFO* header = (BITMAPINFO *) aClipboardData;
-  int32_t width  = header->bmiHeader.biWidth;
-  int32_t height = header->bmiHeader.biHeight;
-  // neg. heights mean the Y axis is inverted and we don't handle that case
-  NS_ENSURE_TRUE(height > 0, NS_ERROR_FAILURE); 
-
-  unsigned char * rgbData = new unsigned char[width * height * 3 /* RGB */];
-
-  if (rgbData) {
-    BYTE  * pGlobal = (BYTE *) aClipboardData;
-    // Convert the clipboard image into RGB packed pixel data
-    rv = ConvertColorBitMap((unsigned char *) (pGlobal + header->bmiHeader.biSize), header, rgbData);
-    // if that succeeded, encode the bitmap as aMIMEFormat data. Don't return early or we risk leaking rgbData
-    if (NS_SUCCEEDED(rv)) {
-      nsAutoCString encoderCID(NS_LITERAL_CSTRING("@mozilla.org/image/encoder;2?type="));
-
-      // Map image/jpg to image/jpeg (which is how the encoder is registered).
-      if (strcmp(aMIMEFormat, kJPGImageMime) == 0)
-        encoderCID.AppendLiteral("image/jpeg");
-      else
-        encoderCID.Append(aMIMEFormat);
-      nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(encoderCID.get(), &rv);
-      if (NS_SUCCEEDED(rv)){
-        rv = encoder->InitFromData(rgbData, 0, width, height, 3 * width /* RGB * # pixels in a row */, 
-                                   imgIEncoder::INPUT_FORMAT_RGB, EmptyString());
-        if (NS_SUCCEEDED(rv)) {
-          encoder.forget(aInputStream);
-        }
-      }
-    }
-    delete [] rgbData;
-  } 
-  else 
-    rv = NS_ERROR_OUT_OF_MEMORY;
-
-  return rv;
-} // GetImage
-
-//
-// InvertRows
-//
-// Take the image data from the clipboard and invert the rows. Modifying aInitialBuffer in place.
-//
-void
-nsImageFromClipboard::InvertRows(unsigned char * aInitialBuffer, uint32_t aSizeOfBuffer, uint32_t aNumBytesPerRow)
-{
-  if (!aNumBytesPerRow) 
-    return; 
-
-  uint32_t numRows = aSizeOfBuffer / aNumBytesPerRow;
-  unsigned char * row = new unsigned char[aNumBytesPerRow];
-
-  uint32_t currentRow = 0;
-  uint32_t lastRow = (numRows - 1) * aNumBytesPerRow;
-  while (currentRow < lastRow)
-  {
-    // store the current row into a temporary buffer
-    memcpy(row, &aInitialBuffer[currentRow], aNumBytesPerRow);
-    memcpy(&aInitialBuffer[currentRow], &aInitialBuffer[lastRow], aNumBytesPerRow);
-    memcpy(&aInitialBuffer[lastRow], row, aNumBytesPerRow);
-    lastRow -= aNumBytesPerRow;
-    currentRow += aNumBytesPerRow;
-  }
-
-  delete[] row;
-}
-
-//
-// ConvertColorBitMap
-//
-// Takes the clipboard bitmap and converts it into a RGB packed pixel values.
-//
-nsresult 
-nsImageFromClipboard::ConvertColorBitMap(unsigned char * aInputBuffer, PBITMAPINFO pBitMapInfo, unsigned char * aOutBuffer)
-{
-  uint8_t bitCount = pBitMapInfo->bmiHeader.biBitCount; 
-  uint32_t imageSize = pBitMapInfo->bmiHeader.biSizeImage; // may be zero for BI_RGB bitmaps which means we need to calculate by hand
-  uint32_t bytesPerPixel = bitCount / 8;
-  
-  if (bitCount <= 4)
-    bytesPerPixel = 1;
-
-  // rows are DWORD aligned. Calculate how many real bytes are in each row in the bitmap. This number won't 
-  // correspond to biWidth.
-  uint32_t rowSize = (bitCount * pBitMapInfo->bmiHeader.biWidth + 7) / 8; // +7 to round up
-  if (rowSize % 4)
-    rowSize += (4 - (rowSize % 4)); // Pad to DWORD Boundary
-  
-  // if our buffer includes a color map, skip over it 
-  if (bitCount <= 8)
-  {
-    int32_t bytesToSkip = (pBitMapInfo->bmiHeader.biClrUsed ? pBitMapInfo->bmiHeader.biClrUsed : (1 << bitCount) ) * sizeof(RGBQUAD);
-    aInputBuffer +=  bytesToSkip;
-  }
-
-  bitFields colorMasks; // only used if biCompression == BI_BITFIELDS
-
-  if (pBitMapInfo->bmiHeader.biCompression == BI_BITFIELDS)
-  {
-    // color table consists of 3 DWORDS containing the color masks...
-    colorMasks.red = (*((uint32_t*)&(pBitMapInfo->bmiColors[0]))); 
-    colorMasks.green = (*((uint32_t*)&(pBitMapInfo->bmiColors[1]))); 
-    colorMasks.blue = (*((uint32_t*)&(pBitMapInfo->bmiColors[2]))); 
-    CalcBitShift(&colorMasks);
-    aInputBuffer += 3 * sizeof(DWORD);
-  } 
-  else if (pBitMapInfo->bmiHeader.biCompression == BI_RGB && !imageSize)  // BI_RGB can have a size of zero which means we figure it out
-  {
-    // XXX: note use rowSize here and not biWidth. rowSize accounts for the DWORD padding for each row
-    imageSize = rowSize * pBitMapInfo->bmiHeader.biHeight;
-  }
-
-  // The windows clipboard image format inverts the rows 
-  InvertRows(aInputBuffer, imageSize, rowSize);
-
-  if (!pBitMapInfo->bmiHeader.biCompression || pBitMapInfo->bmiHeader.biCompression == BI_BITFIELDS) 
-  {  
-    uint32_t index = 0;
-    uint32_t writeIndex = 0;
-     
-    unsigned char redValue, greenValue, blueValue;
-    uint8_t colorTableEntry = 0;
-    int8_t bit; // used for grayscale bitmaps where each bit is a pixel
-    uint32_t numPixelsLeftInRow = pBitMapInfo->bmiHeader.biWidth; // how many more pixels do we still need to read for the current row
-    uint32_t pos = 0;
-
-    while (index < imageSize)
-    {
-      switch (bitCount) 
-      {
-        case 1:
-          for (bit = 7; bit >= 0 && numPixelsLeftInRow; bit--)
-          {
-            colorTableEntry = (aInputBuffer[index] >> bit) & 1;
-            aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbRed;
-            aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbGreen;
-            aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbBlue;
-            numPixelsLeftInRow--;
-          }
-          pos += 1;
-          break;
-        case 4:
-          {
-            // each aInputBuffer[index] entry contains data for two pixels.
-            // read the first pixel
-            colorTableEntry = aInputBuffer[index] >> 4;
-            aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbRed;
-            aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbGreen;
-            aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbBlue;
-            numPixelsLeftInRow--;
-
-            if (numPixelsLeftInRow) // now read the second pixel
-            {
-              colorTableEntry = aInputBuffer[index] & 0xF;
-              aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbRed;
-              aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbGreen;
-              aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbBlue;
-              numPixelsLeftInRow--;
-            }
-            pos += 1;
-          }
-          break;
-        case 8:
-          aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[aInputBuffer[index]].rgbRed;
-          aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[aInputBuffer[index]].rgbGreen;
-          aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[aInputBuffer[index]].rgbBlue;
-          numPixelsLeftInRow--;
-          pos += 1;    
-          break;
-        case 16:
-          {
-            uint16_t num = 0;
-            num = (uint8_t) aInputBuffer[index+1];
-            num <<= 8;
-            num |= (uint8_t) aInputBuffer[index];
-
-            redValue = ((uint32_t) (((float)(num & 0xf800) / 0xf800) * 0xFF0000) & 0xFF0000)>> 16;
-            greenValue =  ((uint32_t)(((float)(num & 0x07E0) / 0x07E0) * 0x00FF00) & 0x00FF00)>> 8;
-            blueValue =  ((uint32_t)(((float)(num & 0x001F) / 0x001F) * 0x0000FF) & 0x0000FF);
-
-            // now we have the right RGB values...
-            aOutBuffer[writeIndex++] = redValue;
-            aOutBuffer[writeIndex++] = greenValue;
-            aOutBuffer[writeIndex++] = blueValue;
-            numPixelsLeftInRow--;
-            pos += 2;          
-          }
-          break;
-        case 32:
-        case 24:
-          if (pBitMapInfo->bmiHeader.biCompression == BI_BITFIELDS)
-          {
-            uint32_t val = *((uint32_t*) (aInputBuffer + index) );
-            aOutBuffer[writeIndex++] = (val & colorMasks.red) >> colorMasks.redRightShift << colorMasks.redLeftShift;
-            aOutBuffer[writeIndex++] =  (val & colorMasks.green) >> colorMasks.greenRightShift << colorMasks.greenLeftShift;
-            aOutBuffer[writeIndex++] = (val & colorMasks.blue) >> colorMasks.blueRightShift << colorMasks.blueLeftShift;
-            numPixelsLeftInRow--;
-            pos += 4; // we read in 4 bytes of data in order to process this pixel
-          }
-          else
-          {
-            aOutBuffer[writeIndex++] = aInputBuffer[index+2];
-            aOutBuffer[writeIndex++] =  aInputBuffer[index+1];
-            aOutBuffer[writeIndex++] = aInputBuffer[index];
-            numPixelsLeftInRow--;
-            pos += bytesPerPixel; // 3 bytes for 24 bit data, 4 bytes for 32 bit data (we skip over the 4th byte)...
-          }
-          break;
-        default:
-          // This is probably the wrong place to check this...
-          return NS_ERROR_FAILURE;
-      }
-
-      index += bytesPerPixel; // increment our loop counter
-
-      if (!numPixelsLeftInRow)
-      {
-        if (rowSize != pos)
-        {
-          // advance index to skip over remaining padding bytes
-          index += (rowSize - pos);
-        }
-        numPixelsLeftInRow = pBitMapInfo->bmiHeader.biWidth;
-        pos = 0; 
-      }
-
-    } // while we still have bytes to process
-  }
-
-  return NS_OK;
-}
-
-void nsImageFromClipboard::CalcBitmask(uint32_t aMask, uint8_t& aBegin, uint8_t& aLength)
-{
-  // find the rightmost 1
-  uint8_t pos;
-  bool started = false;
-  aBegin = aLength = 0;
-  for (pos = 0; pos <= 31; pos++) 
-  {
-    if (!started && (aMask & (1 << pos))) 
-    {
-      aBegin = pos;
-      started = true;
-    }
-    else if (started && !(aMask & (1 << pos))) 
-    {
-      aLength = pos - aBegin;
-      break;
-    }
-  }
-}
-
-void nsImageFromClipboard::CalcBitShift(bitFields * aColorMask)
-{
-  uint8_t begin, length;
-  // red
-  CalcBitmask(aColorMask->red, begin, length);
-  aColorMask->redRightShift = begin;
-  aColorMask->redLeftShift = 8 - length;
-  // green
-  CalcBitmask(aColorMask->green, begin, length);
-  aColorMask->greenRightShift = begin;
-  aColorMask->greenLeftShift = 8 - length;
-  // blue
-  CalcBitmask(aColorMask->blue, begin, length);
-  aColorMask->blueRightShift = begin;
-  aColorMask->blueLeftShift = 8 - length;
-}
deleted file mode 100644
--- a/widget/windows/nsImageClipboard.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef nsImageClipboard_h
-#define nsImageClipboard_h
-
-/* Things To Do 11/8/00
-
-Check image metrics, can we support them? Do we need to?
-Any other render format? HTML?
-
-*/
-
-#include "nsError.h"
-#include <windows.h>
-
-#include "nsCOMPtr.h"
-#include "imgIContainer.h"
-#include "nsIInputStream.h"
-
-
-//
-// nsImageToClipboard
-//
-// A utility class that takes an imgIContainer and does all the bitmap magic
-// to allow us to put it on the clipboard
-//
-class nsImageToClipboard
-{
-public:
-  explicit nsImageToClipboard(imgIContainer* aInImage, bool aWantDIBV5 = true);
-  ~nsImageToClipboard();
-
-    // Call to get the actual bits that go on the clipboard. If |nullptr|, the
-    // setup operations have failed.
-    //
-    // NOTE: The caller owns the handle and must delete it with ::GlobalRelease()
-  nsresult GetPicture ( HANDLE* outBits ) ;
-
-private:
-
-    // Computes # of bytes needed by a bitmap with the specified attributes.
-  int32_t CalcSize(int32_t aHeight, int32_t aColors, WORD aBitsPerPixel, int32_t aSpanBytes);
-  int32_t CalcSpanLength(uint32_t aWidth, uint32_t aBitCount);
-
-    // Do the work
-  nsresult CreateFromImage ( imgIContainer* inImage, HANDLE* outBitmap );
-
-  nsCOMPtr<imgIContainer> mImage;            // the image we're working with
-  bool mWantDIBV5;
-
-}; // class nsImageToClipboard
-
-
-struct bitFields {
-    uint32_t red;
-    uint32_t green;
-    uint32_t blue;
-    uint8_t redLeftShift;
-    uint8_t redRightShift;
-    uint8_t greenLeftShift;
-    uint8_t greenRightShift;
-    uint8_t blueLeftShift;
-    uint8_t blueRightShift;
-};
-
-//
-// nsImageFromClipboard
-//
-// A utility class that takes a DIB from the win32 clipboard and does
-// all the bitmap magic to convert it to a PNG or a JPEG in the form of a nsIInputStream
-//
-class nsImageFromClipboard
-{
-public:
-  nsImageFromClipboard () ;
-  ~nsImageFromClipboard ( ) ;
-  
-    // Retrieve the newly created image
-  nsresult GetEncodedImageStream (unsigned char * aClipboardData, const char * aMIMEFormat, nsIInputStream** outImage);
-
-private:
-
-  void InvertRows(unsigned char * aInitialBuffer, uint32_t aSizeOfBuffer, uint32_t aNumBytesPerRow);
-  nsresult ConvertColorBitMap(unsigned char * aInputBuffer, PBITMAPINFO pBitMapInfo, unsigned char * aOutBuffer);
-  void CalcBitmask(uint32_t aMask, uint8_t& aBegin, uint8_t& aLength);
-  void CalcBitShift(bitFields * aColorMask);
-
-}; // nsImageFromClipboard
-
-#endif
--- a/widget/windows/nsNativeThemeWin.cpp
+++ b/widget/windows/nsNativeThemeWin.cpp
@@ -6,16 +6,17 @@
 #include "nsNativeThemeWin.h"
 
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/Logging.h"
 #include "mozilla/RelativeLuminanceUtils.h"
 #include "mozilla/StaticPrefs.h"
 #include "mozilla/WindowsVersion.h"
+#include "mozilla/gfx/Types.h" // for Color::FromABGR
 #include "nsColor.h"
 #include "nsDeviceContext.h"
 #include "nsRect.h"
 #include "nsSize.h"
 #include "nsTransform2D.h"
 #include "nsStyleConsts.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
@@ -39,16 +40,17 @@
 #include "gfxWindowsSurface.h"
 #include "gfxWindowsNativeDrawing.h"
 
 #include "nsUXThemeData.h"
 #include "nsUXThemeConstants.h"
 #include <algorithm>
 
 using namespace mozilla;
+using namespace mozilla::gfx;
 using namespace mozilla::widget;
 
 extern mozilla::LazyLogModule gWindowsLog;
 
 NS_IMPL_ISUPPORTS_INHERITED(nsNativeThemeWin, nsNativeTheme, nsITheme)
 
 nsNativeThemeWin::nsNativeThemeWin() :
   mProgressDeterminateTimeStamp(TimeStamp::Now()),
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -158,17 +158,17 @@ NoteWeakMapChildrenTracer::onChild(const
   if (aThing.is<JSString>()) {
     return;
   }
 
   if (!JS::GCThingIsMarkedGray(aThing) && !mCb.WantAllTraces()) {
     return;
   }
 
-  if (AddToCCKind(aThing.kind())) {
+  if (JS::IsCCTraceKind(aThing.kind())) {
     mCb.NoteWeakMapping(mMap, mKey, mKeyDelegate, aThing);
     mTracedAny = true;
   } else {
     JS::TraceChildren(this, aThing);
   }
 }
 
 struct NoteWeakMapsTracer : public js::WeakMapTracer
@@ -193,32 +193,32 @@ NoteWeakMapsTracer::trace(JSObject* aMap
       return;
     }
   }
 
   // The cycle collector can only properly reason about weak maps if it can
   // reason about the liveness of their keys, which in turn requires that
   // the key can be represented in the cycle collector graph.  All existing
   // uses of weak maps use either objects or scripts as keys, which are okay.
-  MOZ_ASSERT(AddToCCKind(aKey.kind()));
+  MOZ_ASSERT(JS::IsCCTraceKind(aKey.kind()));
 
   // As an emergency fallback for non-debug builds, if the key is not
   // representable in the cycle collector graph, we treat it as marked.  This
   // can cause leaks, but is preferable to ignoring the binding, which could
   // cause the cycle collector to free live objects.
-  if (!AddToCCKind(aKey.kind())) {
+  if (!JS::IsCCTraceKind(aKey.kind())) {
     aKey = nullptr;
   }
 
   JSObject* kdelegate = nullptr;
   if (aKey.is<JSObject>()) {
     kdelegate = js::GetWeakmapKeyDelegate(&aKey.as<JSObject>());
   }
 
-  if (AddToCCKind(aValue.kind())) {
+  if (JS::IsCCTraceKind(aValue.kind())) {
     mCb.NoteWeakMapping(aMap, aKey, kdelegate, aValue);
   } else {
     mChildTracer.mTracedAny = false;
     mChildTracer.mMap = aMap;
     mChildTracer.mKey = aKey;
     mChildTracer.mKeyDelegate = kdelegate;
 
     if (!aValue.is<JSString>()) {
@@ -246,17 +246,17 @@ ShouldWeakMappingEntryBeBlack(JSObject* 
   // If nothing that could be held alive by this entry is marked gray, return.
   bool keyMightNeedMarking = aKey && JS::GCThingIsMarkedGray(aKey);
   bool valueMightNeedMarking = aValue && JS::GCThingIsMarkedGray(aValue) &&
     aValue.kind() != JS::TraceKind::String;
   if (!keyMightNeedMarking && !valueMightNeedMarking) {
     return;
   }
 
-  if (!AddToCCKind(aKey.kind())) {
+  if (!JS::IsCCTraceKind(aKey.kind())) {
     aKey = nullptr;
   }
 
   if (keyMightNeedMarking && aKey.is<JSObject>()) {
     JSObject* kdelegate = js::GetWeakmapKeyDelegate(&aKey.as<JSObject>());
     if (kdelegate && !JS::ObjectIsMarkedGray(kdelegate) &&
         (!aMap || !JS::ObjectIsMarkedGray(aMap)))
     {
@@ -352,17 +352,17 @@ CheckParticipatesInCycleCollection(JS::G
                                    void* aClosure)
 {
   bool* cycleCollectionEnabled = static_cast<bool*>(aClosure);
 
   if (*cycleCollectionEnabled) {
     return;
   }
 
-  if (AddToCCKind(aThing.kind()) && JS::GCThingIsMarkedGray(aThing)) {
+  if (JS::IsCCTraceKind(aThing.kind()) && JS::GCThingIsMarkedGray(aThing)) {
     *cycleCollectionEnabled = true;
   }
 }
 
 NS_IMETHODIMP
 JSGCThingParticipant::TraverseNative(void* aPtr,
                                      nsCycleCollectionTraversalCallback& aCb)
 {
@@ -416,22 +416,22 @@ TraversalTracer::onChild(const JS::GCCel
 
   // Don't traverse non-gray objects, unless we want all traces.
   if (!JS::GCThingIsMarkedGray(aThing) && !mCb.WantAllTraces()) {
     return;
   }
 
   /*
    * This function needs to be careful to avoid stack overflow. Normally, when
-   * AddToCCKind is true, the recursion terminates immediately as we just add
+   * IsCCTraceKind is true, the recursion terminates immediately as we just add
    * |thing| to the CC graph. So overflow is only possible when there are long
-   * or cyclic chains of non-AddToCCKind GC things. Places where this can occur
+   * or cyclic chains of non-IsCCTraceKind GC things. Places where this can occur
    * use special APIs to handle such chains iteratively.
    */
-  if (AddToCCKind(aThing.kind())) {
+  if (JS::IsCCTraceKind(aThing.kind())) {
     if (MOZ_UNLIKELY(mCb.WantDebugInfo())) {
       char buffer[200];
       getTracingEdgeName(buffer, sizeof(buffer));
       mCb.NoteNextEdgeName(buffer);
     }
     mCb.NoteJSChild(aThing);
   } else if (aThing.is<js::Shape>()) {
     // The maximum depth of traversal when tracing a Shape is unbounded, due to
--- a/xpcom/base/CycleCollectedJSRuntime.h
+++ b/xpcom/base/CycleCollectedJSRuntime.h
@@ -12,16 +12,17 @@
 #include "mozilla/CycleCollectedJSContext.h"
 #include "mozilla/DeferredFinalize.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/mozalloc.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/SegmentedVector.h"
 #include "jsapi.h"
 #include "jsfriendapi.h"
+#include "js/TraceKind.h"
 
 #include "nsCycleCollectionParticipant.h"
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 #include "nsTHashtable.h"
 
 class nsCycleCollectionNoteRootCallback;
 class nsIException;
@@ -407,26 +408,11 @@ private:
   ErrorInterceptor mErrorInterceptor;
 
 #endif // defined(NIGHTLY_BUILD)
 
 };
 
 void TraceScriptHolder(nsISupports* aHolder, JSTracer* aTracer);
 
-// Returns true if the JS::TraceKind is one the cycle collector cares about.
-// Everything used as WeakMap key should be listed here, to represent the key
-// in cycle collector's graph, otherwise the key is considered to be pointed
-// from somewhere unknown, and results in leaking the subgraph which contains
-// the key.
-// See the comments in NoteWeakMapsTracer::trace for more details.
-inline bool AddToCCKind(JS::TraceKind aKind)
-{
-  return aKind == JS::TraceKind::Object ||
-         aKind == JS::TraceKind::Script ||
-         aKind == JS::TraceKind::LazyScript ||
-         aKind == JS::TraceKind::Scope ||
-         aKind == JS::TraceKind::RegExpShared;
-}
-
 } // namespace mozilla
 
 #endif // mozilla_CycleCollectedJSRuntime_h
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -2057,24 +2057,24 @@ nsCycleCollector_createLogger()
 {
   nsCOMPtr<nsICycleCollectorListener> logger = new nsCycleCollectorLogger();
   return logger.forget();
 }
 
 static bool
 GCThingIsGrayCCThing(JS::GCCellPtr thing)
 {
-    return AddToCCKind(thing.kind()) &&
+    return JS::IsCCTraceKind(thing.kind()) &&
            JS::GCThingIsMarkedGray(thing);
 }
 
 static bool
 ValueIsGrayCCThing(const JS::Value& value)
 {
-    return AddToCCKind(value.traceKind()) &&
+    return JS::IsCCTraceKind(value.traceKind()) &&
            JS::GCThingIsMarkedGray(value.toGCCellPtr());
 }
 
 ////////////////////////////////////////////////////////////////////////
 // Bacon & Rajan's |MarkRoots| routine.
 ////////////////////////////////////////////////////////////////////////
 
 class CCGraphBuilder final : public nsCycleCollectionTraversalCallback,
--- a/xpcom/base/nsCycleCollectorTraceJSHelpers.cpp
+++ b/xpcom/base/nsCycleCollectorTraceJSHelpers.cpp
@@ -23,17 +23,17 @@ CycleCollectionNoteEdgeNameImpl(nsCycleC
 void
 nsCycleCollectionParticipant::NoteJSChild(JS::GCCellPtr aGCThing,
                                           const char* aName,
                                           void* aClosure)
 {
   nsCycleCollectionTraversalCallback* cb =
     static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, aName);
-  if (mozilla::AddToCCKind(aGCThing.kind())) {
+  if (JS::IsCCTraceKind(aGCThing.kind())) {
     cb->NoteJSChild(aGCThing);
   }
 }
 
 void
 TraceCallbackFunc::Trace(JS::Heap<JS::Value>* aPtr, const char* aName,
                          void* aClosure) const
 {