diff --git a/accessible/base/NotificationController.h b/accessible/base/NotificationController.h
index afb6230bb613ecde4a5e3271478a682d0396dc3b..a3a7d9786f9d18bad6afc292264b9dbc62c14cf2 100644
--- a/accessible/base/NotificationController.h
+++ b/accessible/base/NotificationController.h
@@ -276,6 +276,8 @@ class NotificationController final : public EventQueue,
   }
 #endif
 
+  bool IsUpdatePendingForJugglerAccessibility() { return IsUpdatePending(); }
+
  protected:
   virtual ~NotificationController();
 
diff --git a/accessible/interfaces/nsIAccessibleDocument.idl b/accessible/interfaces/nsIAccessibleDocument.idl
index a91df31c96afda66f478a5a38eaa4352039c2a0b..ee777c1746284027fb3aa2f1686f8082af9d89ee 100644
--- a/accessible/interfaces/nsIAccessibleDocument.idl
+++ b/accessible/interfaces/nsIAccessibleDocument.idl
@@ -72,4 +72,9 @@ interface nsIAccessibleDocument : nsISupports
    * Return the child document accessible at the given index.
    */
   nsIAccessibleDocument getChildDocumentAt(in unsigned long index);
+
+  /**
+   * Return whether it is updating.
+   */
+  readonly attribute boolean isUpdatePendingForJugglerAccessibility;
 };
diff --git a/accessible/xpcom/xpcAccessibleDocument.cpp b/accessible/xpcom/xpcAccessibleDocument.cpp
index ec83b699e1449b2610b43b35694ee18d80cee2ff..66854bda7d8c20627949289b9f2e2e161a00fea8 100644
--- a/accessible/xpcom/xpcAccessibleDocument.cpp
+++ b/accessible/xpcom/xpcAccessibleDocument.cpp
@@ -142,6 +142,15 @@ xpcAccessibleDocument::GetVirtualCursor(nsIAccessiblePivot** aVirtualCursor) {
   return NS_OK;
 }
 
+
+NS_IMETHODIMP
+xpcAccessibleDocument::GetIsUpdatePendingForJugglerAccessibility(bool* updating) {
+  NS_ENSURE_ARG_POINTER(updating);
+  *updating = Intl()->Controller()->IsUpdatePendingForJugglerAccessibility();
+  return NS_OK;
+}
+
+
 ////////////////////////////////////////////////////////////////////////////////
 // xpcAccessibleDocument
 
diff --git a/accessible/xpcom/xpcAccessibleDocument.h b/accessible/xpcom/xpcAccessibleDocument.h
index 416a1c5497c97ed80cc0f37d72545e36f7e36b4c..b81983cf7153378260a21f6af225e3493f8f30dc 100644
--- a/accessible/xpcom/xpcAccessibleDocument.h
+++ b/accessible/xpcom/xpcAccessibleDocument.h
@@ -48,6 +48,8 @@ class xpcAccessibleDocument : public xpcAccessibleHyperText,
                                 nsIAccessibleDocument** aDocument) final;
   NS_IMETHOD GetVirtualCursor(nsIAccessiblePivot** aVirtualCursor) final;
 
+  NS_IMETHOD GetIsUpdatePendingForJugglerAccessibility(bool* aUpdating) final;
+
   /**
    * Return XPCOM wrapper for the internal accessible.
    */
diff --git a/browser/app/winlauncher/LauncherProcessWin.cpp b/browser/app/winlauncher/LauncherProcessWin.cpp
index 4460774865769609b66c0710f7c83f4d5c02b6fa..2ca95607b9b093218d48f83adc95c514cebe661b 100644
--- a/browser/app/winlauncher/LauncherProcessWin.cpp
+++ b/browser/app/winlauncher/LauncherProcessWin.cpp
@@ -23,6 +23,7 @@
 #include "mozilla/WinHeaderOnlyUtils.h"
 #include "nsWindowsHelpers.h"
 
+#include <io.h>
 #include <windows.h>
 #include <processthreadsapi.h>
 
