playwright/browser_patches/firefox/patches/bootstrap.diff

3337 lines
130 KiB
Diff

diff --git a/accessible/base/NotificationController.h b/accessible/base/NotificationController.h
index 1bcd464d3bd6b8465f78c62b074b0d57dbc6a082..f878ac9db2d800542dabcc2f48e8ae4727ec4b9a 100644
--- a/accessible/base/NotificationController.h
+++ b/accessible/base/NotificationController.h
@@ -244,6 +244,8 @@ class NotificationController final : public EventQueue,
}
#endif
+ bool IsUpdatePendingForJugglerAccessibility() { return IsUpdatePending(); }
+
protected:
virtual ~NotificationController();
diff --git a/accessible/interfaces/nsIAccessibleDocument.idl b/accessible/interfaces/nsIAccessibleDocument.idl
index 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..24a0837c508f7bc2709538fc28fdafe83ed524f8 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()->IsUpdatePendingForJugglerAccessibility();
+ 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 <io.h>
#include <windows.h>
#include <processthreadsapi.h>
@@ -422,8 +423,18 @@ Maybe<int> LauncherMain(int& argc, wchar_t* argv[],
HANDLE stdHandles[] = {::GetStdHandle(STD_INPUT_HANDLE),
::GetStdHandle(STD_OUTPUT_HANDLE),
::GetStdHandle(STD_ERROR_HANDLE)};
-
attrs.AddInheritableHandles(stdHandles);
+ // Playwright pipe installation.
+ bool hasJugglerPipe =
+ mozilla::CheckArg(argc, argv, "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<HANDLE>(stdio3),
+ reinterpret_cast<HANDLE>(stdio4)};
+ attrs.AddInheritableHandles(pipeHandles);
+ }
DWORD creationFlags = CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT;
diff --git a/browser/installer/allowed-dupes.mn b/browser/installer/allowed-dupes.mn
index a315ebcb8b60875b4eddbb5d654764603e0e7bec..fa67db1ff5a331dda4eaff4457418c306869d011 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 6ebf2f62c47757f16841d04c164d2d86447fcbd0..cae3f3ac6f6ced0b59fe850643bbb90d619750d0 100644
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -192,6 +192,9 @@
@RESPATH@/chrome/remote.manifest
#endif
+@RESPATH@/chrome/juggler@JAREXT@
+@RESPATH@/chrome/juggler.manifest
+
; [Extensions]
@RESPATH@/components/extensions-toolkit.manifest
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 1a33afa481826b1a53c507d5ea596bcb629d8ac4..8f4f13ff1325b104af80e319cf092be9fd2baab0 100644
--- a/docshell/base/BrowsingContext.cpp
+++ b/docshell/base/BrowsingContext.cpp
@@ -109,8 +109,15 @@ struct ParamTraits<mozilla::dom::DisplayMode>
template <>
struct ParamTraits<mozilla::dom::PrefersColorSchemeOverride>
- : public mozilla::dom::WebIDLEnumSerializer<
- mozilla::dom::PrefersColorSchemeOverride> {};
+ : public mozilla::dom::WebIDLEnumSerializer<mozilla::dom::PrefersColorSchemeOverride> {};
+
+template <>
+struct ParamTraits<mozilla::dom::PrefersReducedMotionOverride>
+ : public mozilla::dom::WebIDLEnumSerializer<mozilla::dom::PrefersReducedMotionOverride> {};
+
+template <>
+struct ParamTraits<mozilla::dom::PrefersContrastOverride>
+ : public mozilla::dom::WebIDLEnumSerializer<mozilla::dom::PrefersContrastOverride> {};
template <>
struct ParamTraits<mozilla::dom::ForcedColorsOverride>
@@ -2915,6 +2922,32 @@ void BrowsingContext::DidSet(FieldIndex<IDX_ForcedColorsOverride>,
PresContextAffectingFieldChanged();
}
+void BrowsingContext::DidSet(FieldIndex<IDX_PrefersContrastOverride>,
+ dom::PrefersContrastOverride aOldValue) {
+ MOZ_ASSERT(IsTop());
+ if (PrefersContrastOverride() == aOldValue) {
+ return;
+ }
+ PresContextAffectingFieldChanged();
+}
+
+void BrowsingContext::DidSet(FieldIndex<IDX_PrefersReducedMotionOverride>,
+ dom::PrefersReducedMotionOverride aOldValue) {
+ MOZ_ASSERT(IsTop());
+ if (PrefersReducedMotionOverride() == aOldValue) {
+ return;
+ }
+ PreOrderWalk([&](BrowsingContext* aContext) {
+ if (nsIDocShell* shell = aContext->GetDocShell()) {
+ if (nsPresContext* pc = shell->GetPresContext()) {
+ pc->MediaFeatureValuesChanged(
+ {MediaFeatureChangeReason::SystemMetricsChange},
+ MediaFeatureChangePropagation::JustThisDocument);
+ }
+ }
+ });
+}
+
void BrowsingContext::DidSet(FieldIndex<IDX_MediumOverride>,
nsString&& aOldValue) {
MOZ_ASSERT(IsTop());
diff --git a/docshell/base/BrowsingContext.h b/docshell/base/BrowsingContext.h
index 0bd3efa16dcae42ff02f42bddce378a7f0c7b621..c8cc1bce7d9901aced6032d0e2e2285cf9eb394b 100644
--- a/docshell/base/BrowsingContext.h
+++ b/docshell/base/BrowsingContext.h
@@ -205,10 +205,10 @@ 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(UserAgentOverride, nsString) \
- FIELD(TouchEventsOverrideInternal, mozilla::dom::TouchEventsOverride) \
+ FIELD(TouchEventsOverrideInternal, dom::TouchEventsOverride) \
FIELD(EmbedderElementType, Maybe<nsString>) \
FIELD(MessageManagerGroup, nsString) \
FIELD(MaxTouchPointsOverride, uint8_t) \
@@ -245,6 +245,9 @@ struct EmbedderColorSchemes {
* <browser> 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) \
@@ -967,6 +970,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(); }
@@ -1131,6 +1142,11 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
return IsTop();
}
+ bool CanSet(FieldIndex<IDX_PrefersContrastOverride>,
+ dom::PrefersContrastOverride, ContentParent*) {
+ return IsTop();
+ }
+
bool CanSet(FieldIndex<IDX_ForcedColorsOverride>, dom::ForcedColorsOverride,
ContentParent*) {
return IsTop();
@@ -1149,10 +1165,22 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
void DidSet(FieldIndex<IDX_ForcedColorsOverride>,
dom::ForcedColorsOverride aOldValue);
+ void DidSet(FieldIndex<IDX_PrefersContrastOverride>,
+ dom::PrefersContrastOverride aOldValue);
+
template <typename Callback>
void WalkPresContexts(Callback&&);
void PresContextAffectingFieldChanged();
+ bool CanSet(FieldIndex<IDX_PrefersReducedMotionOverride>,
+ dom::PrefersReducedMotionOverride, ContentParent*) {
+ return IsTop();
+ }
+
+ void DidSet(FieldIndex<IDX_PrefersReducedMotionOverride>,
+ dom::PrefersReducedMotionOverride aOldValue);
+
+
void DidSet(FieldIndex<IDX_MediumOverride>, nsString&& aOldValue);
bool CanSet(FieldIndex<IDX_SuspendMediaWhenInactive>, bool, ContentParent*) {
diff --git a/docshell/base/CanonicalBrowsingContext.cpp b/docshell/base/CanonicalBrowsingContext.cpp
index 1c5c421d6ec153ab61d3aae29200f8abb02b1a33..68751ec0190f308c20aae6b6c58687dcf0fa225d 100644
--- a/docshell/base/CanonicalBrowsingContext.cpp
+++ b/docshell/base/CanonicalBrowsingContext.cpp
@@ -325,6 +325,8 @@ void CanonicalBrowsingContext::ReplacedBy(
txn.SetForceOffline(GetForceOffline());
txn.SetTopInnerSizeForRFP(GetTopInnerSizeForRFP());
txn.SetIPAddressSpace(GetIPAddressSpace());
+ txn.SetPrefersReducedMotionOverride(GetPrefersReducedMotionOverride());
+ txn.SetForcedColorsOverride(GetForcedColorsOverride());
// Propagate some settings on BrowsingContext replacement so they're not lost
// on bfcached navigations. These are important for GeckoView (see bug
@@ -1635,6 +1637,12 @@ void CanonicalBrowsingContext::LoadURI(nsIURI* aURI,
return;
}
+ {
+ nsCOMPtr<nsIObserverService> 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 5bcbbfbcb522adb9988ba421a4f590ee2105e1d3..cb9bc09a7901334b6ba73834971498f4472cce2d 100644
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -16,6 +16,12 @@
# include <unistd.h> // for getpid()
#endif
+#if JS_HAS_INTL_API && !MOZ_SYSTEM_ICU
+# include "unicode/locid.h"
+#endif /* JS_HAS_INTL_API && !MOZ_SYSTEM_ICU */
+
+#include "js/LocaleSensitive.h"
+
#include "mozilla/ArrayUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/AutoRestore.h"
@@ -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"
@@ -95,6 +102,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"
@@ -118,6 +126,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"
@@ -212,6 +221,7 @@
#include "nsGlobalWindowInner.h"
#include "nsGlobalWindowOuter.h"
#include "nsJSEnvironment.h"
+#include "nsJSUtils.h"
#include "nsNetCID.h"
#include "nsNetUtil.h"
#include "nsObjectLoadingContent.h"
@@ -353,6 +363,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),
@@ -3025,6 +3043,232 @@ nsDocShell::GetMessageManager(ContentFrameMessageManager** aMessageManager) {
return NS_OK;
}
+// =============== Juggler Begin =======================
+
+nsDocShell* nsDocShell::GetRootDocShell() {
+ nsCOMPtr<nsIDocShellTreeItem> rootAsItem;
+ GetInProcessSameTypeRootTreeItem(getter_AddRefs(rootAsItem));
+ nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(rootAsItem);
+ return nsDocShell::Cast(rootShell);
+}
+
+NS_IMETHODIMP
+nsDocShell::GetBypassCSPEnabled(bool* aEnabled) {
+ MOZ_ASSERT(aEnabled);
+ *aEnabled = mBypassCSPEnabled;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetBypassCSPEnabled(bool aEnabled) {
+ mBypassCSPEnabled = aEnabled;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::GetForceActiveState(bool* aEnabled) {
+ MOZ_ASSERT(aEnabled);
+ *aEnabled = mForceActiveState;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetForceActiveState(bool aEnabled) {
+ mForceActiveState = aEnabled;
+ ActivenessMaybeChanged();
+ return NS_OK;
+}
+
+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<nsIObserverService> observerService =
+ mozilla::services::GetObserverService();
+ observerService->NotifyObservers(
+ ToSupports(element), "juggler-file-picker-shown", nullptr);
+}
+
+RefPtr<nsGeolocationService> nsDocShell::GetGeolocationServiceOverride() {
+ return GetRootDocShell()->mGeolocationServiceOverride;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetGeolocationOverride(nsIDOMGeoPosition* aGeolocationOverride) {
+ if (aGeolocationOverride) {
+ if (!mGeolocationServiceOverride) {
+ mGeolocationServiceOverride = new nsGeolocationService();
+ mGeolocationServiceOverride->Init();
+ }
+ mGeolocationServiceOverride->Update(aGeolocationOverride);
+ } else {
+ mGeolocationServiceOverride = nullptr;
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::GetReducedMotionOverride(ReducedMotionOverride* aReducedMotionOverride) {
+ *aReducedMotionOverride = GetRootDocShell()->mReducedMotionOverride;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetReducedMotionOverride(ReducedMotionOverride aReducedMotionOverride) {
+ mReducedMotionOverride = aReducedMotionOverride;
+ RefPtr<nsPresContext> presContext = GetPresContext();
+ if (presContext) {
+ presContext->MediaFeatureValuesChanged(
+ {MediaFeatureChangeReason::SystemMetricsChange},
+ MediaFeatureChangePropagation::JustThisDocument);
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::GetForcedColorsOverride(ForcedColorsOverride* aForcedColorsOverride) {
+ *aForcedColorsOverride = GetRootDocShell()->mForcedColorsOverride;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetForcedColorsOverride(ForcedColorsOverride aForcedColorsOverride) {
+ mForcedColorsOverride = aForcedColorsOverride;
+ RefPtr<nsPresContext> presContext = GetPresContext();
+ if (presContext) {
+ presContext->MediaFeatureValuesChanged(
+ {MediaFeatureChangeReason::SystemMetricsChange},
+ MediaFeatureChangePropagation::JustThisDocument);
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::GetContrastOverride(ContrastOverride* aContrastOverride) {
+ *aContrastOverride = GetRootDocShell()->mContrastOverride;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetContrastOverride(ContrastOverride aContrastOverride) {
+ mContrastOverride = aContrastOverride;
+ RefPtr<nsPresContext> presContext = GetPresContext();
+ if (presContext) {
+ presContext->MediaFeatureValuesChanged(
+ {MediaFeatureChangeReason::SystemMetricsChange},
+ MediaFeatureChangePropagation::JustThisDocument);
+ }
+ return NS_OK;
+}
+
+// =============== Juggler End =======================
+
NS_IMETHODIMP
nsDocShell::GetIsNavigating(bool* aOut) {
*aOut = mIsNavigating;
@@ -4790,7 +5034,7 @@ nsDocShell::GetVisibility(bool* aVisibility) {
}
void nsDocShell::ActivenessMaybeChanged() {
- const bool isActive = mBrowsingContext->IsActive();
+ const bool isActive = mForceActiveState || mBrowsingContext->IsActive();
if (RefPtr<PresShell> presShell = GetPresShell()) {
presShell->ActivenessMaybeChanged();
}
@@ -6723,6 +6967,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<nsIDocumentViewer> viewer = mOSHE->GetDocumentViewer();
@@ -8464,6 +8712,12 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState) {
true, // aForceNoOpener
getter_AddRefs(newBC));
MOZ_ASSERT(!newBC);
+ if (rv == NS_OK) {
+ nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
+ if (observerService) {
+ observerService->NotifyObservers(GetAsSupports(this), "juggler-window-open-in-new-context", nullptr);
+ }
+ }
return rv;
}
@@ -9754,6 +10008,16 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState,
nsINetworkPredictor::PREDICT_LOAD, attrs, nullptr);
nsCOMPtr<nsIRequest> req;
+
+ // Juggler: report navigation started for non-same-document and non-javascript
+ // navigations.
+ if (!isJavaScript && !sameDocument) {
+ nsCOMPtr<nsIObserverService> 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)) {
@@ -12970,6 +13234,9 @@ class OnLinkClickEvent : public Runnable {
mHandler->OnLinkClickSync(mContent, mLoadState, mNoOpenerImplied,
mTriggeringPrincipal);
}
+ nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
+ observerService->NotifyObservers(ToSupports(mContent), "juggler-link-click-sync", nullptr);
+
return NS_OK;
}
@@ -13083,6 +13350,8 @@ nsresult nsDocShell::OnLinkClick(
nsCOMPtr<nsIRunnable> ev = new OnLinkClickEvent(
this, aContent, loadState, noOpenerImplied, aTriggeringPrincipal);
+ nsCOMPtr<nsIObserverService> 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 32d1673ea09a2c9f6bb14f6dcd8a9c1c8f9831c4..a301ecd30fcad4d79d370ab316fa0d8e5e509795 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"
@@ -78,6 +79,7 @@ class nsCommandManager;
class nsDocShellEditorData;
class nsDOMNavigationTiming;
class nsDSURIContentListener;
+class nsGeolocationService;
class nsGlobalWindowOuter;
class FramingChecker;
@@ -408,6 +410,15 @@ class nsDocShell final : public nsDocLoader,
void SetWillChangeProcess() { mWillChangeProcess = true; }
bool WillChangeProcess() { return mWillChangeProcess; }
+ bool IsFileInputInterceptionEnabled();
+ void FilePickerShown(mozilla::dom::Element* element);
+
+ bool ShouldOverrideHasFocus() const;
+
+ bool IsBypassCSPEnabled();
+
+ RefPtr<nsGeolocationService> GetGeolocationServiceOverride();
+
// Create a content viewer within this nsDocShell for the given
// `WindowGlobalChild` actor.
nsresult CreateDocumentViewerForActor(
@@ -1013,6 +1024,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
@@ -1301,6 +1314,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<nsGeolocationService> 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 159daa1dd936e84f1bf3ce413643382e4d37f592..607224a5270995abccf439992ec577f11178e522 100644
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -44,6 +44,7 @@ interface nsIURI;
interface nsIChannel;
interface nsIContentSecurityPolicy;
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 a16bef739fcde0f14ba7e53e0acfa3aa2ee1dd3a..c4747478156c973307b7866f84c65520e4bff9d1 100644
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -3818,6 +3818,9 @@ void Document::SendToConsole(nsCOMArray<nsISecurityConsoleMessage>& aMessages) {
}
void Document::ApplySettingsFromCSP(bool aSpeculative) {
+ if (mDocumentContainer && mDocumentContainer->IsBypassCSPEnabled())
+ return;
+
nsresult rv = NS_OK;
if (!aSpeculative) {
// 1) apply settings from regular CSP
@@ -3875,6 +3878,11 @@ nsresult Document::InitCSP(nsIChannel* aChannel) {
MOZ_ASSERT(!mScriptGlobalObject,
"CSP must be initialized before mScriptGlobalObject is set!");
+ nsCOMPtr<nsIDocShell> shell(mDocumentContainer);
+ if (shell && nsDocShell::Cast(shell)->IsBypassCSPEnabled()) {
+ return NS_OK;
+ }
+
// If this is a data document - no need to set CSP.
if (mLoadedAsData) {
return NS_OK;
@@ -4699,6 +4707,10 @@ bool Document::HasFocus(ErrorResult& rv) const {
return false;
}
+ if (IsActive() && mDocumentContainer->ShouldOverrideHasFocus()) {
+ return true;
+ }
+
if (!fm->IsInActiveWindow(bc)) {
return false;
}
@@ -20107,6 +20119,35 @@ ColorScheme Document::PreferredColorScheme(IgnoreRFP aIgnoreRFP) const {
return PreferenceSheet::PrefsFor(*this).mColorScheme;
}
+bool Document::PrefersReducedMotion() const {
+ auto* docShell = static_cast<nsDocShell*>(GetDocShell());
+ nsIDocShell::ReducedMotionOverride reducedMotion;
+ if (docShell && docShell->GetReducedMotionOverride(&reducedMotion) == NS_OK &&
+ reducedMotion != nsIDocShell::REDUCED_MOTION_OVERRIDE_NONE) {
+ switch (reducedMotion) {
+ case nsIDocShell::REDUCED_MOTION_OVERRIDE_REDUCE:
+ return true;
+ case nsIDocShell::REDUCED_MOTION_OVERRIDE_NO_PREFERENCE:
+ return false;
+ case nsIDocShell::REDUCED_MOTION_OVERRIDE_NONE:
+ break;
+ };
+ }
+
+ if (auto* bc = GetBrowsingContext()) {
+ switch (bc->Top()->PrefersReducedMotionOverride()) {
+ case dom::PrefersReducedMotionOverride::Reduce:
+ return true;
+ case dom::PrefersReducedMotionOverride::No_preference:
+ return false;
+ case dom::PrefersReducedMotionOverride::None:
+ 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 f9f8089ad484330a9d863fac7559b94aa34d80fd..75b6f3b03a6fe11511cc1e9ebdc6aa16936bbbcb 100644
--- a/dom/base/Document.h
+++ b/dom/base/Document.h
@@ -4224,6 +4224,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 fac275953573368e91e99bc8a72a885fb1c75521..7c1bcfdba325f8310239fc69921aaa0f14255f33 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<nsString>& aLanguages) {
+void Navigator::GetAcceptLanguages(const nsString* aLanguageOverride, nsTArray<nsString>& aLanguages) {
MOZ_ASSERT(NS_IsMainThread());
aLanguages.Clear();
// E.g. "de-de, en-us,en".
nsAutoString acceptLang;
- Preferences::GetLocalizedString("intl.accept_languages", acceptLang);
+ if (aLanguageOverride && aLanguageOverride->Length())
+ acceptLang = *aLanguageOverride;
+ else
+ Preferences::GetLocalizedString("intl.accept_languages", acceptLang);
+
// Split values on commas.
for (nsDependentSubstring lang :
@@ -406,7 +410,13 @@ void Navigator::GetLanguage(nsAString& aLanguage) {
}
void Navigator::GetLanguages(nsTArray<nsString>& aLanguages) {
- GetAcceptLanguages(aLanguages);
+ if (mWindow && mWindow->GetDocShell()) {
+ nsString languageOverride;
+ mWindow->GetDocShell()->GetLanguageOverride(languageOverride);
+ GetAcceptLanguages(&languageOverride, aLanguages);
+ } else {
+ GetAcceptLanguages(nullptr, aLanguages);
+ }
// The returned value is cached by the binding code. The window listens to the
// accept languages change and will clear the cache when needed. It has to
@@ -2309,7 +2319,8 @@ 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
@@ -220,7 +220,7 @@ class Navigator final : public nsISupports, public nsWrapperCache {
StorageManager* Storage();
- static void GetAcceptLanguages(nsTArray<nsString>& aLanguages);
+ static void GetAcceptLanguages(const nsString* aLanguageOverride, nsTArray<nsString>& aLanguages);
dom::MediaCapabilities* MediaCapabilities();
dom::MediaSession* MediaSession();
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
index 787d4c4e22715a72197e5d06831bd6d284129c2c..75fc73ce2863f994ce703b0f822acb924bee4f3d 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -9432,11 +9432,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<WidgetMouseEvent::ExitFrom> exitFrom;
bool contextMenuKey = false;
+ bool isPWDragEventMessage = false;
if (aType.EqualsLiteral("mousedown")) {
msg = eMouseDown;
} else if (aType.EqualsLiteral("mouseup")) {
@@ -9462,6 +9464,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;
}
@@ -9472,7 +9480,14 @@ nsresult nsContentUtils::SendMouseEvent(
Maybe<WidgetPointerEvent> pointerEvent;
Maybe<WidgetMouseEvent> mouseEvent;
- if (IsPointerEventMessage(msg)) {
+ Maybe<WidgetDragEvent> 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)) {
@@ -9491,8 +9506,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;
@@ -9505,6 +9523,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 7d89626774660fb9e0f564808270e3059e4d7b3c..c7f748e6f33cbcd72b0c97d437b2abbcbe4242be 100644
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -3078,8 +3078,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 e85140d5afebf57cf56bf16ef0c43c425c8d50c7..3062737c3319e35cdc4786c06750a1ac2a99565f 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> 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 a8a48d28fc4ef612f8234bc2490a41672f1704f5..f702b0c9a0783ec547a41bbefd68e18a27a239fe 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 be89a1c984982ea005e9bf7f440f5c8a2e8bab55..f8154882b9af02c5e9d7181e7a15b78824be8df9 100644
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -1719,6 +1719,10 @@ Maybe<uint64_t> 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)) {
@@ -2305,6 +2309,7 @@ bool nsFocusManager::BlurImpl(BrowsingContext* aBrowsingContextToClear,
bool aIsLeavingDocument, bool aAdjustWidget,
bool aRemainActive, Element* aElementToFocus,
uint64_t aActionId) {
+
LOGFOCUS(("<<Blur begin actionid: %" PRIu64 ">>", aActionId));
// hold a reference to the focused content, which may be null
@@ -2351,6 +2356,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> presShell = docShell->GetPresShell();
@@ -3061,7 +3071,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 42ee50b53a666c05c6540a1ddcf3745694aaed2d..b15150f7d2e293c2e338f8cd3ada927c052b30b2 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<nsIObserverService> observerService =
+ mozilla::services::GetObserverService();
+ if (observerService && mDoc) {
+ nsIPrincipal* principal = mDoc->NodePrincipal();
+ if (!principal->IsSystemPrincipal()) {
+ observerService->NotifyObservers(static_cast<nsIDOMWindow*>(this),
+ "juggler-dom-window-reused",
+ nullptr);
+ }
+ }
+}
+
void nsGlobalWindowOuter::ClearStatus() { SetStatusOuter(u""_ns); }
void nsGlobalWindowOuter::SetDocShell(nsDocShell* aDocShell) {
diff --git a/dom/base/nsGlobalWindowOuter.h b/dom/base/nsGlobalWindowOuter.h
index a846e57a8786e77e055d17474c5d910a6844cd5f..02815da6a94e98d452e8b4781a998fc0d5ed1124 100644
--- a/dom/base/nsGlobalWindowOuter.h
+++ b/dom/base/nsGlobalWindowOuter.h
@@ -320,6 +320,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 7d5e58f27b2ae07f8e8ac23c6d12bf90d2fdd8b7..2510572d9bfe8ea2909c48d9c3e86aa02c69e28e 100644
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -1498,6 +1498,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> 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<DOMQuad> nsINode::ConvertQuadFromNode(
DOMQuad& aQuad, const GeometryNode& aFrom,
const ConvertCoordinateOptions& aOptions, CallerType aCallerType,
diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h
index 6a982b3f278bf810dd582b3d5ebc33967323047e..4e991ef317c572c4a79c053d468f14df6c8880b5 100644
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -2417,6 +2417,10 @@ class nsINode : public mozilla::dom::EventTarget {
nsTArray<RefPtr<DOMQuad>>& aResult,
ErrorResult& aRv);
+ void ScrollRectIntoViewIfNeeded(int32_t x, int32_t y,
+ int32_t w, int32_t h,
+ ErrorResult& aRv);
+
already_AddRefed<DOMQuad> ConvertQuadFromNode(
DOMQuad& aQuad, const TextOrElementOrDocument& aFrom,
const ConvertCoordinateOptions& aOptions, CallerType aCallerType,
diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp
index bf7eb34da03c0958de688deecb53b407d430f645..a2ec3b1b7e86f72bee38d890c0834abfe4be8637 100644
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -149,6 +149,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 7923fcfb3e70aabddf343ab3ec2f25313bbd227e..cf02ce032d11d85a13bcf91e93e98882eaa9f7c7 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.
*/
@@ -226,6 +246,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 2a29279a6d74770a2ec5cee80891bff9eadf1d13..bce59065615a33cf020aae4b20750ce8b1be66ce 100644
--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -702,6 +702,12 @@ already_AddRefed<Promise> 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 fcdddf2f772af305c68cc169ba891386a1dba982..d8b19d35719fff3f9c55c199718f4dc1d15cdfe9 100644
--- a/dom/fetch/FetchService.cpp
+++ b/dom/fetch/FetchService.cpp
@@ -268,6 +268,14 @@ RefPtr<FetchServicePromises> FetchService::FetchInstance::Fetch() {
false // IsTrackingFetch
);
+ /* --> Playwright: associate keep-alive fetch with the window */
+ if (mArgsType == FetchArgsType::MainThreadFetch) {
+ auto& args = mArgs.as<MainThreadFetchArgs>();
+ mFetchDriver->SetAssociatedBrowsingContextID(
+ args.mAssociatedBrowsingContextID);
+ }
+ /* <-- Playwright */
+
if (mArgsType == FetchArgsType::WorkerFetch) {
auto& args = mArgs.as<WorkerFetchArgs>();
mFetchDriver->SetWorkerScript(args.mWorkerScript);
diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp
index 9382c73dc527f3fb676e8ea3457a30eee2d9415f..f1785121db1de071ce5aa1a0ad38d3d603c486f7 100644
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -63,6 +63,7 @@
#include "mozilla/dom/Document.h"
#include "mozilla/dom/HTMLDataListElement.h"
#include "mozilla/dom/HTMLOptionElement.h"
+#include "nsDocShell.h"
#include "nsIFrame.h"
#include "nsRangeFrame.h"
#include "nsError.h"
@@ -816,6 +817,13 @@ nsresult HTMLInputElement::InitFilePicker(FilePickerType aType) {
return NS_ERROR_FAILURE;
}
+ nsCOMPtr<nsPIDOMWindowOuter> win = doc->GetWindow();
+ nsDocShell* docShell = win ? static_cast<nsDocShell*>(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 4cdfcaafa779ed402d02411f69c02ab0eb5b4e09..e69c837f7ec340a11e8ae9485cd5b714a3ea9a88 100644
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -374,6 +374,26 @@ interface nsIDOMWindowUtils : nsISupports {
[optional] in long aButtons,
[optional] in unsigned long aIdentifier);
+ /**
+ * 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 310e22a130612c055f7642d813b2bc06538c8797..8528cd75252c6cf0bebe42ffbf83c0220551ba28 100644
--- a/dom/ipc/BrowserChild.cpp
+++ b/dom/ipc/BrowserChild.cpp
@@ -1760,6 +1760,21 @@ void BrowserChild::HandleRealMouseButtonEvent(const WidgetMouseEvent& aEvent,
if (postLayerization) {
postLayerization->Register();
}
+
+ // Playwright: notify content that mouse event has been received and handled.
+ nsCOMPtr<nsIObserverService> 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 31d56e5d4ea1f21b4b827c763d6e4b34432eeb7d..8537ae198faeec5fd5cced71995bbce9dccf90c4 100644
--- a/dom/ipc/CoalescedMouseData.cpp
+++ b/dom/ipc/CoalescedMouseData.cpp
@@ -71,6 +71,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<DesktopCaptureImpl>(aModuleId, aUniqueId,
- aType);
+ aType, aCaptureCursor);
}
static DesktopCaptureOptions CreateDesktopCaptureOptions() {
@@ -156,8 +157,10 @@ static std::unique_ptr<DesktopCapturer> CreateTabCapturer(
static std::unique_ptr<DesktopCapturer> 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<DesktopCapturer> 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<VideoCaptureModule::DeviceInfo>
CreateDeviceInfo(const int32_t aId,
@@ -66,6 +94,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback,
void DeRegisterCaptureDataCallback(
rtc::VideoSinkInterface<VideoFrame>* 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<DesktopCapturer> aCapturer, int aFramerate);
void UpdateOnThread(int aFramerate);
void ShutdownOnThread();
+
+ rtc::RecursiveCriticalSection mApiCs;
+ std::set<RawFrameCallback*> _rawFrameCallbacks;
// DesktopCapturer::Callback interface.
void OnCaptureResult(DesktopCapturer::Result aResult,
std::unique_ptr<DesktopFrame> 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<nsISerialEventTarget> 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<JSObject*> proto(cx);
+ JS::RootedObject rootedGlobal(cx, globalObject);
+ if (!JS_GetPrototype(cx, rootedGlobal, &proto))
+ return global;
+ if (!proto || !xpc::IsSandboxPrototypeProxy(proto))
+ return global;
+ // If this is a sandbox associated with a DOMWindow via a
+ // sandboxPrototype, use that DOMWindow. This supports GreaseMonkey
+ // and JetPack content scripts.
+ proto = js::CheckedUnwrapDynamic(proto, cx, /* stopAtWindowProxy = */ false);
+ if (!proto)
+ return global;
+ return xpc::WindowGlobalOrNull(proto);
+}
+
// If the entry or incumbent global ends up being something that the subject
// principal doesn't subsume, we don't want to use it. This never happens on
// the web, but can happen with asymmetric privilege relationships (i.e.
@@ -177,7 +201,7 @@ static nsIGlobalObject* ClampToSubject(nsIGlobalObject* aGlobalOrNull) {
NS_ENSURE_TRUE(globalPrin, GetCurrentGlobal());
if (!nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller()
->SubsumesConsideringDomain(globalPrin)) {
- return GetCurrentGlobal();
+ return UnwrapSandboxGlobal(GetCurrentGlobal());
}
return aGlobalOrNull;
diff --git a/dom/security/nsCSPUtils.cpp b/dom/security/nsCSPUtils.cpp
index 40844c900fc64415e39f4d2dead4c490d5ec301b..f63d0fd6a6df7ea932ca4d4bb70dfbd7562b2fa0 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"
@@ -135,6 +136,11 @@ void CSP_ApplyMetaCSPToDoc(mozilla::dom::Document& aDoc,
return;
}
+ if (aDoc.GetDocShell() &&
+ nsDocShell::Cast(aDoc.GetDocShell())->IsBypassCSPEnabled()) {
+ return;
+ }
+
nsAutoString policyStr(
nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
aPolicyStr));
diff --git a/dom/webidl/GeometryUtils.webidl b/dom/webidl/GeometryUtils.webidl
index 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<DOMQuad> 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 76035deec8f20933800284211a07ff23e124c1b9..d46c22728c82c15ed6b5c9d3c57f8b8e2229212b 100644
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -1079,7 +1079,7 @@ void PrefLanguagesChanged(const char* /* aPrefName */, void* /* aClosure */) {
AssertIsOnMainThread();
nsTArray<nsString> languages;
- Navigator::GetAcceptLanguages(languages);
+ Navigator::GetAcceptLanguages(nullptr, languages);
RuntimeService* runtime = RuntimeService::GetService();
if (runtime) {
@@ -1269,8 +1269,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;
}
@@ -1898,6 +1897,13 @@ void RuntimeService::PropagateStorageAccessPermissionGranted(
}
}
+void RuntimeService::ResetDefaultLocaleInAllWorkers() {
+ AssertIsOnMainThread();
+ BroadcastAllWorkers([](auto& worker) {
+ worker.ResetDefaultLocale();
+ });
+}
+
template <typename Func>
void RuntimeService::BroadcastAllWorkers(const Func& aFunc) {
AssertIsOnMainThread();
@@ -2438,6 +2444,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 b17efeafac1df3653ed9659e506c3d582044e2d0..3dc739c3b72980daf8a99190123920d0096da00c 100644
--- a/dom/workers/RuntimeService.h
+++ b/dom/workers/RuntimeService.h
@@ -112,6 +112,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 c928f8292a29ce7b53dd45aec4abc107263b1c8f..e11fdf6159623b2232e51160efbcbb6df5b6ed89 100644
--- a/dom/workers/WorkerCommon.h
+++ b/dom/workers/WorkerCommon.h
@@ -47,6 +47,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 e19f398e2672a6ffe07f53c820dd53c3210dd8b1..8dba789845e910986d3240f317a8749a37cd50b6 100644
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -755,6 +755,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<nsString> mLanguages;
@@ -2401,6 +2413,16 @@ void WorkerPrivate::UpdateContextOptions(
}
}
+void WorkerPrivate::ResetDefaultLocale() {
+ AssertIsOnParentThread();
+
+ RefPtr<ResetDefaultLocaleRunnable> runnable =
+ new ResetDefaultLocaleRunnable(this);
+ if (!runnable->Dispatch(this)) {
+ NS_WARNING("Failed to reset default locale in worker!");
+ }
+}
+
void WorkerPrivate::UpdateLanguages(const nsTArray<nsString>& aLanguages) {
AssertIsOnParentThread();
@@ -6374,6 +6396,15 @@ void WorkerPrivate::UpdateContextOptionsInternal(
}
}
+void WorkerPrivate::ResetDefaultLocaleInternal(JSContext* aCx) {
+ JS_ResetDefaultLocale(JS_GetRuntime(aCx));
+ auto data = mWorkerThreadAccessible.Access();
+
+ for (uint32_t index = 0; index < data->mChildWorkers.Length(); index++) {
+ data->mChildWorkers[index]->ResetDefaultLocale();
+ }
+}
+
void WorkerPrivate::UpdateLanguagesInternal(
const nsTArray<nsString>& aLanguages) {
WorkerGlobalScope* globalScope = GlobalScope();
diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h
index d887a9ca510730aef61d71c6f8b2e58c3762e5df..7ffe86c8ec792558e3d83e5b7ca8fccd39147385 100644
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -453,6 +453,8 @@ class WorkerPrivate final
void UpdateContextOptionsInternal(JSContext* aCx,
const JS::ContextOptions& aContextOptions);
+ void ResetDefaultLocaleInternal(JSContext* aCx);
+
void UpdateLanguagesInternal(const nsTArray<nsString>& aLanguages);
void UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key,
@@ -1099,6 +1101,8 @@ class WorkerPrivate final
void UpdateContextOptions(const JS::ContextOptions& aContextOptions);
+ void ResetDefaultLocale();
+
void UpdateLanguages(const nsTArray<nsString>& aLanguages);
void UpdateJSWorkerMemoryParameter(JSGCParamKey key, Maybe<uint32_t> value);
diff --git a/intl/components/src/TimeZone.cpp b/intl/components/src/TimeZone.cpp
index 7a069ef0c59895cf1f8dc35d612f1494c9c9f1ef..5b09dfdcc5323def65c35b0696141b44eef9dcda 100644
--- a/intl/components/src/TimeZone.cpp
+++ b/intl/components/src/TimeZone.cpp
@@ -16,6 +16,7 @@
namespace mozilla::intl {
+
/* static */
Result<UniquePtr<TimeZone>, ICUError> TimeZone::TryCreate(
Maybe<Span<const char16_t>> aTimeZoneOverride) {
@@ -318,6 +319,13 @@ static ICUResult SetDefaultTimeZone(TimeZoneIdentifierVector& timeZone) {
}
#endif
+bool TimeZone::IsValidTimeZoneId(const char* timeZoneId) {
+ // Validate timezone id.
+ mozilla::UniquePtr<icu::TimeZone> timeZone(icu::TimeZone::createTimeZone(
+ icu::UnicodeString(timeZoneId, -1, US_INV)));
+ return timeZone && *timeZone != icu::TimeZone::getUnknown();
+}
+
Result<bool, ICUError> TimeZone::SetDefaultTimeZone(
Span<const char> aTimeZone) {
#if MOZ_INTL_USE_ICU_CPP_TIMEZONE
diff --git a/intl/components/src/TimeZone.h b/intl/components/src/TimeZone.h
index 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<Completion> DebuggerObject::call(JSContext* cx,
invokeArgs[i].set(args2[i]);
}
+ // Disable CSP for the scope of the call.
+ const JSSecurityCallbacks* securityCallbacks = JS_GetSecurityCallbacks(cx);
+ JS_SetSecurityCallbacks(cx, nullptr);
ok = js::Call(cx, calleev, thisv, invokeArgs, &result);
+ JS_SetSecurityCallbacks(cx, securityCallbacks);
}
}
diff --git a/js/src/vm/DateTime.cpp b/js/src/vm/DateTime.cpp
index a57b8fefa104f966393a99f5a81876b9a95f9743..adc42dd227e52643b06fb101170aeafb490c0acc 100644
--- a/js/src/vm/DateTime.cpp
+++ b/js/src/vm/DateTime.cpp
@@ -185,6 +185,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);
@@ -528,10 +533,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) {
@@ -749,6 +768,15 @@ static bool ReadTimeZoneLink(std::string_view tz,
void js::DateTimeInfo::internalResyncICUDefaultTimeZone() {
#if JS_HAS_INTL_API
+ if (!timeZoneOverride_.empty()) {
+ mozilla::Span<const char> tzid = mozilla::Span(timeZoneOverride_.data(), timeZoneOverride_.length());
+ auto result = mozilla::intl::TimeZone::SetDefaultTimeZone(tzid);
+ if (result.isErr()) {
+ fprintf(stderr, "ERROR: failed to setup default time zone\n");
+ }
+ return;
+ }
+
// 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
@@ -760,7 +788,6 @@ void js::DateTimeInfo::internalResyncICUDefaultTimeZone() {
if (const char* tzenv = std::getenv("TZ")) {
std::string_view tz(tzenv);
-
mozilla::Span<const char> tzid;
# if defined(XP_WIN)
diff --git a/js/src/vm/DateTime.h b/js/src/vm/DateTime.h
index e3cf82daa3749664aa8ced7e6553b8c6434dfec8..b45b49c4f3bbf12853c4afb12de21d99ac88d77b 100644
--- a/js/src/vm/DateTime.h
+++ b/js/src/vm/DateTime.h
@@ -65,6 +65,8 @@ enum class ResetTimeZoneMode : bool {
*/
extern void ResetTimeZoneInternal(ResetTimeZoneMode mode);
+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
@@ -253,6 +255,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) {
{
@@ -352,6 +355,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
@@ -367,6 +372,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 4bfd336ddcbee8004ac538ca7b7d8216d04a61c3..cd22351c4aeacea8afc9828972222aca1b3063bf 100644
--- a/layout/base/GeometryUtils.cpp
+++ b/layout/base/GeometryUtils.cpp
@@ -23,6 +23,7 @@
#include "nsContentUtils.h"
#include "nsCSSFrameConstructor.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<RefPtr<DOMQuad>>& 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 1922382f924e74dde81501540d38699dcf3d9e57..c05b9ed071a9a4c99e2afb28eef0dba376777976 100644
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -11881,7 +11881,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 bc5b7ab177070178d1a3c49b563df0f04860e7d3..393f694c766bec5e5443d91922a8bc3524ade676 100644
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -708,6 +708,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();
@@ -9773,6 +9777,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 4cdceba041ddc5af98982d27b6e622a0dd5d0e34..50f644a91923e529ff06a164256f5704e5c4d8ae 100644
--- a/layout/style/GeckoBindings.h
+++ b/layout/style/GeckoBindings.h
@@ -594,6 +594,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 d843c5952e273c64703af6e9f2528798e3ada307..50dcfd6839777dd0ed9f806dfac3e1a4b0102efa 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 c9d6cace8de545779ae9c4630973c5a920cd52c6..032a42b732179a951181f390199c2520fecd742b 100644
--- a/netwerk/base/LoadInfo.cpp
+++ b/netwerk/base/LoadInfo.cpp
@@ -792,7 +792,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(
@@ -2705,4 +2706,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 7946dacf862aa13da58c65aba3c72deef575dbba..eb307b58b5fda79fa44e5df94f1bcb4dfaa0a8b6 100644
--- a/netwerk/base/LoadInfo.h
+++ b/netwerk/base/LoadInfo.h
@@ -448,6 +448,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 dd8cc849fb3dd56d6e979cc3cbff96727f702d90..dd2d543977cd9543494c52e862552831d955fdb2 100644
--- a/netwerk/base/TRRLoadInfo.cpp
+++ b/netwerk/base/TRRLoadInfo.cpp
@@ -973,5 +973,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 1cfda408c33c16c75a74ea839ae3bde6142ac92b..b3951bc2df4d448e6c3b7e51bef2c0050e97a35d 100644
--- a/netwerk/base/nsILoadInfo.idl
+++ b/netwerk/base/nsILoadInfo.idl
@@ -1650,4 +1650,6 @@ interface nsILoadInfo : nsISupports
return static_cast<mozilla::dom::UserNavigationInvolvement>(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 c486793f79e2c8c248e25f7963ba4e2c08f553d2..f1e625c59ec79c1104fe9594dbf86d39f3293438 100644
--- a/netwerk/ipc/DocumentLoadListener.cpp
+++ b/netwerk/ipc/DocumentLoadListener.cpp
@@ -178,6 +178,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..787bf014d3bf0b8537f99bf5eb4074e100c78c18 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<nsINetworkInterceptController> 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<nsIChannel*>(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<bool> 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 af4c6482ad41ad67f41b93183c94d6f341fb4989..0a18827e53760b4132381fd0aff286ee69c460e7 100644
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -688,11 +688,9 @@ nsresult nsHttpChannel::OnBeforeConnect() {
// SecurityInfo.sys.mjs
mLoadInfo->SetHstsStatus(isSecureURI);
- RefPtr<mozilla::dom::BrowsingContext> 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;
}
@@ -805,9 +803,7 @@ nsresult nsHttpChannel::MaybeUseHTTPSRRForUpgrade(bool aShouldUpgrade,
return aStatus;
}
- RefPtr<mozilla::dom::BrowsingContext> bc;
- mLoadInfo->GetBrowsingContext(getter_AddRefs(bc));
- bool forceOffline = bc && bc->Top()->GetForceOffline();
+ bool forceOffline = IsForcedOffline();
if (mURI->SchemeIs("https") || aShouldUpgrade || !LoadUseHTTPSSVC() ||
forceOffline) {
@@ -1266,15 +1262,14 @@ nsresult nsHttpChannel::ContinueConnect() {
"CORS preflight must have been finished by the time we "
"do the rest of ContinueConnect");
- RefPtr<mozilla::dom::BrowsingContext> 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;
}
@@ -1316,7 +1311,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;
}
@@ -1421,12 +1416,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<mozilla::dom::BrowsingContext> bc;
- mLoadInfo->GetBrowsingContext(getter_AddRefs(bc));
-
if (gIOService->IsOffline() || mUpgradeProtocolCallback ||
!(mCaps & NS_HTTP_ALLOW_KEEPALIVE) ||
- (bc && bc->Top()->GetForceOffline())) {
+ IsForcedOffline()) {
return;
}
@@ -4198,9 +4190,6 @@ nsresult nsHttpChannel::OpenCacheEntryInternal(bool isHttps) {
uint32_t cacheEntryOpenFlags;
bool offline = gIOService->IsOffline();
- RefPtr<mozilla::dom::BrowsingContext> bc;
- mLoadInfo->GetBrowsingContext(getter_AddRefs(bc));
-
bool maybeRCWN = false;
nsAutoCString cacheControlRequestHeader;
@@ -4211,7 +4200,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) {
@@ -7315,6 +7304,20 @@ void nsHttpChannel::MaybeStartDNSPrefetch() {
}
}
+bool nsHttpChannel::IsForcedOffline() {
+ RefPtr<mozilla::dom::BrowsingContext> bc;
+ mLoadInfo->GetBrowsingContext(getter_AddRefs(bc));
+ if (bc && bc->Top()->GetForceOffline())
+ return true;
+
+ RefPtr<mozilla::dom::BrowsingContext> 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 fb16e050efea8d49cd315203bfc6a0779f34bb02..c7b5a9894cb993bd420a5407c1aefb4aacd35595 100644
--- a/netwerk/protocol/http/nsHttpChannel.h
+++ b/netwerk/protocol/http/nsHttpChannel.h
@@ -303,6 +303,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 324d71a1567ef2acbd5e9a008961e39a11445419..e76d57612f318b7ad325196684e2e57660008a94 100644
--- a/parser/html/nsHtml5TreeOpExecutor.cpp
+++ b/parser/html/nsHtml5TreeOpExecutor.cpp
@@ -1359,6 +1359,10 @@ void nsHtml5TreeOpExecutor::UpdateReferrerInfoFromMeta(
void nsHtml5TreeOpExecutor::AddSpeculationCSP(const nsAString& aCSP) {
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+ if (mDocShell && static_cast<nsDocShell*>(mDocShell.get())->IsBypassCSPEnabled()) {
+ return;
+ }
+
nsresult rv = NS_OK;
nsCOMPtr<nsIContentSecurityPolicy> preloadCsp = mDocument->GetPreloadCsp();
if (!preloadCsp) {
diff --git a/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<nsIMarionette> 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 7dc1cee243017e1647521b021424781532552d8c..47908d73a7a39a7f95ae8ea28362b4f29505508f 100644
--- a/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp
+++ b/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp
@@ -587,7 +587,7 @@ void PopulateLanguages() {
// sufficient to only collect this information as the other properties are
// just reformats of Navigator::GetAcceptLanguages.
nsTArray<nsString> 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 316a86d5fcadba99918254ba132f363fb462cc3f..9dcd1b208ffd2d42db6c8ff52476a22791149eb4 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<nsISimpleEnumerator> windowEnumerator;
nsCOMPtr<nsIWindowMediator> mediator(
do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
- if (mediator) {
+ if (ferocity != eForceQuit && mediator) {
mediator->GetEnumerator(nullptr, getter_AddRefs(windowEnumerator));
if (windowEnumerator) {
bool more;
diff --git a/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp b/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp
index 89f7233835b4d03e7a140ca2c75ed8db097d482d..ed7c92d30b3cd77c102467eb0f12c9f482a08fde 100644
--- a/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp
+++ b/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp
@@ -174,8 +174,8 @@ nsBrowserStatusFilter::OnStateChange(nsIWebProgress* aWebProgress,
}
NS_IMETHODIMP
-nsBrowserStatusFilter::OnProgressChange(nsIWebProgress* aWebProgress,
- nsIRequest* aRequest,
+nsBrowserStatusFilter::OnProgressChange(nsIWebProgress *aWebProgress,
+ nsIRequest *aRequest,
int32_t aCurSelfProgress,
int32_t aMaxSelfProgress,
int32_t aCurTotalProgress,
diff --git a/toolkit/components/windowwatcher/nsWindowWatcher.cpp b/toolkit/components/windowwatcher/nsWindowWatcher.cpp
index 811fb16410e8cf900ad873797269e5fe715579a5..821f5b0c2af8e1dc8754cd023571d1d0ff09eeb6 100644
--- a/toolkit/components/windowwatcher/nsWindowWatcher.cpp
+++ b/toolkit/components/windowwatcher/nsWindowWatcher.cpp
@@ -1880,7 +1880,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 26d633f4f4fe9125df557ee7367809c8591d7211..6c558e8297114ac3f94ae3836c25e9edd51cc4d4 100644
--- a/toolkit/mozapps/update/UpdateService.sys.mjs
+++ b/toolkit/mozapps/update/UpdateService.sys.mjs
@@ -3873,6 +3873,8 @@ export class UpdateService {
}
get disabledForTesting() {
+ /* playwright */
+ return true;
return lazy.UpdateServiceStub.updateDisabledForTesting;
}
diff --git a/toolkit/toolkit.mozbuild b/toolkit/toolkit.mozbuild
index 304c39a11bd88e0b8cf681a3c3bc5dc11ed929ec..71e57ce2164e5436fac68d696b632d120a85d6f2 100644
--- a/toolkit/toolkit.mozbuild
+++ b/toolkit/toolkit.mozbuild
@@ -151,6 +151,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 <io.h>
#include <windows.h>
#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 444116840b68443c31d8df66699d47a582ce4622..9ae13a8462301a8a3024bffb10d9a20f9accff1d 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<nsIObserverService> os = mozilla::services::GetObserverService();
+ if (os) {
+ nsIPrincipal* principal = doc->NodePrincipal();
+ if (!principal->IsSystemPrincipal())
+ os->NotifyObservers(ToSupports(doc), "juggler-document-open-loaded", nullptr);
+ }
// This is a very cut-down version of
// nsDocumentViewer::LoadComplete that doesn't do various things
// that are not relevant here because this wasn't an actual
diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp
index 7cd8c24d871465bc96fe7249eb9a41c999057eb5..02b3ce1fbaa8056219a139a3bc3f107343f9bb89 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);
@@ -1486,7 +1493,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);
@@ -1671,7 +1683,36 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) {
return NS_OK;
}
- rv = SetUpTempFile(aChannel);
+ bool isIntercepted = false;
+ nsCOMPtr<nsIDownloadInterceptor> interceptor = mExtProtSvc->mInterceptor;
+ if (interceptor) {
+ nsCOMPtr<nsIFile> fileToUse;
+ rv = interceptor->InterceptDownloadRequest(this, request, mBrowsingContext, getter_AddRefs(fileToUse), &isIntercepted);
+ if (!NS_SUCCEEDED(rv)) {
+ LOG((" failed to call nsIDowloadInterceptor.interceptDownloadRequest"));
+ return rv;
+ }
+ if (isIntercepted) {
+ LOG((" request interceped by nsIDowloadInterceptor"));
+ if (fileToUse) {
+ mTempFile = fileToUse;
+ rv = mTempFile->GetLeafName(mTempLeafName);
+ NS_ENSURE_SUCCESS(rv, rv);
+ } else {
+ Cancel(NS_BINDING_ABORTED);
+ return NS_OK;
+ }
+ }
+ }
+
+ // Temp file is the final destination when download is intercepted. In that
+ // case we only need to create saver (and not create transfer later). Not creating
+ // mTransfer also cuts off all downloads handling logic in the js compoenents and
+ // browser UI.
+ if (isIntercepted)
+ rv = CreateSaverForTempFile();
+ else
+ rv = SetUpTempFile(aChannel);
if (NS_FAILED(rv)) {
nsresult transferError = rv;
@@ -1732,6 +1773,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
@@ -2248,6 +2292,16 @@ nsExternalAppHandler::OnSaveComplete(nsIBackgroundFileSaver* aSaver,
NotifyTransfer(aStatus);
}
+ if (!mCanceled) {
+ nsCOMPtr<nsIDownloadInterceptor> interceptor = mExtProtSvc->mInterceptor;
+ if (interceptor) {
+ nsCString noError;
+ nsresult rv = interceptor->OnDownloadComplete(this, noError);
+ MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to call nsIDowloadInterceptor.OnDownloadComplete");
+ Unused << rv;
+ }
+ }
+
return NS_OK;
}
@@ -2731,6 +2785,15 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason) {
}
}
+ nsCOMPtr<nsIDownloadInterceptor> interceptor = mExtProtSvc->mInterceptor;
+ if (interceptor) {
+ nsCString errorName;
+ GetErrorName(aReason, errorName);
+ nsresult rv = interceptor->OnDownloadComplete(this, errorName);
+ MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed notify nsIDowloadInterceptor about cancel");
+ Unused << rv;
+ }
+
// Break our reference cycle with the helper app dialog (set up in
// OnStartRequest)
mDialog = nullptr;
diff --git a/uriloader/exthandler/nsExternalHelperAppService.h b/uriloader/exthandler/nsExternalHelperAppService.h
index 68f240c9f9280c498900561e6cdb3bc4c4d45a38..395f54e8c47d56b0892c75a513e5828de7e4fceb 100644
--- a/uriloader/exthandler/nsExternalHelperAppService.h
+++ b/uriloader/exthandler/nsExternalHelperAppService.h
@@ -254,6 +254,8 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService,
mozilla::dom::BrowsingContext* aContentContext, bool aForceSave,
nsIInterfaceRequestor* aWindowContext,
nsIStreamListener** aStreamListener);
+
+ nsCOMPtr<nsIDownloadInterceptor> mInterceptor;
};
/**
@@ -451,6 +453,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 53ea934dd4876e4b491b724385c8fbf7d00ee6cd..0b7b88c853b21ce778d8e87fea0a2bfe839ad412 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
@@ -4,7 +4,10 @@
#include "InProcessCompositorWidget.h"
+#include "HeadlessCompositorWidget.h"
+#include "HeadlessWidget.h"
#include "mozilla/VsyncDispatcher.h"
+#include "mozilla/widget/PlatformWidgetTypes.h"
#include "nsBaseWidget.h"
namespace mozilla {
@@ -23,6 +26,12 @@ RefPtr<CompositorWidget> CompositorWidget::CreateLocal(
// do it after the static_cast.
nsBaseWidget* widget = static_cast<nsBaseWidget*>(aWidget);
MOZ_RELEASE_ASSERT(widget);
+ if (aInitData.type() ==
+ CompositorWidgetInitData::THeadlessCompositorWidgetInitData) {
+ return new HeadlessCompositorWidget(
+ aInitData.get_HeadlessCompositorWidgetInitData(), aOptions,
+ static_cast<HeadlessWidget*>(aWidget));
+ }
return new InProcessCompositorWidget(aOptions, widget);
}
#endif
diff --git a/widget/MouseEvents.h b/widget/MouseEvents.h
index 8004d6fe2130246252e57198f2ea731f84d1968a..7a0774b8320741108dc209c3b7069f524b1360ca 100644
--- a/widget/MouseEvents.h
+++ b/widget/MouseEvents.h
@@ -375,6 +375,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;
@@ -398,6 +401,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 @@
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 @@
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 @@
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 @@
!aEvent.IsShift()
? ToObjcSelectorPtr(@selector(moveToBeginningOfDocument:))
: ToObjcSelectorPtr(
- @selector(moveToBegginingOfDocumentAndModifySelection:)),
+ @selector(moveToBeginningOfDocumentAndModifySelection:)),
aCommands);
break;
}
@@ -630,6 +648,10 @@
break;
case KEY_NAME_INDEX_ArrowDown:
if (aEvent.IsControl()) {
+ if (aEvent.IsMeta() || aEvent.IsAlt())
+ break;
+ instance->AppendEditCommandsForSelector(
+ ToObjcSelectorPtr(@selector(scrollPageDown:)), aCommands);
break;
}
if (aEvent.IsMeta()) {
diff --git a/widget/gtk/nsFilePicker.cpp b/widget/gtk/nsFilePicker.cpp
index 02b7b185caf4a2352522c0ed4185d89b514c1738..912a270b6d87e1154d844bde2ffe6a3c2b8f3061 100644
--- a/widget/gtk/nsFilePicker.cpp
+++ b/widget/gtk/nsFilePicker.cpp
@@ -21,6 +21,7 @@
#include "mozilla/Components.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/Promise.h"
+#include "gfxPlatform.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<gfx::DrawTarget> HeadlessCompositorWidget::StartRemoteDrawingInRegion(
+ const LayoutDeviceIntRegion& aInvalidRegion) {
+ if (!mDrawTarget)
+ return nullptr;
+
+ RefPtr<gfx::DrawTarget> result = mDrawTarget;
+ return result.forget();
+}
+
void HeadlessCompositorWidget::ObserveVsync(VsyncObserver* aObserver) {
if (RefPtr<CompositorVsyncDispatcher> cvd =
mWidget->GetCompositorVsyncDispatcher()) {
@@ -31,6 +53,59 @@ void HeadlessCompositorWidget::NotifyClientSizeChanged(
const LayoutDeviceIntSize& aClientSize) {
auto size = mClientSize.Lock();
*size = aClientSize;
+ layers::CompositorThread()->Dispatch(NewRunnableMethod<LayoutDeviceIntSize>(
+ "HeadlessCompositorWidget::UpdateDrawTarget", this,
+ &HeadlessCompositorWidget::UpdateDrawTarget,
+ aClientSize));
+}
+
+void HeadlessCompositorWidget::UpdateDrawTarget(const LayoutDeviceIntSize& aClientSize) {
+ MOZ_ASSERT(NS_IsInCompositorThread());
+ if (aClientSize.IsEmpty()) {
+ mDrawTarget = nullptr;
+ return;
+ }
+
+ RefPtr<gfx::DrawTarget> old = std::move(mDrawTarget);
+ gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8;
+ gfx::IntSize size = aClientSize.ToUnknownSize();
+ mDrawTarget = mozilla::gfx::Factory::CreateDrawTarget(
+ mozilla::gfx::BackendType::SKIA, size, format);
+ if (old) {
+ RefPtr<gfx::SourceSurface> snapshot = old->Snapshot();
+ if (snapshot)
+ mDrawTarget->CopySurface(snapshot.get(), old->GetRect(), gfx::IntPoint(0, 0));
+ }
+}
+
+void HeadlessCompositorWidget::PeriodicSnapshot() {
+ ReentrantMonitorAutoEnter lock(mMon);
+ if (!mSnapshotListener)
+ return;
+
+ TakeSnapshot();
+ NS_DelayedDispatchToCurrentThread(NewRunnableMethod(
+ "HeadlessCompositorWidget::PeriodicSnapshot", this,
+ &HeadlessCompositorWidget::PeriodicSnapshot), 40);
+}
+
+void HeadlessCompositorWidget::TakeSnapshot() {
+ if (!mDrawTarget)
+ return;
+
+ RefPtr<gfx::SourceSurface> snapshot = mDrawTarget->Snapshot();
+ if (!snapshot) {
+ fprintf(stderr, "Failed to get snapshot of draw target\n");
+ return;
+ }
+
+ RefPtr<gfx::DataSourceSurface> dataSurface = snapshot->GetDataSurface();
+ if (!dataSurface) {
+ fprintf(stderr, "Failed to get data surface from snapshot\n");
+ return;
+ }
+
+ mSnapshotListener(std::move(dataSurface));
}
LayoutDeviceIntSize HeadlessCompositorWidget::GetClientSize() {
diff --git a/widget/headless/HeadlessCompositorWidget.h b/widget/headless/HeadlessCompositorWidget.h
index 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<gfx::DrawTarget> 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<LayoutDeviceIntSize> mClientSize;
+
+ HeadlessWidget::SnapshotListener mSnapshotListener;
+ RefPtr<gfx::DrawTarget> mDrawTarget;
};
} // namespace widget
diff --git a/widget/headless/HeadlessWidget.cpp b/widget/headless/HeadlessWidget.cpp
index daa2d455374fd9f75a5c6ac9f7b91696d88b065c..f45184137b52db0a5774bf3365b15f784532fbdf 100644
--- a/widget/headless/HeadlessWidget.cpp
+++ b/widget/headless/HeadlessWidget.cpp
@@ -111,6 +111,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 39833c28e40c61e354119cde429b8389056bafac..a638fb7520b857219ce58fcbf9ca0ed939528924 100644
--- a/widget/headless/HeadlessWidget.h
+++ b/widget/headless/HeadlessWidget.h
@@ -132,6 +132,9 @@ class HeadlessWidget final : public nsBaseWidget {
int32_t aModifierFlags,
nsIObserver* aObserver) override;
+ using SnapshotListener = std::function<void(RefPtr<gfx::DataSourceSurface>&&)>;
+ void SetSnapshotListener(SnapshotListener&& listener);
+
private:
~HeadlessWidget();
bool mEnabled;
diff --git a/widget/nsGUIEventIPC.h b/widget/nsGUIEventIPC.h
index f7262978239665cbe20470da0790d4d177d4c501..70d11aca3d5b509cf5b37d626299a23fede73ba3 100644
--- a/widget/nsGUIEventIPC.h
+++ b/widget/nsGUIEventIPC.h
@@ -244,6 +244,7 @@ struct ParamTraits<mozilla::WidgetMouseEvent> {
aParam.mExitFrom.value()));
}
WriteParam(aWriter, aParam.mClickCount);
+ WriteParam(aWriter, aParam.mJugglerEventId);
}
static bool Read(MessageReader* aReader, paramType* aResult) {
@@ -268,6 +269,7 @@ struct ParamTraits<mozilla::WidgetMouseEvent> {
aResult->mExitFrom = Some(static_cast<paramType::ExitFrom>(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
/**