3184 lines
126 KiB
Diff
Raw Normal View History

diff --git a/accessible/base/NotificationController.h b/accessible/base/NotificationController.h
index 2f0428b53d5e1fc4fd97cbc6c0619edbe425e7bd..8e72e1b3d0f69ab613eb95bc1d4676dcaec5c6a9 100644
--- a/accessible/base/NotificationController.h
+++ b/accessible/base/NotificationController.h
@@ -245,6 +245,8 @@ class NotificationController final : public EventQueue,
}
#endif
+ bool IsUpdatePendingForJugglerAccessibility() { return IsUpdatePending(); }
+
protected:
virtual ~NotificationController();
diff --git a/accessible/interfaces/nsIAccessibleDocument.idl b/accessible/interfaces/nsIAccessibleDocument.idl
index a91df31c96afda66f478a5a38eaa4352039c2a0b..ee777c1746284027fb3aa2f1686f8082af9d89ee 100644
--- a/accessible/interfaces/nsIAccessibleDocument.idl
+++ b/accessible/interfaces/nsIAccessibleDocument.idl
@@ -72,4 +72,9 @@ interface nsIAccessibleDocument : nsISupports
* Return the child document accessible at the given index.
*/
nsIAccessibleDocument getChildDocumentAt(in unsigned long index);
+
+ /**
+ * Return whether it is updating.
+ */
+ readonly attribute boolean isUpdatePendingForJugglerAccessibility;
};
diff --git a/accessible/xpcom/xpcAccessibleDocument.cpp b/accessible/xpcom/xpcAccessibleDocument.cpp
index 1ddd5c8372c2742a8dc4e7a8156c084aaf2442fc..7e3aa30c20d8b2fcae5c12d293ca7772ecd28657 100644
--- a/accessible/xpcom/xpcAccessibleDocument.cpp
+++ b/accessible/xpcom/xpcAccessibleDocument.cpp
@@ -143,6 +143,15 @@ xpcAccessibleDocument::GetVirtualCursor(nsIAccessiblePivot** aVirtualCursor) {
return NS_OK;
}
+
+NS_IMETHODIMP
+xpcAccessibleDocument::GetIsUpdatePendingForJugglerAccessibility(bool* updating) {
+ NS_ENSURE_ARG_POINTER(updating);
+ *updating = Intl()->Controller()->IsUpdatePendingForJugglerAccessibility();
+ return NS_OK;
+}
+
+
////////////////////////////////////////////////////////////////////////////////
// xpcAccessibleDocument
diff --git a/accessible/xpcom/xpcAccessibleDocument.h b/accessible/xpcom/xpcAccessibleDocument.h
index 416a1c5497c97ed80cc0f37d72545e36f7e36b4c..b81983cf7153378260a21f6af225e3493f8f30dc 100644
--- a/accessible/xpcom/xpcAccessibleDocument.h
+++ b/accessible/xpcom/xpcAccessibleDocument.h
@@ -48,6 +48,8 @@ class xpcAccessibleDocument : public xpcAccessibleHyperText,
nsIAccessibleDocument** aDocument) final;
NS_IMETHOD GetVirtualCursor(nsIAccessiblePivot** aVirtualCursor) final;
+ NS_IMETHOD GetIsUpdatePendingForJugglerAccessibility(bool* aUpdating) final;
+
/**
* Return XPCOM wrapper for the internal accessible.
*/
diff --git a/browser/app/winlauncher/LauncherProcessWin.cpp b/browser/app/winlauncher/LauncherProcessWin.cpp
index 33b8ed52bff98c2216c16d47840fcd55907c414b..5a0320b4ad87055280c4fba4deb0cdc9b7557c50 100644
--- a/browser/app/winlauncher/LauncherProcessWin.cpp
+++ b/browser/app/winlauncher/LauncherProcessWin.cpp
@@ -24,6 +24,7 @@
#include "mozilla/WinHeaderOnlyUtils.h"
#include "nsWindowsHelpers.h"
+#include <io.h>
#include <windows.h>
#include <processthreadsapi.h>
@@ -430,8 +431,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-19 10: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-18 18:18:28 -08:00
diff --git a/browser/installer/allowed-dupes.mn b/browser/installer/allowed-dupes.mn
index 6ab29ba31e937e1c5bb1208a9a2508ff0496fd02..7989da51c5368fa80cc66cccdfc018a9b3fb2f38 100644
2019-11-18 18:18:28 -08:00
--- a/browser/installer/allowed-dupes.mn
+++ b/browser/installer/allowed-dupes.mn
@@ -67,6 +67,12 @@ browser/features/webcompat@mozilla.org/shims/empty-shim.txt
removed-files
#endif
2019-11-18 18: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
+
2019-11-18 18:18:28 -08:00
#ifdef MOZ_EME_WIN32_ARTIFACT
gmp-clearkey/0.1/manifest.json
i686/gmp-clearkey/0.1/manifest.json
diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in
index 8caff8de9465e44c3535448622386c9a0b8034c2..ea498cce8de6ee099fb36eb640590d0fdace081b 100644
2019-11-18 18:18:28 -08:00
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -195,6 +195,9 @@
@RESPATH@/chrome/remote.manifest
2019-11-18 18:18:28 -08:00
#endif
+@RESPATH@/chrome/juggler@JAREXT@
+@RESPATH@/chrome/juggler.manifest
+
; [Extensions]
@RESPATH@/components/extensions-toolkit.manifest
@RESPATH@/browser/components/extensions-browser.manifest
diff --git a/devtools/server/socket/websocket-server.js b/devtools/server/socket/websocket-server.js
index a32156978aacd7c8cbe9001250bfa1516dbc360f..ff03ff48b505ef8a9117671bf21e8b0e8214ec1f 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 b270badc02ec47c3995fda5c7e6ef2b81fe86150..6027542882ced5ffc55f2cc888cab161774bf90e 100644
--- a/docshell/base/BrowsingContext.cpp
+++ b/docshell/base/BrowsingContext.cpp
@@ -112,6 +112,20 @@ struct ParamTraits<mozilla::dom::PrefersColorSchemeOverride>
mozilla::dom::PrefersColorSchemeOverride::None,
mozilla::dom::PrefersColorSchemeOverride::EndGuard_> {};
+template <>
+struct ParamTraits<mozilla::dom::PrefersReducedMotionOverride>
+ : public ContiguousEnumSerializer<
+ mozilla::dom::PrefersReducedMotionOverride,
+ mozilla::dom::PrefersReducedMotionOverride::None,
+ mozilla::dom::PrefersReducedMotionOverride::EndGuard_> {};
+
+template <>
+struct ParamTraits<mozilla::dom::ForcedColorsOverride>
+ : public ContiguousEnumSerializer<
+ mozilla::dom::ForcedColorsOverride,
+ mozilla::dom::ForcedColorsOverride::None,
+ mozilla::dom::ForcedColorsOverride::EndGuard_> {};
+
template <>
struct ParamTraits<mozilla::dom::ExplicitActiveStatus>
: public ContiguousEnumSerializer<
@@ -2857,6 +2871,40 @@ void BrowsingContext::DidSet(FieldIndex<IDX_PrefersColorSchemeOverride>,
PresContextAffectingFieldChanged();
}
+void BrowsingContext::DidSet(FieldIndex<IDX_PrefersReducedMotionOverride>,
+ dom::PrefersReducedMotionOverride aOldValue) {
+ MOZ_ASSERT(IsTop());
+ if (PrefersReducedMotionOverride() == aOldValue) {
+ return;
+ }
+ PreOrderWalk([&](BrowsingContext* aContext) {
+ if (nsIDocShell* shell = aContext->GetDocShell()) {
+ if (nsPresContext* pc = shell->GetPresContext()) {
+ pc->MediaFeatureValuesChanged(
+ {MediaFeatureChangeReason::SystemMetricsChange},
+ MediaFeatureChangePropagation::JustThisDocument);
+ }
+ }
+ });
+}
+
+void BrowsingContext::DidSet(FieldIndex<IDX_ForcedColorsOverride>,
+ dom::ForcedColorsOverride aOldValue) {
+ MOZ_ASSERT(IsTop());
+ if (ForcedColorsOverride() == aOldValue) {
+ return;
+ }
+ PreOrderWalk([&](BrowsingContext* aContext) {
+ if (nsIDocShell* shell = aContext->GetDocShell()) {
+ if (nsPresContext* pc = shell->GetPresContext()) {
+ pc->MediaFeatureValuesChanged(
+ {MediaFeatureChangeReason::SystemMetricsChange},
+ MediaFeatureChangePropagation::JustThisDocument);
+ }
+ }
+ });
+}
+
void BrowsingContext::DidSet(FieldIndex<IDX_MediumOverride>,
nsString&& aOldValue) {
MOZ_ASSERT(IsTop());
diff --git a/docshell/base/BrowsingContext.h b/docshell/base/BrowsingContext.h
index 9fc591e0981d587b47f51d9a7c94e3ab8e54d06e..1d05700dc98422e7aed7236e6e5922e0e3501f24 100644
--- a/docshell/base/BrowsingContext.h
+++ b/docshell/base/BrowsingContext.h
@@ -190,10 +190,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) \
@@ -231,6 +231,10 @@ struct EmbedderColorSchemes {
* <browser> embedder element. */ \
FIELD(EmbedderColorSchemes, EmbedderColorSchemes) \
FIELD(DisplayMode, dom::DisplayMode) \
+ /* playwright addition */ \
+ FIELD(PrefersReducedMotionOverride, dom::PrefersReducedMotionOverride) \
+ /* playwright addition */ \
+ FIELD(ForcedColorsOverride, dom::ForcedColorsOverride) \
/* The number of entries added to the session history because of this \
* browsing context. */ \
FIELD(HistoryEntryCount, uint32_t) \
@@ -343,6 +347,10 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
bool IsOwnedByProcess() const;
+ uint64_t JugglerCurrentLoadIdentifier() const {
+ return GetCurrentLoadIdentifier() ? GetCurrentLoadIdentifier().value() : 0;
+ }
+
bool CanHaveRemoteOuterProxies() const {
return !mIsInProcess || mDanglingRemoteOuterProxies;
}
@@ -922,6 +930,14 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
return GetPrefersColorSchemeOverride();
}
+ dom::PrefersReducedMotionOverride PrefersReducedMotionOverride() const {
+ return GetPrefersReducedMotionOverride();
+ }
+
+ dom::ForcedColorsOverride ForcedColorsOverride() const {
+ return GetForcedColorsOverride();
+ }
+
bool IsInBFCache() const;
bool AllowJavascript() const { return GetAllowJavascript(); }
@@ -1081,6 +1097,23 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
void WalkPresContexts(Callback&&);
void PresContextAffectingFieldChanged();
+ bool CanSet(FieldIndex<IDX_PrefersReducedMotionOverride>,
+ dom::PrefersReducedMotionOverride, ContentParent*) {
+ return IsTop();
+ }
+
+ void DidSet(FieldIndex<IDX_PrefersReducedMotionOverride>,
+ dom::PrefersReducedMotionOverride aOldValue);
+
+
+ bool CanSet(FieldIndex<IDX_ForcedColorsOverride>,
+ dom::ForcedColorsOverride, ContentParent*) {
+ return IsTop();
+ }
+
+ void DidSet(FieldIndex<IDX_ForcedColorsOverride>,
+ dom::ForcedColorsOverride aOldValue);
+
void DidSet(FieldIndex<IDX_MediumOverride>, nsString&& aOldValue);
bool CanSet(FieldIndex<IDX_SuspendMediaWhenInactive>, bool, ContentParent*) {
diff --git a/docshell/base/CanonicalBrowsingContext.cpp b/docshell/base/CanonicalBrowsingContext.cpp
index fef6ea286b5a7c1f7756f1265b74ad27bd8c9917..2697e73023217314fbfaed8f8e5d204232d45cb6 100644
--- a/docshell/base/CanonicalBrowsingContext.cpp
+++ b/docshell/base/CanonicalBrowsingContext.cpp
@@ -1447,6 +1447,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-18 18:18:28 -08:00
diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
index 132ed5c9a9e89cf023a76e7280e2d471475bfc87..7f5a21b0087a823190c2049d165c7fc7dea6c956 100644
2019-11-18 18:18:28 -08:00
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -15,6 +15,12 @@
# include <unistd.h> // for getpid()
#endif
+#if JS_HAS_INTL_API && !MOZ_SYSTEM_ICU
+# include "unicode/locid.h"
+#endif /* JS_HAS_INTL_API && !MOZ_SYSTEM_ICU */
+
+#include "js/LocaleSensitive.h"
+
#include "mozilla/ArrayUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/AutoRestore.h"
@@ -65,6 +71,7 @@
#include "mozilla/dom/ContentFrameMessageManager.h"
#include "mozilla/dom/DocGroup.h"
#include "mozilla/dom/Element.h"
+#include "mozilla/dom/Geolocation.h"
#include "mozilla/dom/HTMLAnchorElement.h"
#include "mozilla/dom/HTMLIFrameElement.h"
#include "mozilla/dom/PerformanceNavigation.h"
@@ -90,6 +97,7 @@
#include "mozilla/dom/JSWindowActorChild.h"
#include "mozilla/dom/DocumentBinding.h"
#include "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/dom/WorkerCommon.h"
#include "mozilla/net/DocumentChannel.h"
#include "mozilla/net/DocumentChannelChild.h"
#include "mozilla/net/ParentChannelWrapper.h"
@@ -113,6 +121,7 @@
#include "nsIDocShellTreeOwner.h"
#include "mozilla/dom/Document.h"
#include "nsHTMLDocument.h"
+#include "mozilla/dom/Element.h"
#include "nsIDocumentLoaderFactory.h"
#include "nsIDOMWindow.h"
#include "nsIEditingSession.h"
@@ -207,6 +216,7 @@
#include "nsFocusManager.h"
#include "nsGlobalWindow.h"
#include "nsJSEnvironment.h"
+#include "nsJSUtils.h"
#include "nsNetCID.h"
#include "nsNetUtil.h"
#include "nsObjectLoadingContent.h"
@@ -349,6 +359,14 @@ nsDocShell::nsDocShell(BrowsingContext* aBrowsingContext,
mAllowDNSPrefetch(true),
mAllowWindowControl(true),
mCSSErrorReportingEnabled(false),
+ mFileInputInterceptionEnabled(false),
+ mOverrideHasFocus(false),
+ mBypassCSPEnabled(false),
+ mForceActiveState(false),
+ mDisallowBFCache(false),
+ mOnlineOverride(nsIDocShell::ONLINE_OVERRIDE_NONE),
+ mReducedMotionOverride(REDUCED_MOTION_OVERRIDE_NONE),
+ mForcedColorsOverride(FORCED_COLORS_OVERRIDE_NO_OVERRIDE),
mAllowAuth(mItemType == typeContent),
mAllowKeywordFixup(false),
mDisableMetaRefreshWhenInactive(false),
@@ -3246,6 +3264,234 @@ 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)
+ return;
+ UErrorCode error_code = U_ZERO_ERROR;
+ const char* lang = locale.getLanguage();
+ if (lang != nullptr && *lang != '\0') {
+ icu::Locale::setDefault(locale, error_code);
+ } else {
+ fprintf(stderr, "SetIcuLocale Failed to set the ICU default locale to %s\n", NS_LossyConvertUTF16toASCII(aLanguageOverride).get());
+ }
+
+ AutoJSAPI jsapi;
+ jsapi.Init();
+ JSContext* cx = jsapi.cx();
+ JS_ResetDefaultLocale(JS_GetRuntime(cx));
+
+ ResetDefaultLocaleInAllWorkers();
+}
+
+NS_IMETHODIMP
+nsDocShell::SetLanguageOverride(const nsAString& aLanguageOverride) {
+ mLanguageOverride = aLanguageOverride;
+ SetIcuLocale(aLanguageOverride);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::OverrideTimezone(const nsAString& aTimezoneOverride,
+ bool* aSuccess) {
+ NS_ENSURE_ARG(aSuccess);
+ NS_LossyConvertUTF16toASCII timeZoneId(aTimezoneOverride);
+ *aSuccess = nsJSUtils::SetTimeZoneOverride(timeZoneId.get());
+
+ // Set TZ which affects localtime_s().
+ auto setTimeZoneEnv = [](const char* value) {
+#if defined(_WIN32)
+ return _putenv_s("TZ", value) == 0;
+#else
+ return setenv("TZ", value, true) == 0;
+#endif /* _WIN32 */
+ };
+ if (*aSuccess) {
+ *aSuccess = setTimeZoneEnv(timeZoneId.get());
+ if (!*aSuccess) {
+ fprintf(stderr, "Failed to set 'TZ' to '%s'\n", timeZoneId.get());
+ }
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::GetFileInputInterceptionEnabled(bool* aEnabled) {
+ MOZ_ASSERT(aEnabled);
+ *aEnabled = GetRootDocShell()->mFileInputInterceptionEnabled;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetFileInputInterceptionEnabled(bool aEnabled) {
+ mFileInputInterceptionEnabled = aEnabled;
+ return NS_OK;
+}
+
+bool nsDocShell::IsFileInputInterceptionEnabled() {
+ return GetRootDocShell()->mFileInputInterceptionEnabled;
+}
+
+void nsDocShell::FilePickerShown(mozilla::dom::Element* element) {
+ nsCOMPtr<nsIObserverService> observerService =
+ mozilla::services::GetObserverService();
+ observerService->NotifyObservers(
+ ToSupports(element), "juggler-file-picker-shown", nullptr);
+}
+
+RefPtr<nsGeolocationService> nsDocShell::GetGeolocationServiceOverride() {
+ return GetRootDocShell()->mGeolocationServiceOverride;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetGeolocationOverride(nsIDOMGeoPosition* aGeolocationOverride) {
+ if (aGeolocationOverride) {
+ if (!mGeolocationServiceOverride) {
+ mGeolocationServiceOverride = new nsGeolocationService();
+ mGeolocationServiceOverride->Init();
+ }
+ mGeolocationServiceOverride->Update(aGeolocationOverride);
+ } else {
+ mGeolocationServiceOverride = nullptr;
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::GetOnlineOverride(OnlineOverride* aOnlineOverride) {
+ *aOnlineOverride = GetRootDocShell()->mOnlineOverride;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetOnlineOverride(OnlineOverride aOnlineOverride) {
+ // We don't have a way to verify this coming from Javascript, so this check is
+ // still needed.
+ if (!(aOnlineOverride == ONLINE_OVERRIDE_NONE ||
+ aOnlineOverride == ONLINE_OVERRIDE_ONLINE ||
+ aOnlineOverride == ONLINE_OVERRIDE_OFFLINE)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ mOnlineOverride = aOnlineOverride;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::GetReducedMotionOverride(ReducedMotionOverride* aReducedMotionOverride) {
+ *aReducedMotionOverride = GetRootDocShell()->mReducedMotionOverride;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetReducedMotionOverride(ReducedMotionOverride aReducedMotionOverride) {
+ mReducedMotionOverride = aReducedMotionOverride;
+ RefPtr<nsPresContext> presContext = GetPresContext();
+ if (presContext) {
+ presContext->MediaFeatureValuesChanged(
+ {MediaFeatureChangeReason::SystemMetricsChange},
+ MediaFeatureChangePropagation::JustThisDocument);
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::GetForcedColorsOverride(ForcedColorsOverride* aForcedColorsOverride) {
+ *aForcedColorsOverride = GetRootDocShell()->mForcedColorsOverride;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetForcedColorsOverride(ForcedColorsOverride aForcedColorsOverride) {
+ mForcedColorsOverride = aForcedColorsOverride;
+ RefPtr<nsPresContext> presContext = GetPresContext();
+ if (presContext) {
+ presContext->MediaFeatureValuesChanged(
+ {MediaFeatureChangeReason::SystemMetricsChange},
+ MediaFeatureChangePropagation::JustThisDocument);
+ }
+ return NS_OK;
+}
+
+// =============== Juggler End =======================
+
NS_IMETHODIMP
nsDocShell::GetIsNavigating(bool* aOut) {
*aOut = mIsNavigating;
@@ -4945,7 +5191,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();
}
@@ -6890,6 +7136,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<nsIContentViewer> viewer = mOSHE->GetContentViewer();
@@ -8667,6 +8917,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;
}
@@ -9697,6 +9953,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)) {
@@ -12861,6 +13127,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;
}
@@ -12940,6 +13209,8 @@ nsresult nsDocShell::OnLinkClick(
nsCOMPtr<nsIRunnable> ev =
new OnLinkClickEvent(this, aContent, loadState, noOpenerImplied,
aIsTrusted, aTriggeringPrincipal);
+ nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
+ observerService->NotifyObservers(ToSupports(aContent), "juggler-link-click", nullptr);
return Dispatch(TaskCategory::UI, ev.forget());
}
diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h
index 40bc4a21e789e2ee7f241f4adc410e1915105906..31f5574adcace75af6b184a3859e621022671a8a 100644
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -16,6 +16,7 @@
#include "mozilla/UniquePtr.h"
#include "mozilla/WeakPtr.h"
#include "mozilla/dom/BrowsingContext.h"
+#include "mozilla/dom/Element.h"
#include "mozilla/dom/WindowProxyHolder.h"
#include "nsCOMPtr.h"
#include "nsCharsetSource.h"
@@ -77,6 +78,7 @@ class nsCommandManager;
class nsDocShellEditorData;
class nsDOMNavigationTiming;
class nsDSURIContentListener;
+class nsGeolocationService;
class nsGlobalWindowOuter;
class FramingChecker;
@@ -409,6 +411,15 @@ class nsDocShell final : public nsDocLoader,
void SetWillChangeProcess() { mWillChangeProcess = true; }
bool WillChangeProcess() { return mWillChangeProcess; }
+ bool IsFileInputInterceptionEnabled();
+ void FilePickerShown(mozilla::dom::Element* element);
+
+ bool ShouldOverrideHasFocus() const;
+
+ bool IsBypassCSPEnabled();
+
+ RefPtr<nsGeolocationService> GetGeolocationServiceOverride();
+
// Create a content viewer within this nsDocShell for the given
// `WindowGlobalChild` actor.
nsresult CreateContentViewerForActor(
@@ -1028,6 +1039,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
@@ -1317,6 +1330,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;
+ OnlineOverride mOnlineOverride;
+ ReducedMotionOverride mReducedMotionOverride;
+ ForcedColorsOverride mForcedColorsOverride;
+
bool mAllowAuth : 1;
bool mAllowKeywordFixup : 1;
bool mDisableMetaRefreshWhenInactive : 1;
diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl
index cc34ebbe0e8706888e26148f507180a1ebba1326..c0e6a5612beba81c3382839303e3e7a10ded8f05 100644
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -44,6 +44,7 @@ interface nsIURI;
interface nsIChannel;
interface nsIContentViewer;
interface nsIContentSecurityPolicy;
+interface nsIDOMGeoPosition;
interface nsIEditor;
interface nsIEditingSession;
interface nsIInputStream;
@@ -803,6 +804,43 @@ 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 OnlineOverride: 8 {
+ ONLINE_OVERRIDE_NONE = 0,
+ ONLINE_OVERRIDE_ONLINE = 1,
+ ONLINE_OVERRIDE_OFFLINE = 2,
+ };
+ [infallible] attribute nsIDocShell_OnlineOverride onlineOverride;
+
+ cenum ReducedMotionOverride : 8 {
+ REDUCED_MOTION_OVERRIDE_REDUCE,
+ REDUCED_MOTION_OVERRIDE_NO_PREFERENCE,
+ REDUCED_MOTION_OVERRIDE_NONE, /* This clears the override. */
+ };
+ [infallible] attribute nsIDocShell_ReducedMotionOverride reducedMotionOverride;
+
+ cenum ForcedColorsOverride : 8 {
+ FORCED_COLORS_OVERRIDE_ACTIVE,
+ FORCED_COLORS_OVERRIDE_NONE,
+ FORCED_COLORS_OVERRIDE_NO_OVERRIDE, /* This clears the override. */
+ };
+ [infallible] attribute nsIDocShell_ForcedColorsOverride forcedColorsOverride;
+
+ void setGeolocationOverride(in nsIDOMGeoPosition position);
+
/**
* This attempts to save any applicable layout history state (like
* scroll position) in the nsISHEntry. This is normally done
diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp
index fb54b0ebfb2e910546feb8b4d5b7ab69528c162c..865296d65fed772a5a551935fd3423b7c43f5c5a 100644
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -3645,6 +3645,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
@@ -3702,6 +3705,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;
@@ -4525,6 +4533,10 @@ bool Document::HasFocus(ErrorResult& rv) const {
return false;
}
+ if (IsActive() && mDocumentContainer->ShouldOverrideHasFocus()) {
+ return true;
+ }
+
if (!fm->IsInActiveWindow(bc)) {
return false;
}
@@ -18029,6 +18041,71 @@ ColorScheme Document::PreferredColorScheme(IgnoreRFP aIgnoreRFP) const {
return LookAndFeel::PreferredColorSchemeForContent();
}
+bool Document::PrefersReducedMotion() const {
+ auto* docShell = static_cast<nsDocShell*>(GetDocShell());
+ nsIDocShell::ReducedMotionOverride reducedMotion;
+ if (docShell && docShell->GetReducedMotionOverride(&reducedMotion) == NS_OK &&
+ reducedMotion != nsIDocShell::REDUCED_MOTION_OVERRIDE_NONE) {
+ switch (reducedMotion) {
+ case nsIDocShell::REDUCED_MOTION_OVERRIDE_REDUCE:
+ return true;
+ case nsIDocShell::REDUCED_MOTION_OVERRIDE_NO_PREFERENCE:
+ return false;
+ case nsIDocShell::REDUCED_MOTION_OVERRIDE_NONE:
+ break;
+ };
+ }
+
+ if (auto* bc = GetBrowsingContext()) {
+ switch (bc->Top()->PrefersReducedMotionOverride()) {
+ case dom::PrefersReducedMotionOverride::Reduce:
+ return true;
+ case dom::PrefersReducedMotionOverride::No_preference:
+ return false;
+ case dom::PrefersReducedMotionOverride::None:
+ case dom::PrefersReducedMotionOverride::EndGuard_:
+ break;
+ }
+ }
+
+ if (ShouldResistFingerprinting()) {
+ return false;
+ }
+ return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1;
+}
+
+bool Document::ForcedColors() const {
+ auto* docShell = static_cast<nsDocShell*>(GetDocShell());
+ nsIDocShell::ForcedColorsOverride forcedColors;
+ if (docShell && docShell->GetForcedColorsOverride(&forcedColors) == NS_OK) {
+ switch (forcedColors) {
+ case nsIDocShell::FORCED_COLORS_OVERRIDE_ACTIVE:
+ return true;
+ case nsIDocShell::FORCED_COLORS_OVERRIDE_NONE:
+ return false;
+ case nsIDocShell::FORCED_COLORS_OVERRIDE_NO_OVERRIDE:
+ break;
+ };
+ }
+
+ if (auto* bc = GetBrowsingContext()) {
+ switch (bc->Top()->ForcedColorsOverride()) {
+ case dom::ForcedColorsOverride::Active:
+ return true;
+ case dom::ForcedColorsOverride::None:
+ return false;
+ case dom::ForcedColorsOverride::No_override:
+ case dom::ForcedColorsOverride::EndGuard_:
+ break;
+ }
+ }
+
+ if (mIsBeingUsedAsImage) {
+ return false;
+ }
+ return !PreferenceSheet::PrefsFor(*this).mUseDocumentColors;
+}
+
bool Document::HasRecentlyStartedForegroundLoads() {
if (!sLoadingForegroundTopLevelContentDocument) {
return false;
diff --git a/dom/base/Document.h b/dom/base/Document.h
index 5cee4a31e29a15809e604473e4c80cbbf763b3d9..23a2165b3aefd4b1e84d3035b7ac8ac9edf45535 100644
--- a/dom/base/Document.h
+++ b/dom/base/Document.h
@@ -4074,6 +4074,9 @@ class Document : public nsINode,
// color-scheme meta tag.
ColorScheme DefaultColorScheme() const;
+ bool PrefersReducedMotion() const;
+ bool ForcedColors() const;
+
static bool HasRecentlyStartedForegroundLoads();
static bool AutomaticStorageAccessPermissionCanBeGranted(
diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp
index aebd8fb26596e0f701cc2173bd60d827e987e992..8fc5bdd912c9cf71fbd6541c5ae1189f56bb6bef 100644
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -331,14 +331,18 @@ void Navigator::GetAppName(nsAString& aAppName, CallerType aCallerType) const {
* for more detail.
*/
/* static */
-void Navigator::GetAcceptLanguages(nsTArray<nsString>& aLanguages) {
+void Navigator::GetAcceptLanguages(const nsString* aLanguageOverride, nsTArray<nsString>& aLanguages) {
MOZ_ASSERT(NS_IsMainThread());
aLanguages.Clear();
// E.g. "de-de, en-us,en".
nsAutoString acceptLang;
- Preferences::GetLocalizedString("intl.accept_languages", acceptLang);
+ if (aLanguageOverride && aLanguageOverride->Length())
+ acceptLang = *aLanguageOverride;
+ else
+ Preferences::GetLocalizedString("intl.accept_languages", acceptLang);
+
// Split values on commas.
for (nsDependentSubstring lang :
@@ -390,7 +394,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
@@ -569,7 +579,13 @@ bool Navigator::CookieEnabled() {
return granted;
}
-bool Navigator::OnLine() { return !NS_IsOffline(); }
+bool Navigator::OnLine() {
+ nsDocShell* docShell = static_cast<nsDocShell*>(GetDocShell());
+ nsIDocShell::OnlineOverride onlineOverride;
+ if (!docShell || docShell->GetOnlineOverride(&onlineOverride) != NS_OK || onlineOverride == nsIDocShell::ONLINE_OVERRIDE_NONE)
+ return !NS_IsOffline();
+ return onlineOverride == nsIDocShell::ONLINE_OVERRIDE_ONLINE;
+}
void Navigator::GetBuildID(nsAString& aBuildID, CallerType aCallerType,
ErrorResult& aRv) const {
diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h
index 9f6b85ecfac7196cc57c1b1979313403a41d4a6c..0fe045f38c36eb0284bb7c1fb6d3346378f4ae07 100644
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -217,7 +217,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 1b5573d5b8508775a4b0f608183b2a6911614e97..a4b7f7e0459b9762848244ce6813e757890bacc1 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -8432,7 +8432,8 @@ nsresult nsContentUtils::SendMouseEvent(
bool aIgnoreRootScrollFrame, float aPressure,
unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow,
PreventDefaultResult* aPreventDefault, bool aIsDOMEventSynthesized,
- bool aIsWidgetEventSynthesized) {
+ bool aIsWidgetEventSynthesized,
+ bool convertToPointer, uint32_t aJugglerEventId) {
nsPoint offset;
nsCOMPtr<nsIWidget> widget = GetWidget(aPresShell, &offset);
if (!widget) return NS_ERROR_FAILURE;
@@ -8440,6 +8441,7 @@ nsresult nsContentUtils::SendMouseEvent(
EventMessage msg;
Maybe<WidgetMouseEvent::ExitFrom> exitFrom;
bool contextMenuKey = false;
+ bool isDragEvent = false;
if (aType.EqualsLiteral("mousedown")) {
msg = eMouseDown;
} else if (aType.EqualsLiteral("mouseup")) {
@@ -8464,6 +8466,12 @@ nsresult nsContentUtils::SendMouseEvent(
msg = eMouseHitTest;
} else if (aType.EqualsLiteral("MozMouseExploreByTouch")) {
msg = eMouseExploreByTouch;
+ } else if (aType.EqualsLiteral("dragover")) {
+ msg = eDragOver;
+ isDragEvent = true;
+ } else if (aType.EqualsLiteral("drop")) {
+ msg = eDrop;
+ isDragEvent = true;
} else {
return NS_ERROR_FAILURE;
}
@@ -8472,12 +8480,21 @@ nsresult nsContentUtils::SendMouseEvent(
aInputSourceArg = MouseEvent_Binding::MOZ_SOURCE_MOUSE;
}
- WidgetMouseEvent event(true, msg, widget,
+ std::unique_ptr<WidgetMouseEvent> eventOwner;
+ if (isDragEvent) {
+ eventOwner.reset(new WidgetDragEvent(true, msg, widget));
+ eventOwner->mReason = aIsWidgetEventSynthesized
+ ? WidgetMouseEvent::eSynthesized
+ : WidgetMouseEvent::eReal;
+ } else {
+ eventOwner.reset(new WidgetMouseEvent(true, msg, widget,
aIsWidgetEventSynthesized
? WidgetMouseEvent::eSynthesized
: WidgetMouseEvent::eReal,
contextMenuKey ? WidgetMouseEvent::eContextMenuKey
- : WidgetMouseEvent::eNormal);
+ : WidgetMouseEvent::eNormal));
+ }
+ WidgetMouseEvent& event = *eventOwner.get();
event.pointerId = aIdentifier;
event.mModifiers = GetWidgetModifiers(aModifiers);
event.mButton = aButton;
@@ -8488,8 +8505,10 @@ nsresult nsContentUtils::SendMouseEvent(
event.mPressure = aPressure;
event.mInputSource = aInputSourceArg;
event.mClickCount = aClickCount;
+ event.mJugglerEventId = aJugglerEventId;
event.mFlags.mIsSynthesizedForTests = aIsDOMEventSynthesized;
event.mExitFrom = exitFrom;
+ event.convertToPointer = convertToPointer;
nsPresContext* presContext = aPresShell->GetPresContext();
if (!presContext) return NS_ERROR_FAILURE;
diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h
index dd455bb3617fce75a94b3312894441ddc7d464d6..2637d4b7c523f90d7df96dc0468d581694852f9c 100644
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2911,7 +2911,8 @@ class nsContentUtils {
int32_t aModifiers, bool aIgnoreRootScrollFrame, float aPressure,
unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow,
mozilla::PreventDefaultResult* aPreventDefault,
- bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized);
+ bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized,
+ bool convertToPointer = true, uint32_t aJugglerEventId = 0);
static void FirePageShowEventForFrameLoaderSwap(
nsIDocShellTreeItem* aItem,
diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp
index 007bcf54ca784d49655f1d9d56243dedc8dcafb4..a9ce0d07ffdd362cda194a8485aa8690a3c6ad4a 100644
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -675,6 +675,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,
@@ -689,7 +709,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
@@ -707,7 +727,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
@@ -716,13 +736,13 @@ nsDOMWindowUtils::SendMouseEventCommon(
int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame,
float aPressure, unsigned short aInputSourceArg, uint32_t aPointerId,
bool aToWindow, bool* aPreventDefault, bool aIsDOMEventSynthesized,
- bool aIsWidgetEventSynthesized, int32_t aButtons) {
+ bool aIsWidgetEventSynthesized, int32_t aButtons, bool aConvertToPointer, uint32_t aJugglerEventId) {
RefPtr<PresShell> presShell = GetPresShell();
PreventDefaultResult preventDefaultResult;
nsresult rv = nsContentUtils::SendMouseEvent(
presShell, aType, aX, aY, aButton, aButtons, aClickCount, aModifiers,
aIgnoreRootScrollFrame, aPressure, aInputSourceArg, aPointerId, aToWindow,
- &preventDefaultResult, aIsDOMEventSynthesized, aIsWidgetEventSynthesized);
+ &preventDefaultResult, aIsDOMEventSynthesized, aIsWidgetEventSynthesized, aConvertToPointer, aJugglerEventId);
if (aPreventDefault) {
*aPreventDefault = preventDefaultResult != PreventDefaultResult::No;
diff --git a/dom/base/nsDOMWindowUtils.h b/dom/base/nsDOMWindowUtils.h
index 63968c9b7a4e418e4c0de6e7a75fa215a36a9105..decf3ea3833ccdffd49a7aded2d600f9416e8306 100644
--- a/dom/base/nsDOMWindowUtils.h
+++ b/dom/base/nsDOMWindowUtils.h
@@ -93,7 +93,7 @@ class nsDOMWindowUtils final : public nsIDOMWindowUtils,
int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame,
float aPressure, unsigned short aInputSourceArg, uint32_t aIdentifier,
bool aToWindow, bool* aPreventDefault, bool aIsDOMEventSynthesized,
- bool aIsWidgetEventSynthesized, int32_t aButtons);
+ bool aIsWidgetEventSynthesized, int32_t aButtons, bool aConvertToPointer = true, uint32_t aJugglerEventId = 0);
MOZ_CAN_RUN_SCRIPT
nsresult SendTouchEventCommon(
diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp
index 415e941727187a9ec21aded76857e3d61c32c39b..aad2c96bcba8229b1cda3d578369af62692cf382 100644
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -1656,6 +1656,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)) {
@@ -2935,7 +2939,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 7a5df6943c7652d33f2b4ed773679fd6062023b5..786d50ddec3456dda59e36959fc9ec814770f6f1 100644
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -2481,7 +2481,7 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument,
&nsGlobalWindowInner::FireOnNewGlobalObject));
}
- if (newInnerWindow && !newInnerWindow->mHasNotifiedGlobalCreated && mDoc) {
+ if (newInnerWindow && mDoc) {
// We should probably notify. However if this is the, arguably bad,
// situation when we're creating a temporary non-chrome-about-blank
// document in a chrome docshell, don't notify just yet. Instead wait
@@ -2500,10 +2500,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));
+ }
}
}
@@ -2624,6 +2630,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 5d2a162dce39170b66595de3f99d83afedfae287..a98c01bb6ce1971e41c0398900bf8060542663c9 100644
--- a/dom/base/nsGlobalWindowOuter.h
+++ b/dom/base/nsGlobalWindowOuter.h
@@ -333,6 +333,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 6a28c0f314e573373114b9c973f7b9087824cf34..bca53a40f213ba1f7f273ae000609749816f6786 100644
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -1340,6 +1340,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 1245cb9bd967d27cc95ba710999181d90a3531fd..a6c74c4ced45117f97874e0675c43ce04d22212e 100644
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -2150,6 +2150,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 1da84501bf3ce25b932ec3693f247cdb1a4fdf21..2305a1730e18ba7293a41772b9b7495b5aa66210 100644
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -169,6 +169,11 @@ bool nsJSUtils::GetScopeChainForElement(
return true;
}
+/* static */
+bool nsJSUtils::SetTimeZoneOverride(const char* timezoneId) {
+ return JS::SetTimeZoneOverride(timezoneId);
+}
+
/* static */
void nsJSUtils::ResetTimeZone() { JS::ResetTimeZone(); }
diff --git a/dom/base/nsJSUtils.h b/dom/base/nsJSUtils.h
index 85a21e459305f556933f4dc0fa7441d8f9ed95a9..d7cb86479ba2ed06542307349d6d86dfd026d55d 100644
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -78,6 +78,7 @@ class nsJSUtils {
JSContext* aCx, mozilla::dom::Element* aElement,
JS::MutableHandleVector<JSObject*> aScopeChain);
+ static bool SetTimeZoneOverride(const char* timezoneId);
static void ResetTimeZone();
static bool DumpEnabled();
diff --git a/dom/chrome-webidl/BrowsingContext.webidl b/dom/chrome-webidl/BrowsingContext.webidl
index 369da91c6e31dbffe63fcd5044622bb8ca6150d5..aa874d57145261f14fe93e18e398c95eb63b8af5 100644
--- a/dom/chrome-webidl/BrowsingContext.webidl
+++ b/dom/chrome-webidl/BrowsingContext.webidl
@@ -52,6 +52,24 @@ enum PrefersColorSchemeOverride {
"dark",
};
+/**
+ * CSS prefers-reduced-motion values.
+ */
+enum PrefersReducedMotionOverride {
+ "none",
+ "reduce",
+ "no-preference",
+};
+
+/**
+ * CSS forced-colors values.
+ */
+enum ForcedColorsOverride {
+ "none",
+ "active",
+ "no-override", /* This clears the override. */
+};
+
/**
* Allowed overrides of platform/pref default behaviour for touch events.
*/
@@ -188,6 +206,12 @@ interface BrowsingContext {
// Color-scheme simulation, for DevTools.
[SetterThrows] attribute PrefersColorSchemeOverride prefersColorSchemeOverride;
+ // Reduced-Motion simulation, for DevTools.
+ [SetterThrows] attribute PrefersReducedMotionOverride prefersReducedMotionOverride;
+
+ // Forced-Colors simulation, for DevTools.
+ [SetterThrows] attribute ForcedColorsOverride forcedColorsOverride;
+
/**
* A unique identifier for the browser element that is hosting this
* BrowsingContext tree. Every BrowsingContext in the element's tree will
@@ -246,6 +270,8 @@ interface BrowsingContext {
undefined resetLocationChangeRateLimit();
readonly attribute long childOffset;
+
+ readonly attribute unsigned long long jugglerCurrentLoadIdentifier;
};
BrowsingContext includes LoadContextMixin;
diff --git a/dom/geolocation/Geolocation.cpp b/dom/geolocation/Geolocation.cpp
index ff6fe276e3f5a19e3e22d98c4a38222880797d99..96157d17485534f97a4e39675ee77808ac495bfe 100644
--- a/dom/geolocation/Geolocation.cpp
+++ b/dom/geolocation/Geolocation.cpp
@@ -23,6 +23,7 @@
#include "nsComponentManagerUtils.h"
#include "nsContentPermissionHelper.h"
#include "nsContentUtils.h"
+#include "nsDocShell.h"
#include "nsGlobalWindow.h"
#include "mozilla/dom/Document.h"
#include "nsINamed.h"
@@ -260,10 +261,8 @@ nsGeolocationRequest::Allow(JS::Handle<JS::Value> aChoices) {
return NS_OK;
}
- RefPtr<nsGeolocationService> gs =
- nsGeolocationService::GetGeolocationService();
-
- bool canUseCache = false;
+ nsGeolocationService* gs = mLocator->GetGeolocationService();
+ bool canUseCache = gs != nsGeolocationService::sService.get();
CachedPositionAndAccuracy lastPosition = gs->GetCachedPosition();
if (lastPosition.position) {
EpochTimeStamp cachedPositionTime_ms;
@@ -441,8 +440,7 @@ void nsGeolocationRequest::Shutdown() {
// If there are no other high accuracy requests, the geolocation service will
// notify the provider to switch to the default accuracy.
if (mOptions && mOptions->mEnableHighAccuracy) {
- RefPtr<nsGeolocationService> gs =
- nsGeolocationService::GetGeolocationService();
+ nsGeolocationService* gs = mLocator ? mLocator->GetGeolocationService() : nullptr;
if (gs) {
gs->UpdateAccuracy();
}
@@ -732,8 +730,14 @@ void nsGeolocationService::StopDevice() {
StaticRefPtr<nsGeolocationService> nsGeolocationService::sService;
already_AddRefed<nsGeolocationService>
-nsGeolocationService::GetGeolocationService() {
+nsGeolocationService::GetGeolocationService(nsDocShell* docShell) {
RefPtr<nsGeolocationService> result;
+ if (docShell) {
+ result = docShell->GetGeolocationServiceOverride();
+ if (result)
+ return result.forget();
+ }
+
if (nsGeolocationService::sService) {
result = nsGeolocationService::sService;
@@ -825,7 +829,9 @@ nsresult Geolocation::Init(nsPIDOMWindowInner* aContentDom) {
// If no aContentDom was passed into us, we are being used
// by chrome/c++ and have no mOwner, no mPrincipal, and no need
// to prompt.
- mService = nsGeolocationService::GetGeolocationService();
+ nsCOMPtr<Document> doc = aContentDom ? aContentDom->GetDoc() : nullptr;
+ mService = nsGeolocationService::GetGeolocationService(
+ doc ? static_cast<nsDocShell*>(doc->GetDocShell()) : nullptr);
if (mService) {
mService->AddLocator(this);
}
diff --git a/dom/geolocation/Geolocation.h b/dom/geolocation/Geolocation.h
index 7e1af00d05fbafa2d828e2c7e4dcc5c82d115f5b..e85af9718d064e4d2865bc944e9d4ba1efb9a5d7 100644
--- a/dom/geolocation/Geolocation.h
+++ b/dom/geolocation/Geolocation.h
@@ -31,6 +31,7 @@
#include "nsIGeolocationProvider.h"
#include "mozilla/Attributes.h"
+#include "nsDocShell.h"
class nsGeolocationService;
class nsGeolocationRequest;
@@ -48,13 +49,14 @@ struct CachedPositionAndAccuracy {
bool isHighAccuracy;
};
+
/**
* Singleton that manages the geolocation provider
*/
class nsGeolocationService final : public nsIGeolocationUpdate,
public nsIObserver {
public:
- static already_AddRefed<nsGeolocationService> GetGeolocationService();
+ static already_AddRefed<nsGeolocationService> GetGeolocationService(nsDocShell* docShell = nullptr);
static mozilla::StaticRefPtr<nsGeolocationService> sService;
NS_DECL_THREADSAFE_ISUPPORTS
@@ -179,6 +181,8 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache {
// null.
static already_AddRefed<Geolocation> NonWindowSingleton();
+ nsGeolocationService* GetGeolocationService() { return mService; };
+
private:
~Geolocation();
diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp
index cb486a7b1270083498be997b31a6e29a206fc320..4387fe0a72463c3759eff30ee9e96e850ed39bc9 100644
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -58,6 +58,7 @@
#include "mozilla/dom/Document.h"
#include "mozilla/dom/HTMLDataListElement.h"
#include "mozilla/dom/HTMLOptionElement.h"
+#include "nsDocShell.h"
#include "nsIFormControlFrame.h"
#include "nsITextControlFrame.h"
#include "nsIFrame.h"
@@ -780,6 +781,12 @@ nsresult HTMLInputElement::InitFilePicker(FilePickerType aType) {
return NS_ERROR_FAILURE;
}
+ nsDocShell* docShell = static_cast<nsDocShell*>(win->GetDocShell());
+ if (docShell && docShell->IsFileInputInterceptionEnabled()) {
+ docShell->FilePickerShown(this);
+ return NS_OK;
+ }
+
if (IsPopupBlocked(doc)) {
return NS_OK;
}
diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl
index 25633e4ed848996efb790f4d462d00cbffa13f6d..dc21dcafe7561c3bf226d5190670a1f9b389266b 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 4d21d631a523e012acbb15fe6f274db67f462484..9f86f994acb494a49403ef313e48658d9cdd5232 100644
--- a/dom/ipc/BrowserChild.cpp
+++ b/dom/ipc/BrowserChild.cpp
@@ -1678,6 +1678,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 5aa445d2e0a6169e57c44569974d557b3baf7064..671f71979b407f0ca17c66f13805e851ba30479e 100644
--- a/dom/ipc/CoalescedMouseData.cpp
+++ b/dom/ipc/CoalescedMouseData.cpp
@@ -67,6 +67,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);
}
diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.cc b/dom/media/systemservices/video_engine/desktop_capture_impl.cc
index c5fc05f772900dd6d30b252783adb96dfbbde2a1..86d88db3ff9e411adf9fecb114e9ced1af29b610 100644
--- a/dom/media/systemservices/video_engine/desktop_capture_impl.cc
+++ b/dom/media/systemservices/video_engine/desktop_capture_impl.cc
@@ -132,11 +132,12 @@ int32_t ScreenDeviceInfoImpl::GetOrientation(const char* aDeviceUniqueIdUTF8,
return 0;
}
-VideoCaptureModule* DesktopCaptureImpl::Create(const int32_t aModuleId,
+VideoCaptureModuleEx* 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);
}
int32_t WindowDeviceInfoImpl::Init() {
@@ -436,8 +437,12 @@ int32_t DesktopCaptureImpl::EnsureCapturer() {
DesktopCapturer::SourceId sourceId = atoi(mDeviceUniqueId.c_str());
windowCapturer->SelectSource(sourceId);
- mCapturer = std::make_unique<DesktopAndCursorComposer>(
- std::move(windowCapturer), options);
+ if (capture_cursor_) {
+ mCapturer = std::make_unique<DesktopAndCursorComposer>(
+ std::move(windowCapturer), options);
+ } else {
+ mCapturer = std::move(windowCapturer);
+ }
} else if (mDeviceType == CaptureDeviceType::Browser) {
// XXX We don't capture cursors, so avoid the extra indirection layer. We
// could also pass null for the pMouseCursorMonitor.
@@ -453,7 +458,8 @@ int32_t DesktopCaptureImpl::EnsureCapturer() {
}
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) {
@@ -472,6 +478,7 @@ DesktopCaptureImpl::DesktopCaptureImpl(const int32_t aId, const char* aUniqueId,
mDeviceType(aType),
mControlThread(mozilla::GetCurrentSerialEventTarget()),
mNextFrameMinimumTime(Timestamp::Zero()),
+ capture_cursor_(aCaptureCursor),
mRunning(false),
mCallbacks("DesktopCaptureImpl::mCallbacks") {}
@@ -492,6 +499,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();
@@ -618,6 +638,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 162589cb0902820afae86f0def2afab7630b96aa..4b95c351d813f5af5e316ea32fc8128ca3e1c8fb 100644
--- a/dom/media/systemservices/video_engine/desktop_capture_impl.h
+++ b/dom/media/systemservices/video_engine/desktop_capture_impl.h
@@ -24,6 +24,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 "desktop_device_info.h"
#include "mozilla/DataMutex.h"
@@ -43,6 +44,21 @@ namespace webrtc {
class VideoCaptureEncodeInterface;
+class RawFrameCallback {
+ public:
+ virtual ~RawFrameCallback() {}
+
+ virtual void OnRawFrame(uint8_t* videoFrame, size_t videoFrameLength, const VideoCaptureCapability& frameInfo) = 0;
+};
+
+class VideoCaptureModuleEx : public VideoCaptureModule {
+ public:
+ virtual ~VideoCaptureModuleEx() {}
+
+ virtual void RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) = 0;
+ virtual void DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) = 0;
+};
+
// simulate deviceInfo interface for video engine, bridge screen/application and
// real screen/application device info
@@ -155,13 +171,13 @@ class BrowserDeviceInfoImpl : public VideoCaptureModule::DeviceInfo {
// As with video, DesktopCaptureImpl is a proxy for screen sharing
// and follows the video pipeline design
class DesktopCaptureImpl : public DesktopCapturer::Callback,
- public VideoCaptureModule {
+ public VideoCaptureModuleEx {
public:
/* Create a screen capture modules object
*/
- static VideoCaptureModule* Create(
+ static VideoCaptureModuleEx* 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,
@@ -173,6 +189,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;
@@ -195,7 +213,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:
@@ -204,6 +223,9 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback,
int32_t EnsureCapturer();
void InitOnThread(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;
@@ -215,6 +237,7 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback,
const nsCOMPtr<nsISerialEventTarget> mControlThread;
// Set in StartCapture. mControlThread only.
VideoCaptureCapability mRequestedCapability;
+ bool capture_cursor_ = true;
// This is created on mControlThread and accessed on both mControlThread and
// mCaptureThread. It is created prior to mCaptureThread starting and is
// destroyed after it is stopped.
diff --git a/dom/script/ScriptSettings.cpp b/dom/script/ScriptSettings.cpp
index 1f2d92bcb5d989bf9ecc044f8c51006f991b0007..9cf5dd885e658e0fe5e7ab75e7fc1f97a8d214b8 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 5f9156ce2e70eb64653db72eb9dd1afddcec5633..af9efd55cf62b06ba9291bdc3af6819cc75be105 100644
--- a/dom/security/nsCSPUtils.cpp
+++ b/dom/security/nsCSPUtils.cpp
@@ -127,6 +127,11 @@ void CSP_ApplyMetaCSPToDoc(mozilla::dom::Document& aDoc,
return;
}
+ if (aDoc.GetDocShell() &&
+ nsDocShell::Cast(aDoc.GetDocShell())->IsBypassCSPEnabled()) {
+ return;
+ }
+
nsAutoString policyStr(
nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
aPolicyStr));
diff --git a/dom/webidl/GeometryUtils.webidl b/dom/webidl/GeometryUtils.webidl
index 2f71b284ee5f7e11f117c447834b48355784448c..2640bd57123c2b03bf4b06a2419cd020ba95f155 100644
--- a/dom/webidl/GeometryUtils.webidl
+++ b/dom/webidl/GeometryUtils.webidl
@@ -16,6 +16,8 @@ dictionary BoxQuadOptions {
GeometryNode relativeTo;
[ChromeOnly]
boolean createFramesForSuppressedWhitespace = true;
+ [ChromeOnly]
+ boolean recurseWhenNoFrame = false;
};
dictionary ConvertCoordinateOptions {
@@ -27,6 +29,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 ecafc907fa17f16561d6bd43061aacf5eb8c3076..b90c50fdbc7186702959a2f1cc12d82dd11d9ac3 100644
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -982,7 +982,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) {
@@ -1184,8 +1184,7 @@ bool RuntimeService::RegisterWorker(WorkerPrivate& aWorkerPrivate) {
}
// The navigator overridden properties should have already been read.
-
- Navigator::GetAcceptLanguages(mNavigatorProperties.mLanguages);
+ Navigator::GetAcceptLanguages(nullptr, mNavigatorProperties.mLanguages);
mNavigatorPropertiesLoaded = true;
}
@@ -1783,6 +1782,13 @@ void RuntimeService::PropagateStorageAccessPermissionGranted(
}
}
+void RuntimeService::ResetDefaultLocaleInAllWorkers() {
+ AssertIsOnMainThread();
+ BroadcastAllWorkers([](auto& worker) {
+ worker.ResetDefaultLocale();
+ });
+}
+
template <typename Func>
void RuntimeService::BroadcastAllWorkers(const Func& aFunc) {
AssertIsOnMainThread();
@@ -2210,6 +2216,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 d1a44a19e865fb76cf2b7bfe5e1fbd9c64ec0465..1a44fee6508ea0ef3f48700b83b1185565778cc8 100644
--- a/dom/workers/RuntimeService.h
+++ b/dom/workers/RuntimeService.h
@@ -110,6 +110,8 @@ class RuntimeService final : public nsIObserver {
void PropagateStorageAccessPermissionGranted(
const nsPIDOMWindowInner& aWindow);
+ void ResetDefaultLocaleInAllWorkers();
+
const NavigatorProperties& GetNavigatorProperties() const {
return mNavigatorProperties;
}
diff --git a/dom/workers/WorkerCommon.h b/dom/workers/WorkerCommon.h
index d10dabb5c5ff8e17851edf2bd2efc08e74584d8e..53c4070c5fde43b27fb8fbfdcf4c23d8af57fba3 100644
--- a/dom/workers/WorkerCommon.h
+++ b/dom/workers/WorkerCommon.h
@@ -44,6 +44,8 @@ void ResumeWorkersForWindow(const nsPIDOMWindowInner& aWindow);
void PropagateStorageAccessPermissionGrantedToWorkers(
const nsPIDOMWindowInner& aWindow);
+void ResetDefaultLocaleInAllWorkers();
+
// All of these are implemented in WorkerScope.cpp
bool IsWorkerGlobal(JSObject* global);
diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp
index a5c7f0eb41e83353916819c8c75aec475249356b..706d8501be1f1cb194648950a7e62ea0621febba 100644
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -703,6 +703,18 @@ class UpdateContextOptionsRunnable final : public WorkerControlRunnable {
}
};
+class ResetDefaultLocaleRunnable final : public WorkerControlRunnable {
+ public:
+ explicit ResetDefaultLocaleRunnable(WorkerPrivate* aWorkerPrivate)
+ : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) {}
+
+ virtual bool WorkerRun(JSContext* aCx,
+ WorkerPrivate* aWorkerPrivate) override {
+ aWorkerPrivate->ResetDefaultLocaleInternal(aCx);
+ return true;
+ }
+};
+
class UpdateLanguagesRunnable final : public WorkerRunnable {
nsTArray<nsString> mLanguages;
@@ -1974,6 +1986,16 @@ void WorkerPrivate::UpdateContextOptions(
}
}
+void WorkerPrivate::ResetDefaultLocale() {
+ AssertIsOnParentThread();
+
+ RefPtr<ResetDefaultLocaleRunnable> runnable =
+ new ResetDefaultLocaleRunnable(this);
+ if (!runnable->Dispatch()) {
+ NS_WARNING("Failed to reset default locale in worker!");
+ }
+}
+
void WorkerPrivate::UpdateLanguages(const nsTArray<nsString>& aLanguages) {
AssertIsOnParentThread();
@@ -5287,6 +5309,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 bc6e31d0aecf437e22f758cc1b1485712bd507fd..5a6b1213ea1a81205894ccc78571be0978cf6ecc 100644
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -340,6 +340,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,
@@ -961,6 +963,8 @@ class WorkerPrivate final
void UpdateContextOptions(const JS::ContextOptions& aContextOptions);
+ void ResetDefaultLocale();
+
void UpdateLanguages(const nsTArray<nsString>& aLanguages);
void UpdateJSWorkerMemoryParameter(JSGCParamKey key, Maybe<uint32_t> value);
diff --git a/intl/components/src/TimeZone.cpp b/intl/components/src/TimeZone.cpp
index 145dd3f07112c2390325de50f8eae674484adfe6..8cb3787e1b6bb25c6a58f1d910ae7dbc440d9ace 100644
--- a/intl/components/src/TimeZone.cpp
+++ b/intl/components/src/TimeZone.cpp
@@ -16,6 +16,7 @@
namespace mozilla::intl {
+
/* static */
Result<UniquePtr<TimeZone>, ICUError> TimeZone::TryCreate(
Maybe<Span<const char16_t>> aTimeZoneOverride) {
@@ -239,6 +240,13 @@ static ICUResult SetDefaultTimeZone(TimeZoneIdentifierVector& timeZone) {
}
#endif
+bool TimeZone::IsValidTimeZoneId(const char* timeZoneId) {
+ // Validate timezone id.
+ mozilla::UniquePtr<icu::TimeZone> timeZone(icu::TimeZone::createTimeZone(
+ icu::UnicodeString(timeZoneId, -1, US_INV)));
+ return timeZone && *timeZone != icu::TimeZone::getUnknown();
+}
+
Result<bool, ICUError> TimeZone::SetDefaultTimeZone(
Span<const char> aTimeZone) {
#if MOZ_INTL_USE_ICU_CPP_TIMEZONE
diff --git a/intl/components/src/TimeZone.h b/intl/components/src/TimeZone.h
index 180092bd3fc0b70462cc6ba67e72946e4c4c7604..bcaecb9fcd7b630c75289581a887cc6894733168 100644
--- a/intl/components/src/TimeZone.h
+++ b/intl/components/src/TimeZone.h
@@ -154,6 +154,8 @@ class TimeZone final {
return FillBufferWithICUCall(aBuffer, ucal_getHostTimeZone);
}
+ static bool IsValidTimeZoneId(const char* timeZoneId);
+
/**
* Set the default time zone.
*/
diff --git a/js/public/Date.h b/js/public/Date.h
index cd641a54d9f968b4f5ac62aff701576e63a29439..27067c68a74a5578b8b5e6bbef3a4b4876897eb1 100644
--- a/js/public/Date.h
+++ b/js/public/Date.h
@@ -53,6 +53,8 @@ namespace JS {
*/
extern JS_PUBLIC_API void ResetTimeZone();
+extern JS_PUBLIC_API bool SetTimeZoneOverride(const char* timezoneId);
+
class ClippedTime;
inline ClippedTime TimeClip(double time);
diff --git a/js/src/debugger/Object.cpp b/js/src/debugger/Object.cpp
index 893542410468e2a999d49a826614fcba94576ccd..ff4daddfbbaa239cf12a05907f6f33b8a3be0bab 100644
--- a/js/src/debugger/Object.cpp
+++ b/js/src/debugger/Object.cpp
@@ -2421,7 +2421,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 cb3d1288c8b3f40fbcb40429381306c230960d76..7ec3f6c4e6d037aadd798f891ecfca0b5a83678a 100644
--- a/js/src/vm/DateTime.cpp
+++ b/js/src/vm/DateTime.cpp
@@ -179,6 +179,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);
@@ -510,10 +515,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) {
@@ -735,9 +754,17 @@ void js::ResyncICUDefaultTimeZone() {
void js::DateTimeInfo::internalResyncICUDefaultTimeZone() {
#if JS_HAS_INTL_API
+ if (!timeZoneOverride_.empty()) {
+ mozilla::Span<const char> tzid = mozilla::Span(timeZoneOverride_.data(), timeZoneOverride_.length());
+ auto result = mozilla::intl::TimeZone::SetDefaultTimeZone(tzid);
+ if (result.isErr()) {
+ fprintf(stderr, "ERROR: failed to setup default time zone\n");
+ }
+ return;
+ }
+
if (const char* tzenv = std::getenv("TZ")) {
std::string_view tz(tzenv);
-
mozilla::Span<const char> tzid;
# if defined(XP_WIN)
diff --git a/js/src/vm/DateTime.h b/js/src/vm/DateTime.h
index b70e4e0ae25947daed0079334956b8cabd5c52b7..38750b81cf82749d5cc6aaa72aa037bc466468f4 100644
--- a/js/src/vm/DateTime.h
+++ b/js/src/vm/DateTime.h
@@ -62,6 +62,8 @@ enum class ResetTimeZoneMode : bool {
*/
extern void ResetTimeZoneInternal(ResetTimeZoneMode mode);
+extern void SetTimeZoneOverrideInternal(std::string timeZone);
+
/**
* ICU's default time zone, used for various date/time formatting operations
* that include the local time in the representation, is allowed to go stale
@@ -201,6 +203,7 @@ class DateTimeInfo {
// and js::ResyncICUDefaultTimeZone().
friend void js::ResetTimeZoneInternal(ResetTimeZoneMode);
friend void js::ResyncICUDefaultTimeZone();
+ friend void js::SetTimeZoneOverrideInternal(std::string);
static void resetTimeZone(ResetTimeZoneMode mode) {
auto guard = instance->lock();
@@ -292,6 +295,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
@@ -307,6 +312,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 dac899f7558b26d6848da8b98ed8a93555c8751a..2a07d67fa1c2840b25085566e84dc3b2d9b789cf 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;
@@ -261,11 +262,27 @@ static bool CheckFramesInSameTopLevelBrowsingContext(nsIFrame* aFrame1,
return false;
}
+static nsIFrame* GetFrameForNode(nsINode* aNode,
+ bool aCreateFramesForSuppressedWhitespace,
+ bool aRecurseWhenNoFrame) {
+ nsIFrame* frame = GetFrameForNode(aNode, aCreateFramesForSuppressedWhitespace);
+ if (!frame && aRecurseWhenNoFrame && aNode->IsContent()) {
+ dom::FlattenedChildIterator iter(aNode->AsContent());
+ for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
+ frame = GetFrameForNode(child, aCreateFramesForSuppressedWhitespace, 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.mCreateFramesForSuppressedWhitespace);
+ GetFrameForNode(aNode, aOptions.mCreateFramesForSuppressedWhitespace, aOptions.mRecurseWhenNoFrame);
if (!frame) {
// No boxes to return
return;
@@ -280,7 +297,7 @@ void GetBoxQuads(nsINode* aNode, const dom::BoxQuadOptions& aOptions,
// when that happens and re-check it.
if (!weakFrame.IsAlive()) {
frame =
- GetFrameForNode(aNode, aOptions.mCreateFramesForSuppressedWhitespace);
+ GetFrameForNode(aNode, aOptions.mCreateFramesForSuppressedWhitespace, aOptions.mRecurseWhenNoFrame);
if (!frame) {
// No boxes to return
return;
diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp
index 4b16430f9d713428c9df5607d3b25b9c2d777647..4f42913c7ecee91921e1f528d0198cf3591eb3a2 100644
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -10901,7 +10901,9 @@ auto PresShell::ComputeActiveness() const -> Activeness {
if (!browserChild->IsVisible()) {
MOZ_LOG(gLog, LogLevel::Debug,
(" > BrowserChild %p is not visible", browserChild));
- return {false, inActiveTab};
+ bool isActive;
+ root->GetDocShell()->GetForceActiveState(&isActive);
+ return {isActive, inActiveTab};
}
// If the browser is visible but just due to be preserving layers
diff --git a/layout/style/GeckoBindings.h b/layout/style/GeckoBindings.h
index 171a524cf42b2ca9304a709401f77d12c952c8c4..7b5f0a93c06738927e34de183fa7b28dc5d8e16a 100644
--- a/layout/style/GeckoBindings.h
+++ b/layout/style/GeckoBindings.h
@@ -630,6 +630,7 @@ void Gecko_MediaFeatures_GetDeviceSize(const mozilla::dom::Document*,
float Gecko_MediaFeatures_GetResolution(const mozilla::dom::Document*);
bool Gecko_MediaFeatures_PrefersReducedMotion(const mozilla::dom::Document*);
+bool Gecko_MediaFeatures_ForcedColors(const mozilla::dom::Document*);
mozilla::StylePrefersContrast Gecko_MediaFeatures_PrefersContrast(
const mozilla::dom::Document*);
mozilla::StylePrefersColorScheme Gecko_MediaFeatures_PrefersColorScheme(
diff --git a/layout/style/nsMediaFeatures.cpp b/layout/style/nsMediaFeatures.cpp
index 3e1201e8877dd3a2bd1897f8b50732c8579b27f4..d27139a4926c12b9e389f45ad7de8f59fb421f4b 100644
--- a/layout/style/nsMediaFeatures.cpp
+++ b/layout/style/nsMediaFeatures.cpp
@@ -277,10 +277,11 @@ bool Gecko_MediaFeatures_MatchesPlatform(StylePlatform aPlatform) {
}
bool Gecko_MediaFeatures_PrefersReducedMotion(const Document* aDocument) {
- if (aDocument->ShouldResistFingerprinting()) {
- return false;
- }
- return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1;
+ return aDocument->PrefersReducedMotion();
+}
+
+bool Gecko_MediaFeatures_ForcedColors(const Document* aDocument) {
+ return aDocument->ForcedColors();
}
StylePrefersColorScheme Gecko_MediaFeatures_PrefersColorScheme(
diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js
index 22a15d306b807902c93dede5855007705237bdbd..65c70243944c87b6894d3e654fd0e4f971cfea70 100644
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -4113,7 +4113,9 @@ pref("devtools.experiment.f12.shortcut_disabled", false);
// doesn't provide a way to lock the pref
pref("dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled", false);
#else
-pref("dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled", false, locked);
+// Playwright: DO NOT make preference locked so that we can overwrite it
+// later in our playwright.cfg file.
+pref("dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled", false);
#endif
// Whether sites require the open-protocol-handler permission to open a
diff --git a/netwerk/base/nsINetworkInterceptController.idl b/netwerk/base/nsINetworkInterceptController.idl
index d72dc570dc82ff9d576942b9e7c23d8a74d68049..a5fcddc4b0e53a862e5a77120b4ccff8a27cfbab 100644
--- a/netwerk/base/nsINetworkInterceptController.idl
+++ b/netwerk/base/nsINetworkInterceptController.idl
@@ -59,6 +59,7 @@ interface nsIInterceptedChannel : nsISupports
* results in the resulting client not being controlled.
*/
void resetInterception(in boolean bypass);
+ void resetInterceptionWithURI(in nsIURI aURI);
/**
* Set the status and reason for the forthcoming synthesized response.
diff --git a/netwerk/protocol/http/InterceptedHttpChannel.cpp b/netwerk/protocol/http/InterceptedHttpChannel.cpp
index 735b3a134a8c7104909ff9424eff74eab80c4830..a31e8b68e201dbf238d80ab32d46d4657f9b8cd7 100644
--- a/netwerk/protocol/http/InterceptedHttpChannel.cpp
+++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp
@@ -728,6 +728,14 @@ NS_IMPL_ISUPPORTS(ResetInterceptionHeaderVisitor, nsIHttpHeaderVisitor)
} // anonymous namespace
+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",
@@ -1070,11 +1078,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/gecko-dev/commit/92e2cdde79c11510c3e4192e1b6264d00398ed95
+ /*
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/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp
index da570e5b6dbaffb9a7ba8bffcf14dd9e180d5215..3782a2d47b1feca7897924bff46ac4a0b0a383df 100644
--- a/parser/html/nsHtml5TreeOpExecutor.cpp
+++ b/parser/html/nsHtml5TreeOpExecutor.cpp
@@ -1371,6 +1371,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 4f2f595fb14c7c7244d5fe9a3da2eadc0c3b3adc..3ca0b4a3b9f4bdf21c1107a1e5ea3f0f58050f51 100644
--- a/security/manager/ssl/nsCertOverrideService.cpp
+++ b/security/manager/ssl/nsCertOverrideService.cpp
@@ -472,7 +472,12 @@ nsCertOverrideService::HasMatchingOverride(
bool disableAllSecurityCheck = false;
{
MutexAutoLock lock(mMutex);
- disableAllSecurityCheck = mDisableAllSecurityCheck;
+ if (aOriginAttributes.mUserContextId) {
+ disableAllSecurityCheck = mUserContextIdsWithDisabledSecurityChecks.has(
+ aOriginAttributes.mUserContextId);
+ } else {
+ disableAllSecurityCheck = mDisableAllSecurityCheck;
+ }
}
if (disableAllSecurityCheck) {
*aIsTemporary = false;
@@ -689,14 +694,24 @@ static bool IsDebugger() {
NS_IMETHODIMP
nsCertOverrideService::
- SetDisableAllSecurityChecksAndLetAttackersInterceptMyData(bool aDisable) {
- if (!(PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR") || IsDebugger())) {
+ SetDisableAllSecurityChecksAndLetAttackersInterceptMyData(
+ bool aDisable, uint32_t aUserContextId) {
+ if (false /* juggler hacks */ && !(PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR") || IsDebugger())) {
return NS_ERROR_NOT_AVAILABLE;
}
{
MutexAutoLock lock(mMutex);
- mDisableAllSecurityCheck = aDisable;
+ if (aUserContextId) {
+ if (aDisable) {
+ mozilla::Unused << mUserContextIdsWithDisabledSecurityChecks.put(aUserContextId);
+ } else {
+ mUserContextIdsWithDisabledSecurityChecks.remove(aUserContextId);
+ }
+ return NS_OK;
+ } else {
+ mDisableAllSecurityCheck = aDisable;
+ }
}
nsCOMPtr<nsINSSComponent> nss(do_GetService(PSM_COMPONENT_CONTRACTID));
diff --git a/security/manager/ssl/nsCertOverrideService.h b/security/manager/ssl/nsCertOverrideService.h
index 42760f8ec675af22bdf27a07954b1d3b600d29ab..aad868ef636dbb743f3268d662db7914a2418588 100644
--- a/security/manager/ssl/nsCertOverrideService.h
+++ b/security/manager/ssl/nsCertOverrideService.h
@@ -119,6 +119,7 @@ class nsCertOverrideService final : public nsICertOverrideService,
mozilla::Mutex mMutex;
bool mDisableAllSecurityCheck MOZ_GUARDED_BY(mMutex);
+ mozilla::HashSet<uint32_t> mUserContextIdsWithDisabledSecurityChecks MOZ_GUARDED_BY(mMutex);
nsCOMPtr<nsIFile> mSettingsFile MOZ_GUARDED_BY(mMutex);
nsTHashtable<nsCertOverrideEntry> mSettingsTable MOZ_GUARDED_BY(mMutex);
diff --git a/security/manager/ssl/nsICertOverrideService.idl b/security/manager/ssl/nsICertOverrideService.idl
index e31cf158dcac3540b0c721cbd677b8522d7549b3..029fc67df81911e3abf3724e8ed99e4bde010f4b 100644
--- a/security/manager/ssl/nsICertOverrideService.idl
+++ b/security/manager/ssl/nsICertOverrideService.idl
@@ -143,7 +143,9 @@ interface nsICertOverrideService : nsISupports {
* @param aDisable If true, disable all security check and make
* hasMatchingOverride always return true.
*/
- void setDisableAllSecurityChecksAndLetAttackersInterceptMyData(in boolean aDisable);
+ void setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
+ in boolean aDisable,
+ [optional] in uint32_t aUserContextId);
readonly attribute boolean securityCheckDisabled;
};
diff --git a/services/settings/Utils.jsm b/services/settings/Utils.jsm
index 94f47133802fd47a8a2bb800bdda8382d7ee82e5..2aa50e24dc1cb39012ed1d2b3b370cce546d28b1 100644
--- a/services/settings/Utils.jsm
+++ b/services/settings/Utils.jsm
@@ -103,7 +103,7 @@ function _isUndefined(value) {
var Utils = {
get SERVER_URL() {
- return lazy.allowServerURLOverride
+ return true || lazy.allowServerURLOverride
? lazy.gServerURL
: AppConstants.REMOTE_SETTINGS_SERVER_URL;
},
diff --git a/servo/components/style/gecko/media_features.rs b/servo/components/style/gecko/media_features.rs
index e2ba9f62f0fc8ab83a1d810f74f17d6dd195d6c2..23e268b300475b9372a31e836e52240f5b84852a 100644
--- a/servo/components/style/gecko/media_features.rs
+++ b/servo/components/style/gecko/media_features.rs
@@ -265,10 +265,15 @@ pub enum ForcedColors {
/// https://drafts.csswg.org/mediaqueries-5/#forced-colors
fn eval_forced_colors(context: &Context, query_value: Option<ForcedColors>) -> bool {
- let forced = !context.device().use_document_colors();
+ let prefers_forced_colors =
+ unsafe { bindings::Gecko_MediaFeatures_ForcedColors(context.device().document()) };
+ let query_value = match query_value {
+ Some(v) => v,
+ None => return prefers_forced_colors,
+ };
match query_value {
- Some(query_value) => forced == (query_value == ForcedColors::Active),
- None => forced,
+ ForcedColors::Active => prefers_forced_colors,
+ ForcedColors::None => !prefers_forced_colors,
}
}
diff --git a/toolkit/components/browser/nsIWebBrowserChrome.idl b/toolkit/components/browser/nsIWebBrowserChrome.idl
index 54de3abab5757dd706e3d909ccef6a0bed5deacc..f5c5480cd052ede0c76e5eec733dbb9283389045 100644
--- a/toolkit/components/browser/nsIWebBrowserChrome.idl
+++ b/toolkit/components/browser/nsIWebBrowserChrome.idl
@@ -71,6 +71,9 @@ interface nsIWebBrowserChrome : nsISupports
// Whether this window should use out-of-process cross-origin subframes.
const unsigned long CHROME_FISSION_WINDOW = 0x00200000;
+ // Whether this window has "width" or "height" defined in features
+ const unsigned long JUGGLER_WINDOW_EXPLICIT_SIZE = 0x00400000;
+
// Prevents new window animations on MacOS and Windows. Currently
// ignored for Linux.
const unsigned long CHROME_SUPPRESS_ANIMATION = 0x01000000;
diff --git a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs
index 0fad0ee2916098af5923f5ad0fc8a479f8ec706a..4b5586f7213919e871c085cb8b07f80f5a7d893f 100644
--- a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs
+++ b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs
@@ -113,6 +113,12 @@ EnterprisePoliciesManager.prototype = {
Services.prefs.clearUserPref(PREF_POLICIES_APPLIED);
}
+ // Playwright: Disable enterprise policies
+ if (true) {
+ this.status = Ci.nsIEnterprisePolicies.INACTIVE;
+ return;
+ }
+
let provider = this._chooseProvider();
if (provider.failed) {
diff --git a/toolkit/components/startup/nsAppStartup.cpp b/toolkit/components/startup/nsAppStartup.cpp
index 34ced370120f843ab7afd330fb5626ae6f6da7e4..205fc4e5fe3adeacbfe5ab6c15d1bbccf7baf9e8 100644
--- a/toolkit/components/startup/nsAppStartup.cpp
+++ b/toolkit/components/startup/nsAppStartup.cpp
@@ -370,7 +370,7 @@ nsAppStartup::Quit(uint32_t aMode, int aExitCode, bool* aUserAllowedQuit) {
nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
nsCOMPtr<nsIWindowMediator> mediator(
do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
- if (mediator) {
+ if (ferocity != eForceQuit && mediator) {
mediator->GetEnumerator(nullptr, getter_AddRefs(windowEnumerator));
if (windowEnumerator) {
bool more;
2019-11-18 18:18:28 -08:00
diff --git a/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp b/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp
index 654903fadb709be976b72f36f155e23bc0622152..815b3dc24c9fda6b1db6c4666ac68904c87ac0ab 100644
2019-11-18 18: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-18 18: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 6d6a91821e0df64e12e576d8c9e5b3d2e6aade27..1a8b8ff82586cca439dafc5e13e8c46adadd6ecc 100644
--- a/toolkit/components/windowwatcher/nsWindowWatcher.cpp
+++ b/toolkit/components/windowwatcher/nsWindowWatcher.cpp
@@ -1854,7 +1854,11 @@ uint32_t nsWindowWatcher::CalculateChromeFlagsForContent(
// Open a minimal popup.
*aIsPopupRequested = true;
- return nsIWebBrowserChrome::CHROME_MINIMAL_POPUP;
+ uint32_t chromeFlags = 0;
+ if (aFeatures.Exists("width") || aFeatures.Exists("height")) {
+ chromeFlags |= nsIWebBrowserChrome::JUGGLER_WINDOW_EXPLICIT_SIZE;
+ }
+ return chromeFlags | nsIWebBrowserChrome::CHROME_MINIMAL_POPUP;
}
/**
diff --git a/toolkit/mozapps/update/UpdateService.jsm b/toolkit/mozapps/update/UpdateService.jsm
index b6257a954787a9f4015c4d55836c70865edeb5a4..ea2eb94efea166aa90993217871c3c80c6d247fc 100644
--- a/toolkit/mozapps/update/UpdateService.jsm
+++ b/toolkit/mozapps/update/UpdateService.jsm
@@ -3864,6 +3864,8 @@ UpdateService.prototype = {
},
get disabledForTesting() {
+ /* for playwright */
+ return true;
return (
(Cu.isInAutomation ||
lazy.Marionette.running ||
2019-11-18 18:18:28 -08:00
diff --git a/toolkit/toolkit.mozbuild b/toolkit/toolkit.mozbuild
index 04453a437873b2e6339cb7e81ee11c2a5bb46bb1..2ce3151b9a97e7b86619109716a6d942b80f58ed 100644
2019-11-18 18:18:28 -08:00
--- a/toolkit/toolkit.mozbuild
+++ b/toolkit/toolkit.mozbuild
@@ -153,6 +153,7 @@ if CONFIG['ENABLE_WEBDRIVER']:
'/remote',
2019-11-18 18:18:28 -08:00
'/testing/firefox-ui',
'/testing/marionette',
+ '/juggler',
2019-11-18 18:18:28 -08:00
'/toolkit/components/telemetry/tests/marionette',
]
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-19 10:32:47 -08:00
diff --git a/toolkit/xre/nsWindowsWMain.cpp b/toolkit/xre/nsWindowsWMain.cpp
index ea14a59b80bbfbaa17d7569734b8409d9d21fcde..28cb052c3115f91e6a036ad8466385ff1d740cd0 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-19 10:32:47 -08:00
--- a/toolkit/xre/nsWindowsWMain.cpp
+++ b/toolkit/xre/nsWindowsWMain.cpp
@@ -14,9 +14,11 @@
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-19 10:32:47 -08:00
#endif
#include "mozilla/Char16.h"
+#include "mozilla/CmdLineAndEnvUtils.h"
#include "nsUTF8Utils.h"
#include "nsWindowsHelpers.h"
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-19 10:32:47 -08:00
+#include <io.h>
#include <windows.h>
#include <versionhelpers.h>
@@ -130,6 +132,19 @@ 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-19 10: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-19 10: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-18 18:18:28 -08:00
diff --git a/uriloader/base/nsDocLoader.cpp b/uriloader/base/nsDocLoader.cpp
index e1e46ccdceae595f95d100116ff480905047e82b..eaa0252e768140120158525723ad867b8cb020be 100644
2019-11-18 18:18:28 -08:00
--- a/uriloader/base/nsDocLoader.cpp
+++ b/uriloader/base/nsDocLoader.cpp
@@ -830,6 +830,13 @@ void nsDocLoader::DocLoaderIsEmpty(bool aFlushLayout,
("DocLoader:%p: Firing load event for document.open\n",
this));
+ nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
+ if (os) {
+ nsIPrincipal* principal = doc->NodePrincipal();
+ if (!principal->IsSystemPrincipal())
+ os->NotifyObservers(ToSupports(doc), "juggler-document-open-loaded", nullptr);
+ }
+
// This is a very cut-down version of
// nsDocumentViewer::LoadComplete that doesn't do various things
// that are not relevant here because this wasn't an actual
diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp
index 43dc9b0614ab007c938dbf66a02ff614524353b7..758dc42b1fcd4f81a1a13ae9e30942489a1b620c 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"
@@ -836,6 +837,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);
@@ -1446,7 +1453,12 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel* aChannel) {
// Strip off the ".part" from mTempLeafName
mTempLeafName.Truncate(mTempLeafName.Length() - ArrayLength(".part") + 1);
+ return CreateSaverForTempFile();
+}
+
+nsresult nsExternalAppHandler::CreateSaverForTempFile() {
MOZ_ASSERT(!mSaver, "Output file initialization called more than once!");
+ nsresult rv;
mSaver =
do_CreateInstance(NS_BACKGROUNDFILESAVERSTREAMLISTENER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
@@ -1635,7 +1647,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;
@@ -1687,6 +1728,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
@@ -2197,6 +2241,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;
}
@@ -2682,6 +2736,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 6c8cbc5871d3aa721a3f1a3ff6c0ef8b0044c63e..8e7c9af1a2cfe60c9c543af1ab55f6c229000bd4 100644
--- a/uriloader/exthandler/nsExternalHelperAppService.h
+++ b/uriloader/exthandler/nsExternalHelperAppService.h
@@ -257,6 +257,8 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService,
mozilla::dom::BrowsingContext* aContentContext, bool aForceSave,
nsIInterfaceRequestor* aWindowContext,
nsIStreamListener** aStreamListener);
+
+ nsCOMPtr<nsIDownloadInterceptor> mInterceptor;
};
/**
@@ -456,6 +458,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 307e6196a89df52d0bccc3ebd1359f58e32de75d..c3692d0f76178ac3aeb1c77a0e973bfa22359346 100644
--- a/uriloader/exthandler/nsIExternalHelperAppService.idl
+++ b/uriloader/exthandler/nsIExternalHelperAppService.idl
@@ -6,6 +6,8 @@
#include "nsICancelable.idl"
+webidl BrowsingContext;
+interface nsIHelperAppLauncher;
interface nsIURI;
interface nsIRequest;
interface nsIStreamListener;
@@ -15,6 +17,17 @@ interface nsIWebProgressListener2;
interface nsIInterfaceRequestor;
webidl BrowsingContext;
+/**
+ * Interceptor interface used by Juggler.
+ */
+[scriptable, uuid(9a20e9b0-75d0-11ea-bc55-0242ac130003)]
+interface nsIDownloadInterceptor : nsISupports
+{
+ bool interceptDownloadRequest(in nsIHelperAppLauncher aHandler, in nsIRequest aRequest, in BrowsingContext aBrowsingContext, out nsIFile file);
+
+ void onDownloadComplete(in nsIHelperAppLauncher aHandler, in ACString aErrorName);
+};
+
/**
* The external helper app service is used for finding and launching
* platform specific external applications for a given mime content type.
@@ -76,6 +89,7 @@ interface nsIExternalHelperAppService : nsISupports
boolean applyDecodingForExtension(in AUTF8String aExtension,
in ACString aEncodingType);
+ void setDownloadInterceptor(in nsIDownloadInterceptor interceptor);
};
/**
diff --git a/widget/InProcessCompositorWidget.cpp b/widget/InProcessCompositorWidget.cpp
index 1c25e9d9a101233f71e92288a0f93125b81ac1c5..22cf67b0f6e3ddd2b3ed725a314ba6a9896abd1c 100644
--- a/widget/InProcessCompositorWidget.cpp
+++ b/widget/InProcessCompositorWidget.cpp
@@ -4,7 +4,10 @@
#include "InProcessCompositorWidget.h"
+#include "HeadlessCompositorWidget.h"
+#include "HeadlessWidget.h"
#include "mozilla/VsyncDispatcher.h"
+#include "mozilla/widget/PlatformWidgetTypes.h"
#include "nsBaseWidget.h"
namespace mozilla {
@@ -23,6 +26,12 @@ RefPtr<CompositorWidget> CompositorWidget::CreateLocal(
// do it after the static_cast.
nsBaseWidget* widget = static_cast<nsBaseWidget*>(aWidget);
MOZ_RELEASE_ASSERT(widget);
+ if (aInitData.type() ==
+ CompositorWidgetInitData::THeadlessCompositorWidgetInitData) {
+ return new HeadlessCompositorWidget(
+ aInitData.get_HeadlessCompositorWidgetInitData(), aOptions,
+ static_cast<HeadlessWidget*>(aWidget));
+ }
return new InProcessCompositorWidget(aOptions, widget);
}
#endif
diff --git a/widget/MouseEvents.h b/widget/MouseEvents.h
index 5a19cb4082674ede982a0c66c84bf7c4642abe2b..5fe6ae7b5bf605e5d9130aa164d7cbbb486e54e0 100644
--- a/widget/MouseEvents.h
+++ b/widget/MouseEvents.h
@@ -203,6 +203,7 @@ class WidgetMouseEvent : public WidgetMouseEventBase,
: mReason(eReal),
mContextMenuTrigger(eNormal),
mClickCount(0),
+ mJugglerEventId(0),
mIgnoreRootScrollFrame(false),
mUseLegacyNonPrimaryDispatch(false),
mClickEventPrevented(false) {}
@@ -213,6 +214,7 @@ class WidgetMouseEvent : public WidgetMouseEventBase,
mReason(aReason),
mContextMenuTrigger(eNormal),
mClickCount(0),
+ mJugglerEventId(0),
mIgnoreRootScrollFrame(false),
mUseLegacyNonPrimaryDispatch(false),
mClickEventPrevented(false) {}
@@ -231,6 +233,7 @@ class WidgetMouseEvent : public WidgetMouseEventBase,
mReason(aReason),
mContextMenuTrigger(aContextMenuTrigger),
mClickCount(0),
+ mJugglerEventId(0),
mIgnoreRootScrollFrame(false),
mUseLegacyNonPrimaryDispatch(false),
mClickEventPrevented(false) {
@@ -280,6 +283,9 @@ class WidgetMouseEvent : public WidgetMouseEventBase,
// Otherwise, this must be 0.
uint32_t mClickCount;
+ // Unique event ID
+ uint32_t mJugglerEventId;
+
// Whether the event should ignore scroll frame bounds during dispatch.
bool mIgnoreRootScrollFrame;
@@ -296,6 +302,7 @@ class WidgetMouseEvent : public WidgetMouseEventBase,
mExitFrom = aEvent.mExitFrom;
mClickCount = aEvent.mClickCount;
+ mJugglerEventId = aEvent.mJugglerEventId;
mIgnoreRootScrollFrame = aEvent.mIgnoreRootScrollFrame;
mUseLegacyNonPrimaryDispatch = aEvent.mUseLegacyNonPrimaryDispatch;
mClickEventPrevented = aEvent.mClickEventPrevented;
diff --git a/widget/cocoa/NativeKeyBindings.mm b/widget/cocoa/NativeKeyBindings.mm
index d3e5983259053175584254e7ac01ca9ce024f33a..97f5b851c402fea5477c0ee57af451c62b016eec 100644
--- a/widget/cocoa/NativeKeyBindings.mm
+++ b/widget/cocoa/NativeKeyBindings.mm
@@ -492,6 +492,13 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
break;
case KEY_NAME_INDEX_ArrowLeft:
if (aEvent.IsAlt()) {
+ if (aEvent.IsMeta() || aEvent.IsControl())
+ break;
+ instance->AppendEditCommandsForSelector(
+ !aEvent.IsShift()
+ ? ToObjcSelectorPtr(@selector(moveWordLeft:))
+ : ToObjcSelectorPtr(@selector(moveWordLeftAndModifySelection:)),
+ aCommands);
break;
}
if (aEvent.IsMeta() || (aEvent.IsControl() && aEvent.IsShift())) {
@@ -512,6 +519,13 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
break;
case KEY_NAME_INDEX_ArrowRight:
if (aEvent.IsAlt()) {
+ if (aEvent.IsMeta() || aEvent.IsControl())
+ break;
+ instance->AppendEditCommandsForSelector(
+ !aEvent.IsShift()
+ ? ToObjcSelectorPtr(@selector(moveWordRight:))
+ : ToObjcSelectorPtr(@selector(moveWordRightAndModifySelection:)),
+ aCommands);
break;
}
if (aEvent.IsMeta() || (aEvent.IsControl() && aEvent.IsShift())) {
@@ -532,6 +546,10 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
break;
case KEY_NAME_INDEX_ArrowUp:
if (aEvent.IsControl()) {
+ if (aEvent.IsMeta() || aEvent.IsAlt())
+ break;
+ instance->AppendEditCommandsForSelector(
+ ToObjcSelectorPtr(@selector(scrollPageUp:)), aCommands);
break;
}
if (aEvent.IsMeta()) {
@@ -541,7 +559,7 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
instance->AppendEditCommandsForSelector(
!aEvent.IsShift()
? ToObjcSelectorPtr(@selector(moveToBeginningOfDocument:))
- : ToObjcSelectorPtr(@selector(moveToBegginingOfDocumentAndModifySelection:)),
+ : ToObjcSelectorPtr(@selector(moveToBeginningOfDocumentAndModifySelection:)),
aCommands);
break;
}
@@ -564,6 +582,10 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
break;
case KEY_NAME_INDEX_ArrowDown:
if (aEvent.IsControl()) {
+ if (aEvent.IsMeta() || aEvent.IsAlt())
+ break;
+ instance->AppendEditCommandsForSelector(
+ ToObjcSelectorPtr(@selector(scrollPageDown:)), aCommands);
break;
}
if (aEvent.IsMeta()) {
diff --git a/widget/headless/HeadlessCompositorWidget.cpp b/widget/headless/HeadlessCompositorWidget.cpp
index bb4ee9175e66dc40de1871a7f91368fe309494a3..856faef297c9eb0a510df123513b9ac095634e98 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"
@@ -16,7 +17,30 @@ HeadlessCompositorWidget::HeadlessCompositorWidget(
: CompositorWidget(aOptions),
mWidget(aWindow),
mClientSize(LayoutDeviceIntSize(aInitData.InitialClientSize()),
- "HeadlessCompositorWidget::mClientSize") {}
+ "HeadlessCompositorWidget::mClientSize"),
+ mMon("snapshotListener") {}
+
+void HeadlessCompositorWidget::SetSnapshotListener(HeadlessWidget::SnapshotListener&& listener) {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ ReentrantMonitorAutoEnter lock(mMon);
+ mSnapshotListener = std::move(listener);
+ layers::CompositorThread()->Dispatch(NewRunnableMethod(
+ "HeadlessCompositorWidget::PeriodicSnapshot", this,
+ &HeadlessCompositorWidget::PeriodicSnapshot
+ ));
+}
+
+already_AddRefed<gfx::DrawTarget> HeadlessCompositorWidget::StartRemoteDrawingInRegion(
+ const LayoutDeviceIntRegion& aInvalidRegion,
+ layers::BufferMode* aBufferMode) {
+ if (!mDrawTarget)
+ return nullptr;
+
+ *aBufferMode = layers::BufferMode::BUFFER_NONE;
+ RefPtr<gfx::DrawTarget> result = mDrawTarget;
+ return result.forget();
+}
void HeadlessCompositorWidget::ObserveVsync(VsyncObserver* aObserver) {
if (RefPtr<CompositorVsyncDispatcher> cvd =
@@ -31,6 +55,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..d6dea95472bec6006411753c3dfdab2e3659171f 100644
--- a/widget/headless/HeadlessCompositorWidget.h
+++ b/widget/headless/HeadlessCompositorWidget.h
@@ -6,6 +6,7 @@
#ifndef widget_headless_HeadlessCompositorWidget_h
#define widget_headless_HeadlessCompositorWidget_h
+#include "mozilla/ReentrantMonitor.h"
#include "mozilla/widget/CompositorWidget.h"
#include "HeadlessWidget.h"
@@ -23,8 +24,12 @@ class HeadlessCompositorWidget final : public CompositorWidget,
HeadlessWidget* aWindow);
void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize);
+ void SetSnapshotListener(HeadlessWidget::SnapshotListener&& listener);
// CompositorWidget Overrides
+ already_AddRefed<gfx::DrawTarget> StartRemoteDrawingInRegion(
+ const LayoutDeviceIntRegion& aInvalidRegion,
+ layers::BufferMode* aBufferMode) override;
uintptr_t GetWidgetKey() override;
@@ -42,10 +47,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 bb369eb0a5e1118d363c5a2fc35984b7d6c2aa28..3e9a6d31558c2720c2c6eef6a8de258bfa422a80 100644
--- a/widget/headless/HeadlessWidget.cpp
+++ b/widget/headless/HeadlessWidget.cpp
@@ -110,6 +110,8 @@ void HeadlessWidget::Destroy() {
}
}
+ SetSnapshotListener(nullptr);
+
nsBaseWidget::OnDestroy();
nsBaseWidget::Destroy();
@@ -621,5 +623,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 9856991ef32f25f51942f8cd664a09bec2192c70..948947a421179e91c51005aeb83ed0d18cfc84ce 100644
--- a/widget/headless/HeadlessWidget.h
+++ b/widget/headless/HeadlessWidget.h
@@ -141,6 +141,9 @@ class HeadlessWidget : 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 ad9c1887c6c95447b161b73c8623cef478137c75..c71e9ede72ff69c7e6c2080d804ec47c0051c397 100644
--- a/widget/nsGUIEventIPC.h
+++ b/widget/nsGUIEventIPC.h
@@ -234,6 +234,7 @@ struct ParamTraits<mozilla::WidgetMouseEvent> {
aParam.mExitFrom.value()));
}
WriteParam(aWriter, aParam.mClickCount);
+ WriteParam(aWriter, aParam.mJugglerEventId);
}
static bool Read(MessageReader* aReader, paramType* aResult) {
@@ -258,6 +259,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 2456c2c2b58b27cd595880b547ed20fb687a1835..e967c089b2331c7cd36d34e511543fbc84320b7d 100644
--- a/xpcom/reflect/xptinfo/xptinfo.h
+++ b/xpcom/reflect/xptinfo/xptinfo.h
@@ -514,7 +514,7 @@ static_assert(sizeof(nsXPTMethodInfo) == 8, "wrong size");
#if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
# define PARAM_BUFFER_COUNT 18
#else
-# define PARAM_BUFFER_COUNT 14
+# define PARAM_BUFFER_COUNT 15
#endif
/**