playwright/browser_patches/firefox/patches/bootstrap.diff

3337 lines
130 KiB
Diff
Raw Normal View History

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;
browser(firefox): properly initialize debugging pipe on windows (#5514) browser(firefox): properly initialize debugging pipe on windows Firefox on Windows has 2 launch modes: - default: a special "launcher process" is used to start browser as a sub-process - non-default: browser process starts right away Firefox has a logic to detect how successful was the use of the launcher process to do self-recovery when things go wrong. Namely: - when attempting to use launcher process, firefox records a timestamp of the attempt beginning - once the launcher process successfully launches browser sub-process, firefox records another timestamp of the completion On a new launch, firefox checks what timestamps are present. If there's a timestamp that signifies start of launcher process, but no successful timestamp, it decides that last "launcher process" use was not successful and falls back to launching browser right away. When launching 2 firefox processes right away, the first process uses attempts to use launcher process and records the first timestamp. At the same time, the second instance sees the first timestamp and doesn't see the second timestamp, and falls back to launching browser right away. Our debugging pipe code, however, does not support non-launcher-process code path. This patch adds support for remote debugging pipe in case of non-launcher-process startup. Drive-by: - disable crashreporter altogether - remove stray dcheck that breaks firefox debug compilation - disable compilation of firefox update agent - do not use WIN32_DISTRIB flag unless doing full builds since it kills incremental compilation References #4660
2021-02-20 02:32:47 +08:00
+ 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;
2019-11-19 10:18:28 +08:00
diff --git a/browser/installer/allowed-dupes.mn b/browser/installer/allowed-dupes.mn
index a315ebcb8b60875b4eddbb5d654764603e0e7bec..fa67db1ff5a331dda4eaff4457418c306869d011 100644
2019-11-19 10:18:28 +08:00
--- 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
2019-11-19 10:18:28 +08:00
+# 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
2019-11-19 10:18:28 +08:00
diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in
index 6ebf2f62c47757f16841d04c164d2d86447fcbd0..cae3f3ac6f6ced0b59fe850643bbb90d619750d0 100644
2019-11-19 10:18:28 +08:00
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -192,6 +192,9 @@
@RESPATH@/chrome/remote.manifest
2019-11-19 10:18:28 +08:00
#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);
}
2019-11-19 10:18:28 +08:00
diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
index 5bcbbfbcb522adb9988ba421a4f590ee2105e1d3..cb9bc09a7901334b6ba73834971498f4472cce2d 100644
2019-11-19 10:18:28 +08:00
--- 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;
2019-11-19 10:18:28 +08:00
diff --git a/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp b/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp
index 89f7233835b4d03e7a140ca2c75ed8db097d482d..ed7c92d30b3cd77c102467eb0f12c9f482a08fde 100644
2019-11-19 10:18:28 +08:00
--- a/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp
+++ b/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp
@@ -174,8 +174,8 @@ nsBrowserStatusFilter::OnStateChange(nsIWebProgress* aWebProgress,
2019-11-19 10:18:28 +08:00
}
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;
}
2019-11-19 10:18:28 +08:00
diff --git a/toolkit/toolkit.mozbuild b/toolkit/toolkit.mozbuild
index 304c39a11bd88e0b8cf681a3c3bc5dc11ed929ec..71e57ce2164e5436fac68d696b632d120a85d6f2 100644
2019-11-19 10:18:28 +08:00
--- 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",
2019-11-19 10:18:28 +08:00
]
browser(firefox): properly initialize debugging pipe on windows (#5514) browser(firefox): properly initialize debugging pipe on windows Firefox on Windows has 2 launch modes: - default: a special "launcher process" is used to start browser as a sub-process - non-default: browser process starts right away Firefox has a logic to detect how successful was the use of the launcher process to do self-recovery when things go wrong. Namely: - when attempting to use launcher process, firefox records a timestamp of the attempt beginning - once the launcher process successfully launches browser sub-process, firefox records another timestamp of the completion On a new launch, firefox checks what timestamps are present. If there's a timestamp that signifies start of launcher process, but no successful timestamp, it decides that last "launcher process" use was not successful and falls back to launching browser right away. When launching 2 firefox processes right away, the first process uses attempts to use launcher process and records the first timestamp. At the same time, the second instance sees the first timestamp and doesn't see the second timestamp, and falls back to launching browser right away. Our debugging pipe code, however, does not support non-launcher-process code path. This patch adds support for remote debugging pipe in case of non-launcher-process startup. Drive-by: - disable crashreporter altogether - remove stray dcheck that breaks firefox debug compilation - disable compilation of firefox update agent - do not use WIN32_DISTRIB flag unless doing full builds since it kills incremental compilation References #4660
2021-02-20 02:32:47 +08:00
diff --git a/toolkit/xre/nsWindowsWMain.cpp b/toolkit/xre/nsWindowsWMain.cpp
index 7eb9e1104682d4eb47060654f43a1efa8b2a6bb2..a8315d6decf654b5302bea5beeea34140c300ded 100644
browser(firefox): properly initialize debugging pipe on windows (#5514) browser(firefox): properly initialize debugging pipe on windows Firefox on Windows has 2 launch modes: - default: a special "launcher process" is used to start browser as a sub-process - non-default: browser process starts right away Firefox has a logic to detect how successful was the use of the launcher process to do self-recovery when things go wrong. Namely: - when attempting to use launcher process, firefox records a timestamp of the attempt beginning - once the launcher process successfully launches browser sub-process, firefox records another timestamp of the completion On a new launch, firefox checks what timestamps are present. If there's a timestamp that signifies start of launcher process, but no successful timestamp, it decides that last "launcher process" use was not successful and falls back to launching browser right away. When launching 2 firefox processes right away, the first process uses attempts to use launcher process and records the first timestamp. At the same time, the second instance sees the first timestamp and doesn't see the second timestamp, and falls back to launching browser right away. Our debugging pipe code, however, does not support non-launcher-process code path. This patch adds support for remote debugging pipe in case of non-launcher-process startup. Drive-by: - disable crashreporter altogether - remove stray dcheck that breaks firefox debug compilation - disable compilation of firefox update agent - do not use WIN32_DISTRIB flag unless doing full builds since it kills incremental compilation References #4660
2021-02-20 02:32:47 +08:00
--- a/toolkit/xre/nsWindowsWMain.cpp
+++ b/toolkit/xre/nsWindowsWMain.cpp
@@ -14,8 +14,10 @@
browser(firefox): properly initialize debugging pipe on windows (#5514) browser(firefox): properly initialize debugging pipe on windows Firefox on Windows has 2 launch modes: - default: a special "launcher process" is used to start browser as a sub-process - non-default: browser process starts right away Firefox has a logic to detect how successful was the use of the launcher process to do self-recovery when things go wrong. Namely: - when attempting to use launcher process, firefox records a timestamp of the attempt beginning - once the launcher process successfully launches browser sub-process, firefox records another timestamp of the completion On a new launch, firefox checks what timestamps are present. If there's a timestamp that signifies start of launcher process, but no successful timestamp, it decides that last "launcher process" use was not successful and falls back to launching browser right away. When launching 2 firefox processes right away, the first process uses attempts to use launcher process and records the first timestamp. At the same time, the second instance sees the first timestamp and doesn't see the second timestamp, and falls back to launching browser right away. Our debugging pipe code, however, does not support non-launcher-process code path. This patch adds support for remote debugging pipe in case of non-launcher-process startup. Drive-by: - disable crashreporter altogether - remove stray dcheck that breaks firefox debug compilation - disable compilation of firefox update agent - do not use WIN32_DISTRIB flag unless doing full builds since it kills incremental compilation References #4660
2021-02-20 02:32:47 +08:00
#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) {
browser(firefox): properly initialize debugging pipe on windows (#5514) browser(firefox): properly initialize debugging pipe on windows Firefox on Windows has 2 launch modes: - default: a special "launcher process" is used to start browser as a sub-process - non-default: browser process starts right away Firefox has a logic to detect how successful was the use of the launcher process to do self-recovery when things go wrong. Namely: - when attempting to use launcher process, firefox records a timestamp of the attempt beginning - once the launcher process successfully launches browser sub-process, firefox records another timestamp of the completion On a new launch, firefox checks what timestamps are present. If there's a timestamp that signifies start of launcher process, but no successful timestamp, it decides that last "launcher process" use was not successful and falls back to launching browser right away. When launching 2 firefox processes right away, the first process uses attempts to use launcher process and records the first timestamp. At the same time, the second instance sees the first timestamp and doesn't see the second timestamp, and falls back to launching browser right away. Our debugging pipe code, however, does not support non-launcher-process code path. This patch adds support for remote debugging pipe in case of non-launcher-process startup. Drive-by: - disable crashreporter altogether - remove stray dcheck that breaks firefox debug compilation - disable compilation of firefox update agent - do not use WIN32_DISTRIB flag unless doing full builds since it kills incremental compilation References #4660
2021-02-20 02:32:47 +08:00
SanitizeEnvironmentVariables();
SetDllDirectoryW(L"");
+ bool hasJugglerPipe =
+ mozilla::CheckArg(argc, argv, "juggler-pipe", nullptr,
browser(firefox): properly initialize debugging pipe on windows (#5514) browser(firefox): properly initialize debugging pipe on windows Firefox on Windows has 2 launch modes: - default: a special "launcher process" is used to start browser as a sub-process - non-default: browser process starts right away Firefox has a logic to detect how successful was the use of the launcher process to do self-recovery when things go wrong. Namely: - when attempting to use launcher process, firefox records a timestamp of the attempt beginning - once the launcher process successfully launches browser sub-process, firefox records another timestamp of the completion On a new launch, firefox checks what timestamps are present. If there's a timestamp that signifies start of launcher process, but no successful timestamp, it decides that last "launcher process" use was not successful and falls back to launching browser right away. When launching 2 firefox processes right away, the first process uses attempts to use launcher process and records the first timestamp. At the same time, the second instance sees the first timestamp and doesn't see the second timestamp, and falls back to launching browser right away. Our debugging pipe code, however, does not support non-launcher-process code path. This patch adds support for remote debugging pipe in case of non-launcher-process startup. Drive-by: - disable crashreporter altogether - remove stray dcheck that breaks firefox debug compilation - disable compilation of firefox update agent - do not use WIN32_DISTRIB flag unless doing full builds since it kills incremental compilation References #4660
2021-02-20 02:32:47 +08:00
+ 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.
2019-11-19 10:18:28 +08:00
diff --git a/uriloader/base/nsDocLoader.cpp b/uriloader/base/nsDocLoader.cpp
index 444116840b68443c31d8df66699d47a582ce4622..9ae13a8462301a8a3024bffb10d9a20f9accff1d 100644
2019-11-19 10:18:28 +08:00
--- 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
/**