diff --git a/patches/playwright/0-playwright.patch.backup b/patches/playwright/0-playwright.patch.backup deleted file mode 100644 index 8d063a2d..00000000 --- a/patches/playwright/0-playwright.patch.backup +++ /dev/null @@ -1,3469 +0,0 @@ -diff --git a/accessible/interfaces/nsIAccessibleDocument.idl b/accessible/interfaces/nsIAccessibleDocument.idl -index 6c932c14a03e9cbf70723171dc9a1006bd2c017d..6312131c94c6d7e994a4a49dd64b2b4c5777251f 100644 ---- a/accessible/interfaces/nsIAccessibleDocument.idl -+++ b/accessible/interfaces/nsIAccessibleDocument.idl -@@ -73,4 +73,9 @@ interface nsIAccessibleDocument : nsISupports - * The BrowsingContext of this document. - */ - readonly attribute BrowsingContext browsingContext; -+ -+ /** -+ * Return whether it is updating. -+ */ -+ readonly attribute boolean isUpdatePendingForJugglerAccessibility; - }; -diff --git a/accessible/xpcom/xpcAccessibleDocument.cpp b/accessible/xpcom/xpcAccessibleDocument.cpp -index 3229ee415b93b9a47d7d40605ed7b509744c94ad..c2cc38ded257a02de8922312057892bf9d0cad7b 100644 ---- a/accessible/xpcom/xpcAccessibleDocument.cpp -+++ b/accessible/xpcom/xpcAccessibleDocument.cpp -@@ -151,6 +151,13 @@ xpcAccessibleDocument::GetBrowsingContext( - return NS_OK; - } - -+NS_IMETHODIMP -+xpcAccessibleDocument::GetIsUpdatePendingForJugglerAccessibility(bool* updating) { -+ NS_ENSURE_ARG_POINTER(updating); -+ *updating = Intl()->Controller()->IsUpdatePending(); -+ return NS_OK; -+} -+ - //////////////////////////////////////////////////////////////////////////////// - // xpcAccessibleDocument - -diff --git a/accessible/xpcom/xpcAccessibleDocument.h b/accessible/xpcom/xpcAccessibleDocument.h -index 9b6effc38fbecb50897a93b49c41d4453b10fb7f..939ff9615bd422eec186d8164e2ac7e643f39beb 100644 ---- a/accessible/xpcom/xpcAccessibleDocument.h -+++ b/accessible/xpcom/xpcAccessibleDocument.h -@@ -48,6 +48,8 @@ class xpcAccessibleDocument : public xpcAccessibleHyperText, - nsIAccessibleDocument** aDocument) final; - NS_IMETHOD GetBrowsingContext(dom::BrowsingContext** aBrowsingContext) 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 8167d2b81c918e02ce757f7f448f22e07c29d140..3ae798880acfd8aa965ae08051f2f81855133711 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 - #include - #include - -@@ -422,8 +423,18 @@ Maybe 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, "juggler-pipe", 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(stdio3), -+ reinterpret_cast(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 6bbc4016cd6d56e8625e808b5070515a23de7600..2fb56fb1afa5b108a426737cb5e62dc42a199354 100644 ---- a/browser/installer/allowed-dupes.mn -+++ b/browser/installer/allowed-dupes.mn -@@ -59,6 +59,12 @@ browser/chrome/browser/builtin-addons/webcompat/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 -+ - # Bug 1606928 - There's no reliable way to connect Top Sites favicons with the favicons in the Search Service - browser/chrome/browser/content/activity-stream/data/content/tippytop/favicons/allegro-pl.ico - browser/defaults/settings/main/search-config-icons/96327a73-c433-5eb4-a16d-b090cadfb80b -diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in -index 2b4d35e060dc592bb70a1f2b7ceee68616c8202b..323abfaee37445942f7678037dd5b53792dd5ed4 100644 ---- a/browser/installer/package-manifest.in -+++ b/browser/installer/package-manifest.in -@@ -183,6 +183,9 @@ - @RESPATH@/chrome/remote.manifest - #endif - -+@RESPATH@/chrome/juggler@JAREXT@ -+@RESPATH@/chrome/juggler.manifest -+ - ; Modules - @RESPATH@/browser/modules/* - @RESPATH@/modules/* -diff --git a/devtools/server/socket/websocket-server.js b/devtools/server/socket/websocket-server.js -index d49c6fbf1bf83b832795fa674f6b41f223eef812..7ea3540947ff5f61b15f27fbf4b955649f8e9ff9 100644 ---- a/devtools/server/socket/websocket-server.js -+++ b/devtools/server/socket/websocket-server.js -@@ -134,13 +134,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"); - } - -@@ -190,13 +189,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, [ -@@ -218,8 +217,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 97334bee3a111a538779789d3495805cec8b1e9a..67d030f2adecd9acc62665e2a627123148aa927d 100644 ---- a/docshell/base/BrowsingContext.cpp -+++ b/docshell/base/BrowsingContext.cpp -@@ -110,8 +110,15 @@ struct ParamTraits - - template <> - struct ParamTraits -- : public mozilla::dom::WebIDLEnumSerializer< -- mozilla::dom::PrefersColorSchemeOverride> {}; -+ : public mozilla::dom::WebIDLEnumSerializer {}; -+ -+template <> -+struct ParamTraits -+ : public mozilla::dom::WebIDLEnumSerializer {}; -+ -+template <> -+struct ParamTraits -+ : public mozilla::dom::WebIDLEnumSerializer {}; - - template <> - struct ParamTraits -@@ -2950,6 +2957,32 @@ void BrowsingContext::DidSet(FieldIndex, - }); - } - -+void BrowsingContext::DidSet(FieldIndex, -+ dom::PrefersContrastOverride aOldValue) { -+ MOZ_ASSERT(IsTop()); -+ if (PrefersContrastOverride() == aOldValue) { -+ return; -+ } -+ PresContextAffectingFieldChanged(); -+} -+ -+void BrowsingContext::DidSet(FieldIndex, -+ 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, - nsString&& aOldValue) { - MOZ_ASSERT(IsTop()); -@@ -3290,7 +3323,7 @@ void BrowsingContext::SetGeolocationServiceOverride( - if (aGeolocationOverride.WasPassed()) { - if (!mGeolocationServiceOverride) { - mGeolocationServiceOverride = new nsGeolocationService(); -- mGeolocationServiceOverride->Init(); -+ mGeolocationServiceOverride->Init(true /* isOverride */); - } - mGeolocationServiceOverride->Update(aGeolocationOverride.Value()); - } else if (RefPtr serviceOverride = -@@ -3793,6 +3826,23 @@ void BrowsingContext::DidSet(FieldIndex, - } - } - -+void BrowsingContext::DidSet(FieldIndex, bool aOldValue) { -+ const bool newValue = ForceOffline(); -+ if (newValue == aOldValue) { -+ return; -+ } -+ PreOrderWalk([&](BrowsingContext* aContext) { -+ if (Document* doc = aContext->GetDocument()) { -+ if (nsPIDOMWindowOuter* win = aContext->GetDOMWindow()) { -+ nsContentUtils::DispatchTrustedEvent( -+ doc, nsGlobalWindowOuter::Cast(win), -+ newValue ? u"offline"_ns : u"online"_ns, -+ CanBubble::eYes, Cancelable::eYes, nullptr); -+ } -+ } -+ }); -+} -+ - bool BrowsingContext::IsPopupAllowed() { - for (auto* context = GetCurrentWindowContext(); context; - context = context->GetParentWindowContext()) { -diff --git a/docshell/base/BrowsingContext.h b/docshell/base/BrowsingContext.h -index b42c32133c6490755ae4e1c599255418e6443011..afa502833ba55c94dbd30726d37450c460a69e2b 100644 ---- a/docshell/base/BrowsingContext.h -+++ b/docshell/base/BrowsingContext.h -@@ -209,11 +209,11 @@ struct EmbedderColorSchemes { - FIELD(GVInaudibleAutoplayRequestStatus, GVAutoplayRequestStatus) \ - /* ScreenOrientation-related APIs */ \ - FIELD(CurrentOrientationAngle, float) \ -- FIELD(CurrentOrientationType, mozilla::dom::OrientationType) \ -+ FIELD(CurrentOrientationType, dom::OrientationType) \ - FIELD(OrientationLock, mozilla::hal::ScreenOrientation) \ - FIELD(HasOrientationOverride, bool) \ - FIELD(UserAgentOverride, nsString) \ -- FIELD(TouchEventsOverrideInternal, mozilla::dom::TouchEventsOverride) \ -+ FIELD(TouchEventsOverrideInternal, dom::TouchEventsOverride) \ - FIELD(EmbedderElementType, Maybe) \ - FIELD(MessageManagerGroup, nsString) \ - FIELD(MaxTouchPointsOverride, uint8_t) \ -@@ -253,6 +256,9 @@ struct EmbedderColorSchemes { - * embedder element. */ \ - FIELD(EmbedderColorSchemes, EmbedderColorSchemes) \ - FIELD(DisplayMode, dom::DisplayMode) \ -+ /* playwright addition */ \ -+ FIELD(PrefersReducedMotionOverride, dom::PrefersReducedMotionOverride) \ -+ FIELD(PrefersContrastOverride, dom::PrefersContrastOverride) \ - /* The number of entries added to the session history because of this \ - * browsing context. */ \ - FIELD(HistoryEntryCount, uint32_t) \ -@@ -975,6 +978,14 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - return GetForcedColorsOverride(); - } - -+ dom::PrefersReducedMotionOverride PrefersReducedMotionOverride() const { -+ return GetPrefersReducedMotionOverride(); -+ } -+ -+ dom::PrefersContrastOverride PrefersContrastOverride() const { -+ return GetPrefersContrastOverride(); -+ } -+ - bool IsInBFCache() const; - - bool AllowJavascript() const { return GetAllowJavascript(); } -@@ -1146,6 +1157,11 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - return IsTop(); - } - -+ bool CanSet(FieldIndex, -+ dom::PrefersContrastOverride, ContentParent*) { -+ return IsTop(); -+ } -+ - bool CanSet(FieldIndex, dom::ForcedColorsOverride, - ContentParent*) { - return IsTop(); -@@ -1278,13 +1297,25 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - void DidSet(FieldIndex, - dom::ForcedColorsOverride aOldValue); - -+ void DidSet(FieldIndex, -+ dom::PrefersContrastOverride aOldValue); -+ - template - void WalkPresContexts(Callback&&); - void PresContextAffectingFieldChanged(); - - void DidSet(FieldIndex, nsCString&& aOldValue); - - void DidSet(FieldIndex, nsString&& aOldValue); - -+ bool CanSet(FieldIndex, -+ dom::PrefersReducedMotionOverride, ContentParent*) { -+ return IsTop(); -+ } -+ -+ void DidSet(FieldIndex, -+ dom::PrefersReducedMotionOverride aOldValue); -+ -+ - void DidSet(FieldIndex, nsString&& aOldValue); - - bool CanSet(FieldIndex, bool, ContentParent*) { -@@ -1360,6 +1388,8 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - - void DidSet(FieldIndex, bool aOldValue); - -+ void DidSet(FieldIndex, bool aOldValue); -+ - // Allow if the process attemping to set field is the same as the owning - // process. Deprecated. New code that might use this should generally be moved - // to WindowContext or be settable only by the parent process. -diff --git a/docshell/base/CanonicalBrowsingContext.cpp b/docshell/base/CanonicalBrowsingContext.cpp -index 4953744c3f627bb68b78606d8ae4bf6ab649398a..17c7cc94dafc76cd72aacddfd633b7df58eeae78 100644 ---- a/docshell/base/CanonicalBrowsingContext.cpp -+++ b/docshell/base/CanonicalBrowsingContext.cpp -@@ -274,7 +274,9 @@ void CanonicalBrowsingContext::ReplacedBy( - txn.SetForceOffline(GetForceOffline()); - txn.SetTopInnerSizeForRFP(GetTopInnerSizeForRFP()); - txn.SetIPAddressSpace(GetIPAddressSpace()); -+ txn.SetPrefersReducedMotionOverride(GetPrefersReducedMotionOverride()); -+ txn.SetForcedColorsOverride(GetForcedColorsOverride()); - txn.SetParentalControlsEnabled(GetParentalControlsEnabled()); - - if (!GetLanguageOverride().IsEmpty()) { - // Reapply language override to update the corresponding realm. - txn.SetLanguageOverride(GetLanguageOverride()); - } - if (!GetTimezoneOverride().IsEmpty()) { - // Reapply timezone override to update the corresponding realm. -@@ -1892,6 +1894,12 @@ void CanonicalBrowsingContext::LoadURI(nsIURI* aURI, - (void)SetIsCaptivePortalTab(true); - } - -+ { -+ nsCOMPtr observerService = mozilla::services::GetObserverService(); -+ if (observerService) { -+ observerService->NotifyObservers(ToSupports(this), "juggler-navigation-started-browser", NS_ConvertASCIItoUTF16(nsPrintfCString("%" PRIu64, loadState->GetLoadIdentifier())).get()); -+ } -+ } - LoadURI(loadState, true); - } - -diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp -index bf702818cf4116ec1cd911b6e7b5f7ddafa3e508..d846e5f6f900d2d69228331b80031bd1c18b08ed 100644 ---- a/docshell/base/nsDocShell.cpp -+++ b/docshell/base/nsDocShell.cpp -@@ -18,6 +18,12 @@ - #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/Attributes.h" - #include "mozilla/AutoRestore.h" - #include "mozilla/BasePrincipal.h" -@@ -67,6 +73,7 @@ - #include "mozilla/dom/DocGroup.h" - #include "mozilla/dom/Element.h" - #include "mozilla/dom/FragmentDirective.h" -+#include "mozilla/dom/Geolocation.h" - #include "mozilla/dom/HTMLAnchorElement.h" - #include "mozilla/dom/HTMLIFrameElement.h" - #include "mozilla/dom/Navigation.h" -@@ -98,6 +105,7 @@ - #include "mozilla/dom/DocumentBinding.h" - #include "mozilla/glean/DocshellMetrics.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" -@@ -122,6 +130,7 @@ - #include "nsIDocumentViewer.h" - #include "mozilla/dom/Document.h" - #include "nsHTMLDocument.h" -+#include "mozilla/dom/Element.h" - #include "nsIDocumentLoaderFactory.h" - #include "nsIDOMWindow.h" - #include "nsIEditingSession.h" -@@ -217,6 +226,7 @@ - #include "nsGlobalWindowInner.h" - #include "nsGlobalWindowOuter.h" - #include "nsJSEnvironment.h" -+#include "nsJSUtils.h" - #include "nsNetCID.h" - #include "nsNetUtil.h" - #include "nsObjectLoadingContent.h" -@@ -358,6 +368,14 @@ nsDocShell::nsDocShell(BrowsingContext* aBrowsingContext, - mAllowDNSPrefetch(true), - mAllowWindowControl(true), - mCSSErrorReportingEnabled(false), -+ mFileInputInterceptionEnabled(false), -+ mOverrideHasFocus(false), -+ mBypassCSPEnabled(false), -+ mForceActiveState(false), -+ mDisallowBFCache(false), -+ mReducedMotionOverride(REDUCED_MOTION_OVERRIDE_NONE), -+ mForcedColorsOverride(FORCED_COLORS_OVERRIDE_NO_OVERRIDE), -+ mContrastOverride(CONTRAST_OVERRIDE_NONE), - mAllowAuth(mItemType == typeContent), - mAllowKeywordFixup(false), - mDisableMetaRefreshWhenInactive(false), -@@ -3037,6 +3055,232 @@ nsDocShell::GetMessageManager(ContentFrameMessageManager** aMessageManager) { - return NS_OK; - } - -+// =============== Juggler Begin ======================= -+ -+nsDocShell* nsDocShell::GetRootDocShell() { -+ nsCOMPtr rootAsItem; -+ GetInProcessSameTypeRootTreeItem(getter_AddRefs(rootAsItem)); -+ nsCOMPtr 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; -+} -+ -+NS_IMETHODIMP -+nsDocShell::GetDisallowBFCache(bool* aEnabled) { -+ MOZ_ASSERT(aEnabled); -+ *aEnabled = mDisallowBFCache; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetDisallowBFCache(bool aEnabled) { -+ mDisallowBFCache = aEnabled; -+ 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) { -+ 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 observerService = -+ mozilla::services::GetObserverService(); -+ observerService->NotifyObservers( -+ ToSupports(element), "juggler-file-picker-shown", nullptr); -+} -+ -+RefPtr 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::GetReducedMotionOverride(ReducedMotionOverride* aReducedMotionOverride) { -+ *aReducedMotionOverride = GetRootDocShell()->mReducedMotionOverride; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetReducedMotionOverride(ReducedMotionOverride aReducedMotionOverride) { -+ mReducedMotionOverride = aReducedMotionOverride; -+ RefPtr 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 presContext = GetPresContext(); -+ if (presContext) { -+ presContext->MediaFeatureValuesChanged( -+ {MediaFeatureChangeReason::SystemMetricsChange}, -+ MediaFeatureChangePropagation::JustThisDocument); -+ } -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::GetContrastOverride(ContrastOverride* aContrastOverride) { -+ *aContrastOverride = GetRootDocShell()->mContrastOverride; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetContrastOverride(ContrastOverride aContrastOverride) { -+ mContrastOverride = aContrastOverride; -+ RefPtr presContext = GetPresContext(); -+ if (presContext) { -+ presContext->MediaFeatureValuesChanged( -+ {MediaFeatureChangeReason::SystemMetricsChange}, -+ MediaFeatureChangePropagation::JustThisDocument); -+ } -+ return NS_OK; -+} -+ -+// =============== Juggler End ======================= -+ - NS_IMETHODIMP - nsDocShell::GetIsNavigating(bool* aOut) { - *aOut = mIsNavigating; -@@ -4819,7 +5063,7 @@ nsDocShell::GetVisibility(bool* aVisibility) { - } - - void nsDocShell::ActivenessMaybeChanged() { -- const bool isActive = mBrowsingContext->IsActive(); -+ const bool isActive = mForceActiveState || mBrowsingContext->IsActive(); - if (RefPtr presShell = GetPresShell()) { - presShell->ActivenessMaybeChanged(); - } -@@ -6881,6 +7125,10 @@ bool nsDocShell::CanSavePresentation(uint32_t aLoadType, - return false; // no entry to save into - } - -+ if (mDisallowBFCache) { -+ return false; -+ } -+ - MOZ_ASSERT(!mozilla::SessionHistoryInParent(), - "mOSHE cannot be non-null with SHIP"); - nsCOMPtr viewer = mOSHE->GetDocumentViewer(); -@@ -8637,6 +8885,12 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState) { - true, // aForceNoOpener - getter_AddRefs(newBC)); - MOZ_ASSERT(!newBC); -+ if (rv == NS_OK) { -+ nsCOMPtr observerService = mozilla::services::GetObserverService(); -+ if (observerService) { -+ observerService->NotifyObservers(GetAsSupports(this), "juggler-window-open-in-new-context", nullptr); -+ } -+ } - return rv; - } - -@@ -9934,6 +10188,16 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState, - nsINetworkPredictor::PREDICT_LOAD, attrs, nullptr); - - nsCOMPtr req; -+ -+ // Juggler: report navigation started for non-same-document and non-javascript -+ // navigations. -+ if (!isJavaScript && !sameDocument) { -+ nsCOMPtr observerService = -+ mozilla::services::GetObserverService(); -+ if (observerService) { -+ observerService->NotifyObservers(GetAsSupports(this), "juggler-navigation-started-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("%" PRIu64, aLoadState->GetLoadIdentifier())).get()); -+ } -+ } - rv = DoURILoad(aLoadState, aCacheKey, getter_AddRefs(req)); - - if (NS_SUCCEEDED(rv)) { -@@ -13323,6 +13587,9 @@ class OnLinkClickEvent : public Runnable { - mHandler->OnLinkClickSync(mContent, mLoadState, mNoOpenerImplied, - mTriggeringPrincipal); - } -+ nsCOMPtr observerService = mozilla::services::GetObserverService(); -+ observerService->NotifyObservers(ToSupports(mContent), "juggler-link-click-sync", nullptr); -+ - return NS_OK; - } - -@@ -13439,6 +13706,8 @@ nsresult nsDocShell::OnLinkClick( - - nsCOMPtr ev = new OnLinkClickEvent( - this, aContent, loadState, noOpenerImplied, aTriggeringPrincipal); -+ nsCOMPtr observerService = mozilla::services::GetObserverService(); -+ observerService->NotifyObservers(ToSupports(aContent), "juggler-link-click", nullptr); - return Dispatch(ev.forget()); - } - -diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h -index 3050f0a5a10c7f49f56cf325cd8bfe5e6508b5be..a4f4895f69a2eaa55f3eeae77bd6a3fb29931ad4 100644 ---- a/docshell/base/nsDocShell.h -+++ b/docshell/base/nsDocShell.h -@@ -16,6 +16,7 @@ - #include "mozilla/WeakPtr.h" - #include "mozilla/dom/BrowsingContext.h" - #include "mozilla/dom/NavigationBinding.h" -+#include "mozilla/dom/Element.h" - #include "mozilla/dom/WindowProxyHolder.h" - #include "nsCOMPtr.h" - #include "nsCharsetSource.h" -@@ -80,6 +81,7 @@ class nsCommandManager; - class nsDocShellEditorData; - class nsDOMNavigationTiming; - class nsDSURIContentListener; -+class nsGeolocationService; - class nsGlobalWindowOuter; - - class FramingChecker; -@@ -410,6 +412,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 GetGeolocationServiceOverride(); -+ - // Create a content viewer within this nsDocShell for the given - // `WindowGlobalChild` actor. - nsresult CreateDocumentViewerForActor( -@@ -1036,6 +1047,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 -@@ -1355,6 +1368,17 @@ 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; -+ bool mDisallowBFCache : 1; -+ nsString mLanguageOverride; -+ RefPtr mGeolocationServiceOverride; -+ ReducedMotionOverride mReducedMotionOverride; -+ ForcedColorsOverride mForcedColorsOverride; -+ ContrastOverride mContrastOverride; -+ - bool mAllowAuth : 1; - bool mAllowKeywordFixup : 1; - bool mDisableMetaRefreshWhenInactive : 1; -diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl -index 763c7adb5ab9e3e56d6f1608899f6622997f272a..4f77795b5ce1f8fff79581987e017165dbdcbc1e 100644 ---- a/docshell/base/nsIDocShell.idl -+++ b/docshell/base/nsIDocShell.idl -@@ -44,6 +44,7 @@ interface nsIURI; - interface nsIChannel; - interface nsIPolicyContainer; - interface nsIDocumentViewer; -+interface nsIDOMGeoPosition; - interface nsIEditor; - interface nsIEditingSession; - interface nsIInputStream; -@@ -719,6 +720,45 @@ interface nsIDocShell : nsIDocShellTreeItem - */ - void synchronizeLayoutHistoryState(); - -+ attribute boolean fileInputInterceptionEnabled; -+ -+ attribute boolean overrideHasFocus; -+ -+ attribute boolean bypassCSPEnabled; -+ -+ attribute boolean forceActiveState; -+ -+ attribute boolean disallowBFCache; -+ -+ attribute AString languageOverride; -+ -+ boolean overrideTimezone(in AString timezoneId); -+ -+ 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; -+ -+ cenum ContrastOverride : 8 { -+ CONTRAST_OVERRIDE_LESS, -+ CONTRAST_OVERRIDE_MORE, -+ CONTRAST_OVERRIDE_CUSTOM, -+ CONTRAST_OVERRIDE_NO_PREFERENCE, -+ CONTRAST_OVERRIDE_NONE, /* This clears the override. */ -+ }; -+ [infallible] attribute nsIDocShell_ContrastOverride contrastOverride; -+ -+ 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 40da41ae4ac7d8d61c664e25bec8a74091d8b3e0..50ee1170e6d5b261334c7baccc63ed492b86ec38 100644 ---- a/dom/base/Document.cpp -+++ b/dom/base/Document.cpp -@@ -3799,6 +3799,9 @@ void Document::SendToConsole(nsCOMArray& aMessages) { - } - - void Document::ApplySettingsFromCSP(bool aSpeculative) { -+ if (mDocumentContainer && mDocumentContainer->IsBypassCSPEnabled()) -+ return; -+ - nsresult rv = NS_OK; - if (!aSpeculative) { - nsIContentSecurityPolicy* csp = PolicyContainer::GetCSP(mPolicyContainer); -@@ -3887,6 +3890,11 @@ nsresult Document::InitCSP(nsIChannel* aChannel) { - MOZ_ASSERT(mPolicyContainer, - "Policy container must be initialized before CSP!"); - -+ nsCOMPtr 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; -@@ -4753,6 +4761,10 @@ bool Document::HasFocus(ErrorResult& rv) const { - return false; - } - -+ if (IsActive() && mDocumentContainer->ShouldOverrideHasFocus()) { -+ return true; -+ } -+ - if (!fm->IsInActiveWindow(bc)) { - return false; - } -@@ -20326,6 +20338,35 @@ ColorScheme Document::PreferredColorScheme(IgnoreRFP aIgnoreRFP) const { - return PreferenceSheet::PrefsFor(*this).mColorScheme; - } - -+bool Document::PrefersReducedMotion() const { -+ auto* docShell = static_cast(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: -+ break; -+ } -+ } -+ -+ return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1; -+} -+ - bool Document::HasRecentlyStartedForegroundLoads() { - if (!sLoadingForegroundTopLevelContentDocument) { - return false; -diff --git a/dom/base/Document.h b/dom/base/Document.h -index 20f726a52f9f3591502597e20eeb8c07fe35feb2..c46f58ac88d536850169e6c51b9cfcb871d36e70 100644 ---- a/dom/base/Document.h -+++ b/dom/base/Document.h -@@ -4252,6 +4252,8 @@ class Document : public nsINode, - // color-scheme meta tag. - ColorScheme DefaultColorScheme() const; - -+ bool PrefersReducedMotion() const; -+ - static bool HasRecentlyStartedForegroundLoads(); - - static bool AutomaticStorageAccessPermissionCanBeGranted( -diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp -index 11a57adbb57b0adccf7ae491e7d7757f838bd9dc..e478244cedc2089fb99b3153d7493b7d36d72ea9 100644 ---- a/dom/base/Navigator.cpp -+++ b/dom/base/Navigator.cpp -@@ -347,14 +347,18 @@ void Navigator::GetAppName(nsAString& aAppName) const { - * for more detail. - */ - /* static */ --void Navigator::GetAcceptLanguages(nsTArray& aLanguages) { -+void Navigator::GetAcceptLanguages(const nsString* aLanguageOverride, nsTArray& 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 : -@@ -406,7 +410,13 @@ void Navigator::GetLanguage(nsAString& aLanguage) { - } - - void Navigator::GetLanguages(nsTArray& aLanguages) { -- GetAcceptLanguages(aLanguages); -+ if (mWindow && mWindow->GetDocShell()) { -+ nsString languageOverride; -+ mWindow->GetDocShell()->GetLanguageOverride(languageOverride); -+ GetAcceptLanguages(&languageOverride, aLanguages); -+ } else { -+ GetAcceptLanguages(nullptr, aLanguages); -+ } - - @@ -2336,6 +2336,7 @@ bool Navigator::Webdriver() { - } - #endif - -- return false; -+ // Playwright is automating the browser, so we should pretend to be a webdriver -+ return true; - } - - AutoplayPolicy Navigator::GetAutoplayPolicy(AutoplayPolicyMediaType aType) { -diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h -index 893947475fbb8688becb1c1495385e4048d4927d..dfb50acf689223fdab7ef6f42afbbd53341e1b0b 100644 ---- a/dom/base/Navigator.h -+++ b/dom/base/Navigator.h -@@ -228,7 +228,7 @@ class Navigator final : public nsISupports, public nsWrapperCache { - - StorageManager* Storage(); - -- static void GetAcceptLanguages(nsTArray& aLanguages); -+ static void GetAcceptLanguages(const nsString* aLanguageOverride, nsTArray& aLanguages); - - dom::MediaCapabilities* MediaCapabilities(); - dom::MediaSession* MediaSession(); -diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp -index 7703ab18c104848eab9377769641d3b60e9bcf8e..3028fc5a7e6c54a7f4455f135e889d038eed378d 100644 ---- a/dom/base/nsContentUtils.cpp -+++ b/dom/base/nsContentUtils.cpp -@@ -9528,11 +9528,13 @@ nsresult nsContentUtils::SendMouseEvent( - int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, - float aPressure, unsigned short aInputSourceArg, uint32_t aIdentifier, - bool aToWindow, bool* aPreventDefault, bool aIsDOMEventSynthesized, -- bool aIsWidgetEventSynthesized) { -+ bool aIsWidgetEventSynthesized, -+ bool convertToPointer, uint32_t aJugglerEventId) { - MOZ_ASSERT(aWidget); - EventMessage msg; - Maybe exitFrom; - bool contextMenuKey = false; -+ bool isPWDragEventMessage = false; - if (aType.EqualsLiteral("mousedown")) { - msg = eMouseDown; - } else if (aType.EqualsLiteral("mouseup")) { -@@ -9558,6 +9560,12 @@ nsresult nsContentUtils::SendMouseEvent( - msg = eMouseHitTest; - } else if (aType.EqualsLiteral("MozMouseExploreByTouch")) { - msg = eMouseExploreByTouch; -+ } else if (aType.EqualsLiteral("dragover")) { -+ msg = eDragOver; -+ isPWDragEventMessage = true; -+ } else if (aType.EqualsLiteral("drop")) { -+ msg = eDrop; -+ isPWDragEventMessage = true; - } else { - return NS_ERROR_FAILURE; - } -@@ -9568,7 +9576,14 @@ nsresult nsContentUtils::SendMouseEvent( - - Maybe pointerEvent; - Maybe mouseEvent; -- if (IsPointerEventMessage(msg)) { -+ Maybe pwDragEvent; -+ -+ if (isPWDragEventMessage) { -+ pwDragEvent.emplace(true, msg, aWidget); -+ pwDragEvent->mReason = aIsWidgetEventSynthesized -+ ? WidgetMouseEvent::eSynthesized -+ : WidgetMouseEvent::eReal; -+ } else if (IsPointerEventMessage(msg)) { - MOZ_ASSERT(!aIsWidgetEventSynthesized, - "The event shouldn't be dispatched as a synthesized event"); - if (MOZ_UNLIKELY(aIsWidgetEventSynthesized)) { -@@ -9587,8 +9602,11 @@ nsresult nsContentUtils::SendMouseEvent( - contextMenuKey ? WidgetMouseEvent::eContextMenuKey - : WidgetMouseEvent::eNormal); - } -+ - WidgetMouseEvent& mouseOrPointerEvent = -+ pwDragEvent.isSome() ? pwDragEvent.ref() : - pointerEvent.isSome() ? pointerEvent.ref() : mouseEvent.ref(); -+ - mouseOrPointerEvent.pointerId = aIdentifier; - mouseOrPointerEvent.mModifiers = GetWidgetModifiers(aModifiers); - mouseOrPointerEvent.mButton = aButton; -@@ -9601,6 +9619,8 @@ nsresult nsContentUtils::SendMouseEvent( - mouseOrPointerEvent.mClickCount = aClickCount; - mouseOrPointerEvent.mFlags.mIsSynthesizedForTests = aIsDOMEventSynthesized; - mouseOrPointerEvent.mExitFrom = exitFrom; -+ mouseOrPointerEvent.mJugglerEventId = aJugglerEventId; -+ mouseOrPointerEvent.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 a1b96bce18e1904f4068057defa26142ebe8874b..f2fc14da57cf08139723980dedc33f2d3a9a431b 100644 ---- a/dom/base/nsContentUtils.h -+++ b/dom/base/nsContentUtils.h -@@ -3080,8 +3080,9 @@ class nsContentUtils { - int32_t aButton, int32_t aButtons, int32_t aClickCount, - int32_t aModifiers, bool aIgnoreRootScrollFrame, float aPressure, - unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow, -- bool* aPreventDefault, bool aIsDOMEventSynthesized, -- bool aIsWidgetEventSynthesized); -+ bool* aPreventDefault, -+ bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized, -+ bool convertToPointer = true, uint32_t aJugglerEventId = 0); - - static void FirePageShowEventForFrameLoaderSwap( - nsIDocShellTreeItem* aItem, -diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp -index c6c5833cd29ef041da348d4398513bab7ef2f9aa..424cc396bfc211bc7debb3df203cfa26da7a4c55 100644 ---- a/dom/base/nsDOMWindowUtils.cpp -+++ b/dom/base/nsDOMWindowUtils.cpp -@@ -707,6 +707,26 @@ nsDOMWindowUtils::GetPresShellId(uint32_t* aPresShellId) { - return NS_ERROR_FAILURE; - } - -+static uint32_t sJugglerEventId = 1000; -+ -+NS_IMETHODIMP -+nsDOMWindowUtils::JugglerSendMouseEvent( -+ const nsAString& aType, float aX, float aY, int32_t aButton, -+ int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, -+ float aPressure, unsigned short aInputSourceArg, -+ bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized, -+ int32_t aButtons, uint32_t aIdentifier, bool aDisablePointerEvent, -+ uint32_t* aJugglerEventId) { -+ *aJugglerEventId = ++sJugglerEventId; -+ return SendMouseEventCommon( -+ aType, aX, aY, aButton, aClickCount, aModifiers, aIgnoreRootScrollFrame, -+ aPressure, aInputSourceArg, -+ aIdentifier, false, -+ nullptr, aIsDOMEventSynthesized, -+ aIsWidgetEventSynthesized, -+ aButtons, !aDisablePointerEvent, *aJugglerEventId); -+} -+ - NS_IMETHODIMP - nsDOMWindowUtils::SendMouseEvent( - const nsAString& aType, float aX, float aY, int32_t aButton, -@@ -721,7 +741,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, true, 0); - } - - NS_IMETHODIMP -@@ -739,7 +759,7 @@ nsDOMWindowUtils::SendMouseEventToWindow( - aOptionalArgCount >= 7 ? aIdentifier : DEFAULT_MOUSE_POINTER_ID, true, - nullptr, aOptionalArgCount >= 4 ? aIsDOMEventSynthesized : true, - aOptionalArgCount >= 5 ? aIsWidgetEventSynthesized : false, -- aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED); -+ aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED, 0); - } - - NS_IMETHODIMP -@@ -748,7 +768,7 @@ 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, uint32_t aJugglerEventId) { - RefPtr presShell = GetPresShell(); - if (!presShell) { - return NS_ERROR_FAILURE; -@@ -765,7 +785,7 @@ nsDOMWindowUtils::SendMouseEventCommon( - presShell, widget, aType, refPoint, aButton, aButtons, aClickCount, - aModifiers, aIgnoreRootScrollFrame, aPressure, aInputSourceArg, - aPointerId, aToWindow, aPreventDefault, aIsDOMEventSynthesized, -- aIsWidgetEventSynthesized); -+ aIsWidgetEventSynthesized, aConvertToPointer, aJugglerEventId); - } - - NS_IMETHODIMP -diff --git a/dom/base/nsDOMWindowUtils.h b/dom/base/nsDOMWindowUtils.h -index 4553ad5e7696055e861be5f840f8ce2bc54a5b29..1afc16325fcb63a3e510bdc387c8386eccf5d48b 100644 ---- a/dom/base/nsDOMWindowUtils.h -+++ b/dom/base/nsDOMWindowUtils.h -@@ -94,7 +94,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, uint32_t aJugglerEventId = 0); - - MOZ_CAN_RUN_SCRIPT - nsresult SendTouchEventCommon( -diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp -index 62c4bfb96dbb6e64aeadd9e45c296905b7956811..83f1e7303e2ebabfc73921d9bd27a255304a2ea4 100644 ---- a/dom/base/nsFocusManager.cpp -+++ b/dom/base/nsFocusManager.cpp -@@ -1717,6 +1717,10 @@ Maybe nsFocusManager::SetFocusInner(Element* aNewContent, - (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)) { -@@ -2303,6 +2307,7 @@ bool nsFocusManager::BlurImpl(BrowsingContext* aBrowsingContextToClear, - bool aIsLeavingDocument, bool aAdjustWidget, - bool aRemainActive, Element* aElementToFocus, - uint64_t aActionId) { -+ - LOGFOCUS(("<>", aActionId)); - - // hold a reference to the focused content, which may be null -@@ -2346,6 +2351,11 @@ bool nsFocusManager::BlurImpl(BrowsingContext* aBrowsingContextToClear, - return true; - } - -+ // Playwright: emulate focused page by never bluring when leaving document. -+ if (XRE_IsContentProcess() && aIsLeavingDocument && docShell && nsDocShell::Cast(docShell)->ShouldOverrideHasFocus()) { -+ return true; -+ } -+ - // Keep a ref to presShell since dispatching the DOM event may cause - // the document to be destroyed. - RefPtr presShell = docShell->GetPresShell(); -@@ -3046,7 +3056,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 5e2844f6e65da71ca9e1dadb1a88a74ab45f485c..a8f033e17ffbc28261072d561c89914d4bd2e325 100644 ---- a/dom/base/nsGlobalWindowOuter.cpp -+++ b/dom/base/nsGlobalWindowOuter.cpp -@@ -2511,10 +2511,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)); -+ } - } - } - -@@ -2634,6 +2640,19 @@ void nsGlobalWindowOuter::DispatchDOMWindowCreated() { - } - } - -+void nsGlobalWindowOuter::JugglerDispatchDOMWindowReused() { -+ nsCOMPtr observerService = -+ mozilla::services::GetObserverService(); -+ if (observerService && mDoc) { -+ nsIPrincipal* principal = mDoc->NodePrincipal(); -+ if (!principal->IsSystemPrincipal()) { -+ observerService->NotifyObservers(static_cast(this), -+ "juggler-dom-window-reused", -+ nullptr); -+ } -+ } -+} -+ - void nsGlobalWindowOuter::ClearStatus() { SetStatusOuter(u""_ns); } - - void nsGlobalWindowOuter::SetDocShell(nsDocShell* aDocShell) { -diff --git a/dom/base/nsGlobalWindowOuter.h b/dom/base/nsGlobalWindowOuter.h -index 1fbb506b07714f9ab2a2c9aff3683aa7fec4b156..42878f8f0c6365c7e2958a3b35fce0e7db9abfff 100644 ---- a/dom/base/nsGlobalWindowOuter.h -+++ b/dom/base/nsGlobalWindowOuter.h -@@ -318,6 +318,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 7b8da8b4a5e8de02d0d2e1befc8407da88fbf890..533f3bf77e1ef78dd231ac899e3d8032938ea812 100644 ---- a/dom/base/nsINode.cpp -+++ b/dom/base/nsINode.cpp -@@ -1500,6 +1500,61 @@ void nsINode::GetBoxQuadsFromWindowOrigin(const BoxQuadOptions& aOptions, - mozilla::GetBoxQuadsFromWindowOrigin(this, aOptions, aResult, aRv); - } - -+static nsIFrame* GetFirstFrame(nsINode* aNode) { -+ if (!aNode->IsContent()) -+ return nullptr; -+ nsIFrame* frame = aNode->AsContent()->GetPrimaryFrame(FlushType::Frames); -+ if (!frame) { -+ FlattenedChildIterator iter(aNode->AsContent()); -+ for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { -+ frame = child->GetPrimaryFrame(FlushType::Frames); -+ if (frame) { -+ break; -+ } -+ } -+ } -+ return frame; -+} -+ -+void nsINode::ScrollRectIntoViewIfNeeded(int32_t x, int32_t y, -+ int32_t w, int32_t h, -+ ErrorResult& aRv) { -+ aRv = NS_ERROR_UNEXPECTED; -+ nsCOMPtr 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"); -+ } -+ nsIFrame* primaryFrame = GetFirstFrame(this); -+ if (!primaryFrame) { -+ return aRv.ThrowNotFoundError("Node does not have a layout object"); -+ } -+ aRv = NS_OK; -+ 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->ScrollFrameIntoView( -+ primaryFrame, Some(rect), -+ ScrollAxis(WhereToScroll::Center, WhenToScroll::IfNotFullyVisible), -+ ScrollAxis(WhereToScroll::Center, WhenToScroll::IfNotFullyVisible), -+ 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 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 c3d84856e1bc92caf0437be312ccdbf7a2726ba5..d81c8e7152ca79b0fbb1ebee0f6f3aa40d0f34e2 100644 ---- a/dom/base/nsINode.h -+++ b/dom/base/nsINode.h -@@ -2421,6 +2421,10 @@ class nsINode : public mozilla::dom::EventTarget { - nsTArray>& aResult, - ErrorResult& aRv); - -+ void ScrollRectIntoViewIfNeeded(int32_t x, int32_t y, -+ int32_t w, int32_t h, -+ ErrorResult& aRv); -+ - already_AddRefed ConvertQuadFromNode( - DOMQuad& aQuad, const TextOrElementOrDocument& aFrom, - const ConvertCoordinateOptions& aOptions, CallerType aCallerType, -diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp -index aed59277e27a5a90f4244dd4513f9b4feb5858c3..26750fa09bead1ffabb22482468dea5999899f18 100644 ---- a/dom/base/nsJSUtils.cpp -+++ b/dom/base/nsJSUtils.cpp -@@ -151,6 +151,11 @@ bool nsJSUtils::GetEnvironmentChainForElement(JSContext* aCx, Element* aElement, - 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 f32e21752d5013bf143eb45391ab9218debab08e..83763d2354dade2f8d2b7930ba18ae91c55133ad 100644 ---- a/dom/base/nsJSUtils.h -+++ b/dom/base/nsJSUtils.h -@@ -75,6 +75,7 @@ class nsJSUtils { - mozilla::dom::Element* aElement, - JS::EnvironmentChain& aEnvChain); - -+ 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 6d150cc3ad77f694af5aa943c60eac37ba0733c0..9e68e18601cfb3e9e9c03b4bf0057c1a3d50a9d5 100644 ---- a/dom/chrome-webidl/BrowsingContext.webidl -+++ b/dom/chrome-webidl/BrowsingContext.webidl -@@ -62,6 +62,26 @@ enum ForcedColorsOverride { - "active", - }; - -+/** -+ * CSS prefers-reduced-motion values. -+ */ -+enum PrefersReducedMotionOverride { -+ "none", -+ "reduce", -+ "no-preference", -+}; -+ -+/** -+ * CSS prefers-contrast values. -+ */ -+enum PrefersContrastOverride { -+ "none", -+ "no-preference", -+ "more", -+ "less", -+ "custom", -+}; -+ - /** - * Allowed overrides of platform/pref default behaviour for touch events. - */ -@@ -228,6 +248,12 @@ interface BrowsingContext { - // Forced-colors simulation, for DevTools - [SetterThrows] attribute ForcedColorsOverride forcedColorsOverride; - -+ // Reduced-Motion simulation, for DevTools. -+ [SetterThrows] attribute PrefersReducedMotionOverride prefersReducedMotionOverride; -+ -+ // Contrast simulation, for DevTools. -+ [SetterThrows] attribute PrefersContrastOverride prefersContrastOverride; -+ - /** - * 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/fetch/Fetch.cpp b/dom/fetch/Fetch.cpp -index 52cf33bfc863d5ef1d3ac889ddfba3023600d60a..ccb521f367b8ccc8c40d8bad78aa621ab1b074c0 100644 ---- a/dom/fetch/Fetch.cpp -+++ b/dom/fetch/Fetch.cpp -@@ -704,6 +704,12 @@ already_AddRefed FetchRequest(nsIGlobalObject* aGlobal, - ipcArgs.hasCSPEventListener() = false; - ipcArgs.isWorkerRequest() = false; - -+ /* --> Playwright: associate keep-alive fetch with the window */ -+ BrowsingContext* bc = window ? window->GetBrowsingContext() : nullptr; -+ if (bc) -+ ipcArgs.associatedBrowsingContextID() = bc->Id(); -+ /* <-- Playwright */ -+ - actor->DoFetchOp(ipcArgs); - - mozilla::glean::networking::fetch_keepalive_request_count.Get("main"_ns) -diff --git a/dom/fetch/FetchService.cpp b/dom/fetch/FetchService.cpp -index 1734429e8eeb155b742211ca58afcbeb73a8bf7c..15635a2e5c266f8085093a0d17288abe8ed54d9e 100644 ---- a/dom/fetch/FetchService.cpp -+++ b/dom/fetch/FetchService.cpp -@@ -268,6 +268,14 @@ RefPtr FetchService::FetchInstance::Fetch() { - net::ClassificationFlags({0, 0}) // TrackingFlags - ); - -+ /* --> Playwright: associate keep-alive fetch with the window */ -+ if (mArgsType == FetchArgsType::MainThreadFetch) { -+ auto& args = mArgs.as(); -+ mFetchDriver->SetAssociatedBrowsingContextID( -+ args.mAssociatedBrowsingContextID); -+ } -+ /* <-- Playwright */ -+ - if (mArgsType == FetchArgsType::WorkerFetch) { - auto& args = mArgs.as(); - mFetchDriver->SetWorkerScript(args.mWorkerScript); -diff --git a/dom/geolocation/Geolocation.cpp b/dom/geolocation/Geolocation.cpp -index 70ce9ce97c6d0ccba8b4129c55079cf9122e5b17..1c503c68c2c0949cfdaa18a76a263a81807952e1 100644 ---- a/dom/geolocation/Geolocation.cpp -+++ b/dom/geolocation/Geolocation.cpp -@@ -394,7 +394,10 @@ nsGeolocationRequest::Allow(JS::Handle aChoices) { - return NS_OK; - } - -- if (mBehavior != SystemGeolocationPermissionBehavior::NoPrompt) { -+ RefPtr gs = nsGeolocationService::GetGeolocationService( -+ mLocator->GetBrowsingContext()); -+ -+ if (mBehavior != SystemGeolocationPermissionBehavior::NoPrompt && !gs->IsOverride()) { - // Asynchronously present the system dialog or open system preferences - // (RequestGeolocationPermissionFromUser will know which to do), and wait - // for the permission to change or the request to be canceled. If the -@@ -426,8 +429,6 @@ nsGeolocationRequest::Allow(JS::Handle aChoices) { - return NS_OK; - } - -- RefPtr gs = nsGeolocationService::GetGeolocationService( -- mLocator->GetBrowsingContext()); - bool canUseCache = false; - CachedPositionAndAccuracy lastPosition = gs->GetCachedPosition(); - if (lastPosition.position) { -@@ -710,11 +711,16 @@ NS_INTERFACE_MAP_END - NS_IMPL_ADDREF(nsGeolocationService) - NS_IMPL_RELEASE(nsGeolocationService) - --nsresult nsGeolocationService::Init() { -+nsresult nsGeolocationService::Init(bool isOverride) { - if (!StaticPrefs::geo_enabled()) { - return NS_ERROR_FAILURE; - } - -+ if (isOverride) { -+ mIsOverride = true; -+ mHigherAccuracy = true; -+ } -+ - if (XRE_IsContentProcess()) { - return NS_OK; - } -@@ -793,6 +799,10 @@ nsresult nsGeolocationService::Init() { - return NS_OK; - } - -+bool nsGeolocationService::IsOverride() { -+ return mIsOverride; -+} -+ - nsGeolocationService::~nsGeolocationService() = default; - - NS_IMETHODIMP -@@ -936,6 +946,10 @@ bool nsGeolocationService::HighAccuracyRequested() { - } - - void nsGeolocationService::UpdateAccuracy(bool aForceHigh) { -+ if (mIsOverride) { -+ return; -+ } -+ - bool highRequired = aForceHigh || HighAccuracyRequested(); - - if (XRE_IsContentProcess()) { -diff --git a/dom/geolocation/Geolocation.h b/dom/geolocation/Geolocation.h -index 57814242d551774e81403b7fdc20c795deadb625..c48c1b19a8d5499784ffb7b50d5e88e40c7b2a05 100644 ---- a/dom/geolocation/Geolocation.h -+++ b/dom/geolocation/Geolocation.h -@@ -67,7 +67,7 @@ class nsGeolocationService final : public nsIGeolocationUpdate, - - nsGeolocationService() = default; - -- nsresult Init(); -+ nsresult Init(bool isOverride = false); - - // Management of the Geolocation objects - void AddLocator(mozilla::dom::Geolocation* aLocator); -@@ -92,6 +92,8 @@ class nsGeolocationService final : public nsIGeolocationUpdate, - void UpdateAccuracy(bool aForceHigh = false); - bool HighAccuracyRequested(); - -+ bool IsOverride(); -+ - private: - ~nsGeolocationService(); - -@@ -118,6 +120,8 @@ class nsGeolocationService final : public nsIGeolocationUpdate, - // Nothing() if not being started, or a boolean reflecting the requested - // accuracy. - mozilla::Maybe mStarting; -+ -+ bool mIsOverride = false; - }; - - namespace mozilla::dom { -diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp -index 5b0228d4a61dfe2b95e7a3ce016217007e8dee12..b753b0fceeec3278cb026d9137aafab5fb6ef968 100644 ---- a/dom/html/HTMLInputElement.cpp -+++ b/dom/html/HTMLInputElement.cpp -@@ -45,6 +45,7 @@ - #include "mozilla/dom/GetFilesHelper.h" - #include "mozilla/dom/HTMLDataListElement.h" - #include "mozilla/dom/HTMLOptionElement.h" -+#include "nsDocShell.h" - #include "mozilla/dom/InputType.h" - #include "mozilla/dom/MouseEvent.h" - #include "mozilla/dom/MutationEventBinding.h" -@@ -842,6 +843,13 @@ nsresult HTMLInputElement::InitFilePicker(FilePickerType aType) { - return NS_ERROR_FAILURE; - } - -+ nsCOMPtr win = doc->GetWindow(); -+ nsDocShell* docShell = win ? static_cast(win->GetDocShell()) : nullptr; -+ if (docShell && docShell->IsFileInputInterceptionEnabled()) { -+ docShell->FilePickerShown(this); -+ return NS_OK; -+ } -+ - if (IsPickerBlocked(doc)) { - return NS_OK; - } -diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl -index 64a2dad65911395ea7eb8ded3374ae6bdd31cf3c..e333c802f8a9232e58d963e05187c0a1b30948f5 100644 ---- a/dom/interfaces/base/nsIDOMWindowUtils.idl -+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl -@@ -390,6 +390,26 @@ cenum AsyncEnabledOption : 8 { - ASYNC_ENABLED = 1 - }; - -+ /** -+ * Playwright: a separate method to dispatch mouse event with a -+ * specific `jugglerEventId`. -+ */ -+ [can_run_script] -+ unsigned long jugglerSendMouseEvent(in AString aType, -+ in float aX, -+ in float aY, -+ in long aButton, -+ in long aClickCount, -+ in long aModifiers, -+ in boolean aIgnoreRootScrollFrame, -+ in float aPressure, -+ in unsigned short aInputSourceArg, -+ in boolean aIsDOMEventSynthesized, -+ in boolean aIsWidgetEventSynthesized, -+ in long aButtons, -+ in unsigned long aIdentifier, -+ in boolean aDisablePointerEvent); -+ - /** Synthesize a touch event. The event types supported are: - * touchstart, touchend, touchmove, and touchcancel - * -diff --git a/dom/ipc/BrowserChild.cpp b/dom/ipc/BrowserChild.cpp -index 780550d573644bcfe4a9bc03243aa4559a62d979..9ed69194ef329aad1e8a3e2c06041a443e4bc6ba 100644 ---- a/dom/ipc/BrowserChild.cpp -+++ b/dom/ipc/BrowserChild.cpp -@@ -1744,6 +1744,21 @@ void BrowserChild::HandleRealMouseButtonEvent(const WidgetMouseEvent& aEvent, - if (postLayerization) { - postLayerization->Register(); - } -+ -+ // Playwright: notify content that mouse event has been received and handled. -+ nsCOMPtr observerService = -+ mozilla::services::GetObserverService(); -+ if (observerService && aEvent.mJugglerEventId) { -+ if (aEvent.mMessage == eMouseUp) { -+ observerService->NotifyObservers(nullptr, "juggler-mouse-event-hit-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("mouseup %" PRIu32, aEvent.mJugglerEventId)).get()); -+ } else if (aEvent.mMessage == eMouseDown) { -+ observerService->NotifyObservers(nullptr, "juggler-mouse-event-hit-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("mousedown %" PRIu32, aEvent.mJugglerEventId)).get()); -+ } else if (aEvent.mMessage == eMouseMove) { -+ observerService->NotifyObservers(nullptr, "juggler-mouse-event-hit-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("mousemove %" PRIu32, aEvent.mJugglerEventId)).get()); -+ } else if (aEvent.mMessage == eContextMenu) { -+ observerService->NotifyObservers(nullptr, "juggler-mouse-event-hit-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("contextmenu %" PRIu32, aEvent.mJugglerEventId)).get()); -+ } -+ } - } - - mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealMouseButtonEvent( -diff --git a/dom/ipc/CoalescedMouseData.cpp b/dom/ipc/CoalescedMouseData.cpp -index 83aa0d08839f6fa5a150e5791b9b717e5aa9e751..fc1e1140ac7c6cda8cf116027c2fc2898dbe9d4b 100644 ---- a/dom/ipc/CoalescedMouseData.cpp -+++ b/dom/ipc/CoalescedMouseData.cpp -@@ -72,6 +72,9 @@ bool CoalescedMouseData::CanCoalesce(const WidgetMouseEvent& aEvent, - mCoalescedInputEvent->pointerId != aEvent.pointerId || - mCoalescedInputEvent->mButton != aEvent.mButton || - mCoalescedInputEvent->mButtons != aEvent.mButtons || mGuid != aGuid || -+ // `mJugglerEventId` is 0 for non-juggler events and a unique number for -+ // juggler-emitted events. -+ mCoalescedInputEvent->mJugglerEventId != aEvent.mJugglerEventId || - mInputBlockId != aInputBlockId) { - return false; - } -diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.cc b/dom/media/systemservices/video_engine/desktop_capture_impl.cc -index db777994b583efc2a3533e7d4534fff894c733bb..eb317c19b2422bd983d5e132c9ee4dac31687428 100644 ---- a/dom/media/systemservices/video_engine/desktop_capture_impl.cc -+++ b/dom/media/systemservices/video_engine/desktop_capture_impl.cc -@@ -53,9 +53,10 @@ namespace webrtc { - - DesktopCaptureImpl* DesktopCaptureImpl::Create(const int32_t aModuleId, - const char* aUniqueId, -- const CaptureDeviceType aType) { -+ const CaptureDeviceType aType, -+ bool aCaptureCursor) { - return new rtc::RefCountedObject(aModuleId, aUniqueId, -- aType); -+ aType, aCaptureCursor); - } - - static DesktopCaptureOptions CreateDesktopCaptureOptions() { -@@ -156,8 +157,10 @@ static std::unique_ptr CreateTabCapturer( - - static std::unique_ptr CreateDesktopCapturerAndThread( - CaptureDeviceType aDeviceType, DesktopCapturer::SourceId aSourceId, -- nsIThread** aOutThread) { -+ nsIThread** aOutThread, bool aCaptureCursor) { - DesktopCaptureOptions options = CreateDesktopCaptureOptions(); -+ if (aCaptureCursor) -+ options.set_prefer_cursor_embedded(aCaptureCursor); - auto ensureThread = [&]() { - if (*aOutThread) { - return *aOutThread; -@@ -254,7 +257,8 @@ static std::unique_ptr CreateDesktopCapturerAndThread( - } - - DesktopCaptureImpl::DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, -- const CaptureDeviceType aType) -+ const CaptureDeviceType aType, -+ bool aCaptureCursor) - : mModuleId(aId), - mTrackingId(mozilla::TrackingId(CaptureEngineToTrackingSourceStr([&] { - switch (aType) { -@@ -271,6 +275,7 @@ DesktopCaptureImpl::DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, - aId)), - mDeviceUniqueId(aUniqueId), - mDeviceType(aType), -+ capture_cursor_(aCaptureCursor), - mControlThread(mozilla::GetCurrentSerialEventTarget()), - mNextFrameMinimumTime(Timestamp::Zero()), - mCallbacks("DesktopCaptureImpl::mCallbacks") {} -@@ -295,6 +300,19 @@ void DesktopCaptureImpl::DeRegisterCaptureDataCallback( - } - } - -+void DesktopCaptureImpl::RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) { -+ rtc::CritScope lock(&mApiCs); -+ _rawFrameCallbacks.insert(rawFrameCallback); -+} -+ -+void DesktopCaptureImpl::DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) { -+ rtc::CritScope lock(&mApiCs); -+ auto it = _rawFrameCallbacks.find(rawFrameCallback); -+ if (it != _rawFrameCallbacks.end()) { -+ _rawFrameCallbacks.erase(it); -+ } -+} -+ - int32_t DesktopCaptureImpl::StopCaptureIfAllClientsClose() { - { - auto callbacks = mCallbacks.Lock(); -@@ -350,7 +368,7 @@ int32_t DesktopCaptureImpl::StartCapture( - return -1; - } - std::unique_ptr capturer = CreateDesktopCapturerAndThread( -- mDeviceType, sourceId, getter_AddRefs(mCaptureThread)); -+ mDeviceType, sourceId, getter_AddRefs(mCaptureThread), capture_cursor_); - - MOZ_ASSERT(!capturer == !mCaptureThread); - if (!capturer) { -@@ -458,6 +476,15 @@ void DesktopCaptureImpl::OnCaptureResult(DesktopCapturer::Result aResult, - frameInfo.height = aFrame->size().height(); - frameInfo.videoType = VideoType::kARGB; - -+ size_t videoFrameStride = -+ frameInfo.width * DesktopFrame::kBytesPerPixel; -+ { -+ rtc::CritScope cs(&mApiCs); -+ for (auto rawFrameCallback : _rawFrameCallbacks) { -+ rawFrameCallback->OnRawFrame(videoFrame, videoFrameStride, frameInfo); -+ } -+ } -+ - size_t videoFrameLength = - frameInfo.width * frameInfo.height * DesktopFrame::kBytesPerPixel; - -diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.h b/dom/media/systemservices/video_engine/desktop_capture_impl.h -index a76b7de569db1cb42728a5514fb80e5c46e0344e..3d61ad8d3aa4a7eaf96957dcd680e1e1ee8abdf4 100644 ---- a/dom/media/systemservices/video_engine/desktop_capture_impl.h -+++ b/dom/media/systemservices/video_engine/desktop_capture_impl.h -@@ -26,6 +26,7 @@ - #include "api/video/video_sink_interface.h" - #include "modules/desktop_capture/desktop_capturer.h" - #include "modules/video_capture/video_capture.h" -+#include "rtc_base/deprecated/recursive_critical_section.h" - #include "mozilla/DataMutex.h" - #include "mozilla/Maybe.h" - #include "mozilla/TimeStamp.h" -@@ -42,17 +43,44 @@ 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; -+ int32_t StartCaptureCounted(const VideoCaptureCapability& aCapability) { -+ ++capture_counter_; -+ return capture_counter_ == 1 ? StartCapture(aCapability) : 0; -+ } -+ -+ int32_t StopCaptureCounted() { -+ --capture_counter_; -+ return capture_counter_ == 0 ? StopCapture() : 0; -+ } -+ -+ private: -+ int32_t capture_counter_ = 0; -+}; -+ - // Reuses the video engine pipeline for screen sharing. - // 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 DesktopCaptureImpl* Create( - const int32_t aModuleId, const char* aUniqueId, -- const mozilla::camera::CaptureDeviceType aType); -+ const mozilla::camera::CaptureDeviceType aType, bool aCaptureCursor = true); - - [[nodiscard]] static std::shared_ptr - CreateDeviceInfo(const int32_t aId, -@@ -66,6 +94,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - void DeRegisterCaptureDataCallback( - rtc::VideoSinkInterface* aCallback) override; - int32_t StopCaptureIfAllClientsClose() override; -+ void RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) override; -+ void DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) override; - - int32_t SetCaptureRotation(VideoRotation aRotation) override; - bool SetApplyRotation(bool aEnable) override; -@@ -89,7 +119,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - - protected: - DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, -- const mozilla::camera::CaptureDeviceType aType); -+ const mozilla::camera::CaptureDeviceType aType, -+ bool aCaptureCusor); - virtual ~DesktopCaptureImpl(); - - private: -@@ -98,6 +129,9 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - void InitOnThread(std::unique_ptr aCapturer, int aFramerate); - void UpdateOnThread(int aFramerate); - void ShutdownOnThread(); -+ -+ rtc::RecursiveCriticalSection mApiCs; -+ std::set _rawFrameCallbacks; - // DesktopCapturer::Callback interface. - void OnCaptureResult(DesktopCapturer::Result aResult, - std::unique_ptr aFrame) override; -@@ -105,6 +139,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - // Notifies all mCallbacks of OnFrame(). mCaptureThread only. - void NotifyOnFrame(const VideoFrame& aFrame); - -+ bool capture_cursor_ = true; -+ - // Control thread on which the public API is called. - const nsCOMPtr mControlThread; - // Set in StartCapture. -diff --git a/dom/script/ScriptSettings.cpp b/dom/script/ScriptSettings.cpp -index d5964b27e9c99af76fe3f4076322592a9370c2d0..da217e2c1fbd9ca02e50ff74dde028189a216a6d 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 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 8b68f22ae64d19165bf4b3c58aea8f5c237ba351..c3733bfa4ed550c98ab5f72c406cd6d01a621aca 100644 ---- a/dom/security/nsCSPUtils.cpp -+++ b/dom/security/nsCSPUtils.cpp -@@ -24,6 +24,7 @@ - #include "nsSandboxFlags.h" - #include "nsServiceManagerUtils.h" - #include "nsWhitespaceTokenizer.h" -+#include "nsDocShell.h" - - #include "mozilla/Assertions.h" - #include "mozilla/Components.h" -@@ -136,6 +137,11 @@ void CSP_ApplyMetaCSPToDoc(mozilla::dom::Document& aDoc, - return; - } - -+ if (aDoc.GetDocShell() && -+ nsDocShell::Cast(aDoc.GetDocShell())->IsBypassCSPEnabled()) { -+ return; -+ } -+ - nsAutoString policyStr( - nsContentUtils::TrimWhitespace( - aPolicyStr)); -diff --git a/dom/webidl/GeometryUtils.webidl b/dom/webidl/GeometryUtils.webidl -index aee376e971ae01ac1e512c3920b115bfaf06afa8..1701311534bf77e6cd9bafc0e3a283610476aa8f 100644 ---- a/dom/webidl/GeometryUtils.webidl -+++ b/dom/webidl/GeometryUtils.webidl -@@ -17,6 +17,8 @@ dictionary GeometryUtilsOptions { - boolean createFramesForSuppressedWhitespace = true; - [ChromeOnly] - boolean flush = true; -+ [ChromeOnly] -+ boolean recurseWhenNoFrame = false; - }; - - dictionary BoxQuadOptions : GeometryUtilsOptions { -@@ -35,6 +37,9 @@ interface mixin GeometryUtils { - [Throws, Func="nsINode::HasBoxQuadsSupport", NeedsCallerType] - sequence getBoxQuads(optional BoxQuadOptions options = {}); - -+ [ChromeOnly, Throws, Func="nsINode::HasBoxQuadsSupport"] -+ undefined 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 83cef5b52b8f5c3168cd1d59266b4149425647fd..a80e89ec26a7e049c8ed84687ba2cd49597be05f 100644 ---- a/dom/workers/RuntimeService.cpp -+++ b/dom/workers/RuntimeService.cpp -@@ -1082,7 +1082,7 @@ void PrefLanguagesChanged(const char* /* aPrefName */, void* /* aClosure */) { - AssertIsOnMainThread(); - - nsTArray languages; -- Navigator::GetAcceptLanguages(languages); -+ Navigator::GetAcceptLanguages(nullptr, languages); - - RuntimeService* runtime = RuntimeService::GetService(); - if (runtime) { -@@ -1272,8 +1272,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; - } - -@@ -1901,6 +1900,13 @@ void RuntimeService::PropagateStorageAccessPermissionGranted( - } - } - -+void RuntimeService::ResetDefaultLocaleInAllWorkers() { -+ AssertIsOnMainThread(); -+ BroadcastAllWorkers([](auto& worker) { -+ worker.ResetDefaultLocale(); -+ }); -+} -+ - template - void RuntimeService::BroadcastAllWorkers(const Func& aFunc) { - AssertIsOnMainThread(); -@@ -2451,6 +2457,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 6d75c6708bcb999dc1dc3b0172afa14136110bc6..809d0ef80ffe793beff5d3c11bf6bf7912385e99 100644 ---- a/dom/workers/RuntimeService.h -+++ b/dom/workers/RuntimeService.h -@@ -115,6 +115,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 af8d36c0d72683712a3fee22661f8c3279e103db..6b3a967c9acde2c81ab38148d4b1ac120a4717a2 100644 ---- a/dom/workers/WorkerCommon.h -+++ b/dom/workers/WorkerCommon.h -@@ -50,6 +50,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 06083bb8f9546be06fa0b5c78d4e005a1617e51b..1753896265c1701ad50425c565f8d44392d0afb9 100644 ---- a/dom/workers/WorkerPrivate.cpp -+++ b/dom/workers/WorkerPrivate.cpp -@@ -738,6 +738,18 @@ class UpdateContextOptionsRunnable final : public WorkerControlRunnable { - } - }; - -+class ResetDefaultLocaleRunnable final : public WorkerControlRunnable { -+ public: -+ explicit ResetDefaultLocaleRunnable(WorkerPrivate* aWorkerPrivate) -+ : WorkerControlRunnable("ResetDefaultLocaleRunnable") {} -+ -+ virtual bool WorkerRun(JSContext* aCx, -+ WorkerPrivate* aWorkerPrivate) override { -+ aWorkerPrivate->ResetDefaultLocaleInternal(aCx); -+ return true; -+ } -+}; -+ - class UpdateLanguagesRunnable final : public WorkerThreadRunnable { - nsTArray mLanguages; - -@@ -2334,6 +2346,16 @@ void WorkerPrivate::UpdateContextOptions( - } - } - -+void WorkerPrivate::ResetDefaultLocale() { -+ AssertIsOnParentThread(); -+ -+ RefPtr runnable = -+ new ResetDefaultLocaleRunnable(this); -+ if (!runnable->Dispatch(this)) { -+ NS_WARNING("Failed to reset default locale in worker!"); -+ } -+} -+ - void WorkerPrivate::UpdateLanguages(const nsTArray& aLanguages) { - AssertIsOnParentThread(); - -@@ -5996,6 +6018,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& aLanguages) { - WorkerGlobalScope* globalScope = GlobalScope(); -diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h -index 15c819c84fa934e25517ac8f55fd39ef8ba46986..fe01e09abcf2315abe41a3d19418c4e0f8c7df2b 100644 ---- a/dom/workers/WorkerPrivate.h -+++ b/dom/workers/WorkerPrivate.h -@@ -457,6 +457,8 @@ class WorkerPrivate final - void UpdateContextOptionsInternal(JSContext* aCx, - const JS::ContextOptions& aContextOptions); - -+ void ResetDefaultLocaleInternal(JSContext* aCx); -+ - void UpdateLanguagesInternal(const nsTArray& aLanguages); - - void UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key, -@@ -1103,6 +1105,8 @@ class WorkerPrivate final - - void UpdateContextOptions(const JS::ContextOptions& aContextOptions); - -+ void ResetDefaultLocale(); -+ - void UpdateLanguages(const nsTArray& aLanguages); - - void UpdateJSWorkerMemoryParameter(JSGCParamKey key, Maybe value); -diff --git a/intl/components/src/TimeZone.cpp b/intl/components/src/TimeZone.cpp -index 7a069ef0c59895cf1f8dc35d612f1494c9c9f1ef..5b09dfdcc5323def65c35b0696141b44eef9dcda 100644 ---- a/intl/components/src/TimeZone.cpp -+++ b/intl/components/src/TimeZone.cpp -@@ -16,6 +16,7 @@ - - namespace mozilla::intl { - -+ - /* static */ - Result, ICUError> TimeZone::TryCreate( - Maybe> aTimeZoneOverride) { -@@ -318,6 +319,13 @@ static ICUResult SetDefaultTimeZone(TimeZoneIdentifierVector& timeZone) { - } - #endif - -+bool TimeZone::IsValidTimeZoneId(const char* timeZoneId) { -+ // Validate timezone id. -+ mozilla::UniquePtr timeZone(icu::TimeZone::createTimeZone( -+ icu::UnicodeString(timeZoneId, -1, US_INV))); -+ return timeZone && *timeZone != icu::TimeZone::getUnknown(); -+} -+ - Result TimeZone::SetDefaultTimeZone( - Span aTimeZone) { - #if MOZ_INTL_USE_ICU_CPP_TIMEZONE -diff --git a/intl/components/src/TimeZone.h b/intl/components/src/TimeZone.h -index 89770839ae108b5f3462a7f20684fdb72c4ab2fb..a7e40d6b7c33c234b41e586eac573ba4ce3a7d18 100644 ---- a/intl/components/src/TimeZone.h -+++ b/intl/components/src/TimeZone.h -@@ -191,6 +191,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 523e84c8c93f4221701f90f2e8ee146ec8e1adbd..98d5b1176e5378431b859a2dbd4d4e778d236e78 100644 ---- a/js/public/Date.h -+++ b/js/public/Date.h -@@ -55,6 +55,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 2d177b5aade6d158e9ae62d317d5155b72cdcf84..28af5d41eb06d4b33cd5f86484dc29c923308835 100644 ---- a/js/src/debugger/Object.cpp -+++ b/js/src/debugger/Object.cpp -@@ -2516,7 +2516,11 @@ Maybe 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 cc366b4cc411ed8de972811237563edb376355e3..adf727cf80fadebce3be9301752dc1d0b9ee35b9 100644 ---- a/js/src/vm/DateTime.cpp -+++ b/js/src/vm/DateTime.cpp -@@ -188,6 +188,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); - -@@ -556,10 +561,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) { -@@ -773,6 +792,15 @@ static bool ReadTimeZoneLink(std::string_view tz, - - void js::DateTimeInfo::internalResyncICUDefaultTimeZone() { - #if JS_HAS_INTL_API -+ if (!timeZoneOverride_.empty()) { -+ mozilla::Span 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; -+ } -+ - // In the future we should not be setting a default ICU time zone at all, - // instead all accesses should go through the appropriate DateTimeInfo - // instance depending on the resist fingerprinting status. For now we return -@@ -784,7 +812,6 @@ void js::DateTimeInfo::internalResyncICUDefaultTimeZone() { - - if (const char* tzenv = std::getenv("TZ")) { - std::string_view tz(tzenv); -- - mozilla::Span tzid; - - # if defined(XP_WIN) -diff --git a/js/src/vm/DateTime.h b/js/src/vm/DateTime.h -index 7be5b49afdce8e761af05dfbd48f3cb22e9ce318..3899c7988959f11bbadd0c005462acb979823fd1 100644 ---- a/js/src/vm/DateTime.h -+++ b/js/src/vm/DateTime.h -@@ -75,6 +75,8 @@ using TimeZoneIdentifierVector = - SystemAllocPolicy>; - #endif - -+extern void SetTimeZoneOverrideInternal(std::string timeZone); -+ - /** - * Stores date/time information, particularly concerning the current local - * time zone, and implements a small cache for daylight saving time offset -@@ -258,6 +260,7 @@ class DateTimeInfo { - private: - // The method below should only be called via js::ResetTimeZoneInternal(). - friend void js::ResetTimeZoneInternal(ResetTimeZoneMode); -+ friend void js::SetTimeZoneOverrideInternal(std::string); - - static void resetTimeZone(ResetTimeZoneMode mode) { - { -@@ -362,6 +365,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 -@@ -377,6 +382,8 @@ class DateTimeInfo { - - void internalResetTimeZone(ResetTimeZoneMode mode); - -+ void internalSetTimeZoneOverride(std::string timeZone); -+ - void updateTimeZone(); - - void internalResyncICUDefaultTimeZone(); -diff --git a/layout/base/GeometryUtils.cpp b/layout/base/GeometryUtils.cpp -index 67673c5c306e7237613b0560c7b3f888bd6ad1b8..fe4a278dad4b1747b41b5a824978636a70a9dea8 100644 ---- a/layout/base/GeometryUtils.cpp -+++ b/layout/base/GeometryUtils.cpp -@@ -23,6 +23,7 @@ - #include "nsContentUtils.h" - #include "nsIFrame.h" - #include "nsLayoutUtils.h" -+#include "ChildIterator.h" - - using namespace mozilla; - using namespace mozilla::dom; -@@ -265,10 +266,27 @@ static bool CheckFramesInSameTopLevelBrowsingContext(nsIFrame* aFrame1, - return false; - } - -+static nsIFrame* GetFrameForNodeRecursive(nsINode* aNode, -+ const GeometryUtilsOptions& aOptions, -+ bool aRecurseWhenNoFrame) { -+ nsIFrame* frame = GetFrameForNode(aNode, aOptions); -+ if (!frame && aRecurseWhenNoFrame && aNode->IsContent()) { -+ dom::FlattenedChildIterator iter(aNode->AsContent()); -+ for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { -+ frame = GetFrameForNodeRecursive(child, aOptions, aRecurseWhenNoFrame); -+ if (frame) { -+ break; -+ } -+ } -+ } -+ return frame; -+} -+ - void GetBoxQuads(nsINode* aNode, const dom::BoxQuadOptions& aOptions, - nsTArray>& aResult, CallerType aCallerType, - ErrorResult& aRv) { -- nsIFrame* frame = GetFrameForNode(aNode, aOptions); -+ nsIFrame* frame = -+ GetFrameForNodeRecursive(aNode, aOptions, aOptions.mRecurseWhenNoFrame); - if (!frame) { - // No boxes to return - return; -@@ -281,7 +299,8 @@ void GetBoxQuads(nsINode* aNode, const dom::BoxQuadOptions& aOptions, - // EnsureFrameForTextNode call. We need to get the first frame again - // when that happens and re-check it. - if (!weakFrame.IsAlive()) { -- frame = GetFrameForNode(aNode, aOptions); -+ frame = -+ GetFrameForNodeRecursive(aNode, aOptions, aOptions.mRecurseWhenNoFrame); - if (!frame) { - // No boxes to return - return; -diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp -index 26119628ab4839858733ce39c6c9ef2970092b49..a9c4dbc4936755fd25b8528511e9a4c62695de89 100644 ---- a/layout/base/PresShell.cpp -+++ b/layout/base/PresShell.cpp -@@ -12150,7 +12150,9 @@ bool PresShell::ComputeActiveness() const { - if (!browserChild->IsVisible()) { - MOZ_LOG(gLog, LogLevel::Debug, - (" > BrowserChild %p is not visible", browserChild)); -- return false; -+ bool isActive; -+ root->GetDocShell()->GetForceActiveState(&isActive); -+ return isActive; - } - - // If the browser is visible but just due to be preserving layers -diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp -index ee4e4b7e04f0f949b0afc7e8097711fcefe8b3c3..3af1d380d514b70392d1daaa4bc623afd7a570e6 100644 ---- a/layout/base/nsLayoutUtils.cpp -+++ b/layout/base/nsLayoutUtils.cpp -@@ -707,6 +707,10 @@ bool nsLayoutUtils::AllowZoomingForDocument( - !aDocument->GetPresShell()->AsyncPanZoomEnabled()) { - return false; - } -+ -+ /* Playwright: disable zooming as we don't support meta viewport tag */ -+ if (1 == 1) return false; -+ - // True if we allow zooming for all documents on this platform, or if we are - // in RDM. - BrowsingContext* bc = aDocument->GetBrowsingContext(); -@@ -9772,6 +9776,9 @@ void nsLayoutUtils::ComputeSystemFont(nsFont* aSystemFont, - - /* static */ - bool nsLayoutUtils::ShouldHandleMetaViewport(const Document* aDocument) { -+ /* Playwright: disable meta viewport handling since we don't require one */ -+ if (1 == 1) return false; -+ - BrowsingContext* bc = aDocument->GetBrowsingContext(); - return StaticPrefs::dom_meta_viewport_enabled() || (bc && bc->InRDMPane()); - } -diff --git a/layout/style/GeckoBindings.h b/layout/style/GeckoBindings.h -index 9527443c79077e0a728d78c3184ab7319f1c9efd..4e193ed114b4f70fb72bea928709fc7723f35b88 100644 ---- a/layout/style/GeckoBindings.h -+++ b/layout/style/GeckoBindings.h -@@ -591,6 +592,7 @@ float Gecko_MediaFeatures_GetResolution(const mozilla::dom::Document*); - bool Gecko_MediaFeatures_PrefersReducedMotion(const mozilla::dom::Document*); - bool Gecko_MediaFeatures_PrefersReducedTransparency( - 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 21bcc8e890a0d3f3e86b5ea6eed79d017dd2fb76..eefc7d5c934f03b4a9213dafcbb65dd32b695622 100644 ---- a/layout/style/nsMediaFeatures.cpp -+++ b/layout/style/nsMediaFeatures.cpp -@@ -268,11 +268,7 @@ bool Gecko_MediaFeatures_MatchesPlatform(StylePlatform aPlatform) { - } - - bool Gecko_MediaFeatures_PrefersReducedMotion(const Document* aDocument) { -- if (aDocument->ShouldResistFingerprinting( -- RFPTarget::CSSPrefersReducedMotion)) { -- return false; -- } -- return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1; -+ return aDocument->PrefersReducedMotion(); - } - - bool Gecko_MediaFeatures_PrefersReducedTransparency(const Document* aDocument) { -@@ -297,6 +293,20 @@ StylePrefersColorScheme Gecko_MediaFeatures_PrefersColorScheme( - // as a signal. - StylePrefersContrast Gecko_MediaFeatures_PrefersContrast( - const Document* aDocument) { -+ if (auto* bc = aDocument->GetBrowsingContext()) { -+ switch (bc->Top()->PrefersContrastOverride()) { -+ case dom::PrefersContrastOverride::No_preference: -+ return StylePrefersContrast::NoPreference; -+ case dom::PrefersContrastOverride::Less: -+ return StylePrefersContrast::Less; -+ case dom::PrefersContrastOverride::More: -+ return StylePrefersContrast::More; -+ case dom::PrefersContrastOverride::Custom: -+ return StylePrefersContrast::Custom; -+ } -+ } -+ -+ - if (aDocument->ShouldResistFingerprinting(RFPTarget::CSSPrefersContrast)) { - return StylePrefersContrast::NoPreference; - } -diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp -index e5cf36273d5790de2c80acb42a6ee181bdb66f08..0523a37fc19b470e3817ae61c912a3dc54fc57a6 100644 ---- a/netwerk/base/LoadInfo.cpp -+++ b/netwerk/base/LoadInfo.cpp -@@ -801,7 +801,8 @@ LoadInfo::LoadInfo(const LoadInfo& rhs) - rhs.mHasInjectedCookieForCookieBannerHandling), - mSchemelessInput(rhs.mSchemelessInput), - mHttpsUpgradeTelemetry(rhs.mHttpsUpgradeTelemetry), -- mIsNewWindowTarget(rhs.mIsNewWindowTarget) { -+ mIsNewWindowTarget(rhs.mIsNewWindowTarget), -+ mJugglerLoadIdentifier(rhs.mJugglerLoadIdentifier) { - } - - LoadInfo::LoadInfo( -@@ -2778,4 +2779,16 @@ void LoadInfo::UpdateParentAddressSpaceInfo() { - } - } - -+NS_IMETHODIMP -+LoadInfo::GetJugglerLoadIdentifier(uint64_t* aResult) { -+ *aResult = mJugglerLoadIdentifier; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+LoadInfo::SetJugglerLoadIdentifier(uint64_t aID) { -+ mJugglerLoadIdentifier = aID; -+ return NS_OK; -+} -+ - } // namespace mozilla::net -diff --git a/netwerk/base/LoadInfo.h b/netwerk/base/LoadInfo.h -index 6547d451f3a764c8860dd0c19b5b490caecbf0af..feccce92e3769b8e9a3a4926cca9b85fccda86a5 100644 ---- a/netwerk/base/LoadInfo.h -+++ b/netwerk/base/LoadInfo.h -@@ -455,6 +455,8 @@ class LoadInfo final : public nsILoadInfo { - - bool mIsNewWindowTarget = false; - bool mSkipHTTPSUpgrade = false; -+ -+ uint64_t mJugglerLoadIdentifier = 0; - }; - // This is exposed solely for testing purposes and should not be used outside of - // LoadInfo -diff --git a/netwerk/base/TRRLoadInfo.cpp b/netwerk/base/TRRLoadInfo.cpp -index 551d89315243f4b515aa29d3a67eb23050ea9f0a..ac3a1ca6d846826c5d704d1b4abdaee55b834b0d 100644 ---- a/netwerk/base/TRRLoadInfo.cpp -+++ b/netwerk/base/TRRLoadInfo.cpp -@@ -1010,5 +1010,15 @@ TRRLoadInfo::GetFetchDestination(nsACString& aDestination) { - return NS_ERROR_NOT_IMPLEMENTED; - } - -+NS_IMETHODIMP -+TRRLoadInfo::GetJugglerLoadIdentifier(uint64_t* aResult) { -+ return NS_ERROR_NOT_IMPLEMENTED; -+} -+ -+NS_IMETHODIMP -+TRRLoadInfo::SetJugglerLoadIdentifier(uint64_t aResult) { -+ return NS_ERROR_NOT_IMPLEMENTED; -+} -+ - } // namespace net - } // namespace mozilla -diff --git a/netwerk/base/nsILoadInfo.idl b/netwerk/base/nsILoadInfo.idl -index f1b54736d9ee006292bf4c9cd0b3490d5ec8da66..257fda17a10f702cee39fb42ad69e0cd86ca95d1 100644 ---- a/netwerk/base/nsILoadInfo.idl -+++ b/netwerk/base/nsILoadInfo.idl -@@ -1686,4 +1686,6 @@ interface nsILoadInfo : nsISupports - return static_cast(userNavigationInvolvement); - } - %} -+ -+ [infallible] attribute unsigned long long jugglerLoadIdentifier; - }; -diff --git a/netwerk/base/nsINetworkInterceptController.idl b/netwerk/base/nsINetworkInterceptController.idl -index 7f91d2df6f8bb4020c75c132dc8f6bf26625fa1e..aaa5541a17039d6b13ad83ab176fdaaf79edb2a0 100644 ---- a/netwerk/base/nsINetworkInterceptController.idl -+++ b/netwerk/base/nsINetworkInterceptController.idl -@@ -60,6 +60,16 @@ interface nsIInterceptedChannel : nsISupports - */ - void resetInterception(in boolean bypass); - -+ // ----- Playwright begin ----- -+ -+ // Same as resetInterception, but updates the URI. -+ void resetInterceptionWithURI(in nsIURI aURI); -+ -+ // After resetInterception is called, this request will be intercepted again. -+ void interceptAfterServiceWorkerResets(); -+ -+ // ----- Playwright end ------- -+ - /** - * Set the status and reason for the forthcoming synthesized response. - * Multiple calls overwrite existing values. -diff --git a/netwerk/ipc/DocumentLoadListener.cpp b/netwerk/ipc/DocumentLoadListener.cpp -index 1471432c1f1a47be5073ed01b746f1f13d3a0b47..585f81762e2bf51681d11c06c9459063121c34e9 100644 ---- a/netwerk/ipc/DocumentLoadListener.cpp -+++ b/netwerk/ipc/DocumentLoadListener.cpp -@@ -185,6 +185,7 @@ static auto CreateDocumentLoadInfo(CanonicalBrowsingContext* aBrowsingContext, - loadInfo->SetTextDirectiveUserActivation( - aLoadState->GetTextDirectiveUserActivation()); - loadInfo->SetIsMetaRefresh(aLoadState->IsMetaRefresh()); -+ loadInfo->SetJugglerLoadIdentifier(aLoadState->GetLoadIdentifier()); - - return loadInfo.forget(); - } -diff --git a/netwerk/protocol/http/InterceptedHttpChannel.cpp b/netwerk/protocol/http/InterceptedHttpChannel.cpp -index fbf4bdf1e24d1102df113984be6c8dc3a7d0d810..cf1978009d74221ae804b998e223904fa943a91f 100644 ---- a/netwerk/protocol/http/InterceptedHttpChannel.cpp -+++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp -@@ -728,10 +728,33 @@ NS_IMPL_ISUPPORTS(ResetInterceptionHeaderVisitor, nsIHttpHeaderVisitor) - - } // anonymous namespace - -+NS_IMETHODIMP -+InterceptedHttpChannel::InterceptAfterServiceWorkerResets() { -+ mInterceptAfterServiceWorkerResets = true; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+InterceptedHttpChannel::ResetInterceptionWithURI(nsIURI* aURI) { -+ if (aURI) { -+ mURI = aURI; -+ } -+ return ResetInterception(true); -+} -+ - NS_IMETHODIMP - InterceptedHttpChannel::ResetInterception(bool aBypass) { - INTERCEPTED_LOG(("InterceptedHttpChannel::ResetInterception [%p] bypass: %s", - this, aBypass ? "true" : "false")); -+ if (mInterceptAfterServiceWorkerResets) { -+ mInterceptAfterServiceWorkerResets = false; -+ nsCOMPtr controller; -+ GetCallback(controller); -+ if (!controller) -+ return NS_ERROR_DOM_INVALID_STATE_ERR; -+ return controller->ChannelIntercepted(this); -+ } -+ - if (mCanceled) { - return mStatus; - } -@@ -1146,11 +1169,18 @@ InterceptedHttpChannel::OnStartRequest(nsIRequest* aRequest) { - GetCallback(mProgressSink); - } - -+ // Playwright: main requests in firefox do not have loading principal. -+ // As they are intercepted by Playwright, they don't have -+ // serviceWorkerTainting as well. -+ // Thus these asserts are wrong for Playwright world. -+ // Note: these checks were added in https://github.com/mozilla-firefox/firefox/commit/bb16ca6496682c3b0ddd452d0dd4c1dd46ff71f8 -+ /* - MOZ_ASSERT_IF(!mLoadInfo->GetServiceWorkerTaintingSynthesized(), - mLoadInfo->GetLoadingPrincipal()); - // No need to do ORB checks if these conditions hold. - MOZ_DIAGNOSTIC_ASSERT(mLoadInfo->GetServiceWorkerTaintingSynthesized() || - mLoadInfo->GetLoadingPrincipal()->IsSystemPrincipal()); -+ */ - - if (mPump && mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS) { - mPump->PeekStream(CallTypeSniffers, static_cast(this)); -diff --git a/netwerk/protocol/http/InterceptedHttpChannel.h b/netwerk/protocol/http/InterceptedHttpChannel.h -index 704404c9f094640ad63b685d64bd5a396e733e4b..92bdc21b4d6a015cc2f2bb22781ec6750c7789ec 100644 ---- a/netwerk/protocol/http/InterceptedHttpChannel.h -+++ b/netwerk/protocol/http/InterceptedHttpChannel.h -@@ -90,6 +90,11 @@ class InterceptedHttpChannel final - Atomic mCallingStatusAndProgress; - bool mInterceptionReset{false}; - -+ // ----- Playwright begin ----- -+ // After resetInterception is called, this request will call into interceptors again. -+ bool mInterceptAfterServiceWorkerResets{false}; -+ // ----- Playwright end ------- -+ - /** - * InterceptionTimeStamps is used to record the time stamps of the - * interception. -diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp -index 1051d1e91c1ebf036f2e5db82a37636dd7cda4c3..3ef53c09442e24fb50308740950aa6d354703b7d 100644 ---- a/netwerk/protocol/http/nsHttpChannel.cpp -+++ b/netwerk/protocol/http/nsHttpChannel.cpp -@@ -685,11 +685,9 @@ nsresult nsHttpChannel::OnBeforeConnect() { - // SecurityInfo.sys.mjs - mLoadInfo->SetHstsStatus(isSecureURI); - -- RefPtr bc; -- mLoadInfo->GetBrowsingContext(getter_AddRefs(bc)); - // If bypassing the cache and we're forced offline - // we can just return the error here. -- if (bc && bc->Top()->GetForceOffline() && -+ if (IsForcedOffline() && - BYPASS_LOCAL_CACHE(mLoadFlags, LoadPreferCacheLoadOverBypass())) { - return NS_ERROR_OFFLINE; - } -@@ -802,9 +800,7 @@ nsresult nsHttpChannel::MaybeUseHTTPSRRForUpgrade(bool aShouldUpgrade, - return aStatus; - } - -- RefPtr bc; -- mLoadInfo->GetBrowsingContext(getter_AddRefs(bc)); -- bool forceOffline = bc && bc->Top()->GetForceOffline(); -+ bool forceOffline = IsForcedOffline(); - - if (mURI->SchemeIs("https") || aShouldUpgrade || !LoadUseHTTPSSVC() || - forceOffline) { -@@ -1263,15 +1259,14 @@ nsresult nsHttpChannel::ContinueConnect() { - "CORS preflight must have been finished by the time we " - "do the rest of ContinueConnect"); - -- RefPtr bc; -- mLoadInfo->GetBrowsingContext(getter_AddRefs(bc)); -+ bool isForcedOffline = IsForcedOffline(); - - // we may or may not have a cache entry at this point - if (mCacheEntry) { - // read straight from the cache if possible... - if (CachedContentIsValid()) { - // If we're forced offline, and set to bypass the cache, return offline. -- if (bc && bc->Top()->GetForceOffline() && -+ if (isForcedOffline && - BYPASS_LOCAL_CACHE(mLoadFlags, LoadPreferCacheLoadOverBypass())) { - return NS_ERROR_OFFLINE; - } -@@ -1313,7 +1308,7 @@ nsresult nsHttpChannel::ContinueConnect() { - } - - // We're about to hit the network. Don't if we're forced offline. -- if (bc && bc->Top()->GetForceOffline()) { -+ if (isForcedOffline) { - return NS_ERROR_OFFLINE; - } - -@@ -1418,12 +1413,9 @@ void nsHttpChannel::SpeculativeConnect() { - // don't speculate if we are offline, when doing http upgrade (i.e. - // websockets bootstrap), or if we can't do keep-alive (because then we - // couldn't reuse the speculative connection anyhow). -- RefPtr bc; -- mLoadInfo->GetBrowsingContext(getter_AddRefs(bc)); -- - if (gIOService->IsOffline() || mUpgradeProtocolCallback || - !(mCaps & NS_HTTP_ALLOW_KEEPALIVE) || -- (bc && bc->Top()->GetForceOffline())) { -+ IsForcedOffline()) { - return; - } - -@@ -4240,9 +4232,6 @@ nsresult nsHttpChannel::OpenCacheEntryInternal(bool isHttps) { - uint32_t cacheEntryOpenFlags; - bool offline = gIOService->IsOffline(); - -- RefPtr bc; -- mLoadInfo->GetBrowsingContext(getter_AddRefs(bc)); -- - bool maybeRCWN = false; - - nsAutoCString cacheControlRequestHeader; -@@ -4253,7 +4242,7 @@ nsresult nsHttpChannel::OpenCacheEntryInternal(bool isHttps) { - return NS_OK; - } - -- bool forceOffline = bc && bc->Top()->GetForceOffline(); -+ bool forceOffline = IsForcedOffline(); - if (offline || (mLoadFlags & INHIBIT_CACHING) || forceOffline) { - if (BYPASS_LOCAL_CACHE(mLoadFlags, LoadPreferCacheLoadOverBypass()) && - !offline && !forceOffline) { -@@ -7357,6 +7346,20 @@ void nsHttpChannel::MaybeStartDNSPrefetch() { - } - } - -+bool nsHttpChannel::IsForcedOffline() { -+ RefPtr bc; -+ mLoadInfo->GetBrowsingContext(getter_AddRefs(bc)); -+ if (bc && bc->Top()->GetForceOffline()) -+ return true; -+ -+ RefPtr wbc; -+ mLoadInfo->GetWorkerAssociatedBrowsingContext(getter_AddRefs(wbc)); -+ if (wbc && wbc->Top()->GetForceOffline()) -+ return true; -+ -+ return false; -+} -+ - NS_IMETHODIMP - nsHttpChannel::GetEncodedBodySize(uint64_t* aEncodedBodySize) { - if (mCacheEntry && !LoadCacheEntryIsWriteOnly()) { -diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h -index 9d28bae2d270690517c11383abe4c4bcc0edda96..9087d345b1b63bdce0912abb0c880c50900a797b 100644 ---- a/netwerk/protocol/http/nsHttpChannel.h -+++ b/netwerk/protocol/http/nsHttpChannel.h -@@ -305,6 +305,10 @@ class nsHttpChannel final : public HttpBaseChannel, - void MaybeResolveProxyAndBeginConnect(); - void MaybeStartDNSPrefetch(); - -+ // ---- Playwright begin -+ bool IsForcedOffline(); -+ // ---- Playwright end -+ - // Based on the proxy configuration determine the strategy for resolving the - // end server host name. - ProxyDNSStrategy GetProxyDNSStrategy(); -diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp -index ce2a868b9a915b98938518b6c935870f8169e0f7..e6d0a75bb3f5e8dea3f3e7f3448b553979860bd3 100644 ---- a/parser/html/nsHtml5TreeOpExecutor.cpp -+++ b/parser/html/nsHtml5TreeOpExecutor.cpp -@@ -1361,6 +1361,10 @@ void nsHtml5TreeOpExecutor::UpdateReferrerInfoFromMeta( - void nsHtml5TreeOpExecutor::AddSpeculationCSP(const nsAString& aCSP) { - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - -+ if (mDocShell && static_cast(mDocShell.get())->IsBypassCSPEnabled()) { -+ return; -+ } -+ - nsresult rv = NS_OK; - nsCOMPtr preloadCsp = mDocument->GetPreloadCsp(); - if (!preloadCsp) { -diff --git a/security/manager/ssl/nsCertOverrideService.cpp b/security/manager/ssl/nsCertOverrideService.cpp -index 0ecf2c0df3aad52e004a69b4c7a22fea7532b4d8..f5982c2cf1d6ea0522ac7f7e1fb5b4ab8fa07cb4 100644 ---- a/security/manager/ssl/nsCertOverrideService.cpp -+++ b/security/manager/ssl/nsCertOverrideService.cpp -@@ -627,6 +627,8 @@ void nsCertOverrideService::CountPermanentOverrideTelemetry( - } - - static bool IsDebugger() { -+ // In playwright world, this is always enabled. -+ if (1 == 1) return true; - #ifdef ENABLE_WEBDRIVER - nsCOMPtr marionette = do_GetService(NS_MARIONETTE_CONTRACTID); - if (marionette) { -diff --git a/services/settings/Utils.sys.mjs b/services/settings/Utils.sys.mjs -index cbdf07bcdae11de6f59e6c6c279833aca430dc70..6840c78350ccb52e99f23446b010abc2a1d92a55 100644 ---- a/services/settings/Utils.sys.mjs -+++ b/services/settings/Utils.sys.mjs -@@ -97,7 +97,7 @@ const _cdnURLs = {}; - - export var Utils = { - get SERVER_URL() { -- return lazy.allowServerURLOverride -+ return true || lazy.allowServerURLOverride - ? lazy.gServerURL - : AppConstants.REMOTE_SETTINGS_SERVER_URL; - }, -@@ -110,6 +110,9 @@ export var Utils = { - log, - - get shouldSkipRemoteActivityDueToTests() { -+ // Playwright does not set Cu.isInAutomation, hence we just return true -+ // here in order to disable the remote activity. -+ return true; - return ( - (lazy.isRunningTests || Cu.isInAutomation) && - this.SERVER_URL == "data:,#remote-settings-dummy/v1" -diff --git a/toolkit/components/browser/nsIWebBrowserChrome.idl b/toolkit/components/browser/nsIWebBrowserChrome.idl -index 75555352b8a15a50e4a21e34fc8ede4e9246c7cc..72855a404effa42b6c55cd0c2fcb8bdd6c2b3f9f 100644 ---- a/toolkit/components/browser/nsIWebBrowserChrome.idl -+++ b/toolkit/components/browser/nsIWebBrowserChrome.idl -@@ -74,6 +74,9 @@ interface nsIWebBrowserChrome : nsISupports - // Whether this window should use out-of-process cross-origin subframes. - const unsigned long CHROME_FISSION_WINDOW = 1 << 21; - -+ // 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 = 1 << 24; -diff --git a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs -index 3d8837cdb38fb5b25abfb9e3e369ad6fe688706e..867ce2efaa10eaea87ffeeb2669cc5a7be0045b3 100644 ---- a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs -+++ b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs -@@ -106,7 +106,9 @@ EnterprisePoliciesManager.prototype = { - Services.prefs.clearUserPref(PREF_POLICIES_APPLIED); - } - -- let provider = this._chooseProvider(); -+ // --- Playwright begin --- -+ let provider = new PlaywrightPoliciesProvider(); -+ // --- Playwright end --- - - if (provider.failed) { - this.status = Ci.nsIEnterprisePolicies.FAILED; -@@ -606,6 +608,19 @@ class JSONPoliciesProvider { - } - } - -+class PlaywrightPoliciesProvider extends JSONPoliciesProvider { -+ _getConfigurationFile() { -+ let prefPath = Services.prefs.getStringPref(PREF_ALTERNATE_PATH, ""); -+ if (!prefPath) -+ return null; -+ -+ dump(`Playwright: loading enterprise policies from ${prefPath}\n`); -+ let configFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); -+ configFile.initWithPath(prefPath); -+ return configFile; -+ } -+} -+ - class WindowsGPOPoliciesProvider { - constructor() { - this._policies = null; -diff --git a/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp b/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp -index 52fa968554a88d1624bf9403b07781a8b42c93b6..2bd5162859dbc482361e2f6aaf5b7a732e9a5929 100644 ---- a/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp -+++ b/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp -@@ -588,7 +588,7 @@ void PopulateLanguages() { - // sufficient to only collect this information as the other properties are - // just reformats of Navigator::GetAcceptLanguages. - nsTArray languages; -- dom::Navigator::GetAcceptLanguages(languages); -+ dom::Navigator::GetAcceptLanguages(nullptr, languages); - nsCString output = "["_ns; - - for (const auto& language : languages) { -diff --git a/toolkit/components/startup/nsAppStartup.cpp b/toolkit/components/startup/nsAppStartup.cpp -index d8f0c072c8a52c2837d87fe749ccac6e3e59e48a..6837927e6a49a8ff4c9f709502bf8d8983bd735c 100644 ---- a/toolkit/components/startup/nsAppStartup.cpp -+++ b/toolkit/components/startup/nsAppStartup.cpp -@@ -361,7 +361,7 @@ nsAppStartup::Quit(uint32_t aMode, int aExitCode, bool* aUserAllowedQuit) { - nsCOMPtr windowEnumerator; - nsCOMPtr 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 c0d60b927542653ab9beee730ec2c07f4b3d911c..85c416315f567a5edf8cfc89262dd7a48250dfd6 100644 ---- a/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp -+++ b/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp -@@ -176,8 +176,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 622ff7fe214d22e1e5d5a561753cffe3e1eafe31..ac2f30e00a9a6d18c61d00b0d6d4bf41ff48af95 100644 ---- a/toolkit/components/windowwatcher/nsWindowWatcher.cpp -+++ b/toolkit/components/windowwatcher/nsWindowWatcher.cpp -@@ -1882,7 +1882,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.sys.mjs b/toolkit/mozapps/update/UpdateService.sys.mjs -index 5d5a3f2c46138b578b583ad4a3506e1d227607ad..6d414635b80a74edb0b5ecfc6a98dd0fee763952 100644 ---- a/toolkit/mozapps/update/UpdateService.sys.mjs -+++ b/toolkit/mozapps/update/UpdateService.sys.mjs -@@ -3874,6 +3874,8 @@ export class UpdateService { - } - - get disabledForTesting() { -+ /* playwright */ -+ return true; - return lazy.UpdateServiceStub.updateDisabledForTesting; - } - -diff --git a/toolkit/toolkit.mozbuild b/toolkit/toolkit.mozbuild -index e8399d277ec0b64e5ea29aa7262b118936a02779..983ed73ad1d6d734af55a9066a8e8a6cf3ae3f45 100644 ---- a/toolkit/toolkit.mozbuild -+++ b/toolkit/toolkit.mozbuild -@@ -155,6 +155,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 7eb9e1104682d4eb47060654f43a1efa8b2a6bb2..a8315d6decf654b5302bea5beeea34140c300ded 100644 ---- a/toolkit/xre/nsWindowsWMain.cpp -+++ b/toolkit/xre/nsWindowsWMain.cpp -@@ -14,8 +14,10 @@ - #endif - - #include "mozilla/Char16.h" -+#include "mozilla/CmdLineAndEnvUtils.h" - #include "nsUTF8Utils.h" - -+#include - #include - - #ifdef __MINGW32__ -@@ -114,6 +116,19 @@ static void FreeAllocStrings(int argc, char** argv) { - int wmain(int argc, WCHAR** argv) { - SanitizeEnvironmentVariables(); - SetDllDirectoryW(L""); -+ bool hasJugglerPipe = -+ mozilla::CheckArg(argc, argv, "juggler-pipe", 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 9ef5370d1524ddecb965785a73a3cfea39867324..e0245cca94e496bcffba40c9660a52b518803d44 100644 ---- a/uriloader/base/nsDocLoader.cpp -+++ b/uriloader/base/nsDocLoader.cpp -@@ -861,6 +861,12 @@ void nsDocLoader::DocLoaderIsEmpty(bool aFlushLayout, - ("DocLoader:%p: Firing load event for document.open\n", - this)); - -+ nsCOMPtr 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 5bd60b585b53cc77e75c0b68c763957f90b7e164..940b3b62b09ca70ae5e69c3e94eda11ad35b9dfe 100644 ---- a/uriloader/exthandler/nsExternalHelperAppService.cpp -+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp -@@ -112,6 +112,7 @@ - - #include "mozilla/Components.h" - #include "mozilla/ClearOnShutdown.h" -+#include "mozilla/ErrorNames.h" - #include "mozilla/Preferences.h" - #include "mozilla/ipc/URIUtils.h" - -@@ -865,6 +866,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); -@@ -1500,7 +1507,12 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel* aChannel) { - // Strip off the ".part" from mTempLeafName - mTempLeafName.Truncate(mTempLeafName.Length() - std::size(".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); -@@ -1684,7 +1696,36 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { - return NS_OK; - } - -- rv = SetUpTempFile(aChannel); -+ bool isIntercepted = false; -+ nsCOMPtr interceptor = mExtProtSvc->mInterceptor; -+ if (interceptor) { -+ nsCOMPtr 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; - -@@ -1745,6 +1786,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 -@@ -2261,6 +2305,16 @@ nsExternalAppHandler::OnSaveComplete(nsIBackgroundFileSaver* aSaver, - NotifyTransfer(aStatus); - } - -+ if (!mCanceled) { -+ nsCOMPtr 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; - } - -@@ -2744,6 +2798,15 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason) { - } - } - -+ nsCOMPtr 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 26dfc6f04298420317c8b87b2ecc3f2f47f59598..c458ab5efb238c62499ee13452f2d750e0569e38 100644 ---- a/uriloader/exthandler/nsExternalHelperAppService.h -+++ b/uriloader/exthandler/nsExternalHelperAppService.h -@@ -263,6 +263,8 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService, - mozilla::dom::BrowsingContext* aContentContext, bool aForceSave, - nsIInterfaceRequestor* aWindowContext, - nsIStreamListener** aStreamListener); -+ -+ nsCOMPtr mInterceptor; - }; - - /** -@@ -460,6 +462,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 e6490ebb086eb4dca9db560c14e073a9e7722e29..2792373dcb30ebc787a9bdca306ac12e72aa19ec 100644 ---- a/uriloader/exthandler/nsIExternalHelperAppService.idl -+++ b/uriloader/exthandler/nsIExternalHelperAppService.idl -@@ -6,8 +6,11 @@ - - #include "nsICancelable.idl" - -+webidl BrowsingContext; -+interface nsIHelperAppLauncher; - interface nsIURI; - interface nsIChannel; -+interface nsIRequest; - interface nsIStreamListener; - interface nsIFile; - interface nsIMIMEInfo; -@@ -15,6 +18,17 @@ interface nsIWebProgressListener2; - interface nsIInterfaceRequestor; - webidl BrowsingContext; - -+/** -+ * Interceptor interface used by Juggler. -+ */ -+[scriptable, uuid(9a20e9b0-75d0-11ea-bc55-0242ac130003)] -+interface nsIDownloadInterceptor : nsISupports -+{ -+ boolean 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. -@@ -87,6 +101,8 @@ interface nsIExternalHelperAppService : nsISupports - * `DownloadIntegration.sys.mjs`, which is implemented on all platforms. - */ - nsIFile getPreferredDownloadsDirectory(); -+ -+ void setDownloadInterceptor(in nsIDownloadInterceptor interceptor); - }; - - /** -diff --git a/widget/InProcessCompositorWidget.cpp b/widget/InProcessCompositorWidget.cpp -index 7098db301770ecb5b9a506d7caec89d5cf63384b..aff8d7562f8a3e595a077ce8e591008762479587 100644 ---- a/widget/InProcessCompositorWidget.cpp -+++ b/widget/InProcessCompositorWidget.cpp -@@ -5,8 +5,11 @@ - #include "InProcessCompositorWidget.h" - -+#include "HeadlessCompositorWidget.h" -+#include "HeadlessWidget.h" - #include "mozilla/VsyncDispatcher.h" -+#include "mozilla/widget/PlatformWidgetTypes.h" - #include "mozilla/layers/NativeLayer.h" - #include "nsIWidget.h" - - namespace mozilla { -@@ -26,6 +29,12 @@ RefPtr CompositorWidget::CreateLocal( - // do it after the static_cast. - nsIWidget* widget = static_cast(aWidget)); -+ } - return new InProcessCompositorWidget(aOptions, widget); - } - #endif -diff --git a/widget/MouseEvents.h b/widget/MouseEvents.h -index 4f7ca9d0d460da3124ec8489917a9484661d5624..a04c3661b3e1e2be030ac6fe90041c81e653d26e 100644 ---- a/widget/MouseEvents.h -+++ b/widget/MouseEvents.h -@@ -380,6 +380,9 @@ class WidgetMouseEvent : public WidgetMouseEventBase, - // Otherwise, this must be 0. - uint32_t mClickCount = 0; - -+ // Unique event ID -+ uint32_t mJugglerEventId = 0; -+ - // Whether the event should ignore scroll frame bounds during dispatch. - bool mIgnoreRootScrollFrame = false; - -@@ -407,6 +410,7 @@ class WidgetMouseEvent : public WidgetMouseEventBase, - mContextMenuTrigger = aEvent.mContextMenuTrigger; - mExitFrom = aEvent.mExitFrom; - mClickCount = aEvent.mClickCount; -+ mJugglerEventId = aEvent.mJugglerEventId; - mIgnoreRootScrollFrame = aEvent.mIgnoreRootScrollFrame; - mIgnoreCapturingContent = aEvent.mIgnoreCapturingContent; - mClickEventPrevented = aEvent.mClickEventPrevented; -diff --git a/widget/cocoa/NativeKeyBindings.mm b/widget/cocoa/NativeKeyBindings.mm -index 24b70173c2e8bb9be9fd6255984a70efe3b14099..75ac367a1c4bb44d4b68b5f4ecc6adf56dbd408e 100644 ---- a/widget/cocoa/NativeKeyBindings.mm -+++ b/widget/cocoa/NativeKeyBindings.mm -@@ -549,6 +549,13 @@ void NativeKeyBindings::GetEditCommandsForTests( - 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())) { -@@ -571,6 +578,13 @@ void NativeKeyBindings::GetEditCommandsForTests( - 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())) { -@@ -593,6 +607,10 @@ void NativeKeyBindings::GetEditCommandsForTests( - 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()) { -@@ -603,7 +621,7 @@ void NativeKeyBindings::GetEditCommandsForTests( - !aEvent.IsShift() - ? ToObjcSelectorPtr(@selector(moveToBeginningOfDocument:)) - : ToObjcSelectorPtr( -- @selector(moveToBegginingOfDocumentAndModifySelection:)), -+ @selector(moveToBeginningOfDocumentAndModifySelection:)), - aCommands); - break; - } -@@ -630,6 +648,10 @@ void NativeKeyBindings::GetEditCommandsForTests( - 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/gtk/nsFilePicker.cpp b/widget/gtk/nsFilePicker.cpp -index f09b0e4994304413cbd75f14e6650cf3f9df9025..41c184e74df2b9c59315a236506946bcb5d69216 100644 ---- a/widget/gtk/nsFilePicker.cpp -+++ b/widget/gtk/nsFilePicker.cpp -@@ -21,7 +21,8 @@ - #include "mozilla/Components.h" - #include "mozilla/Preferences.h" - #include "mozilla/dom/Promise.h" -+#include "gfxPlatform.h" - #include "mozilla/dom/Document.h" - - #include "nsArrayEnumerator.h" - #include "nsEnumeratorUtils.h" -diff --git a/widget/headless/HeadlessCompositorWidget.cpp b/widget/headless/HeadlessCompositorWidget.cpp -index bb4ee9175e66dc40de1871a7f91368fe309494a3..6814ae85038d31f1a3b1f87ba341219ffbc1e6b3 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" -@@ -15,9 +16,30 @@ HeadlessCompositorWidget::HeadlessCompositorWidget( - const layers::CompositorOptions& aOptions, HeadlessWidget* aWindow) - : CompositorWidget(aOptions), - mWidget(aWindow), -+ mMon("snapshotListener"), - mClientSize(LayoutDeviceIntSize(aInitData.InitialClientSize()), - "HeadlessCompositorWidget::mClientSize") {} - -+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 HeadlessCompositorWidget::StartRemoteDrawingInRegion( -+ const LayoutDeviceIntRegion& aInvalidRegion) { -+ if (!mDrawTarget) -+ return nullptr; -+ -+ RefPtr result = mDrawTarget; -+ return result.forget(); -+} -+ - void HeadlessCompositorWidget::ObserveVsync(VsyncObserver* aObserver) { - if (RefPtr cvd = - mWidget->GetCompositorVsyncDispatcher()) { -@@ -31,6 +53,59 @@ void HeadlessCompositorWidget::NotifyClientSizeChanged( - const LayoutDeviceIntSize& aClientSize) { - auto size = mClientSize.Lock(); - *size = aClientSize; -+ layers::CompositorThread()->Dispatch(NewRunnableMethod( -+ "HeadlessCompositorWidget::UpdateDrawTarget", this, -+ &HeadlessCompositorWidget::UpdateDrawTarget, -+ aClientSize)); -+} -+ -+void HeadlessCompositorWidget::UpdateDrawTarget(const LayoutDeviceIntSize& aClientSize) { -+ MOZ_ASSERT(NS_IsInCompositorThread()); -+ if (aClientSize.IsEmpty()) { -+ mDrawTarget = nullptr; -+ return; -+ } -+ -+ RefPtr 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 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 snapshot = mDrawTarget->Snapshot(); -+ if (!snapshot) { -+ fprintf(stderr, "Failed to get snapshot of draw target\n"); -+ return; -+ } -+ -+ RefPtr 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 facd2bc65afab8ec1aa322faa20a67464964dfb9..3c5751ad1b7f042bc7cd9a63895cebcd2942ccd3 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,11 @@ class HeadlessCompositorWidget final : public CompositorWidget, - HeadlessWidget* aWindow); - - void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize); -+ void SetSnapshotListener(HeadlessWidget::SnapshotListener&& listener); - - // CompositorWidget Overrides -+ already_AddRefed StartRemoteDrawingInRegion( -+ const LayoutDeviceIntRegion& aInvalidRegion) override; - - uintptr_t GetWidgetKey() override; - -@@ -42,10 +46,18 @@ class HeadlessCompositorWidget final : public CompositorWidget, - } - - private: -+ void UpdateDrawTarget(const LayoutDeviceIntSize& aClientSize); -+ void PeriodicSnapshot(); -+ void TakeSnapshot(); -+ - HeadlessWidget* mWidget; -+ mozilla::ReentrantMonitor mMon; - - // See GtkCompositorWidget for the justification for this mutex. - DataMutex mClientSize; -+ -+ HeadlessWidget::SnapshotListener mSnapshotListener; -+ RefPtr mDrawTarget; - }; - - } // namespace widget -diff --git a/widget/headless/HeadlessWidget.cpp b/widget/headless/HeadlessWidget.cpp -index 290de12f9d0ff858474564fa8ce54814a04f6088..c144a891b84c3c57f394d6d551e6c89dcd6d9829 100644 ---- a/widget/headless/HeadlessWidget.cpp -+++ b/widget/headless/HeadlessWidget.cpp -@@ -112,6 +112,8 @@ void HeadlessWidget::Destroy() { - } - } - -+ SetSnapshotListener(nullptr); -+ - nsBaseWidget::OnDestroy(); - - nsBaseWidget::Destroy(); -@@ -593,5 +595,14 @@ nsresult HeadlessWidget::SynthesizeNativeTouchpadPan( - 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 60598d097d9dae829ebdc15dede78bd915e3107d..3b5ac5e5590dcb36440e28569f71592db3c1218c 100644 ---- a/widget/headless/HeadlessWidget.h -+++ b/widget/headless/HeadlessWidget.h -@@ -131,6 +131,9 @@ class HeadlessWidget final : public nsBaseWidget { - double aDeltaX, double aDeltaY, int32_t aModifierFlags, - nsISynthesizedEventCallback* aCallback) override; - -+ using SnapshotListener = std::function&&)>; -+ void SetSnapshotListener(SnapshotListener&& listener); -+ - private: - ~HeadlessWidget(); - bool mEnabled; -diff --git a/widget/nsGUIEventIPC.h b/widget/nsGUIEventIPC.h -index 2f4c33f151870bb9233899b186a5eccfaa6f5da6..6acf66e4938e3f9727916824a08d6294f8993452 100644 ---- a/widget/nsGUIEventIPC.h -+++ b/widget/nsGUIEventIPC.h -@@ -251,6 +251,7 @@ struct ParamTraits { - aParam.mExitFrom.value())); - } - WriteParam(aWriter, aParam.mClickCount); -+ WriteParam(aWriter, aParam.mJugglerEventId); - } - - static bool Read(MessageReader* aReader, paramType* aResult) { -@@ -275,6 +276,7 @@ struct ParamTraits { - aResult->mExitFrom = Some(static_cast(exitFrom)); - } - rv = rv && ReadParam(aReader, &aResult->mClickCount); -+ rv = rv && ReadParam(aReader, &aResult->mJugglerEventId); - return rv; - } - }; -diff --git a/xpcom/reflect/xptinfo/xptinfo.h b/xpcom/reflect/xptinfo/xptinfo.h -index 787d30d881adedd57d2025ca57bff4bc6c57e803..ae1a0172c960ab16919133485722d2ae0cdbcbd4 100644 ---- a/xpcom/reflect/xptinfo/xptinfo.h -+++ b/xpcom/reflect/xptinfo/xptinfo.h -@@ -505,7 +505,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 - - /** diff --git a/patches/playwright/0-playwright.patch.bak b/patches/playwright/0-playwright.patch.bak deleted file mode 100644 index d0200a14..00000000 --- a/patches/playwright/0-playwright.patch.bak +++ /dev/null @@ -1,3469 +0,0 @@ -diff --git a/accessible/interfaces/nsIAccessibleDocument.idl b/accessible/interfaces/nsIAccessibleDocument.idl -index 6c932c14a03e9cbf70723171dc9a1006bd2c017d..6312131c94c6d7e994a4a49dd64b2b4c5777251f 100644 ---- a/accessible/interfaces/nsIAccessibleDocument.idl -+++ b/accessible/interfaces/nsIAccessibleDocument.idl -@@ -73,4 +73,9 @@ interface nsIAccessibleDocument : nsISupports - * The BrowsingContext of this document. - */ - readonly attribute BrowsingContext browsingContext; -+ -+ /** -+ * Return whether it is updating. -+ */ -+ readonly attribute boolean isUpdatePendingForJugglerAccessibility; - }; -diff --git a/accessible/xpcom/xpcAccessibleDocument.cpp b/accessible/xpcom/xpcAccessibleDocument.cpp -index 3229ee415b93b9a47d7d40605ed7b509744c94ad..c2cc38ded257a02de8922312057892bf9d0cad7b 100644 ---- a/accessible/xpcom/xpcAccessibleDocument.cpp -+++ b/accessible/xpcom/xpcAccessibleDocument.cpp -@@ -151,6 +151,13 @@ xpcAccessibleDocument::GetBrowsingContext( - return NS_OK; - } - -+NS_IMETHODIMP -+xpcAccessibleDocument::GetIsUpdatePendingForJugglerAccessibility(bool* updating) { -+ NS_ENSURE_ARG_POINTER(updating); -+ *updating = Intl()->Controller()->IsUpdatePending(); -+ return NS_OK; -+} -+ - //////////////////////////////////////////////////////////////////////////////// - // xpcAccessibleDocument - -diff --git a/accessible/xpcom/xpcAccessibleDocument.h b/accessible/xpcom/xpcAccessibleDocument.h -index 9b6effc38fbecb50897a93b49c41d4453b10fb7f..939ff9615bd422eec186d8164e2ac7e643f39beb 100644 ---- a/accessible/xpcom/xpcAccessibleDocument.h -+++ b/accessible/xpcom/xpcAccessibleDocument.h -@@ -48,6 +48,8 @@ class xpcAccessibleDocument : public xpcAccessibleHyperText, - nsIAccessibleDocument** aDocument) final; - NS_IMETHOD GetBrowsingContext(dom::BrowsingContext** aBrowsingContext) 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 8167d2b81c918e02ce757f7f448f22e07c29d140..3ae798880acfd8aa965ae08051f2f81855133711 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 - #include - #include - -@@ -422,8 +423,18 @@ Maybe 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, "juggler-pipe", 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(stdio3), -+ reinterpret_cast(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 6bbc4016cd6d56e8625e808b5070515a23de7600..2fb56fb1afa5b108a426737cb5e62dc42a199354 100644 ---- a/browser/installer/allowed-dupes.mn -+++ b/browser/installer/allowed-dupes.mn -@@ -59,6 +59,12 @@ browser/chrome/browser/builtin-addons/webcompat/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 -+ - # Bug 1606928 - There's no reliable way to connect Top Sites favicons with the favicons in the Search Service - browser/chrome/browser/content/activity-stream/data/content/tippytop/favicons/allegro-pl.ico - browser/defaults/settings/main/search-config-icons/96327a73-c433-5eb4-a16d-b090cadfb80b -diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in -index 2b4d35e060dc592bb70a1f2b7ceee68616c8202b..323abfaee37445942f7678037dd5b53792dd5ed4 100644 ---- a/browser/installer/package-manifest.in -+++ b/browser/installer/package-manifest.in -@@ -183,6 +183,9 @@ - @RESPATH@/chrome/remote.manifest - #endif - -+@RESPATH@/chrome/juggler@JAREXT@ -+@RESPATH@/chrome/juggler.manifest -+ - ; Modules - @RESPATH@/browser/modules/* - @RESPATH@/modules/* -diff --git a/devtools/server/socket/websocket-server.js b/devtools/server/socket/websocket-server.js -index d49c6fbf1bf83b832795fa674f6b41f223eef812..7ea3540947ff5f61b15f27fbf4b955649f8e9ff9 100644 ---- a/devtools/server/socket/websocket-server.js -+++ b/devtools/server/socket/websocket-server.js -@@ -134,13 +134,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"); - } - -@@ -190,13 +189,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, [ -@@ -218,8 +217,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 97334bee3a111a538779789d3495805cec8b1e9a..67d030f2adecd9acc62665e2a627123148aa927d 100644 ---- a/docshell/base/BrowsingContext.cpp -+++ b/docshell/base/BrowsingContext.cpp -@@ -110,8 +110,15 @@ struct ParamTraits - - template <> - struct ParamTraits -- : public mozilla::dom::WebIDLEnumSerializer< -- mozilla::dom::PrefersColorSchemeOverride> {}; -+ : public mozilla::dom::WebIDLEnumSerializer {}; -+ -+template <> -+struct ParamTraits -+ : public mozilla::dom::WebIDLEnumSerializer {}; -+ -+template <> -+struct ParamTraits -+ : public mozilla::dom::WebIDLEnumSerializer {}; - - template <> - struct ParamTraits -@@ -2950,6 +2957,32 @@ void BrowsingContext::DidSet(FieldIndex, - }); - } - -+void BrowsingContext::DidSet(FieldIndex, -+ dom::PrefersContrastOverride aOldValue) { -+ MOZ_ASSERT(IsTop()); -+ if (PrefersContrastOverride() == aOldValue) { -+ return; -+ } -+ PresContextAffectingFieldChanged(); -+} -+ -+void BrowsingContext::DidSet(FieldIndex, -+ 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, - nsString&& aOldValue) { - MOZ_ASSERT(IsTop()); -@@ -3290,7 +3323,7 @@ void BrowsingContext::SetGeolocationServiceOverride( - if (aGeolocationOverride.WasPassed()) { - if (!mGeolocationServiceOverride) { - mGeolocationServiceOverride = new nsGeolocationService(); -- mGeolocationServiceOverride->Init(); -+ mGeolocationServiceOverride->Init(true /* isOverride */); - } - mGeolocationServiceOverride->Update(aGeolocationOverride.Value()); - } else if (RefPtr serviceOverride = -@@ -3793,6 +3826,23 @@ void BrowsingContext::DidSet(FieldIndex, - } - } - -+void BrowsingContext::DidSet(FieldIndex, bool aOldValue) { -+ const bool newValue = ForceOffline(); -+ if (newValue == aOldValue) { -+ return; -+ } -+ PreOrderWalk([&](BrowsingContext* aContext) { -+ if (Document* doc = aContext->GetDocument()) { -+ if (nsPIDOMWindowOuter* win = aContext->GetDOMWindow()) { -+ nsContentUtils::DispatchTrustedEvent( -+ doc, nsGlobalWindowOuter::Cast(win), -+ newValue ? u"offline"_ns : u"online"_ns, -+ CanBubble::eYes, Cancelable::eYes, nullptr); -+ } -+ } -+ }); -+} -+ - bool BrowsingContext::IsPopupAllowed() { - for (auto* context = GetCurrentWindowContext(); context; - context = context->GetParentWindowContext()) { -diff --git a/docshell/base/BrowsingContext.h b/docshell/base/BrowsingContext.h -index b42c32133c6490755ae4e1c599255418e6443011..afa502833ba55c94dbd30726d37450c460a69e2b 100644 ---- a/docshell/base/BrowsingContext.h -+++ b/docshell/base/BrowsingContext.h -@@ -209,11 +209,11 @@ struct EmbedderColorSchemes { - FIELD(GVInaudibleAutoplayRequestStatus, GVAutoplayRequestStatus) \ - /* ScreenOrientation-related APIs */ \ - FIELD(CurrentOrientationAngle, float) \ -- FIELD(CurrentOrientationType, mozilla::dom::OrientationType) \ -+ FIELD(CurrentOrientationType, dom::OrientationType) \ - FIELD(OrientationLock, mozilla::hal::ScreenOrientation) \ - FIELD(HasOrientationOverride, bool) \ - FIELD(UserAgentOverride, nsString) \ -- FIELD(TouchEventsOverrideInternal, mozilla::dom::TouchEventsOverride) \ -+ FIELD(TouchEventsOverrideInternal, dom::TouchEventsOverride) \ - FIELD(EmbedderElementType, Maybe) \ - FIELD(MessageManagerGroup, nsString) \ - FIELD(MaxTouchPointsOverride, uint8_t) \ -@@ -253,6 +256,9 @@ struct EmbedderColorSchemes { - * embedder element. */ \ - FIELD(EmbedderColorSchemes, EmbedderColorSchemes) \ - FIELD(DisplayMode, dom::DisplayMode) \ -+ /* playwright addition */ \ -+ FIELD(PrefersReducedMotionOverride, dom::PrefersReducedMotionOverride) \ -+ FIELD(PrefersContrastOverride, dom::PrefersContrastOverride) \ - /* The number of entries added to the session history because of this \ - * browsing context. */ \ - FIELD(HistoryEntryCount, uint32_t) \ -@@ -975,6 +978,14 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - return GetForcedColorsOverride(); - } - -+ dom::PrefersReducedMotionOverride PrefersReducedMotionOverride() const { -+ return GetPrefersReducedMotionOverride(); -+ } -+ -+ dom::PrefersContrastOverride PrefersContrastOverride() const { -+ return GetPrefersContrastOverride(); -+ } -+ - bool IsInBFCache() const; - - bool AllowJavascript() const { return GetAllowJavascript(); } -@@ -1146,6 +1157,11 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - return IsTop(); - } - -+ bool CanSet(FieldIndex, -+ dom::PrefersContrastOverride, ContentParent*) { -+ return IsTop(); -+ } -+ - bool CanSet(FieldIndex, dom::ForcedColorsOverride, - ContentParent*) { - return IsTop(); -@@ -1278,13 +1297,25 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - void DidSet(FieldIndex, - dom::ForcedColorsOverride aOldValue); - -+ void DidSet(FieldIndex, -+ dom::PrefersContrastOverride aOldValue); -+ - template - void WalkPresContexts(Callback&&); - void PresContextAffectingFieldChanged(); - - void DidSet(FieldIndex, nsCString&& aOldValue); - - void DidSet(FieldIndex, nsString&& aOldValue); - -+ bool CanSet(FieldIndex, -+ dom::PrefersReducedMotionOverride, ContentParent*) { -+ return IsTop(); -+ } -+ -+ void DidSet(FieldIndex, -+ dom::PrefersReducedMotionOverride aOldValue); -+ -+ - void DidSet(FieldIndex, nsString&& aOldValue); - - bool CanSet(FieldIndex, bool, ContentParent*) { -@@ -1360,6 +1388,8 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - - void DidSet(FieldIndex, bool aOldValue); - -+ void DidSet(FieldIndex, bool aOldValue); -+ - // Allow if the process attemping to set field is the same as the owning - // process. Deprecated. New code that might use this should generally be moved - // to WindowContext or be settable only by the parent process. -diff --git a/docshell/base/CanonicalBrowsingContext.cpp b/docshell/base/CanonicalBrowsingContext.cpp -index 4953744c3f627bb68b78606d8ae4bf6ab649398a..17c7cc94dafc76cd72aacddfd633b7df58eeae78 100644 ---- a/docshell/base/CanonicalBrowsingContext.cpp -+++ b/docshell/base/CanonicalBrowsingContext.cpp -@@ -274,7 +274,9 @@ void CanonicalBrowsingContext::ReplacedBy( - txn.SetForceOffline(GetForceOffline()); - txn.SetTopInnerSizeForRFP(GetTopInnerSizeForRFP()); - txn.SetIPAddressSpace(GetIPAddressSpace()); -+ txn.SetPrefersReducedMotionOverride(GetPrefersReducedMotionOverride()); -+ txn.SetForcedColorsOverride(GetForcedColorsOverride()); - txn.SetParentalControlsEnabled(GetParentalControlsEnabled()); - - if (!GetLanguageOverride().IsEmpty()) { - // Reapply language override to update the corresponding realm. - txn.SetLanguageOverride(GetLanguageOverride()); - } - if (!GetTimezoneOverride().IsEmpty()) { - // Reapply timezone override to update the corresponding realm. -@@ -1903,6 +1905,12 @@ void CanonicalBrowsingContext::LoadURI(nsIURI* aURI, - return; - } - -+ { -+ nsCOMPtr observerService = mozilla::services::GetObserverService(); -+ if (observerService) { -+ observerService->NotifyObservers(ToSupports(this), "juggler-navigation-started-browser", NS_ConvertASCIItoUTF16(nsPrintfCString("%" PRIu64, loadState->GetLoadIdentifier())).get()); -+ } -+ } - LoadURI(loadState, true); - } - -diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp -index bf702818cf4116ec1cd911b6e7b5f7ddafa3e508..d846e5f6f900d2d69228331b80031bd1c18b08ed 100644 ---- a/docshell/base/nsDocShell.cpp -+++ b/docshell/base/nsDocShell.cpp -@@ -18,6 +18,12 @@ - #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/Attributes.h" - #include "mozilla/AutoRestore.h" - #include "mozilla/BasePrincipal.h" -@@ -67,6 +73,7 @@ - #include "mozilla/dom/DocGroup.h" - #include "mozilla/dom/Element.h" - #include "mozilla/dom/FragmentDirective.h" -+#include "mozilla/dom/Geolocation.h" - #include "mozilla/dom/HTMLAnchorElement.h" - #include "mozilla/dom/HTMLIFrameElement.h" - #include "mozilla/dom/Navigation.h" -@@ -98,6 +105,7 @@ - #include "mozilla/dom/DocumentBinding.h" - #include "mozilla/glean/DocshellMetrics.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" -@@ -122,6 +130,7 @@ - #include "nsIDocumentViewer.h" - #include "mozilla/dom/Document.h" - #include "nsHTMLDocument.h" -+#include "mozilla/dom/Element.h" - #include "nsIDocumentLoaderFactory.h" - #include "nsIDOMWindow.h" - #include "nsIEditingSession.h" -@@ -217,6 +226,7 @@ - #include "nsGlobalWindowInner.h" - #include "nsGlobalWindowOuter.h" - #include "nsJSEnvironment.h" -+#include "nsJSUtils.h" - #include "nsNetCID.h" - #include "nsNetUtil.h" - #include "nsObjectLoadingContent.h" -@@ -358,6 +368,14 @@ nsDocShell::nsDocShell(BrowsingContext* aBrowsingContext, - mAllowDNSPrefetch(true), - mAllowWindowControl(true), - mCSSErrorReportingEnabled(false), -+ mFileInputInterceptionEnabled(false), -+ mOverrideHasFocus(false), -+ mBypassCSPEnabled(false), -+ mForceActiveState(false), -+ mDisallowBFCache(false), -+ mReducedMotionOverride(REDUCED_MOTION_OVERRIDE_NONE), -+ mForcedColorsOverride(FORCED_COLORS_OVERRIDE_NO_OVERRIDE), -+ mContrastOverride(CONTRAST_OVERRIDE_NONE), - mAllowAuth(mItemType == typeContent), - mAllowKeywordFixup(false), - mDisableMetaRefreshWhenInactive(false), -@@ -3037,6 +3055,232 @@ nsDocShell::GetMessageManager(ContentFrameMessageManager** aMessageManager) { - return NS_OK; - } - -+// =============== Juggler Begin ======================= -+ -+nsDocShell* nsDocShell::GetRootDocShell() { -+ nsCOMPtr rootAsItem; -+ GetInProcessSameTypeRootTreeItem(getter_AddRefs(rootAsItem)); -+ nsCOMPtr 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; -+} -+ -+NS_IMETHODIMP -+nsDocShell::GetDisallowBFCache(bool* aEnabled) { -+ MOZ_ASSERT(aEnabled); -+ *aEnabled = mDisallowBFCache; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetDisallowBFCache(bool aEnabled) { -+ mDisallowBFCache = aEnabled; -+ 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) { -+ 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 observerService = -+ mozilla::services::GetObserverService(); -+ observerService->NotifyObservers( -+ ToSupports(element), "juggler-file-picker-shown", nullptr); -+} -+ -+RefPtr 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::GetReducedMotionOverride(ReducedMotionOverride* aReducedMotionOverride) { -+ *aReducedMotionOverride = GetRootDocShell()->mReducedMotionOverride; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetReducedMotionOverride(ReducedMotionOverride aReducedMotionOverride) { -+ mReducedMotionOverride = aReducedMotionOverride; -+ RefPtr 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 presContext = GetPresContext(); -+ if (presContext) { -+ presContext->MediaFeatureValuesChanged( -+ {MediaFeatureChangeReason::SystemMetricsChange}, -+ MediaFeatureChangePropagation::JustThisDocument); -+ } -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::GetContrastOverride(ContrastOverride* aContrastOverride) { -+ *aContrastOverride = GetRootDocShell()->mContrastOverride; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetContrastOverride(ContrastOverride aContrastOverride) { -+ mContrastOverride = aContrastOverride; -+ RefPtr presContext = GetPresContext(); -+ if (presContext) { -+ presContext->MediaFeatureValuesChanged( -+ {MediaFeatureChangeReason::SystemMetricsChange}, -+ MediaFeatureChangePropagation::JustThisDocument); -+ } -+ return NS_OK; -+} -+ -+// =============== Juggler End ======================= -+ - NS_IMETHODIMP - nsDocShell::GetIsNavigating(bool* aOut) { - *aOut = mIsNavigating; -@@ -4819,7 +5063,7 @@ nsDocShell::GetVisibility(bool* aVisibility) { - } - - void nsDocShell::ActivenessMaybeChanged() { -- const bool isActive = mBrowsingContext->IsActive(); -+ const bool isActive = mForceActiveState || mBrowsingContext->IsActive(); - if (RefPtr presShell = GetPresShell()) { - presShell->ActivenessMaybeChanged(); - } -@@ -6881,6 +7125,10 @@ bool nsDocShell::CanSavePresentation(uint32_t aLoadType, - return false; // no entry to save into - } - -+ if (mDisallowBFCache) { -+ return false; -+ } -+ - MOZ_ASSERT(!mozilla::SessionHistoryInParent(), - "mOSHE cannot be non-null with SHIP"); - nsCOMPtr viewer = mOSHE->GetDocumentViewer(); -@@ -8637,6 +8885,12 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState) { - true, // aForceNoOpener - getter_AddRefs(newBC)); - MOZ_ASSERT(!newBC); -+ if (rv == NS_OK) { -+ nsCOMPtr observerService = mozilla::services::GetObserverService(); -+ if (observerService) { -+ observerService->NotifyObservers(GetAsSupports(this), "juggler-window-open-in-new-context", nullptr); -+ } -+ } - return rv; - } - -@@ -9934,6 +10188,16 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState, - nsINetworkPredictor::PREDICT_LOAD, attrs, nullptr); - - nsCOMPtr req; -+ -+ // Juggler: report navigation started for non-same-document and non-javascript -+ // navigations. -+ if (!isJavaScript && !sameDocument) { -+ nsCOMPtr observerService = -+ mozilla::services::GetObserverService(); -+ if (observerService) { -+ observerService->NotifyObservers(GetAsSupports(this), "juggler-navigation-started-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("%" PRIu64, aLoadState->GetLoadIdentifier())).get()); -+ } -+ } - rv = DoURILoad(aLoadState, aCacheKey, getter_AddRefs(req)); - - if (NS_SUCCEEDED(rv)) { -@@ -13323,6 +13587,9 @@ class OnLinkClickEvent : public Runnable { - mHandler->OnLinkClickSync(mContent, mLoadState, mNoOpenerImplied, - mTriggeringPrincipal); - } -+ nsCOMPtr observerService = mozilla::services::GetObserverService(); -+ observerService->NotifyObservers(ToSupports(mContent), "juggler-link-click-sync", nullptr); -+ - return NS_OK; - } - -@@ -13439,6 +13706,8 @@ nsresult nsDocShell::OnLinkClick( - - nsCOMPtr ev = new OnLinkClickEvent( - this, aContent, loadState, noOpenerImplied, aTriggeringPrincipal); -+ nsCOMPtr observerService = mozilla::services::GetObserverService(); -+ observerService->NotifyObservers(ToSupports(aContent), "juggler-link-click", nullptr); - return Dispatch(ev.forget()); - } - -diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h -index 3050f0a5a10c7f49f56cf325cd8bfe5e6508b5be..a4f4895f69a2eaa55f3eeae77bd6a3fb29931ad4 100644 ---- a/docshell/base/nsDocShell.h -+++ b/docshell/base/nsDocShell.h -@@ -16,6 +16,7 @@ - #include "mozilla/WeakPtr.h" - #include "mozilla/dom/BrowsingContext.h" - #include "mozilla/dom/NavigationBinding.h" -+#include "mozilla/dom/Element.h" - #include "mozilla/dom/WindowProxyHolder.h" - #include "nsCOMPtr.h" - #include "nsCharsetSource.h" -@@ -80,6 +81,7 @@ class nsCommandManager; - class nsDocShellEditorData; - class nsDOMNavigationTiming; - class nsDSURIContentListener; -+class nsGeolocationService; - class nsGlobalWindowOuter; - - class FramingChecker; -@@ -410,6 +412,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 GetGeolocationServiceOverride(); -+ - // Create a content viewer within this nsDocShell for the given - // `WindowGlobalChild` actor. - nsresult CreateDocumentViewerForActor( -@@ -1036,6 +1047,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 -@@ -1355,6 +1368,17 @@ 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; -+ bool mDisallowBFCache : 1; -+ nsString mLanguageOverride; -+ RefPtr mGeolocationServiceOverride; -+ ReducedMotionOverride mReducedMotionOverride; -+ ForcedColorsOverride mForcedColorsOverride; -+ ContrastOverride mContrastOverride; -+ - bool mAllowAuth : 1; - bool mAllowKeywordFixup : 1; - bool mDisableMetaRefreshWhenInactive : 1; -diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl -index 763c7adb5ab9e3e56d6f1608899f6622997f272a..4f77795b5ce1f8fff79581987e017165dbdcbc1e 100644 ---- a/docshell/base/nsIDocShell.idl -+++ b/docshell/base/nsIDocShell.idl -@@ -44,6 +44,7 @@ interface nsIURI; - interface nsIChannel; - interface nsIPolicyContainer; - interface nsIDocumentViewer; -+interface nsIDOMGeoPosition; - interface nsIEditor; - interface nsIEditingSession; - interface nsIInputStream; -@@ -719,6 +720,45 @@ interface nsIDocShell : nsIDocShellTreeItem - */ - void synchronizeLayoutHistoryState(); - -+ attribute boolean fileInputInterceptionEnabled; -+ -+ attribute boolean overrideHasFocus; -+ -+ attribute boolean bypassCSPEnabled; -+ -+ attribute boolean forceActiveState; -+ -+ attribute boolean disallowBFCache; -+ -+ attribute AString languageOverride; -+ -+ boolean overrideTimezone(in AString timezoneId); -+ -+ 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; -+ -+ cenum ContrastOverride : 8 { -+ CONTRAST_OVERRIDE_LESS, -+ CONTRAST_OVERRIDE_MORE, -+ CONTRAST_OVERRIDE_CUSTOM, -+ CONTRAST_OVERRIDE_NO_PREFERENCE, -+ CONTRAST_OVERRIDE_NONE, /* This clears the override. */ -+ }; -+ [infallible] attribute nsIDocShell_ContrastOverride contrastOverride; -+ -+ 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 40da41ae4ac7d8d61c664e25bec8a74091d8b3e0..50ee1170e6d5b261334c7baccc63ed492b86ec38 100644 ---- a/dom/base/Document.cpp -+++ b/dom/base/Document.cpp -@@ -3799,6 +3799,9 @@ void Document::SendToConsole(nsCOMArray& aMessages) { - } - - void Document::ApplySettingsFromCSP(bool aSpeculative) { -+ if (mDocumentContainer && mDocumentContainer->IsBypassCSPEnabled()) -+ return; -+ - nsresult rv = NS_OK; - if (!aSpeculative) { - nsIContentSecurityPolicy* csp = PolicyContainer::GetCSP(mPolicyContainer); -@@ -3887,6 +3890,11 @@ nsresult Document::InitCSP(nsIChannel* aChannel) { - MOZ_ASSERT(mPolicyContainer, - "Policy container must be initialized before CSP!"); - -+ nsCOMPtr 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; -@@ -4753,6 +4761,10 @@ bool Document::HasFocus(ErrorResult& rv) const { - return false; - } - -+ if (IsActive() && mDocumentContainer->ShouldOverrideHasFocus()) { -+ return true; -+ } -+ - if (!fm->IsInActiveWindow(bc)) { - return false; - } -@@ -20326,6 +20338,35 @@ ColorScheme Document::PreferredColorScheme(IgnoreRFP aIgnoreRFP) const { - return PreferenceSheet::PrefsFor(*this).mColorScheme; - } - -+bool Document::PrefersReducedMotion() const { -+ auto* docShell = static_cast(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: -+ break; -+ } -+ } -+ -+ return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1; -+} -+ - bool Document::HasRecentlyStartedForegroundLoads() { - if (!sLoadingForegroundTopLevelContentDocument) { - return false; -diff --git a/dom/base/Document.h b/dom/base/Document.h -index 20f726a52f9f3591502597e20eeb8c07fe35feb2..c46f58ac88d536850169e6c51b9cfcb871d36e70 100644 ---- a/dom/base/Document.h -+++ b/dom/base/Document.h -@@ -4252,6 +4252,8 @@ class Document : public nsINode, - // color-scheme meta tag. - ColorScheme DefaultColorScheme() const; - -+ bool PrefersReducedMotion() const; -+ - static bool HasRecentlyStartedForegroundLoads(); - - static bool AutomaticStorageAccessPermissionCanBeGranted( -diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp -index 11a57adbb57b0adccf7ae491e7d7757f838bd9dc..e478244cedc2089fb99b3153d7493b7d36d72ea9 100644 ---- a/dom/base/Navigator.cpp -+++ b/dom/base/Navigator.cpp -@@ -347,14 +347,18 @@ void Navigator::GetAppName(nsAString& aAppName) const { - * for more detail. - */ - /* static */ --void Navigator::GetAcceptLanguages(nsTArray& aLanguages) { -+void Navigator::GetAcceptLanguages(const nsString* aLanguageOverride, nsTArray& 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 : -@@ -406,7 +410,13 @@ void Navigator::GetLanguage(nsAString& aLanguage) { - } - - void Navigator::GetLanguages(nsTArray& aLanguages) { -- GetAcceptLanguages(aLanguages); -+ if (mWindow && mWindow->GetDocShell()) { -+ nsString languageOverride; -+ mWindow->GetDocShell()->GetLanguageOverride(languageOverride); -+ GetAcceptLanguages(&languageOverride, aLanguages); -+ } else { -+ GetAcceptLanguages(nullptr, aLanguages); -+ } - - @@ -2336,6 +2336,7 @@ bool Navigator::Webdriver() { - } - #endif - -- return false; -+ // Playwright is automating the browser, so we should pretend to be a webdriver -+ return true; - } - - AutoplayPolicy Navigator::GetAutoplayPolicy(AutoplayPolicyMediaType aType) { -diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h -index 893947475fbb8688becb1c1495385e4048d4927d..dfb50acf689223fdab7ef6f42afbbd53341e1b0b 100644 ---- a/dom/base/Navigator.h -+++ b/dom/base/Navigator.h -@@ -228,7 +228,7 @@ class Navigator final : public nsISupports, public nsWrapperCache { - - StorageManager* Storage(); - -- static void GetAcceptLanguages(nsTArray& aLanguages); -+ static void GetAcceptLanguages(const nsString* aLanguageOverride, nsTArray& aLanguages); - - dom::MediaCapabilities* MediaCapabilities(); - dom::MediaSession* MediaSession(); -diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp -index 7703ab18c104848eab9377769641d3b60e9bcf8e..3028fc5a7e6c54a7f4455f135e889d038eed378d 100644 ---- a/dom/base/nsContentUtils.cpp -+++ b/dom/base/nsContentUtils.cpp -@@ -9528,11 +9528,13 @@ nsresult nsContentUtils::SendMouseEvent( - int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, - float aPressure, unsigned short aInputSourceArg, uint32_t aIdentifier, - bool aToWindow, bool* aPreventDefault, bool aIsDOMEventSynthesized, -- bool aIsWidgetEventSynthesized) { -+ bool aIsWidgetEventSynthesized, -+ bool convertToPointer, uint32_t aJugglerEventId) { - MOZ_ASSERT(aWidget); - EventMessage msg; - Maybe exitFrom; - bool contextMenuKey = false; -+ bool isPWDragEventMessage = false; - if (aType.EqualsLiteral("mousedown")) { - msg = eMouseDown; - } else if (aType.EqualsLiteral("mouseup")) { -@@ -9558,6 +9560,12 @@ nsresult nsContentUtils::SendMouseEvent( - msg = eMouseHitTest; - } else if (aType.EqualsLiteral("MozMouseExploreByTouch")) { - msg = eMouseExploreByTouch; -+ } else if (aType.EqualsLiteral("dragover")) { -+ msg = eDragOver; -+ isPWDragEventMessage = true; -+ } else if (aType.EqualsLiteral("drop")) { -+ msg = eDrop; -+ isPWDragEventMessage = true; - } else { - return NS_ERROR_FAILURE; - } -@@ -9568,7 +9576,14 @@ nsresult nsContentUtils::SendMouseEvent( - - Maybe pointerEvent; - Maybe mouseEvent; -- if (IsPointerEventMessage(msg)) { -+ Maybe pwDragEvent; -+ -+ if (isPWDragEventMessage) { -+ pwDragEvent.emplace(true, msg, aWidget); -+ pwDragEvent->mReason = aIsWidgetEventSynthesized -+ ? WidgetMouseEvent::eSynthesized -+ : WidgetMouseEvent::eReal; -+ } else if (IsPointerEventMessage(msg)) { - MOZ_ASSERT(!aIsWidgetEventSynthesized, - "The event shouldn't be dispatched as a synthesized event"); - if (MOZ_UNLIKELY(aIsWidgetEventSynthesized)) { -@@ -9587,8 +9602,11 @@ nsresult nsContentUtils::SendMouseEvent( - contextMenuKey ? WidgetMouseEvent::eContextMenuKey - : WidgetMouseEvent::eNormal); - } -+ - WidgetMouseEvent& mouseOrPointerEvent = -+ pwDragEvent.isSome() ? pwDragEvent.ref() : - pointerEvent.isSome() ? pointerEvent.ref() : mouseEvent.ref(); -+ - mouseOrPointerEvent.pointerId = aIdentifier; - mouseOrPointerEvent.mModifiers = GetWidgetModifiers(aModifiers); - mouseOrPointerEvent.mButton = aButton; -@@ -9601,6 +9619,8 @@ nsresult nsContentUtils::SendMouseEvent( - mouseOrPointerEvent.mClickCount = aClickCount; - mouseOrPointerEvent.mFlags.mIsSynthesizedForTests = aIsDOMEventSynthesized; - mouseOrPointerEvent.mExitFrom = exitFrom; -+ mouseOrPointerEvent.mJugglerEventId = aJugglerEventId; -+ mouseOrPointerEvent.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 a1b96bce18e1904f4068057defa26142ebe8874b..f2fc14da57cf08139723980dedc33f2d3a9a431b 100644 ---- a/dom/base/nsContentUtils.h -+++ b/dom/base/nsContentUtils.h -@@ -3080,8 +3080,9 @@ class nsContentUtils { - int32_t aButton, int32_t aButtons, int32_t aClickCount, - int32_t aModifiers, bool aIgnoreRootScrollFrame, float aPressure, - unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow, -- bool* aPreventDefault, bool aIsDOMEventSynthesized, -- bool aIsWidgetEventSynthesized); -+ bool* aPreventDefault, -+ bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized, -+ bool convertToPointer = true, uint32_t aJugglerEventId = 0); - - static void FirePageShowEventForFrameLoaderSwap( - nsIDocShellTreeItem* aItem, -diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp -index c6c5833cd29ef041da348d4398513bab7ef2f9aa..424cc396bfc211bc7debb3df203cfa26da7a4c55 100644 ---- a/dom/base/nsDOMWindowUtils.cpp -+++ b/dom/base/nsDOMWindowUtils.cpp -@@ -707,6 +707,26 @@ nsDOMWindowUtils::GetPresShellId(uint32_t* aPresShellId) { - return NS_ERROR_FAILURE; - } - -+static uint32_t sJugglerEventId = 1000; -+ -+NS_IMETHODIMP -+nsDOMWindowUtils::JugglerSendMouseEvent( -+ const nsAString& aType, float aX, float aY, int32_t aButton, -+ int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, -+ float aPressure, unsigned short aInputSourceArg, -+ bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized, -+ int32_t aButtons, uint32_t aIdentifier, bool aDisablePointerEvent, -+ uint32_t* aJugglerEventId) { -+ *aJugglerEventId = ++sJugglerEventId; -+ return SendMouseEventCommon( -+ aType, aX, aY, aButton, aClickCount, aModifiers, aIgnoreRootScrollFrame, -+ aPressure, aInputSourceArg, -+ aIdentifier, false, -+ nullptr, aIsDOMEventSynthesized, -+ aIsWidgetEventSynthesized, -+ aButtons, !aDisablePointerEvent, *aJugglerEventId); -+} -+ - NS_IMETHODIMP - nsDOMWindowUtils::SendMouseEvent( - const nsAString& aType, float aX, float aY, int32_t aButton, -@@ -721,7 +741,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, true, 0); - } - - NS_IMETHODIMP -@@ -739,7 +759,7 @@ nsDOMWindowUtils::SendMouseEventToWindow( - aOptionalArgCount >= 7 ? aIdentifier : DEFAULT_MOUSE_POINTER_ID, true, - nullptr, aOptionalArgCount >= 4 ? aIsDOMEventSynthesized : true, - aOptionalArgCount >= 5 ? aIsWidgetEventSynthesized : false, -- aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED); -+ aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED, 0); - } - - NS_IMETHODIMP -@@ -748,7 +768,7 @@ 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, uint32_t aJugglerEventId) { - RefPtr presShell = GetPresShell(); - if (!presShell) { - return NS_ERROR_FAILURE; -@@ -765,7 +785,7 @@ nsDOMWindowUtils::SendMouseEventCommon( - presShell, widget, aType, refPoint, aButton, aButtons, aClickCount, - aModifiers, aIgnoreRootScrollFrame, aPressure, aInputSourceArg, - aPointerId, aToWindow, aPreventDefault, aIsDOMEventSynthesized, -- aIsWidgetEventSynthesized); -+ aIsWidgetEventSynthesized, aConvertToPointer, aJugglerEventId); - } - - NS_IMETHODIMP -diff --git a/dom/base/nsDOMWindowUtils.h b/dom/base/nsDOMWindowUtils.h -index 4553ad5e7696055e861be5f840f8ce2bc54a5b29..1afc16325fcb63a3e510bdc387c8386eccf5d48b 100644 ---- a/dom/base/nsDOMWindowUtils.h -+++ b/dom/base/nsDOMWindowUtils.h -@@ -94,7 +94,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, uint32_t aJugglerEventId = 0); - - MOZ_CAN_RUN_SCRIPT - nsresult SendTouchEventCommon( -diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp -index 62c4bfb96dbb6e64aeadd9e45c296905b7956811..83f1e7303e2ebabfc73921d9bd27a255304a2ea4 100644 ---- a/dom/base/nsFocusManager.cpp -+++ b/dom/base/nsFocusManager.cpp -@@ -1717,6 +1717,10 @@ Maybe nsFocusManager::SetFocusInner(Element* aNewContent, - (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)) { -@@ -2303,6 +2307,7 @@ bool nsFocusManager::BlurImpl(BrowsingContext* aBrowsingContextToClear, - bool aIsLeavingDocument, bool aAdjustWidget, - bool aRemainActive, Element* aElementToFocus, - uint64_t aActionId) { -+ - LOGFOCUS(("<>", aActionId)); - - // hold a reference to the focused content, which may be null -@@ -2346,6 +2351,11 @@ bool nsFocusManager::BlurImpl(BrowsingContext* aBrowsingContextToClear, - return true; - } - -+ // Playwright: emulate focused page by never bluring when leaving document. -+ if (XRE_IsContentProcess() && aIsLeavingDocument && docShell && nsDocShell::Cast(docShell)->ShouldOverrideHasFocus()) { -+ return true; -+ } -+ - // Keep a ref to presShell since dispatching the DOM event may cause - // the document to be destroyed. - RefPtr presShell = docShell->GetPresShell(); -@@ -3046,7 +3056,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 5e2844f6e65da71ca9e1dadb1a88a74ab45f485c..a8f033e17ffbc28261072d561c89914d4bd2e325 100644 ---- a/dom/base/nsGlobalWindowOuter.cpp -+++ b/dom/base/nsGlobalWindowOuter.cpp -@@ -2511,10 +2511,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)); -+ } - } - } - -@@ -2634,6 +2640,19 @@ void nsGlobalWindowOuter::DispatchDOMWindowCreated() { - } - } - -+void nsGlobalWindowOuter::JugglerDispatchDOMWindowReused() { -+ nsCOMPtr observerService = -+ mozilla::services::GetObserverService(); -+ if (observerService && mDoc) { -+ nsIPrincipal* principal = mDoc->NodePrincipal(); -+ if (!principal->IsSystemPrincipal()) { -+ observerService->NotifyObservers(static_cast(this), -+ "juggler-dom-window-reused", -+ nullptr); -+ } -+ } -+} -+ - void nsGlobalWindowOuter::ClearStatus() { SetStatusOuter(u""_ns); } - - void nsGlobalWindowOuter::SetDocShell(nsDocShell* aDocShell) { -diff --git a/dom/base/nsGlobalWindowOuter.h b/dom/base/nsGlobalWindowOuter.h -index 1fbb506b07714f9ab2a2c9aff3683aa7fec4b156..42878f8f0c6365c7e2958a3b35fce0e7db9abfff 100644 ---- a/dom/base/nsGlobalWindowOuter.h -+++ b/dom/base/nsGlobalWindowOuter.h -@@ -318,6 +318,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 7b8da8b4a5e8de02d0d2e1befc8407da88fbf890..533f3bf77e1ef78dd231ac899e3d8032938ea812 100644 ---- a/dom/base/nsINode.cpp -+++ b/dom/base/nsINode.cpp -@@ -1500,6 +1500,61 @@ void nsINode::GetBoxQuadsFromWindowOrigin(const BoxQuadOptions& aOptions, - mozilla::GetBoxQuadsFromWindowOrigin(this, aOptions, aResult, aRv); - } - -+static nsIFrame* GetFirstFrame(nsINode* aNode) { -+ if (!aNode->IsContent()) -+ return nullptr; -+ nsIFrame* frame = aNode->AsContent()->GetPrimaryFrame(FlushType::Frames); -+ if (!frame) { -+ FlattenedChildIterator iter(aNode->AsContent()); -+ for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { -+ frame = child->GetPrimaryFrame(FlushType::Frames); -+ if (frame) { -+ break; -+ } -+ } -+ } -+ return frame; -+} -+ -+void nsINode::ScrollRectIntoViewIfNeeded(int32_t x, int32_t y, -+ int32_t w, int32_t h, -+ ErrorResult& aRv) { -+ aRv = NS_ERROR_UNEXPECTED; -+ nsCOMPtr 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"); -+ } -+ nsIFrame* primaryFrame = GetFirstFrame(this); -+ if (!primaryFrame) { -+ return aRv.ThrowNotFoundError("Node does not have a layout object"); -+ } -+ aRv = NS_OK; -+ 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->ScrollFrameIntoView( -+ primaryFrame, Some(rect), -+ ScrollAxis(WhereToScroll::Center, WhenToScroll::IfNotFullyVisible), -+ ScrollAxis(WhereToScroll::Center, WhenToScroll::IfNotFullyVisible), -+ 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 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 c3d84856e1bc92caf0437be312ccdbf7a2726ba5..d81c8e7152ca79b0fbb1ebee0f6f3aa40d0f34e2 100644 ---- a/dom/base/nsINode.h -+++ b/dom/base/nsINode.h -@@ -2421,6 +2421,10 @@ class nsINode : public mozilla::dom::EventTarget { - nsTArray>& aResult, - ErrorResult& aRv); - -+ void ScrollRectIntoViewIfNeeded(int32_t x, int32_t y, -+ int32_t w, int32_t h, -+ ErrorResult& aRv); -+ - already_AddRefed ConvertQuadFromNode( - DOMQuad& aQuad, const TextOrElementOrDocument& aFrom, - const ConvertCoordinateOptions& aOptions, CallerType aCallerType, -diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp -index aed59277e27a5a90f4244dd4513f9b4feb5858c3..26750fa09bead1ffabb22482468dea5999899f18 100644 ---- a/dom/base/nsJSUtils.cpp -+++ b/dom/base/nsJSUtils.cpp -@@ -151,6 +151,11 @@ bool nsJSUtils::GetEnvironmentChainForElement(JSContext* aCx, Element* aElement, - 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 f32e21752d5013bf143eb45391ab9218debab08e..83763d2354dade2f8d2b7930ba18ae91c55133ad 100644 ---- a/dom/base/nsJSUtils.h -+++ b/dom/base/nsJSUtils.h -@@ -75,6 +75,7 @@ class nsJSUtils { - mozilla::dom::Element* aElement, - JS::EnvironmentChain& aEnvChain); - -+ 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 6d150cc3ad77f694af5aa943c60eac37ba0733c0..9e68e18601cfb3e9e9c03b4bf0057c1a3d50a9d5 100644 ---- a/dom/chrome-webidl/BrowsingContext.webidl -+++ b/dom/chrome-webidl/BrowsingContext.webidl -@@ -62,6 +62,26 @@ enum ForcedColorsOverride { - "active", - }; - -+/** -+ * CSS prefers-reduced-motion values. -+ */ -+enum PrefersReducedMotionOverride { -+ "none", -+ "reduce", -+ "no-preference", -+}; -+ -+/** -+ * CSS prefers-contrast values. -+ */ -+enum PrefersContrastOverride { -+ "none", -+ "no-preference", -+ "more", -+ "less", -+ "custom", -+}; -+ - /** - * Allowed overrides of platform/pref default behaviour for touch events. - */ -@@ -228,6 +248,12 @@ interface BrowsingContext { - // Forced-colors simulation, for DevTools - [SetterThrows] attribute ForcedColorsOverride forcedColorsOverride; - -+ // Reduced-Motion simulation, for DevTools. -+ [SetterThrows] attribute PrefersReducedMotionOverride prefersReducedMotionOverride; -+ -+ // Contrast simulation, for DevTools. -+ [SetterThrows] attribute PrefersContrastOverride prefersContrastOverride; -+ - /** - * 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/fetch/Fetch.cpp b/dom/fetch/Fetch.cpp -index 52cf33bfc863d5ef1d3ac889ddfba3023600d60a..ccb521f367b8ccc8c40d8bad78aa621ab1b074c0 100644 ---- a/dom/fetch/Fetch.cpp -+++ b/dom/fetch/Fetch.cpp -@@ -704,6 +704,12 @@ already_AddRefed FetchRequest(nsIGlobalObject* aGlobal, - ipcArgs.hasCSPEventListener() = false; - ipcArgs.isWorkerRequest() = false; - -+ /* --> Playwright: associate keep-alive fetch with the window */ -+ BrowsingContext* bc = window ? window->GetBrowsingContext() : nullptr; -+ if (bc) -+ ipcArgs.associatedBrowsingContextID() = bc->Id(); -+ /* <-- Playwright */ -+ - actor->DoFetchOp(ipcArgs); - - mozilla::glean::networking::fetch_keepalive_request_count.Get("main"_ns) -diff --git a/dom/fetch/FetchService.cpp b/dom/fetch/FetchService.cpp -index 1734429e8eeb155b742211ca58afcbeb73a8bf7c..15635a2e5c266f8085093a0d17288abe8ed54d9e 100644 ---- a/dom/fetch/FetchService.cpp -+++ b/dom/fetch/FetchService.cpp -@@ -268,6 +268,14 @@ RefPtr FetchService::FetchInstance::Fetch() { - net::ClassificationFlags({0, 0}) // TrackingFlags - ); - -+ /* --> Playwright: associate keep-alive fetch with the window */ -+ if (mArgsType == FetchArgsType::MainThreadFetch) { -+ auto& args = mArgs.as(); -+ mFetchDriver->SetAssociatedBrowsingContextID( -+ args.mAssociatedBrowsingContextID); -+ } -+ /* <-- Playwright */ -+ - if (mArgsType == FetchArgsType::WorkerFetch) { - auto& args = mArgs.as(); - mFetchDriver->SetWorkerScript(args.mWorkerScript); -diff --git a/dom/geolocation/Geolocation.cpp b/dom/geolocation/Geolocation.cpp -index 70ce9ce97c6d0ccba8b4129c55079cf9122e5b17..1c503c68c2c0949cfdaa18a76a263a81807952e1 100644 ---- a/dom/geolocation/Geolocation.cpp -+++ b/dom/geolocation/Geolocation.cpp -@@ -394,7 +394,10 @@ nsGeolocationRequest::Allow(JS::Handle aChoices) { - return NS_OK; - } - -- if (mBehavior != SystemGeolocationPermissionBehavior::NoPrompt) { -+ RefPtr gs = nsGeolocationService::GetGeolocationService( -+ mLocator->GetBrowsingContext()); -+ -+ if (mBehavior != SystemGeolocationPermissionBehavior::NoPrompt && !gs->IsOverride()) { - // Asynchronously present the system dialog or open system preferences - // (RequestGeolocationPermissionFromUser will know which to do), and wait - // for the permission to change or the request to be canceled. If the -@@ -426,8 +429,6 @@ nsGeolocationRequest::Allow(JS::Handle aChoices) { - return NS_OK; - } - -- RefPtr gs = nsGeolocationService::GetGeolocationService( -- mLocator->GetBrowsingContext()); - bool canUseCache = false; - CachedPositionAndAccuracy lastPosition = gs->GetCachedPosition(); - if (lastPosition.position) { -@@ -710,11 +711,16 @@ NS_INTERFACE_MAP_END - NS_IMPL_ADDREF(nsGeolocationService) - NS_IMPL_RELEASE(nsGeolocationService) - --nsresult nsGeolocationService::Init() { -+nsresult nsGeolocationService::Init(bool isOverride) { - if (!StaticPrefs::geo_enabled()) { - return NS_ERROR_FAILURE; - } - -+ if (isOverride) { -+ mIsOverride = true; -+ mHigherAccuracy = true; -+ } -+ - if (XRE_IsContentProcess()) { - return NS_OK; - } -@@ -793,6 +799,10 @@ nsresult nsGeolocationService::Init() { - return NS_OK; - } - -+bool nsGeolocationService::IsOverride() { -+ return mIsOverride; -+} -+ - nsGeolocationService::~nsGeolocationService() = default; - - NS_IMETHODIMP -@@ -936,6 +946,10 @@ bool nsGeolocationService::HighAccuracyRequested() { - } - - void nsGeolocationService::UpdateAccuracy(bool aForceHigh) { -+ if (mIsOverride) { -+ return; -+ } -+ - bool highRequired = aForceHigh || HighAccuracyRequested(); - - if (XRE_IsContentProcess()) { -diff --git a/dom/geolocation/Geolocation.h b/dom/geolocation/Geolocation.h -index 57814242d551774e81403b7fdc20c795deadb625..c48c1b19a8d5499784ffb7b50d5e88e40c7b2a05 100644 ---- a/dom/geolocation/Geolocation.h -+++ b/dom/geolocation/Geolocation.h -@@ -67,7 +67,7 @@ class nsGeolocationService final : public nsIGeolocationUpdate, - - nsGeolocationService() = default; - -- nsresult Init(); -+ nsresult Init(bool isOverride = false); - - // Management of the Geolocation objects - void AddLocator(mozilla::dom::Geolocation* aLocator); -@@ -92,6 +92,8 @@ class nsGeolocationService final : public nsIGeolocationUpdate, - void UpdateAccuracy(bool aForceHigh = false); - bool HighAccuracyRequested(); - -+ bool IsOverride(); -+ - private: - ~nsGeolocationService(); - -@@ -118,6 +120,8 @@ class nsGeolocationService final : public nsIGeolocationUpdate, - // Nothing() if not being started, or a boolean reflecting the requested - // accuracy. - mozilla::Maybe mStarting; -+ -+ bool mIsOverride = false; - }; - - namespace mozilla::dom { -diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp -index 5b0228d4a61dfe2b95e7a3ce016217007e8dee12..b753b0fceeec3278cb026d9137aafab5fb6ef968 100644 ---- a/dom/html/HTMLInputElement.cpp -+++ b/dom/html/HTMLInputElement.cpp -@@ -45,6 +45,7 @@ - #include "mozilla/dom/GetFilesHelper.h" - #include "mozilla/dom/HTMLDataListElement.h" - #include "mozilla/dom/HTMLOptionElement.h" -+#include "nsDocShell.h" - #include "mozilla/dom/InputType.h" - #include "mozilla/dom/MouseEvent.h" - #include "mozilla/dom/MutationEventBinding.h" -@@ -842,6 +843,13 @@ nsresult HTMLInputElement::InitFilePicker(FilePickerType aType) { - return NS_ERROR_FAILURE; - } - -+ nsCOMPtr win = doc->GetWindow(); -+ nsDocShell* docShell = win ? static_cast(win->GetDocShell()) : nullptr; -+ if (docShell && docShell->IsFileInputInterceptionEnabled()) { -+ docShell->FilePickerShown(this); -+ return NS_OK; -+ } -+ - if (IsPickerBlocked(doc)) { - return NS_OK; - } -diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl -index 64a2dad65911395ea7eb8ded3374ae6bdd31cf3c..e333c802f8a9232e58d963e05187c0a1b30948f5 100644 ---- a/dom/interfaces/base/nsIDOMWindowUtils.idl -+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl -@@ -390,6 +390,26 @@ cenum AsyncEnabledOption : 8 { - ASYNC_ENABLED = 1 - }; - -+ /** -+ * Playwright: a separate method to dispatch mouse event with a -+ * specific `jugglerEventId`. -+ */ -+ [can_run_script] -+ unsigned long jugglerSendMouseEvent(in AString aType, -+ in float aX, -+ in float aY, -+ in long aButton, -+ in long aClickCount, -+ in long aModifiers, -+ in boolean aIgnoreRootScrollFrame, -+ in float aPressure, -+ in unsigned short aInputSourceArg, -+ in boolean aIsDOMEventSynthesized, -+ in boolean aIsWidgetEventSynthesized, -+ in long aButtons, -+ in unsigned long aIdentifier, -+ in boolean aDisablePointerEvent); -+ - /** Synthesize a touch event. The event types supported are: - * touchstart, touchend, touchmove, and touchcancel - * -diff --git a/dom/ipc/BrowserChild.cpp b/dom/ipc/BrowserChild.cpp -index 780550d573644bcfe4a9bc03243aa4559a62d979..9ed69194ef329aad1e8a3e2c06041a443e4bc6ba 100644 ---- a/dom/ipc/BrowserChild.cpp -+++ b/dom/ipc/BrowserChild.cpp -@@ -1744,6 +1744,21 @@ void BrowserChild::HandleRealMouseButtonEvent(const WidgetMouseEvent& aEvent, - if (postLayerization) { - postLayerization->Register(); - } -+ -+ // Playwright: notify content that mouse event has been received and handled. -+ nsCOMPtr observerService = -+ mozilla::services::GetObserverService(); -+ if (observerService && aEvent.mJugglerEventId) { -+ if (aEvent.mMessage == eMouseUp) { -+ observerService->NotifyObservers(nullptr, "juggler-mouse-event-hit-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("mouseup %" PRIu32, aEvent.mJugglerEventId)).get()); -+ } else if (aEvent.mMessage == eMouseDown) { -+ observerService->NotifyObservers(nullptr, "juggler-mouse-event-hit-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("mousedown %" PRIu32, aEvent.mJugglerEventId)).get()); -+ } else if (aEvent.mMessage == eMouseMove) { -+ observerService->NotifyObservers(nullptr, "juggler-mouse-event-hit-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("mousemove %" PRIu32, aEvent.mJugglerEventId)).get()); -+ } else if (aEvent.mMessage == eContextMenu) { -+ observerService->NotifyObservers(nullptr, "juggler-mouse-event-hit-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("contextmenu %" PRIu32, aEvent.mJugglerEventId)).get()); -+ } -+ } - } - - mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealMouseButtonEvent( -diff --git a/dom/ipc/CoalescedMouseData.cpp b/dom/ipc/CoalescedMouseData.cpp -index 83aa0d08839f6fa5a150e5791b9b717e5aa9e751..fc1e1140ac7c6cda8cf116027c2fc2898dbe9d4b 100644 ---- a/dom/ipc/CoalescedMouseData.cpp -+++ b/dom/ipc/CoalescedMouseData.cpp -@@ -72,6 +72,9 @@ bool CoalescedMouseData::CanCoalesce(const WidgetMouseEvent& aEvent, - mCoalescedInputEvent->pointerId != aEvent.pointerId || - mCoalescedInputEvent->mButton != aEvent.mButton || - mCoalescedInputEvent->mButtons != aEvent.mButtons || mGuid != aGuid || -+ // `mJugglerEventId` is 0 for non-juggler events and a unique number for -+ // juggler-emitted events. -+ mCoalescedInputEvent->mJugglerEventId != aEvent.mJugglerEventId || - mInputBlockId != aInputBlockId) { - return false; - } -diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.cc b/dom/media/systemservices/video_engine/desktop_capture_impl.cc -index db777994b583efc2a3533e7d4534fff894c733bb..eb317c19b2422bd983d5e132c9ee4dac31687428 100644 ---- a/dom/media/systemservices/video_engine/desktop_capture_impl.cc -+++ b/dom/media/systemservices/video_engine/desktop_capture_impl.cc -@@ -53,9 +53,10 @@ namespace webrtc { - - DesktopCaptureImpl* DesktopCaptureImpl::Create(const int32_t aModuleId, - const char* aUniqueId, -- const CaptureDeviceType aType) { -+ const CaptureDeviceType aType, -+ bool aCaptureCursor) { - return new rtc::RefCountedObject(aModuleId, aUniqueId, -- aType); -+ aType, aCaptureCursor); - } - - static DesktopCaptureOptions CreateDesktopCaptureOptions() { -@@ -156,8 +157,10 @@ static std::unique_ptr CreateTabCapturer( - - static std::unique_ptr CreateDesktopCapturerAndThread( - CaptureDeviceType aDeviceType, DesktopCapturer::SourceId aSourceId, -- nsIThread** aOutThread) { -+ nsIThread** aOutThread, bool aCaptureCursor) { - DesktopCaptureOptions options = CreateDesktopCaptureOptions(); -+ if (aCaptureCursor) -+ options.set_prefer_cursor_embedded(aCaptureCursor); - auto ensureThread = [&]() { - if (*aOutThread) { - return *aOutThread; -@@ -254,7 +257,8 @@ static std::unique_ptr CreateDesktopCapturerAndThread( - } - - DesktopCaptureImpl::DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, -- const CaptureDeviceType aType) -+ const CaptureDeviceType aType, -+ bool aCaptureCursor) - : mModuleId(aId), - mTrackingId(mozilla::TrackingId(CaptureEngineToTrackingSourceStr([&] { - switch (aType) { -@@ -271,6 +275,7 @@ DesktopCaptureImpl::DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, - aId)), - mDeviceUniqueId(aUniqueId), - mDeviceType(aType), -+ capture_cursor_(aCaptureCursor), - mControlThread(mozilla::GetCurrentSerialEventTarget()), - mNextFrameMinimumTime(Timestamp::Zero()), - mCallbacks("DesktopCaptureImpl::mCallbacks") {} -@@ -295,6 +300,19 @@ void DesktopCaptureImpl::DeRegisterCaptureDataCallback( - } - } - -+void DesktopCaptureImpl::RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) { -+ rtc::CritScope lock(&mApiCs); -+ _rawFrameCallbacks.insert(rawFrameCallback); -+} -+ -+void DesktopCaptureImpl::DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) { -+ rtc::CritScope lock(&mApiCs); -+ auto it = _rawFrameCallbacks.find(rawFrameCallback); -+ if (it != _rawFrameCallbacks.end()) { -+ _rawFrameCallbacks.erase(it); -+ } -+} -+ - int32_t DesktopCaptureImpl::StopCaptureIfAllClientsClose() { - { - auto callbacks = mCallbacks.Lock(); -@@ -350,7 +368,7 @@ int32_t DesktopCaptureImpl::StartCapture( - return -1; - } - std::unique_ptr capturer = CreateDesktopCapturerAndThread( -- mDeviceType, sourceId, getter_AddRefs(mCaptureThread)); -+ mDeviceType, sourceId, getter_AddRefs(mCaptureThread), capture_cursor_); - - MOZ_ASSERT(!capturer == !mCaptureThread); - if (!capturer) { -@@ -458,6 +476,15 @@ void DesktopCaptureImpl::OnCaptureResult(DesktopCapturer::Result aResult, - frameInfo.height = aFrame->size().height(); - frameInfo.videoType = VideoType::kARGB; - -+ size_t videoFrameStride = -+ frameInfo.width * DesktopFrame::kBytesPerPixel; -+ { -+ rtc::CritScope cs(&mApiCs); -+ for (auto rawFrameCallback : _rawFrameCallbacks) { -+ rawFrameCallback->OnRawFrame(videoFrame, videoFrameStride, frameInfo); -+ } -+ } -+ - size_t videoFrameLength = - frameInfo.width * frameInfo.height * DesktopFrame::kBytesPerPixel; - -diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.h b/dom/media/systemservices/video_engine/desktop_capture_impl.h -index a76b7de569db1cb42728a5514fb80e5c46e0344e..3d61ad8d3aa4a7eaf96957dcd680e1e1ee8abdf4 100644 ---- a/dom/media/systemservices/video_engine/desktop_capture_impl.h -+++ b/dom/media/systemservices/video_engine/desktop_capture_impl.h -@@ -26,6 +26,7 @@ - #include "api/video/video_sink_interface.h" - #include "modules/desktop_capture/desktop_capturer.h" - #include "modules/video_capture/video_capture.h" -+#include "rtc_base/deprecated/recursive_critical_section.h" - #include "mozilla/DataMutex.h" - #include "mozilla/Maybe.h" - #include "mozilla/TimeStamp.h" -@@ -42,17 +43,44 @@ 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; -+ int32_t StartCaptureCounted(const VideoCaptureCapability& aCapability) { -+ ++capture_counter_; -+ return capture_counter_ == 1 ? StartCapture(aCapability) : 0; -+ } -+ -+ int32_t StopCaptureCounted() { -+ --capture_counter_; -+ return capture_counter_ == 0 ? StopCapture() : 0; -+ } -+ -+ private: -+ int32_t capture_counter_ = 0; -+}; -+ - // Reuses the video engine pipeline for screen sharing. - // 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 DesktopCaptureImpl* Create( - const int32_t aModuleId, const char* aUniqueId, -- const mozilla::camera::CaptureDeviceType aType); -+ const mozilla::camera::CaptureDeviceType aType, bool aCaptureCursor = true); - - [[nodiscard]] static std::shared_ptr - CreateDeviceInfo(const int32_t aId, -@@ -66,6 +94,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - void DeRegisterCaptureDataCallback( - rtc::VideoSinkInterface* aCallback) override; - int32_t StopCaptureIfAllClientsClose() override; -+ void RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) override; -+ void DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) override; - - int32_t SetCaptureRotation(VideoRotation aRotation) override; - bool SetApplyRotation(bool aEnable) override; -@@ -89,7 +119,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - - protected: - DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, -- const mozilla::camera::CaptureDeviceType aType); -+ const mozilla::camera::CaptureDeviceType aType, -+ bool aCaptureCusor); - virtual ~DesktopCaptureImpl(); - - private: -@@ -98,6 +129,9 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - void InitOnThread(std::unique_ptr aCapturer, int aFramerate); - void UpdateOnThread(int aFramerate); - void ShutdownOnThread(); -+ -+ rtc::RecursiveCriticalSection mApiCs; -+ std::set _rawFrameCallbacks; - // DesktopCapturer::Callback interface. - void OnCaptureResult(DesktopCapturer::Result aResult, - std::unique_ptr aFrame) override; -@@ -105,6 +139,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - // Notifies all mCallbacks of OnFrame(). mCaptureThread only. - void NotifyOnFrame(const VideoFrame& aFrame); - -+ bool capture_cursor_ = true; -+ - // Control thread on which the public API is called. - const nsCOMPtr mControlThread; - // Set in StartCapture. -diff --git a/dom/script/ScriptSettings.cpp b/dom/script/ScriptSettings.cpp -index d5964b27e9c99af76fe3f4076322592a9370c2d0..da217e2c1fbd9ca02e50ff74dde028189a216a6d 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 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 8b68f22ae64d19165bf4b3c58aea8f5c237ba351..c3733bfa4ed550c98ab5f72c406cd6d01a621aca 100644 ---- a/dom/security/nsCSPUtils.cpp -+++ b/dom/security/nsCSPUtils.cpp -@@ -24,6 +24,7 @@ - #include "nsSandboxFlags.h" - #include "nsServiceManagerUtils.h" - #include "nsWhitespaceTokenizer.h" -+#include "nsDocShell.h" - - #include "mozilla/Assertions.h" - #include "mozilla/Components.h" -@@ -136,6 +137,11 @@ void CSP_ApplyMetaCSPToDoc(mozilla::dom::Document& aDoc, - return; - } - -+ if (aDoc.GetDocShell() && -+ nsDocShell::Cast(aDoc.GetDocShell())->IsBypassCSPEnabled()) { -+ return; -+ } -+ - nsAutoString policyStr( - nsContentUtils::TrimWhitespace( - aPolicyStr)); -diff --git a/dom/webidl/GeometryUtils.webidl b/dom/webidl/GeometryUtils.webidl -index aee376e971ae01ac1e512c3920b115bfaf06afa8..1701311534bf77e6cd9bafc0e3a283610476aa8f 100644 ---- a/dom/webidl/GeometryUtils.webidl -+++ b/dom/webidl/GeometryUtils.webidl -@@ -17,6 +17,8 @@ dictionary GeometryUtilsOptions { - boolean createFramesForSuppressedWhitespace = true; - [ChromeOnly] - boolean flush = true; -+ [ChromeOnly] -+ boolean recurseWhenNoFrame = false; - }; - - dictionary BoxQuadOptions : GeometryUtilsOptions { -@@ -35,6 +37,9 @@ interface mixin GeometryUtils { - [Throws, Func="nsINode::HasBoxQuadsSupport", NeedsCallerType] - sequence getBoxQuads(optional BoxQuadOptions options = {}); - -+ [ChromeOnly, Throws, Func="nsINode::HasBoxQuadsSupport"] -+ undefined 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 83cef5b52b8f5c3168cd1d59266b4149425647fd..a80e89ec26a7e049c8ed84687ba2cd49597be05f 100644 ---- a/dom/workers/RuntimeService.cpp -+++ b/dom/workers/RuntimeService.cpp -@@ -1082,7 +1082,7 @@ void PrefLanguagesChanged(const char* /* aPrefName */, void* /* aClosure */) { - AssertIsOnMainThread(); - - nsTArray languages; -- Navigator::GetAcceptLanguages(languages); -+ Navigator::GetAcceptLanguages(nullptr, languages); - - RuntimeService* runtime = RuntimeService::GetService(); - if (runtime) { -@@ -1272,8 +1272,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; - } - -@@ -1901,6 +1900,13 @@ void RuntimeService::PropagateStorageAccessPermissionGranted( - } - } - -+void RuntimeService::ResetDefaultLocaleInAllWorkers() { -+ AssertIsOnMainThread(); -+ BroadcastAllWorkers([](auto& worker) { -+ worker.ResetDefaultLocale(); -+ }); -+} -+ - template - void RuntimeService::BroadcastAllWorkers(const Func& aFunc) { - AssertIsOnMainThread(); -@@ -2451,6 +2457,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 6d75c6708bcb999dc1dc3b0172afa14136110bc6..809d0ef80ffe793beff5d3c11bf6bf7912385e99 100644 ---- a/dom/workers/RuntimeService.h -+++ b/dom/workers/RuntimeService.h -@@ -115,6 +115,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 af8d36c0d72683712a3fee22661f8c3279e103db..6b3a967c9acde2c81ab38148d4b1ac120a4717a2 100644 ---- a/dom/workers/WorkerCommon.h -+++ b/dom/workers/WorkerCommon.h -@@ -50,6 +50,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 06083bb8f9546be06fa0b5c78d4e005a1617e51b..1753896265c1701ad50425c565f8d44392d0afb9 100644 ---- a/dom/workers/WorkerPrivate.cpp -+++ b/dom/workers/WorkerPrivate.cpp -@@ -738,6 +738,18 @@ class UpdateContextOptionsRunnable final : public WorkerControlRunnable { - } - }; - -+class ResetDefaultLocaleRunnable final : public WorkerControlRunnable { -+ public: -+ explicit ResetDefaultLocaleRunnable(WorkerPrivate* aWorkerPrivate) -+ : WorkerControlRunnable("ResetDefaultLocaleRunnable") {} -+ -+ virtual bool WorkerRun(JSContext* aCx, -+ WorkerPrivate* aWorkerPrivate) override { -+ aWorkerPrivate->ResetDefaultLocaleInternal(aCx); -+ return true; -+ } -+}; -+ - class UpdateLanguagesRunnable final : public WorkerThreadRunnable { - nsTArray mLanguages; - -@@ -2334,6 +2346,16 @@ void WorkerPrivate::UpdateContextOptions( - } - } - -+void WorkerPrivate::ResetDefaultLocale() { -+ AssertIsOnParentThread(); -+ -+ RefPtr runnable = -+ new ResetDefaultLocaleRunnable(this); -+ if (!runnable->Dispatch(this)) { -+ NS_WARNING("Failed to reset default locale in worker!"); -+ } -+} -+ - void WorkerPrivate::UpdateLanguages(const nsTArray& aLanguages) { - AssertIsOnParentThread(); - -@@ -5996,6 +6018,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& aLanguages) { - WorkerGlobalScope* globalScope = GlobalScope(); -diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h -index 15c819c84fa934e25517ac8f55fd39ef8ba46986..fe01e09abcf2315abe41a3d19418c4e0f8c7df2b 100644 ---- a/dom/workers/WorkerPrivate.h -+++ b/dom/workers/WorkerPrivate.h -@@ -457,6 +457,8 @@ class WorkerPrivate final - void UpdateContextOptionsInternal(JSContext* aCx, - const JS::ContextOptions& aContextOptions); - -+ void ResetDefaultLocaleInternal(JSContext* aCx); -+ - void UpdateLanguagesInternal(const nsTArray& aLanguages); - - void UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key, -@@ -1103,6 +1105,8 @@ class WorkerPrivate final - - void UpdateContextOptions(const JS::ContextOptions& aContextOptions); - -+ void ResetDefaultLocale(); -+ - void UpdateLanguages(const nsTArray& aLanguages); - - void UpdateJSWorkerMemoryParameter(JSGCParamKey key, Maybe value); -diff --git a/intl/components/src/TimeZone.cpp b/intl/components/src/TimeZone.cpp -index 7a069ef0c59895cf1f8dc35d612f1494c9c9f1ef..5b09dfdcc5323def65c35b0696141b44eef9dcda 100644 ---- a/intl/components/src/TimeZone.cpp -+++ b/intl/components/src/TimeZone.cpp -@@ -16,6 +16,7 @@ - - namespace mozilla::intl { - -+ - /* static */ - Result, ICUError> TimeZone::TryCreate( - Maybe> aTimeZoneOverride) { -@@ -318,6 +319,13 @@ static ICUResult SetDefaultTimeZone(TimeZoneIdentifierVector& timeZone) { - } - #endif - -+bool TimeZone::IsValidTimeZoneId(const char* timeZoneId) { -+ // Validate timezone id. -+ mozilla::UniquePtr timeZone(icu::TimeZone::createTimeZone( -+ icu::UnicodeString(timeZoneId, -1, US_INV))); -+ return timeZone && *timeZone != icu::TimeZone::getUnknown(); -+} -+ - Result TimeZone::SetDefaultTimeZone( - Span aTimeZone) { - #if MOZ_INTL_USE_ICU_CPP_TIMEZONE -diff --git a/intl/components/src/TimeZone.h b/intl/components/src/TimeZone.h -index 89770839ae108b5f3462a7f20684fdb72c4ab2fb..a7e40d6b7c33c234b41e586eac573ba4ce3a7d18 100644 ---- a/intl/components/src/TimeZone.h -+++ b/intl/components/src/TimeZone.h -@@ -191,6 +191,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 523e84c8c93f4221701f90f2e8ee146ec8e1adbd..98d5b1176e5378431b859a2dbd4d4e778d236e78 100644 ---- a/js/public/Date.h -+++ b/js/public/Date.h -@@ -55,6 +55,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 2d177b5aade6d158e9ae62d317d5155b72cdcf84..28af5d41eb06d4b33cd5f86484dc29c923308835 100644 ---- a/js/src/debugger/Object.cpp -+++ b/js/src/debugger/Object.cpp -@@ -2516,7 +2516,11 @@ Maybe 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 cc366b4cc411ed8de972811237563edb376355e3..adf727cf80fadebce3be9301752dc1d0b9ee35b9 100644 ---- a/js/src/vm/DateTime.cpp -+++ b/js/src/vm/DateTime.cpp -@@ -188,6 +188,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); - -@@ -556,10 +561,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) { -@@ -773,6 +792,15 @@ static bool ReadTimeZoneLink(std::string_view tz, - - void js::DateTimeInfo::internalResyncICUDefaultTimeZone() { - #if JS_HAS_INTL_API -+ if (!timeZoneOverride_.empty()) { -+ mozilla::Span 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; -+ } -+ - // In the future we should not be setting a default ICU time zone at all, - // instead all accesses should go through the appropriate DateTimeInfo - // instance depending on the resist fingerprinting status. For now we return -@@ -784,7 +812,6 @@ void js::DateTimeInfo::internalResyncICUDefaultTimeZone() { - - if (const char* tzenv = std::getenv("TZ")) { - std::string_view tz(tzenv); -- - mozilla::Span tzid; - - # if defined(XP_WIN) -diff --git a/js/src/vm/DateTime.h b/js/src/vm/DateTime.h -index 7be5b49afdce8e761af05dfbd48f3cb22e9ce318..3899c7988959f11bbadd0c005462acb979823fd1 100644 ---- a/js/src/vm/DateTime.h -+++ b/js/src/vm/DateTime.h -@@ -75,6 +75,8 @@ using TimeZoneIdentifierVector = - SystemAllocPolicy>; - #endif - -+extern void SetTimeZoneOverrideInternal(std::string timeZone); -+ - /** - * Stores date/time information, particularly concerning the current local - * time zone, and implements a small cache for daylight saving time offset -@@ -258,6 +260,7 @@ class DateTimeInfo { - private: - // The method below should only be called via js::ResetTimeZoneInternal(). - friend void js::ResetTimeZoneInternal(ResetTimeZoneMode); -+ friend void js::SetTimeZoneOverrideInternal(std::string); - - static void resetTimeZone(ResetTimeZoneMode mode) { - { -@@ -362,6 +365,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 -@@ -377,6 +382,8 @@ class DateTimeInfo { - - void internalResetTimeZone(ResetTimeZoneMode mode); - -+ void internalSetTimeZoneOverride(std::string timeZone); -+ - void updateTimeZone(); - - void internalResyncICUDefaultTimeZone(); -diff --git a/layout/base/GeometryUtils.cpp b/layout/base/GeometryUtils.cpp -index 67673c5c306e7237613b0560c7b3f888bd6ad1b8..fe4a278dad4b1747b41b5a824978636a70a9dea8 100644 ---- a/layout/base/GeometryUtils.cpp -+++ b/layout/base/GeometryUtils.cpp -@@ -23,6 +23,7 @@ - #include "nsContentUtils.h" - #include "nsIFrame.h" - #include "nsLayoutUtils.h" -+#include "ChildIterator.h" - - using namespace mozilla; - using namespace mozilla::dom; -@@ -265,10 +266,27 @@ static bool CheckFramesInSameTopLevelBrowsingContext(nsIFrame* aFrame1, - return false; - } - -+static nsIFrame* GetFrameForNodeRecursive(nsINode* aNode, -+ const GeometryUtilsOptions& aOptions, -+ bool aRecurseWhenNoFrame) { -+ nsIFrame* frame = GetFrameForNode(aNode, aOptions); -+ if (!frame && aRecurseWhenNoFrame && aNode->IsContent()) { -+ dom::FlattenedChildIterator iter(aNode->AsContent()); -+ for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { -+ frame = GetFrameForNodeRecursive(child, aOptions, aRecurseWhenNoFrame); -+ if (frame) { -+ break; -+ } -+ } -+ } -+ return frame; -+} -+ - void GetBoxQuads(nsINode* aNode, const dom::BoxQuadOptions& aOptions, - nsTArray>& aResult, CallerType aCallerType, - ErrorResult& aRv) { -- nsIFrame* frame = GetFrameForNode(aNode, aOptions); -+ nsIFrame* frame = -+ GetFrameForNodeRecursive(aNode, aOptions, aOptions.mRecurseWhenNoFrame); - if (!frame) { - // No boxes to return - return; -@@ -281,7 +299,8 @@ void GetBoxQuads(nsINode* aNode, const dom::BoxQuadOptions& aOptions, - // EnsureFrameForTextNode call. We need to get the first frame again - // when that happens and re-check it. - if (!weakFrame.IsAlive()) { -- frame = GetFrameForNode(aNode, aOptions); -+ frame = -+ GetFrameForNodeRecursive(aNode, aOptions, aOptions.mRecurseWhenNoFrame); - if (!frame) { - // No boxes to return - return; -diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp -index 26119628ab4839858733ce39c6c9ef2970092b49..a9c4dbc4936755fd25b8528511e9a4c62695de89 100644 ---- a/layout/base/PresShell.cpp -+++ b/layout/base/PresShell.cpp -@@ -12150,7 +12150,9 @@ bool PresShell::ComputeActiveness() const { - if (!browserChild->IsVisible()) { - MOZ_LOG(gLog, LogLevel::Debug, - (" > BrowserChild %p is not visible", browserChild)); -- return false; -+ bool isActive; -+ root->GetDocShell()->GetForceActiveState(&isActive); -+ return isActive; - } - - // If the browser is visible but just due to be preserving layers -diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp -index ee4e4b7e04f0f949b0afc7e8097711fcefe8b3c3..3af1d380d514b70392d1daaa4bc623afd7a570e6 100644 ---- a/layout/base/nsLayoutUtils.cpp -+++ b/layout/base/nsLayoutUtils.cpp -@@ -707,6 +707,10 @@ bool nsLayoutUtils::AllowZoomingForDocument( - !aDocument->GetPresShell()->AsyncPanZoomEnabled()) { - return false; - } -+ -+ /* Playwright: disable zooming as we don't support meta viewport tag */ -+ if (1 == 1) return false; -+ - // True if we allow zooming for all documents on this platform, or if we are - // in RDM. - BrowsingContext* bc = aDocument->GetBrowsingContext(); -@@ -9772,6 +9776,9 @@ void nsLayoutUtils::ComputeSystemFont(nsFont* aSystemFont, - - /* static */ - bool nsLayoutUtils::ShouldHandleMetaViewport(const Document* aDocument) { -+ /* Playwright: disable meta viewport handling since we don't require one */ -+ if (1 == 1) return false; -+ - BrowsingContext* bc = aDocument->GetBrowsingContext(); - return StaticPrefs::dom_meta_viewport_enabled() || (bc && bc->InRDMPane()); - } -diff --git a/layout/style/GeckoBindings.h b/layout/style/GeckoBindings.h -index 9527443c79077e0a728d78c3184ab7319f1c9efd..4e193ed114b4f70fb72bea928709fc7723f35b88 100644 ---- a/layout/style/GeckoBindings.h -+++ b/layout/style/GeckoBindings.h -@@ -591,6 +592,7 @@ float Gecko_MediaFeatures_GetResolution(const mozilla::dom::Document*); - bool Gecko_MediaFeatures_PrefersReducedMotion(const mozilla::dom::Document*); - bool Gecko_MediaFeatures_PrefersReducedTransparency( - 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 21bcc8e890a0d3f3e86b5ea6eed79d017dd2fb76..eefc7d5c934f03b4a9213dafcbb65dd32b695622 100644 ---- a/layout/style/nsMediaFeatures.cpp -+++ b/layout/style/nsMediaFeatures.cpp -@@ -268,11 +268,7 @@ bool Gecko_MediaFeatures_MatchesPlatform(StylePlatform aPlatform) { - } - - bool Gecko_MediaFeatures_PrefersReducedMotion(const Document* aDocument) { -- if (aDocument->ShouldResistFingerprinting( -- RFPTarget::CSSPrefersReducedMotion)) { -- return false; -- } -- return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1; -+ return aDocument->PrefersReducedMotion(); - } - - bool Gecko_MediaFeatures_PrefersReducedTransparency(const Document* aDocument) { -@@ -297,6 +293,20 @@ StylePrefersColorScheme Gecko_MediaFeatures_PrefersColorScheme( - // as a signal. - StylePrefersContrast Gecko_MediaFeatures_PrefersContrast( - const Document* aDocument) { -+ if (auto* bc = aDocument->GetBrowsingContext()) { -+ switch (bc->Top()->PrefersContrastOverride()) { -+ case dom::PrefersContrastOverride::No_preference: -+ return StylePrefersContrast::NoPreference; -+ case dom::PrefersContrastOverride::Less: -+ return StylePrefersContrast::Less; -+ case dom::PrefersContrastOverride::More: -+ return StylePrefersContrast::More; -+ case dom::PrefersContrastOverride::Custom: -+ return StylePrefersContrast::Custom; -+ } -+ } -+ -+ - if (aDocument->ShouldResistFingerprinting(RFPTarget::CSSPrefersContrast)) { - return StylePrefersContrast::NoPreference; - } -diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp -index e5cf36273d5790de2c80acb42a6ee181bdb66f08..0523a37fc19b470e3817ae61c912a3dc54fc57a6 100644 ---- a/netwerk/base/LoadInfo.cpp -+++ b/netwerk/base/LoadInfo.cpp -@@ -801,7 +801,8 @@ LoadInfo::LoadInfo(const LoadInfo& rhs) - rhs.mHasInjectedCookieForCookieBannerHandling), - mSchemelessInput(rhs.mSchemelessInput), - mHttpsUpgradeTelemetry(rhs.mHttpsUpgradeTelemetry), -- mIsNewWindowTarget(rhs.mIsNewWindowTarget) { -+ mIsNewWindowTarget(rhs.mIsNewWindowTarget), -+ mJugglerLoadIdentifier(rhs.mJugglerLoadIdentifier) { - } - - LoadInfo::LoadInfo( -@@ -2778,4 +2779,16 @@ void LoadInfo::UpdateParentAddressSpaceInfo() { - } - } - -+NS_IMETHODIMP -+LoadInfo::GetJugglerLoadIdentifier(uint64_t* aResult) { -+ *aResult = mJugglerLoadIdentifier; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+LoadInfo::SetJugglerLoadIdentifier(uint64_t aID) { -+ mJugglerLoadIdentifier = aID; -+ return NS_OK; -+} -+ - } // namespace mozilla::net -diff --git a/netwerk/base/LoadInfo.h b/netwerk/base/LoadInfo.h -index 6547d451f3a764c8860dd0c19b5b490caecbf0af..feccce92e3769b8e9a3a4926cca9b85fccda86a5 100644 ---- a/netwerk/base/LoadInfo.h -+++ b/netwerk/base/LoadInfo.h -@@ -455,6 +455,8 @@ class LoadInfo final : public nsILoadInfo { - - bool mIsNewWindowTarget = false; - bool mSkipHTTPSUpgrade = false; -+ -+ uint64_t mJugglerLoadIdentifier = 0; - }; - // This is exposed solely for testing purposes and should not be used outside of - // LoadInfo -diff --git a/netwerk/base/TRRLoadInfo.cpp b/netwerk/base/TRRLoadInfo.cpp -index 551d89315243f4b515aa29d3a67eb23050ea9f0a..ac3a1ca6d846826c5d704d1b4abdaee55b834b0d 100644 ---- a/netwerk/base/TRRLoadInfo.cpp -+++ b/netwerk/base/TRRLoadInfo.cpp -@@ -1010,5 +1010,15 @@ TRRLoadInfo::GetFetchDestination(nsACString& aDestination) { - return NS_ERROR_NOT_IMPLEMENTED; - } - -+NS_IMETHODIMP -+TRRLoadInfo::GetJugglerLoadIdentifier(uint64_t* aResult) { -+ return NS_ERROR_NOT_IMPLEMENTED; -+} -+ -+NS_IMETHODIMP -+TRRLoadInfo::SetJugglerLoadIdentifier(uint64_t aResult) { -+ return NS_ERROR_NOT_IMPLEMENTED; -+} -+ - } // namespace net - } // namespace mozilla -diff --git a/netwerk/base/nsILoadInfo.idl b/netwerk/base/nsILoadInfo.idl -index f1b54736d9ee006292bf4c9cd0b3490d5ec8da66..257fda17a10f702cee39fb42ad69e0cd86ca95d1 100644 ---- a/netwerk/base/nsILoadInfo.idl -+++ b/netwerk/base/nsILoadInfo.idl -@@ -1686,4 +1686,6 @@ interface nsILoadInfo : nsISupports - return static_cast(userNavigationInvolvement); - } - %} -+ -+ [infallible] attribute unsigned long long jugglerLoadIdentifier; - }; -diff --git a/netwerk/base/nsINetworkInterceptController.idl b/netwerk/base/nsINetworkInterceptController.idl -index 7f91d2df6f8bb4020c75c132dc8f6bf26625fa1e..aaa5541a17039d6b13ad83ab176fdaaf79edb2a0 100644 ---- a/netwerk/base/nsINetworkInterceptController.idl -+++ b/netwerk/base/nsINetworkInterceptController.idl -@@ -60,6 +60,16 @@ interface nsIInterceptedChannel : nsISupports - */ - void resetInterception(in boolean bypass); - -+ // ----- Playwright begin ----- -+ -+ // Same as resetInterception, but updates the URI. -+ void resetInterceptionWithURI(in nsIURI aURI); -+ -+ // After resetInterception is called, this request will be intercepted again. -+ void interceptAfterServiceWorkerResets(); -+ -+ // ----- Playwright end ------- -+ - /** - * Set the status and reason for the forthcoming synthesized response. - * Multiple calls overwrite existing values. -diff --git a/netwerk/ipc/DocumentLoadListener.cpp b/netwerk/ipc/DocumentLoadListener.cpp -index 1471432c1f1a47be5073ed01b746f1f13d3a0b47..585f81762e2bf51681d11c06c9459063121c34e9 100644 ---- a/netwerk/ipc/DocumentLoadListener.cpp -+++ b/netwerk/ipc/DocumentLoadListener.cpp -@@ -185,6 +185,7 @@ static auto CreateDocumentLoadInfo(CanonicalBrowsingContext* aBrowsingContext, - loadInfo->SetTextDirectiveUserActivation( - aLoadState->GetTextDirectiveUserActivation()); - loadInfo->SetIsMetaRefresh(aLoadState->IsMetaRefresh()); -+ loadInfo->SetJugglerLoadIdentifier(aLoadState->GetLoadIdentifier()); - - return loadInfo.forget(); - } -diff --git a/netwerk/protocol/http/InterceptedHttpChannel.cpp b/netwerk/protocol/http/InterceptedHttpChannel.cpp -index fbf4bdf1e24d1102df113984be6c8dc3a7d0d810..cf1978009d74221ae804b998e223904fa943a91f 100644 ---- a/netwerk/protocol/http/InterceptedHttpChannel.cpp -+++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp -@@ -728,10 +728,33 @@ NS_IMPL_ISUPPORTS(ResetInterceptionHeaderVisitor, nsIHttpHeaderVisitor) - - } // anonymous namespace - -+NS_IMETHODIMP -+InterceptedHttpChannel::InterceptAfterServiceWorkerResets() { -+ mInterceptAfterServiceWorkerResets = true; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+InterceptedHttpChannel::ResetInterceptionWithURI(nsIURI* aURI) { -+ if (aURI) { -+ mURI = aURI; -+ } -+ return ResetInterception(true); -+} -+ - NS_IMETHODIMP - InterceptedHttpChannel::ResetInterception(bool aBypass) { - INTERCEPTED_LOG(("InterceptedHttpChannel::ResetInterception [%p] bypass: %s", - this, aBypass ? "true" : "false")); -+ if (mInterceptAfterServiceWorkerResets) { -+ mInterceptAfterServiceWorkerResets = false; -+ nsCOMPtr controller; -+ GetCallback(controller); -+ if (!controller) -+ return NS_ERROR_DOM_INVALID_STATE_ERR; -+ return controller->ChannelIntercepted(this); -+ } -+ - if (mCanceled) { - return mStatus; - } -@@ -1146,11 +1169,18 @@ InterceptedHttpChannel::OnStartRequest(nsIRequest* aRequest) { - GetCallback(mProgressSink); - } - -+ // Playwright: main requests in firefox do not have loading principal. -+ // As they are intercepted by Playwright, they don't have -+ // serviceWorkerTainting as well. -+ // Thus these asserts are wrong for Playwright world. -+ // Note: these checks were added in https://github.com/mozilla-firefox/firefox/commit/bb16ca6496682c3b0ddd452d0dd4c1dd46ff71f8 -+ /* - MOZ_ASSERT_IF(!mLoadInfo->GetServiceWorkerTaintingSynthesized(), - mLoadInfo->GetLoadingPrincipal()); - // No need to do ORB checks if these conditions hold. - MOZ_DIAGNOSTIC_ASSERT(mLoadInfo->GetServiceWorkerTaintingSynthesized() || - mLoadInfo->GetLoadingPrincipal()->IsSystemPrincipal()); -+ */ - - if (mPump && mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS) { - mPump->PeekStream(CallTypeSniffers, static_cast(this)); -diff --git a/netwerk/protocol/http/InterceptedHttpChannel.h b/netwerk/protocol/http/InterceptedHttpChannel.h -index 704404c9f094640ad63b685d64bd5a396e733e4b..92bdc21b4d6a015cc2f2bb22781ec6750c7789ec 100644 ---- a/netwerk/protocol/http/InterceptedHttpChannel.h -+++ b/netwerk/protocol/http/InterceptedHttpChannel.h -@@ -90,6 +90,11 @@ class InterceptedHttpChannel final - Atomic mCallingStatusAndProgress; - bool mInterceptionReset{false}; - -+ // ----- Playwright begin ----- -+ // After resetInterception is called, this request will call into interceptors again. -+ bool mInterceptAfterServiceWorkerResets{false}; -+ // ----- Playwright end ------- -+ - /** - * InterceptionTimeStamps is used to record the time stamps of the - * interception. -diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp -index 1051d1e91c1ebf036f2e5db82a37636dd7cda4c3..3ef53c09442e24fb50308740950aa6d354703b7d 100644 ---- a/netwerk/protocol/http/nsHttpChannel.cpp -+++ b/netwerk/protocol/http/nsHttpChannel.cpp -@@ -685,11 +685,9 @@ nsresult nsHttpChannel::OnBeforeConnect() { - // SecurityInfo.sys.mjs - mLoadInfo->SetHstsStatus(isSecureURI); - -- RefPtr bc; -- mLoadInfo->GetBrowsingContext(getter_AddRefs(bc)); - // If bypassing the cache and we're forced offline - // we can just return the error here. -- if (bc && bc->Top()->GetForceOffline() && -+ if (IsForcedOffline() && - BYPASS_LOCAL_CACHE(mLoadFlags, LoadPreferCacheLoadOverBypass())) { - return NS_ERROR_OFFLINE; - } -@@ -802,9 +800,7 @@ nsresult nsHttpChannel::MaybeUseHTTPSRRForUpgrade(bool aShouldUpgrade, - return aStatus; - } - -- RefPtr bc; -- mLoadInfo->GetBrowsingContext(getter_AddRefs(bc)); -- bool forceOffline = bc && bc->Top()->GetForceOffline(); -+ bool forceOffline = IsForcedOffline(); - - if (mURI->SchemeIs("https") || aShouldUpgrade || !LoadUseHTTPSSVC() || - forceOffline) { -@@ -1263,15 +1259,14 @@ nsresult nsHttpChannel::ContinueConnect() { - "CORS preflight must have been finished by the time we " - "do the rest of ContinueConnect"); - -- RefPtr bc; -- mLoadInfo->GetBrowsingContext(getter_AddRefs(bc)); -+ bool isForcedOffline = IsForcedOffline(); - - // we may or may not have a cache entry at this point - if (mCacheEntry) { - // read straight from the cache if possible... - if (CachedContentIsValid()) { - // If we're forced offline, and set to bypass the cache, return offline. -- if (bc && bc->Top()->GetForceOffline() && -+ if (isForcedOffline && - BYPASS_LOCAL_CACHE(mLoadFlags, LoadPreferCacheLoadOverBypass())) { - return NS_ERROR_OFFLINE; - } -@@ -1313,7 +1308,7 @@ nsresult nsHttpChannel::ContinueConnect() { - } - - // We're about to hit the network. Don't if we're forced offline. -- if (bc && bc->Top()->GetForceOffline()) { -+ if (isForcedOffline) { - return NS_ERROR_OFFLINE; - } - -@@ -1418,12 +1413,9 @@ void nsHttpChannel::SpeculativeConnect() { - // don't speculate if we are offline, when doing http upgrade (i.e. - // websockets bootstrap), or if we can't do keep-alive (because then we - // couldn't reuse the speculative connection anyhow). -- RefPtr bc; -- mLoadInfo->GetBrowsingContext(getter_AddRefs(bc)); -- - if (gIOService->IsOffline() || mUpgradeProtocolCallback || - !(mCaps & NS_HTTP_ALLOW_KEEPALIVE) || -- (bc && bc->Top()->GetForceOffline())) { -+ IsForcedOffline()) { - return; - } - -@@ -4240,9 +4232,6 @@ nsresult nsHttpChannel::OpenCacheEntryInternal(bool isHttps) { - uint32_t cacheEntryOpenFlags; - bool offline = gIOService->IsOffline(); - -- RefPtr bc; -- mLoadInfo->GetBrowsingContext(getter_AddRefs(bc)); -- - bool maybeRCWN = false; - - nsAutoCString cacheControlRequestHeader; -@@ -4253,7 +4242,7 @@ nsresult nsHttpChannel::OpenCacheEntryInternal(bool isHttps) { - return NS_OK; - } - -- bool forceOffline = bc && bc->Top()->GetForceOffline(); -+ bool forceOffline = IsForcedOffline(); - if (offline || (mLoadFlags & INHIBIT_CACHING) || forceOffline) { - if (BYPASS_LOCAL_CACHE(mLoadFlags, LoadPreferCacheLoadOverBypass()) && - !offline && !forceOffline) { -@@ -7357,6 +7346,20 @@ void nsHttpChannel::MaybeStartDNSPrefetch() { - } - } - -+bool nsHttpChannel::IsForcedOffline() { -+ RefPtr bc; -+ mLoadInfo->GetBrowsingContext(getter_AddRefs(bc)); -+ if (bc && bc->Top()->GetForceOffline()) -+ return true; -+ -+ RefPtr wbc; -+ mLoadInfo->GetWorkerAssociatedBrowsingContext(getter_AddRefs(wbc)); -+ if (wbc && wbc->Top()->GetForceOffline()) -+ return true; -+ -+ return false; -+} -+ - NS_IMETHODIMP - nsHttpChannel::GetEncodedBodySize(uint64_t* aEncodedBodySize) { - if (mCacheEntry && !LoadCacheEntryIsWriteOnly()) { -diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h -index 9d28bae2d270690517c11383abe4c4bcc0edda96..9087d345b1b63bdce0912abb0c880c50900a797b 100644 ---- a/netwerk/protocol/http/nsHttpChannel.h -+++ b/netwerk/protocol/http/nsHttpChannel.h -@@ -305,6 +305,10 @@ class nsHttpChannel final : public HttpBaseChannel, - void MaybeResolveProxyAndBeginConnect(); - void MaybeStartDNSPrefetch(); - -+ // ---- Playwright begin -+ bool IsForcedOffline(); -+ // ---- Playwright end -+ - // Based on the proxy configuration determine the strategy for resolving the - // end server host name. - ProxyDNSStrategy GetProxyDNSStrategy(); -diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp -index ce2a868b9a915b98938518b6c935870f8169e0f7..e6d0a75bb3f5e8dea3f3e7f3448b553979860bd3 100644 ---- a/parser/html/nsHtml5TreeOpExecutor.cpp -+++ b/parser/html/nsHtml5TreeOpExecutor.cpp -@@ -1361,6 +1361,10 @@ void nsHtml5TreeOpExecutor::UpdateReferrerInfoFromMeta( - void nsHtml5TreeOpExecutor::AddSpeculationCSP(const nsAString& aCSP) { - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - -+ if (mDocShell && static_cast(mDocShell.get())->IsBypassCSPEnabled()) { -+ return; -+ } -+ - nsresult rv = NS_OK; - nsCOMPtr preloadCsp = mDocument->GetPreloadCsp(); - if (!preloadCsp) { -diff --git a/security/manager/ssl/nsCertOverrideService.cpp b/security/manager/ssl/nsCertOverrideService.cpp -index 0ecf2c0df3aad52e004a69b4c7a22fea7532b4d8..f5982c2cf1d6ea0522ac7f7e1fb5b4ab8fa07cb4 100644 ---- a/security/manager/ssl/nsCertOverrideService.cpp -+++ b/security/manager/ssl/nsCertOverrideService.cpp -@@ -627,6 +627,8 @@ void nsCertOverrideService::CountPermanentOverrideTelemetry( - } - - static bool IsDebugger() { -+ // In playwright world, this is always enabled. -+ if (1 == 1) return true; - #ifdef ENABLE_WEBDRIVER - nsCOMPtr marionette = do_GetService(NS_MARIONETTE_CONTRACTID); - if (marionette) { -diff --git a/services/settings/Utils.sys.mjs b/services/settings/Utils.sys.mjs -index cbdf07bcdae11de6f59e6c6c279833aca430dc70..6840c78350ccb52e99f23446b010abc2a1d92a55 100644 ---- a/services/settings/Utils.sys.mjs -+++ b/services/settings/Utils.sys.mjs -@@ -97,7 +97,7 @@ const _cdnURLs = {}; - - export var Utils = { - get SERVER_URL() { -- return lazy.allowServerURLOverride -+ return true || lazy.allowServerURLOverride - ? lazy.gServerURL - : AppConstants.REMOTE_SETTINGS_SERVER_URL; - }, -@@ -110,6 +110,9 @@ export var Utils = { - log, - - get shouldSkipRemoteActivityDueToTests() { -+ // Playwright does not set Cu.isInAutomation, hence we just return true -+ // here in order to disable the remote activity. -+ return true; - return ( - (lazy.isRunningTests || Cu.isInAutomation) && - this.SERVER_URL == "data:,#remote-settings-dummy/v1" -diff --git a/toolkit/components/browser/nsIWebBrowserChrome.idl b/toolkit/components/browser/nsIWebBrowserChrome.idl -index 75555352b8a15a50e4a21e34fc8ede4e9246c7cc..72855a404effa42b6c55cd0c2fcb8bdd6c2b3f9f 100644 ---- a/toolkit/components/browser/nsIWebBrowserChrome.idl -+++ b/toolkit/components/browser/nsIWebBrowserChrome.idl -@@ -74,6 +74,9 @@ interface nsIWebBrowserChrome : nsISupports - // Whether this window should use out-of-process cross-origin subframes. - const unsigned long CHROME_FISSION_WINDOW = 1 << 21; - -+ // 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 = 1 << 24; -diff --git a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs -index 3d8837cdb38fb5b25abfb9e3e369ad6fe688706e..867ce2efaa10eaea87ffeeb2669cc5a7be0045b3 100644 ---- a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs -+++ b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs -@@ -106,7 +106,9 @@ EnterprisePoliciesManager.prototype = { - Services.prefs.clearUserPref(PREF_POLICIES_APPLIED); - } - -- let provider = this._chooseProvider(); -+ // --- Playwright begin --- -+ let provider = new PlaywrightPoliciesProvider(); -+ // --- Playwright end --- - - if (provider.failed) { - this.status = Ci.nsIEnterprisePolicies.FAILED; -@@ -606,6 +608,19 @@ class JSONPoliciesProvider { - } - } - -+class PlaywrightPoliciesProvider extends JSONPoliciesProvider { -+ _getConfigurationFile() { -+ let prefPath = Services.prefs.getStringPref(PREF_ALTERNATE_PATH, ""); -+ if (!prefPath) -+ return null; -+ -+ dump(`Playwright: loading enterprise policies from ${prefPath}\n`); -+ let configFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); -+ configFile.initWithPath(prefPath); -+ return configFile; -+ } -+} -+ - class WindowsGPOPoliciesProvider { - constructor() { - this._policies = null; -diff --git a/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp b/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp -index 52fa968554a88d1624bf9403b07781a8b42c93b6..2bd5162859dbc482361e2f6aaf5b7a732e9a5929 100644 ---- a/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp -+++ b/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp -@@ -588,7 +588,7 @@ void PopulateLanguages() { - // sufficient to only collect this information as the other properties are - // just reformats of Navigator::GetAcceptLanguages. - nsTArray languages; -- dom::Navigator::GetAcceptLanguages(languages); -+ dom::Navigator::GetAcceptLanguages(nullptr, languages); - nsCString output = "["_ns; - - for (const auto& language : languages) { -diff --git a/toolkit/components/startup/nsAppStartup.cpp b/toolkit/components/startup/nsAppStartup.cpp -index d8f0c072c8a52c2837d87fe749ccac6e3e59e48a..6837927e6a49a8ff4c9f709502bf8d8983bd735c 100644 ---- a/toolkit/components/startup/nsAppStartup.cpp -+++ b/toolkit/components/startup/nsAppStartup.cpp -@@ -361,7 +361,7 @@ nsAppStartup::Quit(uint32_t aMode, int aExitCode, bool* aUserAllowedQuit) { - nsCOMPtr windowEnumerator; - nsCOMPtr 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 c0d60b927542653ab9beee730ec2c07f4b3d911c..85c416315f567a5edf8cfc89262dd7a48250dfd6 100644 ---- a/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp -+++ b/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp -@@ -176,8 +176,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 622ff7fe214d22e1e5d5a561753cffe3e1eafe31..ac2f30e00a9a6d18c61d00b0d6d4bf41ff48af95 100644 ---- a/toolkit/components/windowwatcher/nsWindowWatcher.cpp -+++ b/toolkit/components/windowwatcher/nsWindowWatcher.cpp -@@ -1882,7 +1882,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.sys.mjs b/toolkit/mozapps/update/UpdateService.sys.mjs -index 5d5a3f2c46138b578b583ad4a3506e1d227607ad..6d414635b80a74edb0b5ecfc6a98dd0fee763952 100644 ---- a/toolkit/mozapps/update/UpdateService.sys.mjs -+++ b/toolkit/mozapps/update/UpdateService.sys.mjs -@@ -3874,6 +3874,8 @@ export class UpdateService { - } - - get disabledForTesting() { -+ /* playwright */ -+ return true; - return lazy.UpdateServiceStub.updateDisabledForTesting; - } - -diff --git a/toolkit/toolkit.mozbuild b/toolkit/toolkit.mozbuild -index e8399d277ec0b64e5ea29aa7262b118936a02779..983ed73ad1d6d734af55a9066a8e8a6cf3ae3f45 100644 ---- a/toolkit/toolkit.mozbuild -+++ b/toolkit/toolkit.mozbuild -@@ -155,6 +155,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 7eb9e1104682d4eb47060654f43a1efa8b2a6bb2..a8315d6decf654b5302bea5beeea34140c300ded 100644 ---- a/toolkit/xre/nsWindowsWMain.cpp -+++ b/toolkit/xre/nsWindowsWMain.cpp -@@ -14,8 +14,10 @@ - #endif - - #include "mozilla/Char16.h" -+#include "mozilla/CmdLineAndEnvUtils.h" - #include "nsUTF8Utils.h" - -+#include - #include - - #ifdef __MINGW32__ -@@ -114,6 +116,19 @@ static void FreeAllocStrings(int argc, char** argv) { - int wmain(int argc, WCHAR** argv) { - SanitizeEnvironmentVariables(); - SetDllDirectoryW(L""); -+ bool hasJugglerPipe = -+ mozilla::CheckArg(argc, argv, "juggler-pipe", 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 9ef5370d1524ddecb965785a73a3cfea39867324..e0245cca94e496bcffba40c9660a52b518803d44 100644 ---- a/uriloader/base/nsDocLoader.cpp -+++ b/uriloader/base/nsDocLoader.cpp -@@ -861,6 +861,12 @@ void nsDocLoader::DocLoaderIsEmpty(bool aFlushLayout, - ("DocLoader:%p: Firing load event for document.open\n", - this)); - -+ nsCOMPtr 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 5bd60b585b53cc77e75c0b68c763957f90b7e164..940b3b62b09ca70ae5e69c3e94eda11ad35b9dfe 100644 ---- a/uriloader/exthandler/nsExternalHelperAppService.cpp -+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp -@@ -112,6 +112,7 @@ - - #include "mozilla/Components.h" - #include "mozilla/ClearOnShutdown.h" -+#include "mozilla/ErrorNames.h" - #include "mozilla/Preferences.h" - #include "mozilla/ipc/URIUtils.h" - -@@ -865,6 +866,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); -@@ -1500,7 +1507,12 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel* aChannel) { - // Strip off the ".part" from mTempLeafName - mTempLeafName.Truncate(mTempLeafName.Length() - std::size(".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); -@@ -1684,7 +1696,36 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { - return NS_OK; - } - -- rv = SetUpTempFile(aChannel); -+ bool isIntercepted = false; -+ nsCOMPtr interceptor = mExtProtSvc->mInterceptor; -+ if (interceptor) { -+ nsCOMPtr 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; - -@@ -1745,6 +1786,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 -@@ -2261,6 +2305,16 @@ nsExternalAppHandler::OnSaveComplete(nsIBackgroundFileSaver* aSaver, - NotifyTransfer(aStatus); - } - -+ if (!mCanceled) { -+ nsCOMPtr 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; - } - -@@ -2744,6 +2798,15 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason) { - } - } - -+ nsCOMPtr 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 26dfc6f04298420317c8b87b2ecc3f2f47f59598..c458ab5efb238c62499ee13452f2d750e0569e38 100644 ---- a/uriloader/exthandler/nsExternalHelperAppService.h -+++ b/uriloader/exthandler/nsExternalHelperAppService.h -@@ -263,6 +263,8 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService, - mozilla::dom::BrowsingContext* aContentContext, bool aForceSave, - nsIInterfaceRequestor* aWindowContext, - nsIStreamListener** aStreamListener); -+ -+ nsCOMPtr mInterceptor; - }; - - /** -@@ -460,6 +462,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 e6490ebb086eb4dca9db560c14e073a9e7722e29..2792373dcb30ebc787a9bdca306ac12e72aa19ec 100644 ---- a/uriloader/exthandler/nsIExternalHelperAppService.idl -+++ b/uriloader/exthandler/nsIExternalHelperAppService.idl -@@ -6,8 +6,11 @@ - - #include "nsICancelable.idl" - -+webidl BrowsingContext; -+interface nsIHelperAppLauncher; - interface nsIURI; - interface nsIChannel; -+interface nsIRequest; - interface nsIStreamListener; - interface nsIFile; - interface nsIMIMEInfo; -@@ -15,6 +18,17 @@ interface nsIWebProgressListener2; - interface nsIInterfaceRequestor; - webidl BrowsingContext; - -+/** -+ * Interceptor interface used by Juggler. -+ */ -+[scriptable, uuid(9a20e9b0-75d0-11ea-bc55-0242ac130003)] -+interface nsIDownloadInterceptor : nsISupports -+{ -+ boolean 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. -@@ -87,6 +101,8 @@ interface nsIExternalHelperAppService : nsISupports - * `DownloadIntegration.sys.mjs`, which is implemented on all platforms. - */ - nsIFile getPreferredDownloadsDirectory(); -+ -+ void setDownloadInterceptor(in nsIDownloadInterceptor interceptor); - }; - - /** -diff --git a/widget/InProcessCompositorWidget.cpp b/widget/InProcessCompositorWidget.cpp -index 7098db301770ecb5b9a506d7caec89d5cf63384b..aff8d7562f8a3e595a077ce8e591008762479587 100644 ---- a/widget/InProcessCompositorWidget.cpp -+++ b/widget/InProcessCompositorWidget.cpp -@@ -5,8 +5,11 @@ - #include "InProcessCompositorWidget.h" - -+#include "HeadlessCompositorWidget.h" -+#include "HeadlessWidget.h" - #include "mozilla/VsyncDispatcher.h" -+#include "mozilla/widget/PlatformWidgetTypes.h" - #include "mozilla/layers/NativeLayer.h" - #include "nsIWidget.h" - - namespace mozilla { -@@ -26,6 +29,12 @@ RefPtr CompositorWidget::CreateLocal( - // do it after the static_cast. - nsIWidget* widget = static_cast(aWidget)); -+ } - return new InProcessCompositorWidget(aOptions, widget); - } - #endif -diff --git a/widget/MouseEvents.h b/widget/MouseEvents.h -index 4f7ca9d0d460da3124ec8489917a9484661d5624..a04c3661b3e1e2be030ac6fe90041c81e653d26e 100644 ---- a/widget/MouseEvents.h -+++ b/widget/MouseEvents.h -@@ -380,6 +380,9 @@ class WidgetMouseEvent : public WidgetMouseEventBase, - // Otherwise, this must be 0. - uint32_t mClickCount = 0; - -+ // Unique event ID -+ uint32_t mJugglerEventId = 0; -+ - // Whether the event should ignore scroll frame bounds during dispatch. - bool mIgnoreRootScrollFrame = false; - -@@ -407,6 +410,7 @@ class WidgetMouseEvent : public WidgetMouseEventBase, - mContextMenuTrigger = aEvent.mContextMenuTrigger; - mExitFrom = aEvent.mExitFrom; - mClickCount = aEvent.mClickCount; -+ mJugglerEventId = aEvent.mJugglerEventId; - mIgnoreRootScrollFrame = aEvent.mIgnoreRootScrollFrame; - mIgnoreCapturingContent = aEvent.mIgnoreCapturingContent; - mClickEventPrevented = aEvent.mClickEventPrevented; -diff --git a/widget/cocoa/NativeKeyBindings.mm b/widget/cocoa/NativeKeyBindings.mm -index 24b70173c2e8bb9be9fd6255984a70efe3b14099..75ac367a1c4bb44d4b68b5f4ecc6adf56dbd408e 100644 ---- a/widget/cocoa/NativeKeyBindings.mm -+++ b/widget/cocoa/NativeKeyBindings.mm -@@ -549,6 +549,13 @@ void NativeKeyBindings::GetEditCommandsForTests( - 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())) { -@@ -571,6 +578,13 @@ void NativeKeyBindings::GetEditCommandsForTests( - 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())) { -@@ -593,6 +607,10 @@ void NativeKeyBindings::GetEditCommandsForTests( - 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()) { -@@ -603,7 +621,7 @@ void NativeKeyBindings::GetEditCommandsForTests( - !aEvent.IsShift() - ? ToObjcSelectorPtr(@selector(moveToBeginningOfDocument:)) - : ToObjcSelectorPtr( -- @selector(moveToBegginingOfDocumentAndModifySelection:)), -+ @selector(moveToBeginningOfDocumentAndModifySelection:)), - aCommands); - break; - } -@@ -630,6 +648,10 @@ void NativeKeyBindings::GetEditCommandsForTests( - 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/gtk/nsFilePicker.cpp b/widget/gtk/nsFilePicker.cpp -index f09b0e4994304413cbd75f14e6650cf3f9df9025..41c184e74df2b9c59315a236506946bcb5d69216 100644 ---- a/widget/gtk/nsFilePicker.cpp -+++ b/widget/gtk/nsFilePicker.cpp -@@ -21,7 +21,8 @@ - #include "mozilla/Components.h" - #include "mozilla/Preferences.h" - #include "mozilla/dom/Promise.h" -+#include "gfxPlatform.h" - #include "mozilla/dom/Document.h" - - #include "nsArrayEnumerator.h" - #include "nsEnumeratorUtils.h" -diff --git a/widget/headless/HeadlessCompositorWidget.cpp b/widget/headless/HeadlessCompositorWidget.cpp -index bb4ee9175e66dc40de1871a7f91368fe309494a3..6814ae85038d31f1a3b1f87ba341219ffbc1e6b3 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" -@@ -15,9 +16,30 @@ HeadlessCompositorWidget::HeadlessCompositorWidget( - const layers::CompositorOptions& aOptions, HeadlessWidget* aWindow) - : CompositorWidget(aOptions), - mWidget(aWindow), -+ mMon("snapshotListener"), - mClientSize(LayoutDeviceIntSize(aInitData.InitialClientSize()), - "HeadlessCompositorWidget::mClientSize") {} - -+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 HeadlessCompositorWidget::StartRemoteDrawingInRegion( -+ const LayoutDeviceIntRegion& aInvalidRegion) { -+ if (!mDrawTarget) -+ return nullptr; -+ -+ RefPtr result = mDrawTarget; -+ return result.forget(); -+} -+ - void HeadlessCompositorWidget::ObserveVsync(VsyncObserver* aObserver) { - if (RefPtr cvd = - mWidget->GetCompositorVsyncDispatcher()) { -@@ -31,6 +53,59 @@ void HeadlessCompositorWidget::NotifyClientSizeChanged( - const LayoutDeviceIntSize& aClientSize) { - auto size = mClientSize.Lock(); - *size = aClientSize; -+ layers::CompositorThread()->Dispatch(NewRunnableMethod( -+ "HeadlessCompositorWidget::UpdateDrawTarget", this, -+ &HeadlessCompositorWidget::UpdateDrawTarget, -+ aClientSize)); -+} -+ -+void HeadlessCompositorWidget::UpdateDrawTarget(const LayoutDeviceIntSize& aClientSize) { -+ MOZ_ASSERT(NS_IsInCompositorThread()); -+ if (aClientSize.IsEmpty()) { -+ mDrawTarget = nullptr; -+ return; -+ } -+ -+ RefPtr 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 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 snapshot = mDrawTarget->Snapshot(); -+ if (!snapshot) { -+ fprintf(stderr, "Failed to get snapshot of draw target\n"); -+ return; -+ } -+ -+ RefPtr 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 facd2bc65afab8ec1aa322faa20a67464964dfb9..3c5751ad1b7f042bc7cd9a63895cebcd2942ccd3 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,11 @@ class HeadlessCompositorWidget final : public CompositorWidget, - HeadlessWidget* aWindow); - - void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize); -+ void SetSnapshotListener(HeadlessWidget::SnapshotListener&& listener); - - // CompositorWidget Overrides -+ already_AddRefed StartRemoteDrawingInRegion( -+ const LayoutDeviceIntRegion& aInvalidRegion) override; - - uintptr_t GetWidgetKey() override; - -@@ -42,10 +46,18 @@ class HeadlessCompositorWidget final : public CompositorWidget, - } - - private: -+ void UpdateDrawTarget(const LayoutDeviceIntSize& aClientSize); -+ void PeriodicSnapshot(); -+ void TakeSnapshot(); -+ - HeadlessWidget* mWidget; -+ mozilla::ReentrantMonitor mMon; - - // See GtkCompositorWidget for the justification for this mutex. - DataMutex mClientSize; -+ -+ HeadlessWidget::SnapshotListener mSnapshotListener; -+ RefPtr mDrawTarget; - }; - - } // namespace widget -diff --git a/widget/headless/HeadlessWidget.cpp b/widget/headless/HeadlessWidget.cpp -index 290de12f9d0ff858474564fa8ce54814a04f6088..c144a891b84c3c57f394d6d551e6c89dcd6d9829 100644 ---- a/widget/headless/HeadlessWidget.cpp -+++ b/widget/headless/HeadlessWidget.cpp -@@ -112,6 +112,8 @@ void HeadlessWidget::Destroy() { - } - } - -+ SetSnapshotListener(nullptr); -+ - nsBaseWidget::OnDestroy(); - - nsBaseWidget::Destroy(); -@@ -593,5 +595,14 @@ nsresult HeadlessWidget::SynthesizeNativeTouchpadPan( - 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 60598d097d9dae829ebdc15dede78bd915e3107d..3b5ac5e5590dcb36440e28569f71592db3c1218c 100644 ---- a/widget/headless/HeadlessWidget.h -+++ b/widget/headless/HeadlessWidget.h -@@ -131,6 +131,9 @@ class HeadlessWidget final : public nsBaseWidget { - double aDeltaX, double aDeltaY, int32_t aModifierFlags, - nsISynthesizedEventCallback* aCallback) override; - -+ using SnapshotListener = std::function&&)>; -+ void SetSnapshotListener(SnapshotListener&& listener); -+ - private: - ~HeadlessWidget(); - bool mEnabled; -diff --git a/widget/nsGUIEventIPC.h b/widget/nsGUIEventIPC.h -index 2f4c33f151870bb9233899b186a5eccfaa6f5da6..6acf66e4938e3f9727916824a08d6294f8993452 100644 ---- a/widget/nsGUIEventIPC.h -+++ b/widget/nsGUIEventIPC.h -@@ -251,6 +251,7 @@ struct ParamTraits { - aParam.mExitFrom.value())); - } - WriteParam(aWriter, aParam.mClickCount); -+ WriteParam(aWriter, aParam.mJugglerEventId); - } - - static bool Read(MessageReader* aReader, paramType* aResult) { -@@ -275,6 +276,7 @@ struct ParamTraits { - aResult->mExitFrom = Some(static_cast(exitFrom)); - } - rv = rv && ReadParam(aReader, &aResult->mClickCount); -+ rv = rv && ReadParam(aReader, &aResult->mJugglerEventId); - return rv; - } - }; -diff --git a/xpcom/reflect/xptinfo/xptinfo.h b/xpcom/reflect/xptinfo/xptinfo.h -index 787d30d881adedd57d2025ca57bff4bc6c57e803..ae1a0172c960ab16919133485722d2ae0cdbcbd4 100644 ---- a/xpcom/reflect/xptinfo/xptinfo.h -+++ b/xpcom/reflect/xptinfo/xptinfo.h -@@ -505,7 +505,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 - - /** diff --git a/patches/playwright/0-playwright.patch.bak2 b/patches/playwright/0-playwright.patch.bak2 deleted file mode 100644 index 3e3ba5bc..00000000 --- a/patches/playwright/0-playwright.patch.bak2 +++ /dev/null @@ -1,3469 +0,0 @@ -diff --git a/accessible/interfaces/nsIAccessibleDocument.idl b/accessible/interfaces/nsIAccessibleDocument.idl -index 6c932c14a03e9cbf70723171dc9a1006bd2c017d..6312131c94c6d7e994a4a49dd64b2b4c5777251f 100644 ---- a/accessible/interfaces/nsIAccessibleDocument.idl -+++ b/accessible/interfaces/nsIAccessibleDocument.idl -@@ -73,4 +73,9 @@ interface nsIAccessibleDocument : nsISupports - * The BrowsingContext of this document. - */ - readonly attribute BrowsingContext browsingContext; -+ -+ /** -+ * Return whether it is updating. -+ */ -+ readonly attribute boolean isUpdatePendingForJugglerAccessibility; - }; -diff --git a/accessible/xpcom/xpcAccessibleDocument.cpp b/accessible/xpcom/xpcAccessibleDocument.cpp -index 3229ee415b93b9a47d7d40605ed7b509744c94ad..c2cc38ded257a02de8922312057892bf9d0cad7b 100644 ---- a/accessible/xpcom/xpcAccessibleDocument.cpp -+++ b/accessible/xpcom/xpcAccessibleDocument.cpp -@@ -151,6 +151,13 @@ xpcAccessibleDocument::GetBrowsingContext( - return NS_OK; - } - -+NS_IMETHODIMP -+xpcAccessibleDocument::GetIsUpdatePendingForJugglerAccessibility(bool* updating) { -+ NS_ENSURE_ARG_POINTER(updating); -+ *updating = Intl()->Controller()->IsUpdatePending(); -+ return NS_OK; -+} -+ - //////////////////////////////////////////////////////////////////////////////// - // xpcAccessibleDocument - -diff --git a/accessible/xpcom/xpcAccessibleDocument.h b/accessible/xpcom/xpcAccessibleDocument.h -index 9b6effc38fbecb50897a93b49c41d4453b10fb7f..939ff9615bd422eec186d8164e2ac7e643f39beb 100644 ---- a/accessible/xpcom/xpcAccessibleDocument.h -+++ b/accessible/xpcom/xpcAccessibleDocument.h -@@ -48,6 +48,8 @@ class xpcAccessibleDocument : public xpcAccessibleHyperText, - nsIAccessibleDocument** aDocument) final; - NS_IMETHOD GetBrowsingContext(dom::BrowsingContext** aBrowsingContext) 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 8167d2b81c918e02ce757f7f448f22e07c29d140..3ae798880acfd8aa965ae08051f2f81855133711 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 - #include - #include - -@@ -422,8 +423,18 @@ Maybe 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, "juggler-pipe", 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(stdio3), -+ reinterpret_cast(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 6bbc4016cd6d56e8625e808b5070515a23de7600..2fb56fb1afa5b108a426737cb5e62dc42a199354 100644 ---- a/browser/installer/allowed-dupes.mn -+++ b/browser/installer/allowed-dupes.mn -@@ -59,6 +59,12 @@ browser/chrome/browser/builtin-addons/webcompat/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 -+ - # Bug 1606928 - There's no reliable way to connect Top Sites favicons with the favicons in the Search Service - browser/chrome/browser/content/activity-stream/data/content/tippytop/favicons/allegro-pl.ico - browser/defaults/settings/main/search-config-icons/96327a73-c433-5eb4-a16d-b090cadfb80b -diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in -index 2b4d35e060dc592bb70a1f2b7ceee68616c8202b..323abfaee37445942f7678037dd5b53792dd5ed4 100644 ---- a/browser/installer/package-manifest.in -+++ b/browser/installer/package-manifest.in -@@ -183,6 +183,9 @@ - @RESPATH@/chrome/remote.manifest - #endif - -+@RESPATH@/chrome/juggler@JAREXT@ -+@RESPATH@/chrome/juggler.manifest -+ - ; Modules - @RESPATH@/browser/modules/* - @RESPATH@/modules/* -diff --git a/devtools/server/socket/websocket-server.js b/devtools/server/socket/websocket-server.js -index d49c6fbf1bf83b832795fa674f6b41f223eef812..7ea3540947ff5f61b15f27fbf4b955649f8e9ff9 100644 ---- a/devtools/server/socket/websocket-server.js -+++ b/devtools/server/socket/websocket-server.js -@@ -134,13 +134,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"); - } - -@@ -190,13 +189,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, [ -@@ -218,8 +217,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 97334bee3a111a538779789d3495805cec8b1e9a..67d030f2adecd9acc62665e2a627123148aa927d 100644 ---- a/docshell/base/BrowsingContext.cpp -+++ b/docshell/base/BrowsingContext.cpp -@@ -110,8 +110,15 @@ struct ParamTraits - - template <> - struct ParamTraits -- : public mozilla::dom::WebIDLEnumSerializer< -- mozilla::dom::PrefersColorSchemeOverride> {}; -+ : public mozilla::dom::WebIDLEnumSerializer {}; -+ -+template <> -+struct ParamTraits -+ : public mozilla::dom::WebIDLEnumSerializer {}; -+ -+template <> -+struct ParamTraits -+ : public mozilla::dom::WebIDLEnumSerializer {}; - - template <> - struct ParamTraits -@@ -2950,6 +2957,32 @@ void BrowsingContext::DidSet(FieldIndex, - }); - } - -+void BrowsingContext::DidSet(FieldIndex, -+ dom::PrefersContrastOverride aOldValue) { -+ MOZ_ASSERT(IsTop()); -+ if (PrefersContrastOverride() == aOldValue) { -+ return; -+ } -+ PresContextAffectingFieldChanged(); -+} -+ -+void BrowsingContext::DidSet(FieldIndex, -+ 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, - nsString&& aOldValue) { - MOZ_ASSERT(IsTop()); -@@ -3290,7 +3323,7 @@ void BrowsingContext::SetGeolocationServiceOverride( - if (aGeolocationOverride.WasPassed()) { - if (!mGeolocationServiceOverride) { - mGeolocationServiceOverride = new nsGeolocationService(); -- mGeolocationServiceOverride->Init(); -+ mGeolocationServiceOverride->Init(true /* isOverride */); - } - mGeolocationServiceOverride->Update(aGeolocationOverride.Value()); - } else if (RefPtr serviceOverride = -@@ -3793,6 +3826,23 @@ void BrowsingContext::DidSet(FieldIndex, - } - } - -+void BrowsingContext::DidSet(FieldIndex, bool aOldValue) { -+ const bool newValue = ForceOffline(); -+ if (newValue == aOldValue) { -+ return; -+ } -+ PreOrderWalk([&](BrowsingContext* aContext) { -+ if (Document* doc = aContext->GetDocument()) { -+ if (nsPIDOMWindowOuter* win = aContext->GetDOMWindow()) { -+ nsContentUtils::DispatchTrustedEvent( -+ doc, nsGlobalWindowOuter::Cast(win), -+ newValue ? u"offline"_ns : u"online"_ns, -+ CanBubble::eYes, Cancelable::eYes, nullptr); -+ } -+ } -+ }); -+} -+ - bool BrowsingContext::IsPopupAllowed() { - for (auto* context = GetCurrentWindowContext(); context; - context = context->GetParentWindowContext()) { -diff --git a/docshell/base/BrowsingContext.h b/docshell/base/BrowsingContext.h -index b42c32133c6490755ae4e1c599255418e6443011..afa502833ba55c94dbd30726d37450c460a69e2b 100644 ---- a/docshell/base/BrowsingContext.h -+++ b/docshell/base/BrowsingContext.h -@@ -209,11 +209,11 @@ struct EmbedderColorSchemes { - FIELD(GVInaudibleAutoplayRequestStatus, GVAutoplayRequestStatus) \ - /* ScreenOrientation-related APIs */ \ - FIELD(CurrentOrientationAngle, float) \ -- FIELD(CurrentOrientationType, mozilla::dom::OrientationType) \ -+ FIELD(CurrentOrientationType, dom::OrientationType) \ - FIELD(OrientationLock, mozilla::hal::ScreenOrientation) \ - FIELD(HasOrientationOverride, bool) \ - FIELD(UserAgentOverride, nsString) \ -- FIELD(TouchEventsOverrideInternal, mozilla::dom::TouchEventsOverride) \ -+ FIELD(TouchEventsOverrideInternal, dom::TouchEventsOverride) \ - FIELD(EmbedderElementType, Maybe) \ - FIELD(MessageManagerGroup, nsString) \ - FIELD(MaxTouchPointsOverride, uint8_t) \ -@@ -253,6 +256,9 @@ struct EmbedderColorSchemes { - * embedder element. */ \ - FIELD(EmbedderColorSchemes, EmbedderColorSchemes) \ - FIELD(DisplayMode, dom::DisplayMode) \ -+ /* playwright addition */ \ -+ FIELD(PrefersReducedMotionOverride, dom::PrefersReducedMotionOverride) \ -+ FIELD(PrefersContrastOverride, dom::PrefersContrastOverride) \ - /* The number of entries added to the session history because of this \ - * browsing context. */ \ - FIELD(HistoryEntryCount, uint32_t) \ -@@ -975,6 +978,14 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - return GetForcedColorsOverride(); - } - -+ dom::PrefersReducedMotionOverride PrefersReducedMotionOverride() const { -+ return GetPrefersReducedMotionOverride(); -+ } -+ -+ dom::PrefersContrastOverride PrefersContrastOverride() const { -+ return GetPrefersContrastOverride(); -+ } -+ - bool IsInBFCache() const; - - bool AllowJavascript() const { return GetAllowJavascript(); } -@@ -1146,6 +1157,11 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - return IsTop(); - } - -+ bool CanSet(FieldIndex, -+ dom::PrefersContrastOverride, ContentParent*) { -+ return IsTop(); -+ } -+ - bool CanSet(FieldIndex, dom::ForcedColorsOverride, - ContentParent*) { - return IsTop(); -@@ -1278,13 +1297,25 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - void DidSet(FieldIndex, - dom::ForcedColorsOverride aOldValue); - -+ void DidSet(FieldIndex, -+ dom::PrefersContrastOverride aOldValue); -+ - template - void WalkPresContexts(Callback&&); - void PresContextAffectingFieldChanged(); - - void DidSet(FieldIndex, nsCString&& aOldValue); - - void DidSet(FieldIndex, nsString&& aOldValue); - -+ bool CanSet(FieldIndex, -+ dom::PrefersReducedMotionOverride, ContentParent*) { -+ return IsTop(); -+ } -+ -+ void DidSet(FieldIndex, -+ dom::PrefersReducedMotionOverride aOldValue); -+ -+ - void DidSet(FieldIndex, nsString&& aOldValue); - - bool CanSet(FieldIndex, bool, ContentParent*) { -@@ -1360,6 +1388,8 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - - void DidSet(FieldIndex, bool aOldValue); - -+ void DidSet(FieldIndex, bool aOldValue); -+ - // Allow if the process attemping to set field is the same as the owning - // process. Deprecated. New code that might use this should generally be moved - // to WindowContext or be settable only by the parent process. -diff --git a/docshell/base/CanonicalBrowsingContext.cpp b/docshell/base/CanonicalBrowsingContext.cpp -index 4953744c3f627bb68b78606d8ae4bf6ab649398a..17c7cc94dafc76cd72aacddfd633b7df58eeae78 100644 ---- a/docshell/base/CanonicalBrowsingContext.cpp -+++ b/docshell/base/CanonicalBrowsingContext.cpp -@@ -274,7 +274,9 @@ void CanonicalBrowsingContext::ReplacedBy( - txn.SetForceOffline(GetForceOffline()); - txn.SetTopInnerSizeForRFP(GetTopInnerSizeForRFP()); - txn.SetIPAddressSpace(GetIPAddressSpace()); -+ txn.SetPrefersReducedMotionOverride(GetPrefersReducedMotionOverride()); -+ txn.SetForcedColorsOverride(GetForcedColorsOverride()); - txn.SetParentalControlsEnabled(GetParentalControlsEnabled()); - - if (!GetLanguageOverride().IsEmpty()) { - // Reapply language override to update the corresponding realm. - txn.SetLanguageOverride(GetLanguageOverride()); - } - if (!GetTimezoneOverride().IsEmpty()) { - // Reapply timezone override to update the corresponding realm. -@@ -1908,6 +1910,12 @@ void CanonicalBrowsingContext::LoadURI(nsIURI* aURI, - return; - } - -+ { -+ nsCOMPtr observerService = mozilla::services::GetObserverService(); -+ if (observerService) { -+ observerService->NotifyObservers(ToSupports(this), "juggler-navigation-started-browser", NS_ConvertASCIItoUTF16(nsPrintfCString("%" PRIu64, loadState->GetLoadIdentifier())).get()); -+ } -+ } - LoadURI(loadState, true); - } - -diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp -index bf702818cf4116ec1cd911b6e7b5f7ddafa3e508..d846e5f6f900d2d69228331b80031bd1c18b08ed 100644 ---- a/docshell/base/nsDocShell.cpp -+++ b/docshell/base/nsDocShell.cpp -@@ -18,6 +18,12 @@ - #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/Attributes.h" - #include "mozilla/AutoRestore.h" - #include "mozilla/BasePrincipal.h" -@@ -67,6 +73,7 @@ - #include "mozilla/dom/DocGroup.h" - #include "mozilla/dom/Element.h" - #include "mozilla/dom/FragmentDirective.h" -+#include "mozilla/dom/Geolocation.h" - #include "mozilla/dom/HTMLAnchorElement.h" - #include "mozilla/dom/HTMLIFrameElement.h" - #include "mozilla/dom/Navigation.h" -@@ -98,6 +105,7 @@ - #include "mozilla/dom/DocumentBinding.h" - #include "mozilla/glean/DocshellMetrics.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" -@@ -122,6 +130,7 @@ - #include "nsIDocumentViewer.h" - #include "mozilla/dom/Document.h" - #include "nsHTMLDocument.h" -+#include "mozilla/dom/Element.h" - #include "nsIDocumentLoaderFactory.h" - #include "nsIDOMWindow.h" - #include "nsIEditingSession.h" -@@ -217,6 +226,7 @@ - #include "nsGlobalWindowInner.h" - #include "nsGlobalWindowOuter.h" - #include "nsJSEnvironment.h" -+#include "nsJSUtils.h" - #include "nsNetCID.h" - #include "nsNetUtil.h" - #include "nsObjectLoadingContent.h" -@@ -358,6 +368,14 @@ nsDocShell::nsDocShell(BrowsingContext* aBrowsingContext, - mAllowDNSPrefetch(true), - mAllowWindowControl(true), - mCSSErrorReportingEnabled(false), -+ mFileInputInterceptionEnabled(false), -+ mOverrideHasFocus(false), -+ mBypassCSPEnabled(false), -+ mForceActiveState(false), -+ mDisallowBFCache(false), -+ mReducedMotionOverride(REDUCED_MOTION_OVERRIDE_NONE), -+ mForcedColorsOverride(FORCED_COLORS_OVERRIDE_NO_OVERRIDE), -+ mContrastOverride(CONTRAST_OVERRIDE_NONE), - mAllowAuth(mItemType == typeContent), - mAllowKeywordFixup(false), - mDisableMetaRefreshWhenInactive(false), -@@ -3037,6 +3055,232 @@ nsDocShell::GetMessageManager(ContentFrameMessageManager** aMessageManager) { - return NS_OK; - } - -+// =============== Juggler Begin ======================= -+ -+nsDocShell* nsDocShell::GetRootDocShell() { -+ nsCOMPtr rootAsItem; -+ GetInProcessSameTypeRootTreeItem(getter_AddRefs(rootAsItem)); -+ nsCOMPtr 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; -+} -+ -+NS_IMETHODIMP -+nsDocShell::GetDisallowBFCache(bool* aEnabled) { -+ MOZ_ASSERT(aEnabled); -+ *aEnabled = mDisallowBFCache; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetDisallowBFCache(bool aEnabled) { -+ mDisallowBFCache = aEnabled; -+ 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) { -+ 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 observerService = -+ mozilla::services::GetObserverService(); -+ observerService->NotifyObservers( -+ ToSupports(element), "juggler-file-picker-shown", nullptr); -+} -+ -+RefPtr 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::GetReducedMotionOverride(ReducedMotionOverride* aReducedMotionOverride) { -+ *aReducedMotionOverride = GetRootDocShell()->mReducedMotionOverride; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetReducedMotionOverride(ReducedMotionOverride aReducedMotionOverride) { -+ mReducedMotionOverride = aReducedMotionOverride; -+ RefPtr 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 presContext = GetPresContext(); -+ if (presContext) { -+ presContext->MediaFeatureValuesChanged( -+ {MediaFeatureChangeReason::SystemMetricsChange}, -+ MediaFeatureChangePropagation::JustThisDocument); -+ } -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::GetContrastOverride(ContrastOverride* aContrastOverride) { -+ *aContrastOverride = GetRootDocShell()->mContrastOverride; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetContrastOverride(ContrastOverride aContrastOverride) { -+ mContrastOverride = aContrastOverride; -+ RefPtr presContext = GetPresContext(); -+ if (presContext) { -+ presContext->MediaFeatureValuesChanged( -+ {MediaFeatureChangeReason::SystemMetricsChange}, -+ MediaFeatureChangePropagation::JustThisDocument); -+ } -+ return NS_OK; -+} -+ -+// =============== Juggler End ======================= -+ - NS_IMETHODIMP - nsDocShell::GetIsNavigating(bool* aOut) { - *aOut = mIsNavigating; -@@ -4819,7 +5063,7 @@ nsDocShell::GetVisibility(bool* aVisibility) { - } - - void nsDocShell::ActivenessMaybeChanged() { -- const bool isActive = mBrowsingContext->IsActive(); -+ const bool isActive = mForceActiveState || mBrowsingContext->IsActive(); - if (RefPtr presShell = GetPresShell()) { - presShell->ActivenessMaybeChanged(); - } -@@ -6881,6 +7125,10 @@ bool nsDocShell::CanSavePresentation(uint32_t aLoadType, - return false; // no entry to save into - } - -+ if (mDisallowBFCache) { -+ return false; -+ } -+ - MOZ_ASSERT(!mozilla::SessionHistoryInParent(), - "mOSHE cannot be non-null with SHIP"); - nsCOMPtr viewer = mOSHE->GetDocumentViewer(); -@@ -8637,6 +8885,12 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState) { - true, // aForceNoOpener - getter_AddRefs(newBC)); - MOZ_ASSERT(!newBC); -+ if (rv == NS_OK) { -+ nsCOMPtr observerService = mozilla::services::GetObserverService(); -+ if (observerService) { -+ observerService->NotifyObservers(GetAsSupports(this), "juggler-window-open-in-new-context", nullptr); -+ } -+ } - return rv; - } - -@@ -9934,6 +10188,16 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState, - nsINetworkPredictor::PREDICT_LOAD, attrs, nullptr); - - nsCOMPtr req; -+ -+ // Juggler: report navigation started for non-same-document and non-javascript -+ // navigations. -+ if (!isJavaScript && !sameDocument) { -+ nsCOMPtr observerService = -+ mozilla::services::GetObserverService(); -+ if (observerService) { -+ observerService->NotifyObservers(GetAsSupports(this), "juggler-navigation-started-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("%" PRIu64, aLoadState->GetLoadIdentifier())).get()); -+ } -+ } - rv = DoURILoad(aLoadState, aCacheKey, getter_AddRefs(req)); - - if (NS_SUCCEEDED(rv)) { -@@ -13323,6 +13587,9 @@ class OnLinkClickEvent : public Runnable { - mHandler->OnLinkClickSync(mContent, mLoadState, mNoOpenerImplied, - mTriggeringPrincipal); - } -+ nsCOMPtr observerService = mozilla::services::GetObserverService(); -+ observerService->NotifyObservers(ToSupports(mContent), "juggler-link-click-sync", nullptr); -+ - return NS_OK; - } - -@@ -13439,6 +13706,8 @@ nsresult nsDocShell::OnLinkClick( - - nsCOMPtr ev = new OnLinkClickEvent( - this, aContent, loadState, noOpenerImplied, aTriggeringPrincipal); -+ nsCOMPtr observerService = mozilla::services::GetObserverService(); -+ observerService->NotifyObservers(ToSupports(aContent), "juggler-link-click", nullptr); - return Dispatch(ev.forget()); - } - -diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h -index 3050f0a5a10c7f49f56cf325cd8bfe5e6508b5be..a4f4895f69a2eaa55f3eeae77bd6a3fb29931ad4 100644 ---- a/docshell/base/nsDocShell.h -+++ b/docshell/base/nsDocShell.h -@@ -16,6 +16,7 @@ - #include "mozilla/WeakPtr.h" - #include "mozilla/dom/BrowsingContext.h" - #include "mozilla/dom/NavigationBinding.h" -+#include "mozilla/dom/Element.h" - #include "mozilla/dom/WindowProxyHolder.h" - #include "nsCOMPtr.h" - #include "nsCharsetSource.h" -@@ -80,6 +81,7 @@ class nsCommandManager; - class nsDocShellEditorData; - class nsDOMNavigationTiming; - class nsDSURIContentListener; -+class nsGeolocationService; - class nsGlobalWindowOuter; - - class FramingChecker; -@@ -410,6 +412,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 GetGeolocationServiceOverride(); -+ - // Create a content viewer within this nsDocShell for the given - // `WindowGlobalChild` actor. - nsresult CreateDocumentViewerForActor( -@@ -1036,6 +1047,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 -@@ -1355,6 +1368,17 @@ 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; -+ bool mDisallowBFCache : 1; -+ nsString mLanguageOverride; -+ RefPtr mGeolocationServiceOverride; -+ ReducedMotionOverride mReducedMotionOverride; -+ ForcedColorsOverride mForcedColorsOverride; -+ ContrastOverride mContrastOverride; -+ - bool mAllowAuth : 1; - bool mAllowKeywordFixup : 1; - bool mDisableMetaRefreshWhenInactive : 1; -diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl -index 763c7adb5ab9e3e56d6f1608899f6622997f272a..4f77795b5ce1f8fff79581987e017165dbdcbc1e 100644 ---- a/docshell/base/nsIDocShell.idl -+++ b/docshell/base/nsIDocShell.idl -@@ -44,6 +44,7 @@ interface nsIURI; - interface nsIChannel; - interface nsIPolicyContainer; - interface nsIDocumentViewer; -+interface nsIDOMGeoPosition; - interface nsIEditor; - interface nsIEditingSession; - interface nsIInputStream; -@@ -719,6 +720,45 @@ interface nsIDocShell : nsIDocShellTreeItem - */ - void synchronizeLayoutHistoryState(); - -+ attribute boolean fileInputInterceptionEnabled; -+ -+ attribute boolean overrideHasFocus; -+ -+ attribute boolean bypassCSPEnabled; -+ -+ attribute boolean forceActiveState; -+ -+ attribute boolean disallowBFCache; -+ -+ attribute AString languageOverride; -+ -+ boolean overrideTimezone(in AString timezoneId); -+ -+ 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; -+ -+ cenum ContrastOverride : 8 { -+ CONTRAST_OVERRIDE_LESS, -+ CONTRAST_OVERRIDE_MORE, -+ CONTRAST_OVERRIDE_CUSTOM, -+ CONTRAST_OVERRIDE_NO_PREFERENCE, -+ CONTRAST_OVERRIDE_NONE, /* This clears the override. */ -+ }; -+ [infallible] attribute nsIDocShell_ContrastOverride contrastOverride; -+ -+ 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 40da41ae4ac7d8d61c664e25bec8a74091d8b3e0..50ee1170e6d5b261334c7baccc63ed492b86ec38 100644 ---- a/dom/base/Document.cpp -+++ b/dom/base/Document.cpp -@@ -3799,6 +3799,9 @@ void Document::SendToConsole(nsCOMArray& aMessages) { - } - - void Document::ApplySettingsFromCSP(bool aSpeculative) { -+ if (mDocumentContainer && mDocumentContainer->IsBypassCSPEnabled()) -+ return; -+ - nsresult rv = NS_OK; - if (!aSpeculative) { - nsIContentSecurityPolicy* csp = PolicyContainer::GetCSP(mPolicyContainer); -@@ -3887,6 +3890,11 @@ nsresult Document::InitCSP(nsIChannel* aChannel) { - MOZ_ASSERT(mPolicyContainer, - "Policy container must be initialized before CSP!"); - -+ nsCOMPtr 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; -@@ -4753,6 +4761,10 @@ bool Document::HasFocus(ErrorResult& rv) const { - return false; - } - -+ if (IsActive() && mDocumentContainer->ShouldOverrideHasFocus()) { -+ return true; -+ } -+ - if (!fm->IsInActiveWindow(bc)) { - return false; - } -@@ -20326,6 +20338,35 @@ ColorScheme Document::PreferredColorScheme(IgnoreRFP aIgnoreRFP) const { - return PreferenceSheet::PrefsFor(*this).mColorScheme; - } - -+bool Document::PrefersReducedMotion() const { -+ auto* docShell = static_cast(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: -+ break; -+ } -+ } -+ -+ return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1; -+} -+ - bool Document::HasRecentlyStartedForegroundLoads() { - if (!sLoadingForegroundTopLevelContentDocument) { - return false; -diff --git a/dom/base/Document.h b/dom/base/Document.h -index 20f726a52f9f3591502597e20eeb8c07fe35feb2..c46f58ac88d536850169e6c51b9cfcb871d36e70 100644 ---- a/dom/base/Document.h -+++ b/dom/base/Document.h -@@ -4252,6 +4252,8 @@ class Document : public nsINode, - // color-scheme meta tag. - ColorScheme DefaultColorScheme() const; - -+ bool PrefersReducedMotion() const; -+ - static bool HasRecentlyStartedForegroundLoads(); - - static bool AutomaticStorageAccessPermissionCanBeGranted( -diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp -index 11a57adbb57b0adccf7ae491e7d7757f838bd9dc..e478244cedc2089fb99b3153d7493b7d36d72ea9 100644 ---- a/dom/base/Navigator.cpp -+++ b/dom/base/Navigator.cpp -@@ -347,14 +347,18 @@ void Navigator::GetAppName(nsAString& aAppName) const { - * for more detail. - */ - /* static */ --void Navigator::GetAcceptLanguages(nsTArray& aLanguages) { -+void Navigator::GetAcceptLanguages(const nsString* aLanguageOverride, nsTArray& 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 : -@@ -406,7 +410,13 @@ void Navigator::GetLanguage(nsAString& aLanguage) { - } - - void Navigator::GetLanguages(nsTArray& aLanguages) { -- GetAcceptLanguages(aLanguages); -+ if (mWindow && mWindow->GetDocShell()) { -+ nsString languageOverride; -+ mWindow->GetDocShell()->GetLanguageOverride(languageOverride); -+ GetAcceptLanguages(&languageOverride, aLanguages); -+ } else { -+ GetAcceptLanguages(nullptr, aLanguages); -+ } - - @@ -2336,6 +2336,7 @@ bool Navigator::Webdriver() { - } - #endif - -- return false; -+ // Playwright is automating the browser, so we should pretend to be a webdriver -+ return true; - } - - AutoplayPolicy Navigator::GetAutoplayPolicy(AutoplayPolicyMediaType aType) { -diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h -index 893947475fbb8688becb1c1495385e4048d4927d..dfb50acf689223fdab7ef6f42afbbd53341e1b0b 100644 ---- a/dom/base/Navigator.h -+++ b/dom/base/Navigator.h -@@ -228,7 +228,7 @@ class Navigator final : public nsISupports, public nsWrapperCache { - - StorageManager* Storage(); - -- static void GetAcceptLanguages(nsTArray& aLanguages); -+ static void GetAcceptLanguages(const nsString* aLanguageOverride, nsTArray& aLanguages); - - dom::MediaCapabilities* MediaCapabilities(); - dom::MediaSession* MediaSession(); -diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp -index 7703ab18c104848eab9377769641d3b60e9bcf8e..3028fc5a7e6c54a7f4455f135e889d038eed378d 100644 ---- a/dom/base/nsContentUtils.cpp -+++ b/dom/base/nsContentUtils.cpp -@@ -9528,11 +9528,13 @@ nsresult nsContentUtils::SendMouseEvent( - int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, - float aPressure, unsigned short aInputSourceArg, uint32_t aIdentifier, - bool aToWindow, bool* aPreventDefault, bool aIsDOMEventSynthesized, -- bool aIsWidgetEventSynthesized) { -+ bool aIsWidgetEventSynthesized, -+ bool convertToPointer, uint32_t aJugglerEventId) { - MOZ_ASSERT(aWidget); - EventMessage msg; - Maybe exitFrom; - bool contextMenuKey = false; -+ bool isPWDragEventMessage = false; - if (aType.EqualsLiteral("mousedown")) { - msg = eMouseDown; - } else if (aType.EqualsLiteral("mouseup")) { -@@ -9558,6 +9560,12 @@ nsresult nsContentUtils::SendMouseEvent( - msg = eMouseHitTest; - } else if (aType.EqualsLiteral("MozMouseExploreByTouch")) { - msg = eMouseExploreByTouch; -+ } else if (aType.EqualsLiteral("dragover")) { -+ msg = eDragOver; -+ isPWDragEventMessage = true; -+ } else if (aType.EqualsLiteral("drop")) { -+ msg = eDrop; -+ isPWDragEventMessage = true; - } else { - return NS_ERROR_FAILURE; - } -@@ -9568,7 +9576,14 @@ nsresult nsContentUtils::SendMouseEvent( - - Maybe pointerEvent; - Maybe mouseEvent; -- if (IsPointerEventMessage(msg)) { -+ Maybe pwDragEvent; -+ -+ if (isPWDragEventMessage) { -+ pwDragEvent.emplace(true, msg, aWidget); -+ pwDragEvent->mReason = aIsWidgetEventSynthesized -+ ? WidgetMouseEvent::eSynthesized -+ : WidgetMouseEvent::eReal; -+ } else if (IsPointerEventMessage(msg)) { - MOZ_ASSERT(!aIsWidgetEventSynthesized, - "The event shouldn't be dispatched as a synthesized event"); - if (MOZ_UNLIKELY(aIsWidgetEventSynthesized)) { -@@ -9587,8 +9602,11 @@ nsresult nsContentUtils::SendMouseEvent( - contextMenuKey ? WidgetMouseEvent::eContextMenuKey - : WidgetMouseEvent::eNormal); - } -+ - WidgetMouseEvent& mouseOrPointerEvent = -+ pwDragEvent.isSome() ? pwDragEvent.ref() : - pointerEvent.isSome() ? pointerEvent.ref() : mouseEvent.ref(); -+ - mouseOrPointerEvent.pointerId = aIdentifier; - mouseOrPointerEvent.mModifiers = GetWidgetModifiers(aModifiers); - mouseOrPointerEvent.mButton = aButton; -@@ -9601,6 +9619,8 @@ nsresult nsContentUtils::SendMouseEvent( - mouseOrPointerEvent.mClickCount = aClickCount; - mouseOrPointerEvent.mFlags.mIsSynthesizedForTests = aIsDOMEventSynthesized; - mouseOrPointerEvent.mExitFrom = exitFrom; -+ mouseOrPointerEvent.mJugglerEventId = aJugglerEventId; -+ mouseOrPointerEvent.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 a1b96bce18e1904f4068057defa26142ebe8874b..f2fc14da57cf08139723980dedc33f2d3a9a431b 100644 ---- a/dom/base/nsContentUtils.h -+++ b/dom/base/nsContentUtils.h -@@ -3080,8 +3080,9 @@ class nsContentUtils { - int32_t aButton, int32_t aButtons, int32_t aClickCount, - int32_t aModifiers, bool aIgnoreRootScrollFrame, float aPressure, - unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow, -- bool* aPreventDefault, bool aIsDOMEventSynthesized, -- bool aIsWidgetEventSynthesized); -+ bool* aPreventDefault, -+ bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized, -+ bool convertToPointer = true, uint32_t aJugglerEventId = 0); - - static void FirePageShowEventForFrameLoaderSwap( - nsIDocShellTreeItem* aItem, -diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp -index c6c5833cd29ef041da348d4398513bab7ef2f9aa..424cc396bfc211bc7debb3df203cfa26da7a4c55 100644 ---- a/dom/base/nsDOMWindowUtils.cpp -+++ b/dom/base/nsDOMWindowUtils.cpp -@@ -707,6 +707,26 @@ nsDOMWindowUtils::GetPresShellId(uint32_t* aPresShellId) { - return NS_ERROR_FAILURE; - } - -+static uint32_t sJugglerEventId = 1000; -+ -+NS_IMETHODIMP -+nsDOMWindowUtils::JugglerSendMouseEvent( -+ const nsAString& aType, float aX, float aY, int32_t aButton, -+ int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, -+ float aPressure, unsigned short aInputSourceArg, -+ bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized, -+ int32_t aButtons, uint32_t aIdentifier, bool aDisablePointerEvent, -+ uint32_t* aJugglerEventId) { -+ *aJugglerEventId = ++sJugglerEventId; -+ return SendMouseEventCommon( -+ aType, aX, aY, aButton, aClickCount, aModifiers, aIgnoreRootScrollFrame, -+ aPressure, aInputSourceArg, -+ aIdentifier, false, -+ nullptr, aIsDOMEventSynthesized, -+ aIsWidgetEventSynthesized, -+ aButtons, !aDisablePointerEvent, *aJugglerEventId); -+} -+ - NS_IMETHODIMP - nsDOMWindowUtils::SendMouseEvent( - const nsAString& aType, float aX, float aY, int32_t aButton, -@@ -721,7 +741,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, true, 0); - } - - NS_IMETHODIMP -@@ -739,7 +759,7 @@ nsDOMWindowUtils::SendMouseEventToWindow( - aOptionalArgCount >= 7 ? aIdentifier : DEFAULT_MOUSE_POINTER_ID, true, - nullptr, aOptionalArgCount >= 4 ? aIsDOMEventSynthesized : true, - aOptionalArgCount >= 5 ? aIsWidgetEventSynthesized : false, -- aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED); -+ aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED, 0); - } - - NS_IMETHODIMP -@@ -748,7 +768,7 @@ 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, uint32_t aJugglerEventId) { - RefPtr presShell = GetPresShell(); - if (!presShell) { - return NS_ERROR_FAILURE; -@@ -765,7 +785,7 @@ nsDOMWindowUtils::SendMouseEventCommon( - presShell, widget, aType, refPoint, aButton, aButtons, aClickCount, - aModifiers, aIgnoreRootScrollFrame, aPressure, aInputSourceArg, - aPointerId, aToWindow, aPreventDefault, aIsDOMEventSynthesized, -- aIsWidgetEventSynthesized); -+ aIsWidgetEventSynthesized, aConvertToPointer, aJugglerEventId); - } - - NS_IMETHODIMP -diff --git a/dom/base/nsDOMWindowUtils.h b/dom/base/nsDOMWindowUtils.h -index 4553ad5e7696055e861be5f840f8ce2bc54a5b29..1afc16325fcb63a3e510bdc387c8386eccf5d48b 100644 ---- a/dom/base/nsDOMWindowUtils.h -+++ b/dom/base/nsDOMWindowUtils.h -@@ -94,7 +94,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, uint32_t aJugglerEventId = 0); - - MOZ_CAN_RUN_SCRIPT - nsresult SendTouchEventCommon( -diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp -index 62c4bfb96dbb6e64aeadd9e45c296905b7956811..83f1e7303e2ebabfc73921d9bd27a255304a2ea4 100644 ---- a/dom/base/nsFocusManager.cpp -+++ b/dom/base/nsFocusManager.cpp -@@ -1717,6 +1717,10 @@ Maybe nsFocusManager::SetFocusInner(Element* aNewContent, - (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)) { -@@ -2303,6 +2307,7 @@ bool nsFocusManager::BlurImpl(BrowsingContext* aBrowsingContextToClear, - bool aIsLeavingDocument, bool aAdjustWidget, - bool aRemainActive, Element* aElementToFocus, - uint64_t aActionId) { -+ - LOGFOCUS(("<>", aActionId)); - - // hold a reference to the focused content, which may be null -@@ -2346,6 +2351,11 @@ bool nsFocusManager::BlurImpl(BrowsingContext* aBrowsingContextToClear, - return true; - } - -+ // Playwright: emulate focused page by never bluring when leaving document. -+ if (XRE_IsContentProcess() && aIsLeavingDocument && docShell && nsDocShell::Cast(docShell)->ShouldOverrideHasFocus()) { -+ return true; -+ } -+ - // Keep a ref to presShell since dispatching the DOM event may cause - // the document to be destroyed. - RefPtr presShell = docShell->GetPresShell(); -@@ -3046,7 +3056,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 5e2844f6e65da71ca9e1dadb1a88a74ab45f485c..a8f033e17ffbc28261072d561c89914d4bd2e325 100644 ---- a/dom/base/nsGlobalWindowOuter.cpp -+++ b/dom/base/nsGlobalWindowOuter.cpp -@@ -2511,10 +2511,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)); -+ } - } - } - -@@ -2634,6 +2640,19 @@ void nsGlobalWindowOuter::DispatchDOMWindowCreated() { - } - } - -+void nsGlobalWindowOuter::JugglerDispatchDOMWindowReused() { -+ nsCOMPtr observerService = -+ mozilla::services::GetObserverService(); -+ if (observerService && mDoc) { -+ nsIPrincipal* principal = mDoc->NodePrincipal(); -+ if (!principal->IsSystemPrincipal()) { -+ observerService->NotifyObservers(static_cast(this), -+ "juggler-dom-window-reused", -+ nullptr); -+ } -+ } -+} -+ - void nsGlobalWindowOuter::ClearStatus() { SetStatusOuter(u""_ns); } - - void nsGlobalWindowOuter::SetDocShell(nsDocShell* aDocShell) { -diff --git a/dom/base/nsGlobalWindowOuter.h b/dom/base/nsGlobalWindowOuter.h -index 1fbb506b07714f9ab2a2c9aff3683aa7fec4b156..42878f8f0c6365c7e2958a3b35fce0e7db9abfff 100644 ---- a/dom/base/nsGlobalWindowOuter.h -+++ b/dom/base/nsGlobalWindowOuter.h -@@ -318,6 +318,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 7b8da8b4a5e8de02d0d2e1befc8407da88fbf890..533f3bf77e1ef78dd231ac899e3d8032938ea812 100644 ---- a/dom/base/nsINode.cpp -+++ b/dom/base/nsINode.cpp -@@ -1500,6 +1500,61 @@ void nsINode::GetBoxQuadsFromWindowOrigin(const BoxQuadOptions& aOptions, - mozilla::GetBoxQuadsFromWindowOrigin(this, aOptions, aResult, aRv); - } - -+static nsIFrame* GetFirstFrame(nsINode* aNode) { -+ if (!aNode->IsContent()) -+ return nullptr; -+ nsIFrame* frame = aNode->AsContent()->GetPrimaryFrame(FlushType::Frames); -+ if (!frame) { -+ FlattenedChildIterator iter(aNode->AsContent()); -+ for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { -+ frame = child->GetPrimaryFrame(FlushType::Frames); -+ if (frame) { -+ break; -+ } -+ } -+ } -+ return frame; -+} -+ -+void nsINode::ScrollRectIntoViewIfNeeded(int32_t x, int32_t y, -+ int32_t w, int32_t h, -+ ErrorResult& aRv) { -+ aRv = NS_ERROR_UNEXPECTED; -+ nsCOMPtr 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"); -+ } -+ nsIFrame* primaryFrame = GetFirstFrame(this); -+ if (!primaryFrame) { -+ return aRv.ThrowNotFoundError("Node does not have a layout object"); -+ } -+ aRv = NS_OK; -+ 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->ScrollFrameIntoView( -+ primaryFrame, Some(rect), -+ ScrollAxis(WhereToScroll::Center, WhenToScroll::IfNotFullyVisible), -+ ScrollAxis(WhereToScroll::Center, WhenToScroll::IfNotFullyVisible), -+ 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 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 c3d84856e1bc92caf0437be312ccdbf7a2726ba5..d81c8e7152ca79b0fbb1ebee0f6f3aa40d0f34e2 100644 ---- a/dom/base/nsINode.h -+++ b/dom/base/nsINode.h -@@ -2421,6 +2421,10 @@ class nsINode : public mozilla::dom::EventTarget { - nsTArray>& aResult, - ErrorResult& aRv); - -+ void ScrollRectIntoViewIfNeeded(int32_t x, int32_t y, -+ int32_t w, int32_t h, -+ ErrorResult& aRv); -+ - already_AddRefed ConvertQuadFromNode( - DOMQuad& aQuad, const TextOrElementOrDocument& aFrom, - const ConvertCoordinateOptions& aOptions, CallerType aCallerType, -diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp -index aed59277e27a5a90f4244dd4513f9b4feb5858c3..26750fa09bead1ffabb22482468dea5999899f18 100644 ---- a/dom/base/nsJSUtils.cpp -+++ b/dom/base/nsJSUtils.cpp -@@ -151,6 +151,11 @@ bool nsJSUtils::GetEnvironmentChainForElement(JSContext* aCx, Element* aElement, - 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 f32e21752d5013bf143eb45391ab9218debab08e..83763d2354dade2f8d2b7930ba18ae91c55133ad 100644 ---- a/dom/base/nsJSUtils.h -+++ b/dom/base/nsJSUtils.h -@@ -75,6 +75,7 @@ class nsJSUtils { - mozilla::dom::Element* aElement, - JS::EnvironmentChain& aEnvChain); - -+ 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 6d150cc3ad77f694af5aa943c60eac37ba0733c0..9e68e18601cfb3e9e9c03b4bf0057c1a3d50a9d5 100644 ---- a/dom/chrome-webidl/BrowsingContext.webidl -+++ b/dom/chrome-webidl/BrowsingContext.webidl -@@ -62,6 +62,26 @@ enum ForcedColorsOverride { - "active", - }; - -+/** -+ * CSS prefers-reduced-motion values. -+ */ -+enum PrefersReducedMotionOverride { -+ "none", -+ "reduce", -+ "no-preference", -+}; -+ -+/** -+ * CSS prefers-contrast values. -+ */ -+enum PrefersContrastOverride { -+ "none", -+ "no-preference", -+ "more", -+ "less", -+ "custom", -+}; -+ - /** - * Allowed overrides of platform/pref default behaviour for touch events. - */ -@@ -228,6 +248,12 @@ interface BrowsingContext { - // Forced-colors simulation, for DevTools - [SetterThrows] attribute ForcedColorsOverride forcedColorsOverride; - -+ // Reduced-Motion simulation, for DevTools. -+ [SetterThrows] attribute PrefersReducedMotionOverride prefersReducedMotionOverride; -+ -+ // Contrast simulation, for DevTools. -+ [SetterThrows] attribute PrefersContrastOverride prefersContrastOverride; -+ - /** - * 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/fetch/Fetch.cpp b/dom/fetch/Fetch.cpp -index 52cf33bfc863d5ef1d3ac889ddfba3023600d60a..ccb521f367b8ccc8c40d8bad78aa621ab1b074c0 100644 ---- a/dom/fetch/Fetch.cpp -+++ b/dom/fetch/Fetch.cpp -@@ -704,6 +704,12 @@ already_AddRefed FetchRequest(nsIGlobalObject* aGlobal, - ipcArgs.hasCSPEventListener() = false; - ipcArgs.isWorkerRequest() = false; - -+ /* --> Playwright: associate keep-alive fetch with the window */ -+ BrowsingContext* bc = window ? window->GetBrowsingContext() : nullptr; -+ if (bc) -+ ipcArgs.associatedBrowsingContextID() = bc->Id(); -+ /* <-- Playwright */ -+ - actor->DoFetchOp(ipcArgs); - - mozilla::glean::networking::fetch_keepalive_request_count.Get("main"_ns) -diff --git a/dom/fetch/FetchService.cpp b/dom/fetch/FetchService.cpp -index 1734429e8eeb155b742211ca58afcbeb73a8bf7c..15635a2e5c266f8085093a0d17288abe8ed54d9e 100644 ---- a/dom/fetch/FetchService.cpp -+++ b/dom/fetch/FetchService.cpp -@@ -268,6 +268,14 @@ RefPtr FetchService::FetchInstance::Fetch() { - net::ClassificationFlags({0, 0}) // TrackingFlags - ); - -+ /* --> Playwright: associate keep-alive fetch with the window */ -+ if (mArgsType == FetchArgsType::MainThreadFetch) { -+ auto& args = mArgs.as(); -+ mFetchDriver->SetAssociatedBrowsingContextID( -+ args.mAssociatedBrowsingContextID); -+ } -+ /* <-- Playwright */ -+ - if (mArgsType == FetchArgsType::WorkerFetch) { - auto& args = mArgs.as(); - mFetchDriver->SetWorkerScript(args.mWorkerScript); -diff --git a/dom/geolocation/Geolocation.cpp b/dom/geolocation/Geolocation.cpp -index 70ce9ce97c6d0ccba8b4129c55079cf9122e5b17..1c503c68c2c0949cfdaa18a76a263a81807952e1 100644 ---- a/dom/geolocation/Geolocation.cpp -+++ b/dom/geolocation/Geolocation.cpp -@@ -394,7 +394,10 @@ nsGeolocationRequest::Allow(JS::Handle aChoices) { - return NS_OK; - } - -- if (mBehavior != SystemGeolocationPermissionBehavior::NoPrompt) { -+ RefPtr gs = nsGeolocationService::GetGeolocationService( -+ mLocator->GetBrowsingContext()); -+ -+ if (mBehavior != SystemGeolocationPermissionBehavior::NoPrompt && !gs->IsOverride()) { - // Asynchronously present the system dialog or open system preferences - // (RequestGeolocationPermissionFromUser will know which to do), and wait - // for the permission to change or the request to be canceled. If the -@@ -426,8 +429,6 @@ nsGeolocationRequest::Allow(JS::Handle aChoices) { - return NS_OK; - } - -- RefPtr gs = nsGeolocationService::GetGeolocationService( -- mLocator->GetBrowsingContext()); - bool canUseCache = false; - CachedPositionAndAccuracy lastPosition = gs->GetCachedPosition(); - if (lastPosition.position) { -@@ -710,11 +711,16 @@ NS_INTERFACE_MAP_END - NS_IMPL_ADDREF(nsGeolocationService) - NS_IMPL_RELEASE(nsGeolocationService) - --nsresult nsGeolocationService::Init() { -+nsresult nsGeolocationService::Init(bool isOverride) { - if (!StaticPrefs::geo_enabled()) { - return NS_ERROR_FAILURE; - } - -+ if (isOverride) { -+ mIsOverride = true; -+ mHigherAccuracy = true; -+ } -+ - if (XRE_IsContentProcess()) { - return NS_OK; - } -@@ -793,6 +799,10 @@ nsresult nsGeolocationService::Init() { - return NS_OK; - } - -+bool nsGeolocationService::IsOverride() { -+ return mIsOverride; -+} -+ - nsGeolocationService::~nsGeolocationService() = default; - - NS_IMETHODIMP -@@ -936,6 +946,10 @@ bool nsGeolocationService::HighAccuracyRequested() { - } - - void nsGeolocationService::UpdateAccuracy(bool aForceHigh) { -+ if (mIsOverride) { -+ return; -+ } -+ - bool highRequired = aForceHigh || HighAccuracyRequested(); - - if (XRE_IsContentProcess()) { -diff --git a/dom/geolocation/Geolocation.h b/dom/geolocation/Geolocation.h -index 57814242d551774e81403b7fdc20c795deadb625..c48c1b19a8d5499784ffb7b50d5e88e40c7b2a05 100644 ---- a/dom/geolocation/Geolocation.h -+++ b/dom/geolocation/Geolocation.h -@@ -67,7 +67,7 @@ class nsGeolocationService final : public nsIGeolocationUpdate, - - nsGeolocationService() = default; - -- nsresult Init(); -+ nsresult Init(bool isOverride = false); - - // Management of the Geolocation objects - void AddLocator(mozilla::dom::Geolocation* aLocator); -@@ -92,6 +92,8 @@ class nsGeolocationService final : public nsIGeolocationUpdate, - void UpdateAccuracy(bool aForceHigh = false); - bool HighAccuracyRequested(); - -+ bool IsOverride(); -+ - private: - ~nsGeolocationService(); - -@@ -118,6 +120,8 @@ class nsGeolocationService final : public nsIGeolocationUpdate, - // Nothing() if not being started, or a boolean reflecting the requested - // accuracy. - mozilla::Maybe mStarting; -+ -+ bool mIsOverride = false; - }; - - namespace mozilla::dom { -diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp -index 5b0228d4a61dfe2b95e7a3ce016217007e8dee12..b753b0fceeec3278cb026d9137aafab5fb6ef968 100644 ---- a/dom/html/HTMLInputElement.cpp -+++ b/dom/html/HTMLInputElement.cpp -@@ -45,6 +45,7 @@ - #include "mozilla/dom/GetFilesHelper.h" - #include "mozilla/dom/HTMLDataListElement.h" - #include "mozilla/dom/HTMLOptionElement.h" -+#include "nsDocShell.h" - #include "mozilla/dom/InputType.h" - #include "mozilla/dom/MouseEvent.h" - #include "mozilla/dom/MutationEventBinding.h" -@@ -842,6 +843,13 @@ nsresult HTMLInputElement::InitFilePicker(FilePickerType aType) { - return NS_ERROR_FAILURE; - } - -+ nsCOMPtr win = doc->GetWindow(); -+ nsDocShell* docShell = win ? static_cast(win->GetDocShell()) : nullptr; -+ if (docShell && docShell->IsFileInputInterceptionEnabled()) { -+ docShell->FilePickerShown(this); -+ return NS_OK; -+ } -+ - if (IsPickerBlocked(doc)) { - return NS_OK; - } -diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl -index 64a2dad65911395ea7eb8ded3374ae6bdd31cf3c..e333c802f8a9232e58d963e05187c0a1b30948f5 100644 ---- a/dom/interfaces/base/nsIDOMWindowUtils.idl -+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl -@@ -390,6 +390,26 @@ cenum AsyncEnabledOption : 8 { - ASYNC_ENABLED = 1 - }; - -+ /** -+ * Playwright: a separate method to dispatch mouse event with a -+ * specific `jugglerEventId`. -+ */ -+ [can_run_script] -+ unsigned long jugglerSendMouseEvent(in AString aType, -+ in float aX, -+ in float aY, -+ in long aButton, -+ in long aClickCount, -+ in long aModifiers, -+ in boolean aIgnoreRootScrollFrame, -+ in float aPressure, -+ in unsigned short aInputSourceArg, -+ in boolean aIsDOMEventSynthesized, -+ in boolean aIsWidgetEventSynthesized, -+ in long aButtons, -+ in unsigned long aIdentifier, -+ in boolean aDisablePointerEvent); -+ - /** Synthesize a touch event. The event types supported are: - * touchstart, touchend, touchmove, and touchcancel - * -diff --git a/dom/ipc/BrowserChild.cpp b/dom/ipc/BrowserChild.cpp -index 780550d573644bcfe4a9bc03243aa4559a62d979..9ed69194ef329aad1e8a3e2c06041a443e4bc6ba 100644 ---- a/dom/ipc/BrowserChild.cpp -+++ b/dom/ipc/BrowserChild.cpp -@@ -1744,6 +1744,21 @@ void BrowserChild::HandleRealMouseButtonEvent(const WidgetMouseEvent& aEvent, - if (postLayerization) { - postLayerization->Register(); - } -+ -+ // Playwright: notify content that mouse event has been received and handled. -+ nsCOMPtr observerService = -+ mozilla::services::GetObserverService(); -+ if (observerService && aEvent.mJugglerEventId) { -+ if (aEvent.mMessage == eMouseUp) { -+ observerService->NotifyObservers(nullptr, "juggler-mouse-event-hit-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("mouseup %" PRIu32, aEvent.mJugglerEventId)).get()); -+ } else if (aEvent.mMessage == eMouseDown) { -+ observerService->NotifyObservers(nullptr, "juggler-mouse-event-hit-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("mousedown %" PRIu32, aEvent.mJugglerEventId)).get()); -+ } else if (aEvent.mMessage == eMouseMove) { -+ observerService->NotifyObservers(nullptr, "juggler-mouse-event-hit-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("mousemove %" PRIu32, aEvent.mJugglerEventId)).get()); -+ } else if (aEvent.mMessage == eContextMenu) { -+ observerService->NotifyObservers(nullptr, "juggler-mouse-event-hit-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("contextmenu %" PRIu32, aEvent.mJugglerEventId)).get()); -+ } -+ } - } - - mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealMouseButtonEvent( -diff --git a/dom/ipc/CoalescedMouseData.cpp b/dom/ipc/CoalescedMouseData.cpp -index 83aa0d08839f6fa5a150e5791b9b717e5aa9e751..fc1e1140ac7c6cda8cf116027c2fc2898dbe9d4b 100644 ---- a/dom/ipc/CoalescedMouseData.cpp -+++ b/dom/ipc/CoalescedMouseData.cpp -@@ -72,6 +72,9 @@ bool CoalescedMouseData::CanCoalesce(const WidgetMouseEvent& aEvent, - mCoalescedInputEvent->pointerId != aEvent.pointerId || - mCoalescedInputEvent->mButton != aEvent.mButton || - mCoalescedInputEvent->mButtons != aEvent.mButtons || mGuid != aGuid || -+ // `mJugglerEventId` is 0 for non-juggler events and a unique number for -+ // juggler-emitted events. -+ mCoalescedInputEvent->mJugglerEventId != aEvent.mJugglerEventId || - mInputBlockId != aInputBlockId) { - return false; - } -diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.cc b/dom/media/systemservices/video_engine/desktop_capture_impl.cc -index db777994b583efc2a3533e7d4534fff894c733bb..eb317c19b2422bd983d5e132c9ee4dac31687428 100644 ---- a/dom/media/systemservices/video_engine/desktop_capture_impl.cc -+++ b/dom/media/systemservices/video_engine/desktop_capture_impl.cc -@@ -53,9 +53,10 @@ namespace webrtc { - - DesktopCaptureImpl* DesktopCaptureImpl::Create(const int32_t aModuleId, - const char* aUniqueId, -- const CaptureDeviceType aType) { -+ const CaptureDeviceType aType, -+ bool aCaptureCursor) { - return new rtc::RefCountedObject(aModuleId, aUniqueId, -- aType); -+ aType, aCaptureCursor); - } - - static DesktopCaptureOptions CreateDesktopCaptureOptions() { -@@ -156,8 +157,10 @@ static std::unique_ptr CreateTabCapturer( - - static std::unique_ptr CreateDesktopCapturerAndThread( - CaptureDeviceType aDeviceType, DesktopCapturer::SourceId aSourceId, -- nsIThread** aOutThread) { -+ nsIThread** aOutThread, bool aCaptureCursor) { - DesktopCaptureOptions options = CreateDesktopCaptureOptions(); -+ if (aCaptureCursor) -+ options.set_prefer_cursor_embedded(aCaptureCursor); - auto ensureThread = [&]() { - if (*aOutThread) { - return *aOutThread; -@@ -254,7 +257,8 @@ static std::unique_ptr CreateDesktopCapturerAndThread( - } - - DesktopCaptureImpl::DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, -- const CaptureDeviceType aType) -+ const CaptureDeviceType aType, -+ bool aCaptureCursor) - : mModuleId(aId), - mTrackingId(mozilla::TrackingId(CaptureEngineToTrackingSourceStr([&] { - switch (aType) { -@@ -271,6 +275,7 @@ DesktopCaptureImpl::DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, - aId)), - mDeviceUniqueId(aUniqueId), - mDeviceType(aType), -+ capture_cursor_(aCaptureCursor), - mControlThread(mozilla::GetCurrentSerialEventTarget()), - mNextFrameMinimumTime(Timestamp::Zero()), - mCallbacks("DesktopCaptureImpl::mCallbacks") {} -@@ -295,6 +300,19 @@ void DesktopCaptureImpl::DeRegisterCaptureDataCallback( - } - } - -+void DesktopCaptureImpl::RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) { -+ rtc::CritScope lock(&mApiCs); -+ _rawFrameCallbacks.insert(rawFrameCallback); -+} -+ -+void DesktopCaptureImpl::DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) { -+ rtc::CritScope lock(&mApiCs); -+ auto it = _rawFrameCallbacks.find(rawFrameCallback); -+ if (it != _rawFrameCallbacks.end()) { -+ _rawFrameCallbacks.erase(it); -+ } -+} -+ - int32_t DesktopCaptureImpl::StopCaptureIfAllClientsClose() { - { - auto callbacks = mCallbacks.Lock(); -@@ -350,7 +368,7 @@ int32_t DesktopCaptureImpl::StartCapture( - return -1; - } - std::unique_ptr capturer = CreateDesktopCapturerAndThread( -- mDeviceType, sourceId, getter_AddRefs(mCaptureThread)); -+ mDeviceType, sourceId, getter_AddRefs(mCaptureThread), capture_cursor_); - - MOZ_ASSERT(!capturer == !mCaptureThread); - if (!capturer) { -@@ -458,6 +476,15 @@ void DesktopCaptureImpl::OnCaptureResult(DesktopCapturer::Result aResult, - frameInfo.height = aFrame->size().height(); - frameInfo.videoType = VideoType::kARGB; - -+ size_t videoFrameStride = -+ frameInfo.width * DesktopFrame::kBytesPerPixel; -+ { -+ rtc::CritScope cs(&mApiCs); -+ for (auto rawFrameCallback : _rawFrameCallbacks) { -+ rawFrameCallback->OnRawFrame(videoFrame, videoFrameStride, frameInfo); -+ } -+ } -+ - size_t videoFrameLength = - frameInfo.width * frameInfo.height * DesktopFrame::kBytesPerPixel; - -diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.h b/dom/media/systemservices/video_engine/desktop_capture_impl.h -index a76b7de569db1cb42728a5514fb80e5c46e0344e..3d61ad8d3aa4a7eaf96957dcd680e1e1ee8abdf4 100644 ---- a/dom/media/systemservices/video_engine/desktop_capture_impl.h -+++ b/dom/media/systemservices/video_engine/desktop_capture_impl.h -@@ -26,6 +26,7 @@ - #include "api/video/video_sink_interface.h" - #include "modules/desktop_capture/desktop_capturer.h" - #include "modules/video_capture/video_capture.h" -+#include "rtc_base/deprecated/recursive_critical_section.h" - #include "mozilla/DataMutex.h" - #include "mozilla/Maybe.h" - #include "mozilla/TimeStamp.h" -@@ -42,17 +43,44 @@ 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; -+ int32_t StartCaptureCounted(const VideoCaptureCapability& aCapability) { -+ ++capture_counter_; -+ return capture_counter_ == 1 ? StartCapture(aCapability) : 0; -+ } -+ -+ int32_t StopCaptureCounted() { -+ --capture_counter_; -+ return capture_counter_ == 0 ? StopCapture() : 0; -+ } -+ -+ private: -+ int32_t capture_counter_ = 0; -+}; -+ - // Reuses the video engine pipeline for screen sharing. - // 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 DesktopCaptureImpl* Create( - const int32_t aModuleId, const char* aUniqueId, -- const mozilla::camera::CaptureDeviceType aType); -+ const mozilla::camera::CaptureDeviceType aType, bool aCaptureCursor = true); - - [[nodiscard]] static std::shared_ptr - CreateDeviceInfo(const int32_t aId, -@@ -66,6 +94,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - void DeRegisterCaptureDataCallback( - rtc::VideoSinkInterface* aCallback) override; - int32_t StopCaptureIfAllClientsClose() override; -+ void RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) override; -+ void DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) override; - - int32_t SetCaptureRotation(VideoRotation aRotation) override; - bool SetApplyRotation(bool aEnable) override; -@@ -89,7 +119,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - - protected: - DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, -- const mozilla::camera::CaptureDeviceType aType); -+ const mozilla::camera::CaptureDeviceType aType, -+ bool aCaptureCusor); - virtual ~DesktopCaptureImpl(); - - private: -@@ -98,6 +129,9 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - void InitOnThread(std::unique_ptr aCapturer, int aFramerate); - void UpdateOnThread(int aFramerate); - void ShutdownOnThread(); -+ -+ rtc::RecursiveCriticalSection mApiCs; -+ std::set _rawFrameCallbacks; - // DesktopCapturer::Callback interface. - void OnCaptureResult(DesktopCapturer::Result aResult, - std::unique_ptr aFrame) override; -@@ -105,6 +139,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - // Notifies all mCallbacks of OnFrame(). mCaptureThread only. - void NotifyOnFrame(const VideoFrame& aFrame); - -+ bool capture_cursor_ = true; -+ - // Control thread on which the public API is called. - const nsCOMPtr mControlThread; - // Set in StartCapture. -diff --git a/dom/script/ScriptSettings.cpp b/dom/script/ScriptSettings.cpp -index d5964b27e9c99af76fe3f4076322592a9370c2d0..da217e2c1fbd9ca02e50ff74dde028189a216a6d 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 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 8b68f22ae64d19165bf4b3c58aea8f5c237ba351..c3733bfa4ed550c98ab5f72c406cd6d01a621aca 100644 ---- a/dom/security/nsCSPUtils.cpp -+++ b/dom/security/nsCSPUtils.cpp -@@ -24,6 +24,7 @@ - #include "nsSandboxFlags.h" - #include "nsServiceManagerUtils.h" - #include "nsWhitespaceTokenizer.h" -+#include "nsDocShell.h" - - #include "mozilla/Assertions.h" - #include "mozilla/Components.h" -@@ -136,6 +137,11 @@ void CSP_ApplyMetaCSPToDoc(mozilla::dom::Document& aDoc, - return; - } - -+ if (aDoc.GetDocShell() && -+ nsDocShell::Cast(aDoc.GetDocShell())->IsBypassCSPEnabled()) { -+ return; -+ } -+ - nsAutoString policyStr( - nsContentUtils::TrimWhitespace( - aPolicyStr)); -diff --git a/dom/webidl/GeometryUtils.webidl b/dom/webidl/GeometryUtils.webidl -index aee376e971ae01ac1e512c3920b115bfaf06afa8..1701311534bf77e6cd9bafc0e3a283610476aa8f 100644 ---- a/dom/webidl/GeometryUtils.webidl -+++ b/dom/webidl/GeometryUtils.webidl -@@ -17,6 +17,8 @@ dictionary GeometryUtilsOptions { - boolean createFramesForSuppressedWhitespace = true; - [ChromeOnly] - boolean flush = true; -+ [ChromeOnly] -+ boolean recurseWhenNoFrame = false; - }; - - dictionary BoxQuadOptions : GeometryUtilsOptions { -@@ -35,6 +37,9 @@ interface mixin GeometryUtils { - [Throws, Func="nsINode::HasBoxQuadsSupport", NeedsCallerType] - sequence getBoxQuads(optional BoxQuadOptions options = {}); - -+ [ChromeOnly, Throws, Func="nsINode::HasBoxQuadsSupport"] -+ undefined 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 83cef5b52b8f5c3168cd1d59266b4149425647fd..a80e89ec26a7e049c8ed84687ba2cd49597be05f 100644 ---- a/dom/workers/RuntimeService.cpp -+++ b/dom/workers/RuntimeService.cpp -@@ -1082,7 +1082,7 @@ void PrefLanguagesChanged(const char* /* aPrefName */, void* /* aClosure */) { - AssertIsOnMainThread(); - - nsTArray languages; -- Navigator::GetAcceptLanguages(languages); -+ Navigator::GetAcceptLanguages(nullptr, languages); - - RuntimeService* runtime = RuntimeService::GetService(); - if (runtime) { -@@ -1272,8 +1272,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; - } - -@@ -1901,6 +1900,13 @@ void RuntimeService::PropagateStorageAccessPermissionGranted( - } - } - -+void RuntimeService::ResetDefaultLocaleInAllWorkers() { -+ AssertIsOnMainThread(); -+ BroadcastAllWorkers([](auto& worker) { -+ worker.ResetDefaultLocale(); -+ }); -+} -+ - template - void RuntimeService::BroadcastAllWorkers(const Func& aFunc) { - AssertIsOnMainThread(); -@@ -2451,6 +2457,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 6d75c6708bcb999dc1dc3b0172afa14136110bc6..809d0ef80ffe793beff5d3c11bf6bf7912385e99 100644 ---- a/dom/workers/RuntimeService.h -+++ b/dom/workers/RuntimeService.h -@@ -115,6 +115,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 af8d36c0d72683712a3fee22661f8c3279e103db..6b3a967c9acde2c81ab38148d4b1ac120a4717a2 100644 ---- a/dom/workers/WorkerCommon.h -+++ b/dom/workers/WorkerCommon.h -@@ -50,6 +50,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 06083bb8f9546be06fa0b5c78d4e005a1617e51b..1753896265c1701ad50425c565f8d44392d0afb9 100644 ---- a/dom/workers/WorkerPrivate.cpp -+++ b/dom/workers/WorkerPrivate.cpp -@@ -738,6 +738,18 @@ class UpdateContextOptionsRunnable final : public WorkerControlRunnable { - } - }; - -+class ResetDefaultLocaleRunnable final : public WorkerControlRunnable { -+ public: -+ explicit ResetDefaultLocaleRunnable(WorkerPrivate* aWorkerPrivate) -+ : WorkerControlRunnable("ResetDefaultLocaleRunnable") {} -+ -+ virtual bool WorkerRun(JSContext* aCx, -+ WorkerPrivate* aWorkerPrivate) override { -+ aWorkerPrivate->ResetDefaultLocaleInternal(aCx); -+ return true; -+ } -+}; -+ - class UpdateLanguagesRunnable final : public WorkerThreadRunnable { - nsTArray mLanguages; - -@@ -2334,6 +2346,16 @@ void WorkerPrivate::UpdateContextOptions( - } - } - -+void WorkerPrivate::ResetDefaultLocale() { -+ AssertIsOnParentThread(); -+ -+ RefPtr runnable = -+ new ResetDefaultLocaleRunnable(this); -+ if (!runnable->Dispatch(this)) { -+ NS_WARNING("Failed to reset default locale in worker!"); -+ } -+} -+ - void WorkerPrivate::UpdateLanguages(const nsTArray& aLanguages) { - AssertIsOnParentThread(); - -@@ -5996,6 +6018,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& aLanguages) { - WorkerGlobalScope* globalScope = GlobalScope(); -diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h -index 15c819c84fa934e25517ac8f55fd39ef8ba46986..fe01e09abcf2315abe41a3d19418c4e0f8c7df2b 100644 ---- a/dom/workers/WorkerPrivate.h -+++ b/dom/workers/WorkerPrivate.h -@@ -457,6 +457,8 @@ class WorkerPrivate final - void UpdateContextOptionsInternal(JSContext* aCx, - const JS::ContextOptions& aContextOptions); - -+ void ResetDefaultLocaleInternal(JSContext* aCx); -+ - void UpdateLanguagesInternal(const nsTArray& aLanguages); - - void UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key, -@@ -1103,6 +1105,8 @@ class WorkerPrivate final - - void UpdateContextOptions(const JS::ContextOptions& aContextOptions); - -+ void ResetDefaultLocale(); -+ - void UpdateLanguages(const nsTArray& aLanguages); - - void UpdateJSWorkerMemoryParameter(JSGCParamKey key, Maybe value); -diff --git a/intl/components/src/TimeZone.cpp b/intl/components/src/TimeZone.cpp -index 7a069ef0c59895cf1f8dc35d612f1494c9c9f1ef..5b09dfdcc5323def65c35b0696141b44eef9dcda 100644 ---- a/intl/components/src/TimeZone.cpp -+++ b/intl/components/src/TimeZone.cpp -@@ -16,6 +16,7 @@ - - namespace mozilla::intl { - -+ - /* static */ - Result, ICUError> TimeZone::TryCreate( - Maybe> aTimeZoneOverride) { -@@ -318,6 +319,13 @@ static ICUResult SetDefaultTimeZone(TimeZoneIdentifierVector& timeZone) { - } - #endif - -+bool TimeZone::IsValidTimeZoneId(const char* timeZoneId) { -+ // Validate timezone id. -+ mozilla::UniquePtr timeZone(icu::TimeZone::createTimeZone( -+ icu::UnicodeString(timeZoneId, -1, US_INV))); -+ return timeZone && *timeZone != icu::TimeZone::getUnknown(); -+} -+ - Result TimeZone::SetDefaultTimeZone( - Span aTimeZone) { - #if MOZ_INTL_USE_ICU_CPP_TIMEZONE -diff --git a/intl/components/src/TimeZone.h b/intl/components/src/TimeZone.h -index 89770839ae108b5f3462a7f20684fdb72c4ab2fb..a7e40d6b7c33c234b41e586eac573ba4ce3a7d18 100644 ---- a/intl/components/src/TimeZone.h -+++ b/intl/components/src/TimeZone.h -@@ -191,6 +191,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 523e84c8c93f4221701f90f2e8ee146ec8e1adbd..98d5b1176e5378431b859a2dbd4d4e778d236e78 100644 ---- a/js/public/Date.h -+++ b/js/public/Date.h -@@ -55,6 +55,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 2d177b5aade6d158e9ae62d317d5155b72cdcf84..28af5d41eb06d4b33cd5f86484dc29c923308835 100644 ---- a/js/src/debugger/Object.cpp -+++ b/js/src/debugger/Object.cpp -@@ -2516,7 +2516,11 @@ Maybe 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 cc366b4cc411ed8de972811237563edb376355e3..adf727cf80fadebce3be9301752dc1d0b9ee35b9 100644 ---- a/js/src/vm/DateTime.cpp -+++ b/js/src/vm/DateTime.cpp -@@ -188,6 +188,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); - -@@ -556,10 +561,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) { -@@ -773,6 +792,15 @@ static bool ReadTimeZoneLink(std::string_view tz, - - void js::DateTimeInfo::internalResyncICUDefaultTimeZone() { - #if JS_HAS_INTL_API -+ if (!timeZoneOverride_.empty()) { -+ mozilla::Span 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; -+ } -+ - // In the future we should not be setting a default ICU time zone at all, - // instead all accesses should go through the appropriate DateTimeInfo - // instance depending on the resist fingerprinting status. For now we return -@@ -784,7 +812,6 @@ void js::DateTimeInfo::internalResyncICUDefaultTimeZone() { - - if (const char* tzenv = std::getenv("TZ")) { - std::string_view tz(tzenv); -- - mozilla::Span tzid; - - # if defined(XP_WIN) -diff --git a/js/src/vm/DateTime.h b/js/src/vm/DateTime.h -index 7be5b49afdce8e761af05dfbd48f3cb22e9ce318..3899c7988959f11bbadd0c005462acb979823fd1 100644 ---- a/js/src/vm/DateTime.h -+++ b/js/src/vm/DateTime.h -@@ -75,6 +75,8 @@ using TimeZoneIdentifierVector = - SystemAllocPolicy>; - #endif - -+extern void SetTimeZoneOverrideInternal(std::string timeZone); -+ - /** - * Stores date/time information, particularly concerning the current local - * time zone, and implements a small cache for daylight saving time offset -@@ -258,6 +260,7 @@ class DateTimeInfo { - private: - // The method below should only be called via js::ResetTimeZoneInternal(). - friend void js::ResetTimeZoneInternal(ResetTimeZoneMode); -+ friend void js::SetTimeZoneOverrideInternal(std::string); - - static void resetTimeZone(ResetTimeZoneMode mode) { - { -@@ -362,6 +365,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 -@@ -377,6 +382,8 @@ class DateTimeInfo { - - void internalResetTimeZone(ResetTimeZoneMode mode); - -+ void internalSetTimeZoneOverride(std::string timeZone); -+ - void updateTimeZone(); - - void internalResyncICUDefaultTimeZone(); -diff --git a/layout/base/GeometryUtils.cpp b/layout/base/GeometryUtils.cpp -index 67673c5c306e7237613b0560c7b3f888bd6ad1b8..fe4a278dad4b1747b41b5a824978636a70a9dea8 100644 ---- a/layout/base/GeometryUtils.cpp -+++ b/layout/base/GeometryUtils.cpp -@@ -23,6 +23,7 @@ - #include "nsContentUtils.h" - #include "nsIFrame.h" - #include "nsLayoutUtils.h" -+#include "ChildIterator.h" - - using namespace mozilla; - using namespace mozilla::dom; -@@ -265,10 +266,27 @@ static bool CheckFramesInSameTopLevelBrowsingContext(nsIFrame* aFrame1, - return false; - } - -+static nsIFrame* GetFrameForNodeRecursive(nsINode* aNode, -+ const GeometryUtilsOptions& aOptions, -+ bool aRecurseWhenNoFrame) { -+ nsIFrame* frame = GetFrameForNode(aNode, aOptions); -+ if (!frame && aRecurseWhenNoFrame && aNode->IsContent()) { -+ dom::FlattenedChildIterator iter(aNode->AsContent()); -+ for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { -+ frame = GetFrameForNodeRecursive(child, aOptions, aRecurseWhenNoFrame); -+ if (frame) { -+ break; -+ } -+ } -+ } -+ return frame; -+} -+ - void GetBoxQuads(nsINode* aNode, const dom::BoxQuadOptions& aOptions, - nsTArray>& aResult, CallerType aCallerType, - ErrorResult& aRv) { -- nsIFrame* frame = GetFrameForNode(aNode, aOptions); -+ nsIFrame* frame = -+ GetFrameForNodeRecursive(aNode, aOptions, aOptions.mRecurseWhenNoFrame); - if (!frame) { - // No boxes to return - return; -@@ -281,7 +299,8 @@ void GetBoxQuads(nsINode* aNode, const dom::BoxQuadOptions& aOptions, - // EnsureFrameForTextNode call. We need to get the first frame again - // when that happens and re-check it. - if (!weakFrame.IsAlive()) { -- frame = GetFrameForNode(aNode, aOptions); -+ frame = -+ GetFrameForNodeRecursive(aNode, aOptions, aOptions.mRecurseWhenNoFrame); - if (!frame) { - // No boxes to return - return; -diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp -index 26119628ab4839858733ce39c6c9ef2970092b49..a9c4dbc4936755fd25b8528511e9a4c62695de89 100644 ---- a/layout/base/PresShell.cpp -+++ b/layout/base/PresShell.cpp -@@ -12150,7 +12150,9 @@ bool PresShell::ComputeActiveness() const { - if (!browserChild->IsVisible()) { - MOZ_LOG(gLog, LogLevel::Debug, - (" > BrowserChild %p is not visible", browserChild)); -- return false; -+ bool isActive; -+ root->GetDocShell()->GetForceActiveState(&isActive); -+ return isActive; - } - - // If the browser is visible but just due to be preserving layers -diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp -index ee4e4b7e04f0f949b0afc7e8097711fcefe8b3c3..3af1d380d514b70392d1daaa4bc623afd7a570e6 100644 ---- a/layout/base/nsLayoutUtils.cpp -+++ b/layout/base/nsLayoutUtils.cpp -@@ -707,6 +707,10 @@ bool nsLayoutUtils::AllowZoomingForDocument( - !aDocument->GetPresShell()->AsyncPanZoomEnabled()) { - return false; - } -+ -+ /* Playwright: disable zooming as we don't support meta viewport tag */ -+ if (1 == 1) return false; -+ - // True if we allow zooming for all documents on this platform, or if we are - // in RDM. - BrowsingContext* bc = aDocument->GetBrowsingContext(); -@@ -9772,6 +9776,9 @@ void nsLayoutUtils::ComputeSystemFont(nsFont* aSystemFont, - - /* static */ - bool nsLayoutUtils::ShouldHandleMetaViewport(const Document* aDocument) { -+ /* Playwright: disable meta viewport handling since we don't require one */ -+ if (1 == 1) return false; -+ - BrowsingContext* bc = aDocument->GetBrowsingContext(); - return StaticPrefs::dom_meta_viewport_enabled() || (bc && bc->InRDMPane()); - } -diff --git a/layout/style/GeckoBindings.h b/layout/style/GeckoBindings.h -index 9527443c79077e0a728d78c3184ab7319f1c9efd..4e193ed114b4f70fb72bea928709fc7723f35b88 100644 ---- a/layout/style/GeckoBindings.h -+++ b/layout/style/GeckoBindings.h -@@ -591,6 +592,7 @@ float Gecko_MediaFeatures_GetResolution(const mozilla::dom::Document*); - bool Gecko_MediaFeatures_PrefersReducedMotion(const mozilla::dom::Document*); - bool Gecko_MediaFeatures_PrefersReducedTransparency( - 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 21bcc8e890a0d3f3e86b5ea6eed79d017dd2fb76..eefc7d5c934f03b4a9213dafcbb65dd32b695622 100644 ---- a/layout/style/nsMediaFeatures.cpp -+++ b/layout/style/nsMediaFeatures.cpp -@@ -268,11 +268,7 @@ bool Gecko_MediaFeatures_MatchesPlatform(StylePlatform aPlatform) { - } - - bool Gecko_MediaFeatures_PrefersReducedMotion(const Document* aDocument) { -- if (aDocument->ShouldResistFingerprinting( -- RFPTarget::CSSPrefersReducedMotion)) { -- return false; -- } -- return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1; -+ return aDocument->PrefersReducedMotion(); - } - - bool Gecko_MediaFeatures_PrefersReducedTransparency(const Document* aDocument) { -@@ -297,6 +293,20 @@ StylePrefersColorScheme Gecko_MediaFeatures_PrefersColorScheme( - // as a signal. - StylePrefersContrast Gecko_MediaFeatures_PrefersContrast( - const Document* aDocument) { -+ if (auto* bc = aDocument->GetBrowsingContext()) { -+ switch (bc->Top()->PrefersContrastOverride()) { -+ case dom::PrefersContrastOverride::No_preference: -+ return StylePrefersContrast::NoPreference; -+ case dom::PrefersContrastOverride::Less: -+ return StylePrefersContrast::Less; -+ case dom::PrefersContrastOverride::More: -+ return StylePrefersContrast::More; -+ case dom::PrefersContrastOverride::Custom: -+ return StylePrefersContrast::Custom; -+ } -+ } -+ -+ - if (aDocument->ShouldResistFingerprinting(RFPTarget::CSSPrefersContrast)) { - return StylePrefersContrast::NoPreference; - } -diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp -index e5cf36273d5790de2c80acb42a6ee181bdb66f08..0523a37fc19b470e3817ae61c912a3dc54fc57a6 100644 ---- a/netwerk/base/LoadInfo.cpp -+++ b/netwerk/base/LoadInfo.cpp -@@ -801,7 +801,8 @@ LoadInfo::LoadInfo(const LoadInfo& rhs) - rhs.mHasInjectedCookieForCookieBannerHandling), - mSchemelessInput(rhs.mSchemelessInput), - mHttpsUpgradeTelemetry(rhs.mHttpsUpgradeTelemetry), -- mIsNewWindowTarget(rhs.mIsNewWindowTarget) { -+ mIsNewWindowTarget(rhs.mIsNewWindowTarget), -+ mJugglerLoadIdentifier(rhs.mJugglerLoadIdentifier) { - } - - LoadInfo::LoadInfo( -@@ -2778,4 +2779,16 @@ void LoadInfo::UpdateParentAddressSpaceInfo() { - } - } - -+NS_IMETHODIMP -+LoadInfo::GetJugglerLoadIdentifier(uint64_t* aResult) { -+ *aResult = mJugglerLoadIdentifier; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+LoadInfo::SetJugglerLoadIdentifier(uint64_t aID) { -+ mJugglerLoadIdentifier = aID; -+ return NS_OK; -+} -+ - } // namespace mozilla::net -diff --git a/netwerk/base/LoadInfo.h b/netwerk/base/LoadInfo.h -index 6547d451f3a764c8860dd0c19b5b490caecbf0af..feccce92e3769b8e9a3a4926cca9b85fccda86a5 100644 ---- a/netwerk/base/LoadInfo.h -+++ b/netwerk/base/LoadInfo.h -@@ -455,6 +455,8 @@ class LoadInfo final : public nsILoadInfo { - - bool mIsNewWindowTarget = false; - bool mSkipHTTPSUpgrade = false; -+ -+ uint64_t mJugglerLoadIdentifier = 0; - }; - // This is exposed solely for testing purposes and should not be used outside of - // LoadInfo -diff --git a/netwerk/base/TRRLoadInfo.cpp b/netwerk/base/TRRLoadInfo.cpp -index 551d89315243f4b515aa29d3a67eb23050ea9f0a..ac3a1ca6d846826c5d704d1b4abdaee55b834b0d 100644 ---- a/netwerk/base/TRRLoadInfo.cpp -+++ b/netwerk/base/TRRLoadInfo.cpp -@@ -1010,5 +1010,15 @@ TRRLoadInfo::GetFetchDestination(nsACString& aDestination) { - return NS_ERROR_NOT_IMPLEMENTED; - } - -+NS_IMETHODIMP -+TRRLoadInfo::GetJugglerLoadIdentifier(uint64_t* aResult) { -+ return NS_ERROR_NOT_IMPLEMENTED; -+} -+ -+NS_IMETHODIMP -+TRRLoadInfo::SetJugglerLoadIdentifier(uint64_t aResult) { -+ return NS_ERROR_NOT_IMPLEMENTED; -+} -+ - } // namespace net - } // namespace mozilla -diff --git a/netwerk/base/nsILoadInfo.idl b/netwerk/base/nsILoadInfo.idl -index f1b54736d9ee006292bf4c9cd0b3490d5ec8da66..257fda17a10f702cee39fb42ad69e0cd86ca95d1 100644 ---- a/netwerk/base/nsILoadInfo.idl -+++ b/netwerk/base/nsILoadInfo.idl -@@ -1686,4 +1686,6 @@ interface nsILoadInfo : nsISupports - return static_cast(userNavigationInvolvement); - } - %} -+ -+ [infallible] attribute unsigned long long jugglerLoadIdentifier; - }; -diff --git a/netwerk/base/nsINetworkInterceptController.idl b/netwerk/base/nsINetworkInterceptController.idl -index 7f91d2df6f8bb4020c75c132dc8f6bf26625fa1e..aaa5541a17039d6b13ad83ab176fdaaf79edb2a0 100644 ---- a/netwerk/base/nsINetworkInterceptController.idl -+++ b/netwerk/base/nsINetworkInterceptController.idl -@@ -60,6 +60,16 @@ interface nsIInterceptedChannel : nsISupports - */ - void resetInterception(in boolean bypass); - -+ // ----- Playwright begin ----- -+ -+ // Same as resetInterception, but updates the URI. -+ void resetInterceptionWithURI(in nsIURI aURI); -+ -+ // After resetInterception is called, this request will be intercepted again. -+ void interceptAfterServiceWorkerResets(); -+ -+ // ----- Playwright end ------- -+ - /** - * Set the status and reason for the forthcoming synthesized response. - * Multiple calls overwrite existing values. -diff --git a/netwerk/ipc/DocumentLoadListener.cpp b/netwerk/ipc/DocumentLoadListener.cpp -index 1471432c1f1a47be5073ed01b746f1f13d3a0b47..585f81762e2bf51681d11c06c9459063121c34e9 100644 ---- a/netwerk/ipc/DocumentLoadListener.cpp -+++ b/netwerk/ipc/DocumentLoadListener.cpp -@@ -185,6 +185,7 @@ static auto CreateDocumentLoadInfo(CanonicalBrowsingContext* aBrowsingContext, - loadInfo->SetTextDirectiveUserActivation( - aLoadState->GetTextDirectiveUserActivation()); - loadInfo->SetIsMetaRefresh(aLoadState->IsMetaRefresh()); -+ loadInfo->SetJugglerLoadIdentifier(aLoadState->GetLoadIdentifier()); - - return loadInfo.forget(); - } -diff --git a/netwerk/protocol/http/InterceptedHttpChannel.cpp b/netwerk/protocol/http/InterceptedHttpChannel.cpp -index fbf4bdf1e24d1102df113984be6c8dc3a7d0d810..cf1978009d74221ae804b998e223904fa943a91f 100644 ---- a/netwerk/protocol/http/InterceptedHttpChannel.cpp -+++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp -@@ -728,10 +728,33 @@ NS_IMPL_ISUPPORTS(ResetInterceptionHeaderVisitor, nsIHttpHeaderVisitor) - - } // anonymous namespace - -+NS_IMETHODIMP -+InterceptedHttpChannel::InterceptAfterServiceWorkerResets() { -+ mInterceptAfterServiceWorkerResets = true; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+InterceptedHttpChannel::ResetInterceptionWithURI(nsIURI* aURI) { -+ if (aURI) { -+ mURI = aURI; -+ } -+ return ResetInterception(true); -+} -+ - NS_IMETHODIMP - InterceptedHttpChannel::ResetInterception(bool aBypass) { - INTERCEPTED_LOG(("InterceptedHttpChannel::ResetInterception [%p] bypass: %s", - this, aBypass ? "true" : "false")); -+ if (mInterceptAfterServiceWorkerResets) { -+ mInterceptAfterServiceWorkerResets = false; -+ nsCOMPtr controller; -+ GetCallback(controller); -+ if (!controller) -+ return NS_ERROR_DOM_INVALID_STATE_ERR; -+ return controller->ChannelIntercepted(this); -+ } -+ - if (mCanceled) { - return mStatus; - } -@@ -1146,11 +1169,18 @@ InterceptedHttpChannel::OnStartRequest(nsIRequest* aRequest) { - GetCallback(mProgressSink); - } - -+ // Playwright: main requests in firefox do not have loading principal. -+ // As they are intercepted by Playwright, they don't have -+ // serviceWorkerTainting as well. -+ // Thus these asserts are wrong for Playwright world. -+ // Note: these checks were added in https://github.com/mozilla-firefox/firefox/commit/bb16ca6496682c3b0ddd452d0dd4c1dd46ff71f8 -+ /* - MOZ_ASSERT_IF(!mLoadInfo->GetServiceWorkerTaintingSynthesized(), - mLoadInfo->GetLoadingPrincipal()); - // No need to do ORB checks if these conditions hold. - MOZ_DIAGNOSTIC_ASSERT(mLoadInfo->GetServiceWorkerTaintingSynthesized() || - mLoadInfo->GetLoadingPrincipal()->IsSystemPrincipal()); -+ */ - - if (mPump && mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS) { - mPump->PeekStream(CallTypeSniffers, static_cast(this)); -diff --git a/netwerk/protocol/http/InterceptedHttpChannel.h b/netwerk/protocol/http/InterceptedHttpChannel.h -index 704404c9f094640ad63b685d64bd5a396e733e4b..92bdc21b4d6a015cc2f2bb22781ec6750c7789ec 100644 ---- a/netwerk/protocol/http/InterceptedHttpChannel.h -+++ b/netwerk/protocol/http/InterceptedHttpChannel.h -@@ -90,6 +90,11 @@ class InterceptedHttpChannel final - Atomic mCallingStatusAndProgress; - bool mInterceptionReset{false}; - -+ // ----- Playwright begin ----- -+ // After resetInterception is called, this request will call into interceptors again. -+ bool mInterceptAfterServiceWorkerResets{false}; -+ // ----- Playwright end ------- -+ - /** - * InterceptionTimeStamps is used to record the time stamps of the - * interception. -diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp -index 1051d1e91c1ebf036f2e5db82a37636dd7cda4c3..3ef53c09442e24fb50308740950aa6d354703b7d 100644 ---- a/netwerk/protocol/http/nsHttpChannel.cpp -+++ b/netwerk/protocol/http/nsHttpChannel.cpp -@@ -685,11 +685,9 @@ nsresult nsHttpChannel::OnBeforeConnect() { - // SecurityInfo.sys.mjs - mLoadInfo->SetHstsStatus(isSecureURI); - -- RefPtr bc; -- mLoadInfo->GetBrowsingContext(getter_AddRefs(bc)); - // If bypassing the cache and we're forced offline - // we can just return the error here. -- if (bc && bc->Top()->GetForceOffline() && -+ if (IsForcedOffline() && - BYPASS_LOCAL_CACHE(mLoadFlags, LoadPreferCacheLoadOverBypass())) { - return NS_ERROR_OFFLINE; - } -@@ -802,9 +800,7 @@ nsresult nsHttpChannel::MaybeUseHTTPSRRForUpgrade(bool aShouldUpgrade, - return aStatus; - } - -- RefPtr bc; -- mLoadInfo->GetBrowsingContext(getter_AddRefs(bc)); -- bool forceOffline = bc && bc->Top()->GetForceOffline(); -+ bool forceOffline = IsForcedOffline(); - - if (mURI->SchemeIs("https") || aShouldUpgrade || !LoadUseHTTPSSVC() || - forceOffline) { -@@ -1263,15 +1259,14 @@ nsresult nsHttpChannel::ContinueConnect() { - "CORS preflight must have been finished by the time we " - "do the rest of ContinueConnect"); - -- RefPtr bc; -- mLoadInfo->GetBrowsingContext(getter_AddRefs(bc)); -+ bool isForcedOffline = IsForcedOffline(); - - // we may or may not have a cache entry at this point - if (mCacheEntry) { - // read straight from the cache if possible... - if (CachedContentIsValid()) { - // If we're forced offline, and set to bypass the cache, return offline. -- if (bc && bc->Top()->GetForceOffline() && -+ if (isForcedOffline && - BYPASS_LOCAL_CACHE(mLoadFlags, LoadPreferCacheLoadOverBypass())) { - return NS_ERROR_OFFLINE; - } -@@ -1313,7 +1308,7 @@ nsresult nsHttpChannel::ContinueConnect() { - } - - // We're about to hit the network. Don't if we're forced offline. -- if (bc && bc->Top()->GetForceOffline()) { -+ if (isForcedOffline) { - return NS_ERROR_OFFLINE; - } - -@@ -1418,12 +1413,9 @@ void nsHttpChannel::SpeculativeConnect() { - // don't speculate if we are offline, when doing http upgrade (i.e. - // websockets bootstrap), or if we can't do keep-alive (because then we - // couldn't reuse the speculative connection anyhow). -- RefPtr bc; -- mLoadInfo->GetBrowsingContext(getter_AddRefs(bc)); -- - if (gIOService->IsOffline() || mUpgradeProtocolCallback || - !(mCaps & NS_HTTP_ALLOW_KEEPALIVE) || -- (bc && bc->Top()->GetForceOffline())) { -+ IsForcedOffline()) { - return; - } - -@@ -4240,9 +4232,6 @@ nsresult nsHttpChannel::OpenCacheEntryInternal(bool isHttps) { - uint32_t cacheEntryOpenFlags; - bool offline = gIOService->IsOffline(); - -- RefPtr bc; -- mLoadInfo->GetBrowsingContext(getter_AddRefs(bc)); -- - bool maybeRCWN = false; - - nsAutoCString cacheControlRequestHeader; -@@ -4253,7 +4242,7 @@ nsresult nsHttpChannel::OpenCacheEntryInternal(bool isHttps) { - return NS_OK; - } - -- bool forceOffline = bc && bc->Top()->GetForceOffline(); -+ bool forceOffline = IsForcedOffline(); - if (offline || (mLoadFlags & INHIBIT_CACHING) || forceOffline) { - if (BYPASS_LOCAL_CACHE(mLoadFlags, LoadPreferCacheLoadOverBypass()) && - !offline && !forceOffline) { -@@ -7357,6 +7346,20 @@ void nsHttpChannel::MaybeStartDNSPrefetch() { - } - } - -+bool nsHttpChannel::IsForcedOffline() { -+ RefPtr bc; -+ mLoadInfo->GetBrowsingContext(getter_AddRefs(bc)); -+ if (bc && bc->Top()->GetForceOffline()) -+ return true; -+ -+ RefPtr wbc; -+ mLoadInfo->GetWorkerAssociatedBrowsingContext(getter_AddRefs(wbc)); -+ if (wbc && wbc->Top()->GetForceOffline()) -+ return true; -+ -+ return false; -+} -+ - NS_IMETHODIMP - nsHttpChannel::GetEncodedBodySize(uint64_t* aEncodedBodySize) { - if (mCacheEntry && !LoadCacheEntryIsWriteOnly()) { -diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h -index 9d28bae2d270690517c11383abe4c4bcc0edda96..9087d345b1b63bdce0912abb0c880c50900a797b 100644 ---- a/netwerk/protocol/http/nsHttpChannel.h -+++ b/netwerk/protocol/http/nsHttpChannel.h -@@ -305,6 +305,10 @@ class nsHttpChannel final : public HttpBaseChannel, - void MaybeResolveProxyAndBeginConnect(); - void MaybeStartDNSPrefetch(); - -+ // ---- Playwright begin -+ bool IsForcedOffline(); -+ // ---- Playwright end -+ - // Based on the proxy configuration determine the strategy for resolving the - // end server host name. - ProxyDNSStrategy GetProxyDNSStrategy(); -diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp -index ce2a868b9a915b98938518b6c935870f8169e0f7..e6d0a75bb3f5e8dea3f3e7f3448b553979860bd3 100644 ---- a/parser/html/nsHtml5TreeOpExecutor.cpp -+++ b/parser/html/nsHtml5TreeOpExecutor.cpp -@@ -1361,6 +1361,10 @@ void nsHtml5TreeOpExecutor::UpdateReferrerInfoFromMeta( - void nsHtml5TreeOpExecutor::AddSpeculationCSP(const nsAString& aCSP) { - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - -+ if (mDocShell && static_cast(mDocShell.get())->IsBypassCSPEnabled()) { -+ return; -+ } -+ - nsresult rv = NS_OK; - nsCOMPtr preloadCsp = mDocument->GetPreloadCsp(); - if (!preloadCsp) { -diff --git a/security/manager/ssl/nsCertOverrideService.cpp b/security/manager/ssl/nsCertOverrideService.cpp -index 0ecf2c0df3aad52e004a69b4c7a22fea7532b4d8..f5982c2cf1d6ea0522ac7f7e1fb5b4ab8fa07cb4 100644 ---- a/security/manager/ssl/nsCertOverrideService.cpp -+++ b/security/manager/ssl/nsCertOverrideService.cpp -@@ -627,6 +627,8 @@ void nsCertOverrideService::CountPermanentOverrideTelemetry( - } - - static bool IsDebugger() { -+ // In playwright world, this is always enabled. -+ if (1 == 1) return true; - #ifdef ENABLE_WEBDRIVER - nsCOMPtr marionette = do_GetService(NS_MARIONETTE_CONTRACTID); - if (marionette) { -diff --git a/services/settings/Utils.sys.mjs b/services/settings/Utils.sys.mjs -index cbdf07bcdae11de6f59e6c6c279833aca430dc70..6840c78350ccb52e99f23446b010abc2a1d92a55 100644 ---- a/services/settings/Utils.sys.mjs -+++ b/services/settings/Utils.sys.mjs -@@ -97,7 +97,7 @@ const _cdnURLs = {}; - - export var Utils = { - get SERVER_URL() { -- return lazy.allowServerURLOverride -+ return true || lazy.allowServerURLOverride - ? lazy.gServerURL - : AppConstants.REMOTE_SETTINGS_SERVER_URL; - }, -@@ -110,6 +110,9 @@ export var Utils = { - log, - - get shouldSkipRemoteActivityDueToTests() { -+ // Playwright does not set Cu.isInAutomation, hence we just return true -+ // here in order to disable the remote activity. -+ return true; - return ( - (lazy.isRunningTests || Cu.isInAutomation) && - this.SERVER_URL == "data:,#remote-settings-dummy/v1" -diff --git a/toolkit/components/browser/nsIWebBrowserChrome.idl b/toolkit/components/browser/nsIWebBrowserChrome.idl -index 75555352b8a15a50e4a21e34fc8ede4e9246c7cc..72855a404effa42b6c55cd0c2fcb8bdd6c2b3f9f 100644 ---- a/toolkit/components/browser/nsIWebBrowserChrome.idl -+++ b/toolkit/components/browser/nsIWebBrowserChrome.idl -@@ -74,6 +74,9 @@ interface nsIWebBrowserChrome : nsISupports - // Whether this window should use out-of-process cross-origin subframes. - const unsigned long CHROME_FISSION_WINDOW = 1 << 21; - -+ // 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 = 1 << 24; -diff --git a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs -index 3d8837cdb38fb5b25abfb9e3e369ad6fe688706e..867ce2efaa10eaea87ffeeb2669cc5a7be0045b3 100644 ---- a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs -+++ b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs -@@ -106,7 +106,9 @@ EnterprisePoliciesManager.prototype = { - Services.prefs.clearUserPref(PREF_POLICIES_APPLIED); - } - -- let provider = this._chooseProvider(); -+ // --- Playwright begin --- -+ let provider = new PlaywrightPoliciesProvider(); -+ // --- Playwright end --- - - if (provider.failed) { - this.status = Ci.nsIEnterprisePolicies.FAILED; -@@ -606,6 +608,19 @@ class JSONPoliciesProvider { - } - } - -+class PlaywrightPoliciesProvider extends JSONPoliciesProvider { -+ _getConfigurationFile() { -+ let prefPath = Services.prefs.getStringPref(PREF_ALTERNATE_PATH, ""); -+ if (!prefPath) -+ return null; -+ -+ dump(`Playwright: loading enterprise policies from ${prefPath}\n`); -+ let configFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); -+ configFile.initWithPath(prefPath); -+ return configFile; -+ } -+} -+ - class WindowsGPOPoliciesProvider { - constructor() { - this._policies = null; -diff --git a/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp b/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp -index 52fa968554a88d1624bf9403b07781a8b42c93b6..2bd5162859dbc482361e2f6aaf5b7a732e9a5929 100644 ---- a/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp -+++ b/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp -@@ -588,7 +588,7 @@ void PopulateLanguages() { - // sufficient to only collect this information as the other properties are - // just reformats of Navigator::GetAcceptLanguages. - nsTArray languages; -- dom::Navigator::GetAcceptLanguages(languages); -+ dom::Navigator::GetAcceptLanguages(nullptr, languages); - nsCString output = "["_ns; - - for (const auto& language : languages) { -diff --git a/toolkit/components/startup/nsAppStartup.cpp b/toolkit/components/startup/nsAppStartup.cpp -index d8f0c072c8a52c2837d87fe749ccac6e3e59e48a..6837927e6a49a8ff4c9f709502bf8d8983bd735c 100644 ---- a/toolkit/components/startup/nsAppStartup.cpp -+++ b/toolkit/components/startup/nsAppStartup.cpp -@@ -361,7 +361,7 @@ nsAppStartup::Quit(uint32_t aMode, int aExitCode, bool* aUserAllowedQuit) { - nsCOMPtr windowEnumerator; - nsCOMPtr 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 c0d60b927542653ab9beee730ec2c07f4b3d911c..85c416315f567a5edf8cfc89262dd7a48250dfd6 100644 ---- a/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp -+++ b/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp -@@ -176,8 +176,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 622ff7fe214d22e1e5d5a561753cffe3e1eafe31..ac2f30e00a9a6d18c61d00b0d6d4bf41ff48af95 100644 ---- a/toolkit/components/windowwatcher/nsWindowWatcher.cpp -+++ b/toolkit/components/windowwatcher/nsWindowWatcher.cpp -@@ -1882,7 +1882,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.sys.mjs b/toolkit/mozapps/update/UpdateService.sys.mjs -index 5d5a3f2c46138b578b583ad4a3506e1d227607ad..6d414635b80a74edb0b5ecfc6a98dd0fee763952 100644 ---- a/toolkit/mozapps/update/UpdateService.sys.mjs -+++ b/toolkit/mozapps/update/UpdateService.sys.mjs -@@ -3874,6 +3874,8 @@ export class UpdateService { - } - - get disabledForTesting() { -+ /* playwright */ -+ return true; - return lazy.UpdateServiceStub.updateDisabledForTesting; - } - -diff --git a/toolkit/toolkit.mozbuild b/toolkit/toolkit.mozbuild -index e8399d277ec0b64e5ea29aa7262b118936a02779..983ed73ad1d6d734af55a9066a8e8a6cf3ae3f45 100644 ---- a/toolkit/toolkit.mozbuild -+++ b/toolkit/toolkit.mozbuild -@@ -155,6 +155,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 7eb9e1104682d4eb47060654f43a1efa8b2a6bb2..a8315d6decf654b5302bea5beeea34140c300ded 100644 ---- a/toolkit/xre/nsWindowsWMain.cpp -+++ b/toolkit/xre/nsWindowsWMain.cpp -@@ -14,8 +14,10 @@ - #endif - - #include "mozilla/Char16.h" -+#include "mozilla/CmdLineAndEnvUtils.h" - #include "nsUTF8Utils.h" - -+#include - #include - - #ifdef __MINGW32__ -@@ -114,6 +116,19 @@ static void FreeAllocStrings(int argc, char** argv) { - int wmain(int argc, WCHAR** argv) { - SanitizeEnvironmentVariables(); - SetDllDirectoryW(L""); -+ bool hasJugglerPipe = -+ mozilla::CheckArg(argc, argv, "juggler-pipe", 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 9ef5370d1524ddecb965785a73a3cfea39867324..e0245cca94e496bcffba40c9660a52b518803d44 100644 ---- a/uriloader/base/nsDocLoader.cpp -+++ b/uriloader/base/nsDocLoader.cpp -@@ -861,6 +861,12 @@ void nsDocLoader::DocLoaderIsEmpty(bool aFlushLayout, - ("DocLoader:%p: Firing load event for document.open\n", - this)); - -+ nsCOMPtr 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 5bd60b585b53cc77e75c0b68c763957f90b7e164..940b3b62b09ca70ae5e69c3e94eda11ad35b9dfe 100644 ---- a/uriloader/exthandler/nsExternalHelperAppService.cpp -+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp -@@ -112,6 +112,7 @@ - - #include "mozilla/Components.h" - #include "mozilla/ClearOnShutdown.h" -+#include "mozilla/ErrorNames.h" - #include "mozilla/Preferences.h" - #include "mozilla/ipc/URIUtils.h" - -@@ -865,6 +866,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); -@@ -1500,7 +1507,12 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel* aChannel) { - // Strip off the ".part" from mTempLeafName - mTempLeafName.Truncate(mTempLeafName.Length() - std::size(".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); -@@ -1684,7 +1696,36 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { - return NS_OK; - } - -- rv = SetUpTempFile(aChannel); -+ bool isIntercepted = false; -+ nsCOMPtr interceptor = mExtProtSvc->mInterceptor; -+ if (interceptor) { -+ nsCOMPtr 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; - -@@ -1745,6 +1786,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 -@@ -2261,6 +2305,16 @@ nsExternalAppHandler::OnSaveComplete(nsIBackgroundFileSaver* aSaver, - NotifyTransfer(aStatus); - } - -+ if (!mCanceled) { -+ nsCOMPtr 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; - } - -@@ -2744,6 +2798,15 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason) { - } - } - -+ nsCOMPtr 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 26dfc6f04298420317c8b87b2ecc3f2f47f59598..c458ab5efb238c62499ee13452f2d750e0569e38 100644 ---- a/uriloader/exthandler/nsExternalHelperAppService.h -+++ b/uriloader/exthandler/nsExternalHelperAppService.h -@@ -263,6 +263,8 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService, - mozilla::dom::BrowsingContext* aContentContext, bool aForceSave, - nsIInterfaceRequestor* aWindowContext, - nsIStreamListener** aStreamListener); -+ -+ nsCOMPtr mInterceptor; - }; - - /** -@@ -460,6 +462,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 e6490ebb086eb4dca9db560c14e073a9e7722e29..2792373dcb30ebc787a9bdca306ac12e72aa19ec 100644 ---- a/uriloader/exthandler/nsIExternalHelperAppService.idl -+++ b/uriloader/exthandler/nsIExternalHelperAppService.idl -@@ -6,8 +6,11 @@ - - #include "nsICancelable.idl" - -+webidl BrowsingContext; -+interface nsIHelperAppLauncher; - interface nsIURI; - interface nsIChannel; -+interface nsIRequest; - interface nsIStreamListener; - interface nsIFile; - interface nsIMIMEInfo; -@@ -15,6 +18,17 @@ interface nsIWebProgressListener2; - interface nsIInterfaceRequestor; - webidl BrowsingContext; - -+/** -+ * Interceptor interface used by Juggler. -+ */ -+[scriptable, uuid(9a20e9b0-75d0-11ea-bc55-0242ac130003)] -+interface nsIDownloadInterceptor : nsISupports -+{ -+ boolean 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. -@@ -87,6 +101,8 @@ interface nsIExternalHelperAppService : nsISupports - * `DownloadIntegration.sys.mjs`, which is implemented on all platforms. - */ - nsIFile getPreferredDownloadsDirectory(); -+ -+ void setDownloadInterceptor(in nsIDownloadInterceptor interceptor); - }; - - /** -diff --git a/widget/InProcessCompositorWidget.cpp b/widget/InProcessCompositorWidget.cpp -index 7098db301770ecb5b9a506d7caec89d5cf63384b..aff8d7562f8a3e595a077ce8e591008762479587 100644 ---- a/widget/InProcessCompositorWidget.cpp -+++ b/widget/InProcessCompositorWidget.cpp -@@ -5,8 +5,11 @@ - #include "InProcessCompositorWidget.h" - -+#include "HeadlessCompositorWidget.h" -+#include "HeadlessWidget.h" - #include "mozilla/VsyncDispatcher.h" -+#include "mozilla/widget/PlatformWidgetTypes.h" - #include "mozilla/layers/NativeLayer.h" - #include "nsIWidget.h" - - namespace mozilla { -@@ -26,6 +29,12 @@ RefPtr CompositorWidget::CreateLocal( - // do it after the static_cast. - nsIWidget* widget = static_cast(aWidget)); -+ } - return new InProcessCompositorWidget(aOptions, widget); - } - #endif -diff --git a/widget/MouseEvents.h b/widget/MouseEvents.h -index 4f7ca9d0d460da3124ec8489917a9484661d5624..a04c3661b3e1e2be030ac6fe90041c81e653d26e 100644 ---- a/widget/MouseEvents.h -+++ b/widget/MouseEvents.h -@@ -380,6 +380,9 @@ class WidgetMouseEvent : public WidgetMouseEventBase, - // Otherwise, this must be 0. - uint32_t mClickCount = 0; - -+ // Unique event ID -+ uint32_t mJugglerEventId = 0; -+ - // Whether the event should ignore scroll frame bounds during dispatch. - bool mIgnoreRootScrollFrame = false; - -@@ -407,6 +410,7 @@ class WidgetMouseEvent : public WidgetMouseEventBase, - mContextMenuTrigger = aEvent.mContextMenuTrigger; - mExitFrom = aEvent.mExitFrom; - mClickCount = aEvent.mClickCount; -+ mJugglerEventId = aEvent.mJugglerEventId; - mIgnoreRootScrollFrame = aEvent.mIgnoreRootScrollFrame; - mIgnoreCapturingContent = aEvent.mIgnoreCapturingContent; - mClickEventPrevented = aEvent.mClickEventPrevented; -diff --git a/widget/cocoa/NativeKeyBindings.mm b/widget/cocoa/NativeKeyBindings.mm -index 24b70173c2e8bb9be9fd6255984a70efe3b14099..75ac367a1c4bb44d4b68b5f4ecc6adf56dbd408e 100644 ---- a/widget/cocoa/NativeKeyBindings.mm -+++ b/widget/cocoa/NativeKeyBindings.mm -@@ -549,6 +549,13 @@ void NativeKeyBindings::GetEditCommandsForTests( - 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())) { -@@ -571,6 +578,13 @@ void NativeKeyBindings::GetEditCommandsForTests( - 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())) { -@@ -593,6 +607,10 @@ void NativeKeyBindings::GetEditCommandsForTests( - 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()) { -@@ -603,7 +621,7 @@ void NativeKeyBindings::GetEditCommandsForTests( - !aEvent.IsShift() - ? ToObjcSelectorPtr(@selector(moveToBeginningOfDocument:)) - : ToObjcSelectorPtr( -- @selector(moveToBegginingOfDocumentAndModifySelection:)), -+ @selector(moveToBeginningOfDocumentAndModifySelection:)), - aCommands); - break; - } -@@ -630,6 +648,10 @@ void NativeKeyBindings::GetEditCommandsForTests( - 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/gtk/nsFilePicker.cpp b/widget/gtk/nsFilePicker.cpp -index f09b0e4994304413cbd75f14e6650cf3f9df9025..41c184e74df2b9c59315a236506946bcb5d69216 100644 ---- a/widget/gtk/nsFilePicker.cpp -+++ b/widget/gtk/nsFilePicker.cpp -@@ -21,7 +21,8 @@ - #include "mozilla/Components.h" - #include "mozilla/Preferences.h" - #include "mozilla/dom/Promise.h" -+#include "gfxPlatform.h" - #include "mozilla/dom/Document.h" - - #include "nsArrayEnumerator.h" - #include "nsEnumeratorUtils.h" -diff --git a/widget/headless/HeadlessCompositorWidget.cpp b/widget/headless/HeadlessCompositorWidget.cpp -index bb4ee9175e66dc40de1871a7f91368fe309494a3..6814ae85038d31f1a3b1f87ba341219ffbc1e6b3 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" -@@ -15,9 +16,30 @@ HeadlessCompositorWidget::HeadlessCompositorWidget( - const layers::CompositorOptions& aOptions, HeadlessWidget* aWindow) - : CompositorWidget(aOptions), - mWidget(aWindow), -+ mMon("snapshotListener"), - mClientSize(LayoutDeviceIntSize(aInitData.InitialClientSize()), - "HeadlessCompositorWidget::mClientSize") {} - -+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 HeadlessCompositorWidget::StartRemoteDrawingInRegion( -+ const LayoutDeviceIntRegion& aInvalidRegion) { -+ if (!mDrawTarget) -+ return nullptr; -+ -+ RefPtr result = mDrawTarget; -+ return result.forget(); -+} -+ - void HeadlessCompositorWidget::ObserveVsync(VsyncObserver* aObserver) { - if (RefPtr cvd = - mWidget->GetCompositorVsyncDispatcher()) { -@@ -31,6 +53,59 @@ void HeadlessCompositorWidget::NotifyClientSizeChanged( - const LayoutDeviceIntSize& aClientSize) { - auto size = mClientSize.Lock(); - *size = aClientSize; -+ layers::CompositorThread()->Dispatch(NewRunnableMethod( -+ "HeadlessCompositorWidget::UpdateDrawTarget", this, -+ &HeadlessCompositorWidget::UpdateDrawTarget, -+ aClientSize)); -+} -+ -+void HeadlessCompositorWidget::UpdateDrawTarget(const LayoutDeviceIntSize& aClientSize) { -+ MOZ_ASSERT(NS_IsInCompositorThread()); -+ if (aClientSize.IsEmpty()) { -+ mDrawTarget = nullptr; -+ return; -+ } -+ -+ RefPtr 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 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 snapshot = mDrawTarget->Snapshot(); -+ if (!snapshot) { -+ fprintf(stderr, "Failed to get snapshot of draw target\n"); -+ return; -+ } -+ -+ RefPtr 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 facd2bc65afab8ec1aa322faa20a67464964dfb9..3c5751ad1b7f042bc7cd9a63895cebcd2942ccd3 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,11 @@ class HeadlessCompositorWidget final : public CompositorWidget, - HeadlessWidget* aWindow); - - void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize); -+ void SetSnapshotListener(HeadlessWidget::SnapshotListener&& listener); - - // CompositorWidget Overrides -+ already_AddRefed StartRemoteDrawingInRegion( -+ const LayoutDeviceIntRegion& aInvalidRegion) override; - - uintptr_t GetWidgetKey() override; - -@@ -42,10 +46,18 @@ class HeadlessCompositorWidget final : public CompositorWidget, - } - - private: -+ void UpdateDrawTarget(const LayoutDeviceIntSize& aClientSize); -+ void PeriodicSnapshot(); -+ void TakeSnapshot(); -+ - HeadlessWidget* mWidget; -+ mozilla::ReentrantMonitor mMon; - - // See GtkCompositorWidget for the justification for this mutex. - DataMutex mClientSize; -+ -+ HeadlessWidget::SnapshotListener mSnapshotListener; -+ RefPtr mDrawTarget; - }; - - } // namespace widget -diff --git a/widget/headless/HeadlessWidget.cpp b/widget/headless/HeadlessWidget.cpp -index 290de12f9d0ff858474564fa8ce54814a04f6088..c144a891b84c3c57f394d6d551e6c89dcd6d9829 100644 ---- a/widget/headless/HeadlessWidget.cpp -+++ b/widget/headless/HeadlessWidget.cpp -@@ -112,6 +112,8 @@ void HeadlessWidget::Destroy() { - } - } - -+ SetSnapshotListener(nullptr); -+ - nsBaseWidget::OnDestroy(); - - nsBaseWidget::Destroy(); -@@ -593,5 +595,14 @@ nsresult HeadlessWidget::SynthesizeNativeTouchpadPan( - 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 60598d097d9dae829ebdc15dede78bd915e3107d..3b5ac5e5590dcb36440e28569f71592db3c1218c 100644 ---- a/widget/headless/HeadlessWidget.h -+++ b/widget/headless/HeadlessWidget.h -@@ -131,6 +131,9 @@ class HeadlessWidget final : public nsBaseWidget { - double aDeltaX, double aDeltaY, int32_t aModifierFlags, - nsISynthesizedEventCallback* aCallback) override; - -+ using SnapshotListener = std::function&&)>; -+ void SetSnapshotListener(SnapshotListener&& listener); -+ - private: - ~HeadlessWidget(); - bool mEnabled; -diff --git a/widget/nsGUIEventIPC.h b/widget/nsGUIEventIPC.h -index 2f4c33f151870bb9233899b186a5eccfaa6f5da6..6acf66e4938e3f9727916824a08d6294f8993452 100644 ---- a/widget/nsGUIEventIPC.h -+++ b/widget/nsGUIEventIPC.h -@@ -251,6 +251,7 @@ struct ParamTraits { - aParam.mExitFrom.value())); - } - WriteParam(aWriter, aParam.mClickCount); -+ WriteParam(aWriter, aParam.mJugglerEventId); - } - - static bool Read(MessageReader* aReader, paramType* aResult) { -@@ -275,6 +276,7 @@ struct ParamTraits { - aResult->mExitFrom = Some(static_cast(exitFrom)); - } - rv = rv && ReadParam(aReader, &aResult->mClickCount); -+ rv = rv && ReadParam(aReader, &aResult->mJugglerEventId); - return rv; - } - }; -diff --git a/xpcom/reflect/xptinfo/xptinfo.h b/xpcom/reflect/xptinfo/xptinfo.h -index 787d30d881adedd57d2025ca57bff4bc6c57e803..ae1a0172c960ab16919133485722d2ae0cdbcbd4 100644 ---- a/xpcom/reflect/xptinfo/xptinfo.h -+++ b/xpcom/reflect/xptinfo/xptinfo.h -@@ -505,7 +505,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 - - /** diff --git a/patches/playwright/0-playwright.patch.bak3 b/patches/playwright/0-playwright.patch.bak3 deleted file mode 100644 index 113f3073..00000000 --- a/patches/playwright/0-playwright.patch.bak3 +++ /dev/null @@ -1,3469 +0,0 @@ -diff --git a/accessible/interfaces/nsIAccessibleDocument.idl b/accessible/interfaces/nsIAccessibleDocument.idl -index 6c932c14a03e9cbf70723171dc9a1006bd2c017d..6312131c94c6d7e994a4a49dd64b2b4c5777251f 100644 ---- a/accessible/interfaces/nsIAccessibleDocument.idl -+++ b/accessible/interfaces/nsIAccessibleDocument.idl -@@ -73,4 +73,9 @@ interface nsIAccessibleDocument : nsISupports - * The BrowsingContext of this document. - */ - readonly attribute BrowsingContext browsingContext; -+ -+ /** -+ * Return whether it is updating. -+ */ -+ readonly attribute boolean isUpdatePendingForJugglerAccessibility; - }; -diff --git a/accessible/xpcom/xpcAccessibleDocument.cpp b/accessible/xpcom/xpcAccessibleDocument.cpp -index 3229ee415b93b9a47d7d40605ed7b509744c94ad..c2cc38ded257a02de8922312057892bf9d0cad7b 100644 ---- a/accessible/xpcom/xpcAccessibleDocument.cpp -+++ b/accessible/xpcom/xpcAccessibleDocument.cpp -@@ -151,6 +151,13 @@ xpcAccessibleDocument::GetBrowsingContext( - return NS_OK; - } - -+NS_IMETHODIMP -+xpcAccessibleDocument::GetIsUpdatePendingForJugglerAccessibility(bool* updating) { -+ NS_ENSURE_ARG_POINTER(updating); -+ *updating = Intl()->Controller()->IsUpdatePending(); -+ return NS_OK; -+} -+ - //////////////////////////////////////////////////////////////////////////////// - // xpcAccessibleDocument - -diff --git a/accessible/xpcom/xpcAccessibleDocument.h b/accessible/xpcom/xpcAccessibleDocument.h -index 9b6effc38fbecb50897a93b49c41d4453b10fb7f..939ff9615bd422eec186d8164e2ac7e643f39beb 100644 ---- a/accessible/xpcom/xpcAccessibleDocument.h -+++ b/accessible/xpcom/xpcAccessibleDocument.h -@@ -48,6 +48,8 @@ class xpcAccessibleDocument : public xpcAccessibleHyperText, - nsIAccessibleDocument** aDocument) final; - NS_IMETHOD GetBrowsingContext(dom::BrowsingContext** aBrowsingContext) 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 8167d2b81c918e02ce757f7f448f22e07c29d140..3ae798880acfd8aa965ae08051f2f81855133711 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 - #include - #include - -@@ -422,8 +423,18 @@ Maybe 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, "juggler-pipe", 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(stdio3), -+ reinterpret_cast(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 6bbc4016cd6d56e8625e808b5070515a23de7600..2fb56fb1afa5b108a426737cb5e62dc42a199354 100644 ---- a/browser/installer/allowed-dupes.mn -+++ b/browser/installer/allowed-dupes.mn -@@ -59,6 +59,12 @@ browser/chrome/browser/builtin-addons/webcompat/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 -+ - # Bug 1606928 - There's no reliable way to connect Top Sites favicons with the favicons in the Search Service - browser/chrome/browser/content/activity-stream/data/content/tippytop/favicons/allegro-pl.ico - browser/defaults/settings/main/search-config-icons/96327a73-c433-5eb4-a16d-b090cadfb80b -diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in -index 2b4d35e060dc592bb70a1f2b7ceee68616c8202b..323abfaee37445942f7678037dd5b53792dd5ed4 100644 ---- a/browser/installer/package-manifest.in -+++ b/browser/installer/package-manifest.in -@@ -183,6 +183,9 @@ - @RESPATH@/chrome/remote.manifest - #endif - -+@RESPATH@/chrome/juggler@JAREXT@ -+@RESPATH@/chrome/juggler.manifest -+ - ; Modules - @RESPATH@/browser/modules/* - @RESPATH@/modules/* -diff --git a/devtools/server/socket/websocket-server.js b/devtools/server/socket/websocket-server.js -index d49c6fbf1bf83b832795fa674f6b41f223eef812..7ea3540947ff5f61b15f27fbf4b955649f8e9ff9 100644 ---- a/devtools/server/socket/websocket-server.js -+++ b/devtools/server/socket/websocket-server.js -@@ -134,13 +134,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"); - } - -@@ -190,13 +189,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, [ -@@ -218,8 +217,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 97334bee3a111a538779789d3495805cec8b1e9a..67d030f2adecd9acc62665e2a627123148aa927d 100644 ---- a/docshell/base/BrowsingContext.cpp -+++ b/docshell/base/BrowsingContext.cpp -@@ -110,8 +110,15 @@ struct ParamTraits - - template <> - struct ParamTraits -- : public mozilla::dom::WebIDLEnumSerializer< -- mozilla::dom::PrefersColorSchemeOverride> {}; -+ : public mozilla::dom::WebIDLEnumSerializer {}; -+ -+template <> -+struct ParamTraits -+ : public mozilla::dom::WebIDLEnumSerializer {}; -+ -+template <> -+struct ParamTraits -+ : public mozilla::dom::WebIDLEnumSerializer {}; - - template <> - struct ParamTraits -@@ -2950,6 +2957,32 @@ void BrowsingContext::DidSet(FieldIndex, - }); - } - -+void BrowsingContext::DidSet(FieldIndex, -+ dom::PrefersContrastOverride aOldValue) { -+ MOZ_ASSERT(IsTop()); -+ if (PrefersContrastOverride() == aOldValue) { -+ return; -+ } -+ PresContextAffectingFieldChanged(); -+} -+ -+void BrowsingContext::DidSet(FieldIndex, -+ 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, - nsString&& aOldValue) { - MOZ_ASSERT(IsTop()); -@@ -3290,7 +3323,7 @@ void BrowsingContext::SetGeolocationServiceOverride( - if (aGeolocationOverride.WasPassed()) { - if (!mGeolocationServiceOverride) { - mGeolocationServiceOverride = new nsGeolocationService(); -- mGeolocationServiceOverride->Init(); -+ mGeolocationServiceOverride->Init(true /* isOverride */); - } - mGeolocationServiceOverride->Update(aGeolocationOverride.Value()); - } else if (RefPtr serviceOverride = -@@ -3793,6 +3826,23 @@ void BrowsingContext::DidSet(FieldIndex, - } - } - -+void BrowsingContext::DidSet(FieldIndex, bool aOldValue) { -+ const bool newValue = ForceOffline(); -+ if (newValue == aOldValue) { -+ return; -+ } -+ PreOrderWalk([&](BrowsingContext* aContext) { -+ if (Document* doc = aContext->GetDocument()) { -+ if (nsPIDOMWindowOuter* win = aContext->GetDOMWindow()) { -+ nsContentUtils::DispatchTrustedEvent( -+ doc, nsGlobalWindowOuter::Cast(win), -+ newValue ? u"offline"_ns : u"online"_ns, -+ CanBubble::eYes, Cancelable::eYes, nullptr); -+ } -+ } -+ }); -+} -+ - bool BrowsingContext::IsPopupAllowed() { - for (auto* context = GetCurrentWindowContext(); context; - context = context->GetParentWindowContext()) { -diff --git a/docshell/base/BrowsingContext.h b/docshell/base/BrowsingContext.h -index b42c32133c6490755ae4e1c599255418e6443011..afa502833ba55c94dbd30726d37450c460a69e2b 100644 ---- a/docshell/base/BrowsingContext.h -+++ b/docshell/base/BrowsingContext.h -@@ -209,11 +209,11 @@ struct EmbedderColorSchemes { - FIELD(GVInaudibleAutoplayRequestStatus, GVAutoplayRequestStatus) \ - /* ScreenOrientation-related APIs */ \ - FIELD(CurrentOrientationAngle, float) \ -- FIELD(CurrentOrientationType, mozilla::dom::OrientationType) \ -+ FIELD(CurrentOrientationType, dom::OrientationType) \ - FIELD(OrientationLock, mozilla::hal::ScreenOrientation) \ - FIELD(HasOrientationOverride, bool) \ - FIELD(UserAgentOverride, nsString) \ -- FIELD(TouchEventsOverrideInternal, mozilla::dom::TouchEventsOverride) \ -+ FIELD(TouchEventsOverrideInternal, dom::TouchEventsOverride) \ - FIELD(EmbedderElementType, Maybe) \ - FIELD(MessageManagerGroup, nsString) \ - FIELD(MaxTouchPointsOverride, uint8_t) \ -@@ -253,6 +256,9 @@ struct EmbedderColorSchemes { - * embedder element. */ \ - FIELD(EmbedderColorSchemes, EmbedderColorSchemes) \ - FIELD(DisplayMode, dom::DisplayMode) \ -+ /* playwright addition */ \ -+ FIELD(PrefersReducedMotionOverride, dom::PrefersReducedMotionOverride) \ -+ FIELD(PrefersContrastOverride, dom::PrefersContrastOverride) \ - /* The number of entries added to the session history because of this \ - * browsing context. */ \ - FIELD(HistoryEntryCount, uint32_t) \ -@@ -975,6 +978,14 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - return GetForcedColorsOverride(); - } - -+ dom::PrefersReducedMotionOverride PrefersReducedMotionOverride() const { -+ return GetPrefersReducedMotionOverride(); -+ } -+ -+ dom::PrefersContrastOverride PrefersContrastOverride() const { -+ return GetPrefersContrastOverride(); -+ } -+ - bool IsInBFCache() const; - - bool AllowJavascript() const { return GetAllowJavascript(); } -@@ -1146,6 +1157,11 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - return IsTop(); - } - -+ bool CanSet(FieldIndex, -+ dom::PrefersContrastOverride, ContentParent*) { -+ return IsTop(); -+ } -+ - bool CanSet(FieldIndex, dom::ForcedColorsOverride, - ContentParent*) { - return IsTop(); -@@ -1278,13 +1297,25 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - void DidSet(FieldIndex, - dom::ForcedColorsOverride aOldValue); - -+ void DidSet(FieldIndex, -+ dom::PrefersContrastOverride aOldValue); -+ - template - void WalkPresContexts(Callback&&); - void PresContextAffectingFieldChanged(); - - void DidSet(FieldIndex, nsCString&& aOldValue); - - void DidSet(FieldIndex, nsString&& aOldValue); - -+ bool CanSet(FieldIndex, -+ dom::PrefersReducedMotionOverride, ContentParent*) { -+ return IsTop(); -+ } -+ -+ void DidSet(FieldIndex, -+ dom::PrefersReducedMotionOverride aOldValue); -+ -+ - void DidSet(FieldIndex, nsString&& aOldValue); - - bool CanSet(FieldIndex, bool, ContentParent*) { -@@ -1360,6 +1388,8 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - - void DidSet(FieldIndex, bool aOldValue); - -+ void DidSet(FieldIndex, bool aOldValue); -+ - // Allow if the process attemping to set field is the same as the owning - // process. Deprecated. New code that might use this should generally be moved - // to WindowContext or be settable only by the parent process. -diff --git a/docshell/base/CanonicalBrowsingContext.cpp b/docshell/base/CanonicalBrowsingContext.cpp -index 4953744c3f627bb68b78606d8ae4bf6ab649398a..17c7cc94dafc76cd72aacddfd633b7df58eeae78 100644 ---- a/docshell/base/CanonicalBrowsingContext.cpp -+++ b/docshell/base/CanonicalBrowsingContext.cpp -@@ -274,7 +274,9 @@ void CanonicalBrowsingContext::ReplacedBy( - txn.SetForceOffline(GetForceOffline()); - txn.SetTopInnerSizeForRFP(GetTopInnerSizeForRFP()); - txn.SetIPAddressSpace(GetIPAddressSpace()); -+ txn.SetPrefersReducedMotionOverride(GetPrefersReducedMotionOverride()); -+ txn.SetForcedColorsOverride(GetForcedColorsOverride()); - txn.SetParentalControlsEnabled(GetParentalControlsEnabled()); - - if (!GetLanguageOverride().IsEmpty()) { - // Reapply language override to update the corresponding realm. - txn.SetLanguageOverride(GetLanguageOverride()); - } - if (!GetTimezoneOverride().IsEmpty()) { - // Reapply timezone override to update the corresponding realm. -@@ -1908,6 +1910,12 @@ void CanonicalBrowsingContext::LoadURI(nsIURI* aURI, - (void)SetIsCaptivePortalTab(true); - } - -+ { -+ nsCOMPtr observerService = mozilla::services::GetObserverService(); -+ if (observerService) { -+ observerService->NotifyObservers(ToSupports(this), "juggler-navigation-started-browser", NS_ConvertASCIItoUTF16(nsPrintfCString("%" PRIu64, loadState->GetLoadIdentifier())).get()); -+ } -+ } - LoadURI(loadState, true); - } - -diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp -index bf702818cf4116ec1cd911b6e7b5f7ddafa3e508..d846e5f6f900d2d69228331b80031bd1c18b08ed 100644 ---- a/docshell/base/nsDocShell.cpp -+++ b/docshell/base/nsDocShell.cpp -@@ -18,6 +18,12 @@ - #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/Attributes.h" - #include "mozilla/AutoRestore.h" - #include "mozilla/BasePrincipal.h" -@@ -67,6 +73,7 @@ - #include "mozilla/dom/DocGroup.h" - #include "mozilla/dom/Element.h" - #include "mozilla/dom/FragmentDirective.h" -+#include "mozilla/dom/Geolocation.h" - #include "mozilla/dom/HTMLAnchorElement.h" - #include "mozilla/dom/HTMLIFrameElement.h" - #include "mozilla/dom/Navigation.h" -@@ -98,6 +105,7 @@ - #include "mozilla/dom/DocumentBinding.h" - #include "mozilla/glean/DocshellMetrics.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" -@@ -122,6 +130,7 @@ - #include "nsIDocumentViewer.h" - #include "mozilla/dom/Document.h" - #include "nsHTMLDocument.h" -+#include "mozilla/dom/Element.h" - #include "nsIDocumentLoaderFactory.h" - #include "nsIDOMWindow.h" - #include "nsIEditingSession.h" -@@ -217,6 +226,7 @@ - #include "nsGlobalWindowInner.h" - #include "nsGlobalWindowOuter.h" - #include "nsJSEnvironment.h" -+#include "nsJSUtils.h" - #include "nsNetCID.h" - #include "nsNetUtil.h" - #include "nsObjectLoadingContent.h" -@@ -358,6 +368,14 @@ nsDocShell::nsDocShell(BrowsingContext* aBrowsingContext, - mAllowDNSPrefetch(true), - mAllowWindowControl(true), - mCSSErrorReportingEnabled(false), -+ mFileInputInterceptionEnabled(false), -+ mOverrideHasFocus(false), -+ mBypassCSPEnabled(false), -+ mForceActiveState(false), -+ mDisallowBFCache(false), -+ mReducedMotionOverride(REDUCED_MOTION_OVERRIDE_NONE), -+ mForcedColorsOverride(FORCED_COLORS_OVERRIDE_NO_OVERRIDE), -+ mContrastOverride(CONTRAST_OVERRIDE_NONE), - mAllowAuth(mItemType == typeContent), - mAllowKeywordFixup(false), - mDisableMetaRefreshWhenInactive(false), -@@ -3037,6 +3055,232 @@ nsDocShell::GetMessageManager(ContentFrameMessageManager** aMessageManager) { - return NS_OK; - } - -+// =============== Juggler Begin ======================= -+ -+nsDocShell* nsDocShell::GetRootDocShell() { -+ nsCOMPtr rootAsItem; -+ GetInProcessSameTypeRootTreeItem(getter_AddRefs(rootAsItem)); -+ nsCOMPtr 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; -+} -+ -+NS_IMETHODIMP -+nsDocShell::GetDisallowBFCache(bool* aEnabled) { -+ MOZ_ASSERT(aEnabled); -+ *aEnabled = mDisallowBFCache; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetDisallowBFCache(bool aEnabled) { -+ mDisallowBFCache = aEnabled; -+ 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) { -+ 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 observerService = -+ mozilla::services::GetObserverService(); -+ observerService->NotifyObservers( -+ ToSupports(element), "juggler-file-picker-shown", nullptr); -+} -+ -+RefPtr 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::GetReducedMotionOverride(ReducedMotionOverride* aReducedMotionOverride) { -+ *aReducedMotionOverride = GetRootDocShell()->mReducedMotionOverride; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetReducedMotionOverride(ReducedMotionOverride aReducedMotionOverride) { -+ mReducedMotionOverride = aReducedMotionOverride; -+ RefPtr 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 presContext = GetPresContext(); -+ if (presContext) { -+ presContext->MediaFeatureValuesChanged( -+ {MediaFeatureChangeReason::SystemMetricsChange}, -+ MediaFeatureChangePropagation::JustThisDocument); -+ } -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::GetContrastOverride(ContrastOverride* aContrastOverride) { -+ *aContrastOverride = GetRootDocShell()->mContrastOverride; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetContrastOverride(ContrastOverride aContrastOverride) { -+ mContrastOverride = aContrastOverride; -+ RefPtr presContext = GetPresContext(); -+ if (presContext) { -+ presContext->MediaFeatureValuesChanged( -+ {MediaFeatureChangeReason::SystemMetricsChange}, -+ MediaFeatureChangePropagation::JustThisDocument); -+ } -+ return NS_OK; -+} -+ -+// =============== Juggler End ======================= -+ - NS_IMETHODIMP - nsDocShell::GetIsNavigating(bool* aOut) { - *aOut = mIsNavigating; -@@ -4819,7 +5063,7 @@ nsDocShell::GetVisibility(bool* aVisibility) { - } - - void nsDocShell::ActivenessMaybeChanged() { -- const bool isActive = mBrowsingContext->IsActive(); -+ const bool isActive = mForceActiveState || mBrowsingContext->IsActive(); - if (RefPtr presShell = GetPresShell()) { - presShell->ActivenessMaybeChanged(); - } -@@ -6881,6 +7125,10 @@ bool nsDocShell::CanSavePresentation(uint32_t aLoadType, - return false; // no entry to save into - } - -+ if (mDisallowBFCache) { -+ return false; -+ } -+ - MOZ_ASSERT(!mozilla::SessionHistoryInParent(), - "mOSHE cannot be non-null with SHIP"); - nsCOMPtr viewer = mOSHE->GetDocumentViewer(); -@@ -8637,6 +8885,12 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState) { - true, // aForceNoOpener - getter_AddRefs(newBC)); - MOZ_ASSERT(!newBC); -+ if (rv == NS_OK) { -+ nsCOMPtr observerService = mozilla::services::GetObserverService(); -+ if (observerService) { -+ observerService->NotifyObservers(GetAsSupports(this), "juggler-window-open-in-new-context", nullptr); -+ } -+ } - return rv; - } - -@@ -9934,6 +10188,16 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState, - nsINetworkPredictor::PREDICT_LOAD, attrs, nullptr); - - nsCOMPtr req; -+ -+ // Juggler: report navigation started for non-same-document and non-javascript -+ // navigations. -+ if (!isJavaScript && !sameDocument) { -+ nsCOMPtr observerService = -+ mozilla::services::GetObserverService(); -+ if (observerService) { -+ observerService->NotifyObservers(GetAsSupports(this), "juggler-navigation-started-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("%" PRIu64, aLoadState->GetLoadIdentifier())).get()); -+ } -+ } - rv = DoURILoad(aLoadState, aCacheKey, getter_AddRefs(req)); - - if (NS_SUCCEEDED(rv)) { -@@ -13323,6 +13587,9 @@ class OnLinkClickEvent : public Runnable { - mHandler->OnLinkClickSync(mContent, mLoadState, mNoOpenerImplied, - mTriggeringPrincipal); - } -+ nsCOMPtr observerService = mozilla::services::GetObserverService(); -+ observerService->NotifyObservers(ToSupports(mContent), "juggler-link-click-sync", nullptr); -+ - return NS_OK; - } - -@@ -13439,6 +13706,8 @@ nsresult nsDocShell::OnLinkClick( - - nsCOMPtr ev = new OnLinkClickEvent( - this, aContent, loadState, noOpenerImplied, aTriggeringPrincipal); -+ nsCOMPtr observerService = mozilla::services::GetObserverService(); -+ observerService->NotifyObservers(ToSupports(aContent), "juggler-link-click", nullptr); - return Dispatch(ev.forget()); - } - -diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h -index 3050f0a5a10c7f49f56cf325cd8bfe5e6508b5be..a4f4895f69a2eaa55f3eeae77bd6a3fb29931ad4 100644 ---- a/docshell/base/nsDocShell.h -+++ b/docshell/base/nsDocShell.h -@@ -16,6 +16,7 @@ - #include "mozilla/WeakPtr.h" - #include "mozilla/dom/BrowsingContext.h" - #include "mozilla/dom/NavigationBinding.h" -+#include "mozilla/dom/Element.h" - #include "mozilla/dom/WindowProxyHolder.h" - #include "nsCOMPtr.h" - #include "nsCharsetSource.h" -@@ -80,6 +81,7 @@ class nsCommandManager; - class nsDocShellEditorData; - class nsDOMNavigationTiming; - class nsDSURIContentListener; -+class nsGeolocationService; - class nsGlobalWindowOuter; - - class FramingChecker; -@@ -410,6 +412,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 GetGeolocationServiceOverride(); -+ - // Create a content viewer within this nsDocShell for the given - // `WindowGlobalChild` actor. - nsresult CreateDocumentViewerForActor( -@@ -1036,6 +1047,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 -@@ -1355,6 +1368,17 @@ 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; -+ bool mDisallowBFCache : 1; -+ nsString mLanguageOverride; -+ RefPtr mGeolocationServiceOverride; -+ ReducedMotionOverride mReducedMotionOverride; -+ ForcedColorsOverride mForcedColorsOverride; -+ ContrastOverride mContrastOverride; -+ - bool mAllowAuth : 1; - bool mAllowKeywordFixup : 1; - bool mDisableMetaRefreshWhenInactive : 1; -diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl -index 763c7adb5ab9e3e56d6f1608899f6622997f272a..4f77795b5ce1f8fff79581987e017165dbdcbc1e 100644 ---- a/docshell/base/nsIDocShell.idl -+++ b/docshell/base/nsIDocShell.idl -@@ -44,6 +44,7 @@ interface nsIURI; - interface nsIChannel; - interface nsIPolicyContainer; - interface nsIDocumentViewer; -+interface nsIDOMGeoPosition; - interface nsIEditor; - interface nsIEditingSession; - interface nsIInputStream; -@@ -719,6 +720,45 @@ interface nsIDocShell : nsIDocShellTreeItem - */ - void synchronizeLayoutHistoryState(); - -+ attribute boolean fileInputInterceptionEnabled; -+ -+ attribute boolean overrideHasFocus; -+ -+ attribute boolean bypassCSPEnabled; -+ -+ attribute boolean forceActiveState; -+ -+ attribute boolean disallowBFCache; -+ -+ attribute AString languageOverride; -+ -+ boolean overrideTimezone(in AString timezoneId); -+ -+ 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; -+ -+ cenum ContrastOverride : 8 { -+ CONTRAST_OVERRIDE_LESS, -+ CONTRAST_OVERRIDE_MORE, -+ CONTRAST_OVERRIDE_CUSTOM, -+ CONTRAST_OVERRIDE_NO_PREFERENCE, -+ CONTRAST_OVERRIDE_NONE, /* This clears the override. */ -+ }; -+ [infallible] attribute nsIDocShell_ContrastOverride contrastOverride; -+ -+ 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 40da41ae4ac7d8d61c664e25bec8a74091d8b3e0..50ee1170e6d5b261334c7baccc63ed492b86ec38 100644 ---- a/dom/base/Document.cpp -+++ b/dom/base/Document.cpp -@@ -3799,6 +3799,9 @@ void Document::SendToConsole(nsCOMArray& aMessages) { - } - - void Document::ApplySettingsFromCSP(bool aSpeculative) { -+ if (mDocumentContainer && mDocumentContainer->IsBypassCSPEnabled()) -+ return; -+ - nsresult rv = NS_OK; - if (!aSpeculative) { - nsIContentSecurityPolicy* csp = PolicyContainer::GetCSP(mPolicyContainer); -@@ -3887,6 +3890,11 @@ nsresult Document::InitCSP(nsIChannel* aChannel) { - MOZ_ASSERT(mPolicyContainer, - "Policy container must be initialized before CSP!"); - -+ nsCOMPtr 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; -@@ -4753,6 +4761,10 @@ bool Document::HasFocus(ErrorResult& rv) const { - return false; - } - -+ if (IsActive() && mDocumentContainer->ShouldOverrideHasFocus()) { -+ return true; -+ } -+ - if (!fm->IsInActiveWindow(bc)) { - return false; - } -@@ -20326,6 +20338,35 @@ ColorScheme Document::PreferredColorScheme(IgnoreRFP aIgnoreRFP) const { - return PreferenceSheet::PrefsFor(*this).mColorScheme; - } - -+bool Document::PrefersReducedMotion() const { -+ auto* docShell = static_cast(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: -+ break; -+ } -+ } -+ -+ return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1; -+} -+ - bool Document::HasRecentlyStartedForegroundLoads() { - if (!sLoadingForegroundTopLevelContentDocument) { - return false; -diff --git a/dom/base/Document.h b/dom/base/Document.h -index 20f726a52f9f3591502597e20eeb8c07fe35feb2..c46f58ac88d536850169e6c51b9cfcb871d36e70 100644 ---- a/dom/base/Document.h -+++ b/dom/base/Document.h -@@ -4252,6 +4252,8 @@ class Document : public nsINode, - // color-scheme meta tag. - ColorScheme DefaultColorScheme() const; - -+ bool PrefersReducedMotion() const; -+ - static bool HasRecentlyStartedForegroundLoads(); - - static bool AutomaticStorageAccessPermissionCanBeGranted( -diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp -index 11a57adbb57b0adccf7ae491e7d7757f838bd9dc..e478244cedc2089fb99b3153d7493b7d36d72ea9 100644 ---- a/dom/base/Navigator.cpp -+++ b/dom/base/Navigator.cpp -@@ -347,14 +347,18 @@ void Navigator::GetAppName(nsAString& aAppName) const { - * for more detail. - */ - /* static */ --void Navigator::GetAcceptLanguages(nsTArray& aLanguages) { -+void Navigator::GetAcceptLanguages(const nsString* aLanguageOverride, nsTArray& 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 : -@@ -406,7 +410,13 @@ void Navigator::GetLanguage(nsAString& aLanguage) { - } - - void Navigator::GetLanguages(nsTArray& aLanguages) { -- GetAcceptLanguages(aLanguages); -+ if (mWindow && mWindow->GetDocShell()) { -+ nsString languageOverride; -+ mWindow->GetDocShell()->GetLanguageOverride(languageOverride); -+ GetAcceptLanguages(&languageOverride, aLanguages); -+ } else { -+ GetAcceptLanguages(nullptr, aLanguages); -+ } - - @@ -2336,6 +2336,7 @@ bool Navigator::Webdriver() { - } - #endif - -- return false; -+ // Playwright is automating the browser, so we should pretend to be a webdriver -+ return true; - } - - AutoplayPolicy Navigator::GetAutoplayPolicy(AutoplayPolicyMediaType aType) { -diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h -index 893947475fbb8688becb1c1495385e4048d4927d..dfb50acf689223fdab7ef6f42afbbd53341e1b0b 100644 ---- a/dom/base/Navigator.h -+++ b/dom/base/Navigator.h -@@ -228,7 +228,7 @@ class Navigator final : public nsISupports, public nsWrapperCache { - - StorageManager* Storage(); - -- static void GetAcceptLanguages(nsTArray& aLanguages); -+ static void GetAcceptLanguages(const nsString* aLanguageOverride, nsTArray& aLanguages); - - dom::MediaCapabilities* MediaCapabilities(); - dom::MediaSession* MediaSession(); -diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp -index 7703ab18c104848eab9377769641d3b60e9bcf8e..3028fc5a7e6c54a7f4455f135e889d038eed378d 100644 ---- a/dom/base/nsContentUtils.cpp -+++ b/dom/base/nsContentUtils.cpp -@@ -9528,11 +9528,13 @@ nsresult nsContentUtils::SendMouseEvent( - int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, - float aPressure, unsigned short aInputSourceArg, uint32_t aIdentifier, - bool aToWindow, bool* aPreventDefault, bool aIsDOMEventSynthesized, -- bool aIsWidgetEventSynthesized) { -+ bool aIsWidgetEventSynthesized, -+ bool convertToPointer, uint32_t aJugglerEventId) { - MOZ_ASSERT(aWidget); - EventMessage msg; - Maybe exitFrom; - bool contextMenuKey = false; -+ bool isPWDragEventMessage = false; - if (aType.EqualsLiteral("mousedown")) { - msg = eMouseDown; - } else if (aType.EqualsLiteral("mouseup")) { -@@ -9558,6 +9560,12 @@ nsresult nsContentUtils::SendMouseEvent( - msg = eMouseHitTest; - } else if (aType.EqualsLiteral("MozMouseExploreByTouch")) { - msg = eMouseExploreByTouch; -+ } else if (aType.EqualsLiteral("dragover")) { -+ msg = eDragOver; -+ isPWDragEventMessage = true; -+ } else if (aType.EqualsLiteral("drop")) { -+ msg = eDrop; -+ isPWDragEventMessage = true; - } else { - return NS_ERROR_FAILURE; - } -@@ -9568,7 +9576,14 @@ nsresult nsContentUtils::SendMouseEvent( - - Maybe pointerEvent; - Maybe mouseEvent; -- if (IsPointerEventMessage(msg)) { -+ Maybe pwDragEvent; -+ -+ if (isPWDragEventMessage) { -+ pwDragEvent.emplace(true, msg, aWidget); -+ pwDragEvent->mReason = aIsWidgetEventSynthesized -+ ? WidgetMouseEvent::eSynthesized -+ : WidgetMouseEvent::eReal; -+ } else if (IsPointerEventMessage(msg)) { - MOZ_ASSERT(!aIsWidgetEventSynthesized, - "The event shouldn't be dispatched as a synthesized event"); - if (MOZ_UNLIKELY(aIsWidgetEventSynthesized)) { -@@ -9587,8 +9602,11 @@ nsresult nsContentUtils::SendMouseEvent( - contextMenuKey ? WidgetMouseEvent::eContextMenuKey - : WidgetMouseEvent::eNormal); - } -+ - WidgetMouseEvent& mouseOrPointerEvent = -+ pwDragEvent.isSome() ? pwDragEvent.ref() : - pointerEvent.isSome() ? pointerEvent.ref() : mouseEvent.ref(); -+ - mouseOrPointerEvent.pointerId = aIdentifier; - mouseOrPointerEvent.mModifiers = GetWidgetModifiers(aModifiers); - mouseOrPointerEvent.mButton = aButton; -@@ -9601,6 +9619,8 @@ nsresult nsContentUtils::SendMouseEvent( - mouseOrPointerEvent.mClickCount = aClickCount; - mouseOrPointerEvent.mFlags.mIsSynthesizedForTests = aIsDOMEventSynthesized; - mouseOrPointerEvent.mExitFrom = exitFrom; -+ mouseOrPointerEvent.mJugglerEventId = aJugglerEventId; -+ mouseOrPointerEvent.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 a1b96bce18e1904f4068057defa26142ebe8874b..f2fc14da57cf08139723980dedc33f2d3a9a431b 100644 ---- a/dom/base/nsContentUtils.h -+++ b/dom/base/nsContentUtils.h -@@ -3080,8 +3080,9 @@ class nsContentUtils { - int32_t aButton, int32_t aButtons, int32_t aClickCount, - int32_t aModifiers, bool aIgnoreRootScrollFrame, float aPressure, - unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow, -- bool* aPreventDefault, bool aIsDOMEventSynthesized, -- bool aIsWidgetEventSynthesized); -+ bool* aPreventDefault, -+ bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized, -+ bool convertToPointer = true, uint32_t aJugglerEventId = 0); - - static void FirePageShowEventForFrameLoaderSwap( - nsIDocShellTreeItem* aItem, -diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp -index c6c5833cd29ef041da348d4398513bab7ef2f9aa..424cc396bfc211bc7debb3df203cfa26da7a4c55 100644 ---- a/dom/base/nsDOMWindowUtils.cpp -+++ b/dom/base/nsDOMWindowUtils.cpp -@@ -707,6 +707,26 @@ nsDOMWindowUtils::GetPresShellId(uint32_t* aPresShellId) { - return NS_ERROR_FAILURE; - } - -+static uint32_t sJugglerEventId = 1000; -+ -+NS_IMETHODIMP -+nsDOMWindowUtils::JugglerSendMouseEvent( -+ const nsAString& aType, float aX, float aY, int32_t aButton, -+ int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, -+ float aPressure, unsigned short aInputSourceArg, -+ bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized, -+ int32_t aButtons, uint32_t aIdentifier, bool aDisablePointerEvent, -+ uint32_t* aJugglerEventId) { -+ *aJugglerEventId = ++sJugglerEventId; -+ return SendMouseEventCommon( -+ aType, aX, aY, aButton, aClickCount, aModifiers, aIgnoreRootScrollFrame, -+ aPressure, aInputSourceArg, -+ aIdentifier, false, -+ nullptr, aIsDOMEventSynthesized, -+ aIsWidgetEventSynthesized, -+ aButtons, !aDisablePointerEvent, *aJugglerEventId); -+} -+ - NS_IMETHODIMP - nsDOMWindowUtils::SendMouseEvent( - const nsAString& aType, float aX, float aY, int32_t aButton, -@@ -721,7 +741,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, true, 0); - } - - NS_IMETHODIMP -@@ -739,7 +759,7 @@ nsDOMWindowUtils::SendMouseEventToWindow( - aOptionalArgCount >= 7 ? aIdentifier : DEFAULT_MOUSE_POINTER_ID, true, - nullptr, aOptionalArgCount >= 4 ? aIsDOMEventSynthesized : true, - aOptionalArgCount >= 5 ? aIsWidgetEventSynthesized : false, -- aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED); -+ aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED, 0); - } - - NS_IMETHODIMP -@@ -748,7 +768,7 @@ 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, uint32_t aJugglerEventId) { - RefPtr presShell = GetPresShell(); - if (!presShell) { - return NS_ERROR_FAILURE; -@@ -765,7 +785,7 @@ nsDOMWindowUtils::SendMouseEventCommon( - presShell, widget, aType, refPoint, aButton, aButtons, aClickCount, - aModifiers, aIgnoreRootScrollFrame, aPressure, aInputSourceArg, - aPointerId, aToWindow, aPreventDefault, aIsDOMEventSynthesized, -- aIsWidgetEventSynthesized); -+ aIsWidgetEventSynthesized, aConvertToPointer, aJugglerEventId); - } - - NS_IMETHODIMP -diff --git a/dom/base/nsDOMWindowUtils.h b/dom/base/nsDOMWindowUtils.h -index 4553ad5e7696055e861be5f840f8ce2bc54a5b29..1afc16325fcb63a3e510bdc387c8386eccf5d48b 100644 ---- a/dom/base/nsDOMWindowUtils.h -+++ b/dom/base/nsDOMWindowUtils.h -@@ -94,7 +94,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, uint32_t aJugglerEventId = 0); - - MOZ_CAN_RUN_SCRIPT - nsresult SendTouchEventCommon( -diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp -index 62c4bfb96dbb6e64aeadd9e45c296905b7956811..83f1e7303e2ebabfc73921d9bd27a255304a2ea4 100644 ---- a/dom/base/nsFocusManager.cpp -+++ b/dom/base/nsFocusManager.cpp -@@ -1717,6 +1717,10 @@ Maybe nsFocusManager::SetFocusInner(Element* aNewContent, - (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)) { -@@ -2303,6 +2307,7 @@ bool nsFocusManager::BlurImpl(BrowsingContext* aBrowsingContextToClear, - bool aIsLeavingDocument, bool aAdjustWidget, - bool aRemainActive, Element* aElementToFocus, - uint64_t aActionId) { -+ - LOGFOCUS(("<>", aActionId)); - - // hold a reference to the focused content, which may be null -@@ -2346,6 +2351,11 @@ bool nsFocusManager::BlurImpl(BrowsingContext* aBrowsingContextToClear, - return true; - } - -+ // Playwright: emulate focused page by never bluring when leaving document. -+ if (XRE_IsContentProcess() && aIsLeavingDocument && docShell && nsDocShell::Cast(docShell)->ShouldOverrideHasFocus()) { -+ return true; -+ } -+ - // Keep a ref to presShell since dispatching the DOM event may cause - // the document to be destroyed. - RefPtr presShell = docShell->GetPresShell(); -@@ -3046,7 +3056,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 5e2844f6e65da71ca9e1dadb1a88a74ab45f485c..a8f033e17ffbc28261072d561c89914d4bd2e325 100644 ---- a/dom/base/nsGlobalWindowOuter.cpp -+++ b/dom/base/nsGlobalWindowOuter.cpp -@@ -2511,10 +2511,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)); -+ } - } - } - -@@ -2634,6 +2640,19 @@ void nsGlobalWindowOuter::DispatchDOMWindowCreated() { - } - } - -+void nsGlobalWindowOuter::JugglerDispatchDOMWindowReused() { -+ nsCOMPtr observerService = -+ mozilla::services::GetObserverService(); -+ if (observerService && mDoc) { -+ nsIPrincipal* principal = mDoc->NodePrincipal(); -+ if (!principal->IsSystemPrincipal()) { -+ observerService->NotifyObservers(static_cast(this), -+ "juggler-dom-window-reused", -+ nullptr); -+ } -+ } -+} -+ - void nsGlobalWindowOuter::ClearStatus() { SetStatusOuter(u""_ns); } - - void nsGlobalWindowOuter::SetDocShell(nsDocShell* aDocShell) { -diff --git a/dom/base/nsGlobalWindowOuter.h b/dom/base/nsGlobalWindowOuter.h -index 1fbb506b07714f9ab2a2c9aff3683aa7fec4b156..42878f8f0c6365c7e2958a3b35fce0e7db9abfff 100644 ---- a/dom/base/nsGlobalWindowOuter.h -+++ b/dom/base/nsGlobalWindowOuter.h -@@ -318,6 +318,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 7b8da8b4a5e8de02d0d2e1befc8407da88fbf890..533f3bf77e1ef78dd231ac899e3d8032938ea812 100644 ---- a/dom/base/nsINode.cpp -+++ b/dom/base/nsINode.cpp -@@ -1500,6 +1500,61 @@ void nsINode::GetBoxQuadsFromWindowOrigin(const BoxQuadOptions& aOptions, - mozilla::GetBoxQuadsFromWindowOrigin(this, aOptions, aResult, aRv); - } - -+static nsIFrame* GetFirstFrame(nsINode* aNode) { -+ if (!aNode->IsContent()) -+ return nullptr; -+ nsIFrame* frame = aNode->AsContent()->GetPrimaryFrame(FlushType::Frames); -+ if (!frame) { -+ FlattenedChildIterator iter(aNode->AsContent()); -+ for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { -+ frame = child->GetPrimaryFrame(FlushType::Frames); -+ if (frame) { -+ break; -+ } -+ } -+ } -+ return frame; -+} -+ -+void nsINode::ScrollRectIntoViewIfNeeded(int32_t x, int32_t y, -+ int32_t w, int32_t h, -+ ErrorResult& aRv) { -+ aRv = NS_ERROR_UNEXPECTED; -+ nsCOMPtr 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"); -+ } -+ nsIFrame* primaryFrame = GetFirstFrame(this); -+ if (!primaryFrame) { -+ return aRv.ThrowNotFoundError("Node does not have a layout object"); -+ } -+ aRv = NS_OK; -+ 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->ScrollFrameIntoView( -+ primaryFrame, Some(rect), -+ ScrollAxis(WhereToScroll::Center, WhenToScroll::IfNotFullyVisible), -+ ScrollAxis(WhereToScroll::Center, WhenToScroll::IfNotFullyVisible), -+ 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 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 c3d84856e1bc92caf0437be312ccdbf7a2726ba5..d81c8e7152ca79b0fbb1ebee0f6f3aa40d0f34e2 100644 ---- a/dom/base/nsINode.h -+++ b/dom/base/nsINode.h -@@ -2421,6 +2421,10 @@ class nsINode : public mozilla::dom::EventTarget { - nsTArray>& aResult, - ErrorResult& aRv); - -+ void ScrollRectIntoViewIfNeeded(int32_t x, int32_t y, -+ int32_t w, int32_t h, -+ ErrorResult& aRv); -+ - already_AddRefed ConvertQuadFromNode( - DOMQuad& aQuad, const TextOrElementOrDocument& aFrom, - const ConvertCoordinateOptions& aOptions, CallerType aCallerType, -diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp -index aed59277e27a5a90f4244dd4513f9b4feb5858c3..26750fa09bead1ffabb22482468dea5999899f18 100644 ---- a/dom/base/nsJSUtils.cpp -+++ b/dom/base/nsJSUtils.cpp -@@ -151,6 +151,11 @@ bool nsJSUtils::GetEnvironmentChainForElement(JSContext* aCx, Element* aElement, - 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 f32e21752d5013bf143eb45391ab9218debab08e..83763d2354dade2f8d2b7930ba18ae91c55133ad 100644 ---- a/dom/base/nsJSUtils.h -+++ b/dom/base/nsJSUtils.h -@@ -75,6 +75,7 @@ class nsJSUtils { - mozilla::dom::Element* aElement, - JS::EnvironmentChain& aEnvChain); - -+ 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 6d150cc3ad77f694af5aa943c60eac37ba0733c0..9e68e18601cfb3e9e9c03b4bf0057c1a3d50a9d5 100644 ---- a/dom/chrome-webidl/BrowsingContext.webidl -+++ b/dom/chrome-webidl/BrowsingContext.webidl -@@ -62,6 +62,26 @@ enum ForcedColorsOverride { - "active", - }; - -+/** -+ * CSS prefers-reduced-motion values. -+ */ -+enum PrefersReducedMotionOverride { -+ "none", -+ "reduce", -+ "no-preference", -+}; -+ -+/** -+ * CSS prefers-contrast values. -+ */ -+enum PrefersContrastOverride { -+ "none", -+ "no-preference", -+ "more", -+ "less", -+ "custom", -+}; -+ - /** - * Allowed overrides of platform/pref default behaviour for touch events. - */ -@@ -228,6 +248,12 @@ interface BrowsingContext { - // Forced-colors simulation, for DevTools - [SetterThrows] attribute ForcedColorsOverride forcedColorsOverride; - -+ // Reduced-Motion simulation, for DevTools. -+ [SetterThrows] attribute PrefersReducedMotionOverride prefersReducedMotionOverride; -+ -+ // Contrast simulation, for DevTools. -+ [SetterThrows] attribute PrefersContrastOverride prefersContrastOverride; -+ - /** - * 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/fetch/Fetch.cpp b/dom/fetch/Fetch.cpp -index 52cf33bfc863d5ef1d3ac889ddfba3023600d60a..ccb521f367b8ccc8c40d8bad78aa621ab1b074c0 100644 ---- a/dom/fetch/Fetch.cpp -+++ b/dom/fetch/Fetch.cpp -@@ -704,6 +704,12 @@ already_AddRefed FetchRequest(nsIGlobalObject* aGlobal, - ipcArgs.hasCSPEventListener() = false; - ipcArgs.isWorkerRequest() = false; - -+ /* --> Playwright: associate keep-alive fetch with the window */ -+ BrowsingContext* bc = window ? window->GetBrowsingContext() : nullptr; -+ if (bc) -+ ipcArgs.associatedBrowsingContextID() = bc->Id(); -+ /* <-- Playwright */ -+ - actor->DoFetchOp(ipcArgs); - - mozilla::glean::networking::fetch_keepalive_request_count.Get("main"_ns) -diff --git a/dom/fetch/FetchService.cpp b/dom/fetch/FetchService.cpp -index 1734429e8eeb155b742211ca58afcbeb73a8bf7c..15635a2e5c266f8085093a0d17288abe8ed54d9e 100644 ---- a/dom/fetch/FetchService.cpp -+++ b/dom/fetch/FetchService.cpp -@@ -268,6 +268,14 @@ RefPtr FetchService::FetchInstance::Fetch() { - net::ClassificationFlags({0, 0}) // TrackingFlags - ); - -+ /* --> Playwright: associate keep-alive fetch with the window */ -+ if (mArgsType == FetchArgsType::MainThreadFetch) { -+ auto& args = mArgs.as(); -+ mFetchDriver->SetAssociatedBrowsingContextID( -+ args.mAssociatedBrowsingContextID); -+ } -+ /* <-- Playwright */ -+ - if (mArgsType == FetchArgsType::WorkerFetch) { - auto& args = mArgs.as(); - mFetchDriver->SetWorkerScript(args.mWorkerScript); -diff --git a/dom/geolocation/Geolocation.cpp b/dom/geolocation/Geolocation.cpp -index 70ce9ce97c6d0ccba8b4129c55079cf9122e5b17..1c503c68c2c0949cfdaa18a76a263a81807952e1 100644 ---- a/dom/geolocation/Geolocation.cpp -+++ b/dom/geolocation/Geolocation.cpp -@@ -394,7 +394,10 @@ nsGeolocationRequest::Allow(JS::Handle aChoices) { - return NS_OK; - } - -- if (mBehavior != SystemGeolocationPermissionBehavior::NoPrompt) { -+ RefPtr gs = nsGeolocationService::GetGeolocationService( -+ mLocator->GetBrowsingContext()); -+ -+ if (mBehavior != SystemGeolocationPermissionBehavior::NoPrompt && !gs->IsOverride()) { - // Asynchronously present the system dialog or open system preferences - // (RequestGeolocationPermissionFromUser will know which to do), and wait - // for the permission to change or the request to be canceled. If the -@@ -426,8 +429,6 @@ nsGeolocationRequest::Allow(JS::Handle aChoices) { - return NS_OK; - } - -- RefPtr gs = nsGeolocationService::GetGeolocationService( -- mLocator->GetBrowsingContext()); - bool canUseCache = false; - CachedPositionAndAccuracy lastPosition = gs->GetCachedPosition(); - if (lastPosition.position) { -@@ -710,11 +711,16 @@ NS_INTERFACE_MAP_END - NS_IMPL_ADDREF(nsGeolocationService) - NS_IMPL_RELEASE(nsGeolocationService) - --nsresult nsGeolocationService::Init() { -+nsresult nsGeolocationService::Init(bool isOverride) { - if (!StaticPrefs::geo_enabled()) { - return NS_ERROR_FAILURE; - } - -+ if (isOverride) { -+ mIsOverride = true; -+ mHigherAccuracy = true; -+ } -+ - if (XRE_IsContentProcess()) { - return NS_OK; - } -@@ -793,6 +799,10 @@ nsresult nsGeolocationService::Init() { - return NS_OK; - } - -+bool nsGeolocationService::IsOverride() { -+ return mIsOverride; -+} -+ - nsGeolocationService::~nsGeolocationService() = default; - - NS_IMETHODIMP -@@ -936,6 +946,10 @@ bool nsGeolocationService::HighAccuracyRequested() { - } - - void nsGeolocationService::UpdateAccuracy(bool aForceHigh) { -+ if (mIsOverride) { -+ return; -+ } -+ - bool highRequired = aForceHigh || HighAccuracyRequested(); - - if (XRE_IsContentProcess()) { -diff --git a/dom/geolocation/Geolocation.h b/dom/geolocation/Geolocation.h -index 57814242d551774e81403b7fdc20c795deadb625..c48c1b19a8d5499784ffb7b50d5e88e40c7b2a05 100644 ---- a/dom/geolocation/Geolocation.h -+++ b/dom/geolocation/Geolocation.h -@@ -67,7 +67,7 @@ class nsGeolocationService final : public nsIGeolocationUpdate, - - nsGeolocationService() = default; - -- nsresult Init(); -+ nsresult Init(bool isOverride = false); - - // Management of the Geolocation objects - void AddLocator(mozilla::dom::Geolocation* aLocator); -@@ -92,6 +92,8 @@ class nsGeolocationService final : public nsIGeolocationUpdate, - void UpdateAccuracy(bool aForceHigh = false); - bool HighAccuracyRequested(); - -+ bool IsOverride(); -+ - private: - ~nsGeolocationService(); - -@@ -118,6 +120,8 @@ class nsGeolocationService final : public nsIGeolocationUpdate, - // Nothing() if not being started, or a boolean reflecting the requested - // accuracy. - mozilla::Maybe mStarting; -+ -+ bool mIsOverride = false; - }; - - namespace mozilla::dom { -diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp -index 5b0228d4a61dfe2b95e7a3ce016217007e8dee12..b753b0fceeec3278cb026d9137aafab5fb6ef968 100644 ---- a/dom/html/HTMLInputElement.cpp -+++ b/dom/html/HTMLInputElement.cpp -@@ -45,6 +45,7 @@ - #include "mozilla/dom/GetFilesHelper.h" - #include "mozilla/dom/HTMLDataListElement.h" - #include "mozilla/dom/HTMLOptionElement.h" -+#include "nsDocShell.h" - #include "mozilla/dom/InputType.h" - #include "mozilla/dom/MouseEvent.h" - #include "mozilla/dom/MutationEventBinding.h" -@@ -842,6 +843,13 @@ nsresult HTMLInputElement::InitFilePicker(FilePickerType aType) { - return NS_ERROR_FAILURE; - } - -+ nsCOMPtr win = doc->GetWindow(); -+ nsDocShell* docShell = win ? static_cast(win->GetDocShell()) : nullptr; -+ if (docShell && docShell->IsFileInputInterceptionEnabled()) { -+ docShell->FilePickerShown(this); -+ return NS_OK; -+ } -+ - if (IsPickerBlocked(doc)) { - return NS_OK; - } -diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl -index 64a2dad65911395ea7eb8ded3374ae6bdd31cf3c..e333c802f8a9232e58d963e05187c0a1b30948f5 100644 ---- a/dom/interfaces/base/nsIDOMWindowUtils.idl -+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl -@@ -390,6 +390,26 @@ cenum AsyncEnabledOption : 8 { - ASYNC_ENABLED = 1 - }; - -+ /** -+ * Playwright: a separate method to dispatch mouse event with a -+ * specific `jugglerEventId`. -+ */ -+ [can_run_script] -+ unsigned long jugglerSendMouseEvent(in AString aType, -+ in float aX, -+ in float aY, -+ in long aButton, -+ in long aClickCount, -+ in long aModifiers, -+ in boolean aIgnoreRootScrollFrame, -+ in float aPressure, -+ in unsigned short aInputSourceArg, -+ in boolean aIsDOMEventSynthesized, -+ in boolean aIsWidgetEventSynthesized, -+ in long aButtons, -+ in unsigned long aIdentifier, -+ in boolean aDisablePointerEvent); -+ - /** Synthesize a touch event. The event types supported are: - * touchstart, touchend, touchmove, and touchcancel - * -diff --git a/dom/ipc/BrowserChild.cpp b/dom/ipc/BrowserChild.cpp -index 780550d573644bcfe4a9bc03243aa4559a62d979..9ed69194ef329aad1e8a3e2c06041a443e4bc6ba 100644 ---- a/dom/ipc/BrowserChild.cpp -+++ b/dom/ipc/BrowserChild.cpp -@@ -1744,6 +1744,21 @@ void BrowserChild::HandleRealMouseButtonEvent(const WidgetMouseEvent& aEvent, - if (postLayerization) { - postLayerization->Register(); - } -+ -+ // Playwright: notify content that mouse event has been received and handled. -+ nsCOMPtr observerService = -+ mozilla::services::GetObserverService(); -+ if (observerService && aEvent.mJugglerEventId) { -+ if (aEvent.mMessage == eMouseUp) { -+ observerService->NotifyObservers(nullptr, "juggler-mouse-event-hit-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("mouseup %" PRIu32, aEvent.mJugglerEventId)).get()); -+ } else if (aEvent.mMessage == eMouseDown) { -+ observerService->NotifyObservers(nullptr, "juggler-mouse-event-hit-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("mousedown %" PRIu32, aEvent.mJugglerEventId)).get()); -+ } else if (aEvent.mMessage == eMouseMove) { -+ observerService->NotifyObservers(nullptr, "juggler-mouse-event-hit-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("mousemove %" PRIu32, aEvent.mJugglerEventId)).get()); -+ } else if (aEvent.mMessage == eContextMenu) { -+ observerService->NotifyObservers(nullptr, "juggler-mouse-event-hit-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("contextmenu %" PRIu32, aEvent.mJugglerEventId)).get()); -+ } -+ } - } - - mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealMouseButtonEvent( -diff --git a/dom/ipc/CoalescedMouseData.cpp b/dom/ipc/CoalescedMouseData.cpp -index 83aa0d08839f6fa5a150e5791b9b717e5aa9e751..fc1e1140ac7c6cda8cf116027c2fc2898dbe9d4b 100644 ---- a/dom/ipc/CoalescedMouseData.cpp -+++ b/dom/ipc/CoalescedMouseData.cpp -@@ -72,6 +72,9 @@ bool CoalescedMouseData::CanCoalesce(const WidgetMouseEvent& aEvent, - mCoalescedInputEvent->pointerId != aEvent.pointerId || - mCoalescedInputEvent->mButton != aEvent.mButton || - mCoalescedInputEvent->mButtons != aEvent.mButtons || mGuid != aGuid || -+ // `mJugglerEventId` is 0 for non-juggler events and a unique number for -+ // juggler-emitted events. -+ mCoalescedInputEvent->mJugglerEventId != aEvent.mJugglerEventId || - mInputBlockId != aInputBlockId) { - return false; - } -diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.cc b/dom/media/systemservices/video_engine/desktop_capture_impl.cc -index db777994b583efc2a3533e7d4534fff894c733bb..eb317c19b2422bd983d5e132c9ee4dac31687428 100644 ---- a/dom/media/systemservices/video_engine/desktop_capture_impl.cc -+++ b/dom/media/systemservices/video_engine/desktop_capture_impl.cc -@@ -53,9 +53,10 @@ namespace webrtc { - - DesktopCaptureImpl* DesktopCaptureImpl::Create(const int32_t aModuleId, - const char* aUniqueId, -- const CaptureDeviceType aType) { -+ const CaptureDeviceType aType, -+ bool aCaptureCursor) { - return new rtc::RefCountedObject(aModuleId, aUniqueId, -- aType); -+ aType, aCaptureCursor); - } - - static DesktopCaptureOptions CreateDesktopCaptureOptions() { -@@ -156,8 +157,10 @@ static std::unique_ptr CreateTabCapturer( - - static std::unique_ptr CreateDesktopCapturerAndThread( - CaptureDeviceType aDeviceType, DesktopCapturer::SourceId aSourceId, -- nsIThread** aOutThread) { -+ nsIThread** aOutThread, bool aCaptureCursor) { - DesktopCaptureOptions options = CreateDesktopCaptureOptions(); -+ if (aCaptureCursor) -+ options.set_prefer_cursor_embedded(aCaptureCursor); - auto ensureThread = [&]() { - if (*aOutThread) { - return *aOutThread; -@@ -254,7 +257,8 @@ static std::unique_ptr CreateDesktopCapturerAndThread( - } - - DesktopCaptureImpl::DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, -- const CaptureDeviceType aType) -+ const CaptureDeviceType aType, -+ bool aCaptureCursor) - : mModuleId(aId), - mTrackingId(mozilla::TrackingId(CaptureEngineToTrackingSourceStr([&] { - switch (aType) { -@@ -271,6 +275,7 @@ DesktopCaptureImpl::DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, - aId)), - mDeviceUniqueId(aUniqueId), - mDeviceType(aType), -+ capture_cursor_(aCaptureCursor), - mControlThread(mozilla::GetCurrentSerialEventTarget()), - mNextFrameMinimumTime(Timestamp::Zero()), - mCallbacks("DesktopCaptureImpl::mCallbacks") {} -@@ -295,6 +300,19 @@ void DesktopCaptureImpl::DeRegisterCaptureDataCallback( - } - } - -+void DesktopCaptureImpl::RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) { -+ rtc::CritScope lock(&mApiCs); -+ _rawFrameCallbacks.insert(rawFrameCallback); -+} -+ -+void DesktopCaptureImpl::DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) { -+ rtc::CritScope lock(&mApiCs); -+ auto it = _rawFrameCallbacks.find(rawFrameCallback); -+ if (it != _rawFrameCallbacks.end()) { -+ _rawFrameCallbacks.erase(it); -+ } -+} -+ - int32_t DesktopCaptureImpl::StopCaptureIfAllClientsClose() { - { - auto callbacks = mCallbacks.Lock(); -@@ -350,7 +368,7 @@ int32_t DesktopCaptureImpl::StartCapture( - return -1; - } - std::unique_ptr capturer = CreateDesktopCapturerAndThread( -- mDeviceType, sourceId, getter_AddRefs(mCaptureThread)); -+ mDeviceType, sourceId, getter_AddRefs(mCaptureThread), capture_cursor_); - - MOZ_ASSERT(!capturer == !mCaptureThread); - if (!capturer) { -@@ -458,6 +476,15 @@ void DesktopCaptureImpl::OnCaptureResult(DesktopCapturer::Result aResult, - frameInfo.height = aFrame->size().height(); - frameInfo.videoType = VideoType::kARGB; - -+ size_t videoFrameStride = -+ frameInfo.width * DesktopFrame::kBytesPerPixel; -+ { -+ rtc::CritScope cs(&mApiCs); -+ for (auto rawFrameCallback : _rawFrameCallbacks) { -+ rawFrameCallback->OnRawFrame(videoFrame, videoFrameStride, frameInfo); -+ } -+ } -+ - size_t videoFrameLength = - frameInfo.width * frameInfo.height * DesktopFrame::kBytesPerPixel; - -diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.h b/dom/media/systemservices/video_engine/desktop_capture_impl.h -index a76b7de569db1cb42728a5514fb80e5c46e0344e..3d61ad8d3aa4a7eaf96957dcd680e1e1ee8abdf4 100644 ---- a/dom/media/systemservices/video_engine/desktop_capture_impl.h -+++ b/dom/media/systemservices/video_engine/desktop_capture_impl.h -@@ -26,6 +26,7 @@ - #include "api/video/video_sink_interface.h" - #include "modules/desktop_capture/desktop_capturer.h" - #include "modules/video_capture/video_capture.h" -+#include "rtc_base/deprecated/recursive_critical_section.h" - #include "mozilla/DataMutex.h" - #include "mozilla/Maybe.h" - #include "mozilla/TimeStamp.h" -@@ -42,17 +43,44 @@ 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; -+ int32_t StartCaptureCounted(const VideoCaptureCapability& aCapability) { -+ ++capture_counter_; -+ return capture_counter_ == 1 ? StartCapture(aCapability) : 0; -+ } -+ -+ int32_t StopCaptureCounted() { -+ --capture_counter_; -+ return capture_counter_ == 0 ? StopCapture() : 0; -+ } -+ -+ private: -+ int32_t capture_counter_ = 0; -+}; -+ - // Reuses the video engine pipeline for screen sharing. - // 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 DesktopCaptureImpl* Create( - const int32_t aModuleId, const char* aUniqueId, -- const mozilla::camera::CaptureDeviceType aType); -+ const mozilla::camera::CaptureDeviceType aType, bool aCaptureCursor = true); - - [[nodiscard]] static std::shared_ptr - CreateDeviceInfo(const int32_t aId, -@@ -66,6 +94,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - void DeRegisterCaptureDataCallback( - rtc::VideoSinkInterface* aCallback) override; - int32_t StopCaptureIfAllClientsClose() override; -+ void RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) override; -+ void DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) override; - - int32_t SetCaptureRotation(VideoRotation aRotation) override; - bool SetApplyRotation(bool aEnable) override; -@@ -89,7 +119,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - - protected: - DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, -- const mozilla::camera::CaptureDeviceType aType); -+ const mozilla::camera::CaptureDeviceType aType, -+ bool aCaptureCusor); - virtual ~DesktopCaptureImpl(); - - private: -@@ -98,6 +129,9 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - void InitOnThread(std::unique_ptr aCapturer, int aFramerate); - void UpdateOnThread(int aFramerate); - void ShutdownOnThread(); -+ -+ rtc::RecursiveCriticalSection mApiCs; -+ std::set _rawFrameCallbacks; - // DesktopCapturer::Callback interface. - void OnCaptureResult(DesktopCapturer::Result aResult, - std::unique_ptr aFrame) override; -@@ -105,6 +139,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - // Notifies all mCallbacks of OnFrame(). mCaptureThread only. - void NotifyOnFrame(const VideoFrame& aFrame); - -+ bool capture_cursor_ = true; -+ - // Control thread on which the public API is called. - const nsCOMPtr mControlThread; - // Set in StartCapture. -diff --git a/dom/script/ScriptSettings.cpp b/dom/script/ScriptSettings.cpp -index d5964b27e9c99af76fe3f4076322592a9370c2d0..da217e2c1fbd9ca02e50ff74dde028189a216a6d 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 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 8b68f22ae64d19165bf4b3c58aea8f5c237ba351..c3733bfa4ed550c98ab5f72c406cd6d01a621aca 100644 ---- a/dom/security/nsCSPUtils.cpp -+++ b/dom/security/nsCSPUtils.cpp -@@ -24,6 +24,7 @@ - #include "nsSandboxFlags.h" - #include "nsServiceManagerUtils.h" - #include "nsWhitespaceTokenizer.h" -+#include "nsDocShell.h" - - #include "mozilla/Assertions.h" - #include "mozilla/Components.h" -@@ -136,6 +137,11 @@ void CSP_ApplyMetaCSPToDoc(mozilla::dom::Document& aDoc, - (void)SetIsCaptivePortalTab(true); - } - -+ if (aDoc.GetDocShell() && -+ nsDocShell::Cast(aDoc.GetDocShell())->IsBypassCSPEnabled()) { -+ return; -+ } -+ - nsAutoString policyStr( - nsContentUtils::TrimWhitespace( - aPolicyStr)); -diff --git a/dom/webidl/GeometryUtils.webidl b/dom/webidl/GeometryUtils.webidl -index aee376e971ae01ac1e512c3920b115bfaf06afa8..1701311534bf77e6cd9bafc0e3a283610476aa8f 100644 ---- a/dom/webidl/GeometryUtils.webidl -+++ b/dom/webidl/GeometryUtils.webidl -@@ -17,6 +17,8 @@ dictionary GeometryUtilsOptions { - boolean createFramesForSuppressedWhitespace = true; - [ChromeOnly] - boolean flush = true; -+ [ChromeOnly] -+ boolean recurseWhenNoFrame = false; - }; - - dictionary BoxQuadOptions : GeometryUtilsOptions { -@@ -35,6 +37,9 @@ interface mixin GeometryUtils { - [Throws, Func="nsINode::HasBoxQuadsSupport", NeedsCallerType] - sequence getBoxQuads(optional BoxQuadOptions options = {}); - -+ [ChromeOnly, Throws, Func="nsINode::HasBoxQuadsSupport"] -+ undefined 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 83cef5b52b8f5c3168cd1d59266b4149425647fd..a80e89ec26a7e049c8ed84687ba2cd49597be05f 100644 ---- a/dom/workers/RuntimeService.cpp -+++ b/dom/workers/RuntimeService.cpp -@@ -1082,7 +1082,7 @@ void PrefLanguagesChanged(const char* /* aPrefName */, void* /* aClosure */) { - AssertIsOnMainThread(); - - nsTArray languages; -- Navigator::GetAcceptLanguages(languages); -+ Navigator::GetAcceptLanguages(nullptr, languages); - - RuntimeService* runtime = RuntimeService::GetService(); - if (runtime) { -@@ -1272,8 +1272,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; - } - -@@ -1901,6 +1900,13 @@ void RuntimeService::PropagateStorageAccessPermissionGranted( - } - } - -+void RuntimeService::ResetDefaultLocaleInAllWorkers() { -+ AssertIsOnMainThread(); -+ BroadcastAllWorkers([](auto& worker) { -+ worker.ResetDefaultLocale(); -+ }); -+} -+ - template - void RuntimeService::BroadcastAllWorkers(const Func& aFunc) { - AssertIsOnMainThread(); -@@ -2451,6 +2457,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 6d75c6708bcb999dc1dc3b0172afa14136110bc6..809d0ef80ffe793beff5d3c11bf6bf7912385e99 100644 ---- a/dom/workers/RuntimeService.h -+++ b/dom/workers/RuntimeService.h -@@ -115,6 +115,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 af8d36c0d72683712a3fee22661f8c3279e103db..6b3a967c9acde2c81ab38148d4b1ac120a4717a2 100644 ---- a/dom/workers/WorkerCommon.h -+++ b/dom/workers/WorkerCommon.h -@@ -50,6 +50,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 06083bb8f9546be06fa0b5c78d4e005a1617e51b..1753896265c1701ad50425c565f8d44392d0afb9 100644 ---- a/dom/workers/WorkerPrivate.cpp -+++ b/dom/workers/WorkerPrivate.cpp -@@ -738,6 +738,18 @@ class UpdateContextOptionsRunnable final : public WorkerControlRunnable { - } - }; - -+class ResetDefaultLocaleRunnable final : public WorkerControlRunnable { -+ public: -+ explicit ResetDefaultLocaleRunnable(WorkerPrivate* aWorkerPrivate) -+ : WorkerControlRunnable("ResetDefaultLocaleRunnable") {} -+ -+ virtual bool WorkerRun(JSContext* aCx, -+ WorkerPrivate* aWorkerPrivate) override { -+ aWorkerPrivate->ResetDefaultLocaleInternal(aCx); -+ return true; -+ } -+}; -+ - class UpdateLanguagesRunnable final : public WorkerThreadRunnable { - nsTArray mLanguages; - -@@ -2334,6 +2346,16 @@ void WorkerPrivate::UpdateContextOptions( - } - } - -+void WorkerPrivate::ResetDefaultLocale() { -+ AssertIsOnParentThread(); -+ -+ RefPtr runnable = -+ new ResetDefaultLocaleRunnable(this); -+ if (!runnable->Dispatch(this)) { -+ NS_WARNING("Failed to reset default locale in worker!"); -+ } -+} -+ - void WorkerPrivate::UpdateLanguages(const nsTArray& aLanguages) { - AssertIsOnParentThread(); - -@@ -5996,6 +6018,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& aLanguages) { - WorkerGlobalScope* globalScope = GlobalScope(); -diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h -index 15c819c84fa934e25517ac8f55fd39ef8ba46986..fe01e09abcf2315abe41a3d19418c4e0f8c7df2b 100644 ---- a/dom/workers/WorkerPrivate.h -+++ b/dom/workers/WorkerPrivate.h -@@ -457,6 +457,8 @@ class WorkerPrivate final - void UpdateContextOptionsInternal(JSContext* aCx, - const JS::ContextOptions& aContextOptions); - -+ void ResetDefaultLocaleInternal(JSContext* aCx); -+ - void UpdateLanguagesInternal(const nsTArray& aLanguages); - - void UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key, -@@ -1103,6 +1105,8 @@ class WorkerPrivate final - - void UpdateContextOptions(const JS::ContextOptions& aContextOptions); - -+ void ResetDefaultLocale(); -+ - void UpdateLanguages(const nsTArray& aLanguages); - - void UpdateJSWorkerMemoryParameter(JSGCParamKey key, Maybe value); -diff --git a/intl/components/src/TimeZone.cpp b/intl/components/src/TimeZone.cpp -index 7a069ef0c59895cf1f8dc35d612f1494c9c9f1ef..5b09dfdcc5323def65c35b0696141b44eef9dcda 100644 ---- a/intl/components/src/TimeZone.cpp -+++ b/intl/components/src/TimeZone.cpp -@@ -16,6 +16,7 @@ - - namespace mozilla::intl { - -+ - /* static */ - Result, ICUError> TimeZone::TryCreate( - Maybe> aTimeZoneOverride) { -@@ -318,6 +319,13 @@ static ICUResult SetDefaultTimeZone(TimeZoneIdentifierVector& timeZone) { - } - #endif - -+bool TimeZone::IsValidTimeZoneId(const char* timeZoneId) { -+ // Validate timezone id. -+ mozilla::UniquePtr timeZone(icu::TimeZone::createTimeZone( -+ icu::UnicodeString(timeZoneId, -1, US_INV))); -+ return timeZone && *timeZone != icu::TimeZone::getUnknown(); -+} -+ - Result TimeZone::SetDefaultTimeZone( - Span aTimeZone) { - #if MOZ_INTL_USE_ICU_CPP_TIMEZONE -diff --git a/intl/components/src/TimeZone.h b/intl/components/src/TimeZone.h -index 89770839ae108b5f3462a7f20684fdb72c4ab2fb..a7e40d6b7c33c234b41e586eac573ba4ce3a7d18 100644 ---- a/intl/components/src/TimeZone.h -+++ b/intl/components/src/TimeZone.h -@@ -191,6 +191,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 523e84c8c93f4221701f90f2e8ee146ec8e1adbd..98d5b1176e5378431b859a2dbd4d4e778d236e78 100644 ---- a/js/public/Date.h -+++ b/js/public/Date.h -@@ -55,6 +55,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 2d177b5aade6d158e9ae62d317d5155b72cdcf84..28af5d41eb06d4b33cd5f86484dc29c923308835 100644 ---- a/js/src/debugger/Object.cpp -+++ b/js/src/debugger/Object.cpp -@@ -2516,7 +2516,11 @@ Maybe 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 cc366b4cc411ed8de972811237563edb376355e3..adf727cf80fadebce3be9301752dc1d0b9ee35b9 100644 ---- a/js/src/vm/DateTime.cpp -+++ b/js/src/vm/DateTime.cpp -@@ -188,6 +188,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); - -@@ -556,10 +561,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) { -@@ -773,6 +792,15 @@ static bool ReadTimeZoneLink(std::string_view tz, - - void js::DateTimeInfo::internalResyncICUDefaultTimeZone() { - #if JS_HAS_INTL_API -+ if (!timeZoneOverride_.empty()) { -+ mozilla::Span 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; -+ } -+ - // In the future we should not be setting a default ICU time zone at all, - // instead all accesses should go through the appropriate DateTimeInfo - // instance depending on the resist fingerprinting status. For now we return -@@ -784,7 +812,6 @@ void js::DateTimeInfo::internalResyncICUDefaultTimeZone() { - - if (const char* tzenv = std::getenv("TZ")) { - std::string_view tz(tzenv); -- - mozilla::Span tzid; - - # if defined(XP_WIN) -diff --git a/js/src/vm/DateTime.h b/js/src/vm/DateTime.h -index 7be5b49afdce8e761af05dfbd48f3cb22e9ce318..3899c7988959f11bbadd0c005462acb979823fd1 100644 ---- a/js/src/vm/DateTime.h -+++ b/js/src/vm/DateTime.h -@@ -75,6 +75,8 @@ using TimeZoneIdentifierVector = - SystemAllocPolicy>; - #endif - -+extern void SetTimeZoneOverrideInternal(std::string timeZone); -+ - /** - * Stores date/time information, particularly concerning the current local - * time zone, and implements a small cache for daylight saving time offset -@@ -258,6 +260,7 @@ class DateTimeInfo { - private: - // The method below should only be called via js::ResetTimeZoneInternal(). - friend void js::ResetTimeZoneInternal(ResetTimeZoneMode); -+ friend void js::SetTimeZoneOverrideInternal(std::string); - - static void resetTimeZone(ResetTimeZoneMode mode) { - { -@@ -362,6 +365,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 -@@ -377,6 +382,8 @@ class DateTimeInfo { - - void internalResetTimeZone(ResetTimeZoneMode mode); - -+ void internalSetTimeZoneOverride(std::string timeZone); -+ - void updateTimeZone(); - - void internalResyncICUDefaultTimeZone(); -diff --git a/layout/base/GeometryUtils.cpp b/layout/base/GeometryUtils.cpp -index 67673c5c306e7237613b0560c7b3f888bd6ad1b8..fe4a278dad4b1747b41b5a824978636a70a9dea8 100644 ---- a/layout/base/GeometryUtils.cpp -+++ b/layout/base/GeometryUtils.cpp -@@ -23,6 +23,7 @@ - #include "nsContentUtils.h" - #include "nsIFrame.h" - #include "nsLayoutUtils.h" -+#include "ChildIterator.h" - - using namespace mozilla; - using namespace mozilla::dom; -@@ -265,10 +266,27 @@ static bool CheckFramesInSameTopLevelBrowsingContext(nsIFrame* aFrame1, - return false; - } - -+static nsIFrame* GetFrameForNodeRecursive(nsINode* aNode, -+ const GeometryUtilsOptions& aOptions, -+ bool aRecurseWhenNoFrame) { -+ nsIFrame* frame = GetFrameForNode(aNode, aOptions); -+ if (!frame && aRecurseWhenNoFrame && aNode->IsContent()) { -+ dom::FlattenedChildIterator iter(aNode->AsContent()); -+ for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { -+ frame = GetFrameForNodeRecursive(child, aOptions, aRecurseWhenNoFrame); -+ if (frame) { -+ break; -+ } -+ } -+ } -+ return frame; -+} -+ - void GetBoxQuads(nsINode* aNode, const dom::BoxQuadOptions& aOptions, - nsTArray>& aResult, CallerType aCallerType, - ErrorResult& aRv) { -- nsIFrame* frame = GetFrameForNode(aNode, aOptions); -+ nsIFrame* frame = -+ GetFrameForNodeRecursive(aNode, aOptions, aOptions.mRecurseWhenNoFrame); - if (!frame) { - // No boxes to return - (void)SetIsCaptivePortalTab(true); -@@ -281,7 +299,8 @@ void GetBoxQuads(nsINode* aNode, const dom::BoxQuadOptions& aOptions, - // EnsureFrameForTextNode call. We need to get the first frame again - // when that happens and re-check it. - if (!weakFrame.IsAlive()) { -- frame = GetFrameForNode(aNode, aOptions); -+ frame = -+ GetFrameForNodeRecursive(aNode, aOptions, aOptions.mRecurseWhenNoFrame); - if (!frame) { - // No boxes to return - return; -diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp -index 26119628ab4839858733ce39c6c9ef2970092b49..a9c4dbc4936755fd25b8528511e9a4c62695de89 100644 ---- a/layout/base/PresShell.cpp -+++ b/layout/base/PresShell.cpp -@@ -12150,7 +12150,9 @@ bool PresShell::ComputeActiveness() const { - if (!browserChild->IsVisible()) { - MOZ_LOG(gLog, LogLevel::Debug, - (" > BrowserChild %p is not visible", browserChild)); -- return false; -+ bool isActive; -+ root->GetDocShell()->GetForceActiveState(&isActive); -+ return isActive; - } - - // If the browser is visible but just due to be preserving layers -diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp -index ee4e4b7e04f0f949b0afc7e8097711fcefe8b3c3..3af1d380d514b70392d1daaa4bc623afd7a570e6 100644 ---- a/layout/base/nsLayoutUtils.cpp -+++ b/layout/base/nsLayoutUtils.cpp -@@ -707,6 +707,10 @@ bool nsLayoutUtils::AllowZoomingForDocument( - !aDocument->GetPresShell()->AsyncPanZoomEnabled()) { - return false; - } -+ -+ /* Playwright: disable zooming as we don't support meta viewport tag */ -+ if (1 == 1) return false; -+ - // True if we allow zooming for all documents on this platform, or if we are - // in RDM. - BrowsingContext* bc = aDocument->GetBrowsingContext(); -@@ -9772,6 +9776,9 @@ void nsLayoutUtils::ComputeSystemFont(nsFont* aSystemFont, - - /* static */ - bool nsLayoutUtils::ShouldHandleMetaViewport(const Document* aDocument) { -+ /* Playwright: disable meta viewport handling since we don't require one */ -+ if (1 == 1) return false; -+ - BrowsingContext* bc = aDocument->GetBrowsingContext(); - return StaticPrefs::dom_meta_viewport_enabled() || (bc && bc->InRDMPane()); - } -diff --git a/layout/style/GeckoBindings.h b/layout/style/GeckoBindings.h -index 9527443c79077e0a728d78c3184ab7319f1c9efd..4e193ed114b4f70fb72bea928709fc7723f35b88 100644 ---- a/layout/style/GeckoBindings.h -+++ b/layout/style/GeckoBindings.h -@@ -591,6 +592,7 @@ float Gecko_MediaFeatures_GetResolution(const mozilla::dom::Document*); - bool Gecko_MediaFeatures_PrefersReducedMotion(const mozilla::dom::Document*); - bool Gecko_MediaFeatures_PrefersReducedTransparency( - 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 21bcc8e890a0d3f3e86b5ea6eed79d017dd2fb76..eefc7d5c934f03b4a9213dafcbb65dd32b695622 100644 ---- a/layout/style/nsMediaFeatures.cpp -+++ b/layout/style/nsMediaFeatures.cpp -@@ -268,11 +268,7 @@ bool Gecko_MediaFeatures_MatchesPlatform(StylePlatform aPlatform) { - } - - bool Gecko_MediaFeatures_PrefersReducedMotion(const Document* aDocument) { -- if (aDocument->ShouldResistFingerprinting( -- RFPTarget::CSSPrefersReducedMotion)) { -- return false; -- } -- return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1; -+ return aDocument->PrefersReducedMotion(); - } - - bool Gecko_MediaFeatures_PrefersReducedTransparency(const Document* aDocument) { -@@ -297,6 +293,20 @@ StylePrefersColorScheme Gecko_MediaFeatures_PrefersColorScheme( - // as a signal. - StylePrefersContrast Gecko_MediaFeatures_PrefersContrast( - const Document* aDocument) { -+ if (auto* bc = aDocument->GetBrowsingContext()) { -+ switch (bc->Top()->PrefersContrastOverride()) { -+ case dom::PrefersContrastOverride::No_preference: -+ return StylePrefersContrast::NoPreference; -+ case dom::PrefersContrastOverride::Less: -+ return StylePrefersContrast::Less; -+ case dom::PrefersContrastOverride::More: -+ return StylePrefersContrast::More; -+ case dom::PrefersContrastOverride::Custom: -+ return StylePrefersContrast::Custom; -+ } -+ } -+ -+ - if (aDocument->ShouldResistFingerprinting(RFPTarget::CSSPrefersContrast)) { - return StylePrefersContrast::NoPreference; - } -diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp -index e5cf36273d5790de2c80acb42a6ee181bdb66f08..0523a37fc19b470e3817ae61c912a3dc54fc57a6 100644 ---- a/netwerk/base/LoadInfo.cpp -+++ b/netwerk/base/LoadInfo.cpp -@@ -801,7 +801,8 @@ LoadInfo::LoadInfo(const LoadInfo& rhs) - rhs.mHasInjectedCookieForCookieBannerHandling), - mSchemelessInput(rhs.mSchemelessInput), - mHttpsUpgradeTelemetry(rhs.mHttpsUpgradeTelemetry), -- mIsNewWindowTarget(rhs.mIsNewWindowTarget) { -+ mIsNewWindowTarget(rhs.mIsNewWindowTarget), -+ mJugglerLoadIdentifier(rhs.mJugglerLoadIdentifier) { - } - - LoadInfo::LoadInfo( -@@ -2778,4 +2779,16 @@ void LoadInfo::UpdateParentAddressSpaceInfo() { - } - } - -+NS_IMETHODIMP -+LoadInfo::GetJugglerLoadIdentifier(uint64_t* aResult) { -+ *aResult = mJugglerLoadIdentifier; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+LoadInfo::SetJugglerLoadIdentifier(uint64_t aID) { -+ mJugglerLoadIdentifier = aID; -+ return NS_OK; -+} -+ - } // namespace mozilla::net -diff --git a/netwerk/base/LoadInfo.h b/netwerk/base/LoadInfo.h -index 6547d451f3a764c8860dd0c19b5b490caecbf0af..feccce92e3769b8e9a3a4926cca9b85fccda86a5 100644 ---- a/netwerk/base/LoadInfo.h -+++ b/netwerk/base/LoadInfo.h -@@ -455,6 +455,8 @@ class LoadInfo final : public nsILoadInfo { - - bool mIsNewWindowTarget = false; - bool mSkipHTTPSUpgrade = false; -+ -+ uint64_t mJugglerLoadIdentifier = 0; - }; - // This is exposed solely for testing purposes and should not be used outside of - // LoadInfo -diff --git a/netwerk/base/TRRLoadInfo.cpp b/netwerk/base/TRRLoadInfo.cpp -index 551d89315243f4b515aa29d3a67eb23050ea9f0a..ac3a1ca6d846826c5d704d1b4abdaee55b834b0d 100644 ---- a/netwerk/base/TRRLoadInfo.cpp -+++ b/netwerk/base/TRRLoadInfo.cpp -@@ -1010,5 +1010,15 @@ TRRLoadInfo::GetFetchDestination(nsACString& aDestination) { - return NS_ERROR_NOT_IMPLEMENTED; - } - -+NS_IMETHODIMP -+TRRLoadInfo::GetJugglerLoadIdentifier(uint64_t* aResult) { -+ return NS_ERROR_NOT_IMPLEMENTED; -+} -+ -+NS_IMETHODIMP -+TRRLoadInfo::SetJugglerLoadIdentifier(uint64_t aResult) { -+ return NS_ERROR_NOT_IMPLEMENTED; -+} -+ - } // namespace net - } // namespace mozilla -diff --git a/netwerk/base/nsILoadInfo.idl b/netwerk/base/nsILoadInfo.idl -index f1b54736d9ee006292bf4c9cd0b3490d5ec8da66..257fda17a10f702cee39fb42ad69e0cd86ca95d1 100644 ---- a/netwerk/base/nsILoadInfo.idl -+++ b/netwerk/base/nsILoadInfo.idl -@@ -1686,4 +1686,6 @@ interface nsILoadInfo : nsISupports - return static_cast(userNavigationInvolvement); - } - %} -+ -+ [infallible] attribute unsigned long long jugglerLoadIdentifier; - }; -diff --git a/netwerk/base/nsINetworkInterceptController.idl b/netwerk/base/nsINetworkInterceptController.idl -index 7f91d2df6f8bb4020c75c132dc8f6bf26625fa1e..aaa5541a17039d6b13ad83ab176fdaaf79edb2a0 100644 ---- a/netwerk/base/nsINetworkInterceptController.idl -+++ b/netwerk/base/nsINetworkInterceptController.idl -@@ -60,6 +60,16 @@ interface nsIInterceptedChannel : nsISupports - */ - void resetInterception(in boolean bypass); - -+ // ----- Playwright begin ----- -+ -+ // Same as resetInterception, but updates the URI. -+ void resetInterceptionWithURI(in nsIURI aURI); -+ -+ // After resetInterception is called, this request will be intercepted again. -+ void interceptAfterServiceWorkerResets(); -+ -+ // ----- Playwright end ------- -+ - /** - * Set the status and reason for the forthcoming synthesized response. - * Multiple calls overwrite existing values. -diff --git a/netwerk/ipc/DocumentLoadListener.cpp b/netwerk/ipc/DocumentLoadListener.cpp -index 1471432c1f1a47be5073ed01b746f1f13d3a0b47..585f81762e2bf51681d11c06c9459063121c34e9 100644 ---- a/netwerk/ipc/DocumentLoadListener.cpp -+++ b/netwerk/ipc/DocumentLoadListener.cpp -@@ -185,6 +185,7 @@ static auto CreateDocumentLoadInfo(CanonicalBrowsingContext* aBrowsingContext, - loadInfo->SetTextDirectiveUserActivation( - aLoadState->GetTextDirectiveUserActivation()); - loadInfo->SetIsMetaRefresh(aLoadState->IsMetaRefresh()); -+ loadInfo->SetJugglerLoadIdentifier(aLoadState->GetLoadIdentifier()); - - return loadInfo.forget(); - } -diff --git a/netwerk/protocol/http/InterceptedHttpChannel.cpp b/netwerk/protocol/http/InterceptedHttpChannel.cpp -index fbf4bdf1e24d1102df113984be6c8dc3a7d0d810..cf1978009d74221ae804b998e223904fa943a91f 100644 ---- a/netwerk/protocol/http/InterceptedHttpChannel.cpp -+++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp -@@ -728,10 +728,33 @@ NS_IMPL_ISUPPORTS(ResetInterceptionHeaderVisitor, nsIHttpHeaderVisitor) - - } // anonymous namespace - -+NS_IMETHODIMP -+InterceptedHttpChannel::InterceptAfterServiceWorkerResets() { -+ mInterceptAfterServiceWorkerResets = true; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+InterceptedHttpChannel::ResetInterceptionWithURI(nsIURI* aURI) { -+ if (aURI) { -+ mURI = aURI; -+ } -+ return ResetInterception(true); -+} -+ - NS_IMETHODIMP - InterceptedHttpChannel::ResetInterception(bool aBypass) { - INTERCEPTED_LOG(("InterceptedHttpChannel::ResetInterception [%p] bypass: %s", - this, aBypass ? "true" : "false")); -+ if (mInterceptAfterServiceWorkerResets) { -+ mInterceptAfterServiceWorkerResets = false; -+ nsCOMPtr controller; -+ GetCallback(controller); -+ if (!controller) -+ return NS_ERROR_DOM_INVALID_STATE_ERR; -+ return controller->ChannelIntercepted(this); -+ } -+ - if (mCanceled) { - return mStatus; - } -@@ -1146,11 +1169,18 @@ InterceptedHttpChannel::OnStartRequest(nsIRequest* aRequest) { - GetCallback(mProgressSink); - } - -+ // Playwright: main requests in firefox do not have loading principal. -+ // As they are intercepted by Playwright, they don't have -+ // serviceWorkerTainting as well. -+ // Thus these asserts are wrong for Playwright world. -+ // Note: these checks were added in https://github.com/mozilla-firefox/firefox/commit/bb16ca6496682c3b0ddd452d0dd4c1dd46ff71f8 -+ /* - MOZ_ASSERT_IF(!mLoadInfo->GetServiceWorkerTaintingSynthesized(), - mLoadInfo->GetLoadingPrincipal()); - // No need to do ORB checks if these conditions hold. - MOZ_DIAGNOSTIC_ASSERT(mLoadInfo->GetServiceWorkerTaintingSynthesized() || - mLoadInfo->GetLoadingPrincipal()->IsSystemPrincipal()); -+ */ - - if (mPump && mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS) { - mPump->PeekStream(CallTypeSniffers, static_cast(this)); -diff --git a/netwerk/protocol/http/InterceptedHttpChannel.h b/netwerk/protocol/http/InterceptedHttpChannel.h -index 704404c9f094640ad63b685d64bd5a396e733e4b..92bdc21b4d6a015cc2f2bb22781ec6750c7789ec 100644 ---- a/netwerk/protocol/http/InterceptedHttpChannel.h -+++ b/netwerk/protocol/http/InterceptedHttpChannel.h -@@ -90,6 +90,11 @@ class InterceptedHttpChannel final - Atomic mCallingStatusAndProgress; - bool mInterceptionReset{false}; - -+ // ----- Playwright begin ----- -+ // After resetInterception is called, this request will call into interceptors again. -+ bool mInterceptAfterServiceWorkerResets{false}; -+ // ----- Playwright end ------- -+ - /** - * InterceptionTimeStamps is used to record the time stamps of the - * interception. -diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp -index 1051d1e91c1ebf036f2e5db82a37636dd7cda4c3..3ef53c09442e24fb50308740950aa6d354703b7d 100644 ---- a/netwerk/protocol/http/nsHttpChannel.cpp -+++ b/netwerk/protocol/http/nsHttpChannel.cpp -@@ -685,11 +685,9 @@ nsresult nsHttpChannel::OnBeforeConnect() { - // SecurityInfo.sys.mjs - mLoadInfo->SetHstsStatus(isSecureURI); - -- RefPtr bc; -- mLoadInfo->GetBrowsingContext(getter_AddRefs(bc)); - // If bypassing the cache and we're forced offline - // we can just return the error here. -- if (bc && bc->Top()->GetForceOffline() && -+ if (IsForcedOffline() && - BYPASS_LOCAL_CACHE(mLoadFlags, LoadPreferCacheLoadOverBypass())) { - return NS_ERROR_OFFLINE; - } -@@ -802,9 +800,7 @@ nsresult nsHttpChannel::MaybeUseHTTPSRRForUpgrade(bool aShouldUpgrade, - return aStatus; - } - -- RefPtr bc; -- mLoadInfo->GetBrowsingContext(getter_AddRefs(bc)); -- bool forceOffline = bc && bc->Top()->GetForceOffline(); -+ bool forceOffline = IsForcedOffline(); - - if (mURI->SchemeIs("https") || aShouldUpgrade || !LoadUseHTTPSSVC() || - forceOffline) { -@@ -1263,15 +1259,14 @@ nsresult nsHttpChannel::ContinueConnect() { - "CORS preflight must have been finished by the time we " - "do the rest of ContinueConnect"); - -- RefPtr bc; -- mLoadInfo->GetBrowsingContext(getter_AddRefs(bc)); -+ bool isForcedOffline = IsForcedOffline(); - - // we may or may not have a cache entry at this point - if (mCacheEntry) { - // read straight from the cache if possible... - if (CachedContentIsValid()) { - // If we're forced offline, and set to bypass the cache, return offline. -- if (bc && bc->Top()->GetForceOffline() && -+ if (isForcedOffline && - BYPASS_LOCAL_CACHE(mLoadFlags, LoadPreferCacheLoadOverBypass())) { - return NS_ERROR_OFFLINE; - } -@@ -1313,7 +1308,7 @@ nsresult nsHttpChannel::ContinueConnect() { - } - - // We're about to hit the network. Don't if we're forced offline. -- if (bc && bc->Top()->GetForceOffline()) { -+ if (isForcedOffline) { - return NS_ERROR_OFFLINE; - } - -@@ -1418,12 +1413,9 @@ void nsHttpChannel::SpeculativeConnect() { - // don't speculate if we are offline, when doing http upgrade (i.e. - // websockets bootstrap), or if we can't do keep-alive (because then we - // couldn't reuse the speculative connection anyhow). -- RefPtr bc; -- mLoadInfo->GetBrowsingContext(getter_AddRefs(bc)); -- - if (gIOService->IsOffline() || mUpgradeProtocolCallback || - !(mCaps & NS_HTTP_ALLOW_KEEPALIVE) || -- (bc && bc->Top()->GetForceOffline())) { -+ IsForcedOffline()) { - (void)SetIsCaptivePortalTab(true); - } - -@@ -4240,9 +4232,6 @@ nsresult nsHttpChannel::OpenCacheEntryInternal(bool isHttps) { - uint32_t cacheEntryOpenFlags; - bool offline = gIOService->IsOffline(); - -- RefPtr bc; -- mLoadInfo->GetBrowsingContext(getter_AddRefs(bc)); -- - bool maybeRCWN = false; - - nsAutoCString cacheControlRequestHeader; -@@ -4253,7 +4242,7 @@ nsresult nsHttpChannel::OpenCacheEntryInternal(bool isHttps) { - return NS_OK; - } - -- bool forceOffline = bc && bc->Top()->GetForceOffline(); -+ bool forceOffline = IsForcedOffline(); - if (offline || (mLoadFlags & INHIBIT_CACHING) || forceOffline) { - if (BYPASS_LOCAL_CACHE(mLoadFlags, LoadPreferCacheLoadOverBypass()) && - !offline && !forceOffline) { -@@ -7357,6 +7346,20 @@ void nsHttpChannel::MaybeStartDNSPrefetch() { - } - } - -+bool nsHttpChannel::IsForcedOffline() { -+ RefPtr bc; -+ mLoadInfo->GetBrowsingContext(getter_AddRefs(bc)); -+ if (bc && bc->Top()->GetForceOffline()) -+ return true; -+ -+ RefPtr wbc; -+ mLoadInfo->GetWorkerAssociatedBrowsingContext(getter_AddRefs(wbc)); -+ if (wbc && wbc->Top()->GetForceOffline()) -+ return true; -+ -+ return false; -+} -+ - NS_IMETHODIMP - nsHttpChannel::GetEncodedBodySize(uint64_t* aEncodedBodySize) { - if (mCacheEntry && !LoadCacheEntryIsWriteOnly()) { -diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h -index 9d28bae2d270690517c11383abe4c4bcc0edda96..9087d345b1b63bdce0912abb0c880c50900a797b 100644 ---- a/netwerk/protocol/http/nsHttpChannel.h -+++ b/netwerk/protocol/http/nsHttpChannel.h -@@ -305,6 +305,10 @@ class nsHttpChannel final : public HttpBaseChannel, - void MaybeResolveProxyAndBeginConnect(); - void MaybeStartDNSPrefetch(); - -+ // ---- Playwright begin -+ bool IsForcedOffline(); -+ // ---- Playwright end -+ - // Based on the proxy configuration determine the strategy for resolving the - // end server host name. - ProxyDNSStrategy GetProxyDNSStrategy(); -diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp -index ce2a868b9a915b98938518b6c935870f8169e0f7..e6d0a75bb3f5e8dea3f3e7f3448b553979860bd3 100644 ---- a/parser/html/nsHtml5TreeOpExecutor.cpp -+++ b/parser/html/nsHtml5TreeOpExecutor.cpp -@@ -1361,6 +1361,10 @@ void nsHtml5TreeOpExecutor::UpdateReferrerInfoFromMeta( - void nsHtml5TreeOpExecutor::AddSpeculationCSP(const nsAString& aCSP) { - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - -+ if (mDocShell && static_cast(mDocShell.get())->IsBypassCSPEnabled()) { -+ return; -+ } -+ - nsresult rv = NS_OK; - nsCOMPtr preloadCsp = mDocument->GetPreloadCsp(); - if (!preloadCsp) { -diff --git a/security/manager/ssl/nsCertOverrideService.cpp b/security/manager/ssl/nsCertOverrideService.cpp -index 0ecf2c0df3aad52e004a69b4c7a22fea7532b4d8..f5982c2cf1d6ea0522ac7f7e1fb5b4ab8fa07cb4 100644 ---- a/security/manager/ssl/nsCertOverrideService.cpp -+++ b/security/manager/ssl/nsCertOverrideService.cpp -@@ -627,6 +627,8 @@ void nsCertOverrideService::CountPermanentOverrideTelemetry( - } - - static bool IsDebugger() { -+ // In playwright world, this is always enabled. -+ if (1 == 1) return true; - #ifdef ENABLE_WEBDRIVER - nsCOMPtr marionette = do_GetService(NS_MARIONETTE_CONTRACTID); - if (marionette) { -diff --git a/services/settings/Utils.sys.mjs b/services/settings/Utils.sys.mjs -index cbdf07bcdae11de6f59e6c6c279833aca430dc70..6840c78350ccb52e99f23446b010abc2a1d92a55 100644 ---- a/services/settings/Utils.sys.mjs -+++ b/services/settings/Utils.sys.mjs -@@ -97,7 +97,7 @@ const _cdnURLs = {}; - - export var Utils = { - get SERVER_URL() { -- return lazy.allowServerURLOverride -+ return true || lazy.allowServerURLOverride - ? lazy.gServerURL - : AppConstants.REMOTE_SETTINGS_SERVER_URL; - }, -@@ -110,6 +110,9 @@ export var Utils = { - log, - - get shouldSkipRemoteActivityDueToTests() { -+ // Playwright does not set Cu.isInAutomation, hence we just return true -+ // here in order to disable the remote activity. -+ return true; - return ( - (lazy.isRunningTests || Cu.isInAutomation) && - this.SERVER_URL == "data:,#remote-settings-dummy/v1" -diff --git a/toolkit/components/browser/nsIWebBrowserChrome.idl b/toolkit/components/browser/nsIWebBrowserChrome.idl -index 75555352b8a15a50e4a21e34fc8ede4e9246c7cc..72855a404effa42b6c55cd0c2fcb8bdd6c2b3f9f 100644 ---- a/toolkit/components/browser/nsIWebBrowserChrome.idl -+++ b/toolkit/components/browser/nsIWebBrowserChrome.idl -@@ -74,6 +74,9 @@ interface nsIWebBrowserChrome : nsISupports - // Whether this window should use out-of-process cross-origin subframes. - const unsigned long CHROME_FISSION_WINDOW = 1 << 21; - -+ // 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 = 1 << 24; -diff --git a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs -index 3d8837cdb38fb5b25abfb9e3e369ad6fe688706e..867ce2efaa10eaea87ffeeb2669cc5a7be0045b3 100644 ---- a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs -+++ b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs -@@ -106,7 +106,9 @@ EnterprisePoliciesManager.prototype = { - Services.prefs.clearUserPref(PREF_POLICIES_APPLIED); - } - -- let provider = this._chooseProvider(); -+ // --- Playwright begin --- -+ let provider = new PlaywrightPoliciesProvider(); -+ // --- Playwright end --- - - if (provider.failed) { - this.status = Ci.nsIEnterprisePolicies.FAILED; -@@ -606,6 +608,19 @@ class JSONPoliciesProvider { - } - } - -+class PlaywrightPoliciesProvider extends JSONPoliciesProvider { -+ _getConfigurationFile() { -+ let prefPath = Services.prefs.getStringPref(PREF_ALTERNATE_PATH, ""); -+ if (!prefPath) -+ return null; -+ -+ dump(`Playwright: loading enterprise policies from ${prefPath}\n`); -+ let configFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); -+ configFile.initWithPath(prefPath); -+ return configFile; -+ } -+} -+ - class WindowsGPOPoliciesProvider { - constructor() { - this._policies = null; -diff --git a/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp b/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp -index 52fa968554a88d1624bf9403b07781a8b42c93b6..2bd5162859dbc482361e2f6aaf5b7a732e9a5929 100644 ---- a/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp -+++ b/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp -@@ -588,7 +588,7 @@ void PopulateLanguages() { - // sufficient to only collect this information as the other properties are - // just reformats of Navigator::GetAcceptLanguages. - nsTArray languages; -- dom::Navigator::GetAcceptLanguages(languages); -+ dom::Navigator::GetAcceptLanguages(nullptr, languages); - nsCString output = "["_ns; - - for (const auto& language : languages) { -diff --git a/toolkit/components/startup/nsAppStartup.cpp b/toolkit/components/startup/nsAppStartup.cpp -index d8f0c072c8a52c2837d87fe749ccac6e3e59e48a..6837927e6a49a8ff4c9f709502bf8d8983bd735c 100644 ---- a/toolkit/components/startup/nsAppStartup.cpp -+++ b/toolkit/components/startup/nsAppStartup.cpp -@@ -361,7 +361,7 @@ nsAppStartup::Quit(uint32_t aMode, int aExitCode, bool* aUserAllowedQuit) { - nsCOMPtr windowEnumerator; - nsCOMPtr 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 c0d60b927542653ab9beee730ec2c07f4b3d911c..85c416315f567a5edf8cfc89262dd7a48250dfd6 100644 ---- a/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp -+++ b/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp -@@ -176,8 +176,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 622ff7fe214d22e1e5d5a561753cffe3e1eafe31..ac2f30e00a9a6d18c61d00b0d6d4bf41ff48af95 100644 ---- a/toolkit/components/windowwatcher/nsWindowWatcher.cpp -+++ b/toolkit/components/windowwatcher/nsWindowWatcher.cpp -@@ -1882,7 +1882,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.sys.mjs b/toolkit/mozapps/update/UpdateService.sys.mjs -index 5d5a3f2c46138b578b583ad4a3506e1d227607ad..6d414635b80a74edb0b5ecfc6a98dd0fee763952 100644 ---- a/toolkit/mozapps/update/UpdateService.sys.mjs -+++ b/toolkit/mozapps/update/UpdateService.sys.mjs -@@ -3874,6 +3874,8 @@ export class UpdateService { - } - - get disabledForTesting() { -+ /* playwright */ -+ return true; - return lazy.UpdateServiceStub.updateDisabledForTesting; - } - -diff --git a/toolkit/toolkit.mozbuild b/toolkit/toolkit.mozbuild -index e8399d277ec0b64e5ea29aa7262b118936a02779..983ed73ad1d6d734af55a9066a8e8a6cf3ae3f45 100644 ---- a/toolkit/toolkit.mozbuild -+++ b/toolkit/toolkit.mozbuild -@@ -155,6 +155,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 7eb9e1104682d4eb47060654f43a1efa8b2a6bb2..a8315d6decf654b5302bea5beeea34140c300ded 100644 ---- a/toolkit/xre/nsWindowsWMain.cpp -+++ b/toolkit/xre/nsWindowsWMain.cpp -@@ -14,8 +14,10 @@ - #endif - - #include "mozilla/Char16.h" -+#include "mozilla/CmdLineAndEnvUtils.h" - #include "nsUTF8Utils.h" - -+#include - #include - - #ifdef __MINGW32__ -@@ -114,6 +116,19 @@ static void FreeAllocStrings(int argc, char** argv) { - int wmain(int argc, WCHAR** argv) { - SanitizeEnvironmentVariables(); - SetDllDirectoryW(L""); -+ bool hasJugglerPipe = -+ mozilla::CheckArg(argc, argv, "juggler-pipe", 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 9ef5370d1524ddecb965785a73a3cfea39867324..e0245cca94e496bcffba40c9660a52b518803d44 100644 ---- a/uriloader/base/nsDocLoader.cpp -+++ b/uriloader/base/nsDocLoader.cpp -@@ -861,6 +861,12 @@ void nsDocLoader::DocLoaderIsEmpty(bool aFlushLayout, - ("DocLoader:%p: Firing load event for document.open\n", - this)); - -+ nsCOMPtr 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 5bd60b585b53cc77e75c0b68c763957f90b7e164..940b3b62b09ca70ae5e69c3e94eda11ad35b9dfe 100644 ---- a/uriloader/exthandler/nsExternalHelperAppService.cpp -+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp -@@ -112,6 +112,7 @@ - - #include "mozilla/Components.h" - #include "mozilla/ClearOnShutdown.h" -+#include "mozilla/ErrorNames.h" - #include "mozilla/Preferences.h" - #include "mozilla/ipc/URIUtils.h" - -@@ -865,6 +866,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); -@@ -1500,7 +1507,12 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel* aChannel) { - // Strip off the ".part" from mTempLeafName - mTempLeafName.Truncate(mTempLeafName.Length() - std::size(".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); -@@ -1684,7 +1696,36 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { - return NS_OK; - } - -- rv = SetUpTempFile(aChannel); -+ bool isIntercepted = false; -+ nsCOMPtr interceptor = mExtProtSvc->mInterceptor; -+ if (interceptor) { -+ nsCOMPtr 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; - -@@ -1745,6 +1786,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 -@@ -2261,6 +2305,16 @@ nsExternalAppHandler::OnSaveComplete(nsIBackgroundFileSaver* aSaver, - NotifyTransfer(aStatus); - } - -+ if (!mCanceled) { -+ nsCOMPtr 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; - } - -@@ -2744,6 +2798,15 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason) { - } - } - -+ nsCOMPtr 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 26dfc6f04298420317c8b87b2ecc3f2f47f59598..c458ab5efb238c62499ee13452f2d750e0569e38 100644 ---- a/uriloader/exthandler/nsExternalHelperAppService.h -+++ b/uriloader/exthandler/nsExternalHelperAppService.h -@@ -263,6 +263,8 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService, - mozilla::dom::BrowsingContext* aContentContext, bool aForceSave, - nsIInterfaceRequestor* aWindowContext, - nsIStreamListener** aStreamListener); -+ -+ nsCOMPtr mInterceptor; - }; - - /** -@@ -460,6 +462,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 e6490ebb086eb4dca9db560c14e073a9e7722e29..2792373dcb30ebc787a9bdca306ac12e72aa19ec 100644 ---- a/uriloader/exthandler/nsIExternalHelperAppService.idl -+++ b/uriloader/exthandler/nsIExternalHelperAppService.idl -@@ -6,8 +6,11 @@ - - #include "nsICancelable.idl" - -+webidl BrowsingContext; -+interface nsIHelperAppLauncher; - interface nsIURI; - interface nsIChannel; -+interface nsIRequest; - interface nsIStreamListener; - interface nsIFile; - interface nsIMIMEInfo; -@@ -15,6 +18,17 @@ interface nsIWebProgressListener2; - interface nsIInterfaceRequestor; - webidl BrowsingContext; - -+/** -+ * Interceptor interface used by Juggler. -+ */ -+[scriptable, uuid(9a20e9b0-75d0-11ea-bc55-0242ac130003)] -+interface nsIDownloadInterceptor : nsISupports -+{ -+ boolean 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. -@@ -87,6 +101,8 @@ interface nsIExternalHelperAppService : nsISupports - * `DownloadIntegration.sys.mjs`, which is implemented on all platforms. - */ - nsIFile getPreferredDownloadsDirectory(); -+ -+ void setDownloadInterceptor(in nsIDownloadInterceptor interceptor); - }; - - /** -diff --git a/widget/InProcessCompositorWidget.cpp b/widget/InProcessCompositorWidget.cpp -index 7098db301770ecb5b9a506d7caec89d5cf63384b..aff8d7562f8a3e595a077ce8e591008762479587 100644 ---- a/widget/InProcessCompositorWidget.cpp -+++ b/widget/InProcessCompositorWidget.cpp -@@ -5,8 +5,11 @@ - #include "InProcessCompositorWidget.h" - -+#include "HeadlessCompositorWidget.h" -+#include "HeadlessWidget.h" - #include "mozilla/VsyncDispatcher.h" -+#include "mozilla/widget/PlatformWidgetTypes.h" - #include "mozilla/layers/NativeLayer.h" - #include "nsIWidget.h" - - namespace mozilla { -@@ -26,6 +29,12 @@ RefPtr CompositorWidget::CreateLocal( - // do it after the static_cast. - nsIWidget* widget = static_cast(aWidget)); -+ } - return new InProcessCompositorWidget(aOptions, widget); - } - #endif -diff --git a/widget/MouseEvents.h b/widget/MouseEvents.h -index 4f7ca9d0d460da3124ec8489917a9484661d5624..a04c3661b3e1e2be030ac6fe90041c81e653d26e 100644 ---- a/widget/MouseEvents.h -+++ b/widget/MouseEvents.h -@@ -380,6 +380,9 @@ class WidgetMouseEvent : public WidgetMouseEventBase, - // Otherwise, this must be 0. - uint32_t mClickCount = 0; - -+ // Unique event ID -+ uint32_t mJugglerEventId = 0; -+ - // Whether the event should ignore scroll frame bounds during dispatch. - bool mIgnoreRootScrollFrame = false; - -@@ -407,6 +410,7 @@ class WidgetMouseEvent : public WidgetMouseEventBase, - mContextMenuTrigger = aEvent.mContextMenuTrigger; - mExitFrom = aEvent.mExitFrom; - mClickCount = aEvent.mClickCount; -+ mJugglerEventId = aEvent.mJugglerEventId; - mIgnoreRootScrollFrame = aEvent.mIgnoreRootScrollFrame; - mIgnoreCapturingContent = aEvent.mIgnoreCapturingContent; - mClickEventPrevented = aEvent.mClickEventPrevented; -diff --git a/widget/cocoa/NativeKeyBindings.mm b/widget/cocoa/NativeKeyBindings.mm -index 24b70173c2e8bb9be9fd6255984a70efe3b14099..75ac367a1c4bb44d4b68b5f4ecc6adf56dbd408e 100644 ---- a/widget/cocoa/NativeKeyBindings.mm -+++ b/widget/cocoa/NativeKeyBindings.mm -@@ -549,6 +549,13 @@ void NativeKeyBindings::GetEditCommandsForTests( - 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())) { -@@ -571,6 +578,13 @@ void NativeKeyBindings::GetEditCommandsForTests( - 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())) { -@@ -593,6 +607,10 @@ void NativeKeyBindings::GetEditCommandsForTests( - 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()) { -@@ -603,7 +621,7 @@ void NativeKeyBindings::GetEditCommandsForTests( - !aEvent.IsShift() - ? ToObjcSelectorPtr(@selector(moveToBeginningOfDocument:)) - : ToObjcSelectorPtr( -- @selector(moveToBegginingOfDocumentAndModifySelection:)), -+ @selector(moveToBeginningOfDocumentAndModifySelection:)), - aCommands); - break; - } -@@ -630,6 +648,10 @@ void NativeKeyBindings::GetEditCommandsForTests( - 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/gtk/nsFilePicker.cpp b/widget/gtk/nsFilePicker.cpp -index f09b0e4994304413cbd75f14e6650cf3f9df9025..41c184e74df2b9c59315a236506946bcb5d69216 100644 ---- a/widget/gtk/nsFilePicker.cpp -+++ b/widget/gtk/nsFilePicker.cpp -@@ -21,7 +21,8 @@ - #include "mozilla/Components.h" - #include "mozilla/Preferences.h" - #include "mozilla/dom/Promise.h" -+#include "gfxPlatform.h" - #include "mozilla/dom/Document.h" - - #include "nsArrayEnumerator.h" - #include "nsEnumeratorUtils.h" -diff --git a/widget/headless/HeadlessCompositorWidget.cpp b/widget/headless/HeadlessCompositorWidget.cpp -index bb4ee9175e66dc40de1871a7f91368fe309494a3..6814ae85038d31f1a3b1f87ba341219ffbc1e6b3 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" -@@ -15,9 +16,30 @@ HeadlessCompositorWidget::HeadlessCompositorWidget( - const layers::CompositorOptions& aOptions, HeadlessWidget* aWindow) - : CompositorWidget(aOptions), - mWidget(aWindow), -+ mMon("snapshotListener"), - mClientSize(LayoutDeviceIntSize(aInitData.InitialClientSize()), - "HeadlessCompositorWidget::mClientSize") {} - -+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 HeadlessCompositorWidget::StartRemoteDrawingInRegion( -+ const LayoutDeviceIntRegion& aInvalidRegion) { -+ if (!mDrawTarget) -+ return nullptr; -+ -+ RefPtr result = mDrawTarget; -+ return result.forget(); -+} -+ - void HeadlessCompositorWidget::ObserveVsync(VsyncObserver* aObserver) { - if (RefPtr cvd = - mWidget->GetCompositorVsyncDispatcher()) { -@@ -31,6 +53,59 @@ void HeadlessCompositorWidget::NotifyClientSizeChanged( - const LayoutDeviceIntSize& aClientSize) { - auto size = mClientSize.Lock(); - *size = aClientSize; -+ layers::CompositorThread()->Dispatch(NewRunnableMethod( -+ "HeadlessCompositorWidget::UpdateDrawTarget", this, -+ &HeadlessCompositorWidget::UpdateDrawTarget, -+ aClientSize)); -+} -+ -+void HeadlessCompositorWidget::UpdateDrawTarget(const LayoutDeviceIntSize& aClientSize) { -+ MOZ_ASSERT(NS_IsInCompositorThread()); -+ if (aClientSize.IsEmpty()) { -+ mDrawTarget = nullptr; -+ return; -+ } -+ -+ RefPtr 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 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 snapshot = mDrawTarget->Snapshot(); -+ if (!snapshot) { -+ fprintf(stderr, "Failed to get snapshot of draw target\n"); -+ return; -+ } -+ -+ RefPtr 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 facd2bc65afab8ec1aa322faa20a67464964dfb9..3c5751ad1b7f042bc7cd9a63895cebcd2942ccd3 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,11 @@ class HeadlessCompositorWidget final : public CompositorWidget, - HeadlessWidget* aWindow); - - void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize); -+ void SetSnapshotListener(HeadlessWidget::SnapshotListener&& listener); - - // CompositorWidget Overrides -+ already_AddRefed StartRemoteDrawingInRegion( -+ const LayoutDeviceIntRegion& aInvalidRegion) override; - - uintptr_t GetWidgetKey() override; - -@@ -42,10 +46,18 @@ class HeadlessCompositorWidget final : public CompositorWidget, - } - - private: -+ void UpdateDrawTarget(const LayoutDeviceIntSize& aClientSize); -+ void PeriodicSnapshot(); -+ void TakeSnapshot(); -+ - HeadlessWidget* mWidget; -+ mozilla::ReentrantMonitor mMon; - - // See GtkCompositorWidget for the justification for this mutex. - DataMutex mClientSize; -+ -+ HeadlessWidget::SnapshotListener mSnapshotListener; -+ RefPtr mDrawTarget; - }; - - } // namespace widget -diff --git a/widget/headless/HeadlessWidget.cpp b/widget/headless/HeadlessWidget.cpp -index 290de12f9d0ff858474564fa8ce54814a04f6088..c144a891b84c3c57f394d6d551e6c89dcd6d9829 100644 ---- a/widget/headless/HeadlessWidget.cpp -+++ b/widget/headless/HeadlessWidget.cpp -@@ -112,6 +112,8 @@ void HeadlessWidget::Destroy() { - } - } - -+ SetSnapshotListener(nullptr); -+ - nsBaseWidget::OnDestroy(); - - nsBaseWidget::Destroy(); -@@ -593,5 +595,14 @@ nsresult HeadlessWidget::SynthesizeNativeTouchpadPan( - 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 60598d097d9dae829ebdc15dede78bd915e3107d..3b5ac5e5590dcb36440e28569f71592db3c1218c 100644 ---- a/widget/headless/HeadlessWidget.h -+++ b/widget/headless/HeadlessWidget.h -@@ -131,6 +131,9 @@ class HeadlessWidget final : public nsBaseWidget { - double aDeltaX, double aDeltaY, int32_t aModifierFlags, - nsISynthesizedEventCallback* aCallback) override; - -+ using SnapshotListener = std::function&&)>; -+ void SetSnapshotListener(SnapshotListener&& listener); -+ - private: - ~HeadlessWidget(); - bool mEnabled; -diff --git a/widget/nsGUIEventIPC.h b/widget/nsGUIEventIPC.h -index 2f4c33f151870bb9233899b186a5eccfaa6f5da6..6acf66e4938e3f9727916824a08d6294f8993452 100644 ---- a/widget/nsGUIEventIPC.h -+++ b/widget/nsGUIEventIPC.h -@@ -251,6 +251,7 @@ struct ParamTraits { - aParam.mExitFrom.value())); - } - WriteParam(aWriter, aParam.mClickCount); -+ WriteParam(aWriter, aParam.mJugglerEventId); - } - - static bool Read(MessageReader* aReader, paramType* aResult) { -@@ -275,6 +276,7 @@ struct ParamTraits { - aResult->mExitFrom = Some(static_cast(exitFrom)); - } - rv = rv && ReadParam(aReader, &aResult->mClickCount); -+ rv = rv && ReadParam(aReader, &aResult->mJugglerEventId); - return rv; - } - }; -diff --git a/xpcom/reflect/xptinfo/xptinfo.h b/xpcom/reflect/xptinfo/xptinfo.h -index 787d30d881adedd57d2025ca57bff4bc6c57e803..ae1a0172c960ab16919133485722d2ae0cdbcbd4 100644 ---- a/xpcom/reflect/xptinfo/xptinfo.h -+++ b/xpcom/reflect/xptinfo/xptinfo.h -@@ -505,7 +505,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 - - /** diff --git a/patches/playwright/1-leak-fixes.patch b/patches/playwright/1-leak-fixes.patch index f43e4103..d686c3c8 100644 --- a/patches/playwright/1-leak-fixes.patch +++ b/patches/playwright/1-leak-fixes.patch @@ -1,3 +1,34 @@ +diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp +index e0cbb3f1f8..d7868e7ae0 100644 +--- a/dom/base/Navigator.cpp ++++ b/dom/base/Navigator.cpp +@@ -2318,22 +2318,7 @@ dom::PrivateAttribution* Navigator::PrivateAttribution() { + + /* static */ + bool Navigator::Webdriver() { +-#ifdef ENABLE_WEBDRIVER +- nsCOMPtr marionette = do_GetService(NS_MARIONETTE_CONTRACTID); +- if (marionette) { +- bool marionetteRunning = false; +- marionette->GetRunning(&marionetteRunning); +- if (marionetteRunning) { +- return true; +- } +- } +- +- nsCOMPtr agent = do_GetService(NS_REMOTEAGENT_CONTRACTID); +- if (agent) { +- bool remoteAgentRunning = false; +- agent->GetRunning(&remoteAgentRunning); +- if (remoteAgentRunning) { +- return true; +- } +- } +-#endif +- + return false; + } + diff --git a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs index 0eeb5924c4..8b975a8b11 100644 --- a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs @@ -5,7 +36,7 @@ index 0eeb5924c4..8b975a8b11 100644 @@ -108,12 +108,6 @@ EnterprisePoliciesManager.prototype = { Services.prefs.clearUserPref(PREF_POLICIES_APPLIED); } - + - // Playwright: Disable enterprise policies - if (true) { - this.status = Ci.nsIEnterprisePolicies.INACTIVE; @@ -13,5 +44,5 @@ index 0eeb5924c4..8b975a8b11 100644 - } - let provider = this._chooseProvider(); - + if (provider.failed) {