@@ -359,8 +360,19 @@ Maybe<int> LauncherMain(int& argc, wchar_t* argv[],
   HANDLE stdHandles[] = {::GetStdHandle(STD_INPUT_HANDLE),
                          ::GetStdHandle(STD_OUTPUT_HANDLE),
                          ::GetStdHandle(STD_ERROR_HANDLE)};
-
   attrs.AddInheritableHandles(stdHandles);
+  // Playwright pipe installation.
+  bool hasJugglerPipe =
+      mozilla::CheckArg(argc, argv, L"juggler-pipe",
+                        static_cast<const wchar_t**>(nullptr),
+                        mozilla::CheckArgFlag::None) == mozilla::ARG_FOUND;
+  if (hasJugglerPipe) {
+    intptr_t stdio3 = _get_osfhandle(3);
+    intptr_t stdio4 = _get_osfhandle(4);
+    HANDLE pipeHandles[] = {reinterpret_cast<HANDLE>(stdio3),
+                            reinterpret_cast<HANDLE>(stdio4)};
+    attrs.AddInheritableHandles(pipeHandles);
+  }
 
   DWORD creationFlags = CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT;
 
diff --git a/browser/installer/allowed-dupes.mn b/browser/installer/allowed-dupes.mn
index b59fe4b1854fec7cb329139f9c6773498fb9de51..29973af04902848808e850b40bf85e5f694d349a 100644
--- a/browser/installer/allowed-dupes.mn
+++ b/browser/installer/allowed-dupes.mn
@@ -71,6 +71,12 @@ browser/features/webcompat@mozilla.org/shims/empty-shim.txt
 removed-files
 #endif
 
+# Juggler/marionette files
+chrome/juggler/content/content/floating-scrollbars.css
+browser/chrome/devtools/skin/floating-scrollbars-responsive-design.css
+chrome/juggler/content/server/stream-utils.js
+chrome/marionette/content/stream-utils.js
+
 #ifdef MOZ_EME_WIN32_ARTIFACT
 gmp-clearkey/0.1/manifest.json
 i686/gmp-clearkey/0.1/manifest.json
diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in
index 73a41dc25b9ad674750ce5849a9db8f9878e5e11..e669054d361a148fff895ee24d1ea28c11d0a484 100644
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -198,6 +198,11 @@
 @RESPATH@/chrome/remote.manifest
 #endif
 
+@RESPATH@/chrome/juggler@JAREXT@
+@RESPATH@/chrome/juggler.manifest
+@RESPATH@/components/juggler.manifest
+@RESPATH@/components/juggler.js
+
 #if defined(ENABLE_TESTS) && defined(MOZ_DEBUG)
 @RESPATH@/components/TestInterfaceJS.js
 @RESPATH@/components/TestInterfaceJS.manifest
diff --git a/devtools/server/socket/websocket-server.js b/devtools/server/socket/websocket-server.js
index 040c7b124dec6bb254563bbe74fe50012cb077a3..b4e6b8132786af70e8ad0dce88b67c2835307f88 100644
--- a/devtools/server/socket/websocket-server.js
+++ b/devtools/server/socket/websocket-server.js
@@ -133,13 +133,12 @@ function writeHttpResponse(output, response) {
  * Process the WebSocket handshake headers and return the key to be sent in
  * Sec-WebSocket-Accept response header.
  */
-function processRequest({ requestLine, headers }) {
+function processRequest({ requestLine, headers }, expectedPath) {
   const [method, path] = requestLine.split(" ");
   if (method !== "GET") {
     throw new Error("The handshake request must use GET method");
   }
-
-  if (path !== "/") {
+  if (path !== expectedPath) {
     throw new Error("The handshake request has unknown path");
   }
 
@@ -189,13 +188,13 @@ function computeKey(key) {
 /**
  * Perform the server part of a WebSocket opening handshake on an incoming connection.
  */
-const serverHandshake = async function(input, output) {
+const serverHandshake = async function(input, output, expectedPath) {
   // Read the request
   const request = await readHttpRequest(input);
 
   try {
     // Check and extract info from the request
-    const { acceptKey } = processRequest(request);
+    const { acceptKey } = processRequest(request, expectedPath);
 
     // Send response headers
     await writeHttpResponse(output, [
@@ -217,8 +216,8 @@ const serverHandshake = async function(input, output) {
  * Performs the WebSocket handshake and waits for the WebSocket to open.
  * Returns Promise with a WebSocket ready to send and receive messages.
  */
-const accept = async function(transport, input, output) {
-  await serverHandshake(input, output);
+const accept = async function(transport, input, output, expectedPath) {
+  await serverHandshake(input, output, expectedPath || "/");
 
   const transportProvider = {
     setListener(upgradeListener) {
diff --git a/docshell/base/BrowsingContext.cpp b/docshell/base/BrowsingContext.cpp
index d47e8056fde52704a618fe148f0320ad94a3bad8..711d7950cd5a60569d3bd6d657f835b07f9c7a09 100644
--- a/docshell/base/BrowsingContext.cpp
+++ b/docshell/base/BrowsingContext.cpp
@@ -111,6 +111,20 @@ struct ParamTraits<mozilla::dom::PrefersColorSchemeOverride>
           mozilla::dom::PrefersColorSchemeOverride::None,
           mozilla::dom::PrefersColorSchemeOverride::EndGuard_> {};
 
+template <>
+struct ParamTraits<mozilla::dom::PrefersReducedMotionOverride>
+    : public ContiguousEnumSerializer<
+          mozilla::dom::PrefersReducedMotionOverride,
+          mozilla::dom::PrefersReducedMotionOverride::None,
+          mozilla::dom::PrefersReducedMotionOverride::EndGuard_> {};
+
+template <>
+struct ParamTraits<mozilla::dom::ForcedColorsOverride>
+    : public ContiguousEnumSerializer<
+          mozilla::dom::ForcedColorsOverride,
+          mozilla::dom::ForcedColorsOverride::None,
+          mozilla::dom::ForcedColorsOverride::EndGuard_> {};
+
 template <>
 struct ParamTraits<mozilla::dom::ExplicitActiveStatus>
     : public ContiguousEnumSerializer<
@@ -2780,6 +2794,40 @@ void BrowsingContext::DidSet(FieldIndex<IDX_PrefersColorSchemeOverride>,
   PresContextAffectingFieldChanged();
 }
 
+void BrowsingContext::DidSet(FieldIndex<IDX_PrefersReducedMotionOverride>,
+                             dom::PrefersReducedMotionOverride aOldValue) {
+  MOZ_ASSERT(IsTop());
+  if (PrefersReducedMotionOverride() == aOldValue) {
+    return;
+  }
+  PreOrderWalk([&](BrowsingContext* aContext) {
+    if (nsIDocShell* shell = aContext->GetDocShell()) {
+      if (nsPresContext* pc = shell->GetPresContext()) {
+        pc->MediaFeatureValuesChanged(
+            {MediaFeatureChangeReason::SystemMetricsChange},
+            MediaFeatureChangePropagation::JustThisDocument);
+      }
+    }
+  });
+}
+
+void BrowsingContext::DidSet(FieldIndex<IDX_ForcedColorsOverride>,
+                             dom::ForcedColorsOverride aOldValue) {
+  MOZ_ASSERT(IsTop());
+  if (ForcedColorsOverride() == aOldValue) {
+    return;
+  }
+  PreOrderWalk([&](BrowsingContext* aContext) {
+    if (nsIDocShell* shell = aContext->GetDocShell()) {
+      if (nsPresContext* pc = shell->GetPresContext()) {
+        pc->MediaFeatureValuesChanged(
+            {MediaFeatureChangeReason::SystemMetricsChange},
+            MediaFeatureChangePropagation::JustThisDocument);
+      }
+    }
+  });
+}
+
 void BrowsingContext::DidSet(FieldIndex<IDX_MediumOverride>,
                              nsString&& aOldValue) {
   MOZ_ASSERT(IsTop());
diff --git a/docshell/base/BrowsingContext.h b/docshell/base/BrowsingContext.h
index e0b091feba6ce38e57681c62c386d3b70234de1f..4fae381a8bded7ae004ccb25187b3ace559fea41 100644
--- a/docshell/base/BrowsingContext.h
+++ b/docshell/base/BrowsingContext.h
@@ -176,10 +176,10 @@ enum class ExplicitActiveStatus : uint8_t {
   FIELD(GVInaudibleAutoplayRequestStatus, GVAutoplayRequestStatus)            \
   /* ScreenOrientation-related APIs */                                        \
   FIELD(CurrentOrientationAngle, float)                                       \
-  FIELD(CurrentOrientationType, mozilla::dom::OrientationType)                \
+  FIELD(CurrentOrientationType, dom::OrientationType)                \
   FIELD(OrientationLock, mozilla::hal::ScreenOrientation)                     \
   FIELD(UserAgentOverride, nsString)                                          \
-  FIELD(TouchEventsOverrideInternal, mozilla::dom::TouchEventsOverride)       \
+  FIELD(TouchEventsOverrideInternal, dom::TouchEventsOverride)       \
   FIELD(EmbedderElementType, Maybe<nsString>)                                 \
   FIELD(MessageManagerGroup, nsString)                                        \
   FIELD(MaxTouchPointsOverride, uint8_t)                                      \
@@ -217,6 +217,10 @@ enum class ExplicitActiveStatus : uint8_t {
    * <browser> embedder element. */                                           \
   FIELD(EmbedderColorScheme, dom::PrefersColorSchemeOverride)                 \
   FIELD(DisplayMode, dom::DisplayMode)                                        \
+  /* playwright addition */                                                   \
+  FIELD(PrefersReducedMotionOverride, dom::PrefersReducedMotionOverride)      \
+  /* playwright addition */                                                   \
+  FIELD(ForcedColorsOverride, dom::ForcedColorsOverride)                      \
   /* The number of entries added to the session history because of this       \
    * browsing context. */                                                     \
   FIELD(HistoryEntryCount, uint32_t)                                          \
@@ -893,6 +897,14 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
     return GetPrefersColorSchemeOverride();
   }
 
+  dom::PrefersReducedMotionOverride PrefersReducedMotionOverride() const {
+    return GetPrefersReducedMotionOverride();
+  }
+
+  dom::ForcedColorsOverride ForcedColorsOverride() const {
+    return GetForcedColorsOverride();
+  }
+
   bool IsInBFCache() const;
 
   bool AllowJavascript() const { return GetAllowJavascript(); }
@@ -1047,6 +1059,23 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
 
   void PresContextAffectingFieldChanged();
 
+  bool CanSet(FieldIndex<IDX_PrefersReducedMotionOverride>,
+              dom::PrefersReducedMotionOverride, ContentParent*) {
+    return IsTop();
+  }
+
+  void DidSet(FieldIndex<IDX_PrefersReducedMotionOverride>,
+              dom::PrefersReducedMotionOverride aOldValue);
+
+
+  bool CanSet(FieldIndex<IDX_ForcedColorsOverride>,
+              dom::ForcedColorsOverride, ContentParent*) {
+    return IsTop();
+  }
+
+  void DidSet(FieldIndex<IDX_ForcedColorsOverride>,
+              dom::ForcedColorsOverride aOldValue);
+
   void DidSet(FieldIndex<IDX_MediumOverride>, nsString&& aOldValue);
 
   bool CanSet(FieldIndex<IDX_SuspendMediaWhenInactive>, bool, ContentParent*) {
diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
index 3c634133e2710c62c1d483b3433d2f3c71a31880..8fed12d3a50b0308c7f8ed5e56b14c8492eef420 100644
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -15,6 +15,12 @@
 #  include <unistd.h>  // for getpid()
 #endif
 
+#if JS_HAS_INTL_API && !MOZ_SYSTEM_ICU
+#  include "unicode/locid.h"
+#endif /* JS_HAS_INTL_API && !MOZ_SYSTEM_ICU */
+
+#include "js/LocaleSensitive.h"
+
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/AutoRestore.h"
@@ -65,6 +71,7 @@
 #include "mozilla/dom/ContentFrameMessageManager.h"
 #include "mozilla/dom/DocGroup.h"
 #include "mozilla/dom/Element.h"
+#include "mozilla/dom/Geolocation.h"
 #include "mozilla/dom/HTMLAnchorElement.h"
 #include "mozilla/dom/HTMLIFrameElement.h"
 #include "mozilla/dom/PerformanceNavigation.h"
@@ -90,6 +97,7 @@
 #include "mozilla/dom/JSWindowActorChild.h"
 #include "mozilla/dom/DocumentBinding.h"
 #include "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/dom/WorkerCommon.h"
 #include "mozilla/net/DocumentChannel.h"
 #include "mozilla/net/DocumentChannelChild.h"
 #include "mozilla/net/ParentChannelWrapper.h"
@@ -114,6 +122,7 @@
 #include "nsIDocShellTreeOwner.h"
 #include "mozilla/dom/Document.h"
 #include "nsHTMLDocument.h"
+#include "mozilla/dom/Element.h"
 #include "nsIDocumentLoaderFactory.h"
 #include "nsIDOMWindow.h"
 #include "nsIEditingSession.h"
@@ -208,6 +217,7 @@
 #include "nsFocusManager.h"
 #include "nsGlobalWindow.h"
 #include "nsJSEnvironment.h"
+#include "nsJSUtils.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsObjectLoadingContent.h"
@@ -371,6 +381,13 @@ nsDocShell::nsDocShell(BrowsingContext* aBrowsingContext,
       mAllowDNSPrefetch(true),
       mAllowWindowControl(true),
       mCSSErrorReportingEnabled(false),
+      mFileInputInterceptionEnabled(false),
+      mOverrideHasFocus(false),
+      mBypassCSPEnabled(false),
+      mForceActiveState(false),
+      mOnlineOverride(nsIDocShell::ONLINE_OVERRIDE_NONE),
+      mReducedMotionOverride(REDUCED_MOTION_OVERRIDE_NONE),
+      mForcedColorsOverride(FORCED_COLORS_OVERRIDE_NO_OVERRIDE),
       mAllowAuth(mItemType == typeContent),
       mAllowKeywordFixup(false),
       mDisableMetaRefreshWhenInactive(false),
@@ -3286,6 +3303,221 @@ nsDocShell::GetMessageManager(ContentFrameMessageManager** aMessageManager) {
   return NS_OK;
 }
 
+// =============== Juggler Begin =======================
+
+nsDocShell* nsDocShell::GetRootDocShell() {
+  nsCOMPtr<nsIDocShellTreeItem> rootAsItem;
+  GetInProcessSameTypeRootTreeItem(getter_AddRefs(rootAsItem));
+  nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(rootAsItem);
+  return nsDocShell::Cast(rootShell);
+}
+
+NS_IMETHODIMP
+nsDocShell::GetBypassCSPEnabled(bool* aEnabled) {
+  MOZ_ASSERT(aEnabled);
+  *aEnabled = mBypassCSPEnabled;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetBypassCSPEnabled(bool aEnabled) {
+  mBypassCSPEnabled = aEnabled;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::GetForceActiveState(bool* aEnabled) {
+  MOZ_ASSERT(aEnabled);
+  *aEnabled = mForceActiveState;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetForceActiveState(bool aEnabled) {
+  mForceActiveState = aEnabled;
+  ActivenessMaybeChanged();
+  return NS_OK;
+}
+
+bool nsDocShell::IsBypassCSPEnabled() {
+  return GetRootDocShell()->mBypassCSPEnabled;
+}
+
+NS_IMETHODIMP
+nsDocShell::GetOverrideHasFocus(bool* aEnabled) {
+  MOZ_ASSERT(aEnabled);
+  *aEnabled = mOverrideHasFocus;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetOverrideHasFocus(bool aEnabled) {
+  mOverrideHasFocus = aEnabled;
+  return NS_OK;
+}
+
+bool nsDocShell::ShouldOverrideHasFocus() const {
+  return mOverrideHasFocus;
+}
+
+NS_IMETHODIMP
+nsDocShell::GetLanguageOverride(nsAString& aLanguageOverride) {
+  aLanguageOverride = GetRootDocShell()->mLanguageOverride;
+  return NS_OK;
+}
+
+
+static void SetIcuLocale(const nsAString& aLanguageOverride) {
+  icu::Locale locale(NS_LossyConvertUTF16toASCII(aLanguageOverride).get());
+  if (icu::Locale::getDefault() == locale)
+    return;
+  UErrorCode error_code = U_ZERO_ERROR;
+  const char* lang = locale.getLanguage();
+  if (lang != nullptr && *lang != '\0') {
+    icu::Locale::setDefault(locale, error_code);
+  } else {
+    fprintf(stderr, "SetIcuLocale Failed to set the ICU default locale to %s\n", NS_LossyConvertUTF16toASCII(aLanguageOverride).get());
+  }
+
+  AutoJSAPI jsapi;
+  jsapi.Init();
+  JSContext* cx = jsapi.cx();
+  JS_ResetDefaultLocale(JS_GetRuntime(cx));
+
+  ResetDefaultLocaleInAllWorkers();
+}
+
+NS_IMETHODIMP
+nsDocShell::SetLanguageOverride(const nsAString& aLanguageOverride) {
+  mLanguageOverride = aLanguageOverride;
+  SetIcuLocale(aLanguageOverride);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::OverrideTimezone(const nsAString& aTimezoneOverride,
+                             bool* aSuccess) {
+  NS_ENSURE_ARG(aSuccess);
+  NS_LossyConvertUTF16toASCII timeZoneId(aTimezoneOverride);
+  *aSuccess = nsJSUtils::SetTimeZoneOverride(timeZoneId.get());
+
+  // Set TZ which affects localtime_s().
+  auto setTimeZoneEnv = [](const char* value) {
+#if defined(_WIN32)
+    return _putenv_s("TZ", value) == 0;
+#else
+    return setenv("TZ", value, true) == 0;
+#endif /* _WIN32 */
+  };
+  if (*aSuccess) {
+    *aSuccess = setTimeZoneEnv(timeZoneId.get());
+    if (!*aSuccess) {
+      fprintf(stderr, "Failed to set 'TZ' to '%s'\n", timeZoneId.get());
+    }
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::GetFileInputInterceptionEnabled(bool* aEnabled) {
+  MOZ_ASSERT(aEnabled);
+  *aEnabled = GetRootDocShell()->mFileInputInterceptionEnabled;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetFileInputInterceptionEnabled(bool aEnabled) {
+  mFileInputInterceptionEnabled = aEnabled;
+  return NS_OK;
+}
+
+bool nsDocShell::IsFileInputInterceptionEnabled() {
+  return GetRootDocShell()->mFileInputInterceptionEnabled;
+}
+
+void nsDocShell::FilePickerShown(mozilla::dom::Element* element) {
+  nsCOMPtr<nsIObserverService> observerService =
+      mozilla::services::GetObserverService();
+  observerService->NotifyObservers(
+      ToSupports(element), "juggler-file-picker-shown", nullptr);
+}
+
+RefPtr<nsGeolocationService> nsDocShell::GetGeolocationServiceOverride() {
+  return GetRootDocShell()->mGeolocationServiceOverride;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetGeolocationOverride(nsIDOMGeoPosition* aGeolocationOverride) {
+  if (aGeolocationOverride) {
+    if (!mGeolocationServiceOverride) {
+      mGeolocationServiceOverride = new nsGeolocationService();
+      mGeolocationServiceOverride->Init();
+    }
+    mGeolocationServiceOverride->Update(aGeolocationOverride);
+  } else {
+    mGeolocationServiceOverride = nullptr;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::GetOnlineOverride(OnlineOverride* aOnlineOverride) {
+  *aOnlineOverride = GetRootDocShell()->mOnlineOverride;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetOnlineOverride(OnlineOverride aOnlineOverride) {
+  // We don't have a way to verify this coming from Javascript, so this check is
+  // still needed.
+  if (!(aOnlineOverride == ONLINE_OVERRIDE_NONE ||
+        aOnlineOverride == ONLINE_OVERRIDE_ONLINE ||
+        aOnlineOverride == ONLINE_OVERRIDE_OFFLINE)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  mOnlineOverride = aOnlineOverride;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::GetReducedMotionOverride(ReducedMotionOverride* aReducedMotionOverride) {
+  *aReducedMotionOverride = GetRootDocShell()->mReducedMotionOverride;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetReducedMotionOverride(ReducedMotionOverride aReducedMotionOverride) {
+  mReducedMotionOverride = aReducedMotionOverride;
+  RefPtr<nsPresContext> presContext = GetPresContext();
+  if (presContext) {
+    presContext->MediaFeatureValuesChanged(
+        {MediaFeatureChangeReason::SystemMetricsChange},
+        MediaFeatureChangePropagation::JustThisDocument);
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::GetForcedColorsOverride(ForcedColorsOverride* aForcedColorsOverride) {
+  *aForcedColorsOverride = GetRootDocShell()->mForcedColorsOverride;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetForcedColorsOverride(ForcedColorsOverride aForcedColorsOverride) {
+  mForcedColorsOverride = aForcedColorsOverride;
+  RefPtr<nsPresContext> presContext = GetPresContext();
+  if (presContext) {
+    presContext->MediaFeatureValuesChanged(
+        {MediaFeatureChangeReason::SystemMetricsChange},
+        MediaFeatureChangePropagation::JustThisDocument);
+  }
+  return NS_OK;
+}
+
+// =============== Juggler End =======================
+
 NS_IMETHODIMP
 nsDocShell::GetIsNavigating(bool* aOut) {
   *aOut = mIsNavigating;
@@ -4922,7 +5154,7 @@ nsDocShell::GetVisibility(bool* aVisibility) {
 }
 
 void nsDocShell::ActivenessMaybeChanged() {
-  const bool isActive = mBrowsingContext->IsActive();
+  const bool isActive = mForceActiveState || mBrowsingContext->IsActive();
   if (RefPtr<PresShell> presShell = GetPresShell()) {
     presShell->ActivenessMaybeChanged();
   }
@@ -8656,6 +8888,12 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState) {
                      true,  // aForceNoOpener
                      getter_AddRefs(newBC));
       MOZ_ASSERT(!newBC);
+      if (rv == NS_OK) {
+        nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
+        if (observerService) {
+          observerService->NotifyObservers(GetAsSupports(this), "juggler-window-open-in-new-context", nullptr);
+        }
+      }
       return rv;
     }
 
@@ -12797,6 +13035,9 @@ class OnLinkClickEvent : public Runnable {
       mHandler->OnLinkClickSync(mContent, mLoadState, mNoOpenerImplied,
                                 mTriggeringPrincipal);
     }
+    nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
+    observerService->NotifyObservers(ToSupports(mContent), "juggler-link-click-sync", nullptr);
+
     return NS_OK;
   }
 
@@ -12876,6 +13117,8 @@ nsresult nsDocShell::OnLinkClick(
   nsCOMPtr<nsIRunnable> ev =
       new OnLinkClickEvent(this, aContent, loadState, noOpenerImplied,
                            aIsTrusted, aTriggeringPrincipal);
+  nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
+  observerService->NotifyObservers(ToSupports(aContent), "juggler-link-click", nullptr);
   return Dispatch(TaskCategory::UI, ev.forget());
 }
 
diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h
index 7326eb6d5c927c0509333447edf111657597ab90..bc9dcabb82832fd1a3a8f2dd8811481a9c5ad84c 100644
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -16,6 +16,7 @@
 #include "mozilla/UniquePtr.h"
 #include "mozilla/WeakPtr.h"
 #include "mozilla/dom/BrowsingContext.h"
+#include "mozilla/dom/Element.h"
 #include "mozilla/dom/WindowProxyHolder.h"
 #include "nsCOMPtr.h"
 #include "nsCharsetSource.h"
@@ -76,6 +77,7 @@ class nsCommandManager;
 class nsDocShellEditorData;
 class nsDOMNavigationTiming;
 class nsDSURIContentListener;
+class nsGeolocationService;
 class nsGlobalWindowOuter;
 
 class FramingChecker;
@@ -411,6 +413,15 @@ class nsDocShell final : public nsDocLoader,
   void SetWillChangeProcess() { mWillChangeProcess = true; }
   bool WillChangeProcess() { return mWillChangeProcess; }
 
+  bool IsFileInputInterceptionEnabled();
+  void FilePickerShown(mozilla::dom::Element* element);
+
+  bool ShouldOverrideHasFocus() const;
+
+  bool IsBypassCSPEnabled();
+
+  RefPtr<nsGeolocationService> GetGeolocationServiceOverride();
+
   // Create a content viewer within this nsDocShell for the given
   // `WindowGlobalChild` actor.
   nsresult CreateContentViewerForActor(
@@ -1026,6 +1037,8 @@ class nsDocShell final : public nsDocLoader,
 
   bool CSSErrorReportingEnabled() const { return mCSSErrorReportingEnabled; }
 
+  nsDocShell* GetRootDocShell();
+
   // Handles retrieval of subframe session history for nsDocShell::LoadURI. If a
   // load is requested in a subframe of the current DocShell, the subframe
   // loadType may need to reflect the loadType of the parent document, or in
@@ -1311,6 +1324,16 @@ class nsDocShell final : public nsDocLoader,
   bool mAllowDNSPrefetch : 1;
   bool mAllowWindowControl : 1;
   bool mCSSErrorReportingEnabled : 1;
+  bool mFileInputInterceptionEnabled: 1;
+  bool mOverrideHasFocus : 1;
+  bool mBypassCSPEnabled : 1;
+  bool mForceActiveState : 1;
+  nsString mLanguageOverride;
+  RefPtr<nsGeolocationService> mGeolocationServiceOverride;
+  OnlineOverride mOnlineOverride;
+  ReducedMotionOverride mReducedMotionOverride;
+  ForcedColorsOverride mForcedColorsOverride;
+
   bool mAllowAuth : 1;
   bool mAllowKeywordFixup : 1;
   bool mDisableMetaRefreshWhenInactive : 1;
diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl
index 6b85ddd842a6d2e29f86047017b78b2007b99867..e0b56c4f85544580b9a631619fb06799ad244494 100644
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -44,6 +44,7 @@ interface nsIURI;
 interface nsIChannel;
 interface nsIContentViewer;
 interface nsIContentSecurityPolicy;
+interface nsIDOMGeoPosition;
 interface nsIEditor;
 interface nsIEditingSession;
 interface nsIInputStream;
@@ -803,6 +804,41 @@ interface nsIDocShell : nsIDocShellTreeItem
    */
   void synchronizeLayoutHistoryState();
 
+  attribute boolean fileInputInterceptionEnabled;
+
+  attribute boolean overrideHasFocus;
+
+  attribute boolean bypassCSPEnabled;
+
+  attribute boolean forceActiveState;
+
+  attribute AString languageOverride;
+
+  boolean overrideTimezone(in AString timezoneId);
+
+  cenum OnlineOverride: 8 {
+    ONLINE_OVERRIDE_NONE = 0,
+    ONLINE_OVERRIDE_ONLINE = 1,
+    ONLINE_OVERRIDE_OFFLINE = 2,
+  };
+  [infallible] attribute nsIDocShell_OnlineOverride onlineOverride;
+
+  cenum ReducedMotionOverride : 8 {
+    REDUCED_MOTION_OVERRIDE_REDUCE,
+    REDUCED_MOTION_OVERRIDE_NO_PREFERENCE,
+    REDUCED_MOTION_OVERRIDE_NONE, /* This clears the override. */
+  };
+  [infallible] attribute nsIDocShell_ReducedMotionOverride reducedMotionOverride;
+
+  cenum ForcedColorsOverride : 8 {
+    FORCED_COLORS_OVERRIDE_ACTIVE,
+    FORCED_COLORS_OVERRIDE_NONE,
+    FORCED_COLORS_OVERRIDE_NO_OVERRIDE, /* This clears the override. */
+  };
+  [infallible] attribute nsIDocShell_ForcedColorsOverride forcedColorsOverride;
+
+  void setGeolocationOverride(in nsIDOMGeoPosition position);
+
   /**
    * This attempts to save any applicable layout history state (like
    * scroll position) in the nsISHEntry. This is normally done
diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp
index 5b7e6f79eec7d48e55ce8bc425056cfc7b672083..4a49765962d0eb9c555ec4522acbf04c61ef72f7 100644
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -3642,6 +3642,9 @@ void Document::SendToConsole(nsCOMArray<nsISecurityConsoleMessage>& aMessages) {
 }
 
 void Document::ApplySettingsFromCSP(bool aSpeculative) {
+  if (mDocumentContainer && mDocumentContainer->IsBypassCSPEnabled())
+    return;
+
   nsresult rv = NS_OK;
   if (!aSpeculative) {
     // 1) apply settings from regular CSP
@@ -3699,6 +3702,11 @@ nsresult Document::InitCSP(nsIChannel* aChannel) {
   MOZ_ASSERT(!mScriptGlobalObject,
              "CSP must be initialized before mScriptGlobalObject is set!");
 
+  nsCOMPtr<nsIDocShell> shell(mDocumentContainer);
+  if (shell && nsDocShell::Cast(shell)->IsBypassCSPEnabled()) {
+    return NS_OK;
+  }
+
   // If this is a data document - no need to set CSP.
   if (mLoadedAsData) {
     return NS_OK;
@@ -4510,6 +4518,10 @@ bool Document::HasFocus(ErrorResult& rv) const {
     return false;
   }
 
+  if (IsActive() && mDocumentContainer->ShouldOverrideHasFocus()) {
+    return true;
+  }
+
   if (!fm->IsInActiveWindow(bc)) {
     return false;
   }
@@ -17823,6 +17835,71 @@ ColorScheme Document::PreferredColorScheme(IgnoreRFP aIgnoreRFP) const {
   return LookAndFeel::PreferredColorSchemeForContent();
 }
 
+bool Document::PrefersReducedMotion() const {
+  auto* docShell = static_cast<nsDocShell*>(GetDocShell());
+  nsIDocShell::ReducedMotionOverride reducedMotion;
+  if (docShell && docShell->GetReducedMotionOverride(&reducedMotion) == NS_OK &&
+      reducedMotion != nsIDocShell::REDUCED_MOTION_OVERRIDE_NONE) {
+    switch (reducedMotion) {
+      case nsIDocShell::REDUCED_MOTION_OVERRIDE_REDUCE:
+        return true;
+      case nsIDocShell::REDUCED_MOTION_OVERRIDE_NO_PREFERENCE:
+        return false;
+      case nsIDocShell::REDUCED_MOTION_OVERRIDE_NONE:
+        break;
+    };
+  }
+
+  if (auto* bc = GetBrowsingContext()) {
+    switch (bc->Top()->PrefersReducedMotionOverride()) {
+      case dom::PrefersReducedMotionOverride::Reduce:
+        return true;
+      case dom::PrefersReducedMotionOverride::No_preference:
+        return false;
+      case dom::PrefersReducedMotionOverride::None:
+      case dom::PrefersReducedMotionOverride::EndGuard_:
+        break;
+    }
+  }
+
+  if (nsContentUtils::ShouldResistFingerprinting(this)) {
+    return false;
+  }
+  return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1;
+}
+
+bool Document::ForcedColors() const {
+  auto* docShell = static_cast<nsDocShell*>(GetDocShell());
+  nsIDocShell::ForcedColorsOverride forcedColors;
+  if (docShell && docShell->GetForcedColorsOverride(&forcedColors) == NS_OK) {
+    switch (forcedColors) {
+      case nsIDocShell::FORCED_COLORS_OVERRIDE_ACTIVE:
+        return true;
+      case nsIDocShell::FORCED_COLORS_OVERRIDE_NONE:
+        return false;
+      case nsIDocShell::FORCED_COLORS_OVERRIDE_NO_OVERRIDE:
+        break;
+    };
+  }
+
+  if (auto* bc = GetBrowsingContext()) {
+    switch (bc->Top()->ForcedColorsOverride()) {
+      case dom::ForcedColorsOverride::Active:
+        return true;
+      case dom::ForcedColorsOverride::None:
+        return false;
+      case dom::ForcedColorsOverride::No_override:
+      case dom::ForcedColorsOverride::EndGuard_:
+        break;
+    }
+  }
+
+  if (mIsBeingUsedAsImage) {
+    return false;
+  }
+  return !PreferenceSheet::PrefsFor(*this).mUseDocumentColors;
+}
+
 bool Document::HasRecentlyStartedForegroundLoads() {
   if (!sLoadingForegroundTopLevelContentDocument) {
     return false;
diff --git a/dom/base/Document.h b/dom/base/Document.h
index d04aee703c53e0c753d8dd55336687d85ad6f716..b698ba08ea795e17993054c49ad187b015d9d411 100644
--- a/dom/base/Document.h
+++ b/dom/base/Document.h
@@ -4021,6 +4021,9 @@ class Document : public nsINode,
   // color-scheme meta tag.
   ColorScheme DefaultColorScheme() const;
 
+  bool PrefersReducedMotion() const;
+  bool ForcedColors() const;
+
   static bool HasRecentlyStartedForegroundLoads();
 
   static bool AutomaticStorageAccessPermissionCanBeGranted(
diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp
index b7da9e6a03bd5f68bb967d21af061fafc61f3105..099bad54715e6901ef4ceff69f1a988109ce1c19 100644
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -326,14 +326,18 @@ void Navigator::GetAppName(nsAString& aAppName, CallerType aCallerType) const {
  * for more detail.
  */
 /* static */
-void Navigator::GetAcceptLanguages(nsTArray<nsString>& aLanguages) {
+void Navigator::GetAcceptLanguages(const nsString* aLanguageOverride, nsTArray<nsString>& aLanguages) {
   MOZ_ASSERT(NS_IsMainThread());
 
   aLanguages.Clear();
 
   // E.g. "de-de, en-us,en".
   nsAutoString acceptLang;
-  Preferences::GetLocalizedString("intl.accept_languages", acceptLang);
+  if (aLanguageOverride && aLanguageOverride->Length())
+    acceptLang = *aLanguageOverride;
+  else
+    Preferences::GetLocalizedString("intl.accept_languages", acceptLang);
+    
 
   // Split values on commas.
   for (nsDependentSubstring lang :
@@ -385,7 +389,13 @@ void Navigator::GetLanguage(nsAString& aLanguage) {
 }
 
 void Navigator::GetLanguages(nsTArray<nsString>& aLanguages) {
-  GetAcceptLanguages(aLanguages);
+  if (mWindow && mWindow->GetDocShell()) {
+    nsString languageOverride;
+    mWindow->GetDocShell()->GetLanguageOverride(languageOverride);
+    GetAcceptLanguages(&languageOverride, aLanguages);
+  } else {
+    GetAcceptLanguages(nullptr, aLanguages);
+  }
 
   // The returned value is cached by the binding code. The window listens to the
   // accept languages change and will clear the cache when needed. It has to
@@ -564,7 +574,13 @@ bool Navigator::CookieEnabled() {
   return granted;
 }
 
-bool Navigator::OnLine() { return !NS_IsOffline(); }
+bool Navigator::OnLine() {
+  nsDocShell* docShell = static_cast<nsDocShell*>(GetDocShell());
+  nsIDocShell::OnlineOverride onlineOverride;
+  if (!docShell || docShell->GetOnlineOverride(&onlineOverride) != NS_OK || onlineOverride == nsIDocShell::ONLINE_OVERRIDE_NONE)
+    return !NS_IsOffline();
+  return onlineOverride == nsIDocShell::ONLINE_OVERRIDE_ONLINE;
+}
 
 void Navigator::GetBuildID(nsAString& aBuildID, CallerType aCallerType,
                            ErrorResult& aRv) const {
diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h
index 2a16e5e18427944f007c3f33301f2faea92f63e0..69a2037379bc03f941789814d00c7e99e58bdf0e 100644
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -216,7 +216,7 @@ class Navigator final : public nsISupports, public nsWrapperCache {
 
   StorageManager* Storage();
 
-  static void GetAcceptLanguages(nsTArray<nsString>& aLanguages);
+  static void GetAcceptLanguages(const nsString* aLanguageOverride, nsTArray<nsString>& aLanguages);
 
   dom::MediaCapabilities* MediaCapabilities();
   dom::MediaSession* MediaSession();
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
index 0562245205a33493d4f664426ad1d84c64cb3d87..409f9f974370b8afd06916128b7bdf0633e76b17 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -8382,7 +8382,8 @@ nsresult nsContentUtils::SendMouseEvent(
     bool aIgnoreRootScrollFrame, float aPressure,
     unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow,
     PreventDefaultResult* aPreventDefault, bool aIsDOMEventSynthesized,
-    bool aIsWidgetEventSynthesized) {
+    bool aIsWidgetEventSynthesized,
+    bool convertToPointer) {
   nsPoint offset;
   nsCOMPtr<nsIWidget> widget = GetWidget(aPresShell, &offset);
   if (!widget) return NS_ERROR_FAILURE;
@@ -8441,6 +8442,7 @@ nsresult nsContentUtils::SendMouseEvent(
   event.mTime = PR_IntervalNow();
   event.mFlags.mIsSynthesizedForTests = aIsDOMEventSynthesized;
   event.mExitFrom = exitFrom;
+  event.convertToPointer = convertToPointer;
 
   nsPresContext* presContext = aPresShell->GetPresContext();
   if (!presContext) return NS_ERROR_FAILURE;
diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h
index 739e8ca23c858ac2bf0356ad8c0eb0da4471d9ea..afb76693d313dc3c97fb54d014ed146a5b1bfb01 100644
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2943,7 +2943,8 @@ class nsContentUtils {
       int32_t aModifiers, bool aIgnoreRootScrollFrame, float aPressure,
       unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow,
       mozilla::PreventDefaultResult* aPreventDefault,
-      bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized);
+      bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized,
+      bool convertToPointer = true);
 
   static void FirePageShowEventForFrameLoaderSwap(
       nsIDocShellTreeItem* aItem,
diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp
index a179752e119d0b6fe3441494eccf29042f327c6e..380415301d981687be3b3fbee898afbabd67bed8 100644
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -655,7 +655,7 @@ nsDOMWindowUtils::SendMouseEvent(
     int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame,
     float aPressure, unsigned short aInputSourceArg,
     bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized,
-    int32_t aButtons, uint32_t aIdentifier, uint8_t aOptionalArgCount,
+    int32_t aButtons, uint32_t aIdentifier, bool aDisablePointerEvent, uint8_t aOptionalArgCount,
     bool* aPreventDefault) {
   return SendMouseEventCommon(
       aType, aX, aY, aButton, aClickCount, aModifiers, aIgnoreRootScrollFrame,
@@ -663,7 +663,7 @@ nsDOMWindowUtils::SendMouseEvent(
       aOptionalArgCount >= 7 ? aIdentifier : DEFAULT_MOUSE_POINTER_ID, false,
       aPreventDefault, aOptionalArgCount >= 4 ? aIsDOMEventSynthesized : true,
       aOptionalArgCount >= 5 ? aIsWidgetEventSynthesized : false,
-      aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED);
+      aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED, !aDisablePointerEvent);
 }
 
 NS_IMETHODIMP
@@ -690,13 +690,13 @@ nsDOMWindowUtils::SendMouseEventCommon(
     int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame,
     float aPressure, unsigned short aInputSourceArg, uint32_t aPointerId,
     bool aToWindow, bool* aPreventDefault, bool aIsDOMEventSynthesized,
-    bool aIsWidgetEventSynthesized, int32_t aButtons) {
+    bool aIsWidgetEventSynthesized, int32_t aButtons, bool aConvertToPointer) {
   RefPtr<PresShell> presShell = GetPresShell();
   PreventDefaultResult preventDefaultResult;
   nsresult rv = nsContentUtils::SendMouseEvent(
       presShell, aType, aX, aY, aButton, aButtons, aClickCount, aModifiers,
       aIgnoreRootScrollFrame, aPressure, aInputSourceArg, aPointerId, aToWindow,
-      &preventDefaultResult, aIsDOMEventSynthesized, aIsWidgetEventSynthesized);
+      &preventDefaultResult, aIsDOMEventSynthesized, aIsWidgetEventSynthesized, aConvertToPointer);
 
   if (aPreventDefault) {
     *aPreventDefault = preventDefaultResult != PreventDefaultResult::No;
diff --git a/dom/base/nsDOMWindowUtils.h b/dom/base/nsDOMWindowUtils.h
index 30e0fafa77857c33e9871259a6ac0cebac965df8..3d8810abcfac1c220529b4e6163b0159475723ff 100644
--- a/dom/base/nsDOMWindowUtils.h
+++ b/dom/base/nsDOMWindowUtils.h
@@ -93,7 +93,7 @@ class nsDOMWindowUtils final : public nsIDOMWindowUtils,
       int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame,
       float aPressure, unsigned short aInputSourceArg, uint32_t aIdentifier,
       bool aToWindow, bool* aPreventDefault, bool aIsDOMEventSynthesized,
-      bool aIsWidgetEventSynthesized, int32_t aButtons);
+      bool aIsWidgetEventSynthesized, int32_t aButtons, bool aConvertToPointer = true);
 
   MOZ_CAN_RUN_SCRIPT
   nsresult SendTouchEventCommon(
diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp
index 018c2aaaeef9e1f30069b425306f230d096c0c91..3a3ee33ef46a7f3295be4766e83cd8d2d2ccc81b 100644
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -1614,6 +1614,10 @@ void nsFocusManager::SetFocusInner(Element* aNewContent, int32_t aFlags,
         (GetActiveBrowsingContext() == newRootBrowsingContext);
   }
 
+  // In Playwright, we want to send focus events even if the element
+  // isn't actually in the active window.
+  isElementInActiveWindow = true;
+
   // Exit fullscreen if a website focuses another window
   if (StaticPrefs::full_screen_api_exit_on_windowRaise() &&
       !isElementInActiveWindow && (aFlags & FLAG_RAISE) &&
@@ -2933,7 +2937,9 @@ void nsFocusManager::RaiseWindow(nsPIDOMWindowOuter* aWindow,
     }
   }
 
-  if (sTestMode) {
+  // In Playwright, we still want to execte the embedder functions
+  // to actually show / focus windows.
+  if (false && sTestMode) {
     // In test mode, emulate raising the window. WindowRaised takes
     // care of lowering the present active window. This happens in
     // a separate runnable to avoid touching multiple windows in
diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp
index d98276d975b731f3138ebb51076c8606b9fbf6c3..2b201af2923bd87bb093ef5001f429de357f9160 100644
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -2480,7 +2480,7 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument,
         &nsGlobalWindowInner::FireOnNewGlobalObject));
   }
 
-  if (newInnerWindow && !newInnerWindow->mHasNotifiedGlobalCreated && mDoc) {
+  if (newInnerWindow && mDoc) {
     // We should probably notify. However if this is the, arguably bad,
     // situation when we're creating a temporary non-chrome-about-blank
     // document in a chrome docshell, don't notify just yet. Instead wait
@@ -2499,10 +2499,16 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument,
     }();
 
     if (!isContentAboutBlankInChromeDocshell) {
-      newInnerWindow->mHasNotifiedGlobalCreated = true;
-      nsContentUtils::AddScriptRunner(NewRunnableMethod(
-          "nsGlobalWindowOuter::DispatchDOMWindowCreated", this,
-          &nsGlobalWindowOuter::DispatchDOMWindowCreated));
+      if (!newInnerWindow->mHasNotifiedGlobalCreated) {
+        newInnerWindow->mHasNotifiedGlobalCreated = true;
+        nsContentUtils::AddScriptRunner(NewRunnableMethod(
+            "nsGlobalWindowOuter::DispatchDOMWindowCreated", this,
+            &nsGlobalWindowOuter::DispatchDOMWindowCreated));
+      } else if (!reUseInnerWindow) {
+        nsContentUtils::AddScriptRunner(NewRunnableMethod(
+            "nsGlobalWindowOuter::JugglerDispatchDOMWindowReused", this,
+            &nsGlobalWindowOuter::JugglerDispatchDOMWindowReused));
+      }
     }
   }
 
@@ -2626,6 +2632,19 @@ void nsGlobalWindowOuter::DispatchDOMWindowCreated() {
   }
 }
 
+void nsGlobalWindowOuter::JugglerDispatchDOMWindowReused() {
+  nsCOMPtr<nsIObserverService> observerService =
+      mozilla::services::GetObserverService();
+  if (observerService && mDoc) {
+    nsIPrincipal* principal = mDoc->NodePrincipal();
+    if (!principal->IsSystemPrincipal()) {
+      observerService->NotifyObservers(static_cast<nsIDOMWindow*>(this),
+                                      "juggler-dom-window-reused",
+                                      nullptr);
+    }
+  }
+}
+
 void nsGlobalWindowOuter::ClearStatus() { SetStatusOuter(u""_ns); }
 
 void nsGlobalWindowOuter::SetDocShell(nsDocShell* aDocShell) {
@@ -3794,6 +3813,14 @@ Maybe<CSSIntSize> nsGlobalWindowOuter::GetRDMDeviceSize(
       }
     }
   }
+  if (topInProcessContentDoc) {
+    nsIDocShell* docShell = topInProcessContentDoc->GetDocShell();
+    if (docShell && docShell->GetDeviceSizeIsPageSize()) {
+      nsPresContext* presContext = docShell->GetPresContext();
+      if (presContext)
+        return Some(CSSPixel::FromAppUnitsRounded(presContext->GetVisibleArea().Size()));
+    }
+  }
   return Nothing();
 }
 
diff --git a/dom/base/nsGlobalWindowOuter.h b/dom/base/nsGlobalWindowOuter.h
index 1a6a72b9261fa7ac7100db2b15b0a4dc9286e94b..7de1bdc42b2b7cf25b679056039152cf965df3c1 100644
--- a/dom/base/nsGlobalWindowOuter.h
+++ b/dom/base/nsGlobalWindowOuter.h
@@ -330,6 +330,7 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget,
 
   // Outer windows only.
   void DispatchDOMWindowCreated();
+  void JugglerDispatchDOMWindowReused();
 
   // Outer windows only.
   virtual void EnsureSizeAndPositionUpToDate() override;
diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp
index 88e24213ce8f052d1bbe00c4fcb385aa70496552..23a463c943e630ad93cc780fb4b7b894ce76f7b9 100644
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -1324,6 +1324,49 @@ void nsINode::GetBoxQuadsFromWindowOrigin(const BoxQuadOptions& aOptions,
   mozilla::GetBoxQuadsFromWindowOrigin(this, aOptions, aResult, aRv);
 }
 
+void nsINode::ScrollRectIntoViewIfNeeded(int32_t x, int32_t y,
+                                         int32_t w, int32_t h,
+                                         ErrorResult& aRv) {
+  aRv = NS_ERROR_UNEXPECTED;
+  nsCOMPtr<Document> document = OwnerDoc();
+  if (!document) {
+    return aRv.ThrowNotFoundError("Node is detached from document");
+  }
+  PresShell* presShell = document->GetPresShell();
+  if (!presShell) {
+    return aRv.ThrowNotFoundError("Node is detached from document");
+  }
+  if (!IsContent()) {
+    return aRv.ThrowNotFoundError("Node does not have a layout object");
+  }
+  aRv = NS_OK;
+  nsIFrame* primaryFrame = AsContent()->GetPrimaryFrame(FlushType::Frames);
+  if (!primaryFrame) {
+    return aRv.ThrowNotFoundError("Node does not have a layout object");
+  }
+  nsRect rect;
+  if (x == -1 && y == -1 && w == -1 && h == -1) {
+    rect = primaryFrame->GetRectRelativeToSelf();
+  } else {
+    rect = nsRect(nsPresContext::CSSPixelsToAppUnits(x),
+                  nsPresContext::CSSPixelsToAppUnits(y),
+                  nsPresContext::CSSPixelsToAppUnits(w),
+                  nsPresContext::CSSPixelsToAppUnits(h));
+  }
+  presShell->ScrollFrameRectIntoView(
+      primaryFrame, rect,
+      nsMargin(),
+      ScrollAxis(kScrollToCenter, WhenToScroll::Always),
+      ScrollAxis(kScrollToCenter, WhenToScroll::Always),
+      ScrollFlags::ScrollOverflowHidden);
+  // If a _visual_ scroll update is pending, cancel it; otherwise, it will
+  // clobber next scroll (e.g. subsequent window.scrollTo(0, 0) wlll break).
+  if (presShell->GetPendingVisualScrollUpdate()) {
+    presShell->AcknowledgePendingVisualScrollUpdate();
+    presShell->ClearPendingVisualScrollUpdate();
+  }
+}
+
 already_AddRefed<DOMQuad> nsINode::ConvertQuadFromNode(
     DOMQuad& aQuad, const GeometryNode& aFrom,
     const ConvertCoordinateOptions& aOptions, CallerType aCallerType,
diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h
index 56adeeb339ec7dcf63785b46c194c38614e2b000..0421f57f310c397438090cbd3f4b4290cc21151b 100644
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -2131,6 +2131,10 @@ class nsINode : public mozilla::dom::EventTarget {
                                    nsTArray<RefPtr<DOMQuad>>& aResult,
                                    ErrorResult& aRv);
 
+  void ScrollRectIntoViewIfNeeded(int32_t x, int32_t y,
+                                  int32_t w, int32_t h,
+                                  ErrorResult& aRv);
+
   already_AddRefed<DOMQuad> ConvertQuadFromNode(
       DOMQuad& aQuad, const TextOrElementOrDocument& aFrom,
       const ConvertCoordinateOptions& aOptions, CallerType aCallerType,
diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp
index 399bae250043708540d99c188ae3dfc4587cb5ea..43c315aa22b97b30ebbc72d13296fd89076b231c 100644
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -169,6 +169,11 @@ bool nsJSUtils::GetScopeChainForElement(
   return true;
 }
 
+/* static */
+bool nsJSUtils::SetTimeZoneOverride(const char* timezoneId) {
+  return JS::SetTimeZoneOverride(timezoneId);
+}
+
 /* static */
 void nsJSUtils::ResetTimeZone() { JS::ResetTimeZone(); }
 
diff --git a/dom/base/nsJSUtils.h b/dom/base/nsJSUtils.h
index 85a21e459305f556933f4dc0fa7441d8f9ed95a9..d7cb86479ba2ed06542307349d6d86dfd026d55d 100644
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -78,6 +78,7 @@ class nsJSUtils {
       JSContext* aCx, mozilla::dom::Element* aElement,
       JS::MutableHandleVector<JSObject*> aScopeChain);
 
+  static bool SetTimeZoneOverride(const char* timezoneId);
   static void ResetTimeZone();
 
   static bool DumpEnabled();
diff --git a/dom/chrome-webidl/BrowsingContext.webidl b/dom/chrome-webidl/BrowsingContext.webidl
index de1c9ba3e0b9e633b6ab9c381e1ce63ce73153ba..3db73ee5164abd1c1bd985b2a60cbf2cb2ec08d2 100644
--- a/dom/chrome-webidl/BrowsingContext.webidl
+++ b/dom/chrome-webidl/BrowsingContext.webidl
@@ -52,6 +52,24 @@ enum PrefersColorSchemeOverride {
   "dark",
 };
 
+/**
+ * CSS prefers-reduced-motion values.
+ */
+enum PrefersReducedMotionOverride {
+  "none",
+  "reduce",
+  "no-preference",
+};
+
+/**
+ * CSS forced-colors values.
+ */
+enum ForcedColorsOverride {
+  "none",
+  "active",
+  "no-override",  /* This clears the override. */
+};
+
 /**
  * Allowed overrides of platform/pref default behaviour for touch events.
  */
@@ -186,6 +204,12 @@ interface BrowsingContext {
   // Color-scheme simulation, for DevTools.
   [SetterThrows] attribute PrefersColorSchemeOverride prefersColorSchemeOverride;
 
+  // Reduced-Motion simulation, for DevTools.
+  [SetterThrows] attribute PrefersReducedMotionOverride prefersReducedMotionOverride;
+
+  // Forced-Colors simulation, for DevTools.
+  [SetterThrows] attribute ForcedColorsOverride forcedColorsOverride;
+
   /**
    * A unique identifier for the browser element that is hosting this
    * BrowsingContext tree. Every BrowsingContext in the element's tree will
diff --git a/dom/geolocation/Geolocation.cpp b/dom/geolocation/Geolocation.cpp
index 4eae991a630b13425db08c834085b02a9c659cad..fd71b72274fa659da0cf4ca5de494869fca862b9 100644
--- a/dom/geolocation/Geolocation.cpp
+++ b/dom/geolocation/Geolocation.cpp
@@ -23,6 +23,7 @@
 #include "nsComponentManagerUtils.h"
 #include "nsContentPermissionHelper.h"
 #include "nsContentUtils.h"
+#include "nsDocShell.h"
 #include "nsGlobalWindow.h"
 #include "mozilla/dom/Document.h"
 #include "nsINamed.h"
@@ -260,10 +261,8 @@ nsGeolocationRequest::Allow(JS::HandleValue aChoices) {
     return NS_OK;
   }
 
-  RefPtr<nsGeolocationService> gs =
-      nsGeolocationService::GetGeolocationService();
-
-  bool canUseCache = false;
+  nsGeolocationService* gs = mLocator->GetGeolocationService();
+  bool canUseCache = gs != nsGeolocationService::sService.get();
   CachedPositionAndAccuracy lastPosition = gs->GetCachedPosition();
   if (lastPosition.position) {
     EpochTimeStamp cachedPositionTime_ms;
@@ -436,8 +435,7 @@ void nsGeolocationRequest::Shutdown() {
   // If there are no other high accuracy requests, the geolocation service will
   // notify the provider to switch to the default accuracy.
   if (mOptions && mOptions->mEnableHighAccuracy) {
-    RefPtr<nsGeolocationService> gs =
-        nsGeolocationService::GetGeolocationService();
+    nsGeolocationService* gs = mLocator ? mLocator->GetGeolocationService() : nullptr;
     if (gs) {
       gs->UpdateAccuracy();
     }
@@ -727,8 +725,14 @@ void nsGeolocationService::StopDevice() {
 StaticRefPtr<nsGeolocationService> nsGeolocationService::sService;
 
 already_AddRefed<nsGeolocationService>
-nsGeolocationService::GetGeolocationService() {
+nsGeolocationService::GetGeolocationService(nsDocShell* docShell) {
   RefPtr<nsGeolocationService> result;
+  if (docShell) {
+    result = docShell->GetGeolocationServiceOverride();
+    if (result)
+      return result.forget();
+  }
+
   if (nsGeolocationService::sService) {
     result = nsGeolocationService::sService;
 
@@ -820,7 +824,9 @@ nsresult Geolocation::Init(nsPIDOMWindowInner* aContentDom) {
   // If no aContentDom was passed into us, we are being used
   // by chrome/c++ and have no mOwner, no mPrincipal, and no need
   // to prompt.
-  mService = nsGeolocationService::GetGeolocationService();
+  nsCOMPtr<Document> doc = aContentDom ? aContentDom->GetDoc() : nullptr;
+  mService = nsGeolocationService::GetGeolocationService(
+      doc ? static_cast<nsDocShell*>(doc->GetDocShell()) : nullptr);
   if (mService) {
     mService->AddLocator(this);
   }
diff --git a/dom/geolocation/Geolocation.h b/dom/geolocation/Geolocation.h
index 5c0d2f96a22c6928d6aee5a226032c0944ae7a54..5a7bb1f6cea1946eea143dca4e2f1e19746a04a4 100644
--- a/dom/geolocation/Geolocation.h
+++ b/dom/geolocation/Geolocation.h
@@ -31,6 +31,7 @@
 
 #include "nsIGeolocationProvider.h"
 #include "mozilla/Attributes.h"
+#include "nsDocShell.h"
 
 class nsGeolocationService;
 class nsGeolocationRequest;
@@ -48,13 +49,14 @@ struct CachedPositionAndAccuracy {
   bool isHighAccuracy;
 };
 
+
 /**
  * Singleton that manages the geolocation provider
  */
 class nsGeolocationService final : public nsIGeolocationUpdate,
                                    public nsIObserver {
  public:
-  static already_AddRefed<nsGeolocationService> GetGeolocationService();
+  static already_AddRefed<nsGeolocationService> GetGeolocationService(nsDocShell* docShell = nullptr);
   static mozilla::StaticRefPtr<nsGeolocationService> sService;
 
   NS_DECL_THREADSAFE_ISUPPORTS
@@ -179,6 +181,8 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache {
   // null.
   static already_AddRefed<Geolocation> NonWindowSingleton();
 
+  nsGeolocationService* GetGeolocationService() { return mService; };
+
  private:
   ~Geolocation();
 
diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp
index 9fb48fd6d15322bbf324fc63c3c6dec05a2bfb9f..c09d509603cbf4740ba867e4abdd946685d6c626 100644
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -53,6 +53,7 @@
 #include "nsMappedAttributes.h"
 #include "nsIFormControl.h"
 #include "mozilla/dom/Document.h"
+#include "nsDocShell.h"
 #include "nsIFormControlFrame.h"
 #include "nsITextControlFrame.h"
 #include "nsIFrame.h"
@@ -743,6 +744,12 @@ nsresult HTMLInputElement::InitFilePicker(FilePickerType aType) {
     return NS_ERROR_FAILURE;
   }
 
+  nsDocShell* docShell = static_cast<nsDocShell*>(win->GetDocShell());
+  if (docShell && docShell->IsFileInputInterceptionEnabled()) {
+    docShell->FilePickerShown(this);
+    return NS_OK;
+  }
+
   if (IsPopupBlocked(doc)) {
     return NS_OK;
   }
diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl
index 420dc4af627af257e34f205b470eabcdd749fb40..f9ba5debde310316b69d59033ea692ecc5524be9 100644
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -364,7 +364,8 @@ interface nsIDOMWindowUtils : nsISupports {
                          [optional] in boolean aIsDOMEventSynthesized,
                          [optional] in boolean aIsWidgetEventSynthesized,
                          [optional] in long aButtons,
-                         [optional] in unsigned long aIdentifier);
+                         [optional] in unsigned long aIdentifier,
+                         [optional] in boolean aDisablePointerEvent);
 
   /** Synthesize a touch event. The event types supported are:
    *    touchstart, touchend, touchmove, and touchcancel
diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.cc b/dom/media/systemservices/video_engine/desktop_capture_impl.cc
index 9d4e8fbbfe8d45cc6245c7659423004ad1ceedeb..70150e9271720a562fd646a50d30369965d8521a 100644
--- a/dom/media/systemservices/video_engine/desktop_capture_impl.cc
+++ b/dom/media/systemservices/video_engine/desktop_capture_impl.cc
@@ -123,10 +123,11 @@ int32_t ScreenDeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8,
   return 0;
 }
 
-VideoCaptureModule* DesktopCaptureImpl::Create(const int32_t id,
+VideoCaptureModuleEx* DesktopCaptureImpl::Create(const int32_t id,
                                                const char* uniqueId,
-                                               const CaptureDeviceType type) {
-  return new rtc::RefCountedObject<DesktopCaptureImpl>(id, uniqueId, type);
+                                               const CaptureDeviceType type,
+                                               bool captureCursor) {
+  return new rtc::RefCountedObject<DesktopCaptureImpl>(id, uniqueId, type, captureCursor);
 }
 
 int32_t WindowDeviceInfoImpl::Init() {
@@ -358,9 +359,13 @@ int32_t DesktopCaptureImpl::Init() {
     DesktopCapturer::SourceId sourceId = atoi(_deviceUniqueId.c_str());
     pWindowCapturer->SelectSource(sourceId);
 
-    desktop_capturer_cursor_composer_ =
-        std::unique_ptr<DesktopAndCursorComposer>(
-            new DesktopAndCursorComposer(std::move(pWindowCapturer), options));
+    if (capture_cursor_) {
+      desktop_capturer_cursor_composer_ =
+          std::unique_ptr<DesktopAndCursorComposer>(
+              new DesktopAndCursorComposer(std::move(pWindowCapturer), options));
+    } else {
+      desktop_capturer_cursor_composer_ = std::move(pWindowCapturer);
+    }
   } else if (_deviceType == CaptureDeviceType::Browser) {
     // XXX We don't capture cursors, so avoid the extra indirection layer. We
     // could also pass null for the pMouseCursorMonitor.
@@ -377,13 +382,15 @@ int32_t DesktopCaptureImpl::Init() {
 }
 
 DesktopCaptureImpl::DesktopCaptureImpl(const int32_t id, const char* uniqueId,
-                                       const CaptureDeviceType type)
+                                       const CaptureDeviceType type,
+                                       bool captureCursor)
     : _id(id),
       _deviceUniqueId(uniqueId),
       _deviceType(type),
       _requestedCapability(),
       _rotateFrame(kVideoRotation_0),
       last_capture_time_ms_(rtc::TimeMillis()),
+      capture_cursor_(captureCursor),
       time_event_(EventWrapper::Create()),
 #if defined(_WIN32)
       capturer_thread_(
@@ -428,6 +435,19 @@ void DesktopCaptureImpl::DeRegisterCaptureDataCallback(
   }
 }
 
+void DesktopCaptureImpl::RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) {
+  rtc::CritScope lock(&_apiCs);
+  _rawFrameCallbacks.insert(rawFrameCallback);
+}
+
+void DesktopCaptureImpl::DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) {
+  rtc::CritScope lock(&_apiCs);
+  auto it = _rawFrameCallbacks.find(rawFrameCallback);
+  if (it != _rawFrameCallbacks.end()) {
+    _rawFrameCallbacks.erase(it);
+  }
+}
+
 int32_t DesktopCaptureImpl::StopCaptureIfAllClientsClose() {
   if (_dataCallBacks.empty()) {
     return StopCapture();
@@ -636,6 +656,12 @@ void DesktopCaptureImpl::OnCaptureResult(DesktopCapturer::Result result,
   frameInfo.height = frame->size().height();
   frameInfo.videoType = VideoType::kARGB;
 
+  size_t videoFrameStride =
+      frameInfo.width * DesktopFrame::kBytesPerPixel;
+  for (auto rawFrameCallback : _rawFrameCallbacks) {
+    rawFrameCallback->OnRawFrame(videoFrame, videoFrameStride, frameInfo);
+  }
+
   size_t videoFrameLength =
       frameInfo.width * frameInfo.height * DesktopFrame::kBytesPerPixel;
   IncomingFrame(videoFrame, videoFrameLength,
diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.h b/dom/media/systemservices/video_engine/desktop_capture_impl.h
index 7aa166d9f40abddcf55335ba09135a57ffee4e1d..196a274945435b7af0b7af2dffcd055a86fd2d76 100644
--- a/dom/media/systemservices/video_engine/desktop_capture_impl.h
+++ b/dom/media/systemservices/video_engine/desktop_capture_impl.h
@@ -44,6 +44,21 @@ namespace webrtc {
 
 class VideoCaptureEncodeInterface;
 
+class RawFrameCallback {
+ public:
+  virtual ~RawFrameCallback() {}
+
+  virtual void OnRawFrame(uint8_t* videoFrame, size_t videoFrameLength, const VideoCaptureCapability& frameInfo) = 0;
+};
+
+class VideoCaptureModuleEx : public VideoCaptureModule {
+ public:
+  virtual ~VideoCaptureModuleEx() {}
+
+  virtual void RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) = 0;
+  virtual void DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) = 0;
+};
+
 // simulate deviceInfo interface for video engine, bridge screen/application and
 // real screen/application device info
 
@@ -156,12 +171,13 @@ class BrowserDeviceInfoImpl : public VideoCaptureModule::DeviceInfo {
 // As with video, DesktopCaptureImpl is a proxy for screen sharing
 // and follows the video pipeline design
 class DesktopCaptureImpl : public DesktopCapturer::Callback,
-                           public VideoCaptureModule {
+                           public VideoCaptureModuleEx {
  public:
   /* Create a screen capture modules object
    */
-  static VideoCaptureModule* Create(const int32_t id, const char* uniqueId,
-                                    const CaptureDeviceType type);
+  static VideoCaptureModuleEx* Create(const int32_t id, const char* uniqueId,
+                                    const CaptureDeviceType type,
+                                    bool captureCursor = true);
   static VideoCaptureModule::DeviceInfo* CreateDeviceInfo(
       const int32_t id, const CaptureDeviceType type);
 
@@ -171,6 +187,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback,
   void DeRegisterCaptureDataCallback(
       rtc::VideoSinkInterface<VideoFrame>* dataCallback) override;
   int32_t StopCaptureIfAllClientsClose() override;
+  void RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) override;
+  void DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) override;
 
   int32_t SetCaptureRotation(VideoRotation rotation) override;
   bool SetApplyRotation(bool enable) override;
@@ -191,7 +209,7 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback,
 
  protected:
   DesktopCaptureImpl(const int32_t id, const char* uniqueId,
-                     const CaptureDeviceType type);
+                     const CaptureDeviceType type, bool captureCursor);
   virtual ~DesktopCaptureImpl();
   int32_t DeliverCapturedFrame(webrtc::VideoFrame& captureFrame);
 
@@ -213,6 +231,7 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback,
   rtc::RecursiveCriticalSection _apiCs;
 
   std::set<rtc::VideoSinkInterface<VideoFrame>*> _dataCallBacks;
+  std::set<RawFrameCallback*> _rawFrameCallbacks;
 
   int64_t _incomingFrameTimesNanos
       [kFrameRateCountHistorySize];  // timestamp for local captured frames
@@ -235,6 +254,7 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback,
   void ProcessIter();
 
  private:
+  bool capture_cursor_ = true;
   // This is created on the main thread and accessed on both the main thread
   // and the capturer thread. It is created prior to the capturer thread
   // starting and is destroyed after it is stopped.
diff --git a/dom/script/ScriptSettings.cpp b/dom/script/ScriptSettings.cpp
index 8c8a5810fd56512cf37635da1f43757719f06113..d2bc58fcd3b05f989f948839d574d00d0409873c 100644
--- a/dom/script/ScriptSettings.cpp
+++ b/dom/script/ScriptSettings.cpp
@@ -150,6 +150,30 @@ ScriptSettingsStackEntry::~ScriptSettingsStackEntry() {
   MOZ_ASSERT_IF(mGlobalObject, mGlobalObject->HasJSGlobal());
 }
 
+static nsIGlobalObject* UnwrapSandboxGlobal(nsIGlobalObject* global) {
+  if (!global)
+    return global;
+  JSObject* globalObject = global->GetGlobalJSObject();
+  if (!globalObject)
+    return global;
+  JSContext* cx = nsContentUtils::GetCurrentJSContext();
+  if (!cx)
+    return global;
+  JS::Rooted<JSObject*> proto(cx);
+  JS::RootedObject rootedGlobal(cx, globalObject);
+  if (!JS_GetPrototype(cx, rootedGlobal, &proto))
+    return global;
+  if (!proto || !xpc::IsSandboxPrototypeProxy(proto))
+    return global;
+  // If this is a sandbox associated with a DOMWindow via a
+  // sandboxPrototype, use that DOMWindow. This supports GreaseMonkey
+  // and JetPack content scripts.
+  proto = js::CheckedUnwrapDynamic(proto, cx, /* stopAtWindowProxy = */ false);
+  if (!proto)
+    return global;
+  return xpc::WindowGlobalOrNull(proto);
+}
+
 // If the entry or incumbent global ends up being something that the subject
 // principal doesn't subsume, we don't want to use it. This never happens on
 // the web, but can happen with asymmetric privilege relationships (i.e.
@@ -177,7 +201,7 @@ static nsIGlobalObject* ClampToSubject(nsIGlobalObject* aGlobalOrNull) {
   NS_ENSURE_TRUE(globalPrin, GetCurrentGlobal());
   if (!nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller()
            ->SubsumesConsideringDomain(globalPrin)) {
-    return GetCurrentGlobal();
+    return UnwrapSandboxGlobal(GetCurrentGlobal());
   }
 
   return aGlobalOrNull;
diff --git a/dom/security/nsCSPUtils.cpp b/dom/security/nsCSPUtils.cpp
index eb8516ea56952fd630dc9c0d29708fe90e7d73e6..25af107441e1022d76e05c52fa7ea33182845bff 100644
--- a/dom/security/nsCSPUtils.cpp
+++ b/dom/security/nsCSPUtils.cpp
@@ -127,6 +127,11 @@ void CSP_ApplyMetaCSPToDoc(mozilla::dom::Document& aDoc,
     return;
   }
 
+  if (aDoc.GetDocShell() &&
+      nsDocShell::Cast(aDoc.GetDocShell())->IsBypassCSPEnabled()) {
+    return;
+  }
+
   nsAutoString policyStr(
       nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
           aPolicyStr));
diff --git a/dom/webidl/GeometryUtils.webidl b/dom/webidl/GeometryUtils.webidl
index 2f71b284ee5f7e11f117c447834b48355784448c..d996e0a3cbbb19c1dc320c305c6d74037bffa0d3 100644
--- a/dom/webidl/GeometryUtils.webidl
+++ b/dom/webidl/GeometryUtils.webidl
@@ -27,6 +27,9 @@ interface mixin GeometryUtils {
   [Throws, Func="nsINode::HasBoxQuadsSupport", NeedsCallerType]
   sequence<DOMQuad> getBoxQuads(optional BoxQuadOptions options = {});
 
+  [ChromeOnly, Throws, Func="nsINode::HasBoxQuadsSupport"]
+  void scrollRectIntoViewIfNeeded(long x, long y, long w, long h);
+
   /* getBoxQuadsFromWindowOrigin is similar to getBoxQuads, but the
    * returned quads are further translated relative to the window
    * origin -- which is not the layout origin. Further translation
diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp
index 718a5c371f90e259f4231614cb9ffb0ae71c0728..82e736c4258bc5ac81a074f4b21a6618f30e1ec6 100644
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -976,7 +976,7 @@ void PrefLanguagesChanged(const char* /* aPrefName */, void* /* aClosure */) {
   AssertIsOnMainThread();
 
   nsTArray<nsString> languages;
-  Navigator::GetAcceptLanguages(languages);
+  Navigator::GetAcceptLanguages(nullptr, languages);
 
   RuntimeService* runtime = RuntimeService::GetService();
   if (runtime) {
@@ -1178,8 +1178,7 @@ bool RuntimeService::RegisterWorker(WorkerPrivate& aWorkerPrivate) {
       }
 
       // The navigator overridden properties should have already been read.
-
-      Navigator::GetAcceptLanguages(mNavigatorProperties.mLanguages);
+      Navigator::GetAcceptLanguages(nullptr, mNavigatorProperties.mLanguages);
       mNavigatorPropertiesLoaded = true;
     }
 
@@ -1783,6 +1782,13 @@ void RuntimeService::PropagateStorageAccessPermissionGranted(
   }
 }
 
+void RuntimeService::ResetDefaultLocaleInAllWorkers() {
+  AssertIsOnMainThread();
+  BroadcastAllWorkers([](auto& worker) {
+    worker.ResetDefaultLocale();
+  });
+}
+
 template <typename Func>
 void RuntimeService::BroadcastAllWorkers(const Func& aFunc) {
   AssertIsOnMainThread();
@@ -2197,6 +2203,14 @@ void PropagateStorageAccessPermissionGrantedToWorkers(
   }
 }
 
+void ResetDefaultLocaleInAllWorkers() {
+  AssertIsOnMainThread();
+  RuntimeService* runtime = RuntimeService::GetService();
+  if (runtime) {
+    runtime->ResetDefaultLocaleInAllWorkers();
+  }
+}
+
 WorkerPrivate* GetWorkerPrivateFromContext(JSContext* aCx) {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aCx);
diff --git a/dom/workers/RuntimeService.h b/dom/workers/RuntimeService.h
index ef32cc847e8b86319830bb93879aaf809fe464d4..5db3be0dc87e50ff75177194ca734313b22509d6 100644
--- a/dom/workers/RuntimeService.h
+++ b/dom/workers/RuntimeService.h
@@ -110,6 +110,8 @@ class RuntimeService final : public nsIObserver {
   void PropagateStorageAccessPermissionGranted(
       const nsPIDOMWindowInner& aWindow);
 
+  void ResetDefaultLocaleInAllWorkers();
+
   const NavigatorProperties& GetNavigatorProperties() const {
     return mNavigatorProperties;
   }
diff --git a/dom/workers/WorkerCommon.h b/dom/workers/WorkerCommon.h
index d10dabb5c5ff8e17851edf2bd2efc08e74584d8e..53c4070c5fde43b27fb8fbfdcf4c23d8af57fba3 100644
--- a/dom/workers/WorkerCommon.h
+++ b/dom/workers/WorkerCommon.h
@@ -44,6 +44,8 @@ void ResumeWorkersForWindow(const nsPIDOMWindowInner& aWindow);
 void PropagateStorageAccessPermissionGrantedToWorkers(
     const nsPIDOMWindowInner& aWindow);
 
+void ResetDefaultLocaleInAllWorkers();
+
 // All of these are implemented in WorkerScope.cpp
 
 bool IsWorkerGlobal(JSObject* global);
diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp
index 57cff356a84774536dcc2cd7a9d4cacc81106539..fc0fcff445c5ef28d92da301094113ade0fc9d85 100644
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -695,6 +695,18 @@ class UpdateContextOptionsRunnable final : public WorkerControlRunnable {
   }
 };
 
+class ResetDefaultLocaleRunnable final : public WorkerControlRunnable {
+ public:
+  explicit ResetDefaultLocaleRunnable(WorkerPrivate* aWorkerPrivate)
+      : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) {}
+
+  virtual bool WorkerRun(JSContext* aCx,
+                         WorkerPrivate* aWorkerPrivate) override {
+    aWorkerPrivate->ResetDefaultLocaleInternal(aCx);
+    return true;
+  }
+};
+
 class UpdateLanguagesRunnable final : public WorkerRunnable {
   nsTArray<nsString> mLanguages;
 
@@ -1902,6 +1914,16 @@ void WorkerPrivate::UpdateContextOptions(
   }
 }
 
+void WorkerPrivate::ResetDefaultLocale() {
+  AssertIsOnParentThread();
+
+  RefPtr<ResetDefaultLocaleRunnable> runnable =
+      new ResetDefaultLocaleRunnable(this);
+  if (!runnable->Dispatch()) {
+    NS_WARNING("Failed to reset default locale in worker!");
+  }
+}
+
 void WorkerPrivate::UpdateLanguages(const nsTArray<nsString>& aLanguages) {
   AssertIsOnParentThread();
 
@@ -5063,6 +5085,15 @@ void WorkerPrivate::UpdateContextOptionsInternal(
   }
 }
 
+void WorkerPrivate::ResetDefaultLocaleInternal(JSContext* aCx) {
+  JS_ResetDefaultLocale(JS_GetRuntime(aCx));
+  auto data = mWorkerThreadAccessible.Access();
+
+  for (uint32_t index = 0; index < data->mChildWorkers.Length(); index++) {
+    data->mChildWorkers[index]->ResetDefaultLocale();
+  }
+}
+
 void WorkerPrivate::UpdateLanguagesInternal(
     const nsTArray<nsString>& aLanguages) {
   WorkerGlobalScope* globalScope = GlobalScope();
diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h
index 7925e3decfc3c3556b368cbeef09e6398fac39ef..e62683c3b4d12b58e39de215deeb0dae42c9152d 100644
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -330,6 +330,8 @@ class WorkerPrivate final
   void UpdateContextOptionsInternal(JSContext* aCx,
                                     const JS::ContextOptions& aContextOptions);
 
+  void ResetDefaultLocaleInternal(JSContext* aCx);
+
   void UpdateLanguagesInternal(const nsTArray<nsString>& aLanguages);
 
   void UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key,
@@ -964,6 +966,8 @@ class WorkerPrivate final
 
   void UpdateContextOptions(const JS::ContextOptions& aContextOptions);
 
+  void ResetDefaultLocale();
+
   void UpdateLanguages(const nsTArray<nsString>& aLanguages);
 
   void UpdateJSWorkerMemoryParameter(JSGCParamKey key, Maybe<uint32_t> value);
diff --git a/intl/components/src/TimeZone.cpp b/intl/components/src/TimeZone.cpp
index 145dd3f07112c2390325de50f8eae674484adfe6..8cb3787e1b6bb25c6a58f1d910ae7dbc440d9ace 100644
--- a/intl/components/src/TimeZone.cpp
+++ b/intl/components/src/TimeZone.cpp
@@ -16,6 +16,7 @@
 
 namespace mozilla::intl {
 
+
 /* static */
 Result<UniquePtr<TimeZone>, ICUError> TimeZone::TryCreate(
     Maybe<Span<const char16_t>> aTimeZoneOverride) {
@@ -239,6 +240,13 @@ static ICUResult SetDefaultTimeZone(TimeZoneIdentifierVector& timeZone) {
 }
 #endif
 
+bool TimeZone::IsValidTimeZoneId(const char* timeZoneId) {
+  // Validate timezone id.
+  mozilla::UniquePtr<icu::TimeZone> timeZone(icu::TimeZone::createTimeZone(
+      icu::UnicodeString(timeZoneId, -1, US_INV)));
+  return timeZone && *timeZone != icu::TimeZone::getUnknown();
+}
+
 Result<bool, ICUError> TimeZone::SetDefaultTimeZone(
     Span<const char> aTimeZone) {
 #if MOZ_INTL_USE_ICU_CPP_TIMEZONE
diff --git a/intl/components/src/TimeZone.h b/intl/components/src/TimeZone.h
index 180092bd3fc0b70462cc6ba67e72946e4c4c7604..bcaecb9fcd7b630c75289581a887cc6894733168 100644
--- a/intl/components/src/TimeZone.h
+++ b/intl/components/src/TimeZone.h
@@ -154,6 +154,8 @@ class TimeZone final {
     return FillBufferWithICUCall(aBuffer, ucal_getHostTimeZone);
   }
 
+  static bool IsValidTimeZoneId(const char* timeZoneId);
+
   /**
    * Set the default time zone.
    */
diff --git a/js/public/Date.h b/js/public/Date.h
index bb69d58dc96ed7f0b37f73e26abdd0bdfeaaf556..8436d439f72287176a2fe6a1a837d3db73409e67 100644
--- a/js/public/Date.h
+++ b/js/public/Date.h
@@ -53,6 +53,8 @@ namespace JS {
  */
 extern JS_PUBLIC_API void ResetTimeZone();
 
+extern JS_PUBLIC_API bool SetTimeZoneOverride(const char* timezoneId);
+
 class ClippedTime;
 inline ClippedTime TimeClip(double time);
 
diff --git a/js/src/debugger/Object.cpp b/js/src/debugger/Object.cpp
index 838eb84e208a6ee101371ea05ce048615bcd1f1f..ee248d0069d2b710d6ec4279d88e4a63ede721f5 100644
--- a/js/src/debugger/Object.cpp
+++ b/js/src/debugger/Object.cpp
@@ -2371,7 +2371,11 @@ Maybe<Completion> DebuggerObject::call(JSContext* cx,
         invokeArgs[i].set(args2[i]);
       }
 
+      // Disable CSP for the scope of the call.
+      const JSSecurityCallbacks* securityCallbacks = JS_GetSecurityCallbacks(cx);
+      JS_SetSecurityCallbacks(cx, nullptr);
       ok = js::Call(cx, calleev, thisv, invokeArgs, &result);
+      JS_SetSecurityCallbacks(cx, securityCallbacks);
     }
   }
 
diff --git a/js/src/vm/DateTime.cpp b/js/src/vm/DateTime.cpp
index a86a6e9f7177c86624f118ebbc2e012766137bd1..5ebd1f106a556471fda5961d1f11f8eac31718cc 100644
--- a/js/src/vm/DateTime.cpp
+++ b/js/src/vm/DateTime.cpp
@@ -178,6 +178,11 @@ void js::DateTimeInfo::internalResetTimeZone(ResetTimeZoneMode mode) {
   }
 }
 
+void js::DateTimeInfo::internalSetTimeZoneOverride(std::string timeZone) {
+  timeZoneOverride_ = std::move(timeZone);
+  internalResetTimeZone(ResetTimeZoneMode::ResetEvenIfOffsetUnchanged);
+}
+
 void js::DateTimeInfo::updateTimeZone() {
   MOZ_ASSERT(timeZoneStatus_ != TimeZoneStatus::Valid);
 
@@ -502,10 +507,24 @@ void js::ResetTimeZoneInternal(ResetTimeZoneMode mode) {
   js::DateTimeInfo::resetTimeZone(mode);
 }
 
+void js::SetTimeZoneOverrideInternal(std::string timeZone) {
+  auto guard = js::DateTimeInfo::instance->lock();
+  guard->internalSetTimeZoneOverride(timeZone);
+}
+
 JS_PUBLIC_API void JS::ResetTimeZone() {
   js::ResetTimeZoneInternal(js::ResetTimeZoneMode::ResetEvenIfOffsetUnchanged);
 }
 
+JS_PUBLIC_API bool JS::SetTimeZoneOverride(const char* timeZoneId) {
+  if (!mozilla::intl::TimeZone::IsValidTimeZoneId(timeZoneId)) {
+    fprintf(stderr, "Invalid timezone id: %s\n", timeZoneId);
+    return false;
+  }
+  js::SetTimeZoneOverrideInternal(std::string(timeZoneId));
+  return true;
+}
+
 #if JS_HAS_INTL_API
 #  if defined(XP_WIN)
 static bool IsOlsonCompatibleWindowsTimeZoneId(std::string_view tz) {
@@ -727,9 +746,17 @@ void js::ResyncICUDefaultTimeZone() {
 
 void js::DateTimeInfo::internalResyncICUDefaultTimeZone() {
 #if JS_HAS_INTL_API
+  if (!timeZoneOverride_.empty()) {
+    mozilla::Span<const char> tzid = mozilla::Span(timeZoneOverride_.data(), timeZoneOverride_.length());
+    auto result = mozilla::intl::TimeZone::SetDefaultTimeZone(tzid);
+    if (result.isErr()) {
+      fprintf(stderr, "ERROR: failed to setup default time zone\n");
+    }
+    return;
+  }
+
   if (const char* tzenv = std::getenv("TZ")) {
     std::string_view tz(tzenv);
-
     mozilla::Span<const char> tzid;
 
 #  if defined(XP_WIN)
diff --git a/js/src/vm/DateTime.h b/js/src/vm/DateTime.h
index 3ce936fe3a4a83f9161eddc9e5289322d6a363e3..6b1c34244d8b2f2102ec423e2d96812fb5d41a9d 100644
--- a/js/src/vm/DateTime.h
+++ b/js/src/vm/DateTime.h
@@ -63,6 +63,8 @@ enum class ResetTimeZoneMode : bool {
  */
 extern void ResetTimeZoneInternal(ResetTimeZoneMode mode);
 
+extern void SetTimeZoneOverrideInternal(std::string timeZone);
+
 /**
  * ICU's default time zone, used for various date/time formatting operations
  * that include the local time in the representation, is allowed to go stale
@@ -202,6 +204,7 @@ class DateTimeInfo {
   // and js::ResyncICUDefaultTimeZone().
   friend void js::ResetTimeZoneInternal(ResetTimeZoneMode);
   friend void js::ResyncICUDefaultTimeZone();
+  friend void js::SetTimeZoneOverrideInternal(std::string);
 
   static void resetTimeZone(ResetTimeZoneMode mode) {
     auto guard = instance->lock();
@@ -293,6 +296,8 @@ class DateTimeInfo {
   JS::UniqueChars locale_;
   JS::UniqueTwoByteChars standardName_;
   JS::UniqueTwoByteChars daylightSavingsName_;
+
+  std::string timeZoneOverride_;
 #else
   // Restrict the data-time range to the minimum required time_t range as
   // specified in POSIX. Most operating systems support 64-bit time_t
@@ -308,6 +313,8 @@ class DateTimeInfo {
 
   void internalResetTimeZone(ResetTimeZoneMode mode);
 
+  void internalSetTimeZoneOverride(std::string timeZone);
+
   void updateTimeZone();
 
   void internalResyncICUDefaultTimeZone();
diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp
index fa41edbf0f4b34e1c0a2602d53e13416ef4751ec..8513859fcb3c798f583b76451818b6e4a2170c5b 100644
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -10894,7 +10894,9 @@ auto PresShell::ComputeActiveness() const -> Activeness {
     if (!browserChild->IsVisible()) {
       MOZ_LOG(gLog, LogLevel::Debug,
               (" > BrowserChild %p is not visible", browserChild));
-      return {false, inActiveTab};
+      bool isActive;
+      root->GetDocShell()->GetForceActiveState(&isActive);
+      return {isActive, inActiveTab};
     }
 
     // If the browser is visible but just due to be preserving layers
diff --git a/layout/style/GeckoBindings.h b/layout/style/GeckoBindings.h
index a384a0d00ce970a3e9db8983deaa012b45a76324..954bf59def43fdbb62924f35b45cde5f6c1a9fff 100644
--- a/layout/style/GeckoBindings.h
+++ b/layout/style/GeckoBindings.h
@@ -586,6 +586,7 @@ void Gecko_MediaFeatures_GetDeviceSize(const mozilla::dom::Document*,
 
 float Gecko_MediaFeatures_GetResolution(const mozilla::dom::Document*);
 bool Gecko_MediaFeatures_PrefersReducedMotion(const mozilla::dom::Document*);
+bool Gecko_MediaFeatures_ForcedColors(const mozilla::dom::Document*);
 mozilla::StylePrefersContrast Gecko_MediaFeatures_PrefersContrast(
     const mozilla::dom::Document*);
 mozilla::StylePrefersColorScheme Gecko_MediaFeatures_PrefersColorScheme(
diff --git a/layout/style/nsMediaFeatures.cpp b/layout/style/nsMediaFeatures.cpp
index 2ef43008df12886ad00485ef743564774850c2ba..bb53b96ae491146d895e1c32d62dc0f2ea00812f 100644
--- a/layout/style/nsMediaFeatures.cpp
+++ b/layout/style/nsMediaFeatures.cpp
@@ -260,10 +260,11 @@ bool Gecko_MediaFeatures_MatchesPlatform(StylePlatform aPlatform) {
 }
 
 bool Gecko_MediaFeatures_PrefersReducedMotion(const Document* aDocument) {
-  if (nsContentUtils::ShouldResistFingerprinting(aDocument)) {
-    return false;
-  }
-  return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1;
+  return aDocument->PrefersReducedMotion();
+}
+
+bool Gecko_MediaFeatures_ForcedColors(const Document* aDocument) {
+  return aDocument->ForcedColors();
 }
 
 StylePrefersColorScheme Gecko_MediaFeatures_PrefersColorScheme(
diff --git a/media/libjpeg/jconfig.h b/media/libjpeg/jconfig.h
index f2723e654098ff27542e1eb16a536c11ad0af617..b0b480551ff7d895dfdeb5a9800874858929c8ba 100644
--- a/media/libjpeg/jconfig.h
+++ b/media/libjpeg/jconfig.h
@@ -17,6 +17,7 @@
 /* #undef D_ARITH_CODING_SUPPORTED */
 
 /* Support in-memory source/destination managers */
+#define MEM_SRCDST_SUPPORTED 1
 /* #undef MEM_SRCDST_SUPPORTED */
 
 /* Use accelerated SIMD routines. */
diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js
index db545cd135c505c28aaf8d47269eb4730a5047d6..0caeee630ccaec3498fb6d0a5e0b29dec253162d 100644
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -4397,7 +4397,9 @@ pref("devtools.experiment.f12.shortcut_disabled", false);
 // doesn't provide a way to lock the pref
 pref("dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled", false);
 #else
-pref("dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled", false, locked);
+// Playwright: DO NOT make preference locked so that we can overwrite it
+// later in our playwright.cfg file.
+pref("dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled", false);
 #endif
 
 // Whether to start the private browsing mode at application startup
diff --git a/netwerk/base/nsINetworkInterceptController.idl b/netwerk/base/nsINetworkInterceptController.idl
index e869cd28d396aa87c522241d3e63d435ee8dbae6..2d307f089209721d88d231b03e8628890b8228ea 100644
--- a/netwerk/base/nsINetworkInterceptController.idl
+++ b/netwerk/base/nsINetworkInterceptController.idl
@@ -59,6 +59,7 @@ interface nsIInterceptedChannel : nsISupports
      * results in the resulting client not being controlled.
      */
     void resetInterception(in boolean bypass);
+    void resetInterceptionWithURI(in nsIURI aURI);
 
     /**
      * Set the status and reason for the forthcoming synthesized response.
diff --git a/netwerk/protocol/http/InterceptedHttpChannel.cpp b/netwerk/protocol/http/InterceptedHttpChannel.cpp
index 019412c56ba24c06265d20a424dab4d4a850d04b..4ccb5e035fea85fe6b3393473cb620cbc9603de4 100644
--- a/netwerk/protocol/http/InterceptedHttpChannel.cpp
+++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp
@@ -663,6 +663,14 @@ void InterceptedHttpChannel::DoAsyncAbort(nsresult aStatus) {
   Unused << AsyncAbort(aStatus);
 }
 
+NS_IMETHODIMP
+InterceptedHttpChannel::ResetInterceptionWithURI(nsIURI* aURI) {
+  if (aURI) {
+    mURI = aURI;
+  }
+  return ResetInterception(true);
+}
+
 NS_IMETHODIMP
 InterceptedHttpChannel::ResetInterception(bool aBypass) {
   if (mCanceled) {
diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp
index d956b3b5c6ecf6a983689d09e491193519f34ceb..826aabb5b794a2d4028950066ca3036223a35e0c 100644
--- a/parser/html/nsHtml5TreeOpExecutor.cpp
+++ b/parser/html/nsHtml5TreeOpExecutor.cpp
@@ -1330,6 +1330,10 @@ void nsHtml5TreeOpExecutor::UpdateReferrerInfoFromMeta(
 void nsHtml5TreeOpExecutor::AddSpeculationCSP(const nsAString& aCSP) {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
+  if (mDocShell && static_cast<nsDocShell*>(mDocShell.get())->IsBypassCSPEnabled()) {
+    return;
+  }
+
   nsresult rv = NS_OK;
   nsCOMPtr<nsIContentSecurityPolicy> preloadCsp = mDocument->GetPreloadCsp();
   if (!preloadCsp) {
diff --git a/python/mozbuild/mozpack/executables.py b/python/mozbuild/mozpack/executables.py
index 4504ade8e6b3be9404e0d72fd30f60939831ed0f..34988ac3ede846d0aaa0d4637439108fd922361f 100644
--- a/python/mozbuild/mozpack/executables.py
+++ b/python/mozbuild/mozpack/executables.py
@@ -107,7 +107,7 @@ def strip(path):
     """
     from buildconfig import substs
 
-    strip = substs["STRIP"]
+    strip = os.getenv("CMD_STRIP") or substs["STRIP"]
     flags = substs.get("STRIP_FLAGS", [])
     cmd = [strip] + flags + [path]
     if subprocess.call(cmd) != 0:
diff --git a/security/manager/ssl/nsCertOverrideService.cpp b/security/manager/ssl/nsCertOverrideService.cpp
index a579952d3ffa06b69211e64fad8d9fb2656abece..9b4b93fa52972c3010a9e18de2cb199d6a5954c7 100644
--- a/security/manager/ssl/nsCertOverrideService.cpp
+++ b/security/manager/ssl/nsCertOverrideService.cpp
@@ -572,7 +572,12 @@ nsCertOverrideService::HasMatchingOverride(
   bool disableAllSecurityCheck = false;
   {
     MutexAutoLock lock(mMutex);
-    disableAllSecurityCheck = mDisableAllSecurityCheck;
+    if (aOriginAttributes.mUserContextId) {
+      disableAllSecurityCheck = mUserContextIdsWithDisabledSecurityChecks.has(
+          aOriginAttributes.mUserContextId);
+    } else {
+      disableAllSecurityCheck = mDisableAllSecurityCheck;
+    }
   }
   if (disableAllSecurityCheck) {
     nsCertOverride::OverrideBits all = nsCertOverride::OverrideBits::Untrusted |
@@ -778,14 +783,24 @@ static bool IsDebugger() {
 
 NS_IMETHODIMP
 nsCertOverrideService::
-    SetDisableAllSecurityChecksAndLetAttackersInterceptMyData(bool aDisable) {
-  if (!(PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR") || IsDebugger())) {
+    SetDisableAllSecurityChecksAndLetAttackersInterceptMyData(
+      bool aDisable, uint32_t aUserContextId) {
+  if (false /* juggler hacks */ && !(PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR") || IsDebugger())) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   {
     MutexAutoLock lock(mMutex);
-    mDisableAllSecurityCheck = aDisable;
+    if (aUserContextId) {
+      if (aDisable) {
+        mozilla::Unused << mUserContextIdsWithDisabledSecurityChecks.put(aUserContextId);
+      } else {
+        mUserContextIdsWithDisabledSecurityChecks.remove(aUserContextId);
+      }
+      return NS_OK;
+    } else {
+      mDisableAllSecurityCheck = aDisable;
+    }
   }
 
   nsCOMPtr<nsINSSComponent> nss(do_GetService(PSM_COMPONENT_CONTRACTID));
diff --git a/security/manager/ssl/nsCertOverrideService.h b/security/manager/ssl/nsCertOverrideService.h
index b7fb718f2aace5d84f77b2f5b0e31eb5a32d8f5b..45ed06f1ff660d8ee9d17c4eaa748dcbddbafde9 100644
--- a/security/manager/ssl/nsCertOverrideService.h
+++ b/security/manager/ssl/nsCertOverrideService.h
@@ -134,6 +134,7 @@ class nsCertOverrideService final : public nsICertOverrideService,
 
   mozilla::Mutex mMutex;
   bool mDisableAllSecurityCheck GUARDED_BY(mMutex);
+  mozilla::HashSet<uint32_t> mUserContextIdsWithDisabledSecurityChecks GUARDED_BY(mMutex);
   nsCOMPtr<nsIFile> mSettingsFile GUARDED_BY(mMutex);
   nsTHashtable<nsCertOverrideEntry> mSettingsTable GUARDED_BY(mMutex);
 
diff --git a/security/manager/ssl/nsICertOverrideService.idl b/security/manager/ssl/nsICertOverrideService.idl
index 3862fe6830874c036592fd217cab7ad5f4cd3e27..3166b37db0e52f7f2972d2bcb7a72ed819805794 100644
--- a/security/manager/ssl/nsICertOverrideService.idl
+++ b/security/manager/ssl/nsICertOverrideService.idl
@@ -201,7 +201,9 @@ interface nsICertOverrideService : nsISupports {
    *  @param aDisable If true, disable all security check and make
    *                  hasMatchingOverride always return true.
    */
-  void setDisableAllSecurityChecksAndLetAttackersInterceptMyData(in boolean aDisable);
+  void setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
+      in boolean aDisable,
+      [optional] in uint32_t aUserContextId);
 
   readonly attribute boolean securityCheckDisabled;
 };
diff --git a/services/settings/Utils.jsm b/services/settings/Utils.jsm
index 31ad77d28678ae72d0a8044e0ced3ad17bc11232..e66ef451839304b03df76f73496e84a60776553f 100644
--- a/services/settings/Utils.jsm
+++ b/services/settings/Utils.jsm
@@ -101,7 +101,7 @@ function _isUndefined(value) {
 
 var Utils = {
   get SERVER_URL() {
-    return allowServerURLOverride
+    return true || allowServerURLOverride
       ? gServerURL
       : AppConstants.REMOTE_SETTINGS_SERVER_URL;
   },
diff --git a/servo/components/style/gecko/media_features.rs b/servo/components/style/gecko/media_features.rs
index a559adbcb1ae9c0a6805240451e95fda5fc32957..8e78b3f4843104365560fde1ff617cb086d0342c 100644
--- a/servo/components/style/gecko/media_features.rs
+++ b/servo/components/style/gecko/media_features.rs
@@ -224,10 +224,15 @@ pub enum ForcedColors {
 
 /// https://drafts.csswg.org/mediaqueries-5/#forced-colors
 fn eval_forced_colors(context: &Context, query_value: Option<ForcedColors>) -> bool {
-    let forced = !context.device().use_document_colors();
+    let prefers_forced_colors =
+        unsafe { bindings::Gecko_MediaFeatures_ForcedColors(context.device().document()) };
+    let query_value = match query_value {
+        Some(v) => v,
+        None => return prefers_forced_colors,
+    };
     match query_value {
-        Some(query_value) => forced == (query_value == ForcedColors::Active),
-        None => forced,
+        ForcedColors::Active => prefers_forced_colors,
+        ForcedColors::None => !prefers_forced_colors,
     }
 }
 
diff --git a/toolkit/components/browser/nsIWebBrowserChrome.idl b/toolkit/components/browser/nsIWebBrowserChrome.idl
index 4f7337926efbb086a2be97cdbcb3dca39e27c786..f2005cb726ff153d6b1011d6af0479dbf1af02a5 100644
--- a/toolkit/components/browser/nsIWebBrowserChrome.idl
+++ b/toolkit/components/browser/nsIWebBrowserChrome.idl
@@ -70,6 +70,9 @@ interface nsIWebBrowserChrome : nsISupports
     // Whether this window should use out-of-process cross-origin subframes.
     const unsigned long CHROME_FISSION_WINDOW         = 0x00200000;
 
+    // Whether this window has "width" or "height" defined in features
+    const unsigned long JUGGLER_WINDOW_EXPLICIT_SIZE  = 0x00400000;
+
     // Prevents new window animations on MacOS and Windows. Currently
     // ignored for Linux.
     const unsigned long CHROME_SUPPRESS_ANIMATION     = 0x01000000;
diff --git a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.jsm b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.jsm
index bfb8c02573f22760a248472df281420478acd2ce..46a6fa5ddabb680969f19b2196fc3f48d65a94b6 100644
--- a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.jsm
+++ b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.jsm
@@ -115,6 +115,12 @@ EnterprisePoliciesManager.prototype = {
       Services.prefs.clearUserPref(PREF_POLICIES_APPLIED);
     }
 
+    // Playwright: Disable enterprise policies
+    if (true) {
+      this.status = Ci.nsIEnterprisePolicies.INACTIVE;
+      return;
+    }
+
     let provider = this._chooseProvider();
 
     if (provider.failed) {
diff --git a/toolkit/components/startup/nsAppStartup.cpp b/toolkit/components/startup/nsAppStartup.cpp
index a76e612bc7149155305468307bebf0e69679897d..ba3c5dc0af69a34fcfbf04a3dbc506ef45833107 100644
--- a/toolkit/components/startup/nsAppStartup.cpp
+++ b/toolkit/components/startup/nsAppStartup.cpp
@@ -370,7 +370,7 @@ nsAppStartup::Quit(uint32_t aMode, int aExitCode, bool* aUserAllowedQuit) {
     nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
     nsCOMPtr<nsIWindowMediator> mediator(
         do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
-    if (mediator) {
+    if (ferocity != eForceQuit && mediator) {
       mediator->GetEnumerator(nullptr, getter_AddRefs(windowEnumerator));
       if (windowEnumerator) {
         bool more;
diff --git a/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp b/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp
index 3e9672fdfe9ddab8acd0f8b18772aece92bb3b64..83454a9c27c96d72597445653beaa014c38728cd 100644
--- a/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp
+++ b/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp
@@ -174,8 +174,8 @@ nsBrowserStatusFilter::OnStateChange(nsIWebProgress* aWebProgress,
 }
 
 NS_IMETHODIMP
-nsBrowserStatusFilter::OnProgressChange(nsIWebProgress* aWebProgress,
-                                        nsIRequest* aRequest,
+nsBrowserStatusFilter::OnProgressChange(nsIWebProgress *aWebProgress,
+                                        nsIRequest *aRequest,
                                         int32_t aCurSelfProgress,
                                         int32_t aMaxSelfProgress,
                                         int32_t aCurTotalProgress,
diff --git a/toolkit/components/windowwatcher/nsWindowWatcher.cpp b/toolkit/components/windowwatcher/nsWindowWatcher.cpp
index 0f8f1560e734dd82ffdace9edf755d525a0028d9..9f0c24184dc09b31c8f0629a946d9ec0dfeec58f 100644
--- a/toolkit/components/windowwatcher/nsWindowWatcher.cpp
+++ b/toolkit/components/windowwatcher/nsWindowWatcher.cpp
@@ -1813,7 +1813,11 @@ uint32_t nsWindowWatcher::CalculateChromeFlagsForContent(
 
   // Open a minimal popup.
   *aIsPopupRequested = true;
-  return nsIWebBrowserChrome::CHROME_MINIMAL_POPUP;
+  uint32_t chromeFlags = 0;
+  if (aFeatures.Exists("width") || aFeatures.Exists("height")) {
+    chromeFlags |= nsIWebBrowserChrome::JUGGLER_WINDOW_EXPLICIT_SIZE;
+  }
+  return chromeFlags | nsIWebBrowserChrome::CHROME_MINIMAL_POPUP;
 }
 
 /**
diff --git a/toolkit/mozapps/update/UpdateService.jsm b/toolkit/mozapps/update/UpdateService.jsm
index 31c8d26c06b0f44453fa3baa4afeef71c62baea5..7945151507b63cbd31299cf1039c04d9b91fc805 100644
--- a/toolkit/mozapps/update/UpdateService.jsm
+++ b/toolkit/mozapps/update/UpdateService.jsm
@@ -3591,6 +3591,8 @@ UpdateService.prototype = {
   },
 
   get disabledForTesting() {
+    /* for playwright */
+    return true;
     return (
       (Cu.isInAutomation || Marionette.running || RemoteAgent.running) &&
       Services.prefs.getBoolPref(PREF_APP_UPDATE_DISABLEDFORTESTING, false)
diff --git a/toolkit/toolkit.mozbuild b/toolkit/toolkit.mozbuild
index 1241f1b0f94e0965b517898167ca1b52cfb48dc5..39c14eb7c548b81d564bd2a4ed15c70a920e173c 100644
--- a/toolkit/toolkit.mozbuild
+++ b/toolkit/toolkit.mozbuild
@@ -154,6 +154,7 @@ if CONFIG['ENABLE_WEBDRIVER']:
         '/remote',
         '/testing/firefox-ui',
         '/testing/marionette',
+        '/juggler',
         '/toolkit/components/telemetry/tests/marionette',
     ]
 
diff --git a/toolkit/xre/nsWindowsWMain.cpp b/toolkit/xre/nsWindowsWMain.cpp
index ea14a59b80bbfbaa17d7569734b8409d9d21fcde..f993e78e02563cada8c131be3d4658bc8f7532b6 100644
--- a/toolkit/xre/nsWindowsWMain.cpp
+++ b/toolkit/xre/nsWindowsWMain.cpp
@@ -14,9 +14,11 @@
 #endif
 
 #include "mozilla/Char16.h"
+#include "mozilla/CmdLineAndEnvUtils.h"
 #include "nsUTF8Utils.h"
 #include "nsWindowsHelpers.h"
 
+#include <io.h>
 #include <windows.h>
 #include <versionhelpers.h>
 
@@ -130,6 +132,20 @@ int wmain(int argc, WCHAR** argv) {
 
   SanitizeEnvironmentVariables();
   SetDllDirectoryW(L"");
+  bool hasJugglerPipe =
+      mozilla::CheckArg(argc, argv, L"juggler-pipe",
+                        static_cast<const wchar_t**>(nullptr),
+                        mozilla::CheckArgFlag::None) == mozilla::ARG_FOUND;
+  if (hasJugglerPipe && !mozilla::EnvHasValue("PW_PIPE_READ")) {
+    intptr_t stdio3 = _get_osfhandle(3);
+    intptr_t stdio4 = _get_osfhandle(4);
+    CHAR stdio3str[20];
+    CHAR stdio4str[20];
+    itoa(stdio3, stdio3str, 10);
+    itoa(stdio4, stdio4str, 10);
+    SetEnvironmentVariableA("PW_PIPE_READ", stdio3str);
+    SetEnvironmentVariableA("PW_PIPE_WRITE", stdio4str);
+  }
 
   // Only run this code if LauncherProcessWin.h was included beforehand, thus
   // signalling that the hosting process should support launcher mode.
diff --git a/uriloader/base/nsDocLoader.cpp b/uriloader/base/nsDocLoader.cpp
index 9ca3975c99c8bff3829bce1cf49d1235910c3ab8..6606eb02fba53ea8bd401d07460b85b068abd2bd 100644
--- a/uriloader/base/nsDocLoader.cpp
+++ b/uriloader/base/nsDocLoader.cpp
@@ -827,6 +827,13 @@ void nsDocLoader::DocLoaderIsEmpty(bool aFlushLayout,
                         ("DocLoader:%p: Firing load event for document.open\n",
                          this));
 
+                nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
+                if (os) {
+                  nsIPrincipal* principal = doc->NodePrincipal();
+                  if (!principal->IsSystemPrincipal())
+                    os->NotifyObservers(ToSupports(doc), "juggler-document-open-loaded", nullptr);
+                }
+
                 // This is a very cut-down version of
                 // nsDocumentViewer::LoadComplete that doesn't do various things
                 // that are not relevant here because this wasn't an actual
diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp
index d57f544a527cfbf752f75d8cd1cb88197ed2b7ac..c001e1b92f2e48474d82affae1342978aab2c37a 100644
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp
+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp
@@ -110,6 +110,7 @@
 
 #include "mozilla/Components.h"
 #include "mozilla/ClearOnShutdown.h"
+#include "mozilla/ErrorNames.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ipc/URIUtils.h"
 
@@ -833,6 +834,12 @@ NS_IMETHODIMP nsExternalHelperAppService::ApplyDecodingForExtension(
   return NS_OK;
 }
 
+NS_IMETHODIMP nsExternalHelperAppService::SetDownloadInterceptor(
+    nsIDownloadInterceptor* interceptor) {
+  mInterceptor = interceptor;
+  return NS_OK;
+}
+
 nsresult nsExternalHelperAppService::GetFileTokenForPath(
     const char16_t* aPlatformAppPath, nsIFile** aFile) {
   nsDependentString platformAppPath(aPlatformAppPath);
@@ -1442,7 +1449,12 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel* aChannel) {
   // Strip off the ".part" from mTempLeafName
   mTempLeafName.Truncate(mTempLeafName.Length() - ArrayLength(".part") + 1);
 
+  return CreateSaverForTempFile();
+}
+
+nsresult nsExternalAppHandler::CreateSaverForTempFile() {
   MOZ_ASSERT(!mSaver, "Output file initialization called more than once!");
+  nsresult rv;
   mSaver =
       do_CreateInstance(NS_BACKGROUNDFILESAVERSTREAMLISTENER_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -1633,7 +1645,36 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) {
     return NS_OK;
   }
 
-  rv = SetUpTempFile(aChannel);
+  bool isIntercepted = false;
+  nsCOMPtr<nsIDownloadInterceptor> interceptor = mExtProtSvc->mInterceptor;
+  if (interceptor) {
+    nsCOMPtr<nsIFile> fileToUse;
+    rv = interceptor->InterceptDownloadRequest(this, request, mBrowsingContext, getter_AddRefs(fileToUse), &isIntercepted);
+    if (!NS_SUCCEEDED(rv)) {
+      LOG(("    failed to call nsIDowloadInterceptor.interceptDownloadRequest"));
+      return rv;
+    }
+    if (isIntercepted) {
+      LOG(("    request interceped by nsIDowloadInterceptor"));
+      if (fileToUse) {
+        mTempFile = fileToUse;
+        rv = mTempFile->GetLeafName(mTempLeafName);
+        NS_ENSURE_SUCCESS(rv, rv);
+      } else {
+        Cancel(NS_BINDING_ABORTED);
+        return NS_OK;
+      }
+    }
+  }
+
+  // Temp file is the final destination when download is intercepted. In that
+  // case we only need to create saver (and not create transfer later). Not creating
+  // mTransfer also cuts off all downloads handling logic in the js compoenents and
+  // browser UI.
+  if (isIntercepted)
+    rv = CreateSaverForTempFile();
+  else
+    rv = SetUpTempFile(aChannel);
   if (NS_FAILED(rv)) {
     nsresult transferError = rv;
 
@@ -1688,6 +1729,9 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) {
 
   bool alwaysAsk = true;
   mMimeInfo->GetAlwaysAskBeforeHandling(&alwaysAsk);
+  if (isIntercepted) {
+    return NS_OK;
+  }
   if (alwaysAsk) {
     // But we *don't* ask if this mimeInfo didn't come from
     // our user configuration datastore and the user has said
@@ -2253,6 +2297,16 @@ nsExternalAppHandler::OnSaveComplete(nsIBackgroundFileSaver* aSaver,
     NotifyTransfer(aStatus);
   }
 
+  if (!mCanceled) {
+    nsCOMPtr<nsIDownloadInterceptor> interceptor = mExtProtSvc->mInterceptor;
+    if (interceptor) {
+      nsCString noError;
+      nsresult rv = interceptor->OnDownloadComplete(this, noError);
+      MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to call nsIDowloadInterceptor.OnDownloadComplete");
+      Unused << rv;
+    }
+  }
+
   return NS_OK;
 }
 
@@ -2732,6 +2786,15 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason) {
     }
   }
 
+  nsCOMPtr<nsIDownloadInterceptor> interceptor = mExtProtSvc->mInterceptor;
+  if (interceptor) {
+    nsCString errorName;
+    GetErrorName(aReason, errorName);
+    nsresult rv = interceptor->OnDownloadComplete(this, errorName);
+    MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed notify nsIDowloadInterceptor about cancel");
+    Unused << rv;
+  }
+
   // Break our reference cycle with the helper app dialog (set up in
   // OnStartRequest)
   mDialog = nullptr;
diff --git a/uriloader/exthandler/nsExternalHelperAppService.h b/uriloader/exthandler/nsExternalHelperAppService.h
index f8832bbde4042df9631794ca45886dcb02b60457..6a28695117997f1fd3753a75c94bc0e67e49d215 100644
--- a/uriloader/exthandler/nsExternalHelperAppService.h
+++ b/uriloader/exthandler/nsExternalHelperAppService.h
@@ -241,6 +241,8 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService,
       mozilla::dom::BrowsingContext* aContentContext, bool aForceSave,
       nsIInterfaceRequestor* aWindowContext,
       nsIStreamListener** aStreamListener);
+
+  nsCOMPtr<nsIDownloadInterceptor> mInterceptor;
 };
 
 /**
@@ -437,6 +439,9 @@ class nsExternalAppHandler final : public nsIStreamListener,
    * Upon successful return, both mTempFile and mSaver will be valid.
    */
   nsresult SetUpTempFile(nsIChannel* aChannel);
+
+  nsresult CreateSaverForTempFile();
+
   /**
    * When we download a helper app, we are going to retarget all load
    * notifications into our own docloader and load group instead of
diff --git a/uriloader/exthandler/nsIExternalHelperAppService.idl b/uriloader/exthandler/nsIExternalHelperAppService.idl
index 3554c69aaced17631d8d1e4d9a000f0dd8b7ba9c..52d6b60707d076906e79160fef155eaaf999470c 100644
--- a/uriloader/exthandler/nsIExternalHelperAppService.idl
+++ b/uriloader/exthandler/nsIExternalHelperAppService.idl
@@ -6,6 +6,8 @@
 
 #include "nsICancelable.idl"
 
+webidl BrowsingContext;
+interface nsIHelperAppLauncher;
 interface nsIURI;
 interface nsIRequest;
 interface nsIStreamListener;
@@ -15,6 +17,17 @@ interface nsIWebProgressListener2;
 interface nsIInterfaceRequestor;
 webidl BrowsingContext;
 
+/**
+ * Interceptor interface used by Juggler.
+ */
+[scriptable, uuid(9a20e9b0-75d0-11ea-bc55-0242ac130003)]
+interface nsIDownloadInterceptor : nsISupports
+{
+  bool interceptDownloadRequest(in nsIHelperAppLauncher aHandler, in nsIRequest aRequest, in BrowsingContext aBrowsingContext, out nsIFile file);
+
+  void onDownloadComplete(in nsIHelperAppLauncher aHandler, in ACString aErrorName);
+};
+
 /**
  * The external helper app service is used for finding and launching
  * platform specific external applications for a given mime content type.
@@ -76,6 +89,7 @@ interface nsIExternalHelperAppService : nsISupports
   boolean applyDecodingForExtension(in AUTF8String aExtension,
                                     in ACString aEncodingType);
 
+  void setDownloadInterceptor(in nsIDownloadInterceptor interceptor);
 };
 
 /**
diff --git a/widget/InProcessCompositorWidget.cpp b/widget/InProcessCompositorWidget.cpp
index 1c25e9d9a101233f71e92288a0f93125b81ac1c5..22cf67b0f6e3ddd2b3ed725a314ba6a9896abd1c 100644
--- a/widget/InProcessCompositorWidget.cpp
+++ b/widget/InProcessCompositorWidget.cpp
@@ -4,7 +4,10 @@
 
 #include "InProcessCompositorWidget.h"
 
+#include "HeadlessCompositorWidget.h"
+#include "HeadlessWidget.h"
 #include "mozilla/VsyncDispatcher.h"
+#include "mozilla/widget/PlatformWidgetTypes.h"
 #include "nsBaseWidget.h"
 
 namespace mozilla {
@@ -23,6 +26,12 @@ RefPtr<CompositorWidget> CompositorWidget::CreateLocal(
   // do it after the static_cast.
   nsBaseWidget* widget = static_cast<nsBaseWidget*>(aWidget);
   MOZ_RELEASE_ASSERT(widget);
+  if (aInitData.type() ==
+      CompositorWidgetInitData::THeadlessCompositorWidgetInitData) {
+    return new HeadlessCompositorWidget(
+        aInitData.get_HeadlessCompositorWidgetInitData(), aOptions,
+        static_cast<HeadlessWidget*>(aWidget));
+  }
   return new InProcessCompositorWidget(aOptions, widget);
 }
 #endif
diff --git a/widget/cocoa/NativeKeyBindings.mm b/widget/cocoa/NativeKeyBindings.mm
index d3e5983259053175584254e7ac01ca9ce024f33a..97f5b851c402fea5477c0ee57af451c62b016eec 100644
--- a/widget/cocoa/NativeKeyBindings.mm
+++ b/widget/cocoa/NativeKeyBindings.mm
@@ -492,6 +492,13 @@
       break;
     case KEY_NAME_INDEX_ArrowLeft:
       if (aEvent.IsAlt()) {
+        if (aEvent.IsMeta() || aEvent.IsControl())
+          break;
+        instance->AppendEditCommandsForSelector(
+            !aEvent.IsShift()
+                ? ToObjcSelectorPtr(@selector(moveWordLeft:))
+                : ToObjcSelectorPtr(@selector(moveWordLeftAndModifySelection:)),
+            aCommands);
         break;
       }
       if (aEvent.IsMeta() || (aEvent.IsControl() && aEvent.IsShift())) {
@@ -512,6 +519,13 @@
       break;
     case KEY_NAME_INDEX_ArrowRight:
       if (aEvent.IsAlt()) {
+        if (aEvent.IsMeta() || aEvent.IsControl())
+          break;
+        instance->AppendEditCommandsForSelector(
+            !aEvent.IsShift()
+                ? ToObjcSelectorPtr(@selector(moveWordRight:))
+                : ToObjcSelectorPtr(@selector(moveWordRightAndModifySelection:)),
+            aCommands);
         break;
       }
       if (aEvent.IsMeta() || (aEvent.IsControl() && aEvent.IsShift())) {
@@ -532,6 +546,10 @@
       break;
     case KEY_NAME_INDEX_ArrowUp:
       if (aEvent.IsControl()) {
+        if (aEvent.IsMeta() || aEvent.IsAlt())
+          break;
+        instance->AppendEditCommandsForSelector(
+          ToObjcSelectorPtr(@selector(scrollPageUp:)), aCommands);
         break;
       }
       if (aEvent.IsMeta()) {
@@ -541,7 +559,7 @@
         instance->AppendEditCommandsForSelector(
             !aEvent.IsShift()
                 ? ToObjcSelectorPtr(@selector(moveToBeginningOfDocument:))
-                : ToObjcSelectorPtr(@selector(moveToBegginingOfDocumentAndModifySelection:)),
+                : ToObjcSelectorPtr(@selector(moveToBeginningOfDocumentAndModifySelection:)),
             aCommands);
         break;
       }
@@ -564,6 +582,10 @@
       break;
     case KEY_NAME_INDEX_ArrowDown:
       if (aEvent.IsControl()) {
+        if (aEvent.IsMeta() || aEvent.IsAlt())
+          break;
+        instance->AppendEditCommandsForSelector(
+          ToObjcSelectorPtr(@selector(scrollPageDown:)), aCommands);
         break;
       }
       if (aEvent.IsMeta()) {
diff --git a/widget/headless/HeadlessCompositorWidget.cpp b/widget/headless/HeadlessCompositorWidget.cpp
index b31a969b7ab3d0fc80912b110d91dfdf3e5991f4..52aed4f9fb51f3f58a440d7e57eaccd6dfcbc2ab 100644
--- a/widget/headless/HeadlessCompositorWidget.cpp
+++ b/widget/headless/HeadlessCompositorWidget.cpp
@@ -3,6 +3,7 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "mozilla/layers/CompositorThread.h"
 #include "mozilla/widget/PlatformWidgetTypes.h"
 #include "HeadlessCompositorWidget.h"
 #include "VsyncDispatcher.h"
@@ -13,10 +14,32 @@ namespace widget {
 HeadlessCompositorWidget::HeadlessCompositorWidget(
     const HeadlessCompositorWidgetInitData& aInitData,
     const layers::CompositorOptions& aOptions, HeadlessWidget* aWindow)
-    : CompositorWidget(aOptions), mWidget(aWindow) {
+    : CompositorWidget(aOptions), mWidget(aWindow), mMon("snapshotListener") {
   mClientSize = aInitData.InitialClientSize();
 }
 
+void HeadlessCompositorWidget::SetSnapshotListener(HeadlessWidget::SnapshotListener&& listener) {
+  MOZ_ASSERT(NS_IsMainThread());
+
+  ReentrantMonitorAutoEnter lock(mMon);
+  mSnapshotListener = std::move(listener);
+  layers::CompositorThread()->Dispatch(NewRunnableMethod(
+      "HeadlessCompositorWidget::PeriodicSnapshot", this,
+      &HeadlessCompositorWidget::PeriodicSnapshot
+  ));
+}
+
+already_AddRefed<gfx::DrawTarget> HeadlessCompositorWidget::StartRemoteDrawingInRegion(
+    const LayoutDeviceIntRegion& aInvalidRegion,
+    layers::BufferMode* aBufferMode) {
+  if (!mDrawTarget)
+    return nullptr;
+
+  *aBufferMode = layers::BufferMode::BUFFER_NONE;
+  RefPtr<gfx::DrawTarget> result = mDrawTarget;
+  return result.forget();
+}
+
 void HeadlessCompositorWidget::ObserveVsync(VsyncObserver* aObserver) {
   if (RefPtr<CompositorVsyncDispatcher> cvd =
           mWidget->GetCompositorVsyncDispatcher()) {
@@ -29,6 +52,59 @@ nsIWidget* HeadlessCompositorWidget::RealWidget() { return mWidget; }
 void HeadlessCompositorWidget::NotifyClientSizeChanged(
     const LayoutDeviceIntSize& aClientSize) {
   mClientSize = aClientSize;
+  layers::CompositorThread()->Dispatch(NewRunnableMethod<LayoutDeviceIntSize>(
+      "HeadlessCompositorWidget::UpdateDrawTarget", this,
+      &HeadlessCompositorWidget::UpdateDrawTarget,
+      aClientSize));
+}
+
+void HeadlessCompositorWidget::UpdateDrawTarget(const LayoutDeviceIntSize& aClientSize) {
+  MOZ_ASSERT(NS_IsInCompositorThread());
+  if (aClientSize.IsEmpty()) {
+    mDrawTarget = nullptr;
+    return;
+  }
+
+  RefPtr<gfx::DrawTarget> old = std::move(mDrawTarget);
+  gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8;
+  gfx::IntSize size = aClientSize.ToUnknownSize();
+  mDrawTarget = mozilla::gfx::Factory::CreateDrawTarget(
+      mozilla::gfx::BackendType::SKIA, size, format);
+  if (old) {
+    RefPtr<gfx::SourceSurface> snapshot = old->Snapshot();
+    if (snapshot)
+      mDrawTarget->CopySurface(snapshot.get(), old->GetRect(), gfx::IntPoint(0, 0));
+  }
+}
+
+void HeadlessCompositorWidget::PeriodicSnapshot() {
+  ReentrantMonitorAutoEnter lock(mMon);
+  if (!mSnapshotListener)
+    return;
+
+  TakeSnapshot();
+  NS_DelayedDispatchToCurrentThread(NewRunnableMethod(
+      "HeadlessCompositorWidget::PeriodicSnapshot", this,
+      &HeadlessCompositorWidget::PeriodicSnapshot), 40);
+}
+
+void HeadlessCompositorWidget::TakeSnapshot() {
+  if (!mDrawTarget)
+    return;
+
+  RefPtr<gfx::SourceSurface> snapshot = mDrawTarget->Snapshot();
+  if (!snapshot) {
+    fprintf(stderr, "Failed to get snapshot of draw target\n");
+    return;
+  }
+
+  RefPtr<gfx::DataSourceSurface> dataSurface = snapshot->GetDataSurface();
+  if (!dataSurface) {
+    fprintf(stderr, "Failed to get data surface from snapshot\n");
+    return;
+  }
+
+  mSnapshotListener(std::move(dataSurface));
 }
 
 LayoutDeviceIntSize HeadlessCompositorWidget::GetClientSize() {
diff --git a/widget/headless/HeadlessCompositorWidget.h b/widget/headless/HeadlessCompositorWidget.h
index 7f91de9e67d7ffa02de3eef1d760e5cfd05e7ad6..753b8902026626e8f0a190ea3130ba5e65c24835 100644
--- a/widget/headless/HeadlessCompositorWidget.h
+++ b/widget/headless/HeadlessCompositorWidget.h
@@ -6,6 +6,7 @@
 #ifndef widget_headless_HeadlessCompositorWidget_h
 #define widget_headless_HeadlessCompositorWidget_h
 
+#include "mozilla/ReentrantMonitor.h"
 #include "mozilla/widget/CompositorWidget.h"
 
 #include "HeadlessWidget.h"
@@ -23,8 +24,12 @@ class HeadlessCompositorWidget final : public CompositorWidget,
                            HeadlessWidget* aWindow);
 
   void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize);
+  void SetSnapshotListener(HeadlessWidget::SnapshotListener&& listener);
 
   // CompositorWidget Overrides
+  already_AddRefed<gfx::DrawTarget> StartRemoteDrawingInRegion(
+      const LayoutDeviceIntRegion& aInvalidRegion,
+      layers::BufferMode* aBufferMode) override;
 
   uintptr_t GetWidgetKey() override;
 
@@ -42,9 +47,17 @@ class HeadlessCompositorWidget final : public CompositorWidget,
   }
 
  private:
+  void UpdateDrawTarget(const LayoutDeviceIntSize& aClientSize);
+  void PeriodicSnapshot();
+  void TakeSnapshot();
+
   HeadlessWidget* mWidget;
+  mozilla::ReentrantMonitor mMon;
 
   LayoutDeviceIntSize mClientSize;
+
+  HeadlessWidget::SnapshotListener mSnapshotListener;
+  RefPtr<gfx::DrawTarget> mDrawTarget;
 };
 
 }  // namespace widget
diff --git a/widget/headless/HeadlessWidget.cpp b/widget/headless/HeadlessWidget.cpp
index c1fbcccc93d9a6876aa82893cdf9c09b72087751..7a8073e3b746aec3a894957e87975189c06782d3 100644
--- a/widget/headless/HeadlessWidget.cpp
+++ b/widget/headless/HeadlessWidget.cpp
@@ -109,6 +109,8 @@ void HeadlessWidget::Destroy() {
     }
   }
 
+  SetSnapshotListener(nullptr);
+
   nsBaseWidget::OnDestroy();
 
   nsBaseWidget::Destroy();
@@ -564,5 +566,15 @@ nsresult HeadlessWidget::SynthesizeNativeTouchPadPinch(
   DispatchPinchGestureInput(inputToDispatch);
   return NS_OK;
 }
+
+void HeadlessWidget::SetSnapshotListener(SnapshotListener&& listener) {
+  if (!mCompositorWidget) {
+    if (listener)
+      fprintf(stderr, "Trying to set SnapshotListener without compositor widget\n");
+    return;
+  }
+  mCompositorWidget->SetSnapshotListener(std::move(listener));
+}
+
 }  // namespace widget
 }  // namespace mozilla
diff --git a/widget/headless/HeadlessWidget.h b/widget/headless/HeadlessWidget.h
index 2b80eea70e58dd53c34edd9c5fa4415c42bcd632..72ecda7d8ddc7a9f87a954b547f8411e67ef1570 100644
--- a/widget/headless/HeadlessWidget.h
+++ b/widget/headless/HeadlessWidget.h
@@ -135,6 +135,9 @@ class HeadlessWidget : public nsBaseWidget {
       TouchpadGesturePhase aEventPhase, float aScale,
       LayoutDeviceIntPoint aPoint, int32_t aModifierFlags) override;
 
+  using SnapshotListener = std::function<void(RefPtr<gfx::DataSourceSurface>&&)>;
+  void SetSnapshotListener(SnapshotListener&& listener);
+
  private:
   ~HeadlessWidget();
   bool mEnabled;
diff --git a/widget/windows/nsAppShell.cpp b/widget/windows/nsAppShell.cpp
index 27435135c8d2eeff35bbfb23b08f5ca31b02ecb9..10b7efb72d47b5aaa897488a9f40960fcdfdfe0e 100644
--- a/widget/windows/nsAppShell.cpp
+++ b/widget/windows/nsAppShell.cpp
@@ -17,7 +17,9 @@
 #include "WinIMEHandler.h"
 #include "mozilla/widget/AudioSession.h"
 #include "mozilla/BackgroundHangMonitor.h"
-#include "mozilla/BackgroundTasks.h"
+#ifdef MOZ_BACKGROUNDTASKS
+#  include "mozilla/BackgroundTasks.h"
+#endif
 #include "mozilla/Hal.h"
 #include "nsIDOMWakeLockListener.h"
 #include "nsIPowerManagerService.h"
diff --git a/xpcom/reflect/xptinfo/xptinfo.h b/xpcom/reflect/xptinfo/xptinfo.h
index 2456c2c2b58b27cd595880b547ed20fb687a1835..e967c089b2331c7cd36d34e511543fbc84320b7d 100644
--- a/xpcom/reflect/xptinfo/xptinfo.h
+++ b/xpcom/reflect/xptinfo/xptinfo.h
@@ -514,7 +514,7 @@ static_assert(sizeof(nsXPTMethodInfo) == 8, "wrong size");
 #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
 #  define PARAM_BUFFER_COUNT 18
 #else
-#  define PARAM_BUFFER_COUNT 14
+#  define PARAM_BUFFER_COUNT 15
 #endif
 
 /**
