Last active
July 20, 2023 17:47
-
-
Save barbolo/0c1b6df0310996e462b9990da9d18bec to your computer and use it in GitHub Desktop.
Playwright patches for firefox 105.0.2 - BASE_REVISION=e0ccf0a049acc6e0911465c9679d9cae1e026ba2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/accessible/base/NotificationController.h b/accessible/base/NotificationController.h | |
index bc1a692c23d8599512a5ce956d99998640347c46..4e77897aa4a84ce88445ba45f1ba3b5b2dde9e23 100644 | |
--- a/accessible/base/NotificationController.h | |
+++ b/accessible/base/NotificationController.h | |
@@ -244,6 +244,8 @@ class NotificationController final : public EventQueue, | |
} | |
#endif | |
+ bool IsUpdatePendingForJugglerAccessibility() { return IsUpdatePending(); } | |
+ | |
protected: | |
virtual ~NotificationController(); | |
diff --git a/accessible/interfaces/nsIAccessibleDocument.idl b/accessible/interfaces/nsIAccessibleDocument.idl | |
index 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 2f9e191c7765194d540a7ab067ea10ec4c3d9553..2ac814f079cdfc8dc0741c2f0bd9606ff229748f 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 082ada9ea705cf62420c6bd409a23517a591df82..781ac8d8ee9b9b01112b620e8c5c11682cdb9ef1 100644 | |
--- a/browser/app/winlauncher/LauncherProcessWin.cpp | |
+++ b/browser/app/winlauncher/LauncherProcessWin.cpp | |
@@ -22,6 +22,7 @@ | |
#include "mozilla/WinHeaderOnlyUtils.h" | |
#include "nsWindowsHelpers.h" | |
+#include <io.h> | |
#include <windows.h> | |
#include <processthreadsapi.h> | |
@@ -428,8 +429,18 @@ Maybe<int> LauncherMain(int& argc, wchar_t* argv[], | |
HANDLE stdHandles[] = {::GetStdHandle(STD_INPUT_HANDLE), | |
::GetStdHandle(STD_OUTPUT_HANDLE), | |
::GetStdHandle(STD_ERROR_HANDLE)}; | |
- | |
attrs.AddInheritableHandles(stdHandles); | |
+ // Playwright pipe installation. | |
+ bool hasJugglerPipe = | |
+ mozilla::CheckArg(argc, argv, "juggler-pipe", nullptr, | |
+ mozilla::CheckArgFlag::None) == mozilla::ARG_FOUND; | |
+ if (hasJugglerPipe) { | |
+ intptr_t stdio3 = _get_osfhandle(3); | |
+ intptr_t stdio4 = _get_osfhandle(4); | |
+ HANDLE pipeHandles[] = {reinterpret_cast<HANDLE>(stdio3), | |
+ reinterpret_cast<HANDLE>(stdio4)}; | |
+ attrs.AddInheritableHandles(pipeHandles); | |
+ } | |
DWORD creationFlags = CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT; | |
diff --git a/browser/installer/allowed-dupes.mn b/browser/installer/allowed-dupes.mn | |
index 6ab29ba31e937e1c5bb1208a9a2508ff0496fd02..7989da51c5368fa80cc66cccdfc018a9b3fb2f38 100644 | |
--- a/browser/installer/allowed-dupes.mn | |
+++ b/browser/installer/allowed-dupes.mn | |
@@ -67,6 +67,12 @@ browser/features/[email protected]/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 34b9bf7d6595226983f696b94f90694970564e92..1110fef252bc68d73d5c3dc71deac98fb41700f0 100644 | |
--- a/browser/installer/package-manifest.in | |
+++ b/browser/installer/package-manifest.in | |
@@ -197,6 +197,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 4236ec2921bd57c58cfffdf1cdcf509d76fca3db..23d0cb1f06bb8c7a1cac8fcec94a99fba5bfe3f2 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 695621bb786289198ec4db5679b7ac5a11f18bce..acdc0aae6db9f452964bcfdddace261b1ef8a1cf 100644 | |
--- a/docshell/base/BrowsingContext.cpp | |
+++ b/docshell/base/BrowsingContext.cpp | |
@@ -114,6 +114,20 @@ struct ParamTraits<mozilla::dom::PrefersColorSchemeOverride> | |
mozilla::dom::PrefersColorSchemeOverride::None, | |
mozilla::dom::PrefersColorSchemeOverride::EndGuard_> {}; | |
+template <> | |
+struct ParamTraits<mozilla::dom::PrefersReducedMotionOverride> | |
+ : public ContiguousEnumSerializer< | |
+ mozilla::dom::PrefersReducedMotionOverride, | |
+ mozilla::dom::PrefersReducedMotionOverride::None, | |
+ mozilla::dom::PrefersReducedMotionOverride::EndGuard_> {}; | |
+ | |
+template <> | |
+struct ParamTraits<mozilla::dom::ForcedColorsOverride> | |
+ : public ContiguousEnumSerializer< | |
+ mozilla::dom::ForcedColorsOverride, | |
+ mozilla::dom::ForcedColorsOverride::None, | |
+ mozilla::dom::ForcedColorsOverride::EndGuard_> {}; | |
+ | |
template <> | |
struct ParamTraits<mozilla::dom::ExplicitActiveStatus> | |
: public ContiguousEnumSerializer< | |
@@ -2747,6 +2761,40 @@ void BrowsingContext::DidSet(FieldIndex<IDX_PrefersColorSchemeOverride>, | |
PresContextAffectingFieldChanged(); | |
} | |
+void BrowsingContext::DidSet(FieldIndex<IDX_PrefersReducedMotionOverride>, | |
+ dom::PrefersReducedMotionOverride aOldValue) { | |
+ MOZ_ASSERT(IsTop()); | |
+ if (PrefersReducedMotionOverride() == aOldValue) { | |
+ return; | |
+ } | |
+ PreOrderWalk([&](BrowsingContext* aContext) { | |
+ if (nsIDocShell* shell = aContext->GetDocShell()) { | |
+ if (nsPresContext* pc = shell->GetPresContext()) { | |
+ pc->MediaFeatureValuesChanged( | |
+ {MediaFeatureChangeReason::SystemMetricsChange}, | |
+ MediaFeatureChangePropagation::JustThisDocument); | |
+ } | |
+ } | |
+ }); | |
+} | |
+ | |
+void BrowsingContext::DidSet(FieldIndex<IDX_ForcedColorsOverride>, | |
+ dom::ForcedColorsOverride aOldValue) { | |
+ MOZ_ASSERT(IsTop()); | |
+ if (ForcedColorsOverride() == aOldValue) { | |
+ return; | |
+ } | |
+ PreOrderWalk([&](BrowsingContext* aContext) { | |
+ if (nsIDocShell* shell = aContext->GetDocShell()) { | |
+ if (nsPresContext* pc = shell->GetPresContext()) { | |
+ pc->MediaFeatureValuesChanged( | |
+ {MediaFeatureChangeReason::SystemMetricsChange}, | |
+ MediaFeatureChangePropagation::JustThisDocument); | |
+ } | |
+ } | |
+ }); | |
+} | |
+ | |
void BrowsingContext::DidSet(FieldIndex<IDX_MediumOverride>, | |
nsString&& aOldValue) { | |
MOZ_ASSERT(IsTop()); | |
diff --git a/docshell/base/BrowsingContext.h b/docshell/base/BrowsingContext.h | |
index 4c245337b7db24f94011ad75fa2a3b32c9a3574c..6ea5000722ca875aecd7938d47f1c43b6c0444a9 100644 | |
--- a/docshell/base/BrowsingContext.h | |
+++ b/docshell/base/BrowsingContext.h | |
@@ -199,10 +199,10 @@ struct EmbedderColorSchemes { | |
FIELD(GVInaudibleAutoplayRequestStatus, GVAutoplayRequestStatus) \ | |
/* ScreenOrientation-related APIs */ \ | |
FIELD(CurrentOrientationAngle, float) \ | |
- FIELD(CurrentOrientationType, mozilla::dom::OrientationType) \ | |
+ FIELD(CurrentOrientationType, dom::OrientationType) \ | |
FIELD(OrientationLock, mozilla::hal::ScreenOrientation) \ | |
FIELD(UserAgentOverride, nsString) \ | |
- FIELD(TouchEventsOverrideInternal, mozilla::dom::TouchEventsOverride) \ | |
+ FIELD(TouchEventsOverrideInternal, dom::TouchEventsOverride) \ | |
FIELD(EmbedderElementType, Maybe<nsString>) \ | |
FIELD(MessageManagerGroup, nsString) \ | |
FIELD(MaxTouchPointsOverride, uint8_t) \ | |
@@ -240,6 +240,10 @@ struct EmbedderColorSchemes { | |
* <browser> embedder element. */ \ | |
FIELD(EmbedderColorSchemes, EmbedderColorSchemes) \ | |
FIELD(DisplayMode, dom::DisplayMode) \ | |
+ /* playwright addition */ \ | |
+ FIELD(PrefersReducedMotionOverride, dom::PrefersReducedMotionOverride) \ | |
+ /* playwright addition */ \ | |
+ FIELD(ForcedColorsOverride, dom::ForcedColorsOverride) \ | |
/* The number of entries added to the session history because of this \ | |
* browsing context. */ \ | |
FIELD(HistoryEntryCount, uint32_t) \ | |
@@ -354,6 +358,10 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { | |
bool IsOwnedByProcess() const; | |
+ uint64_t JugglerCurrentLoadIdentifier() const { | |
+ return GetCurrentLoadIdentifier() ? GetCurrentLoadIdentifier().value() : 0; | |
+ } | |
+ | |
bool CanHaveRemoteOuterProxies() const { | |
return !mIsInProcess || mDanglingRemoteOuterProxies; | |
} | |
@@ -924,6 +932,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(); } | |
@@ -1085,6 +1101,23 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { | |
void WalkPresContexts(Callback&&); | |
void PresContextAffectingFieldChanged(); | |
+ bool CanSet(FieldIndex<IDX_PrefersReducedMotionOverride>, | |
+ dom::PrefersReducedMotionOverride, ContentParent*) { | |
+ return IsTop(); | |
+ } | |
+ | |
+ void DidSet(FieldIndex<IDX_PrefersReducedMotionOverride>, | |
+ dom::PrefersReducedMotionOverride aOldValue); | |
+ | |
+ | |
+ bool CanSet(FieldIndex<IDX_ForcedColorsOverride>, | |
+ dom::ForcedColorsOverride, ContentParent*) { | |
+ return IsTop(); | |
+ } | |
+ | |
+ void DidSet(FieldIndex<IDX_ForcedColorsOverride>, | |
+ dom::ForcedColorsOverride aOldValue); | |
+ | |
void DidSet(FieldIndex<IDX_MediumOverride>, nsString&& aOldValue); | |
bool CanSet(FieldIndex<IDX_SuspendMediaWhenInactive>, bool, ContentParent*) { | |
diff --git a/docshell/base/CanonicalBrowsingContext.cpp b/docshell/base/CanonicalBrowsingContext.cpp | |
index 37f047c7e062d5441be022da97f34012134826ae..a26c71264c0e175361e43464600bea049b7cee56 100644 | |
--- a/docshell/base/CanonicalBrowsingContext.cpp | |
+++ b/docshell/base/CanonicalBrowsingContext.cpp | |
@@ -1454,6 +1454,12 @@ void CanonicalBrowsingContext::LoadURI(nsIURI* aURI, | |
return; | |
} | |
+ { | |
+ nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService(); | |
+ if (observerService) { | |
+ observerService->NotifyObservers(ToSupports(this), "juggler-navigation-started-browser", NS_ConvertASCIItoUTF16(nsPrintfCString("%" PRIu64, loadState->GetLoadIdentifier())).get()); | |
+ } | |
+ } | |
LoadURI(loadState, true); | |
} | |
diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp | |
index 02641049b7303c280ebe04034fd0a927e7389711..3ace412e8cc4277c1984b9d68f23d1889cb9b9da 100644 | |
--- a/docshell/base/nsDocShell.cpp | |
+++ b/docshell/base/nsDocShell.cpp | |
@@ -15,6 +15,12 @@ | |
# include <unistd.h> // for getpid() | |
#endif | |
+#if JS_HAS_INTL_API && !MOZ_SYSTEM_ICU | |
+# include "unicode/locid.h" | |
+#endif /* JS_HAS_INTL_API && !MOZ_SYSTEM_ICU */ | |
+ | |
+#include "js/LocaleSensitive.h" | |
+ | |
#include "mozilla/ArrayUtils.h" | |
#include "mozilla/Attributes.h" | |
#include "mozilla/AutoRestore.h" | |
@@ -65,6 +71,7 @@ | |
#include "mozilla/dom/ContentFrameMessageManager.h" | |
#include "mozilla/dom/DocGroup.h" | |
#include "mozilla/dom/Element.h" | |
+#include "mozilla/dom/Geolocation.h" | |
#include "mozilla/dom/HTMLAnchorElement.h" | |
#include "mozilla/dom/HTMLIFrameElement.h" | |
#include "mozilla/dom/PerformanceNavigation.h" | |
@@ -90,6 +97,7 @@ | |
#include "mozilla/dom/JSWindowActorChild.h" | |
#include "mozilla/dom/DocumentBinding.h" | |
#include "mozilla/ipc/ProtocolUtils.h" | |
+#include "mozilla/dom/WorkerCommon.h" | |
#include "mozilla/net/DocumentChannel.h" | |
#include "mozilla/net/DocumentChannelChild.h" | |
#include "mozilla/net/ParentChannelWrapper.h" | |
@@ -113,6 +121,7 @@ | |
#include "nsIDocShellTreeOwner.h" | |
#include "mozilla/dom/Document.h" | |
#include "nsHTMLDocument.h" | |
+#include "mozilla/dom/Element.h" | |
#include "nsIDocumentLoaderFactory.h" | |
#include "nsIDOMWindow.h" | |
#include "nsIEditingSession.h" | |
@@ -207,6 +216,7 @@ | |
#include "nsFocusManager.h" | |
#include "nsGlobalWindow.h" | |
#include "nsJSEnvironment.h" | |
+#include "nsJSUtils.h" | |
#include "nsNetCID.h" | |
#include "nsNetUtil.h" | |
#include "nsObjectLoadingContent.h" | |
@@ -349,6 +359,14 @@ nsDocShell::nsDocShell(BrowsingContext* aBrowsingContext, | |
mAllowDNSPrefetch(true), | |
mAllowWindowControl(true), | |
mCSSErrorReportingEnabled(false), | |
+ mFileInputInterceptionEnabled(false), | |
+ mOverrideHasFocus(false), | |
+ mBypassCSPEnabled(false), | |
+ mForceActiveState(false), | |
+ mDisallowBFCache(false), | |
+ mOnlineOverride(nsIDocShell::ONLINE_OVERRIDE_NONE), | |
+ mReducedMotionOverride(REDUCED_MOTION_OVERRIDE_NONE), | |
+ mForcedColorsOverride(FORCED_COLORS_OVERRIDE_NO_OVERRIDE), | |
mAllowAuth(mItemType == typeContent), | |
mAllowKeywordFixup(false), | |
mDisableMetaRefreshWhenInactive(false), | |
@@ -3186,6 +3204,234 @@ nsDocShell::GetMessageManager(ContentFrameMessageManager** aMessageManager) { | |
return NS_OK; | |
} | |
+// =============== Juggler Begin ======================= | |
+ | |
+nsDocShell* nsDocShell::GetRootDocShell() { | |
+ nsCOMPtr<nsIDocShellTreeItem> rootAsItem; | |
+ GetInProcessSameTypeRootTreeItem(getter_AddRefs(rootAsItem)); | |
+ nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(rootAsItem); | |
+ return nsDocShell::Cast(rootShell); | |
+} | |
+ | |
+NS_IMETHODIMP | |
+nsDocShell::GetBypassCSPEnabled(bool* aEnabled) { | |
+ MOZ_ASSERT(aEnabled); | |
+ *aEnabled = mBypassCSPEnabled; | |
+ return NS_OK; | |
+} | |
+ | |
+NS_IMETHODIMP | |
+nsDocShell::SetBypassCSPEnabled(bool aEnabled) { | |
+ mBypassCSPEnabled = aEnabled; | |
+ return NS_OK; | |
+} | |
+ | |
+NS_IMETHODIMP | |
+nsDocShell::GetForceActiveState(bool* aEnabled) { | |
+ MOZ_ASSERT(aEnabled); | |
+ *aEnabled = mForceActiveState; | |
+ return NS_OK; | |
+} | |
+ | |
+NS_IMETHODIMP | |
+nsDocShell::SetForceActiveState(bool aEnabled) { | |
+ mForceActiveState = aEnabled; | |
+ ActivenessMaybeChanged(); | |
+ return NS_OK; | |
+} | |
+ | |
+NS_IMETHODIMP | |
+nsDocShell::GetDisallowBFCache(bool* aEnabled) { | |
+ MOZ_ASSERT(aEnabled); | |
+ *aEnabled = mDisallowBFCache; | |
+ return NS_OK; | |
+} | |
+ | |
+NS_IMETHODIMP | |
+nsDocShell::SetDisallowBFCache(bool aEnabled) { | |
+ mDisallowBFCache = aEnabled; | |
+ return NS_OK; | |
+} | |
+ | |
+bool nsDocShell::IsBypassCSPEnabled() { | |
+ return GetRootDocShell()->mBypassCSPEnabled; | |
+} | |
+ | |
+NS_IMETHODIMP | |
+nsDocShell::GetOverrideHasFocus(bool* aEnabled) { | |
+ MOZ_ASSERT(aEnabled); | |
+ *aEnabled = mOverrideHasFocus; | |
+ return NS_OK; | |
+} | |
+ | |
+NS_IMETHODIMP | |
+nsDocShell::SetOverrideHasFocus(bool aEnabled) { | |
+ mOverrideHasFocus = aEnabled; | |
+ return NS_OK; | |
+} | |
+ | |
+bool nsDocShell::ShouldOverrideHasFocus() const { | |
+ return mOverrideHasFocus; | |
+} | |
+ | |
+NS_IMETHODIMP | |
+nsDocShell::GetLanguageOverride(nsAString& aLanguageOverride) { | |
+ aLanguageOverride = GetRootDocShell()->mLanguageOverride; | |
+ return NS_OK; | |
+} | |
+ | |
+ | |
+static void SetIcuLocale(const nsAString& aLanguageOverride) { | |
+ icu::Locale locale(NS_LossyConvertUTF16toASCII(aLanguageOverride).get()); | |
+ if (icu::Locale::getDefault() == locale) | |
+ return; | |
+ UErrorCode error_code = U_ZERO_ERROR; | |
+ const char* lang = locale.getLanguage(); | |
+ if (lang != nullptr && *lang != '\0') { | |
+ icu::Locale::setDefault(locale, error_code); | |
+ } else { | |
+ fprintf(stderr, "SetIcuLocale Failed to set the ICU default locale to %s\n", NS_LossyConvertUTF16toASCII(aLanguageOverride).get()); | |
+ } | |
+ | |
+ AutoJSAPI jsapi; | |
+ jsapi.Init(); | |
+ JSContext* cx = jsapi.cx(); | |
+ JS_ResetDefaultLocale(JS_GetRuntime(cx)); | |
+ | |
+ ResetDefaultLocaleInAllWorkers(); | |
+} | |
+ | |
+NS_IMETHODIMP | |
+nsDocShell::SetLanguageOverride(const nsAString& aLanguageOverride) { | |
+ mLanguageOverride = aLanguageOverride; | |
+ SetIcuLocale(aLanguageOverride); | |
+ return NS_OK; | |
+} | |
+ | |
+NS_IMETHODIMP | |
+nsDocShell::OverrideTimezone(const nsAString& aTimezoneOverride, | |
+ bool* aSuccess) { | |
+ NS_ENSURE_ARG(aSuccess); | |
+ NS_LossyConvertUTF16toASCII timeZoneId(aTimezoneOverride); | |
+ *aSuccess = nsJSUtils::SetTimeZoneOverride(timeZoneId.get()); | |
+ | |
+ // Set TZ which affects localtime_s(). | |
+ auto setTimeZoneEnv = [](const char* value) { | |
+#if defined(_WIN32) | |
+ return _putenv_s("TZ", value) == 0; | |
+#else | |
+ return setenv("TZ", value, true) == 0; | |
+#endif /* _WIN32 */ | |
+ }; | |
+ if (*aSuccess) { | |
+ *aSuccess = setTimeZoneEnv(timeZoneId.get()); | |
+ if (!*aSuccess) { | |
+ fprintf(stderr, "Failed to set 'TZ' to '%s'\n", timeZoneId.get()); | |
+ } | |
+ } | |
+ return NS_OK; | |
+} | |
+ | |
+NS_IMETHODIMP | |
+nsDocShell::GetFileInputInterceptionEnabled(bool* aEnabled) { | |
+ MOZ_ASSERT(aEnabled); | |
+ *aEnabled = GetRootDocShell()->mFileInputInterceptionEnabled; | |
+ return NS_OK; | |
+} | |
+ | |
+NS_IMETHODIMP | |
+nsDocShell::SetFileInputInterceptionEnabled(bool aEnabled) { | |
+ mFileInputInterceptionEnabled = aEnabled; | |
+ return NS_OK; | |
+} | |
+ | |
+bool nsDocShell::IsFileInputInterceptionEnabled() { | |
+ return GetRootDocShell()->mFileInputInterceptionEnabled; | |
+} | |
+ | |
+void nsDocShell::FilePickerShown(mozilla::dom::Element* element) { | |
+ nsCOMPtr<nsIObserverService> observerService = | |
+ mozilla::services::GetObserverService(); | |
+ observerService->NotifyObservers( | |
+ ToSupports(element), "juggler-file-picker-shown", nullptr); | |
+} | |
+ | |
+RefPtr<nsGeolocationService> nsDocShell::GetGeolocationServiceOverride() { | |
+ return GetRootDocShell()->mGeolocationServiceOverride; | |
+} | |
+ | |
+NS_IMETHODIMP | |
+nsDocShell::SetGeolocationOverride(nsIDOMGeoPosition* aGeolocationOverride) { | |
+ if (aGeolocationOverride) { | |
+ if (!mGeolocationServiceOverride) { | |
+ mGeolocationServiceOverride = new nsGeolocationService(); | |
+ mGeolocationServiceOverride->Init(); | |
+ } | |
+ mGeolocationServiceOverride->Update(aGeolocationOverride); | |
+ } else { | |
+ mGeolocationServiceOverride = nullptr; | |
+ } | |
+ return NS_OK; | |
+} | |
+ | |
+NS_IMETHODIMP | |
+nsDocShell::GetOnlineOverride(OnlineOverride* aOnlineOverride) { | |
+ *aOnlineOverride = GetRootDocShell()->mOnlineOverride; | |
+ return NS_OK; | |
+} | |
+ | |
+NS_IMETHODIMP | |
+nsDocShell::SetOnlineOverride(OnlineOverride aOnlineOverride) { | |
+ // We don't have a way to verify this coming from Javascript, so this check is | |
+ // still needed. | |
+ if (!(aOnlineOverride == ONLINE_OVERRIDE_NONE || | |
+ aOnlineOverride == ONLINE_OVERRIDE_ONLINE || | |
+ aOnlineOverride == ONLINE_OVERRIDE_OFFLINE)) { | |
+ return NS_ERROR_INVALID_ARG; | |
+ } | |
+ | |
+ mOnlineOverride = aOnlineOverride; | |
+ return NS_OK; | |
+} | |
+ | |
+NS_IMETHODIMP | |
+nsDocShell::GetReducedMotionOverride(ReducedMotionOverride* aReducedMotionOverride) { | |
+ *aReducedMotionOverride = GetRootDocShell()->mReducedMotionOverride; | |
+ return NS_OK; | |
+} | |
+ | |
+NS_IMETHODIMP | |
+nsDocShell::SetReducedMotionOverride(ReducedMotionOverride aReducedMotionOverride) { | |
+ mReducedMotionOverride = aReducedMotionOverride; | |
+ RefPtr<nsPresContext> presContext = GetPresContext(); | |
+ if (presContext) { | |
+ presContext->MediaFeatureValuesChanged( | |
+ {MediaFeatureChangeReason::SystemMetricsChange}, | |
+ MediaFeatureChangePropagation::JustThisDocument); | |
+ } | |
+ return NS_OK; | |
+} | |
+ | |
+NS_IMETHODIMP | |
+nsDocShell::GetForcedColorsOverride(ForcedColorsOverride* aForcedColorsOverride) { | |
+ *aForcedColorsOverride = GetRootDocShell()->mForcedColorsOverride; | |
+ return NS_OK; | |
+} | |
+ | |
+NS_IMETHODIMP | |
+nsDocShell::SetForcedColorsOverride(ForcedColorsOverride aForcedColorsOverride) { | |
+ mForcedColorsOverride = aForcedColorsOverride; | |
+ RefPtr<nsPresContext> presContext = GetPresContext(); | |
+ if (presContext) { | |
+ presContext->MediaFeatureValuesChanged( | |
+ {MediaFeatureChangeReason::SystemMetricsChange}, | |
+ MediaFeatureChangePropagation::JustThisDocument); | |
+ } | |
+ return NS_OK; | |
+} | |
+ | |
+// =============== Juggler End ======================= | |
+ | |
NS_IMETHODIMP | |
nsDocShell::GetIsNavigating(bool* aOut) { | |
*aOut = mIsNavigating; | |
@@ -4865,7 +5111,7 @@ nsDocShell::GetVisibility(bool* aVisibility) { | |
} | |
void nsDocShell::ActivenessMaybeChanged() { | |
- const bool isActive = mBrowsingContext->IsActive(); | |
+ const bool isActive = mForceActiveState || mBrowsingContext->IsActive(); | |
if (RefPtr<PresShell> presShell = GetPresShell()) { | |
presShell->ActivenessMaybeChanged(); | |
} | |
@@ -6798,6 +7044,10 @@ bool nsDocShell::CanSavePresentation(uint32_t aLoadType, | |
return false; // no entry to save into | |
} | |
+ if (mDisallowBFCache) { | |
+ return false; | |
+ } | |
+ | |
MOZ_ASSERT(!mozilla::SessionHistoryInParent(), | |
"mOSHE cannot be non-null with SHIP"); | |
nsCOMPtr<nsIContentViewer> viewer = mOSHE->GetContentViewer(); | |
@@ -8579,6 +8829,12 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState) { | |
true, // aForceNoOpener | |
getter_AddRefs(newBC)); | |
MOZ_ASSERT(!newBC); | |
+ if (rv == NS_OK) { | |
+ nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService(); | |
+ if (observerService) { | |
+ observerService->NotifyObservers(GetAsSupports(this), "juggler-window-open-in-new-context", nullptr); | |
+ } | |
+ } | |
return rv; | |
} | |
@@ -9633,6 +9889,16 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState, | |
nsINetworkPredictor::PREDICT_LOAD, attrs, nullptr); | |
nsCOMPtr<nsIRequest> req; | |
+ | |
+ // Juggler: report navigation started for non-same-document and non-javascript | |
+ // navigations. | |
+ if (!isJavaScript && !sameDocument) { | |
+ nsCOMPtr<nsIObserverService> observerService = | |
+ mozilla::services::GetObserverService(); | |
+ if (observerService) { | |
+ observerService->NotifyObservers(GetAsSupports(this), "juggler-navigation-started-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("%" PRIu64, aLoadState->GetLoadIdentifier())).get()); | |
+ } | |
+ } | |
rv = DoURILoad(aLoadState, aCacheKey, getter_AddRefs(req)); | |
if (NS_SUCCEEDED(rv)) { | |
@@ -12793,6 +13059,9 @@ class OnLinkClickEvent : public Runnable { | |
mHandler->OnLinkClickSync(mContent, mLoadState, mNoOpenerImplied, | |
mTriggeringPrincipal); | |
} | |
+ nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService(); | |
+ observerService->NotifyObservers(ToSupports(mContent), "juggler-link-click-sync", nullptr); | |
+ | |
return NS_OK; | |
} | |
@@ -12877,6 +13146,8 @@ nsresult nsDocShell::OnLinkClick( | |
nsCOMPtr<nsIRunnable> ev = | |
new OnLinkClickEvent(this, aContent, loadState, noOpenerImplied, | |
aIsTrusted, aTriggeringPrincipal); | |
+ nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService(); | |
+ observerService->NotifyObservers(ToSupports(aContent), "juggler-link-click", nullptr); | |
return Dispatch(TaskCategory::UI, ev.forget()); | |
} | |
diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h | |
index 67090146dcedc87ab80a089a1bf173946fb750d8..d5ff17673105e3b966a79a066d656f0ddfdf4f70 100644 | |
--- a/docshell/base/nsDocShell.h | |
+++ b/docshell/base/nsDocShell.h | |
@@ -16,6 +16,7 @@ | |
#include "mozilla/UniquePtr.h" | |
#include "mozilla/WeakPtr.h" | |
#include "mozilla/dom/BrowsingContext.h" | |
+#include "mozilla/dom/Element.h" | |
#include "mozilla/dom/WindowProxyHolder.h" | |
#include "nsCOMPtr.h" | |
#include "nsCharsetSource.h" | |
@@ -77,6 +78,7 @@ class nsCommandManager; | |
class nsDocShellEditorData; | |
class nsDOMNavigationTiming; | |
class nsDSURIContentListener; | |
+class nsGeolocationService; | |
class nsGlobalWindowOuter; | |
class FramingChecker; | |
@@ -409,6 +411,15 @@ class nsDocShell final : public nsDocLoader, | |
void SetWillChangeProcess() { mWillChangeProcess = true; } | |
bool WillChangeProcess() { return mWillChangeProcess; } | |
+ bool IsFileInputInterceptionEnabled(); | |
+ void FilePickerShown(mozilla::dom::Element* element); | |
+ | |
+ bool ShouldOverrideHasFocus() const; | |
+ | |
+ bool IsBypassCSPEnabled(); | |
+ | |
+ RefPtr<nsGeolocationService> GetGeolocationServiceOverride(); | |
+ | |
// Create a content viewer within this nsDocShell for the given | |
// `WindowGlobalChild` actor. | |
nsresult CreateContentViewerForActor( | |
@@ -1023,6 +1034,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 | |
@@ -1316,6 +1329,17 @@ class nsDocShell final : public nsDocLoader, | |
bool mAllowDNSPrefetch : 1; | |
bool mAllowWindowControl : 1; | |
bool mCSSErrorReportingEnabled : 1; | |
+ bool mFileInputInterceptionEnabled: 1; | |
+ bool mOverrideHasFocus : 1; | |
+ bool mBypassCSPEnabled : 1; | |
+ bool mForceActiveState : 1; | |
+ bool mDisallowBFCache : 1; | |
+ nsString mLanguageOverride; | |
+ RefPtr<nsGeolocationService> mGeolocationServiceOverride; | |
+ OnlineOverride mOnlineOverride; | |
+ ReducedMotionOverride mReducedMotionOverride; | |
+ ForcedColorsOverride mForcedColorsOverride; | |
+ | |
bool mAllowAuth : 1; | |
bool mAllowKeywordFixup : 1; | |
bool mDisableMetaRefreshWhenInactive : 1; | |
diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl | |
index 68f32e968c7e1bc1d0b2b2894320a177a9ae44d2..9e61465ffad927d7b3e972f753940196fc986156 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; | |
@@ -784,6 +785,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 f8153eef91c40a0947bc7ce8d42f8f550b95b701..c56728bd9baf5b4f20de1ab446e8a3fbf95eaea8 100644 | |
--- a/dom/base/Document.cpp | |
+++ b/dom/base/Document.cpp | |
@@ -3675,6 +3675,9 @@ void Document::SendToConsole(nsCOMArray<nsISecurityConsoleMessage>& aMessages) { | |
} | |
void Document::ApplySettingsFromCSP(bool aSpeculative) { | |
+ if (mDocumentContainer && mDocumentContainer->IsBypassCSPEnabled()) | |
+ return; | |
+ | |
nsresult rv = NS_OK; | |
if (!aSpeculative) { | |
// 1) apply settings from regular CSP | |
@@ -3732,6 +3735,11 @@ nsresult Document::InitCSP(nsIChannel* aChannel) { | |
MOZ_ASSERT(!mScriptGlobalObject, | |
"CSP must be initialized before mScriptGlobalObject is set!"); | |
+ nsCOMPtr<nsIDocShell> shell(mDocumentContainer); | |
+ if (shell && nsDocShell::Cast(shell)->IsBypassCSPEnabled()) { | |
+ return NS_OK; | |
+ } | |
+ | |
// If this is a data document - no need to set CSP. | |
if (mLoadedAsData) { | |
return NS_OK; | |
@@ -4572,6 +4580,10 @@ bool Document::HasFocus(ErrorResult& rv) const { | |
return false; | |
} | |
+ if (IsActive() && mDocumentContainer->ShouldOverrideHasFocus()) { | |
+ return true; | |
+ } | |
+ | |
if (!fm->IsInActiveWindow(bc)) { | |
return false; | |
} | |
@@ -18436,6 +18448,71 @@ ColorScheme Document::PreferredColorScheme(IgnoreRFP aIgnoreRFP) const { | |
return LookAndFeel::PreferredColorSchemeForContent(); | |
} | |
+bool Document::PrefersReducedMotion() const { | |
+ auto* docShell = static_cast<nsDocShell*>(GetDocShell()); | |
+ nsIDocShell::ReducedMotionOverride reducedMotion; | |
+ if (docShell && docShell->GetReducedMotionOverride(&reducedMotion) == NS_OK && | |
+ reducedMotion != nsIDocShell::REDUCED_MOTION_OVERRIDE_NONE) { | |
+ switch (reducedMotion) { | |
+ case nsIDocShell::REDUCED_MOTION_OVERRIDE_REDUCE: | |
+ return true; | |
+ case nsIDocShell::REDUCED_MOTION_OVERRIDE_NO_PREFERENCE: | |
+ return false; | |
+ case nsIDocShell::REDUCED_MOTION_OVERRIDE_NONE: | |
+ break; | |
+ }; | |
+ } | |
+ | |
+ if (auto* bc = GetBrowsingContext()) { | |
+ switch (bc->Top()->PrefersReducedMotionOverride()) { | |
+ case dom::PrefersReducedMotionOverride::Reduce: | |
+ return true; | |
+ case dom::PrefersReducedMotionOverride::No_preference: | |
+ return false; | |
+ case dom::PrefersReducedMotionOverride::None: | |
+ case dom::PrefersReducedMotionOverride::EndGuard_: | |
+ break; | |
+ } | |
+ } | |
+ | |
+ if (ShouldResistFingerprinting(RFPTarget::CSSPrefersReducedMotion)) { | |
+ return false; | |
+ } | |
+ return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1; | |
+} | |
+ | |
+bool Document::ForcedColors() const { | |
+ auto* docShell = static_cast<nsDocShell*>(GetDocShell()); | |
+ nsIDocShell::ForcedColorsOverride forcedColors; | |
+ if (docShell && docShell->GetForcedColorsOverride(&forcedColors) == NS_OK) { | |
+ switch (forcedColors) { | |
+ case nsIDocShell::FORCED_COLORS_OVERRIDE_ACTIVE: | |
+ return true; | |
+ case nsIDocShell::FORCED_COLORS_OVERRIDE_NONE: | |
+ return false; | |
+ case nsIDocShell::FORCED_COLORS_OVERRIDE_NO_OVERRIDE: | |
+ break; | |
+ }; | |
+ } | |
+ | |
+ if (auto* bc = GetBrowsingContext()) { | |
+ switch (bc->Top()->ForcedColorsOverride()) { | |
+ case dom::ForcedColorsOverride::Active: | |
+ return true; | |
+ case dom::ForcedColorsOverride::None: | |
+ return false; | |
+ case dom::ForcedColorsOverride::No_override: | |
+ case dom::ForcedColorsOverride::EndGuard_: | |
+ break; | |
+ } | |
+ } | |
+ | |
+ if (mIsBeingUsedAsImage) { | |
+ return false; | |
+ } | |
+ return !PreferenceSheet::PrefsFor(*this).mUseDocumentColors; | |
+} | |
+ | |
bool Document::HasRecentlyStartedForegroundLoads() { | |
if (!sLoadingForegroundTopLevelContentDocument) { | |
return false; | |
diff --git a/dom/base/Document.h b/dom/base/Document.h | |
index 3b12b31b65408500e081527662edc77f3fd64207..4fb7d831123b9f1754675ae8fd7a2ec25b4e12c5 100644 | |
--- a/dom/base/Document.h | |
+++ b/dom/base/Document.h | |
@@ -4127,6 +4127,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 151d992d6fdca956a8925d47c49adde2d545e950..0013db0f6e912f09c7e427764c5f2729bd1db7ec 100644 | |
--- a/dom/base/Navigator.cpp | |
+++ b/dom/base/Navigator.cpp | |
@@ -330,14 +330,18 @@ void Navigator::GetAppName(nsAString& aAppName, CallerType aCallerType) const { | |
* for more detail. | |
*/ | |
/* static */ | |
-void Navigator::GetAcceptLanguages(nsTArray<nsString>& aLanguages) { | |
+void Navigator::GetAcceptLanguages(const nsString* aLanguageOverride, nsTArray<nsString>& aLanguages) { | |
MOZ_ASSERT(NS_IsMainThread()); | |
aLanguages.Clear(); | |
// E.g. "de-de, en-us,en". | |
nsAutoString acceptLang; | |
- Preferences::GetLocalizedString("intl.accept_languages", acceptLang); | |
+ if (aLanguageOverride && aLanguageOverride->Length()) | |
+ acceptLang = *aLanguageOverride; | |
+ else | |
+ Preferences::GetLocalizedString("intl.accept_languages", acceptLang); | |
+ | |
// Split values on commas. | |
for (nsDependentSubstring lang : | |
@@ -389,7 +393,13 @@ void Navigator::GetLanguage(nsAString& aLanguage) { | |
} | |
void Navigator::GetLanguages(nsTArray<nsString>& aLanguages) { | |
- GetAcceptLanguages(aLanguages); | |
+ if (mWindow && mWindow->GetDocShell()) { | |
+ nsString languageOverride; | |
+ mWindow->GetDocShell()->GetLanguageOverride(languageOverride); | |
+ GetAcceptLanguages(&languageOverride, aLanguages); | |
+ } else { | |
+ GetAcceptLanguages(nullptr, aLanguages); | |
+ } | |
// The returned value is cached by the binding code. The window listens to the | |
// accept languages change and will clear the cache when needed. It has to | |
@@ -570,7 +580,13 @@ bool Navigator::CookieEnabled() { | |
return granted; | |
} | |
-bool Navigator::OnLine() { return !NS_IsOffline(); } | |
+bool Navigator::OnLine() { | |
+ nsDocShell* docShell = static_cast<nsDocShell*>(GetDocShell()); | |
+ nsIDocShell::OnlineOverride onlineOverride; | |
+ if (!docShell || docShell->GetOnlineOverride(&onlineOverride) != NS_OK || onlineOverride == nsIDocShell::ONLINE_OVERRIDE_NONE) | |
+ return !NS_IsOffline(); | |
+ return onlineOverride == nsIDocShell::ONLINE_OVERRIDE_ONLINE; | |
+} | |
void Navigator::GetBuildID(nsAString& aBuildID, CallerType aCallerType, | |
ErrorResult& aRv) const { | |
diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h | |
index cbe8d6bb27eb75b1c0eb920c69eccc99fd6133b2..49da35b1f9ec2a81c5886f277fd52ec492ca8418 100644 | |
--- a/dom/base/Navigator.h | |
+++ b/dom/base/Navigator.h | |
@@ -216,7 +216,7 @@ class Navigator final : public nsISupports, public nsWrapperCache { | |
StorageManager* Storage(); | |
- static void GetAcceptLanguages(nsTArray<nsString>& aLanguages); | |
+ static void GetAcceptLanguages(const nsString* aLanguageOverride, nsTArray<nsString>& aLanguages); | |
dom::MediaCapabilities* MediaCapabilities(); | |
dom::MediaSession* MediaSession(); | |
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp | |
index 75a685ec441eb8b7a4b7e456885564746dec43db..baf363b6e9b6f47db5c186ddd18c38c913a1b7f5 100644 | |
--- a/dom/base/nsContentUtils.cpp | |
+++ b/dom/base/nsContentUtils.cpp | |
@@ -8469,7 +8469,8 @@ nsresult nsContentUtils::SendMouseEvent( | |
bool aIgnoreRootScrollFrame, float aPressure, | |
unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow, | |
PreventDefaultResult* aPreventDefault, bool aIsDOMEventSynthesized, | |
- bool aIsWidgetEventSynthesized) { | |
+ bool aIsWidgetEventSynthesized, | |
+ bool convertToPointer, uint32_t aJugglerEventId) { | |
nsPoint offset; | |
nsCOMPtr<nsIWidget> widget = GetWidget(aPresShell, &offset); | |
if (!widget) return NS_ERROR_FAILURE; | |
@@ -8477,6 +8478,7 @@ nsresult nsContentUtils::SendMouseEvent( | |
EventMessage msg; | |
Maybe<WidgetMouseEvent::ExitFrom> exitFrom; | |
bool contextMenuKey = false; | |
+ bool isDragEvent = false; | |
if (aType.EqualsLiteral("mousedown")) { | |
msg = eMouseDown; | |
} else if (aType.EqualsLiteral("mouseup")) { | |
@@ -8501,6 +8503,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; | |
} | |
@@ -8509,12 +8517,21 @@ nsresult nsContentUtils::SendMouseEvent( | |
aInputSourceArg = MouseEvent_Binding::MOZ_SOURCE_MOUSE; | |
} | |
- WidgetMouseEvent event(true, msg, widget, | |
+ std::unique_ptr<WidgetMouseEvent> eventOwner; | |
+ if (isDragEvent) { | |
+ eventOwner.reset(new WidgetDragEvent(true, msg, widget)); | |
+ eventOwner->mReason = aIsWidgetEventSynthesized | |
+ ? WidgetMouseEvent::eSynthesized | |
+ : WidgetMouseEvent::eReal; | |
+ } else { | |
+ eventOwner.reset(new WidgetMouseEvent(true, msg, widget, | |
aIsWidgetEventSynthesized | |
? WidgetMouseEvent::eSynthesized | |
: WidgetMouseEvent::eReal, | |
contextMenuKey ? WidgetMouseEvent::eContextMenuKey | |
- : WidgetMouseEvent::eNormal); | |
+ : WidgetMouseEvent::eNormal)); | |
+ } | |
+ WidgetMouseEvent& event = *eventOwner.get(); | |
event.pointerId = aIdentifier; | |
event.mModifiers = GetWidgetModifiers(aModifiers); | |
event.mButton = aButton; | |
@@ -8525,8 +8542,10 @@ nsresult nsContentUtils::SendMouseEvent( | |
event.mPressure = aPressure; | |
event.mInputSource = aInputSourceArg; | |
event.mClickCount = aClickCount; | |
+ event.mJugglerEventId = aJugglerEventId; | |
event.mFlags.mIsSynthesizedForTests = aIsDOMEventSynthesized; | |
event.mExitFrom = exitFrom; | |
+ event.convertToPointer = convertToPointer; | |
nsPresContext* presContext = aPresShell->GetPresContext(); | |
if (!presContext) return NS_ERROR_FAILURE; | |
diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h | |
index 79e68e8acd16d60e69420429e69cad2afa3947b0..7deae8eabaf03178480d697a701c2171e0ededa1 100644 | |
--- a/dom/base/nsContentUtils.h | |
+++ b/dom/base/nsContentUtils.h | |
@@ -2926,7 +2926,8 @@ class nsContentUtils { | |
int32_t aModifiers, bool aIgnoreRootScrollFrame, float aPressure, | |
unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow, | |
mozilla::PreventDefaultResult* aPreventDefault, | |
- bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized); | |
+ bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized, | |
+ bool convertToPointer = true, uint32_t aJugglerEventId = 0); | |
static void FirePageShowEventForFrameLoaderSwap( | |
nsIDocShellTreeItem* aItem, | |
diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp | |
index fb1cfe4f93585d6dbadfc85af83a4457a605d8a0..2a6dea015cc949b7ba8a7fcab9983d5236c7c72b 100644 | |
--- a/dom/base/nsDOMWindowUtils.cpp | |
+++ b/dom/base/nsDOMWindowUtils.cpp | |
@@ -684,6 +684,26 @@ nsDOMWindowUtils::GetPresShellId(uint32_t* aPresShellId) { | |
return NS_ERROR_FAILURE; | |
} | |
+static uint32_t sJugglerEventId = 1000; | |
+ | |
+NS_IMETHODIMP | |
+nsDOMWindowUtils::JugglerSendMouseEvent( | |
+ const nsAString& aType, float aX, float aY, int32_t aButton, | |
+ int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, | |
+ float aPressure, unsigned short aInputSourceArg, | |
+ bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized, | |
+ int32_t aButtons, uint32_t aIdentifier, bool aDisablePointerEvent, | |
+ uint32_t* aJugglerEventId) { | |
+ *aJugglerEventId = ++sJugglerEventId; | |
+ return SendMouseEventCommon( | |
+ aType, aX, aY, aButton, aClickCount, aModifiers, aIgnoreRootScrollFrame, | |
+ aPressure, aInputSourceArg, | |
+ aIdentifier, false, | |
+ nullptr, aIsDOMEventSynthesized, | |
+ aIsWidgetEventSynthesized, | |
+ aButtons, !aDisablePointerEvent, *aJugglerEventId); | |
+} | |
+ | |
NS_IMETHODIMP | |
nsDOMWindowUtils::SendMouseEvent( | |
const nsAString& aType, float aX, float aY, int32_t aButton, | |
@@ -698,7 +718,7 @@ nsDOMWindowUtils::SendMouseEvent( | |
aOptionalArgCount >= 7 ? aIdentifier : DEFAULT_MOUSE_POINTER_ID, false, | |
aPreventDefault, aOptionalArgCount >= 4 ? aIsDOMEventSynthesized : true, | |
aOptionalArgCount >= 5 ? aIsWidgetEventSynthesized : false, | |
- aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED); | |
+ aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED, true, 0); | |
} | |
NS_IMETHODIMP | |
@@ -716,7 +736,7 @@ nsDOMWindowUtils::SendMouseEventToWindow( | |
aOptionalArgCount >= 7 ? aIdentifier : DEFAULT_MOUSE_POINTER_ID, true, | |
nullptr, aOptionalArgCount >= 4 ? aIsDOMEventSynthesized : true, | |
aOptionalArgCount >= 5 ? aIsWidgetEventSynthesized : false, | |
- aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED); | |
+ aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED, 0); | |
} | |
NS_IMETHODIMP | |
@@ -725,13 +745,13 @@ nsDOMWindowUtils::SendMouseEventCommon( | |
int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, | |
float aPressure, unsigned short aInputSourceArg, uint32_t aPointerId, | |
bool aToWindow, bool* aPreventDefault, bool aIsDOMEventSynthesized, | |
- bool aIsWidgetEventSynthesized, int32_t aButtons) { | |
+ bool aIsWidgetEventSynthesized, int32_t aButtons, bool aConvertToPointer, uint32_t aJugglerEventId) { | |
RefPtr<PresShell> presShell = GetPresShell(); | |
PreventDefaultResult preventDefaultResult; | |
nsresult rv = nsContentUtils::SendMouseEvent( | |
presShell, aType, aX, aY, aButton, aButtons, aClickCount, aModifiers, | |
aIgnoreRootScrollFrame, aPressure, aInputSourceArg, aPointerId, aToWindow, | |
- &preventDefaultResult, aIsDOMEventSynthesized, aIsWidgetEventSynthesized); | |
+ &preventDefaultResult, aIsDOMEventSynthesized, aIsWidgetEventSynthesized, aConvertToPointer, aJugglerEventId); | |
if (aPreventDefault) { | |
*aPreventDefault = preventDefaultResult != PreventDefaultResult::No; | |
diff --git a/dom/base/nsDOMWindowUtils.h b/dom/base/nsDOMWindowUtils.h | |
index 63968c9b7a4e418e4c0de6e7a75fa215a36a9105..decf3ea3833ccdffd49a7aded2d600f9416e8306 100644 | |
--- a/dom/base/nsDOMWindowUtils.h | |
+++ b/dom/base/nsDOMWindowUtils.h | |
@@ -93,7 +93,7 @@ class nsDOMWindowUtils final : public nsIDOMWindowUtils, | |
int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, | |
float aPressure, unsigned short aInputSourceArg, uint32_t aIdentifier, | |
bool aToWindow, bool* aPreventDefault, bool aIsDOMEventSynthesized, | |
- bool aIsWidgetEventSynthesized, int32_t aButtons); | |
+ bool aIsWidgetEventSynthesized, int32_t aButtons, bool aConvertToPointer = true, uint32_t aJugglerEventId = 0); | |
MOZ_CAN_RUN_SCRIPT | |
nsresult SendTouchEventCommon( | |
diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp | |
index ead05d9103a378bf6a4d5a18589a450c2a81108b..50a8bfd2cb6a94b24c85ab1199f12287b8323b3e 100644 | |
--- a/dom/base/nsFocusManager.cpp | |
+++ b/dom/base/nsFocusManager.cpp | |
@@ -1656,6 +1656,10 @@ Maybe<uint64_t> nsFocusManager::SetFocusInner(Element* aNewContent, | |
(GetActiveBrowsingContext() == newRootBrowsingContext); | |
} | |
+ // In Playwright, we want to send focus events even if the element | |
+ // isn't actually in the active window. | |
+ isElementInActiveWindow = true; | |
+ | |
// Exit fullscreen if a website focuses another window | |
if (StaticPrefs::full_screen_api_exit_on_windowRaise() && | |
!isElementInActiveWindow && (aFlags & FLAG_RAISE)) { | |
@@ -2946,7 +2950,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 6fbfe015177c9600b2dadf613717c47a3efc9e17..3e8c659206eea2c6a4015ea59141b978e7f8ac47 100644 | |
--- a/dom/base/nsGlobalWindowOuter.cpp | |
+++ b/dom/base/nsGlobalWindowOuter.cpp | |
@@ -2484,7 +2484,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 | |
@@ -2503,10 +2503,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)); | |
+ } | |
} | |
} | |
@@ -2627,6 +2633,19 @@ void nsGlobalWindowOuter::DispatchDOMWindowCreated() { | |
} | |
} | |
+void nsGlobalWindowOuter::JugglerDispatchDOMWindowReused() { | |
+ nsCOMPtr<nsIObserverService> observerService = | |
+ mozilla::services::GetObserverService(); | |
+ if (observerService && mDoc) { | |
+ nsIPrincipal* principal = mDoc->NodePrincipal(); | |
+ if (!principal->IsSystemPrincipal()) { | |
+ observerService->NotifyObservers(static_cast<nsIDOMWindow*>(this), | |
+ "juggler-dom-window-reused", | |
+ nullptr); | |
+ } | |
+ } | |
+} | |
+ | |
void nsGlobalWindowOuter::ClearStatus() { SetStatusOuter(u""_ns); } | |
void nsGlobalWindowOuter::SetDocShell(nsDocShell* aDocShell) { | |
diff --git a/dom/base/nsGlobalWindowOuter.h b/dom/base/nsGlobalWindowOuter.h | |
index f0e9ec469ab74f889ebd1f3a642de3a6a295f7c2..8d93bc1cb714ff5add6fb9920c8db8a5098cf92d 100644 | |
--- a/dom/base/nsGlobalWindowOuter.h | |
+++ b/dom/base/nsGlobalWindowOuter.h | |
@@ -334,6 +334,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 1f18279ece1e55dd9527f67ea4c5262249a5a64c..dd11bfb65baccb7021ec6673ca9a6b0d76c9ed09 100644 | |
--- a/dom/base/nsINode.cpp | |
+++ b/dom/base/nsINode.cpp | |
@@ -1357,6 +1357,61 @@ void nsINode::GetBoxQuadsFromWindowOrigin(const BoxQuadOptions& aOptions, | |
mozilla::GetBoxQuadsFromWindowOrigin(this, aOptions, aResult, aRv); | |
} | |
+static nsIFrame* GetFirstFrame(nsINode* aNode) { | |
+ if (!aNode->IsContent()) | |
+ return nullptr; | |
+ nsIFrame* frame = aNode->AsContent()->GetPrimaryFrame(FlushType::Frames); | |
+ if (!frame) { | |
+ FlattenedChildIterator iter(aNode->AsContent()); | |
+ for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { | |
+ frame = child->GetPrimaryFrame(FlushType::Frames); | |
+ if (frame) { | |
+ break; | |
+ } | |
+ } | |
+ } | |
+ return frame; | |
+} | |
+ | |
+void nsINode::ScrollRectIntoViewIfNeeded(int32_t x, int32_t y, | |
+ int32_t w, int32_t h, | |
+ ErrorResult& aRv) { | |
+ aRv = NS_ERROR_UNEXPECTED; | |
+ nsCOMPtr<Document> document = OwnerDoc(); | |
+ if (!document) { | |
+ return aRv.ThrowNotFoundError("Node is detached from document"); | |
+ } | |
+ PresShell* presShell = document->GetPresShell(); | |
+ if (!presShell) { | |
+ return aRv.ThrowNotFoundError("Node is detached from document"); | |
+ } | |
+ nsIFrame* primaryFrame = GetFirstFrame(this); | |
+ if (!primaryFrame) { | |
+ return aRv.ThrowNotFoundError("Node does not have a layout object"); | |
+ } | |
+ aRv = NS_OK; | |
+ nsRect rect; | |
+ if (x == -1 && y == -1 && w == -1 && h == -1) { | |
+ rect = primaryFrame->GetRectRelativeToSelf(); | |
+ } else { | |
+ rect = nsRect(nsPresContext::CSSPixelsToAppUnits(x), | |
+ nsPresContext::CSSPixelsToAppUnits(y), | |
+ nsPresContext::CSSPixelsToAppUnits(w), | |
+ nsPresContext::CSSPixelsToAppUnits(h)); | |
+ } | |
+ presShell->ScrollFrameIntoView( | |
+ primaryFrame, Some(rect), | |
+ ScrollAxis(WhereToScroll::Center, WhenToScroll::IfNotFullyVisible), | |
+ ScrollAxis(WhereToScroll::Center, WhenToScroll::IfNotFullyVisible), | |
+ ScrollFlags::ScrollOverflowHidden); | |
+ // If a _visual_ scroll update is pending, cancel it; otherwise, it will | |
+ // clobber next scroll (e.g. subsequent window.scrollTo(0, 0) wlll break). | |
+ if (presShell->GetPendingVisualScrollUpdate()) { | |
+ presShell->AcknowledgePendingVisualScrollUpdate(); | |
+ presShell->ClearPendingVisualScrollUpdate(); | |
+ } | |
+} | |
+ | |
already_AddRefed<DOMQuad> nsINode::ConvertQuadFromNode( | |
DOMQuad& aQuad, const GeometryNode& aFrom, | |
const ConvertCoordinateOptions& aOptions, CallerType aCallerType, | |
diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h | |
index be77a5e084b1037e27896f608e80c1c569ae09d2..313035157ff4abb1d6c3b9a1a07d0c1d9512772d 100644 | |
--- a/dom/base/nsINode.h | |
+++ b/dom/base/nsINode.h | |
@@ -2196,6 +2196,10 @@ class nsINode : public mozilla::dom::EventTarget { | |
nsTArray<RefPtr<DOMQuad>>& aResult, | |
ErrorResult& aRv); | |
+ void ScrollRectIntoViewIfNeeded(int32_t x, int32_t y, | |
+ int32_t w, int32_t h, | |
+ ErrorResult& aRv); | |
+ | |
already_AddRefed<DOMQuad> ConvertQuadFromNode( | |
DOMQuad& aQuad, const TextOrElementOrDocument& aFrom, | |
const ConvertCoordinateOptions& aOptions, CallerType aCallerType, | |
diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp | |
index 86fe04583c34bd84f7239c3515c9f335d84f48a2..b6705bc48f216e856b556349d206756a0cf91867 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 67682173f45c6a83cbad176c2922263d4f7dece9..7dd97f27bdf07673289fce62aaebe3b96492a2eb 100644 | |
--- a/dom/base/nsJSUtils.h | |
+++ b/dom/base/nsJSUtils.h | |
@@ -78,6 +78,7 @@ class nsJSUtils { | |
JSContext* aCx, mozilla::dom::Element* aElement, | |
JS::MutableHandleVector<JSObject*> aScopeChain); | |
+ static bool SetTimeZoneOverride(const char* timezoneId); | |
static void ResetTimeZone(); | |
static bool DumpEnabled(); | |
diff --git a/dom/chrome-webidl/BrowsingContext.webidl b/dom/chrome-webidl/BrowsingContext.webidl | |
index db60c475931caa32110d12ba63bb56980a2b36cc..d71a26cc87e29adc6fa0e353484e43ed9ae2acb4 100644 | |
--- a/dom/chrome-webidl/BrowsingContext.webidl | |
+++ b/dom/chrome-webidl/BrowsingContext.webidl | |
@@ -53,6 +53,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. | |
*/ | |
@@ -199,6 +217,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 | |
@@ -257,6 +281,8 @@ interface BrowsingContext { | |
undefined resetLocationChangeRateLimit(); | |
readonly attribute long childOffset; | |
+ | |
+ readonly attribute unsigned long long jugglerCurrentLoadIdentifier; | |
}; | |
BrowsingContext includes LoadContextMixin; | |
diff --git a/dom/geolocation/Geolocation.cpp b/dom/geolocation/Geolocation.cpp | |
index ff6fe276e3f5a19e3e22d98c4a38222880797d99..96157d17485534f97a4e39675ee77808ac495bfe 100644 | |
--- a/dom/geolocation/Geolocation.cpp | |
+++ b/dom/geolocation/Geolocation.cpp | |
@@ -23,6 +23,7 @@ | |
#include "nsComponentManagerUtils.h" | |
#include "nsContentPermissionHelper.h" | |
#include "nsContentUtils.h" | |
+#include "nsDocShell.h" | |
#include "nsGlobalWindow.h" | |
#include "mozilla/dom/Document.h" | |
#include "nsINamed.h" | |
@@ -260,10 +261,8 @@ nsGeolocationRequest::Allow(JS::Handle<JS::Value> aChoices) { | |
return NS_OK; | |
} | |
- RefPtr<nsGeolocationService> gs = | |
- nsGeolocationService::GetGeolocationService(); | |
- | |
- bool canUseCache = false; | |
+ nsGeolocationService* gs = mLocator->GetGeolocationService(); | |
+ bool canUseCache = gs != nsGeolocationService::sService.get(); | |
CachedPositionAndAccuracy lastPosition = gs->GetCachedPosition(); | |
if (lastPosition.position) { | |
EpochTimeStamp cachedPositionTime_ms; | |
@@ -441,8 +440,7 @@ void nsGeolocationRequest::Shutdown() { | |
// If there are no other high accuracy requests, the geolocation service will | |
// notify the provider to switch to the default accuracy. | |
if (mOptions && mOptions->mEnableHighAccuracy) { | |
- RefPtr<nsGeolocationService> gs = | |
- nsGeolocationService::GetGeolocationService(); | |
+ nsGeolocationService* gs = mLocator ? mLocator->GetGeolocationService() : nullptr; | |
if (gs) { | |
gs->UpdateAccuracy(); | |
} | |
@@ -732,8 +730,14 @@ void nsGeolocationService::StopDevice() { | |
StaticRefPtr<nsGeolocationService> nsGeolocationService::sService; | |
already_AddRefed<nsGeolocationService> | |
-nsGeolocationService::GetGeolocationService() { | |
+nsGeolocationService::GetGeolocationService(nsDocShell* docShell) { | |
RefPtr<nsGeolocationService> result; | |
+ if (docShell) { | |
+ result = docShell->GetGeolocationServiceOverride(); | |
+ if (result) | |
+ return result.forget(); | |
+ } | |
+ | |
if (nsGeolocationService::sService) { | |
result = nsGeolocationService::sService; | |
@@ -825,7 +829,9 @@ nsresult Geolocation::Init(nsPIDOMWindowInner* aContentDom) { | |
// If no aContentDom was passed into us, we are being used | |
// by chrome/c++ and have no mOwner, no mPrincipal, and no need | |
// to prompt. | |
- mService = nsGeolocationService::GetGeolocationService(); | |
+ nsCOMPtr<Document> doc = aContentDom ? aContentDom->GetDoc() : nullptr; | |
+ mService = nsGeolocationService::GetGeolocationService( | |
+ doc ? static_cast<nsDocShell*>(doc->GetDocShell()) : nullptr); | |
if (mService) { | |
mService->AddLocator(this); | |
} | |
diff --git a/dom/geolocation/Geolocation.h b/dom/geolocation/Geolocation.h | |
index 7e1af00d05fbafa2d828e2c7e4dcc5c82d115f5b..e85af9718d064e4d2865bc944e9d4ba1efb9a5d7 100644 | |
--- a/dom/geolocation/Geolocation.h | |
+++ b/dom/geolocation/Geolocation.h | |
@@ -31,6 +31,7 @@ | |
#include "nsIGeolocationProvider.h" | |
#include "mozilla/Attributes.h" | |
+#include "nsDocShell.h" | |
class nsGeolocationService; | |
class nsGeolocationRequest; | |
@@ -48,13 +49,14 @@ struct CachedPositionAndAccuracy { | |
bool isHighAccuracy; | |
}; | |
+ | |
/** | |
* Singleton that manages the geolocation provider | |
*/ | |
class nsGeolocationService final : public nsIGeolocationUpdate, | |
public nsIObserver { | |
public: | |
- static already_AddRefed<nsGeolocationService> GetGeolocationService(); | |
+ static already_AddRefed<nsGeolocationService> GetGeolocationService(nsDocShell* docShell = nullptr); | |
static mozilla::StaticRefPtr<nsGeolocationService> sService; | |
NS_DECL_THREADSAFE_ISUPPORTS | |
@@ -179,6 +181,8 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache { | |
// null. | |
static already_AddRefed<Geolocation> NonWindowSingleton(); | |
+ nsGeolocationService* GetGeolocationService() { return mService; }; | |
+ | |
private: | |
~Geolocation(); | |
diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp | |
index 913a9d4c46dac9936e0e8d5b4b174f8edb86a3a4..efc3e66b97223a3bc0e32b26fdf71f81d779fe6d 100644 | |
--- a/dom/html/HTMLInputElement.cpp | |
+++ b/dom/html/HTMLInputElement.cpp | |
@@ -58,6 +58,7 @@ | |
#include "mozilla/dom/Document.h" | |
#include "mozilla/dom/HTMLDataListElement.h" | |
#include "mozilla/dom/HTMLOptionElement.h" | |
+#include "nsDocShell.h" | |
#include "nsIFormControlFrame.h" | |
#include "nsITextControlFrame.h" | |
#include "nsIFrame.h" | |
@@ -779,6 +780,12 @@ nsresult HTMLInputElement::InitFilePicker(FilePickerType aType) { | |
return NS_ERROR_FAILURE; | |
} | |
+ nsDocShell* docShell = static_cast<nsDocShell*>(win->GetDocShell()); | |
+ if (docShell && docShell->IsFileInputInterceptionEnabled()) { | |
+ docShell->FilePickerShown(this); | |
+ return NS_OK; | |
+ } | |
+ | |
if (IsPopupBlocked(doc)) { | |
return NS_OK; | |
} | |
diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl | |
index 82f7d4d206c7274858a945d5db61aa02c366e472..a23386a5749c4af48b9bb86c8c48928da6aa3a9e 100644 | |
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl | |
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl | |
@@ -374,6 +374,26 @@ interface nsIDOMWindowUtils : nsISupports { | |
[optional] in long aButtons, | |
[optional] in unsigned long aIdentifier); | |
+ /** | |
+ * Playwright: a separate method to dispatch mouse event with a | |
+ * specific `jugglerEventId`. | |
+ */ | |
+ [can_run_script] | |
+ unsigned long jugglerSendMouseEvent(in AString aType, | |
+ in float aX, | |
+ in float aY, | |
+ in long aButton, | |
+ in long aClickCount, | |
+ in long aModifiers, | |
+ in boolean aIgnoreRootScrollFrame, | |
+ in float aPressure, | |
+ in unsigned short aInputSourceArg, | |
+ in boolean aIsDOMEventSynthesized, | |
+ in boolean aIsWidgetEventSynthesized, | |
+ in long aButtons, | |
+ in unsigned long aIdentifier, | |
+ in boolean aDisablePointerEvent); | |
+ | |
/** Synthesize a touch event. The event types supported are: | |
* touchstart, touchend, touchmove, and touchcancel | |
* | |
diff --git a/dom/ipc/BrowserChild.cpp b/dom/ipc/BrowserChild.cpp | |
index 978cd197de694b297ab3c603e5b0f715a7ea6eb5..4216c056cf71e7d10bcd4a6be11633c3ee283570 100644 | |
--- a/dom/ipc/BrowserChild.cpp | |
+++ b/dom/ipc/BrowserChild.cpp | |
@@ -1672,6 +1672,21 @@ void BrowserChild::HandleRealMouseButtonEvent(const WidgetMouseEvent& aEvent, | |
if (postLayerization) { | |
postLayerization->Register(); | |
} | |
+ | |
+ // Playwright: notify content that mouse event has been received and handled. | |
+ nsCOMPtr<nsIObserverService> observerService = | |
+ mozilla::services::GetObserverService(); | |
+ if (observerService && aEvent.mJugglerEventId) { | |
+ if (aEvent.mMessage == eMouseUp) { | |
+ observerService->NotifyObservers(nullptr, "juggler-mouse-event-hit-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("mouseup %" PRIu32, aEvent.mJugglerEventId)).get()); | |
+ } else if (aEvent.mMessage == eMouseDown) { | |
+ observerService->NotifyObservers(nullptr, "juggler-mouse-event-hit-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("mousedown %" PRIu32, aEvent.mJugglerEventId)).get()); | |
+ } else if (aEvent.mMessage == eMouseMove) { | |
+ observerService->NotifyObservers(nullptr, "juggler-mouse-event-hit-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("mousemove %" PRIu32, aEvent.mJugglerEventId)).get()); | |
+ } else if (aEvent.mMessage == eContextMenu) { | |
+ observerService->NotifyObservers(nullptr, "juggler-mouse-event-hit-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("contextmenu %" PRIu32, aEvent.mJugglerEventId)).get()); | |
+ } | |
+ } | |
} | |
mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealMouseButtonEvent( | |
diff --git a/dom/ipc/CoalescedMouseData.cpp b/dom/ipc/CoalescedMouseData.cpp | |
index 5aa445d2e0a6169e57c44569974d557b3baf7064..671f71979b407f0ca17c66f13805e851ba30479e 100644 | |
--- a/dom/ipc/CoalescedMouseData.cpp | |
+++ b/dom/ipc/CoalescedMouseData.cpp | |
@@ -67,6 +67,9 @@ bool CoalescedMouseData::CanCoalesce(const WidgetMouseEvent& aEvent, | |
mCoalescedInputEvent->pointerId == aEvent.pointerId && | |
mCoalescedInputEvent->mButton == aEvent.mButton && | |
mCoalescedInputEvent->mButtons == aEvent.mButtons && mGuid == aGuid && | |
+ // `mJugglerEventId` is 0 for non-juggler events and a unique number for | |
+ // juggler-emitted events. | |
+ mCoalescedInputEvent->mJugglerEventId == aEvent.mJugglerEventId && | |
mInputBlockId == aInputBlockId); | |
} | |
diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.cc b/dom/media/systemservices/video_engine/desktop_capture_impl.cc | |
index 2274a21e8a287932342bb4fb58af728d13b89224..913e72f08fb80fb11494035d2c8ee14a80be9d5b 100644 | |
--- a/dom/media/systemservices/video_engine/desktop_capture_impl.cc | |
+++ b/dom/media/systemservices/video_engine/desktop_capture_impl.cc | |
@@ -135,11 +135,12 @@ int32_t ScreenDeviceInfoImpl::GetOrientation(const char* aDeviceUniqueIdUTF8, | |
return 0; | |
} | |
-VideoCaptureModule* DesktopCaptureImpl::Create(const int32_t aModuleId, | |
+VideoCaptureModuleEx* DesktopCaptureImpl::Create(const int32_t aModuleId, | |
const char* aUniqueId, | |
- const CaptureDeviceType aType) { | |
+ const CaptureDeviceType aType, | |
+ bool aCaptureCursor) { | |
return new rtc::RefCountedObject<DesktopCaptureImpl>(aModuleId, aUniqueId, | |
- aType); | |
+ aType, aCaptureCursor); | |
} | |
int32_t WindowDeviceInfoImpl::Init() { | |
@@ -460,6 +461,12 @@ static std::unique_ptr<DesktopCapturer> CreateDesktopCapturerAndThread( | |
capturer = std::make_unique<DesktopAndCursorComposer>(std::move(capturer), | |
options); | |
+ // if (capture_cursor_) { | |
+ // capturer = std::make_unique<DesktopAndCursorComposer>( | |
+ // std::move(capturer), options); | |
+ // } else { | |
+ // capturer = std::move(capturer); | |
+ // } | |
} else if (aDeviceType == CaptureDeviceType::Browser) { | |
// XXX We don't capture cursors, so avoid the extra indirection layer. We | |
// could also pass null for the pMouseCursorMonitor. | |
@@ -476,7 +483,8 @@ static std::unique_ptr<DesktopCapturer> CreateDesktopCapturerAndThread( | |
} | |
DesktopCaptureImpl::DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, | |
- const CaptureDeviceType aType) | |
+ const CaptureDeviceType aType, | |
+ bool aCaptureCursor) | |
: mModuleId(aId), | |
mTrackingId(mozilla::TrackingId(CaptureEngineToTrackingSourceStr([&] { | |
switch (aType) { | |
@@ -495,6 +503,7 @@ DesktopCaptureImpl::DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, | |
mDeviceType(aType), | |
mControlThread(mozilla::GetCurrentSerialEventTarget()), | |
mNextFrameMinimumTime(Timestamp::Zero()), | |
+ // capture_cursor_(aCaptureCursor), | |
mCallbacks("DesktopCaptureImpl::mCallbacks") {} | |
DesktopCaptureImpl::~DesktopCaptureImpl() { | |
@@ -517,6 +526,19 @@ void DesktopCaptureImpl::DeRegisterCaptureDataCallback( | |
} | |
} | |
+void DesktopCaptureImpl::RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) { | |
+ rtc::CritScope lock(&mApiCs); | |
+ _rawFrameCallbacks.insert(rawFrameCallback); | |
+} | |
+ | |
+void DesktopCaptureImpl::DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) { | |
+ rtc::CritScope lock(&mApiCs); | |
+ auto it = _rawFrameCallbacks.find(rawFrameCallback); | |
+ if (it != _rawFrameCallbacks.end()) { | |
+ _rawFrameCallbacks.erase(it); | |
+ } | |
+} | |
+ | |
int32_t DesktopCaptureImpl::StopCaptureIfAllClientsClose() { | |
{ | |
auto callbacks = mCallbacks.Lock(); | |
@@ -650,6 +672,15 @@ void DesktopCaptureImpl::OnCaptureResult(DesktopCapturer::Result aResult, | |
frameInfo.height = aFrame->size().height(); | |
frameInfo.videoType = VideoType::kARGB; | |
+ size_t videoFrameStride = | |
+ frameInfo.width * DesktopFrame::kBytesPerPixel; | |
+ { | |
+ rtc::CritScope cs(&mApiCs); | |
+ for (auto rawFrameCallback : _rawFrameCallbacks) { | |
+ rawFrameCallback->OnRawFrame(videoFrame, videoFrameStride, frameInfo); | |
+ } | |
+ } | |
+ | |
size_t videoFrameLength = | |
frameInfo.width * frameInfo.height * DesktopFrame::kBytesPerPixel; | |
diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.h b/dom/media/systemservices/video_engine/desktop_capture_impl.h | |
index 64eadb140131ea807db8b55431630523342a88ce..02b086f7bd4848361f4ca808f6e1b7f82bfc78b1 100644 | |
--- a/dom/media/systemservices/video_engine/desktop_capture_impl.h | |
+++ b/dom/media/systemservices/video_engine/desktop_capture_impl.h | |
@@ -24,6 +24,7 @@ | |
#include "api/video/video_sink_interface.h" | |
#include "modules/desktop_capture/desktop_capturer.h" | |
#include "modules/video_capture/video_capture.h" | |
+#include "rtc_base/deprecated/recursive_critical_section.h" | |
#include "desktop_device_info.h" | |
#include "mozilla/DataMutex.h" | |
@@ -43,6 +44,21 @@ namespace webrtc { | |
class VideoCaptureEncodeInterface; | |
+class RawFrameCallback { | |
+ public: | |
+ virtual ~RawFrameCallback() {} | |
+ | |
+ virtual void OnRawFrame(uint8_t* videoFrame, size_t videoFrameLength, const VideoCaptureCapability& frameInfo) = 0; | |
+}; | |
+ | |
+class VideoCaptureModuleEx : public VideoCaptureModule { | |
+ public: | |
+ virtual ~VideoCaptureModuleEx() {} | |
+ | |
+ virtual void RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) = 0; | |
+ virtual void DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) = 0; | |
+}; | |
+ | |
// simulate deviceInfo interface for video engine, bridge screen/application and | |
// real screen/application device info | |
@@ -155,13 +171,13 @@ class BrowserDeviceInfoImpl : public VideoCaptureModule::DeviceInfo { | |
// As with video, DesktopCaptureImpl is a proxy for screen sharing | |
// and follows the video pipeline design | |
class DesktopCaptureImpl : public DesktopCapturer::Callback, | |
- public VideoCaptureModule { | |
+ public VideoCaptureModuleEx { | |
public: | |
/* Create a screen capture modules object | |
*/ | |
- static VideoCaptureModule* Create( | |
+ static VideoCaptureModuleEx* Create( | |
const int32_t aModuleId, const char* aUniqueId, | |
- const mozilla::camera::CaptureDeviceType aType); | |
+ const mozilla::camera::CaptureDeviceType aType, bool aCaptureCursor = true); | |
[[nodiscard]] static std::shared_ptr<VideoCaptureModule::DeviceInfo> | |
CreateDeviceInfo(const int32_t aId, | |
@@ -175,6 +191,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, | |
void DeRegisterCaptureDataCallback( | |
rtc::VideoSinkInterface<VideoFrame>* aCallback) override; | |
int32_t StopCaptureIfAllClientsClose() override; | |
+ void RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) override; | |
+ void DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) override; | |
int32_t SetCaptureRotation(VideoRotation aRotation) override; | |
bool SetApplyRotation(bool aEnable) override; | |
@@ -197,7 +215,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, | |
protected: | |
DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, | |
- const mozilla::camera::CaptureDeviceType aType); | |
+ const mozilla::camera::CaptureDeviceType aType, | |
+ bool aCaptureCusor); | |
virtual ~DesktopCaptureImpl(); | |
private: | |
@@ -205,6 +224,9 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, | |
static constexpr uint32_t kMaxDesktopCaptureCpuUsage = 50; | |
void InitOnThread(std::unique_ptr<DesktopCapturer> aCapturer, int aFramerate); | |
void ShutdownOnThread(); | |
+ | |
+ rtc::RecursiveCriticalSection mApiCs; | |
+ std::set<RawFrameCallback*> _rawFrameCallbacks; | |
// DesktopCapturer::Callback interface. | |
void OnCaptureResult(DesktopCapturer::Result aResult, | |
std::unique_ptr<DesktopFrame> aFrame) override; | |
@@ -217,6 +239,7 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, | |
// Set in StartCapture. | |
mozilla::Maybe<VideoCaptureCapability> mRequestedCapability | |
RTC_GUARDED_BY(mControlThreadChecker); | |
+ bool capture_cursor_ = true; | |
// The DesktopCapturer is created on mControlThread but assigned and accessed | |
// only on mCaptureThread. | |
std::unique_ptr<DesktopCapturer> mCapturer | |
diff --git a/dom/script/ScriptSettings.cpp b/dom/script/ScriptSettings.cpp | |
index 1f2d92bcb5d989bf9ecc044f8c51006f991b0007..9cf5dd885e658e0fe5e7ab75e7fc1f97a8d214b8 100644 | |
--- a/dom/script/ScriptSettings.cpp | |
+++ b/dom/script/ScriptSettings.cpp | |
@@ -150,6 +150,30 @@ ScriptSettingsStackEntry::~ScriptSettingsStackEntry() { | |
MOZ_ASSERT_IF(mGlobalObject, mGlobalObject->HasJSGlobal()); | |
} | |
+static nsIGlobalObject* UnwrapSandboxGlobal(nsIGlobalObject* global) { | |
+ if (!global) | |
+ return global; | |
+ JSObject* globalObject = global->GetGlobalJSObject(); | |
+ if (!globalObject) | |
+ return global; | |
+ JSContext* cx = nsContentUtils::GetCurrentJSContext(); | |
+ if (!cx) | |
+ return global; | |
+ JS::Rooted<JSObject*> proto(cx); | |
+ JS::RootedObject rootedGlobal(cx, globalObject); | |
+ if (!JS_GetPrototype(cx, rootedGlobal, &proto)) | |
+ return global; | |
+ if (!proto || !xpc::IsSandboxPrototypeProxy(proto)) | |
+ return global; | |
+ // If this is a sandbox associated with a DOMWindow via a | |
+ // sandboxPrototype, use that DOMWindow. This supports GreaseMonkey | |
+ // and JetPack content scripts. | |
+ proto = js::CheckedUnwrapDynamic(proto, cx, /* stopAtWindowProxy = */ false); | |
+ if (!proto) | |
+ return global; | |
+ return xpc::WindowGlobalOrNull(proto); | |
+} | |
+ | |
// If the entry or incumbent global ends up being something that the subject | |
// principal doesn't subsume, we don't want to use it. This never happens on | |
// the web, but can happen with asymmetric privilege relationships (i.e. | |
@@ -177,7 +201,7 @@ static nsIGlobalObject* ClampToSubject(nsIGlobalObject* aGlobalOrNull) { | |
NS_ENSURE_TRUE(globalPrin, GetCurrentGlobal()); | |
if (!nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller() | |
->SubsumesConsideringDomain(globalPrin)) { | |
- return GetCurrentGlobal(); | |
+ return UnwrapSandboxGlobal(GetCurrentGlobal()); | |
} | |
return aGlobalOrNull; | |
diff --git a/dom/security/nsCSPUtils.cpp b/dom/security/nsCSPUtils.cpp | |
index e52802d367e206f3903c0ab50c3fe6e6fb9088ca..865b810e245c519be34d0a646443fdc897742621 100644 | |
--- a/dom/security/nsCSPUtils.cpp | |
+++ b/dom/security/nsCSPUtils.cpp | |
@@ -127,6 +127,11 @@ void CSP_ApplyMetaCSPToDoc(mozilla::dom::Document& aDoc, | |
return; | |
} | |
+ if (aDoc.GetDocShell() && | |
+ nsDocShell::Cast(aDoc.GetDocShell())->IsBypassCSPEnabled()) { | |
+ return; | |
+ } | |
+ | |
nsAutoString policyStr( | |
nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>( | |
aPolicyStr)); | |
diff --git a/dom/webidl/GeometryUtils.webidl b/dom/webidl/GeometryUtils.webidl | |
index 2f71b284ee5f7e11f117c447834b48355784448c..2640bd57123c2b03bf4b06a2419cd020ba95f155 100644 | |
--- a/dom/webidl/GeometryUtils.webidl | |
+++ b/dom/webidl/GeometryUtils.webidl | |
@@ -16,6 +16,8 @@ dictionary BoxQuadOptions { | |
GeometryNode relativeTo; | |
[ChromeOnly] | |
boolean createFramesForSuppressedWhitespace = true; | |
+ [ChromeOnly] | |
+ boolean recurseWhenNoFrame = false; | |
}; | |
dictionary ConvertCoordinateOptions { | |
@@ -27,6 +29,9 @@ interface mixin GeometryUtils { | |
[Throws, Func="nsINode::HasBoxQuadsSupport", NeedsCallerType] | |
sequence<DOMQuad> getBoxQuads(optional BoxQuadOptions options = {}); | |
+ [ChromeOnly, Throws, Func="nsINode::HasBoxQuadsSupport"] | |
+ undefined scrollRectIntoViewIfNeeded(long x, long y, long w, long h); | |
+ | |
/* getBoxQuadsFromWindowOrigin is similar to getBoxQuads, but the | |
* returned quads are further translated relative to the window | |
* origin -- which is not the layout origin. Further translation | |
diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp | |
index 51a497f929a23811034e5fbffeaa35ee66dd6c77..41e530c57534b790442b153c7b9bec962a4f80d7 100644 | |
--- a/dom/workers/RuntimeService.cpp | |
+++ b/dom/workers/RuntimeService.cpp | |
@@ -989,7 +989,7 @@ void PrefLanguagesChanged(const char* /* aPrefName */, void* /* aClosure */) { | |
AssertIsOnMainThread(); | |
nsTArray<nsString> languages; | |
- Navigator::GetAcceptLanguages(languages); | |
+ Navigator::GetAcceptLanguages(nullptr, languages); | |
RuntimeService* runtime = RuntimeService::GetService(); | |
if (runtime) { | |
@@ -1191,8 +1191,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; | |
} | |
@@ -1808,6 +1807,13 @@ void RuntimeService::PropagateStorageAccessPermissionGranted( | |
} | |
} | |
+void RuntimeService::ResetDefaultLocaleInAllWorkers() { | |
+ AssertIsOnMainThread(); | |
+ BroadcastAllWorkers([](auto& worker) { | |
+ worker.ResetDefaultLocale(); | |
+ }); | |
+} | |
+ | |
template <typename Func> | |
void RuntimeService::BroadcastAllWorkers(const Func& aFunc) { | |
AssertIsOnMainThread(); | |
@@ -2330,6 +2336,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 a770d7330edb2f99483ab0363211817ae40028b0..f677f14e2ac42c94483726bac8538b52129615cc 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 a0deeb5d02c9df63a801275808b244475d0583fe..8b190bb49c017d78ace2554188286ceb2cf1eacb 100644 | |
--- a/dom/workers/WorkerPrivate.cpp | |
+++ b/dom/workers/WorkerPrivate.cpp | |
@@ -704,6 +704,18 @@ class UpdateContextOptionsRunnable final : public WorkerControlRunnable { | |
} | |
}; | |
+class ResetDefaultLocaleRunnable final : public WorkerControlRunnable { | |
+ public: | |
+ explicit ResetDefaultLocaleRunnable(WorkerPrivate* aWorkerPrivate) | |
+ : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) {} | |
+ | |
+ virtual bool WorkerRun(JSContext* aCx, | |
+ WorkerPrivate* aWorkerPrivate) override { | |
+ aWorkerPrivate->ResetDefaultLocaleInternal(aCx); | |
+ return true; | |
+ } | |
+}; | |
+ | |
class UpdateLanguagesRunnable final : public WorkerRunnable { | |
nsTArray<nsString> mLanguages; | |
@@ -1982,6 +1994,16 @@ void WorkerPrivate::UpdateContextOptions( | |
} | |
} | |
+void WorkerPrivate::ResetDefaultLocale() { | |
+ AssertIsOnParentThread(); | |
+ | |
+ RefPtr<ResetDefaultLocaleRunnable> runnable = | |
+ new ResetDefaultLocaleRunnable(this); | |
+ if (!runnable->Dispatch()) { | |
+ NS_WARNING("Failed to reset default locale in worker!"); | |
+ } | |
+} | |
+ | |
void WorkerPrivate::UpdateLanguages(const nsTArray<nsString>& aLanguages) { | |
AssertIsOnParentThread(); | |
@@ -5296,6 +5318,15 @@ void WorkerPrivate::UpdateContextOptionsInternal( | |
} | |
} | |
+void WorkerPrivate::ResetDefaultLocaleInternal(JSContext* aCx) { | |
+ JS_ResetDefaultLocale(JS_GetRuntime(aCx)); | |
+ auto data = mWorkerThreadAccessible.Access(); | |
+ | |
+ for (uint32_t index = 0; index < data->mChildWorkers.Length(); index++) { | |
+ data->mChildWorkers[index]->ResetDefaultLocale(); | |
+ } | |
+} | |
+ | |
void WorkerPrivate::UpdateLanguagesInternal( | |
const nsTArray<nsString>& aLanguages) { | |
WorkerGlobalScope* globalScope = GlobalScope(); | |
diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h | |
index 84b4f6d89e5d6fa3e622b95f395930993373f76f..b945587f4d6488a6a8191caa06340d4d5074f4c3 100644 | |
--- a/dom/workers/WorkerPrivate.h | |
+++ b/dom/workers/WorkerPrivate.h | |
@@ -414,6 +414,8 @@ class WorkerPrivate final | |
void UpdateContextOptionsInternal(JSContext* aCx, | |
const JS::ContextOptions& aContextOptions); | |
+ void ResetDefaultLocaleInternal(JSContext* aCx); | |
+ | |
void UpdateLanguagesInternal(const nsTArray<nsString>& aLanguages); | |
void UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key, | |
@@ -1036,6 +1038,8 @@ class WorkerPrivate final | |
void UpdateContextOptions(const JS::ContextOptions& aContextOptions); | |
+ void ResetDefaultLocale(); | |
+ | |
void UpdateLanguages(const nsTArray<nsString>& aLanguages); | |
void UpdateJSWorkerMemoryParameter(JSGCParamKey key, Maybe<uint32_t> value); | |
diff --git a/intl/components/src/TimeZone.cpp b/intl/components/src/TimeZone.cpp | |
index 145dd3f07112c2390325de50f8eae674484adfe6..8cb3787e1b6bb25c6a58f1d910ae7dbc440d9ace 100644 | |
--- a/intl/components/src/TimeZone.cpp | |
+++ b/intl/components/src/TimeZone.cpp | |
@@ -16,6 +16,7 @@ | |
namespace mozilla::intl { | |
+ | |
/* static */ | |
Result<UniquePtr<TimeZone>, ICUError> TimeZone::TryCreate( | |
Maybe<Span<const char16_t>> aTimeZoneOverride) { | |
@@ -239,6 +240,13 @@ static ICUResult SetDefaultTimeZone(TimeZoneIdentifierVector& timeZone) { | |
} | |
#endif | |
+bool TimeZone::IsValidTimeZoneId(const char* timeZoneId) { | |
+ // Validate timezone id. | |
+ mozilla::UniquePtr<icu::TimeZone> timeZone(icu::TimeZone::createTimeZone( | |
+ icu::UnicodeString(timeZoneId, -1, US_INV))); | |
+ return timeZone && *timeZone != icu::TimeZone::getUnknown(); | |
+} | |
+ | |
Result<bool, ICUError> TimeZone::SetDefaultTimeZone( | |
Span<const char> aTimeZone) { | |
#if MOZ_INTL_USE_ICU_CPP_TIMEZONE | |
diff --git a/intl/components/src/TimeZone.h b/intl/components/src/TimeZone.h | |
index 364cb45c2fafe9e419b415ee456b3411d5c38dea..ae119db52d55c3100df3d88f10c91d59b3fc07e8 100644 | |
--- a/intl/components/src/TimeZone.h | |
+++ b/intl/components/src/TimeZone.h | |
@@ -155,6 +155,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 45c6a88602e078cb872d49a2f50b30a994f76d8e..90989ff259ef19af094bc6ddfabe7552b80d84f3 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 9c3a652b60e09013f77b9a7f7da03d376d21cb6a..091daaee4a3402a0c572a21142517e4f9e706257 100644 | |
--- a/js/src/debugger/Object.cpp | |
+++ b/js/src/debugger/Object.cpp | |
@@ -2426,7 +2426,11 @@ Maybe<Completion> DebuggerObject::call(JSContext* cx, | |
invokeArgs[i].set(args2[i]); | |
} | |
+ // Disable CSP for the scope of the call. | |
+ const JSSecurityCallbacks* securityCallbacks = JS_GetSecurityCallbacks(cx); | |
+ JS_SetSecurityCallbacks(cx, nullptr); | |
ok = js::Call(cx, calleev, thisv, invokeArgs, &result); | |
+ JS_SetSecurityCallbacks(cx, securityCallbacks); | |
} | |
} | |
diff --git a/js/src/vm/DateTime.cpp b/js/src/vm/DateTime.cpp | |
index 0dd93e00a1d206d7117e4404240b49a2f49bb415..6d6b394c5acf7bbd02475694661230758d0ca942 100644 | |
--- a/js/src/vm/DateTime.cpp | |
+++ b/js/src/vm/DateTime.cpp | |
@@ -187,6 +187,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); | |
@@ -529,10 +534,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) { | |
@@ -750,6 +769,15 @@ static bool ReadTimeZoneLink(std::string_view tz, | |
void js::DateTimeInfo::internalResyncICUDefaultTimeZone() { | |
#if JS_HAS_INTL_API | |
+ if (!timeZoneOverride_.empty()) { | |
+ mozilla::Span<const char> tzid = mozilla::Span(timeZoneOverride_.data(), timeZoneOverride_.length()); | |
+ auto result = mozilla::intl::TimeZone::SetDefaultTimeZone(tzid); | |
+ if (result.isErr()) { | |
+ fprintf(stderr, "ERROR: failed to setup default time zone\n"); | |
+ } | |
+ return; | |
+ } | |
+ | |
// In the future we should not be setting a default ICU time zone at all, | |
// instead all accesses should go through the appropriate DateTimeInfo | |
// instance depending on the resist fingerprinting status. For now we return | |
@@ -761,7 +789,6 @@ void js::DateTimeInfo::internalResyncICUDefaultTimeZone() { | |
if (const char* tzenv = std::getenv("TZ")) { | |
std::string_view tz(tzenv); | |
- | |
mozilla::Span<const char> tzid; | |
# if defined(XP_WIN) | |
diff --git a/js/src/vm/DateTime.h b/js/src/vm/DateTime.h | |
index 20feae33a82f1cd1262aa3679ad23aa75aaf0b38..4dbb75c0ee2d5079de7dcf04a3505e0dee2719f7 100644 | |
--- a/js/src/vm/DateTime.h | |
+++ b/js/src/vm/DateTime.h | |
@@ -65,6 +65,8 @@ enum class ResetTimeZoneMode : bool { | |
*/ | |
extern void ResetTimeZoneInternal(ResetTimeZoneMode mode); | |
+extern void SetTimeZoneOverrideInternal(std::string timeZone); | |
+ | |
/** | |
* Stores date/time information, particularly concerning the current local | |
* time zone, and implements a small cache for daylight saving time offset | |
@@ -226,6 +228,7 @@ class DateTimeInfo { | |
private: | |
// The method below should only be called via js::ResetTimeZoneInternal(). | |
friend void js::ResetTimeZoneInternal(ResetTimeZoneMode); | |
+ friend void js::SetTimeZoneOverrideInternal(std::string); | |
static void resetTimeZone(ResetTimeZoneMode mode) { | |
{ | |
@@ -322,6 +325,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 | |
@@ -337,6 +342,8 @@ class DateTimeInfo { | |
void internalResetTimeZone(ResetTimeZoneMode mode); | |
+ void internalSetTimeZoneOverride(std::string timeZone); | |
+ | |
void updateTimeZone(); | |
void internalResyncICUDefaultTimeZone(); | |
diff --git a/layout/base/GeometryUtils.cpp b/layout/base/GeometryUtils.cpp | |
index dac899f7558b26d6848da8b98ed8a93555c8751a..2a07d67fa1c2840b25085566e84dc3b2d9b789cf 100644 | |
--- a/layout/base/GeometryUtils.cpp | |
+++ b/layout/base/GeometryUtils.cpp | |
@@ -23,6 +23,7 @@ | |
#include "nsContentUtils.h" | |
#include "nsCSSFrameConstructor.h" | |
#include "nsLayoutUtils.h" | |
+#include "ChildIterator.h" | |
using namespace mozilla; | |
using namespace mozilla::dom; | |
@@ -261,11 +262,27 @@ static bool CheckFramesInSameTopLevelBrowsingContext(nsIFrame* aFrame1, | |
return false; | |
} | |
+static nsIFrame* GetFrameForNode(nsINode* aNode, | |
+ bool aCreateFramesForSuppressedWhitespace, | |
+ bool aRecurseWhenNoFrame) { | |
+ nsIFrame* frame = GetFrameForNode(aNode, aCreateFramesForSuppressedWhitespace); | |
+ if (!frame && aRecurseWhenNoFrame && aNode->IsContent()) { | |
+ dom::FlattenedChildIterator iter(aNode->AsContent()); | |
+ for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { | |
+ frame = GetFrameForNode(child, aCreateFramesForSuppressedWhitespace, aRecurseWhenNoFrame); | |
+ if (frame) { | |
+ break; | |
+ } | |
+ } | |
+ } | |
+ return frame; | |
+} | |
+ | |
void GetBoxQuads(nsINode* aNode, const dom::BoxQuadOptions& aOptions, | |
nsTArray<RefPtr<DOMQuad> >& aResult, CallerType aCallerType, | |
ErrorResult& aRv) { | |
nsIFrame* frame = | |
- GetFrameForNode(aNode, aOptions.mCreateFramesForSuppressedWhitespace); | |
+ GetFrameForNode(aNode, aOptions.mCreateFramesForSuppressedWhitespace, aOptions.mRecurseWhenNoFrame); | |
if (!frame) { | |
// No boxes to return | |
return; | |
@@ -280,7 +297,7 @@ void GetBoxQuads(nsINode* aNode, const dom::BoxQuadOptions& aOptions, | |
// when that happens and re-check it. | |
if (!weakFrame.IsAlive()) { | |
frame = | |
- GetFrameForNode(aNode, aOptions.mCreateFramesForSuppressedWhitespace); | |
+ GetFrameForNode(aNode, aOptions.mCreateFramesForSuppressedWhitespace, aOptions.mRecurseWhenNoFrame); | |
if (!frame) { | |
// No boxes to return | |
return; | |
diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp | |
index f984d2e9bdecf0729f53e011032536fce44e317e..f2f27b01735a6785b4ecf98cea2c34221fbd08a4 100644 | |
--- a/layout/base/PresShell.cpp | |
+++ b/layout/base/PresShell.cpp | |
@@ -10896,7 +10896,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 ba52d5ab105d898305a06044aac13c60127c4838..19a78564af2cf467caa0c10f1a1e2220e57b3b79 100644 | |
--- a/layout/style/GeckoBindings.h | |
+++ b/layout/style/GeckoBindings.h | |
@@ -634,6 +634,7 @@ float Gecko_MediaFeatures_GetResolution(const mozilla::dom::Document*); | |
bool Gecko_MediaFeatures_PrefersReducedMotion(const mozilla::dom::Document*); | |
bool Gecko_MediaFeatures_PrefersReducedTransparency( | |
const mozilla::dom::Document*); | |
+bool Gecko_MediaFeatures_ForcedColors(const mozilla::dom::Document*); | |
mozilla::StylePrefersContrast Gecko_MediaFeatures_PrefersContrast( | |
const mozilla::dom::Document*); | |
mozilla::StylePrefersColorScheme Gecko_MediaFeatures_PrefersColorScheme( | |
diff --git a/layout/style/nsMediaFeatures.cpp b/layout/style/nsMediaFeatures.cpp | |
index 229a43854e8e5c14b751aad9f143b41cc212fd3f..0cfb5b1ad1e34155eb67659beb867d89d1e06538 100644 | |
--- a/layout/style/nsMediaFeatures.cpp | |
+++ b/layout/style/nsMediaFeatures.cpp | |
@@ -277,11 +277,11 @@ bool Gecko_MediaFeatures_MatchesPlatform(StylePlatform aPlatform) { | |
} | |
bool Gecko_MediaFeatures_PrefersReducedMotion(const Document* aDocument) { | |
- if (aDocument->ShouldResistFingerprinting( | |
- RFPTarget::CSSPrefersReducedMotion)) { | |
- return false; | |
- } | |
- return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1; | |
+ return aDocument->PrefersReducedMotion(); | |
+} | |
+ | |
+bool Gecko_MediaFeatures_ForcedColors(const Document* aDocument) { | |
+ return aDocument->ForcedColors(); | |
} | |
bool Gecko_MediaFeatures_PrefersReducedTransparency(const Document* aDocument) { | |
diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js | |
index c7c6f0ca825a4db6aa9223d3c096e26a2b005c99..88515dcfed1aa1b29194e17bacc960932d30ab89 100644 | |
--- a/modules/libpref/init/all.js | |
+++ b/modules/libpref/init/all.js | |
@@ -4117,7 +4117,9 @@ pref("devtools.f12_enabled", true); | |
// doesn't provide a way to lock the pref | |
pref("dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled", false); | |
#else | |
-pref("dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled", false, locked); | |
+// Playwright: DO NOT make preference locked so that we can overwrite it | |
+// later in our playwright.cfg file. | |
+pref("dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled", false); | |
#endif | |
// Whether sites require the open-protocol-handler permission to open a | |
diff --git a/netwerk/base/nsINetworkInterceptController.idl b/netwerk/base/nsINetworkInterceptController.idl | |
index d72dc570dc82ff9d576942b9e7c23d8a74d68049..a5fcddc4b0e53a862e5a77120b4ccff8a27cfbab 100644 | |
--- a/netwerk/base/nsINetworkInterceptController.idl | |
+++ b/netwerk/base/nsINetworkInterceptController.idl | |
@@ -59,6 +59,7 @@ interface nsIInterceptedChannel : nsISupports | |
* results in the resulting client not being controlled. | |
*/ | |
void resetInterception(in boolean bypass); | |
+ void resetInterceptionWithURI(in nsIURI aURI); | |
/** | |
* Set the status and reason for the forthcoming synthesized response. | |
diff --git a/netwerk/protocol/http/InterceptedHttpChannel.cpp b/netwerk/protocol/http/InterceptedHttpChannel.cpp | |
index c493259905d8b4e6b3a860cd6436c2606e8e8d29..7060deb04d3b3deb3e1cd90b75848229cf2252f2 100644 | |
--- a/netwerk/protocol/http/InterceptedHttpChannel.cpp | |
+++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp | |
@@ -729,6 +729,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", | |
@@ -1071,11 +1079,18 @@ InterceptedHttpChannel::OnStartRequest(nsIRequest* aRequest) { | |
GetCallback(mProgressSink); | |
} | |
+ // Playwright: main requests in firefox do not have loading principal. | |
+ // As they are intercepted by Playwright, they don't have | |
+ // serviceWorkerTainting as well. | |
+ // Thus these asserts are wrong for Playwright world. | |
+ // Note: these checks were added in https://github.com/mozilla/gecko-dev/commit/92e2cdde79c11510c3e4192e1b6264d00398ed95 | |
+ /* | |
MOZ_ASSERT_IF(!mLoadInfo->GetServiceWorkerTaintingSynthesized(), | |
mLoadInfo->GetLoadingPrincipal()); | |
// No need to do ORB checks if these conditions hold. | |
MOZ_DIAGNOSTIC_ASSERT(mLoadInfo->GetServiceWorkerTaintingSynthesized() || | |
mLoadInfo->GetLoadingPrincipal()->IsSystemPrincipal()); | |
+ */ | |
if (mPump && mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS) { | |
mPump->PeekStream(CallTypeSniffers, static_cast<nsIChannel*>(this)); | |
diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp | |
index 0908642956b66e867be59c5777f26e4c9f95d5ec..3d7677c454c5a0d2169686c2abad7b332f2413ce 100644 | |
--- a/parser/html/nsHtml5TreeOpExecutor.cpp | |
+++ b/parser/html/nsHtml5TreeOpExecutor.cpp | |
@@ -1372,6 +1372,10 @@ void nsHtml5TreeOpExecutor::UpdateReferrerInfoFromMeta( | |
void nsHtml5TreeOpExecutor::AddSpeculationCSP(const nsAString& aCSP) { | |
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); | |
+ if (mDocShell && static_cast<nsDocShell*>(mDocShell.get())->IsBypassCSPEnabled()) { | |
+ return; | |
+ } | |
+ | |
nsresult rv = NS_OK; | |
nsCOMPtr<nsIContentSecurityPolicy> preloadCsp = mDocument->GetPreloadCsp(); | |
if (!preloadCsp) { | |
diff --git a/security/manager/ssl/nsCertOverrideService.cpp b/security/manager/ssl/nsCertOverrideService.cpp | |
index b8d0bbc3a12f74c19284b26eadada361abeb7946..a50379c57158748684e2ea5065550af81c1e9b86 100644 | |
--- a/security/manager/ssl/nsCertOverrideService.cpp | |
+++ b/security/manager/ssl/nsCertOverrideService.cpp | |
@@ -438,7 +438,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; | |
@@ -650,14 +655,24 @@ static bool IsDebugger() { | |
NS_IMETHODIMP | |
nsCertOverrideService:: | |
- SetDisableAllSecurityChecksAndLetAttackersInterceptMyData(bool aDisable) { | |
- if (!(PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR") || IsDebugger())) { | |
+ SetDisableAllSecurityChecksAndLetAttackersInterceptMyData( | |
+ bool aDisable, uint32_t aUserContextId) { | |
+ if (false /* juggler hacks */ && !(PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR") || IsDebugger())) { | |
return NS_ERROR_NOT_AVAILABLE; | |
} | |
{ | |
MutexAutoLock lock(mMutex); | |
- mDisableAllSecurityCheck = aDisable; | |
+ if (aUserContextId) { | |
+ if (aDisable) { | |
+ mozilla::Unused << mUserContextIdsWithDisabledSecurityChecks.put(aUserContextId); | |
+ } else { | |
+ mUserContextIdsWithDisabledSecurityChecks.remove(aUserContextId); | |
+ } | |
+ return NS_OK; | |
+ } else { | |
+ mDisableAllSecurityCheck = aDisable; | |
+ } | |
} | |
nsCOMPtr<nsINSSComponent> nss(do_GetService(PSM_COMPONENT_CONTRACTID)); | |
diff --git a/security/manager/ssl/nsCertOverrideService.h b/security/manager/ssl/nsCertOverrideService.h | |
index 21cff56300db6490cf9649aa62099cb5525749b3..ce9a7fc16c2d5980be166e0f4ab9a25df300ca2f 100644 | |
--- a/security/manager/ssl/nsCertOverrideService.h | |
+++ b/security/manager/ssl/nsCertOverrideService.h | |
@@ -118,6 +118,7 @@ class nsCertOverrideService final : public nsICertOverrideService, | |
mozilla::Mutex mMutex; | |
bool mDisableAllSecurityCheck MOZ_GUARDED_BY(mMutex); | |
+ mozilla::HashSet<uint32_t> mUserContextIdsWithDisabledSecurityChecks MOZ_GUARDED_BY(mMutex); | |
nsCOMPtr<nsIFile> mSettingsFile MOZ_GUARDED_BY(mMutex); | |
nsTHashtable<nsCertOverrideEntry> mSettingsTable MOZ_GUARDED_BY(mMutex); | |
diff --git a/security/manager/ssl/nsICertOverrideService.idl b/security/manager/ssl/nsICertOverrideService.idl | |
index 6dfd07d6b676a99993408921de8dea9d561f201d..e3c6794363cd6336effbeac83a179f3796dd71b0 100644 | |
--- a/security/manager/ssl/nsICertOverrideService.idl | |
+++ b/security/manager/ssl/nsICertOverrideService.idl | |
@@ -137,7 +137,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/servo/components/style/gecko/media_features.rs b/servo/components/style/gecko/media_features.rs | |
index 4ca746ea84d917b95dfb66953660ca0a4572e647..bafeb667f3dbc7fa66d4baf811bf5cd5eb728c60 100644 | |
--- a/servo/components/style/gecko/media_features.rs | |
+++ b/servo/components/style/gecko/media_features.rs | |
@@ -291,10 +291,15 @@ pub enum ForcedColors { | |
/// https://drafts.csswg.org/mediaqueries-5/#forced-colors | |
fn eval_forced_colors(context: &Context, query_value: Option<ForcedColors>) -> bool { | |
- let forced = !context.device().use_document_colors(); | |
+ let prefers_forced_colors = | |
+ unsafe { bindings::Gecko_MediaFeatures_ForcedColors(context.device().document()) }; | |
+ let query_value = match query_value { | |
+ Some(v) => v, | |
+ None => return prefers_forced_colors, | |
+ }; | |
match query_value { | |
- Some(query_value) => forced == (query_value == ForcedColors::Active), | |
- None => forced, | |
+ ForcedColors::Active => prefers_forced_colors, | |
+ ForcedColors::None => !prefers_forced_colors, | |
} | |
} | |
diff --git a/toolkit/components/browser/nsIWebBrowserChrome.idl b/toolkit/components/browser/nsIWebBrowserChrome.idl | |
index 54de3abab5757dd706e3d909ccef6a0bed5deacc..f5c5480cd052ede0c76e5eec733dbb9283389045 100644 | |
--- a/toolkit/components/browser/nsIWebBrowserChrome.idl | |
+++ b/toolkit/components/browser/nsIWebBrowserChrome.idl | |
@@ -71,6 +71,9 @@ interface nsIWebBrowserChrome : nsISupports | |
// Whether this window should use out-of-process cross-origin subframes. | |
const unsigned long CHROME_FISSION_WINDOW = 0x00200000; | |
+ // Whether this window has "width" or "height" defined in features | |
+ const unsigned long JUGGLER_WINDOW_EXPLICIT_SIZE = 0x00400000; | |
+ | |
// Prevents new window animations on MacOS and Windows. Currently | |
// ignored for Linux. | |
const unsigned long CHROME_SUPPRESS_ANIMATION = 0x01000000; | |
diff --git a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs | |
index f2e7dcf9b3267de0c6b0837fcb5f407f72ea561b..bcbaee5b6218be4101237e48db64ee51971ebf96 100644 | |
--- a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs | |
+++ b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs | |
@@ -110,6 +110,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 26a414b5df26e43f2e3fa4ef539190021a167b04..e8d33f28f2696a4ecee3af2668747c7bfb803a2e 100644 | |
--- a/toolkit/components/startup/nsAppStartup.cpp | |
+++ b/toolkit/components/startup/nsAppStartup.cpp | |
@@ -370,7 +370,7 @@ nsAppStartup::Quit(uint32_t aMode, int aExitCode, bool* aUserAllowedQuit) { | |
nsCOMPtr<nsISimpleEnumerator> windowEnumerator; | |
nsCOMPtr<nsIWindowMediator> mediator( | |
do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); | |
- if (mediator) { | |
+ if (ferocity != eForceQuit && mediator) { | |
mediator->GetEnumerator(nullptr, getter_AddRefs(windowEnumerator)); | |
if (windowEnumerator) { | |
bool more; | |
diff --git a/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp b/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp | |
index 654903fadb709be976b72f36f155e23bc0622152..815b3dc24c9fda6b1db6c4666ac68904c87ac0ab 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 9496efd6688a34905794b9812b6c7a139dfe4171..058417afb5b459247a17da6d44c7ad62a0d79264 100644 | |
--- a/toolkit/components/windowwatcher/nsWindowWatcher.cpp | |
+++ b/toolkit/components/windowwatcher/nsWindowWatcher.cpp | |
@@ -1876,7 +1876,11 @@ uint32_t nsWindowWatcher::CalculateChromeFlagsForContent( | |
// Open a minimal popup. | |
*aIsPopupRequested = true; | |
- return nsIWebBrowserChrome::CHROME_MINIMAL_POPUP; | |
+ uint32_t chromeFlags = 0; | |
+ if (aFeatures.Exists("width") || aFeatures.Exists("height")) { | |
+ chromeFlags |= nsIWebBrowserChrome::JUGGLER_WINDOW_EXPLICIT_SIZE; | |
+ } | |
+ return chromeFlags | nsIWebBrowserChrome::CHROME_MINIMAL_POPUP; | |
} | |
/** | |
diff --git a/toolkit/mozapps/update/UpdateService.sys.mjs b/toolkit/mozapps/update/UpdateService.sys.mjs | |
index 23fca6cbe6cf1b3e625baf6e94e0c36112986ff2..07e040f75ac1a0ff7150213c7ef26804056e5f9c 100644 | |
--- a/toolkit/mozapps/update/UpdateService.sys.mjs | |
+++ b/toolkit/mozapps/update/UpdateService.sys.mjs | |
@@ -3848,6 +3848,8 @@ UpdateService.prototype = { | |
}, | |
get disabledForTesting() { | |
+ /* 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 <io.h> | |
#include <windows.h> | |
#include <versionhelpers.h> | |
@@ -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<nsIObserverService> os = mozilla::services::GetObserverService(); | |
+ if (os) { | |
+ nsIPrincipal* principal = doc->NodePrincipal(); | |
+ if (!principal->IsSystemPrincipal()) | |
+ os->NotifyObservers(ToSupports(doc), "juggler-document-open-loaded", nullptr); | |
+ } | |
+ | |
// This is a very cut-down version of | |
// nsDocumentViewer::LoadComplete that doesn't do various things | |
// that are not relevant here because this wasn't an actual | |
diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp | |
index ee210396f0e7265180f07f6f034c9389a87a02ce..6c0997ecb153547558ad1a0c146b0ca4e8ffbc46 100644 | |
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp | |
+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp | |
@@ -112,6 +112,7 @@ | |
#include "mozilla/Components.h" | |
#include "mozilla/ClearOnShutdown.h" | |
+#include "mozilla/ErrorNames.h" | |
#include "mozilla/Preferences.h" | |
#include "mozilla/ipc/URIUtils.h" | |
@@ -836,6 +837,12 @@ NS_IMETHODIMP nsExternalHelperAppService::ApplyDecodingForExtension( | |
return NS_OK; | |
} | |
+NS_IMETHODIMP nsExternalHelperAppService::SetDownloadInterceptor( | |
+ nsIDownloadInterceptor* interceptor) { | |
+ mInterceptor = interceptor; | |
+ return NS_OK; | |
+} | |
+ | |
nsresult nsExternalHelperAppService::GetFileTokenForPath( | |
const char16_t* aPlatformAppPath, nsIFile** aFile) { | |
nsDependentString platformAppPath(aPlatformAppPath); | |
@@ -1446,7 +1453,12 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel* aChannel) { | |
// Strip off the ".part" from mTempLeafName | |
mTempLeafName.Truncate(mTempLeafName.Length() - ArrayLength(".part") + 1); | |
+ return CreateSaverForTempFile(); | |
+} | |
+ | |
+nsresult nsExternalAppHandler::CreateSaverForTempFile() { | |
MOZ_ASSERT(!mSaver, "Output file initialization called more than once!"); | |
+ nsresult rv; | |
mSaver = | |
do_CreateInstance(NS_BACKGROUNDFILESAVERSTREAMLISTENER_CONTRACTID, &rv); | |
NS_ENSURE_SUCCESS(rv, rv); | |
@@ -1635,7 +1647,36 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { | |
return NS_OK; | |
} | |
- rv = SetUpTempFile(aChannel); | |
+ bool isIntercepted = false; | |
+ nsCOMPtr<nsIDownloadInterceptor> interceptor = mExtProtSvc->mInterceptor; | |
+ if (interceptor) { | |
+ nsCOMPtr<nsIFile> fileToUse; | |
+ rv = interceptor->InterceptDownloadRequest(this, request, mBrowsingContext, getter_AddRefs(fileToUse), &isIntercepted); | |
+ if (!NS_SUCCEEDED(rv)) { | |
+ LOG((" failed to call nsIDowloadInterceptor.interceptDownloadRequest")); | |
+ return rv; | |
+ } | |
+ if (isIntercepted) { | |
+ LOG((" request interceped by nsIDowloadInterceptor")); | |
+ if (fileToUse) { | |
+ mTempFile = fileToUse; | |
+ rv = mTempFile->GetLeafName(mTempLeafName); | |
+ NS_ENSURE_SUCCESS(rv, rv); | |
+ } else { | |
+ Cancel(NS_BINDING_ABORTED); | |
+ return NS_OK; | |
+ } | |
+ } | |
+ } | |
+ | |
+ // Temp file is the final destination when download is intercepted. In that | |
+ // case we only need to create saver (and not create transfer later). Not creating | |
+ // mTransfer also cuts off all downloads handling logic in the js compoenents and | |
+ // browser UI. | |
+ if (isIntercepted) | |
+ rv = CreateSaverForTempFile(); | |
+ else | |
+ rv = SetUpTempFile(aChannel); | |
if (NS_FAILED(rv)) { | |
nsresult transferError = rv; | |
@@ -1687,6 +1728,9 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { | |
bool alwaysAsk = true; | |
mMimeInfo->GetAlwaysAskBeforeHandling(&alwaysAsk); | |
+ if (isIntercepted) { | |
+ return NS_OK; | |
+ } | |
if (alwaysAsk) { | |
// But we *don't* ask if this mimeInfo didn't come from | |
// our user configuration datastore and the user has said | |
@@ -2193,6 +2237,16 @@ nsExternalAppHandler::OnSaveComplete(nsIBackgroundFileSaver* aSaver, | |
NotifyTransfer(aStatus); | |
} | |
+ if (!mCanceled) { | |
+ nsCOMPtr<nsIDownloadInterceptor> interceptor = mExtProtSvc->mInterceptor; | |
+ if (interceptor) { | |
+ nsCString noError; | |
+ nsresult rv = interceptor->OnDownloadComplete(this, noError); | |
+ MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to call nsIDowloadInterceptor.OnDownloadComplete"); | |
+ Unused << rv; | |
+ } | |
+ } | |
+ | |
return NS_OK; | |
} | |
@@ -2674,6 +2728,15 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason) { | |
} | |
} | |
+ nsCOMPtr<nsIDownloadInterceptor> interceptor = mExtProtSvc->mInterceptor; | |
+ if (interceptor) { | |
+ nsCString errorName; | |
+ GetErrorName(aReason, errorName); | |
+ nsresult rv = interceptor->OnDownloadComplete(this, errorName); | |
+ MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed notify nsIDowloadInterceptor about cancel"); | |
+ Unused << rv; | |
+ } | |
+ | |
// Break our reference cycle with the helper app dialog (set up in | |
// OnStartRequest) | |
mDialog = nullptr; | |
diff --git a/uriloader/exthandler/nsExternalHelperAppService.h b/uriloader/exthandler/nsExternalHelperAppService.h | |
index 6c8cbc5871d3aa721a3f1a3ff6c0ef8b0044c63e..8e7c9af1a2cfe60c9c543af1ab55f6c229000bd4 100644 | |
--- a/uriloader/exthandler/nsExternalHelperAppService.h | |
+++ b/uriloader/exthandler/nsExternalHelperAppService.h | |
@@ -257,6 +257,8 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService, | |
mozilla::dom::BrowsingContext* aContentContext, bool aForceSave, | |
nsIInterfaceRequestor* aWindowContext, | |
nsIStreamListener** aStreamListener); | |
+ | |
+ nsCOMPtr<nsIDownloadInterceptor> mInterceptor; | |
}; | |
/** | |
@@ -456,6 +458,9 @@ class nsExternalAppHandler final : public nsIStreamListener, | |
* Upon successful return, both mTempFile and mSaver will be valid. | |
*/ | |
nsresult SetUpTempFile(nsIChannel* aChannel); | |
+ | |
+ nsresult CreateSaverForTempFile(); | |
+ | |
/** | |
* When we download a helper app, we are going to retarget all load | |
* notifications into our own docloader and load group instead of | |
diff --git a/uriloader/exthandler/nsIExternalHelperAppService.idl b/uriloader/exthandler/nsIExternalHelperAppService.idl | |
index 307e6196a89df52d0bccc3ebd1359f58e32de75d..c3692d0f76178ac3aeb1c77a0e973bfa22359346 100644 | |
--- a/uriloader/exthandler/nsIExternalHelperAppService.idl | |
+++ b/uriloader/exthandler/nsIExternalHelperAppService.idl | |
@@ -6,6 +6,8 @@ | |
#include "nsICancelable.idl" | |
+webidl BrowsingContext; | |
+interface nsIHelperAppLauncher; | |
interface nsIURI; | |
interface nsIRequest; | |
interface nsIStreamListener; | |
@@ -15,6 +17,17 @@ interface nsIWebProgressListener2; | |
interface nsIInterfaceRequestor; | |
webidl BrowsingContext; | |
+/** | |
+ * Interceptor interface used by Juggler. | |
+ */ | |
+[scriptable, uuid(9a20e9b0-75d0-11ea-bc55-0242ac130003)] | |
+interface nsIDownloadInterceptor : nsISupports | |
+{ | |
+ bool interceptDownloadRequest(in nsIHelperAppLauncher aHandler, in nsIRequest aRequest, in BrowsingContext aBrowsingContext, out nsIFile file); | |
+ | |
+ void onDownloadComplete(in nsIHelperAppLauncher aHandler, in ACString aErrorName); | |
+}; | |
+ | |
/** | |
* The external helper app service is used for finding and launching | |
* platform specific external applications for a given mime content type. | |
@@ -76,6 +89,7 @@ interface nsIExternalHelperAppService : nsISupports | |
boolean applyDecodingForExtension(in AUTF8String aExtension, | |
in ACString aEncodingType); | |
+ void setDownloadInterceptor(in nsIDownloadInterceptor interceptor); | |
}; | |
/** | |
diff --git a/widget/InProcessCompositorWidget.cpp b/widget/InProcessCompositorWidget.cpp | |
index 1c25e9d9a101233f71e92288a0f93125b81ac1c5..22cf67b0f6e3ddd2b3ed725a314ba6a9896abd1c 100644 | |
--- a/widget/InProcessCompositorWidget.cpp | |
+++ b/widget/InProcessCompositorWidget.cpp | |
@@ -4,7 +4,10 @@ | |
#include "InProcessCompositorWidget.h" | |
+#include "HeadlessCompositorWidget.h" | |
+#include "HeadlessWidget.h" | |
#include "mozilla/VsyncDispatcher.h" | |
+#include "mozilla/widget/PlatformWidgetTypes.h" | |
#include "nsBaseWidget.h" | |
namespace mozilla { | |
@@ -23,6 +26,12 @@ RefPtr<CompositorWidget> CompositorWidget::CreateLocal( | |
// do it after the static_cast. | |
nsBaseWidget* widget = static_cast<nsBaseWidget*>(aWidget); | |
MOZ_RELEASE_ASSERT(widget); | |
+ if (aInitData.type() == | |
+ CompositorWidgetInitData::THeadlessCompositorWidgetInitData) { | |
+ return new HeadlessCompositorWidget( | |
+ aInitData.get_HeadlessCompositorWidgetInitData(), aOptions, | |
+ static_cast<HeadlessWidget*>(aWidget)); | |
+ } | |
return new InProcessCompositorWidget(aOptions, widget); | |
} | |
#endif | |
diff --git a/widget/MouseEvents.h b/widget/MouseEvents.h | |
index 5a19cb4082674ede982a0c66c84bf7c4642abe2b..5fe6ae7b5bf605e5d9130aa164d7cbbb486e54e0 100644 | |
--- a/widget/MouseEvents.h | |
+++ b/widget/MouseEvents.h | |
@@ -203,6 +203,7 @@ class WidgetMouseEvent : public WidgetMouseEventBase, | |
: mReason(eReal), | |
mContextMenuTrigger(eNormal), | |
mClickCount(0), | |
+ mJugglerEventId(0), | |
mIgnoreRootScrollFrame(false), | |
mUseLegacyNonPrimaryDispatch(false), | |
mClickEventPrevented(false) {} | |
@@ -213,6 +214,7 @@ class WidgetMouseEvent : public WidgetMouseEventBase, | |
mReason(aReason), | |
mContextMenuTrigger(eNormal), | |
mClickCount(0), | |
+ mJugglerEventId(0), | |
mIgnoreRootScrollFrame(false), | |
mUseLegacyNonPrimaryDispatch(false), | |
mClickEventPrevented(false) {} | |
@@ -231,6 +233,7 @@ class WidgetMouseEvent : public WidgetMouseEventBase, | |
mReason(aReason), | |
mContextMenuTrigger(aContextMenuTrigger), | |
mClickCount(0), | |
+ mJugglerEventId(0), | |
mIgnoreRootScrollFrame(false), | |
mUseLegacyNonPrimaryDispatch(false), | |
mClickEventPrevented(false) { | |
@@ -280,6 +283,9 @@ class WidgetMouseEvent : public WidgetMouseEventBase, | |
// Otherwise, this must be 0. | |
uint32_t mClickCount; | |
+ // Unique event ID | |
+ uint32_t mJugglerEventId; | |
+ | |
// Whether the event should ignore scroll frame bounds during dispatch. | |
bool mIgnoreRootScrollFrame; | |
@@ -296,6 +302,7 @@ class WidgetMouseEvent : public WidgetMouseEventBase, | |
mExitFrom = aEvent.mExitFrom; | |
mClickCount = aEvent.mClickCount; | |
+ mJugglerEventId = aEvent.mJugglerEventId; | |
mIgnoreRootScrollFrame = aEvent.mIgnoreRootScrollFrame; | |
mUseLegacyNonPrimaryDispatch = aEvent.mUseLegacyNonPrimaryDispatch; | |
mClickEventPrevented = aEvent.mClickEventPrevented; | |
diff --git a/widget/cocoa/NativeKeyBindings.mm b/widget/cocoa/NativeKeyBindings.mm | |
index d3e5983259053175584254e7ac01ca9ce024f33a..97f5b851c402fea5477c0ee57af451c62b016eec 100644 | |
--- a/widget/cocoa/NativeKeyBindings.mm | |
+++ b/widget/cocoa/NativeKeyBindings.mm | |
@@ -492,6 +492,13 @@ | |
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 bb4ee9175e66dc40de1871a7f91368fe309494a3..856faef297c9eb0a510df123513b9ac095634e98 100644 | |
--- a/widget/headless/HeadlessCompositorWidget.cpp | |
+++ b/widget/headless/HeadlessCompositorWidget.cpp | |
@@ -3,6 +3,7 @@ | |
* License, v. 2.0. If a copy of the MPL was not distributed with this | |
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
+#include "mozilla/layers/CompositorThread.h" | |
#include "mozilla/widget/PlatformWidgetTypes.h" | |
#include "HeadlessCompositorWidget.h" | |
#include "VsyncDispatcher.h" | |
@@ -16,7 +17,30 @@ HeadlessCompositorWidget::HeadlessCompositorWidget( | |
: CompositorWidget(aOptions), | |
mWidget(aWindow), | |
mClientSize(LayoutDeviceIntSize(aInitData.InitialClientSize()), | |
- "HeadlessCompositorWidget::mClientSize") {} | |
+ "HeadlessCompositorWidget::mClientSize"), | |
+ mMon("snapshotListener") {} | |
+ | |
+void HeadlessCompositorWidget::SetSnapshotListener(HeadlessWidget::SnapshotListener&& listener) { | |
+ MOZ_ASSERT(NS_IsMainThread()); | |
+ | |
+ ReentrantMonitorAutoEnter lock(mMon); | |
+ mSnapshotListener = std::move(listener); | |
+ layers::CompositorThread()->Dispatch(NewRunnableMethod( | |
+ "HeadlessCompositorWidget::PeriodicSnapshot", this, | |
+ &HeadlessCompositorWidget::PeriodicSnapshot | |
+ )); | |
+} | |
+ | |
+already_AddRefed<gfx::DrawTarget> HeadlessCompositorWidget::StartRemoteDrawingInRegion( | |
+ const LayoutDeviceIntRegion& aInvalidRegion, | |
+ layers::BufferMode* aBufferMode) { | |
+ if (!mDrawTarget) | |
+ return nullptr; | |
+ | |
+ *aBufferMode = layers::BufferMode::BUFFER_NONE; | |
+ RefPtr<gfx::DrawTarget> result = mDrawTarget; | |
+ return result.forget(); | |
+} | |
void HeadlessCompositorWidget::ObserveVsync(VsyncObserver* aObserver) { | |
if (RefPtr<CompositorVsyncDispatcher> cvd = | |
@@ -31,6 +55,59 @@ void HeadlessCompositorWidget::NotifyClientSizeChanged( | |
const LayoutDeviceIntSize& aClientSize) { | |
auto size = mClientSize.Lock(); | |
*size = aClientSize; | |
+ layers::CompositorThread()->Dispatch(NewRunnableMethod<LayoutDeviceIntSize>( | |
+ "HeadlessCompositorWidget::UpdateDrawTarget", this, | |
+ &HeadlessCompositorWidget::UpdateDrawTarget, | |
+ aClientSize)); | |
+} | |
+ | |
+void HeadlessCompositorWidget::UpdateDrawTarget(const LayoutDeviceIntSize& aClientSize) { | |
+ MOZ_ASSERT(NS_IsInCompositorThread()); | |
+ if (aClientSize.IsEmpty()) { | |
+ mDrawTarget = nullptr; | |
+ return; | |
+ } | |
+ | |
+ RefPtr<gfx::DrawTarget> old = std::move(mDrawTarget); | |
+ gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8; | |
+ gfx::IntSize size = aClientSize.ToUnknownSize(); | |
+ mDrawTarget = mozilla::gfx::Factory::CreateDrawTarget( | |
+ mozilla::gfx::BackendType::SKIA, size, format); | |
+ if (old) { | |
+ RefPtr<gfx::SourceSurface> snapshot = old->Snapshot(); | |
+ if (snapshot) | |
+ mDrawTarget->CopySurface(snapshot.get(), old->GetRect(), gfx::IntPoint(0, 0)); | |
+ } | |
+} | |
+ | |
+void HeadlessCompositorWidget::PeriodicSnapshot() { | |
+ ReentrantMonitorAutoEnter lock(mMon); | |
+ if (!mSnapshotListener) | |
+ return; | |
+ | |
+ TakeSnapshot(); | |
+ NS_DelayedDispatchToCurrentThread(NewRunnableMethod( | |
+ "HeadlessCompositorWidget::PeriodicSnapshot", this, | |
+ &HeadlessCompositorWidget::PeriodicSnapshot), 40); | |
+} | |
+ | |
+void HeadlessCompositorWidget::TakeSnapshot() { | |
+ if (!mDrawTarget) | |
+ return; | |
+ | |
+ RefPtr<gfx::SourceSurface> snapshot = mDrawTarget->Snapshot(); | |
+ if (!snapshot) { | |
+ fprintf(stderr, "Failed to get snapshot of draw target\n"); | |
+ return; | |
+ } | |
+ | |
+ RefPtr<gfx::DataSourceSurface> dataSurface = snapshot->GetDataSurface(); | |
+ if (!dataSurface) { | |
+ fprintf(stderr, "Failed to get data surface from snapshot\n"); | |
+ return; | |
+ } | |
+ | |
+ mSnapshotListener(std::move(dataSurface)); | |
} | |
LayoutDeviceIntSize HeadlessCompositorWidget::GetClientSize() { | |
diff --git a/widget/headless/HeadlessCompositorWidget.h b/widget/headless/HeadlessCompositorWidget.h | |
index facd2bc65afab8ec1aa322faa20a67464964dfb9..d6dea95472bec6006411753c3dfdab2e3659171f 100644 | |
--- a/widget/headless/HeadlessCompositorWidget.h | |
+++ b/widget/headless/HeadlessCompositorWidget.h | |
@@ -6,6 +6,7 @@ | |
#ifndef widget_headless_HeadlessCompositorWidget_h | |
#define widget_headless_HeadlessCompositorWidget_h | |
+#include "mozilla/ReentrantMonitor.h" | |
#include "mozilla/widget/CompositorWidget.h" | |
#include "HeadlessWidget.h" | |
@@ -23,8 +24,12 @@ class HeadlessCompositorWidget final : public CompositorWidget, | |
HeadlessWidget* aWindow); | |
void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize); | |
+ void SetSnapshotListener(HeadlessWidget::SnapshotListener&& listener); | |
// CompositorWidget Overrides | |
+ already_AddRefed<gfx::DrawTarget> StartRemoteDrawingInRegion( | |
+ const LayoutDeviceIntRegion& aInvalidRegion, | |
+ layers::BufferMode* aBufferMode) override; | |
uintptr_t GetWidgetKey() override; | |
@@ -42,10 +47,18 @@ class HeadlessCompositorWidget final : public CompositorWidget, | |
} | |
private: | |
+ void UpdateDrawTarget(const LayoutDeviceIntSize& aClientSize); | |
+ void PeriodicSnapshot(); | |
+ void TakeSnapshot(); | |
+ | |
HeadlessWidget* mWidget; | |
+ mozilla::ReentrantMonitor mMon; | |
// See GtkCompositorWidget for the justification for this mutex. | |
DataMutex<LayoutDeviceIntSize> mClientSize; | |
+ | |
+ HeadlessWidget::SnapshotListener mSnapshotListener; | |
+ RefPtr<gfx::DrawTarget> mDrawTarget; | |
}; | |
} // namespace widget | |
diff --git a/widget/headless/HeadlessWidget.cpp b/widget/headless/HeadlessWidget.cpp | |
index 083d026d3c019cb76fff2b8f605f3d6ef8dd578f..84c049709ead92c980b86230513a634bf6337085 100644 | |
--- a/widget/headless/HeadlessWidget.cpp | |
+++ b/widget/headless/HeadlessWidget.cpp | |
@@ -111,6 +111,8 @@ void HeadlessWidget::Destroy() { | |
} | |
} | |
+ SetSnapshotListener(nullptr); | |
+ | |
nsBaseWidget::OnDestroy(); | |
nsBaseWidget::Destroy(); | |
@@ -621,5 +623,14 @@ nsresult HeadlessWidget::SynthesizeNativeTouchpadPan( | |
return NS_OK; | |
} | |
+void HeadlessWidget::SetSnapshotListener(SnapshotListener&& listener) { | |
+ if (!mCompositorWidget) { | |
+ if (listener) | |
+ fprintf(stderr, "Trying to set SnapshotListener without compositor widget\n"); | |
+ return; | |
+ } | |
+ mCompositorWidget->SetSnapshotListener(std::move(listener)); | |
+} | |
+ | |
} // namespace widget | |
} // namespace mozilla | |
diff --git a/widget/headless/HeadlessWidget.h b/widget/headless/HeadlessWidget.h | |
index 9856991ef32f25f51942f8cd664a09bec2192c70..948947a421179e91c51005aeb83ed0d18cfc84ce 100644 | |
--- a/widget/headless/HeadlessWidget.h | |
+++ b/widget/headless/HeadlessWidget.h | |
@@ -141,6 +141,9 @@ class HeadlessWidget : public nsBaseWidget { | |
int32_t aModifierFlags, | |
nsIObserver* aObserver) override; | |
+ using SnapshotListener = std::function<void(RefPtr<gfx::DataSourceSurface>&&)>; | |
+ void SetSnapshotListener(SnapshotListener&& listener); | |
+ | |
private: | |
~HeadlessWidget(); | |
bool mEnabled; | |
diff --git a/widget/nsGUIEventIPC.h b/widget/nsGUIEventIPC.h | |
index 53653511f8d08fd25421a60f9d0df138076b29ff..e8ec8c5df247d56e9dcd235f34c789fb13c4133c 100644 | |
--- a/widget/nsGUIEventIPC.h | |
+++ b/widget/nsGUIEventIPC.h | |
@@ -234,6 +234,7 @@ struct ParamTraits<mozilla::WidgetMouseEvent> { | |
aParam.mExitFrom.value())); | |
} | |
WriteParam(aWriter, aParam.mClickCount); | |
+ WriteParam(aWriter, aParam.mJugglerEventId); | |
} | |
static bool Read(MessageReader* aReader, paramType* aResult) { | |
@@ -258,6 +259,7 @@ struct ParamTraits<mozilla::WidgetMouseEvent> { | |
aResult->mExitFrom = Some(static_cast<paramType::ExitFrom>(exitFrom)); | |
} | |
rv = rv && ReadParam(aReader, &aResult->mClickCount); | |
+ rv = rv && ReadParam(aReader, &aResult->mJugglerEventId); | |
return rv; | |
} | |
}; | |
diff --git a/xpcom/reflect/xptinfo/xptinfo.h b/xpcom/reflect/xptinfo/xptinfo.h | |
index 2456c2c2b58b27cd595880b547ed20fb687a1835..e967c089b2331c7cd36d34e511543fbc84320b7d 100644 | |
--- a/xpcom/reflect/xptinfo/xptinfo.h | |
+++ b/xpcom/reflect/xptinfo/xptinfo.h | |
@@ -514,7 +514,7 @@ static_assert(sizeof(nsXPTMethodInfo) == 8, "wrong size"); | |
#if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE) | |
# define PARAM_BUFFER_COUNT 18 | |
#else | |
-# define PARAM_BUFFER_COUNT 14 | |
+# define PARAM_BUFFER_COUNT 15 | |
#endif | |
/** |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment