Bug 1403077 - implement the stylo blocklist mechanism.
In this patch, we read the stylo blocklist into nsLayoutUtils's global static
variable during nsLayoutUtils::Initialize(). So, we can decide if we should
fallback to use Gecko backend while updating style backend for a document.
We add "layout.css.stylo-blocklist.blocked_domains" and
"layout.css.stylo-blocklist.enabled" to ContentPrefs.cpp because they are read
very early (during nsLayoutUtils::Initialize).
MozReview-Commit-ID: 8c4n6m9dYD8
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -13680,17 +13680,18 @@ nsIDocument::UpdateStyleBackendType()
if (nsLayoutUtils::StyloEnabled()) {
// Disable stylo only for system principal. Other principals aren't
// able to use XUL by default, and the back door to enable XUL is
// mostly just for testing, which means they don't matter, and we
// shouldn't respect them at the same time.
// Note that, since tests can have XUL support, we still need to
// explicitly exclude XUL documents here.
if (!nsContentUtils::IsSystemPrincipal(NodePrincipal()) &&
- !IsXULDocument() && !ShouldUseGeckoBackend(mDocumentURI)) {
+ !IsXULDocument() && !ShouldUseGeckoBackend(mDocumentURI) &&
+ !nsLayoutUtils::IsInStyloBlocklist(NodePrincipal())) {
mStyleBackendType = StyleBackendType::Servo;
}
}
#endif
}
/**
* Retrieves the classification of the Flash plugins in the document based on
--- a/dom/ipc/ContentPrefs.cpp
+++ b/dom/ipc/ContentPrefs.cpp
@@ -116,16 +116,20 @@ const char* mozilla::dom::ContentPrefs::
"javascript.options.throw_on_asmjs_validation_failure",
"javascript.options.throw_on_debuggee_would_run",
"javascript.options.wasm",
"javascript.options.wasm_baselinejit",
"javascript.options.wasm_ionjit",
"javascript.options.werror",
"javascript.use_us_english_locale",
"jsloader.shareGlobal",
+#ifdef MOZ_STYLO
+ "layout.css.stylo-blocklist.blocked_domains",
+ "layout.css.stylo-blocklist.enabled",
+#endif
"layout.idle_period.required_quiescent_frames",
"layout.idle_period.time_limit",
"layout.interruptible-reflow.enabled",
"mathml.disabled",
"media.apple.forcevda",
"media.clearkey.persistent-license.enabled",
"media.cubeb.backend",
"media.cubeb.sandbox",
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -122,16 +122,17 @@
#include "mozilla/StyleSetHandleInlines.h"
#include "RegionBuilder.h"
#include "SVGSVGElement.h"
#include "DisplayItemClip.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#include "prenv.h"
#include "TextDrawTarget.h"
#include "nsDeckFrame.h"
+#include "nsIEffectiveTLDService.h" // for IsInStyloBlocklist
#ifdef MOZ_XUL
#include "nsXULPopupManager.h"
#endif
#include "GeckoProfiler.h"
#include "nsAnimationManager.h"
#include "nsTransitionManager.h"
@@ -187,16 +188,18 @@ typedef nsStyleTransformMatrix::Transfor
/* static */ uint32_t nsLayoutUtils::sZoomMaxPercent;
/* static */ uint32_t nsLayoutUtils::sZoomMinPercent;
/* static */ bool nsLayoutUtils::sInvalidationDebuggingIsEnabled;
/* static */ bool nsLayoutUtils::sInterruptibleReflowEnabled;
/* static */ bool nsLayoutUtils::sSVGTransformBoxEnabled;
/* static */ bool nsLayoutUtils::sTextCombineUprightDigitsEnabled;
#ifdef MOZ_STYLO
/* static */ bool nsLayoutUtils::sStyloEnabled;
+/* static */ bool nsLayoutUtils::sStyloBlocklistEnabled;
+/* static */ nsTArray<nsCString>* nsLayoutUtils::sStyloBlocklist = nullptr;
#endif
/* static */ uint32_t nsLayoutUtils::sIdlePeriodDeadlineLimit;
/* static */ uint32_t nsLayoutUtils::sQuiescentFramesBeforeIdlePeriod;
static ViewID sScrollIdCounter = FrameMetrics::START_SCROLL_ID;
typedef nsDataHashtable<nsUint64HashKey, nsIContent*> ContentMap;
static ContentMap* sContentMap = nullptr;
@@ -7966,16 +7969,34 @@ nsLayoutUtils::Initialize()
if (PR_GetEnv("STYLO_FORCE_ENABLED")) {
sStyloEnabled = true;
} else if (PR_GetEnv("STYLO_FORCE_DISABLED")) {
sStyloEnabled = false;
} else {
Preferences::AddBoolVarCache(&sStyloEnabled,
"layout.css.servo.enabled");
}
+ // We should only create the blocklist ONCE, and ignore any blocklist
+ // reloads happen. Because otherwise we could have a top level page that
+ // uses Stylo (if its load happens before the blocklist reload) and a
+ // child iframe that uses Gecko (if its load happens after the blocklist
+ // reload). If some page contains both backends, and they try to move
+ // element across backend boundary, it could crash (see bug 1404020).
+ sStyloBlocklistEnabled =
+ Preferences::GetBool("layout.css.stylo-blocklist.enabled");
+ if (sStyloBlocklistEnabled && !sStyloBlocklist) {
+ nsAutoCString blocklist;
+ Preferences::GetCString("layout.css.stylo-blocklist.blocked_domains", blocklist);
+ if (!blocklist.IsEmpty()) {
+ sStyloBlocklist = new nsTArray<nsCString>;
+ for (const nsACString& domainString : blocklist.Split(',')) {
+ sStyloBlocklist->AppendElement(domainString);
+ }
+ }
+ }
#endif
Preferences::AddUintVarCache(&sIdlePeriodDeadlineLimit,
"layout.idle_period.time_limit",
DEFAULT_IDLE_PERIOD_TIME_LIMIT);
Preferences::AddUintVarCache(&sQuiescentFramesBeforeIdlePeriod,
"layout.idle_period.required_quiescent_frames",
DEFAULT_QUIESCENT_FRAMES);
@@ -7988,26 +8009,65 @@ nsLayoutUtils::Initialize()
/* static */
void
nsLayoutUtils::Shutdown()
{
if (sContentMap) {
delete sContentMap;
sContentMap = nullptr;
}
-
+#ifdef MOZ_STYLO
+ if (sStyloBlocklist) {
+ sStyloBlocklist->Clear();
+ delete sStyloBlocklist;
+ sStyloBlocklist = nullptr;
+ }
+#endif
for (auto& callback : kPrefCallbacks) {
Preferences::UnregisterCallback(callback.func, callback.name);
}
nsComputedDOMStyle::UnregisterPrefChangeCallbacks();
// so the cached initial quotes array doesn't appear to be a leak
nsStyleList::Shutdown();
}
+#ifdef MOZ_STYLO
+/* static */
+bool
+nsLayoutUtils::IsInStyloBlocklist(nsIPrincipal* aPrincipal)
+{
+ if (!sStyloBlocklist) {
+ return false;
+ }
+
+ // Note that a non-codebase principal (eg the system principal) will return
+ // a null URI.
+ nsCOMPtr<nsIURI> codebaseURI;
+ aPrincipal->GetURI(getter_AddRefs(codebaseURI));
+ if (!codebaseURI) {
+ return false;
+ }
+
+ nsCOMPtr<nsIEffectiveTLDService> tldService =
+ do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
+ NS_ENSURE_TRUE(tldService, false);
+
+ // Check if a document's eTLD+1 domain belongs to one of the stylo blocklist.
+ nsAutoCString baseDomain;
+ NS_SUCCEEDED(tldService->GetBaseDomain(codebaseURI, 0, baseDomain));
+ for (const nsCString& domains : *sStyloBlocklist) {
+ if (baseDomain.Equals(domains)) {
+ return true;
+ }
+ }
+ return false;
+}
+#endif
+
/* static */
void
nsLayoutUtils::RegisterImageRequest(nsPresContext* aPresContext,
imgIRequest* aRequest,
bool* aRequestRegistered)
{
if (!aPresContext) {
return;
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -2553,16 +2553,27 @@ public:
*/
static bool InvalidationDebuggingIsEnabled() {
return sInvalidationDebuggingIsEnabled || getenv("MOZ_DUMP_INVALIDATION") != 0;
}
static void Initialize();
static void Shutdown();
+#ifdef MOZ_STYLO
+ /**
+ * Principal-based blocklist for stylo.
+ * Check if aPrincipal is blocked by stylo's blocklist and should fallback to
+ * use Gecko's style backend. Note that using a document's principal rather
+ * than the document URI will let us piggy-back off the existing principal
+ * relationships and symmetries.
+ */
+ static bool IsInStyloBlocklist(nsIPrincipal* aPrincipal);
+#endif
+
/**
* Register an imgIRequest object with a refresh driver.
*
* @param aPresContext The nsPresContext whose refresh driver we want to
* register with.
* @param aRequest A pointer to the imgIRequest object which the client wants
* to register with the refresh driver.
* @param aRequestRegistered A pointer to a boolean value which indicates
@@ -3020,16 +3031,18 @@ private:
static uint32_t sZoomMaxPercent;
static uint32_t sZoomMinPercent;
static bool sInvalidationDebuggingIsEnabled;
static bool sInterruptibleReflowEnabled;
static bool sSVGTransformBoxEnabled;
static bool sTextCombineUprightDigitsEnabled;
#ifdef MOZ_STYLO
static bool sStyloEnabled;
+ static bool sStyloBlocklistEnabled;
+ static nsTArray<nsCString>* sStyloBlocklist;
#endif
static uint32_t sIdlePeriodDeadlineLimit;
static uint32_t sQuiescentFramesBeforeIdlePeriod;
/**
* Helper function for LogTestDataForPaint().
*/
static void DoLogTestDataForPaint(mozilla::layers::LayerManager* aManager,
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5791,16 +5791,18 @@ pref("dom.webkitBlink.dirPicker.enabled"
pref("dom.webkitBlink.filesystem.enabled", true);
#endif
pref("media.block-autoplay-until-in-foreground", true);
// Is Stylo CSS support built and enabled?
// Only define this pref if Stylo support is actually built in.
#ifdef MOZ_STYLO
+pref("layout.css.stylo-blocklist.enabled", true);
+pref("layout.css.stylo-blocklist.blocked_domains", "");
#ifdef MOZ_STYLO_ENABLE
pref("layout.css.servo.enabled", true);
#else
pref("layout.css.servo.enabled", false);
#endif
#endif
// HSTS Priming