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 16e8c466e00d7dafe12e5e958c5be5967b06360b..a34658a87ac19797e694fb69dd369bb2476fb7d4 100644 --- a/browser/app/winlauncher/LauncherProcessWin.cpp +++ b/browser/app/winlauncher/LauncherProcessWin.cpp @@ -23,6 +23,7 @@ #include "mozilla/WinHeaderOnlyUtils.h" #include "nsWindowsHelpers.h" +#include #include #include @@ -421,8 +422,18 @@ Maybe LauncherMain(int& argc, wchar_t* argv[], HANDLE stdHandles[] = {::GetStdHandle(STD_INPUT_HANDLE), ::GetStdHandle(STD_OUTPUT_HANDLE), ::GetStdHandle(STD_ERROR_HANDLE)}; - attrs.AddInheritableHandles(stdHandles); + // Playwright pipe installation. + bool hasJugglerPipe = + mozilla::CheckArg(argc, argv, "juggler-pipe", nullptr, + mozilla::CheckArgFlag::None) == mozilla::ARG_FOUND; + if (hasJugglerPipe) { + intptr_t stdio3 = _get_osfhandle(3); + intptr_t stdio4 = _get_osfhandle(4); + HANDLE pipeHandles[] = {reinterpret_cast(stdio3), + reinterpret_cast(stdio4)}; + attrs.AddInheritableHandles(pipeHandles); + } DWORD creationFlags = CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT; diff --git a/browser/installer/allowed-dupes.mn b/browser/installer/allowed-dupes.mn index 6ab29ba31e937e1c5bb1208a9a2508ff0496fd02..7989da51c5368fa80cc66cccdfc018a9b3fb2f38 100644 --- 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 +# Juggler/marionette files +chrome/juggler/content/content/floating-scrollbars.css +browser/chrome/devtools/skin/floating-scrollbars-responsive-design.css +chrome/juggler/content/server/stream-utils.js +chrome/marionette/content/stream-utils.js + #ifdef MOZ_EME_WIN32_ARTIFACT gmp-clearkey/0.1/manifest.json i686/gmp-clearkey/0.1/manifest.json diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index 9229a0bd0e041815331aaf2973afda22c007423d..3ce0e453d4124d110e11877f5bbade776d11cfd4 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -196,6 +196,9 @@ @RESPATH@/chrome/remote.manifest #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 31a929e3150366d25f5acc295fe81ea0352d4621..217fe517155382ef7fa4d3cb6144be6784b83b55 100644 --- a/docshell/base/BrowsingContext.cpp +++ b/docshell/base/BrowsingContext.cpp @@ -111,6 +111,20 @@ struct ParamTraits mozilla::dom::PrefersColorSchemeOverride::None, mozilla::dom::PrefersColorSchemeOverride::EndGuard_> {}; +template <> +struct ParamTraits + : public ContiguousEnumSerializer< + mozilla::dom::PrefersReducedMotionOverride, + mozilla::dom::PrefersReducedMotionOverride::None, + mozilla::dom::PrefersReducedMotionOverride::EndGuard_> {}; + +template <> +struct ParamTraits + : public ContiguousEnumSerializer< + mozilla::dom::ForcedColorsOverride, + mozilla::dom::ForcedColorsOverride::None, + mozilla::dom::ForcedColorsOverride::EndGuard_> {}; + template <> struct ParamTraits : public ContiguousEnumSerializer< @@ -2839,6 +2853,40 @@ void BrowsingContext::DidSet(FieldIndex, PresContextAffectingFieldChanged(); } +void BrowsingContext::DidSet(FieldIndex, + dom::PrefersReducedMotionOverride aOldValue) { + MOZ_ASSERT(IsTop()); + if (PrefersReducedMotionOverride() == aOldValue) { + return; + } + PreOrderWalk([&](BrowsingContext* aContext) { + if (nsIDocShell* shell = aContext->GetDocShell()) { + if (nsPresContext* pc = shell->GetPresContext()) { + pc->MediaFeatureValuesChanged( + {MediaFeatureChangeReason::SystemMetricsChange}, + MediaFeatureChangePropagation::JustThisDocument); + } + } + }); +} + +void BrowsingContext::DidSet(FieldIndex, + 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, nsString&& aOldValue) { MOZ_ASSERT(IsTop()); diff --git a/docshell/base/BrowsingContext.h b/docshell/base/BrowsingContext.h index 8d32d0f5a37396eb18aa217bcac887f131df9fa2..4971c7ea0c38e2fef4b138dbadd17de1288afe08 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) \ FIELD(MessageManagerGroup, nsString) \ FIELD(MaxTouchPointsOverride, uint8_t) \ @@ -231,6 +231,10 @@ struct EmbedderColorSchemes { * 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) \ @@ -922,6 +926,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(); } @@ -1079,6 +1091,23 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { void PresContextAffectingFieldChanged(); + bool CanSet(FieldIndex, + dom::PrefersReducedMotionOverride, ContentParent*) { + return IsTop(); + } + + void DidSet(FieldIndex, + dom::PrefersReducedMotionOverride aOldValue); + + + bool CanSet(FieldIndex, + dom::ForcedColorsOverride, ContentParent*) { + return IsTop(); + } + + void DidSet(FieldIndex, + dom::ForcedColorsOverride aOldValue); + void DidSet(FieldIndex, nsString&& aOldValue); bool CanSet(FieldIndex, bool, ContentParent*) { diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 0a029957c8232018f46dd1a677e131bc91f12ad6..f24d066592c186ec9059732e3ab59938ab7061e0 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -15,6 +15,12 @@ # include // for getpid() #endif +#if JS_HAS_INTL_API && !MOZ_SYSTEM_ICU +# include "unicode/locid.h" +#endif /* JS_HAS_INTL_API && !MOZ_SYSTEM_ICU */ + +#include "js/LocaleSensitive.h" + #include "mozilla/ArrayUtils.h" #include "mozilla/Attributes.h" #include "mozilla/AutoRestore.h" @@ -65,6 +71,7 @@ #include "mozilla/dom/ContentFrameMessageManager.h" #include "mozilla/dom/DocGroup.h" #include "mozilla/dom/Element.h" +#include "mozilla/dom/Geolocation.h" #include "mozilla/dom/HTMLAnchorElement.h" #include "mozilla/dom/HTMLIFrameElement.h" #include "mozilla/dom/PerformanceNavigation.h" @@ -90,6 +97,7 @@ #include "mozilla/dom/JSWindowActorChild.h" #include "mozilla/dom/DocumentBinding.h" #include "mozilla/ipc/ProtocolUtils.h" +#include "mozilla/dom/WorkerCommon.h" #include "mozilla/net/DocumentChannel.h" #include "mozilla/net/DocumentChannelChild.h" #include "mozilla/net/ParentChannelWrapper.h" @@ -114,6 +122,7 @@ #include "nsIDocShellTreeOwner.h" #include "mozilla/dom/Document.h" #include "nsHTMLDocument.h" +#include "mozilla/dom/Element.h" #include "nsIDocumentLoaderFactory.h" #include "nsIDOMWindow.h" #include "nsIEditingSession.h" @@ -208,6 +217,7 @@ #include "nsFocusManager.h" #include "nsGlobalWindow.h" #include "nsJSEnvironment.h" +#include "nsJSUtils.h" #include "nsNetCID.h" #include "nsNetUtil.h" #include "nsObjectLoadingContent.h" @@ -371,6 +381,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), @@ -3268,6 +3286,234 @@ nsDocShell::GetMessageManager(ContentFrameMessageManager** aMessageManager) { return NS_OK; } +// =============== Juggler Begin ======================= + +nsDocShell* nsDocShell::GetRootDocShell() { + nsCOMPtr rootAsItem; + GetInProcessSameTypeRootTreeItem(getter_AddRefs(rootAsItem)); + nsCOMPtr rootShell = do_QueryInterface(rootAsItem); + return nsDocShell::Cast(rootShell); +} + +NS_IMETHODIMP +nsDocShell::GetBypassCSPEnabled(bool* aEnabled) { + MOZ_ASSERT(aEnabled); + *aEnabled = mBypassCSPEnabled; + return NS_OK; +} + +NS_IMETHODIMP +nsDocShell::SetBypassCSPEnabled(bool aEnabled) { + mBypassCSPEnabled = aEnabled; + return NS_OK; +} + +NS_IMETHODIMP +nsDocShell::GetForceActiveState(bool* aEnabled) { + MOZ_ASSERT(aEnabled); + *aEnabled = mForceActiveState; + return NS_OK; +} + +NS_IMETHODIMP +nsDocShell::SetForceActiveState(bool aEnabled) { + mForceActiveState = aEnabled; + ActivenessMaybeChanged(); + return NS_OK; +} + +NS_IMETHODIMP +nsDocShell::GetDisallowBFCache(bool* aEnabled) { + MOZ_ASSERT(aEnabled); + *aEnabled = mDisallowBFCache; + return NS_OK; +} + +NS_IMETHODIMP +nsDocShell::SetDisallowBFCache(bool aEnabled) { + mDisallowBFCache = aEnabled; + return NS_OK; +} + +bool nsDocShell::IsBypassCSPEnabled() { + return GetRootDocShell()->mBypassCSPEnabled; +} + +NS_IMETHODIMP +nsDocShell::GetOverrideHasFocus(bool* aEnabled) { + MOZ_ASSERT(aEnabled); + *aEnabled = mOverrideHasFocus; + return NS_OK; +} + +NS_IMETHODIMP +nsDocShell::SetOverrideHasFocus(bool aEnabled) { + mOverrideHasFocus = aEnabled; + return NS_OK; +} + +bool nsDocShell::ShouldOverrideHasFocus() const { + return mOverrideHasFocus; +} + +NS_IMETHODIMP +nsDocShell::GetLanguageOverride(nsAString& aLanguageOverride) { + aLanguageOverride = GetRootDocShell()->mLanguageOverride; + return NS_OK; +} + + +static void SetIcuLocale(const nsAString& aLanguageOverride) { + icu::Locale locale(NS_LossyConvertUTF16toASCII(aLanguageOverride).get()); + if (icu::Locale::getDefault() == locale) + 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 observerService = + mozilla::services::GetObserverService(); + observerService->NotifyObservers( + ToSupports(element), "juggler-file-picker-shown", nullptr); +} + +RefPtr nsDocShell::GetGeolocationServiceOverride() { + return GetRootDocShell()->mGeolocationServiceOverride; +} + +NS_IMETHODIMP +nsDocShell::SetGeolocationOverride(nsIDOMGeoPosition* aGeolocationOverride) { + if (aGeolocationOverride) { + if (!mGeolocationServiceOverride) { + mGeolocationServiceOverride = new nsGeolocationService(); + mGeolocationServiceOverride->Init(); + } + mGeolocationServiceOverride->Update(aGeolocationOverride); + } else { + mGeolocationServiceOverride = nullptr; + } + return NS_OK; +} + +NS_IMETHODIMP +nsDocShell::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 presContext = GetPresContext(); + if (presContext) { + presContext->MediaFeatureValuesChanged( + {MediaFeatureChangeReason::SystemMetricsChange}, + MediaFeatureChangePropagation::JustThisDocument); + } + return NS_OK; +} + +NS_IMETHODIMP +nsDocShell::GetForcedColorsOverride(ForcedColorsOverride* aForcedColorsOverride) { + *aForcedColorsOverride = GetRootDocShell()->mForcedColorsOverride; + return NS_OK; +} + +NS_IMETHODIMP +nsDocShell::SetForcedColorsOverride(ForcedColorsOverride aForcedColorsOverride) { + mForcedColorsOverride = aForcedColorsOverride; + RefPtr presContext = GetPresContext(); + if (presContext) { + presContext->MediaFeatureValuesChanged( + {MediaFeatureChangeReason::SystemMetricsChange}, + MediaFeatureChangePropagation::JustThisDocument); + } + return NS_OK; +} + +// =============== Juggler End ======================= + NS_IMETHODIMP nsDocShell::GetIsNavigating(bool* aOut) { *aOut = mIsNavigating; @@ -4895,7 +5141,7 @@ nsDocShell::GetVisibility(bool* aVisibility) { } void nsDocShell::ActivenessMaybeChanged() { - const bool isActive = mBrowsingContext->IsActive(); + const bool isActive = mForceActiveState || mBrowsingContext->IsActive(); if (RefPtr presShell = GetPresShell()) { presShell->ActivenessMaybeChanged(); } @@ -6847,6 +7093,10 @@ bool nsDocShell::CanSavePresentation(uint32_t aLoadType, return false; // no entry to save into } + if (mDisallowBFCache) { + return false; + } + MOZ_ASSERT(!mozilla::SessionHistoryInParent(), "mOSHE cannot be non-null with SHIP"); nsCOMPtr viewer = mOSHE->GetContentViewer(); @@ -8634,6 +8884,12 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState) { true, // aForceNoOpener getter_AddRefs(newBC)); MOZ_ASSERT(!newBC); + if (rv == NS_OK) { + nsCOMPtr observerService = mozilla::services::GetObserverService(); + if (observerService) { + observerService->NotifyObservers(GetAsSupports(this), "juggler-window-open-in-new-context", nullptr); + } + } return rv; } @@ -12793,6 +13049,9 @@ class OnLinkClickEvent : public Runnable { mHandler->OnLinkClickSync(mContent, mLoadState, mNoOpenerImplied, mTriggeringPrincipal); } + nsCOMPtr observerService = mozilla::services::GetObserverService(); + observerService->NotifyObservers(ToSupports(mContent), "juggler-link-click-sync", nullptr); + return NS_OK; } @@ -12872,6 +13131,8 @@ nsresult nsDocShell::OnLinkClick( nsCOMPtr ev = new OnLinkClickEvent(this, aContent, loadState, noOpenerImplied, aIsTrusted, aTriggeringPrincipal); + nsCOMPtr 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 293bfeee6e0779d15dd6ef60fc06f9969f70f003..a0481717f5f7b5ceb0301b7311c27b5631c258ee 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 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 @@ -1313,6 +1326,17 @@ class nsDocShell final : public nsDocLoader, bool mAllowDNSPrefetch : 1; bool mAllowWindowControl : 1; bool mCSSErrorReportingEnabled : 1; + bool mFileInputInterceptionEnabled: 1; + bool mOverrideHasFocus : 1; + bool mBypassCSPEnabled : 1; + bool mForceActiveState : 1; + bool mDisallowBFCache : 1; + nsString mLanguageOverride; + RefPtr mGeolocationServiceOverride; + OnlineOverride mOnlineOverride; + ReducedMotionOverride mReducedMotionOverride; + ForcedColorsOverride mForcedColorsOverride; + bool mAllowAuth : 1; bool mAllowKeywordFixup : 1; bool mDisableMetaRefreshWhenInactive : 1; diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl index 6b85ddd842a6d2e29f86047017b78b2007b99867..f530ab61ac26cb7c94c8ccd07d11aa90c5148212 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 5d529f6023db60091054b975ac9738b91326c330..a06117382098e45693e2170398dbf0b7715184cb 100644 --- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp @@ -3619,6 +3619,9 @@ void Document::SendToConsole(nsCOMArray& aMessages) { } void Document::ApplySettingsFromCSP(bool aSpeculative) { + if (mDocumentContainer && mDocumentContainer->IsBypassCSPEnabled()) + return; + nsresult rv = NS_OK; if (!aSpeculative) { // 1) apply settings from regular CSP @@ -3676,6 +3679,11 @@ nsresult Document::InitCSP(nsIChannel* aChannel) { MOZ_ASSERT(!mScriptGlobalObject, "CSP must be initialized before mScriptGlobalObject is set!"); + nsCOMPtr shell(mDocumentContainer); + if (shell && nsDocShell::Cast(shell)->IsBypassCSPEnabled()) { + return NS_OK; + } + // If this is a data document - no need to set CSP. if (mLoadedAsData) { return NS_OK; @@ -4491,6 +4499,10 @@ bool Document::HasFocus(ErrorResult& rv) const { return false; } + if (IsActive() && mDocumentContainer->ShouldOverrideHasFocus()) { + return true; + } + if (!fm->IsInActiveWindow(bc)) { return false; } @@ -17838,6 +17850,71 @@ ColorScheme Document::PreferredColorScheme(IgnoreRFP aIgnoreRFP) const { return LookAndFeel::PreferredColorSchemeForContent(); } +bool Document::PrefersReducedMotion() const { + auto* docShell = static_cast(GetDocShell()); + nsIDocShell::ReducedMotionOverride reducedMotion; + if (docShell && docShell->GetReducedMotionOverride(&reducedMotion) == NS_OK && + reducedMotion != nsIDocShell::REDUCED_MOTION_OVERRIDE_NONE) { + switch (reducedMotion) { + case nsIDocShell::REDUCED_MOTION_OVERRIDE_REDUCE: + return true; + case nsIDocShell::REDUCED_MOTION_OVERRIDE_NO_PREFERENCE: + return false; + case nsIDocShell::REDUCED_MOTION_OVERRIDE_NONE: + break; + }; + } + + if (auto* bc = GetBrowsingContext()) { + switch (bc->Top()->PrefersReducedMotionOverride()) { + case dom::PrefersReducedMotionOverride::Reduce: + return true; + case dom::PrefersReducedMotionOverride::No_preference: + return false; + case dom::PrefersReducedMotionOverride::None: + case dom::PrefersReducedMotionOverride::EndGuard_: + break; + } + } + + if (nsContentUtils::ShouldResistFingerprinting(this)) { + return false; + } + return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1; +} + +bool Document::ForcedColors() const { + auto* docShell = static_cast(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 b81fb1088ab0025555c24e7353cda836f896b26b..21403d0a219cc478b8de20fda410eb265eb1569a 100644 --- a/dom/base/Document.h +++ b/dom/base/Document.h @@ -4023,6 +4023,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 e432d25c7397be64b009e4cb671cb6e322175830..074b1c7241c64412ee58a6239d36c9f74476ae46 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -326,14 +326,18 @@ void Navigator::GetAppName(nsAString& aAppName, CallerType aCallerType) const { * for more detail. */ /* static */ -void Navigator::GetAcceptLanguages(nsTArray& aLanguages) { +void Navigator::GetAcceptLanguages(const nsString* aLanguageOverride, nsTArray& aLanguages) { MOZ_ASSERT(NS_IsMainThread()); aLanguages.Clear(); // E.g. "de-de, en-us,en". nsAutoString acceptLang; - Preferences::GetLocalizedString("intl.accept_languages", acceptLang); + if (aLanguageOverride && aLanguageOverride->Length()) + acceptLang = *aLanguageOverride; + else + Preferences::GetLocalizedString("intl.accept_languages", acceptLang); + // Split values on commas. for (nsDependentSubstring lang : @@ -385,7 +389,13 @@ void Navigator::GetLanguage(nsAString& aLanguage) { } void Navigator::GetLanguages(nsTArray& aLanguages) { - GetAcceptLanguages(aLanguages); + if (mWindow && mWindow->GetDocShell()) { + nsString languageOverride; + mWindow->GetDocShell()->GetLanguageOverride(languageOverride); + GetAcceptLanguages(&languageOverride, aLanguages); + } else { + GetAcceptLanguages(nullptr, aLanguages); + } // The returned value is cached by the binding code. The window listens to the // accept languages change and will clear the cache when needed. It has to @@ -564,7 +574,13 @@ bool Navigator::CookieEnabled() { return granted; } -bool Navigator::OnLine() { return !NS_IsOffline(); } +bool Navigator::OnLine() { + nsDocShell* docShell = static_cast(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 { @@ -2257,7 +2273,8 @@ bool Navigator::Webdriver() { } #endif - return false; + // Playwright is automating the browser, so we should pretend to be a webdriver + return true; } } // namespace mozilla::dom diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h index 19b9c31fa2464fc3e865e7a7d69ff91140153510..14b617eefc5c23fcca20c407cb71b5618321f6da 100644 --- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -219,7 +219,7 @@ class Navigator final : public nsISupports, public nsWrapperCache { StorageManager* Storage(); - static void GetAcceptLanguages(nsTArray& aLanguages); + static void GetAcceptLanguages(const nsString* aLanguageOverride, nsTArray& aLanguages); dom::MediaCapabilities* MediaCapabilities(); dom::MediaSession* MediaSession(); diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 5a11c595acf75c2de3a50e33572e61f60379dbe9..4b0818df3622ee285f13d7d47bbbe681b5bfb8a3 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -8357,7 +8357,8 @@ nsresult nsContentUtils::SendMouseEvent( bool aIgnoreRootScrollFrame, float aPressure, unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow, PreventDefaultResult* aPreventDefault, bool aIsDOMEventSynthesized, - bool aIsWidgetEventSynthesized) { + bool aIsWidgetEventSynthesized, + bool convertToPointer) { nsPoint offset; nsCOMPtr widget = GetWidget(aPresShell, &offset); if (!widget) return NS_ERROR_FAILURE; @@ -8365,6 +8366,7 @@ nsresult nsContentUtils::SendMouseEvent( EventMessage msg; Maybe exitFrom; bool contextMenuKey = false; + bool isDragEvent = false; if (aType.EqualsLiteral("mousedown")) { msg = eMouseDown; } else if (aType.EqualsLiteral("mouseup")) { @@ -8389,6 +8391,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; } @@ -8397,12 +8405,21 @@ nsresult nsContentUtils::SendMouseEvent( aInputSourceArg = MouseEvent_Binding::MOZ_SOURCE_MOUSE; } - WidgetMouseEvent event(true, msg, widget, + std::unique_ptr 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; @@ -8416,6 +8433,7 @@ nsresult nsContentUtils::SendMouseEvent( event.mTime = PR_IntervalNow(); event.mFlags.mIsSynthesizedForTests = aIsDOMEventSynthesized; event.mExitFrom = exitFrom; + event.convertToPointer = convertToPointer; nsPresContext* presContext = aPresShell->GetPresContext(); if (!presContext) return NS_ERROR_FAILURE; diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 0f48e5319a23b149f0daf38bf0910090c7bf616c..2263a70fe578800301f719a27d084840bc1d6e93 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -2944,7 +2944,8 @@ class nsContentUtils { int32_t aModifiers, bool aIgnoreRootScrollFrame, float aPressure, unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow, mozilla::PreventDefaultResult* aPreventDefault, - bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized); + bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized, + bool convertToPointer = true); static void FirePageShowEventForFrameLoaderSwap( nsIDocShellTreeItem* aItem, diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 885083ab95bf5cfe8183934dfedc4e36b7eb6225..e51374306f322685f0fc1f1da9996d64281dfb79 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -683,7 +683,7 @@ nsDOMWindowUtils::SendMouseEvent( int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, float aPressure, unsigned short aInputSourceArg, bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized, - int32_t aButtons, uint32_t aIdentifier, uint8_t aOptionalArgCount, + int32_t aButtons, uint32_t aIdentifier, bool aDisablePointerEvent, uint8_t aOptionalArgCount, bool* aPreventDefault) { return SendMouseEventCommon( aType, aX, aY, aButton, aClickCount, aModifiers, aIgnoreRootScrollFrame, @@ -691,7 +691,7 @@ nsDOMWindowUtils::SendMouseEvent( aOptionalArgCount >= 7 ? aIdentifier : DEFAULT_MOUSE_POINTER_ID, false, aPreventDefault, aOptionalArgCount >= 4 ? aIsDOMEventSynthesized : true, aOptionalArgCount >= 5 ? aIsWidgetEventSynthesized : false, - aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED); + aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED, !aDisablePointerEvent); } NS_IMETHODIMP @@ -718,13 +718,13 @@ nsDOMWindowUtils::SendMouseEventCommon( int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, float aPressure, unsigned short aInputSourceArg, uint32_t aPointerId, bool aToWindow, bool* aPreventDefault, bool aIsDOMEventSynthesized, - bool aIsWidgetEventSynthesized, int32_t aButtons) { + bool aIsWidgetEventSynthesized, int32_t aButtons, bool aConvertToPointer) { RefPtr presShell = GetPresShell(); PreventDefaultResult preventDefaultResult; nsresult rv = nsContentUtils::SendMouseEvent( presShell, aType, aX, aY, aButton, aButtons, aClickCount, aModifiers, aIgnoreRootScrollFrame, aPressure, aInputSourceArg, aPointerId, aToWindow, - &preventDefaultResult, aIsDOMEventSynthesized, aIsWidgetEventSynthesized); + &preventDefaultResult, aIsDOMEventSynthesized, aIsWidgetEventSynthesized, aConvertToPointer); if (aPreventDefault) { *aPreventDefault = preventDefaultResult != PreventDefaultResult::No; diff --git a/dom/base/nsDOMWindowUtils.h b/dom/base/nsDOMWindowUtils.h index 30e0fafa77857c33e9871259a6ac0cebac965df8..3d8810abcfac1c220529b4e6163b0159475723ff 100644 --- a/dom/base/nsDOMWindowUtils.h +++ b/dom/base/nsDOMWindowUtils.h @@ -93,7 +93,7 @@ class nsDOMWindowUtils final : public nsIDOMWindowUtils, int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, float aPressure, unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow, bool* aPreventDefault, bool aIsDOMEventSynthesized, - bool aIsWidgetEventSynthesized, int32_t aButtons); + bool aIsWidgetEventSynthesized, int32_t aButtons, bool aConvertToPointer = true); MOZ_CAN_RUN_SCRIPT nsresult SendTouchEventCommon( diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp index cf46ac3458eb2d45b8cf2bfd2e06c8597a07d30b..e308ee762ed5936fb92332cf65e53e69e063ebeb 100644 --- a/dom/base/nsFocusManager.cpp +++ b/dom/base/nsFocusManager.cpp @@ -1613,6 +1613,10 @@ void nsFocusManager::SetFocusInner(Element* aNewContent, int32_t aFlags, (GetActiveBrowsingContext() == newRootBrowsingContext); } + // In Playwright, we want to send focus events even if the element + // isn't actually in the active window. + isElementInActiveWindow = true; + // Exit fullscreen if a website focuses another window if (StaticPrefs::full_screen_api_exit_on_windowRaise() && !isElementInActiveWindow && (aFlags & FLAG_RAISE) && @@ -2927,7 +2931,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 d8e2ac7cc54c2ca8adb914b05328c76e909a3041..2b49a20cac7376ea561b2bad1bce1bd216dc960e 100644 --- a/dom/base/nsGlobalWindowOuter.cpp +++ b/dom/base/nsGlobalWindowOuter.cpp @@ -2485,7 +2485,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 @@ -2504,10 +2504,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)); + } } } @@ -2628,6 +2634,19 @@ void nsGlobalWindowOuter::DispatchDOMWindowCreated() { } } +void nsGlobalWindowOuter::JugglerDispatchDOMWindowReused() { + nsCOMPtr observerService = + mozilla::services::GetObserverService(); + if (observerService && mDoc) { + nsIPrincipal* principal = mDoc->NodePrincipal(); + if (!principal->IsSystemPrincipal()) { + observerService->NotifyObservers(static_cast(this), + "juggler-dom-window-reused", + nullptr); + } + } +} + void nsGlobalWindowOuter::ClearStatus() { SetStatusOuter(u""_ns); } void nsGlobalWindowOuter::SetDocShell(nsDocShell* aDocShell) { @@ -3765,6 +3784,14 @@ Maybe nsGlobalWindowOuter::GetRDMDeviceSize( } } } + if (topInProcessContentDoc) { + nsIDocShell* docShell = topInProcessContentDoc->GetDocShell(); + if (docShell && docShell->GetDeviceSizeIsPageSize()) { + nsPresContext* presContext = docShell->GetPresContext(); + if (presContext) + return Some(CSSPixel::FromAppUnitsRounded(presContext->GetVisibleArea().Size())); + } + } return Nothing(); } diff --git a/dom/base/nsGlobalWindowOuter.h b/dom/base/nsGlobalWindowOuter.h index 96bb20c65ab6211e4fdf04b0d5f15b0764143672..4c54c97fb6789798921cc6e3b4d4ef7318756d00 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 7260effcc77431adb800e3577183002369c614d3..4fe3d05882d6a14dbf32dd842d7039ae8da4cae4 100644 --- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp @@ -1331,6 +1331,62 @@ void nsINode::GetBoxQuadsFromWindowOrigin(const BoxQuadOptions& aOptions, mozilla::GetBoxQuadsFromWindowOrigin(this, aOptions, aResult, aRv); } +static nsIFrame* GetFirstFrame(nsINode* aNode) { + if (!aNode->IsContent()) + return nullptr; + nsIFrame* frame = aNode->AsContent()->GetPrimaryFrame(FlushType::Frames); + if (!frame) { + FlattenedChildIterator iter(aNode->AsContent()); + for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { + frame = child->GetPrimaryFrame(FlushType::Frames); + if (frame) { + break; + } + } + } + return frame; +} + +void nsINode::ScrollRectIntoViewIfNeeded(int32_t x, int32_t y, + int32_t w, int32_t h, + ErrorResult& aRv) { + aRv = NS_ERROR_UNEXPECTED; + nsCOMPtr document = OwnerDoc(); + if (!document) { + return aRv.ThrowNotFoundError("Node is detached from document"); + } + PresShell* presShell = document->GetPresShell(); + if (!presShell) { + return aRv.ThrowNotFoundError("Node is detached from document"); + } + nsIFrame* primaryFrame = GetFirstFrame(this); + if (!primaryFrame) { + return aRv.ThrowNotFoundError("Node does not have a layout object"); + } + aRv = NS_OK; + nsRect rect; + if (x == -1 && y == -1 && w == -1 && h == -1) { + rect = primaryFrame->GetRectRelativeToSelf(); + } else { + rect = nsRect(nsPresContext::CSSPixelsToAppUnits(x), + nsPresContext::CSSPixelsToAppUnits(y), + nsPresContext::CSSPixelsToAppUnits(w), + nsPresContext::CSSPixelsToAppUnits(h)); + } + presShell->ScrollFrameRectIntoView( + primaryFrame, rect, + nsMargin(), + ScrollAxis(kScrollToCenter, WhenToScroll::Always), + ScrollAxis(kScrollToCenter, WhenToScroll::Always), + ScrollFlags::ScrollOverflowHidden); + // If a _visual_ scroll update is pending, cancel it; otherwise, it will + // clobber next scroll (e.g. subsequent window.scrollTo(0, 0) wlll break). + if (presShell->GetPendingVisualScrollUpdate()) { + presShell->AcknowledgePendingVisualScrollUpdate(); + presShell->ClearPendingVisualScrollUpdate(); + } +} + already_AddRefed 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 fccf07b43eb05f709eaf49e63c00ab7ddb6df11b..2c07a0f1cf8e321df047b3ef8bcba88752fb855b 100644 --- a/dom/base/nsINode.h +++ b/dom/base/nsINode.h @@ -2140,6 +2140,10 @@ class nsINode : public mozilla::dom::EventTarget { nsTArray>& aResult, ErrorResult& aRv); + void ScrollRectIntoViewIfNeeded(int32_t x, int32_t y, + int32_t w, int32_t h, + ErrorResult& aRv); + already_AddRefed ConvertQuadFromNode( DOMQuad& aQuad, const TextOrElementOrDocument& aFrom, const ConvertCoordinateOptions& aOptions, CallerType aCallerType, diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp index 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 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 76d0d088dea7520f5fd7753525e98840f30db969..fa8ddfc7fbe0969079892b8f035eece2aeed61eb 100644 --- a/dom/chrome-webidl/BrowsingContext.webidl +++ b/dom/chrome-webidl/BrowsingContext.webidl @@ -52,6 +52,24 @@ enum PrefersColorSchemeOverride { "dark", }; +/** + * CSS prefers-reduced-motion values. + */ +enum PrefersReducedMotionOverride { + "none", + "reduce", + "no-preference", +}; + +/** + * CSS forced-colors values. + */ +enum ForcedColorsOverride { + "none", + "active", + "no-override", /* This clears the override. */ +}; + /** * Allowed overrides of platform/pref default behaviour for touch events. */ @@ -186,6 +204,12 @@ interface BrowsingContext { // Color-scheme simulation, for DevTools. [SetterThrows] attribute PrefersColorSchemeOverride prefersColorSchemeOverride; + // Reduced-Motion simulation, for DevTools. + [SetterThrows] attribute PrefersReducedMotionOverride prefersReducedMotionOverride; + + // Forced-Colors simulation, for DevTools. + [SetterThrows] attribute ForcedColorsOverride forcedColorsOverride; + /** * A unique identifier for the browser element that is hosting this * BrowsingContext tree. Every BrowsingContext in the element's tree will diff --git a/dom/geolocation/Geolocation.cpp b/dom/geolocation/Geolocation.cpp index 1d2f65deb8add446993a8a578e1f8bb5b46de090..8dd68391e0e0eb1e6d92898f5263cc984836ee7c 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 aChoices) { return NS_OK; } - RefPtr 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 gs = - nsGeolocationService::GetGeolocationService(); + nsGeolocationService* gs = mLocator ? mLocator->GetGeolocationService() : nullptr; if (gs) { gs->UpdateAccuracy(); } @@ -732,8 +730,14 @@ void nsGeolocationService::StopDevice() { StaticRefPtr nsGeolocationService::sService; already_AddRefed -nsGeolocationService::GetGeolocationService() { +nsGeolocationService::GetGeolocationService(nsDocShell* docShell) { RefPtr 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 doc = aContentDom ? aContentDom->GetDoc() : nullptr; + mService = nsGeolocationService::GetGeolocationService( + doc ? static_cast(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 GetGeolocationService(); + static already_AddRefed GetGeolocationService(nsDocShell* docShell = nullptr); static mozilla::StaticRefPtr sService; NS_DECL_THREADSAFE_ISUPPORTS @@ -179,6 +181,8 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache { // null. static already_AddRefed NonWindowSingleton(); + nsGeolocationService* GetGeolocationService() { return mService; }; + private: ~Geolocation(); diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index 6a724b3e39c0a37450780804c8b07003b2a6656e..dbc79440e34f9dc01a16bf579446ca19a80cc59a 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -53,6 +53,7 @@ #include "nsMappedAttributes.h" #include "nsIFormControl.h" #include "mozilla/dom/Document.h" +#include "nsDocShell.h" #include "nsIFormControlFrame.h" #include "nsITextControlFrame.h" #include "nsIFrame.h" @@ -746,6 +747,12 @@ nsresult HTMLInputElement::InitFilePicker(FilePickerType aType) { return NS_ERROR_FAILURE; } + nsDocShell* docShell = static_cast(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 faefb552491e75b674e4f27418089ef7fcc1a3c0..a1e79fce86440e617ee2e7ae4a3eb0769aa72cfb 100644 --- a/dom/interfaces/base/nsIDOMWindowUtils.idl +++ b/dom/interfaces/base/nsIDOMWindowUtils.idl @@ -372,7 +372,8 @@ interface nsIDOMWindowUtils : nsISupports { [optional] in boolean aIsDOMEventSynthesized, [optional] in boolean aIsWidgetEventSynthesized, [optional] in long aButtons, - [optional] in unsigned long aIdentifier); + [optional] in unsigned long aIdentifier, + [optional] in boolean aDisablePointerEvent); /** Synthesize a touch event. The event types supported are: * touchstart, touchend, touchmove, and touchcancel diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.cc b/dom/media/systemservices/video_engine/desktop_capture_impl.cc index 3d8f2a67e3ec273bc0e7be610b4e683dc23280d4..728f2fdaf1410b86c0d20df0cfbb29beab4c03bf 100644 --- a/dom/media/systemservices/video_engine/desktop_capture_impl.cc +++ b/dom/media/systemservices/video_engine/desktop_capture_impl.cc @@ -124,10 +124,11 @@ int32_t ScreenDeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8, return 0; } -VideoCaptureModule* DesktopCaptureImpl::Create(const int32_t id, +VideoCaptureModuleEx* DesktopCaptureImpl::Create(const int32_t id, const char* uniqueId, - const CaptureDeviceType type) { - return new rtc::RefCountedObject(id, uniqueId, type); + const CaptureDeviceType type, + bool captureCursor) { + return new rtc::RefCountedObject(id, uniqueId, type, captureCursor); } int32_t WindowDeviceInfoImpl::Init() { @@ -365,9 +366,13 @@ int32_t DesktopCaptureImpl::LazyInitDesktopCapturer() { DesktopCapturer::SourceId sourceId = atoi(_deviceUniqueId.c_str()); pWindowCapturer->SelectSource(sourceId); - desktop_capturer_cursor_composer_ = - std::unique_ptr( - new DesktopAndCursorComposer(std::move(pWindowCapturer), options)); + if (capture_cursor_) { + desktop_capturer_cursor_composer_ = + std::unique_ptr( + new DesktopAndCursorComposer(std::move(pWindowCapturer), options)); + } else { + desktop_capturer_cursor_composer_ = std::move(pWindowCapturer); + } } else if (_deviceType == CaptureDeviceType::Browser) { // XXX We don't capture cursors, so avoid the extra indirection layer. We // could also pass null for the pMouseCursorMonitor. @@ -384,13 +389,15 @@ int32_t DesktopCaptureImpl::LazyInitDesktopCapturer() { } DesktopCaptureImpl::DesktopCaptureImpl(const int32_t id, const char* uniqueId, - const CaptureDeviceType type) + const CaptureDeviceType type, + bool captureCursor) : _id(id), _deviceUniqueId(uniqueId), _deviceType(type), _requestedCapability(), _rotateFrame(kVideoRotation_0), last_capture_time_ms_(rtc::TimeMillis()), + capture_cursor_(captureCursor), time_event_(EventWrapper::Create()), capturer_thread_(nullptr), started_(false) { @@ -428,6 +435,19 @@ void DesktopCaptureImpl::DeRegisterCaptureDataCallback( } } +void DesktopCaptureImpl::RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) { + rtc::CritScope lock(&_apiCs); + _rawFrameCallbacks.insert(rawFrameCallback); +} + +void DesktopCaptureImpl::DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) { + rtc::CritScope lock(&_apiCs); + auto it = _rawFrameCallbacks.find(rawFrameCallback); + if (it != _rawFrameCallbacks.end()) { + _rawFrameCallbacks.erase(it); + } +} + int32_t DesktopCaptureImpl::StopCaptureIfAllClientsClose() { if (_dataCallBacks.empty()) { return StopCapture(); @@ -645,6 +665,15 @@ void DesktopCaptureImpl::OnCaptureResult(DesktopCapturer::Result result, frameInfo.height = frame->size().height(); frameInfo.videoType = VideoType::kARGB; + size_t videoFrameStride = + frameInfo.width * DesktopFrame::kBytesPerPixel; + { + rtc::CritScope cs(&_apiCs); + for (auto rawFrameCallback : _rawFrameCallbacks) { + rawFrameCallback->OnRawFrame(videoFrame, videoFrameStride, frameInfo); + } + } + size_t videoFrameLength = frameInfo.width * frameInfo.height * DesktopFrame::kBytesPerPixel; IncomingFrame(videoFrame, videoFrameLength, diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.h b/dom/media/systemservices/video_engine/desktop_capture_impl.h index e8414b154fb615afd888ae06aae1d3046f042e69..fd86601a774befc8b7a03d953a73390870aa380f 100644 --- a/dom/media/systemservices/video_engine/desktop_capture_impl.h +++ b/dom/media/systemservices/video_engine/desktop_capture_impl.h @@ -48,6 +48,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 @@ -160,12 +175,13 @@ class BrowserDeviceInfoImpl : public VideoCaptureModule::DeviceInfo { // As with video, DesktopCaptureImpl is a proxy for screen sharing // and follows the video pipeline design class DesktopCaptureImpl : public DesktopCapturer::Callback, - public VideoCaptureModule { + public VideoCaptureModuleEx { public: /* Create a screen capture modules object */ - static VideoCaptureModule* Create(const int32_t id, const char* uniqueId, - const CaptureDeviceType type); + static VideoCaptureModuleEx* Create(const int32_t id, const char* uniqueId, + const CaptureDeviceType type, + bool captureCursor = true); static VideoCaptureModule::DeviceInfo* CreateDeviceInfo( const int32_t id, const CaptureDeviceType type); @@ -175,6 +191,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, void DeRegisterCaptureDataCallback( rtc::VideoSinkInterface* dataCallback) override; int32_t StopCaptureIfAllClientsClose() override; + void RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) override; + void DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) override; int32_t SetCaptureRotation(VideoRotation rotation) override; bool SetApplyRotation(bool enable) override; @@ -195,7 +213,7 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, protected: DesktopCaptureImpl(const int32_t id, const char* uniqueId, - const CaptureDeviceType type); + const CaptureDeviceType type, bool captureCursor); virtual ~DesktopCaptureImpl(); int32_t DeliverCapturedFrame(webrtc::VideoFrame& captureFrame); @@ -218,6 +236,7 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, rtc::RecursiveCriticalSection _apiCs; std::set*> _dataCallBacks; + std::set _rawFrameCallbacks; int64_t _incomingFrameTimesNanos [kFrameRateCountHistorySize]; // timestamp for local captured frames @@ -240,6 +259,7 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, void ProcessIter(); private: + bool capture_cursor_ = true; // This is created on the main thread and accessed on both the main thread // and the capturer thread. It is created prior to the capturer thread // starting and is destroyed after it is stopped. diff --git a/dom/script/ScriptSettings.cpp b/dom/script/ScriptSettings.cpp index 8c8a5810fd56512cf37635da1f43757719f06113..d2bc58fcd3b05f989f948839d574d00d0409873c 100644 --- a/dom/script/ScriptSettings.cpp +++ b/dom/script/ScriptSettings.cpp @@ -150,6 +150,30 @@ ScriptSettingsStackEntry::~ScriptSettingsStackEntry() { MOZ_ASSERT_IF(mGlobalObject, mGlobalObject->HasJSGlobal()); } +static nsIGlobalObject* UnwrapSandboxGlobal(nsIGlobalObject* global) { + if (!global) + return global; + JSObject* globalObject = global->GetGlobalJSObject(); + if (!globalObject) + return global; + JSContext* cx = nsContentUtils::GetCurrentJSContext(); + if (!cx) + return global; + JS::Rooted 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 3f0ca7fb77fc7722b8cf666b8af20ade826a7bb5..0864882a17e18c12bce73cbc5f259ea7641559b2 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( 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 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 2f9beef0bde229a2f414f46d3ec2b10eac5c4f1c..2aa8c6b75b7791e29b6f579718a2d6e250dc4236 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -981,7 +981,7 @@ void PrefLanguagesChanged(const char* /* aPrefName */, void* /* aClosure */) { AssertIsOnMainThread(); nsTArray languages; - Navigator::GetAcceptLanguages(languages); + Navigator::GetAcceptLanguages(nullptr, languages); RuntimeService* runtime = RuntimeService::GetService(); if (runtime) { @@ -1183,8 +1183,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; } @@ -1782,6 +1781,13 @@ void RuntimeService::PropagateStorageAccessPermissionGranted( } } +void RuntimeService::ResetDefaultLocaleInAllWorkers() { + AssertIsOnMainThread(); + BroadcastAllWorkers([](auto& worker) { + worker.ResetDefaultLocale(); + }); +} + template void RuntimeService::BroadcastAllWorkers(const Func& aFunc) { AssertIsOnMainThread(); @@ -2197,6 +2203,14 @@ void PropagateStorageAccessPermissionGrantedToWorkers( } } +void ResetDefaultLocaleInAllWorkers() { + AssertIsOnMainThread(); + RuntimeService* runtime = RuntimeService::GetService(); + if (runtime) { + runtime->ResetDefaultLocaleInAllWorkers(); + } +} + WorkerPrivate* GetWorkerPrivateFromContext(JSContext* aCx) { MOZ_ASSERT(!NS_IsMainThread()); MOZ_ASSERT(aCx); diff --git a/dom/workers/RuntimeService.h b/dom/workers/RuntimeService.h index 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 e15afcdebdecb9ceed97cb539a511b34670b19c1..9879d33cbe2a6ac3bc7965c9287f72804d60d8ec 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -700,6 +700,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 mLanguages; @@ -1952,6 +1964,16 @@ void WorkerPrivate::UpdateContextOptions( } } +void WorkerPrivate::ResetDefaultLocale() { + AssertIsOnParentThread(); + + RefPtr runnable = + new ResetDefaultLocaleRunnable(this); + if (!runnable->Dispatch()) { + NS_WARNING("Failed to reset default locale in worker!"); + } +} + void WorkerPrivate::UpdateLanguages(const nsTArray& aLanguages) { AssertIsOnParentThread(); @@ -5123,6 +5145,15 @@ void WorkerPrivate::UpdateContextOptionsInternal( } } +void WorkerPrivate::ResetDefaultLocaleInternal(JSContext* aCx) { + JS_ResetDefaultLocale(JS_GetRuntime(aCx)); + auto data = mWorkerThreadAccessible.Access(); + + for (uint32_t index = 0; index < data->mChildWorkers.Length(); index++) { + data->mChildWorkers[index]->ResetDefaultLocale(); + } +} + void WorkerPrivate::UpdateLanguagesInternal( const nsTArray& aLanguages) { WorkerGlobalScope* globalScope = GlobalScope(); diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index 41eb3a9cad9a5d49573faef26b4f6e3815064c85..9e58fc7746d4953ee29a76b4af4c488db35fe0df 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -330,6 +330,8 @@ class WorkerPrivate final void UpdateContextOptionsInternal(JSContext* aCx, const JS::ContextOptions& aContextOptions); + void ResetDefaultLocaleInternal(JSContext* aCx); + void UpdateLanguagesInternal(const nsTArray& aLanguages); void UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key, @@ -956,6 +958,8 @@ class WorkerPrivate final void UpdateContextOptions(const JS::ContextOptions& aContextOptions); + void ResetDefaultLocale(); + void UpdateLanguages(const nsTArray& aLanguages); void UpdateJSWorkerMemoryParameter(JSGCParamKey key, Maybe value); diff --git a/intl/components/src/TimeZone.cpp b/intl/components/src/TimeZone.cpp index 145dd3f07112c2390325de50f8eae674484adfe6..8cb3787e1b6bb25c6a58f1d910ae7dbc440d9ace 100644 --- a/intl/components/src/TimeZone.cpp +++ b/intl/components/src/TimeZone.cpp @@ -16,6 +16,7 @@ namespace mozilla::intl { + /* static */ Result, ICUError> TimeZone::TryCreate( Maybe> aTimeZoneOverride) { @@ -239,6 +240,13 @@ static ICUResult SetDefaultTimeZone(TimeZoneIdentifierVector& timeZone) { } #endif +bool TimeZone::IsValidTimeZoneId(const char* timeZoneId) { + // Validate timezone id. + mozilla::UniquePtr timeZone(icu::TimeZone::createTimeZone( + icu::UnicodeString(timeZoneId, -1, US_INV))); + return timeZone && *timeZone != icu::TimeZone::getUnknown(); +} + Result TimeZone::SetDefaultTimeZone( Span aTimeZone) { #if MOZ_INTL_USE_ICU_CPP_TIMEZONE diff --git a/intl/components/src/TimeZone.h b/intl/components/src/TimeZone.h index 180092bd3fc0b70462cc6ba67e72946e4c4c7604..bcaecb9fcd7b630c75289581a887cc6894733168 100644 --- a/intl/components/src/TimeZone.h +++ b/intl/components/src/TimeZone.h @@ -154,6 +154,8 @@ class TimeZone final { return FillBufferWithICUCall(aBuffer, ucal_getHostTimeZone); } + static bool IsValidTimeZoneId(const char* timeZoneId); + /** * Set the default time zone. */ diff --git a/js/public/Date.h b/js/public/Date.h index bb69d58dc96ed7f0b37f73e26abdd0bdfeaaf556..8436d439f72287176a2fe6a1a837d3db73409e67 100644 --- a/js/public/Date.h +++ b/js/public/Date.h @@ -53,6 +53,8 @@ namespace JS { */ extern JS_PUBLIC_API void ResetTimeZone(); +extern JS_PUBLIC_API bool SetTimeZoneOverride(const char* timezoneId); + class ClippedTime; inline ClippedTime TimeClip(double time); diff --git a/js/src/debugger/Object.cpp b/js/src/debugger/Object.cpp index baf9debd7b2153aa37e791001e6b37bc1bd14122..68a4d69a4e16711b00a46428e9a51c53154ec923 100644 --- a/js/src/debugger/Object.cpp +++ b/js/src/debugger/Object.cpp @@ -2373,7 +2373,11 @@ Maybe DebuggerObject::call(JSContext* cx, invokeArgs[i].set(args2[i]); } + // Disable CSP for the scope of the call. + const JSSecurityCallbacks* securityCallbacks = JS_GetSecurityCallbacks(cx); + JS_SetSecurityCallbacks(cx, nullptr); ok = js::Call(cx, calleev, thisv, invokeArgs, &result); + JS_SetSecurityCallbacks(cx, securityCallbacks); } } diff --git a/js/src/vm/DateTime.cpp b/js/src/vm/DateTime.cpp index a86a6e9f7177c86624f118ebbc2e012766137bd1..5ebd1f106a556471fda5961d1f11f8eac31718cc 100644 --- a/js/src/vm/DateTime.cpp +++ b/js/src/vm/DateTime.cpp @@ -178,6 +178,11 @@ void js::DateTimeInfo::internalResetTimeZone(ResetTimeZoneMode mode) { } } +void js::DateTimeInfo::internalSetTimeZoneOverride(std::string timeZone) { + timeZoneOverride_ = std::move(timeZone); + internalResetTimeZone(ResetTimeZoneMode::ResetEvenIfOffsetUnchanged); +} + void js::DateTimeInfo::updateTimeZone() { MOZ_ASSERT(timeZoneStatus_ != TimeZoneStatus::Valid); @@ -502,10 +507,24 @@ void js::ResetTimeZoneInternal(ResetTimeZoneMode mode) { js::DateTimeInfo::resetTimeZone(mode); } +void js::SetTimeZoneOverrideInternal(std::string timeZone) { + auto guard = js::DateTimeInfo::instance->lock(); + guard->internalSetTimeZoneOverride(timeZone); +} + JS_PUBLIC_API void JS::ResetTimeZone() { js::ResetTimeZoneInternal(js::ResetTimeZoneMode::ResetEvenIfOffsetUnchanged); } +JS_PUBLIC_API bool JS::SetTimeZoneOverride(const char* timeZoneId) { + if (!mozilla::intl::TimeZone::IsValidTimeZoneId(timeZoneId)) { + fprintf(stderr, "Invalid timezone id: %s\n", timeZoneId); + return false; + } + js::SetTimeZoneOverrideInternal(std::string(timeZoneId)); + return true; +} + #if JS_HAS_INTL_API # if defined(XP_WIN) static bool IsOlsonCompatibleWindowsTimeZoneId(std::string_view tz) { @@ -727,9 +746,17 @@ void js::ResyncICUDefaultTimeZone() { void js::DateTimeInfo::internalResyncICUDefaultTimeZone() { #if JS_HAS_INTL_API + if (!timeZoneOverride_.empty()) { + mozilla::Span 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 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 >& 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 13c0b901b39279c023e99d8b42852c315baf847d..5dd2741fd06d8a16af050d55c5333c4c095bf591 100644 --- a/layout/base/PresShell.cpp +++ b/layout/base/PresShell.cpp @@ -10923,7 +10923,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 e5762879ea3120dca4864e286ffce6d52d33d40e..b2281efd2529c3155355eb18a6a1b7b417514869 100644 --- a/layout/style/GeckoBindings.h +++ b/layout/style/GeckoBindings.h @@ -605,6 +605,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 a9d3f075f3587fc1e55544b010864cd0e4b67107..d9ce4a1a7d9e2cd27e20f0ef36132e6599b0bb66 100644 --- a/layout/style/nsMediaFeatures.cpp +++ b/layout/style/nsMediaFeatures.cpp @@ -264,10 +264,11 @@ bool Gecko_MediaFeatures_MatchesPlatform(StylePlatform aPlatform) { } bool Gecko_MediaFeatures_PrefersReducedMotion(const Document* aDocument) { - if (nsContentUtils::ShouldResistFingerprinting(aDocument)) { - return false; - } - return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1; + return aDocument->PrefersReducedMotion(); +} + +bool Gecko_MediaFeatures_ForcedColors(const Document* aDocument) { + return aDocument->ForcedColors(); } StylePrefersColorScheme Gecko_MediaFeatures_PrefersColorScheme( diff --git a/media/libjpeg/jconfig.h b/media/libjpeg/jconfig.h index f2723e654098ff27542e1eb16a536c11ad0af617..b0b480551ff7d895dfdeb5a9800874858929c8ba 100644 --- a/media/libjpeg/jconfig.h +++ b/media/libjpeg/jconfig.h @@ -17,6 +17,7 @@ /* #undef D_ARITH_CODING_SUPPORTED */ /* Support in-memory source/destination managers */ +#define MEM_SRCDST_SUPPORTED 1 /* #undef MEM_SRCDST_SUPPORTED */ /* Use accelerated SIMD routines. */ diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index dfe52b1d7477fea400a387ed221557454d746589..fb50c04fe18c1c876f649bedac7b5ae231e98da8 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4241,7 +4241,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 fba1a83231165cbda92e9b017c70ec6c1d59d037..e8093ed2a06f728c125a4ad8a096d205ef8d3155 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 2c02db86d5ac9567d7174ac5e685296d4466d16c..a0a91ab331d0289a53b3d29c11d3df9496ae9f2b 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", diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp index 55c7dbe1ae90d64e5aa993424cc1c5659833582f..a451248676b9b7cdd773a74948eb3b4d442a2b18 100644 --- a/parser/html/nsHtml5TreeOpExecutor.cpp +++ b/parser/html/nsHtml5TreeOpExecutor.cpp @@ -1363,6 +1363,10 @@ void nsHtml5TreeOpExecutor::UpdateReferrerInfoFromMeta( void nsHtml5TreeOpExecutor::AddSpeculationCSP(const nsAString& aCSP) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + if (mDocShell && static_cast(mDocShell.get())->IsBypassCSPEnabled()) { + return; + } + nsresult rv = NS_OK; nsCOMPtr preloadCsp = mDocument->GetPreloadCsp(); if (!preloadCsp) { diff --git a/security/manager/ssl/nsCertOverrideService.cpp b/security/manager/ssl/nsCertOverrideService.cpp index 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 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 mUserContextIdsWithDisabledSecurityChecks MOZ_GUARDED_BY(mMutex); nsCOMPtr mSettingsFile MOZ_GUARDED_BY(mMutex); nsTHashtable 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 de557af4275b51a0e4dbc95bd4f6896dd585c232..5049f8613c7a1efa3fec5cc28ff761abe18c557c 100644 --- a/services/settings/Utils.jsm +++ b/services/settings/Utils.jsm @@ -102,7 +102,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 f44fd788b00005c64d94a67d72f83946178a7848..015c8c5cb9fc764d0cf1cab2e448da135cbded10 100644 --- a/servo/components/style/gecko/media_features.rs +++ b/servo/components/style/gecko/media_features.rs @@ -232,10 +232,15 @@ pub enum ForcedColors { /// https://drafts.csswg.org/mediaqueries-5/#forced-colors fn eval_forced_colors(context: &Context, query_value: Option) -> bool { - let forced = !context.device().use_document_colors(); + let prefers_forced_colors = + unsafe { bindings::Gecko_MediaFeatures_ForcedColors(context.device().document()) }; + let query_value = match query_value { + Some(v) => v, + None => return prefers_forced_colors, + }; match query_value { - Some(query_value) => forced == (query_value == ForcedColors::Active), - None => forced, + ForcedColors::Active => prefers_forced_colors, + ForcedColors::None => !prefers_forced_colors, } } diff --git a/toolkit/components/browser/nsIWebBrowserChrome.idl b/toolkit/components/browser/nsIWebBrowserChrome.idl index 4f7337926efbb086a2be97cdbcb3dca39e27c786..f2005cb726ff153d6b1011d6af0479dbf1af02a5 100644 --- a/toolkit/components/browser/nsIWebBrowserChrome.idl +++ b/toolkit/components/browser/nsIWebBrowserChrome.idl @@ -70,6 +70,9 @@ interface nsIWebBrowserChrome : nsISupports // Whether this window should use out-of-process cross-origin subframes. const unsigned long CHROME_FISSION_WINDOW = 0x00200000; + // Whether this window has "width" or "height" defined in features + const unsigned long JUGGLER_WINDOW_EXPLICIT_SIZE = 0x00400000; + // Prevents new window animations on MacOS and Windows. Currently // ignored for Linux. const unsigned long CHROME_SUPPRESS_ANIMATION = 0x01000000; diff --git a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs index 0a7ba257a4d43c74841f003a8a0556d7f057700b..cf78a44fa64248ecf5b3ade8a8e92efffeb9f831 100644 --- a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs +++ b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs @@ -116,6 +116,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 windowEnumerator; nsCOMPtr mediator( do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); - if (mediator) { + if (ferocity != eForceQuit && mediator) { mediator->GetEnumerator(nullptr, getter_AddRefs(windowEnumerator)); if (windowEnumerator) { bool more; diff --git a/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp b/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp index 3e9672fdfe9ddab8acd0f8b18772aece92bb3b64..83454a9c27c96d72597445653beaa014c38728cd 100644 --- a/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp +++ b/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp @@ -174,8 +174,8 @@ nsBrowserStatusFilter::OnStateChange(nsIWebProgress* aWebProgress, } NS_IMETHODIMP -nsBrowserStatusFilter::OnProgressChange(nsIWebProgress* aWebProgress, - nsIRequest* aRequest, +nsBrowserStatusFilter::OnProgressChange(nsIWebProgress *aWebProgress, + nsIRequest *aRequest, int32_t aCurSelfProgress, int32_t aMaxSelfProgress, int32_t aCurTotalProgress, diff --git a/toolkit/components/windowwatcher/nsWindowWatcher.cpp b/toolkit/components/windowwatcher/nsWindowWatcher.cpp index 3afb5e02eb9c65b2d4dc34692f7c94e43a103b1a..4037e9118dae628ed370cd14934f1dafc3f99feb 100644 --- a/toolkit/components/windowwatcher/nsWindowWatcher.cpp +++ b/toolkit/components/windowwatcher/nsWindowWatcher.cpp @@ -1852,7 +1852,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 d969d9e8d0790bff7c837828b92e1a92d945b116..34f2a030eca9c8258900c5b8d2564fa06580f1f3 100644 --- a/toolkit/mozapps/update/UpdateService.jsm +++ b/toolkit/mozapps/update/UpdateService.jsm @@ -3610,6 +3610,8 @@ UpdateService.prototype = { }, get disabledForTesting() { + /* for playwright */ + return true; return ( (Cu.isInAutomation || lazy.Marionette.running || diff --git a/toolkit/toolkit.mozbuild b/toolkit/toolkit.mozbuild index 04453a437873b2e6339cb7e81ee11c2a5bb46bb1..2ce3151b9a97e7b86619109716a6d942b80f58ed 100644 --- a/toolkit/toolkit.mozbuild +++ b/toolkit/toolkit.mozbuild @@ -153,6 +153,7 @@ if CONFIG['ENABLE_WEBDRIVER']: '/remote', '/testing/firefox-ui', '/testing/marionette', + '/juggler', '/toolkit/components/telemetry/tests/marionette', ] diff --git a/toolkit/xre/nsWindowsWMain.cpp b/toolkit/xre/nsWindowsWMain.cpp index ea14a59b80bbfbaa17d7569734b8409d9d21fcde..28cb052c3115f91e6a036ad8466385ff1d740cd0 100644 --- a/toolkit/xre/nsWindowsWMain.cpp +++ b/toolkit/xre/nsWindowsWMain.cpp @@ -14,9 +14,11 @@ #endif #include "mozilla/Char16.h" +#include "mozilla/CmdLineAndEnvUtils.h" #include "nsUTF8Utils.h" #include "nsWindowsHelpers.h" +#include #include #include @@ -130,6 +132,19 @@ int wmain(int argc, WCHAR** argv) { SanitizeEnvironmentVariables(); SetDllDirectoryW(L""); + bool hasJugglerPipe = + mozilla::CheckArg(argc, argv, "juggler-pipe", nullptr, + mozilla::CheckArgFlag::None) == mozilla::ARG_FOUND; + if (hasJugglerPipe && !mozilla::EnvHasValue("PW_PIPE_READ")) { + intptr_t stdio3 = _get_osfhandle(3); + intptr_t stdio4 = _get_osfhandle(4); + CHAR stdio3str[20]; + CHAR stdio4str[20]; + itoa(stdio3, stdio3str, 10); + itoa(stdio4, stdio4str, 10); + SetEnvironmentVariableA("PW_PIPE_READ", stdio3str); + SetEnvironmentVariableA("PW_PIPE_WRITE", stdio4str); + } // Only run this code if LauncherProcessWin.h was included beforehand, thus // signalling that the hosting process should support launcher mode. diff --git a/uriloader/base/nsDocLoader.cpp b/uriloader/base/nsDocLoader.cpp index e1e46ccdceae595f95d100116ff480905047e82b..eaa0252e768140120158525723ad867b8cb020be 100644 --- 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 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 54a8d617308c2fb2ce816bb4a88162b8395c2723..140059c6ae4e52b4720aaa34d6313a92729b98a7 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); @@ -1637,7 +1649,36 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { return NS_OK; } - rv = SetUpTempFile(aChannel); + bool isIntercepted = false; + nsCOMPtr interceptor = mExtProtSvc->mInterceptor; + if (interceptor) { + nsCOMPtr fileToUse; + rv = interceptor->InterceptDownloadRequest(this, request, mBrowsingContext, getter_AddRefs(fileToUse), &isIntercepted); + if (!NS_SUCCEEDED(rv)) { + LOG((" failed to call nsIDowloadInterceptor.interceptDownloadRequest")); + return rv; + } + if (isIntercepted) { + LOG((" request interceped by nsIDowloadInterceptor")); + if (fileToUse) { + mTempFile = fileToUse; + rv = mTempFile->GetLeafName(mTempLeafName); + NS_ENSURE_SUCCESS(rv, rv); + } else { + Cancel(NS_BINDING_ABORTED); + return NS_OK; + } + } + } + + // Temp file is the final destination when download is intercepted. In that + // case we only need to create saver (and not create transfer later). Not creating + // mTransfer also cuts off all downloads handling logic in the js compoenents and + // browser UI. + if (isIntercepted) + rv = CreateSaverForTempFile(); + else + rv = SetUpTempFile(aChannel); if (NS_FAILED(rv)) { nsresult transferError = rv; @@ -1691,6 +1732,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 @@ -2259,6 +2303,16 @@ nsExternalAppHandler::OnSaveComplete(nsIBackgroundFileSaver* aSaver, NotifyTransfer(aStatus); } + if (!mCanceled) { + nsCOMPtr interceptor = mExtProtSvc->mInterceptor; + if (interceptor) { + nsCString noError; + nsresult rv = interceptor->OnDownloadComplete(this, noError); + MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to call nsIDowloadInterceptor.OnDownloadComplete"); + Unused << rv; + } + } + return NS_OK; } @@ -2744,6 +2798,15 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason) { } } + nsCOMPtr interceptor = mExtProtSvc->mInterceptor; + if (interceptor) { + nsCString errorName; + GetErrorName(aReason, errorName); + nsresult rv = interceptor->OnDownloadComplete(this, errorName); + MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed notify nsIDowloadInterceptor about cancel"); + Unused << rv; + } + // Break our reference cycle with the helper app dialog (set up in // OnStartRequest) mDialog = nullptr; diff --git a/uriloader/exthandler/nsExternalHelperAppService.h b/uriloader/exthandler/nsExternalHelperAppService.h index 17c7dccf0217b0aa71cff630dd7b0e9beda9f5aa..06558286f5ed9d1e324654365909f9f8cad957ac 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.h +++ b/uriloader/exthandler/nsExternalHelperAppService.h @@ -245,6 +245,8 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService, mozilla::dom::BrowsingContext* aContentContext, bool aForceSave, nsIInterfaceRequestor* aWindowContext, nsIStreamListener** aStreamListener); + + nsCOMPtr mInterceptor; }; /** @@ -447,6 +449,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::CreateLocal( // do it after the static_cast. nsBaseWidget* widget = static_cast(aWidget); MOZ_RELEASE_ASSERT(widget); + if (aInitData.type() == + CompositorWidgetInitData::THeadlessCompositorWidgetInitData) { + return new HeadlessCompositorWidget( + aInitData.get_HeadlessCompositorWidgetInitData(), aOptions, + static_cast(aWidget)); + } return new InProcessCompositorWidget(aOptions, widget); } #endif diff --git a/widget/cocoa/NativeKeyBindings.mm b/widget/cocoa/NativeKeyBindings.mm index d3e5983259053175584254e7ac01ca9ce024f33a..97f5b851c402fea5477c0ee57af451c62b016eec 100644 --- a/widget/cocoa/NativeKeyBindings.mm +++ b/widget/cocoa/NativeKeyBindings.mm @@ -492,6 +492,13 @@ break; case KEY_NAME_INDEX_ArrowLeft: if (aEvent.IsAlt()) { + if (aEvent.IsMeta() || aEvent.IsControl()) + break; + instance->AppendEditCommandsForSelector( + !aEvent.IsShift() + ? ToObjcSelectorPtr(@selector(moveWordLeft:)) + : ToObjcSelectorPtr(@selector(moveWordLeftAndModifySelection:)), + aCommands); break; } if (aEvent.IsMeta() || (aEvent.IsControl() && aEvent.IsShift())) { @@ -512,6 +519,13 @@ break; case KEY_NAME_INDEX_ArrowRight: if (aEvent.IsAlt()) { + if (aEvent.IsMeta() || aEvent.IsControl()) + break; + instance->AppendEditCommandsForSelector( + !aEvent.IsShift() + ? ToObjcSelectorPtr(@selector(moveWordRight:)) + : ToObjcSelectorPtr(@selector(moveWordRightAndModifySelection:)), + aCommands); break; } if (aEvent.IsMeta() || (aEvent.IsControl() && aEvent.IsShift())) { @@ -532,6 +546,10 @@ break; case KEY_NAME_INDEX_ArrowUp: if (aEvent.IsControl()) { + if (aEvent.IsMeta() || aEvent.IsAlt()) + break; + instance->AppendEditCommandsForSelector( + ToObjcSelectorPtr(@selector(scrollPageUp:)), aCommands); break; } if (aEvent.IsMeta()) { @@ -541,7 +559,7 @@ instance->AppendEditCommandsForSelector( !aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveToBeginningOfDocument:)) - : ToObjcSelectorPtr(@selector(moveToBegginingOfDocumentAndModifySelection:)), + : ToObjcSelectorPtr(@selector(moveToBeginningOfDocumentAndModifySelection:)), aCommands); break; } @@ -564,6 +582,10 @@ break; case KEY_NAME_INDEX_ArrowDown: if (aEvent.IsControl()) { + if (aEvent.IsMeta() || aEvent.IsAlt()) + break; + instance->AppendEditCommandsForSelector( + ToObjcSelectorPtr(@selector(scrollPageDown:)), aCommands); break; } if (aEvent.IsMeta()) { diff --git a/widget/headless/HeadlessCompositorWidget.cpp b/widget/headless/HeadlessCompositorWidget.cpp index b31a969b7ab3d0fc80912b110d91dfdf3e5991f4..52aed4f9fb51f3f58a440d7e57eaccd6dfcbc2ab 100644 --- a/widget/headless/HeadlessCompositorWidget.cpp +++ b/widget/headless/HeadlessCompositorWidget.cpp @@ -3,6 +3,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "mozilla/layers/CompositorThread.h" #include "mozilla/widget/PlatformWidgetTypes.h" #include "HeadlessCompositorWidget.h" #include "VsyncDispatcher.h" @@ -13,10 +14,32 @@ namespace widget { HeadlessCompositorWidget::HeadlessCompositorWidget( const HeadlessCompositorWidgetInitData& aInitData, const layers::CompositorOptions& aOptions, HeadlessWidget* aWindow) - : CompositorWidget(aOptions), mWidget(aWindow) { + : CompositorWidget(aOptions), mWidget(aWindow), mMon("snapshotListener") { mClientSize = aInitData.InitialClientSize(); } +void HeadlessCompositorWidget::SetSnapshotListener(HeadlessWidget::SnapshotListener&& listener) { + MOZ_ASSERT(NS_IsMainThread()); + + ReentrantMonitorAutoEnter lock(mMon); + mSnapshotListener = std::move(listener); + layers::CompositorThread()->Dispatch(NewRunnableMethod( + "HeadlessCompositorWidget::PeriodicSnapshot", this, + &HeadlessCompositorWidget::PeriodicSnapshot + )); +} + +already_AddRefed HeadlessCompositorWidget::StartRemoteDrawingInRegion( + const LayoutDeviceIntRegion& aInvalidRegion, + layers::BufferMode* aBufferMode) { + if (!mDrawTarget) + return nullptr; + + *aBufferMode = layers::BufferMode::BUFFER_NONE; + RefPtr result = mDrawTarget; + return result.forget(); +} + void HeadlessCompositorWidget::ObserveVsync(VsyncObserver* aObserver) { if (RefPtr cvd = mWidget->GetCompositorVsyncDispatcher()) { @@ -29,6 +52,59 @@ nsIWidget* HeadlessCompositorWidget::RealWidget() { return mWidget; } void HeadlessCompositorWidget::NotifyClientSizeChanged( const LayoutDeviceIntSize& aClientSize) { mClientSize = aClientSize; + layers::CompositorThread()->Dispatch(NewRunnableMethod( + "HeadlessCompositorWidget::UpdateDrawTarget", this, + &HeadlessCompositorWidget::UpdateDrawTarget, + aClientSize)); +} + +void HeadlessCompositorWidget::UpdateDrawTarget(const LayoutDeviceIntSize& aClientSize) { + MOZ_ASSERT(NS_IsInCompositorThread()); + if (aClientSize.IsEmpty()) { + mDrawTarget = nullptr; + return; + } + + RefPtr old = std::move(mDrawTarget); + gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8; + gfx::IntSize size = aClientSize.ToUnknownSize(); + mDrawTarget = mozilla::gfx::Factory::CreateDrawTarget( + mozilla::gfx::BackendType::SKIA, size, format); + if (old) { + RefPtr snapshot = old->Snapshot(); + if (snapshot) + mDrawTarget->CopySurface(snapshot.get(), old->GetRect(), gfx::IntPoint(0, 0)); + } +} + +void HeadlessCompositorWidget::PeriodicSnapshot() { + ReentrantMonitorAutoEnter lock(mMon); + if (!mSnapshotListener) + return; + + TakeSnapshot(); + NS_DelayedDispatchToCurrentThread(NewRunnableMethod( + "HeadlessCompositorWidget::PeriodicSnapshot", this, + &HeadlessCompositorWidget::PeriodicSnapshot), 40); +} + +void HeadlessCompositorWidget::TakeSnapshot() { + if (!mDrawTarget) + return; + + RefPtr snapshot = mDrawTarget->Snapshot(); + if (!snapshot) { + fprintf(stderr, "Failed to get snapshot of draw target\n"); + return; + } + + RefPtr dataSurface = snapshot->GetDataSurface(); + if (!dataSurface) { + fprintf(stderr, "Failed to get data surface from snapshot\n"); + return; + } + + mSnapshotListener(std::move(dataSurface)); } LayoutDeviceIntSize HeadlessCompositorWidget::GetClientSize() { diff --git a/widget/headless/HeadlessCompositorWidget.h b/widget/headless/HeadlessCompositorWidget.h index 7f91de9e67d7ffa02de3eef1d760e5cfd05e7ad6..753b8902026626e8f0a190ea3130ba5e65c24835 100644 --- a/widget/headless/HeadlessCompositorWidget.h +++ b/widget/headless/HeadlessCompositorWidget.h @@ -6,6 +6,7 @@ #ifndef widget_headless_HeadlessCompositorWidget_h #define widget_headless_HeadlessCompositorWidget_h +#include "mozilla/ReentrantMonitor.h" #include "mozilla/widget/CompositorWidget.h" #include "HeadlessWidget.h" @@ -23,8 +24,12 @@ class HeadlessCompositorWidget final : public CompositorWidget, HeadlessWidget* aWindow); void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize); + void SetSnapshotListener(HeadlessWidget::SnapshotListener&& listener); // CompositorWidget Overrides + already_AddRefed StartRemoteDrawingInRegion( + const LayoutDeviceIntRegion& aInvalidRegion, + layers::BufferMode* aBufferMode) override; uintptr_t GetWidgetKey() override; @@ -42,9 +47,17 @@ class HeadlessCompositorWidget final : public CompositorWidget, } private: + void UpdateDrawTarget(const LayoutDeviceIntSize& aClientSize); + void PeriodicSnapshot(); + void TakeSnapshot(); + HeadlessWidget* mWidget; + mozilla::ReentrantMonitor mMon; LayoutDeviceIntSize mClientSize; + + HeadlessWidget::SnapshotListener mSnapshotListener; + RefPtr mDrawTarget; }; } // namespace widget diff --git a/widget/headless/HeadlessWidget.cpp b/widget/headless/HeadlessWidget.cpp index 340cb723bd4de51e64164b67b69c77da5c5fa443..252f9411479f6aaa0b65942668ccfb7030af7b46 100644 --- a/widget/headless/HeadlessWidget.cpp +++ b/widget/headless/HeadlessWidget.cpp @@ -110,6 +110,8 @@ void HeadlessWidget::Destroy() { } } + SetSnapshotListener(nullptr); + nsBaseWidget::OnDestroy(); nsBaseWidget::Destroy(); @@ -608,5 +610,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 b77ec632a90ff98f4df7af6846fc02fd6411d2e1..ccdbaac472b4c9f6d94e6f8665af9ee740f61311 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 SetSnapshotListener(SnapshotListener&& listener); + private: ~HeadlessWidget(); bool mEnabled; 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 /**