Backed out 4 changesets (bug 1447611) for mass failures due to --enable-stylo removal. CLOSED TREE
authorCsoregi Natalia <ncsoregi@mozilla.com>
Wed, 21 Mar 2018 19:01:07 +0200
changeset 462851 1fadea75f3630176098917eb3e085c57a42a793f
parent 462850 c6193142bbcf6dbd7e7562243282f543310a0ea1
child 462852 57d72a8be27406668002e233fae25fc36a58514d
push id9165
push userasasaki@mozilla.com
push dateThu, 26 Apr 2018 21:04:54 +0000
treeherdermozilla-beta@064c3804de2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1447611
milestone61.0a1
backs outc6193142bbcf6dbd7e7562243282f543310a0ea1
01ada1c5a95f3673687f98154c4b05350780bc43
86c9fed44da23014876fdd6ec915f596d3b3ac23
bb84ac6e14689d1308dced13bab1b71f3f042713
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 4 changesets (bug 1447611) for mass failures due to --enable-stylo removal. CLOSED TREE Backed out changeset c6193142bbcf (bug 1447611) Backed out changeset 01ada1c5a95f (bug 1447611) Backed out changeset 86c9fed44da2 (bug 1447611) Backed out changeset bb84ac6e1468 (bug 1447611)
dom/base/nsDocument.cpp
dom/base/nsIDocument.h
dom/xul/nsXULElement.cpp
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/base/nsStyleSheetService.cpp
layout/style/PreloadedStyleSheet.cpp
layout/style/ServoBindings.toml
layout/tools/reftest/manifest.jsm
layout/xul/crashtests/crashtests.list
modules/libpref/init/all.js
python/mozbuild/mozbuild/mozinfo.py
testing/awsy/mach_commands.py
testing/mozharness/scripts/desktop_unittest.py
testing/mozharness/scripts/web_platform_tests.py
toolkit/components/telemetry/TelemetryEnvironment.jsm
toolkit/library/rust/gkrust-features.mozbuild
toolkit/modules/AppConstants.jsm
toolkit/modules/Troubleshoot.jsm
toolkit/modules/tests/browser/browser_Troubleshoot.js
toolkit/moz.configure
toolkit/mozapps/installer/packager.mk
toolkit/mozapps/installer/upload-files.mk
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1495,16 +1495,17 @@ nsIDocument::nsIDocument()
     mWillReparent(false),
 #endif
     mPendingFullscreenRequests(0),
     mXMLDeclarationBits(0),
     mOnloadBlockCount(0),
     mAsyncOnloadBlockCount(0),
     mCompatMode(eCompatibility_FullStandards),
     mReadyState(ReadyState::READYSTATE_UNINITIALIZED),
+    mStyleBackendType(StyleBackendType::None),
 #ifdef MOZILLA_INTERNAL_API
     mVisibilityState(dom::VisibilityState::Hidden),
 #else
     mDummy(0),
 #endif
     mType(eUnknown),
     mDefaultElementType(0),
     mAllowXULXBL(eTriUnset),
@@ -2150,19 +2151,23 @@ nsDocument::Init()
   // mNodeInfo keeps NodeInfoManager alive!
   mNodeInfo = mNodeInfoManager->GetDocumentNodeInfo();
   NS_ENSURE_TRUE(mNodeInfo, NS_ERROR_OUT_OF_MEMORY);
   MOZ_ASSERT(mNodeInfo->NodeType() == DOCUMENT_NODE,
              "Bad NodeType in aNodeInfo");
 
   NS_ASSERTION(OwnerDoc() == this, "Our nodeinfo is busted!");
 
+  UpdateStyleBackendType();
+
   // Set this when document is initialized and value stays the same for the
   // lifetime of the document.
-  mIsShadowDOMEnabled = nsContentUtils::IsShadowDOMEnabled();
+  mIsShadowDOMEnabled =
+    mStyleBackendType == StyleBackendType::Servo &&
+    nsContentUtils::IsShadowDOMEnabled();
 
   // If after creation the owner js global is not set for a document
   // we use the default compartment for this document, instead of creating
   // wrapper in some random compartment when the document is exposed to js
   // via some events.
   nsCOMPtr<nsIGlobalObject> global = xpc::NativeGlobal(xpc::PrivilegedJunkScope());
   NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
   mScopeObject = do_GetWeakReference(global);
@@ -8894,16 +8899,17 @@ nsDocument::CloneDocHelper(nsDocument* c
   // State from nsIDocument
   clone->mCharacterSet = mCharacterSet;
   clone->mCharacterSetSource = mCharacterSetSource;
   clone->mCompatMode = mCompatMode;
   clone->mBidiOptions = mBidiOptions;
   clone->mContentLanguage = mContentLanguage;
   clone->SetContentTypeInternal(GetContentTypeInternal());
   clone->mSecurityInfo = mSecurityInfo;
+  clone->mStyleBackendType = mStyleBackendType;
 
   // State from nsDocument
   clone->mType = mType;
   clone->mXMLDeclarationBits = mXMLDeclarationBits;
   clone->mBaseTarget = mBaseTarget;
 
   // Preallocate attributes and child arrays
   rv = clone->mChildren.EnsureCapacityToClone(mChildren, aPreallocateChildren);
@@ -12598,16 +12604,31 @@ nsIDocument::ReportHasScrollLinkedEffect
   mHasScrollLinkedEffect = true;
   nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                   NS_LITERAL_CSTRING("Async Pan/Zoom"),
                                   this, nsContentUtils::eLAYOUT_PROPERTIES,
                                   "ScrollLinkedEffectFound2");
 }
 
 void
+nsIDocument::UpdateStyleBackendType()
+{
+  MOZ_ASSERT(mStyleBackendType == StyleBackendType::None,
+             "no need to call UpdateStyleBackendType now");
+
+  // Assume Gecko by default.
+  mStyleBackendType = StyleBackendType::Gecko;
+
+  if (nsLayoutUtils::StyloEnabled() &&
+      nsLayoutUtils::ShouldUseStylo(NodePrincipal())) {
+    mStyleBackendType = StyleBackendType::Servo;
+  }
+}
+
+void
 nsIDocument::SetUserHasInteracted(bool aUserHasInteracted)
 {
   MOZ_LOG(gUserInteractionPRLog, LogLevel::Debug,
           ("Document %p has been interacted by user.", this));
   mUserHasInteracted = aUserHasInteracted;
 }
 
 void
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -1732,23 +1732,34 @@ public:
 
   /**
    * Get this document's CSSLoader.  This is guaranteed to not return null.
    */
   mozilla::css::Loader* CSSLoader() const {
     return mCSSLoader;
   }
 
-  mozilla::StyleBackendType GetStyleBackendType() const
-  {
-    return mozilla::StyleBackendType::Servo;
-  }
-
-  bool IsStyledByServo() const
-  {
+  mozilla::StyleBackendType GetStyleBackendType() const {
+    MOZ_ASSERT(mStyleBackendType != mozilla::StyleBackendType::None,
+               "Not initialized yet");
+    return mStyleBackendType;
+  }
+
+  /**
+   * Documents generally decide their style backend type themselves, and
+   * this is only used for XBL documents to set their style backend type to
+   * their bounding document's.
+   */
+
+  /**
+   * Decide this document's own style backend type.
+   */
+  void UpdateStyleBackendType();
+
+  bool IsStyledByServo() const {
     return GetStyleBackendType() == mozilla::StyleBackendType::Servo;
   }
 
   /**
    * Get this document's StyleImageLoader.  This is guaranteed to not return null.
    */
   mozilla::css::ImageLoader* StyleImageLoader() const {
     return mStyleImageLoader;
@@ -4209,16 +4220,20 @@ protected:
   uint32_t mAsyncOnloadBlockCount;
 
   // Compatibility mode
   nsCompatibility mCompatMode;
 
   // Our readyState
   ReadyState mReadyState;
 
+  // Whether this document has (or will have, once we have a pres shell) a
+  // Gecko- or Servo-backed style system.
+  mozilla::StyleBackendType mStyleBackendType;
+
 #ifdef MOZILLA_INTERNAL_API
   // Our visibility state
   mozilla::dom::VisibilityState mVisibilityState;
   static_assert(sizeof(mozilla::dom::VisibilityState) == sizeof(uint8_t),
                 "Error size of mVisibilityState and mDummy");
 #else
   uint8_t mDummy;
 #endif
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -2363,21 +2363,27 @@ nsXULPrototypeElement::SetAttrAt(uint32_
 
         // This is basically duplicating what nsINode::NodePrincipal() does
         nsIPrincipal* principal =
           mNodeInfo->NodeInfoManager()->DocumentPrincipal();
         // XXX Get correct Base URI (need GetBaseURI on *prototype* element)
         // TODO: If we implement Content Security Policy for chrome documents
         // as has been discussed, the CSP should be checked here to see if
         // inline styles are allowed to be applied.
-        RefPtr<URLExtraData> data =
-          new URLExtraData(aDocumentURI, aDocumentURI, principal);
-        RefPtr<DeclarationBlock> declaration =
-          ServoDeclarationBlock::FromCssText(
-            aValue, data, eCompatibility_FullStandards, nullptr);
+
+        RefPtr<DeclarationBlock> declaration;
+        if (nsLayoutUtils::StyloEnabled() &&
+            nsLayoutUtils::ShouldUseStylo(principal)) {
+          RefPtr<URLExtraData> data =
+            new URLExtraData(aDocumentURI, aDocumentURI, principal);
+          declaration = ServoDeclarationBlock::FromCssText(
+              aValue, data, eCompatibility_FullStandards, nullptr);
+        } else {
+          MOZ_CRASH("old style system disabled");
+        }
         if (declaration) {
             mAttributes[aPos].mValue.SetTo(declaration.forget(), &aValue);
 
             return NS_OK;
         }
         // Don't abort if parsing failed, it could just be malformed css.
     }
 
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -191,16 +191,17 @@ typedef nsStyleTransformMatrix::Transfor
 /* static */ bool nsLayoutUtils::sFontSizeInflationDisabledInMasterProcess;
 /* static */ uint32_t nsLayoutUtils::sSystemFontScale;
 /* 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;
+/* static */ bool nsLayoutUtils::sStyloEnabled;
 /* 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;
 static ContentMap& GetContentMap() {
@@ -8274,16 +8275,18 @@ nsLayoutUtils::Initialize()
   Preferences::AddBoolVarCache(&sInvalidationDebuggingIsEnabled,
                                "nglayout.debug.invalidation");
   Preferences::AddBoolVarCache(&sInterruptibleReflowEnabled,
                                "layout.interruptible-reflow.enabled");
   Preferences::AddBoolVarCache(&sSVGTransformBoxEnabled,
                                "svg.transform-box.enabled");
   Preferences::AddBoolVarCache(&sTextCombineUprightDigitsEnabled,
                                "layout.css.text-combine-upright-digits.enabled");
+  sStyloEnabled = true;
+
   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);
 
   for (auto& callback : kPrefCallbacks) {
@@ -8306,16 +8309,30 @@ nsLayoutUtils::Shutdown()
   }
   nsComputedDOMStyle::UnregisterPrefChangeCallbacks();
 
   // so the cached initial quotes array doesn't appear to be a leak
   nsStyleList::Shutdown();
 }
 
 /* static */
+bool
+nsLayoutUtils::ShouldUseStylo(nsIPrincipal* aPrincipal)
+{
+  return true;
+}
+
+/* static */
+bool
+nsLayoutUtils::StyloChromeEnabled()
+{
+  return true;
+}
+
+/* static */
 void
 nsLayoutUtils::RegisterImageRequest(nsPresContext* aPresContext,
                                     imgIRequest* aRequest,
                                     bool* aRequestRegistered)
 {
   if (!aPresContext) {
     return;
   }
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -2516,16 +2516,46 @@ public:
   static bool SVGTransformBoxEnabled() {
     return sSVGTransformBoxEnabled;
   }
 
   static bool TextCombineUprightDigitsEnabled() {
     return sTextCombineUprightDigitsEnabled;
   }
 
+  // Stylo (the Servo backend for Gecko's style system) is generally enabled
+  // or disabled at compile-time. However, we provide the additional capability
+  // to disable it dynamically in stylo-enabled builds via a pref.
+  static bool StyloEnabled() {
+    return true;
+  }
+
+  // Whether Stylo should be allowed to be enabled in this process.
+  static bool StyloSupportedInCurrentProcess() {
+    if (XRE_IsContentProcess()) {
+      return true;
+    }
+    if (XRE_IsParentProcess()) {
+      // If Stylo is enabled for chrome document, we use it in all
+      // parent processes, regardless of whether it's e10s parent.
+      if (StyloChromeEnabled()) {
+        return true;
+      }
+      // Otherwise we only use stylo on non-e10s parent.
+      return !XRE_IsE10sParentProcess();
+    }
+    // Stylo is not enabled for any other process.
+    MOZ_DIAGNOSTIC_ASSERT(false, "We should not be creating any document "
+                          "in processes other than content and parent");
+    return false;
+  }
+
+  // Whether Stylo should be used on chrome documents.
+  static bool StyloChromeEnabled();
+
   static uint32_t IdlePeriodDeadlineLimit() {
     return sIdlePeriodDeadlineLimit;
   }
 
   static uint32_t QuiescentFramesBeforeIdlePeriod() {
     return sQuiescentFramesBeforeIdlePeriod;
   }
 
@@ -2545,16 +2575,21 @@ public:
   static bool InvalidationDebuggingIsEnabled() {
     return sInvalidationDebuggingIsEnabled || getenv("MOZ_DUMP_INVALIDATION") != 0;
   }
 
   static void Initialize();
   static void Shutdown();
 
   /**
+   * Return whether stylo should be used for a given document principal.
+   */
+  static bool ShouldUseStylo(nsIPrincipal* aPrincipal);
+
+  /**
    * 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
    *        whether the given image request is registered. If
@@ -3061,16 +3096,17 @@ private:
   static bool sFontSizeInflationDisabledInMasterProcess;
   static uint32_t sSystemFontScale;
   static uint32_t sZoomMaxPercent;
   static uint32_t sZoomMinPercent;
   static bool sInvalidationDebuggingIsEnabled;
   static bool sInterruptibleReflowEnabled;
   static bool sSVGTransformBoxEnabled;
   static bool sTextCombineUprightDigitsEnabled;
+  static bool sStyloEnabled;
   static uint32_t sIdlePeriodDeadlineLimit;
   static uint32_t sQuiescentFramesBeforeIdlePeriod;
 
   /**
    * Helper function for LogTestDataForPaint().
    */
   static void DoLogTestDataForPaint(mozilla::layers::LayerManager* aManager,
                                     ViewID aScrollId,
--- a/layout/base/nsStyleSheetService.cpp
+++ b/layout/base/nsStyleSheetService.cpp
@@ -165,21 +165,34 @@ nsStyleSheetService::LoadAndRegisterShee
         u"URI contains unescaped hash character, which might be truncating "
         u"the sheet, if it's a data URI.";
       consoleService->LogStringMessage(message);
     }
   }
 
   rv = LoadAndRegisterSheetInternal(aSheetURI, aSheetType);
   if (NS_SUCCEEDED(rv)) {
+    // Success means that at least the Gecko sheet was loaded. It's possible
+    // that a Servo sheet was also loaded. In both cases, the new sheets are
+    // the last sheets in m{Gecko,Servo}Sheets[aSheetType]
+    bool servoSheetWasAdded = false;
+    servoSheetWasAdded = nsLayoutUtils::StyloSupportedInCurrentProcess();
+
     // Hold on to a copy of the registered PresShells.
     nsTArray<nsCOMPtr<nsIPresShell>> toNotify(mPresShells);
     for (nsIPresShell* presShell : toNotify) {
-      StyleSheet* sheet = Sheets(StyleBackendType::Servo)[aSheetType].LastElement();
-      presShell->NotifyStyleSheetServiceSheetAdded(sheet, aSheetType);
+      if (presShell->StyleSet()) {
+        StyleBackendType backendType = presShell->StyleSet()->BackendType();
+        if (backendType == StyleBackendType::Gecko || servoSheetWasAdded) {
+          StyleSheet* sheet = Sheets(backendType)[aSheetType].LastElement();
+          presShell->NotifyStyleSheetServiceSheetAdded(sheet, aSheetType);
+        } else {
+          MOZ_ASSERT_UNREACHABLE("Servo pres shell, but stylo unsupported?");
+        }
+      }
     }
 
     if (XRE_IsParentProcess()) {
       nsTArray<dom::ContentParent*> children;
       dom::ContentParent::GetAll(children);
 
       if (children.IsEmpty()) {
         return rv;
@@ -227,21 +240,24 @@ nsStyleSheetService::LoadAndRegisterShee
       break;
 
     default:
       NS_WARNING("invalid sheet type argument");
       return NS_ERROR_INVALID_ARG;
   }
 
 
-  RefPtr<StyleSheet> servoSheet;
-  nsresult rv = LoadSheet(aSheetURI, parsingMode, StyleBackendType::Servo, &servoSheet);
-  NS_ENSURE_SUCCESS(rv, rv);
-  MOZ_ASSERT(servoSheet);
-  mServoSheets[aSheetType].AppendElement(servoSheet);
+
+  if (nsLayoutUtils::StyloSupportedInCurrentProcess()) {
+    RefPtr<StyleSheet> servoSheet;
+    nsresult rv = LoadSheet(aSheetURI, parsingMode, StyleBackendType::Servo, &servoSheet);
+    NS_ENSURE_SUCCESS(rv, rv);
+    MOZ_ASSERT(servoSheet);
+    mServoSheets[aSheetType].AppendElement(servoSheet);
+  }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStyleSheetService::SheetRegistered(nsIURI *sheetURI,
                                      uint32_t aSheetType, bool *_retval)
 {
--- a/layout/style/PreloadedStyleSheet.cpp
+++ b/layout/style/PreloadedStyleSheet.cpp
@@ -80,20 +80,23 @@ PreloadedStyleSheet::Preload()
   // and preload a sheet of that type.
   //
   // If we guess wrong, we will re-load the sheet later with the requested type,
   // and we won't really have front loaded the loading time as the name
   // "preload" might suggest.  Also, in theory we could get different data from
   // fetching the URL again, but for the usage patterns of this API this is
   // unlikely, and it doesn't seem worth trying to store the contents of the URL
   // and duplicating a bunch of css::Loader's logic.
+  auto type = nsLayoutUtils::StyloEnabled() ? StyleBackendType::Servo
+                                            : StyleBackendType::Gecko;
+
   mLoaded = true;
 
   StyleSheet* sheet;
-  return GetSheet(StyleBackendType::Servo, &sheet);
+  return GetSheet(type, &sheet);
 }
 
 NS_IMPL_ISUPPORTS(PreloadedStyleSheet::StylesheetPreloadObserver,
                   nsICSSLoaderObserver)
 
 NS_IMETHODIMP
 PreloadedStyleSheet::StylesheetPreloadObserver::StyleSheetLoaded(
   StyleSheet* aSheet, bool aWasAlternate, nsresult aStatus)
@@ -112,20 +115,27 @@ PreloadedStyleSheet::StylesheetPreloadOb
 
 // Note: After calling this method, the preloaded sheet *must not* be used
 // until the observer is notified that the sheet has finished loading.
 nsresult
 PreloadedStyleSheet::PreloadAsync(NotNull<dom::Promise*> aPromise)
 {
   MOZ_DIAGNOSTIC_ASSERT(!mLoaded);
 
-  RefPtr<StyleSheet>& sheet = mServo;
+  // As with the Preload() method, we can't be sure that the sheet will only be
+  // used with the backend that we're preloading it for now. If it's used with
+  // a different backend later, it will be synchronously loaded for that
+  // backend the first time it's used.
+  auto type = nsLayoutUtils::StyloEnabled() ? StyleBackendType::Servo
+                                            : StyleBackendType::Gecko;
 
-  RefPtr<css::Loader> loader =
-    new css::Loader(StyleBackendType::Servo, nullptr);
+  RefPtr<StyleSheet>& sheet =
+    type == StyleBackendType::Gecko ? mGecko : mServo;
+
+  RefPtr<css::Loader> loader = new css::Loader(type, nullptr);
 
   RefPtr<StylesheetPreloadObserver> obs =
     new StylesheetPreloadObserver(aPromise, this);
 
   return loader->LoadSheet(mURI, mParsingMode, false, obs, &sheet);
 }
 
 } // namespace mozilla
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -1,13 +1,13 @@
 [build]
 args = [
     "-x", "c++", "-std=c++14", "-fno-sized-deallocation",
     "-DTRACING=1", "-DIMPL_LIBXUL", "-DMOZ_STYLO_BINDINGS=1",
-    "-DMOZILLA_INTERNAL_API", "-DRUST_BINDGEN"
+    "-DMOZILLA_INTERNAL_API", "-DRUST_BINDGEN", "-DMOZ_STYLO"
 ]
 "family=unix" = ["-DOS_POSIX=1"]
 "os=solaris" = ["-DOS_SOLARIS=1"]
 "os=dragonfly" = ["-DOS_BSD=1", "-DOS_DRAGONFLY=1"]
 "os=freebsd" = ["-DOS_BSD=1", "-DOS_FREEBSD=1"]
 "os=netbsd" = ["-DOS_BSD=1", "-DOS_NETBSD=1"]
 "os=openbsd" = ["-DOS_BSD=1", "-DOS_OPENBSD=1"]
 "os=macos" = [
--- a/layout/tools/reftest/manifest.jsm
+++ b/layout/tools/reftest/manifest.jsm
@@ -477,18 +477,31 @@ function BuildConditionSandbox(aURL) {
 #else
     sandbox.webrtc = false;
 #endif
 
 let retainedDisplayListsEnabled = prefs.getBoolPref("layout.display-list.retain", false);
 sandbox.retainedDisplayLists = retainedDisplayListsEnabled && !g.compareRetainedDisplayLists;
 sandbox.compareRetainedDisplayLists = g.compareRetainedDisplayLists;
 
-// TODO(emilio): Remove the remaining reftest expectations that mention stylo.
-sandbox.stylo = true;
+#ifdef MOZ_STYLO
+    let styloEnabled = false;
+    // Perhaps a bit redundant in places, but this is easier to compare with the
+    // the real check in `nsLayoutUtils.cpp` to ensure they test the same way.
+    if (env.get("STYLO_FORCE_ENABLED")) {
+        styloEnabled = true;
+    } else if (env.get("STYLO_FORCE_DISABLED")) {
+        styloEnabled = false;
+    } else {
+        styloEnabled = prefs.getBoolPref("layout.css.servo.enabled", false);
+    }
+    sandbox.stylo = styloEnabled;
+#else
+    sandbox.stylo = false;
+#endif
 
     sandbox.skiaPdf = false;
 
 #ifdef RELEASE_OR_BETA
     sandbox.release_or_beta = true;
 #else
     sandbox.release_or_beta = false;
 #endif
--- a/layout/xul/crashtests/crashtests.list
+++ b/layout/xul/crashtests/crashtests.list
@@ -92,10 +92,16 @@ load 514300-1.xul
 load 536931-1.xhtml
 load 538308-1.xul
 load 557174-1.xml
 load 564705-1.xul
 load 583957-1.html
 load 617089.html
 load menulist-focused.xhtml
 load 716503.html
-load 1379332-1.xul
-load 1379332-2.xul
+
+# Bug 1379332's tests need stylo to be disabled in order for the
+# 'visiblity:collapse' to take effect (which is needed to trigger the assertion
+# that these tests are screening for, in unpatched builds). (Also, we skip
+# these tests on Android, because otherwise we trigger bug 1350948 when trying
+# to force the servo pref to false on that platform.)
+skip-if(Android) pref(layout.css.servo.enabled,false) load 1379332-1.xul
+skip-if(Android) pref(layout.css.servo.enabled,false) load 1379332-2.xul
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5913,16 +5913,31 @@ pref("osfile.reset_worker_delay", 30000)
 
 #if !defined(MOZ_WIDGET_ANDROID)
 pref("dom.webkitBlink.dirPicker.enabled", true);
 pref("dom.webkitBlink.filesystem.enabled", true);
 #endif
 
 pref("media.block-autoplay-until-in-foreground", true);
 
+// Is Stylo CSS support built and enabled?
+// Only define these prefs if Stylo support is actually built in.
+#ifdef MOZ_STYLO
+#ifdef MOZ_STYLO_ENABLE
+pref("layout.css.servo.enabled", true);
+#else
+pref("layout.css.servo.enabled", false);
+#endif
+// Whether Stylo is enabled for chrome document?
+// If Stylo is not enabled, this pref doesn't take any effect.
+// Note that this pref is only read once when requested. Changing it
+// at runtime may have no effect.
+pref("layout.css.servo.chrome.enabled", true);
+#endif
+
 // TODO: Bug 1324406: Treat 'data:' documents as unique, opaque origins
 // If true, data: URIs will be treated as unique opaque origins, hence will use
 // a NullPrincipal as the security context.
 // Otherwise it will inherit the origin from parent node, this is the legacy
 // behavior of Firefox.
 pref("security.data_uri.unique_opaque_origin", true);
 
 // If true, all toplevel data: URI navigations will be blocked.
--- a/python/mozbuild/mozbuild/mozinfo.py
+++ b/python/mozbuild/mozbuild/mozinfo.py
@@ -78,18 +78,17 @@ def build_dict(config, env=os.environ):
     d['nightly_build'] = substs.get('NIGHTLY_BUILD') == '1'
     d['release_or_beta'] = substs.get('RELEASE_OR_BETA') == '1'
     d['devedition'] = substs.get('MOZ_DEV_EDITION') == '1'
     d['pgo'] = substs.get('MOZ_PGO') == '1'
     d['crashreporter'] = bool(substs.get('MOZ_CRASHREPORTER'))
     d['datareporting'] = bool(substs.get('MOZ_DATA_REPORTING'))
     d['healthreport'] = substs.get('MOZ_SERVICES_HEALTHREPORT') == '1'
     d['sync'] = substs.get('MOZ_SERVICES_SYNC') == '1'
-    # FIXME(emilio): We need to update a lot of WPT expectations before removing this.
-    d['stylo'] = True
+    d['stylo'] = substs.get('MOZ_STYLO_ENABLE') == '1'
     d['asan'] = substs.get('MOZ_ASAN') == '1'
     d['tsan'] = substs.get('MOZ_TSAN') == '1'
     d['ubsan'] = substs.get('MOZ_UBSAN') == '1'
     d['telemetry'] = substs.get('MOZ_TELEMETRY_REPORTING') == '1'
     d['tests_enabled'] = substs.get('ENABLE_TESTS') == "1"
     d['bin_suffix'] = substs.get('BIN_SUFFIX', '')
     d['addon_signing'] = substs.get('MOZ_ADDON_SIGNING') == '1'
     d['require_signing'] = substs.get('MOZ_REQUIRE_SIGNING') == '1'
--- a/testing/awsy/mach_commands.py
+++ b/testing/awsy/mach_commands.py
@@ -64,16 +64,19 @@ class MachCommands(MachCommandBase):
             kwargs['perTabPause'] = 1
             kwargs['settleWaitTime'] = 1
 
         if 'single_stylo_traversal' in kwargs and kwargs['single_stylo_traversal']:
             os.environ['STYLO_THREADS'] = '1'
         else:
             os.environ['STYLO_THREADS'] = '4'
 
+        if 'enable_stylo' in kwargs and kwargs['enable_stylo']:
+            os.environ['STYLO_FORCE_ENABLED'] = '1'
+
         if 'enable_webrender' in kwargs and kwargs['enable_webrender']:
             os.environ['MOZ_WEBRENDER'] = '1'
             os.environ['MOZ_ACCELERATED'] = '1'
 
         runtime_testvars = {}
         for arg in ('webRootDir', 'pageManifest', 'resultsDir', 'entities', 'iterations',
                     'perTabPause', 'settleWaitTime', 'maxTabs', 'dmd'):
             if kwargs[arg]:
@@ -197,16 +200,19 @@ class MachCommands(MachCommandBase):
     @CommandArgument('--per-tab-pause', group='AWSY', action='store', type=int,
                      dest='perTabPause',
                      help='Seconds to wait in between opening tabs. '
                      'Defaults to %s.' % PER_TAB_PAUSE)
     @CommandArgument('--settle-wait-time', group='AWSY', action='store', type=int,
                      dest='settleWaitTime',
                      help='Seconds to wait for things to settled down. '
                      'Defaults to %s.' % SETTLE_WAIT_TIME)
+    @CommandArgument('--enable-stylo', group='AWSY', action='store_true',
+                     dest='enable_stylo', default=False,
+                     help='Enable Stylo.')
     @CommandArgument('--single-stylo-traversal', group='AWSY', action='store_true',
                      dest='single_stylo_traversal', default=False,
                      help='Set STYLO_THREADS=1.')
     @CommandArgument('--enable-webrender', group='AWSY', action='store_true',
                      dest='enable_webrender', default=False,
                      help='Enable WebRender.')
     @CommandArgument('--dmd', group='AWSY', action='store_true',
                      dest='dmd', default=False,
--- a/testing/mozharness/scripts/desktop_unittest.py
+++ b/testing/mozharness/scripts/desktop_unittest.py
@@ -158,16 +158,22 @@ class DesktopUnittest(TestingMixin, Merc
                     "the GL compositor."}
          ],
         [["--single-stylo-traversal"], {
             "action": "store_true",
             "dest": "single_stylo_traversal",
             "default": False,
             "help": "Forcibly enable single thread traversal in Stylo with STYLO_THREADS=1"}
          ],
+        [["--enable-stylo"], {
+            "action": "store_true",
+            "dest": "enable_stylo",
+            "default": False,
+            "help": "Run tests with Stylo enabled"}
+         ],
         [["--enable-webrender"], {
             "action": "store_true",
             "dest": "enable_webrender",
             "default": False,
             "help": "Tries to enable the WebRender compositor."}
          ],
     ] + copy.deepcopy(testing_config_options) + \
         copy.deepcopy(blobupload_config_options) + \
--- a/testing/mozharness/scripts/web_platform_tests.py
+++ b/testing/mozharness/scripts/web_platform_tests.py
@@ -83,16 +83,28 @@ class WebPlatformTest(TestingMixin, Merc
             "help": "Specify headless fake screen height (default: 1200)."}
          ],
         [["--single-stylo-traversal"], {
             "action": "store_true",
             "dest": "single_stylo_traversal",
             "default": False,
             "help": "Forcibly enable single thread traversal in Stylo with STYLO_THREADS=1"}
          ],
+        [["--enable-stylo"], {
+            "action": "store_true",
+            "dest": "enable_stylo",
+            "default": False,
+            "help": "Run tests with Stylo enabled"}
+         ],
+        [["--disable-stylo"], {
+            "action": "store_true",
+            "dest": "disable_stylo",
+            "default": False,
+            "help": "Run tests with Stylo disabled"}
+         ],
     ] + copy.deepcopy(testing_config_options) + \
         copy.deepcopy(blobupload_config_options) + \
         copy.deepcopy(code_coverage_config_options)
 
     def __init__(self, require_config_file=True):
         super(WebPlatformTest, self).__init__(
             config_options=self.config_options,
             all_actions=[
@@ -305,21 +317,30 @@ class WebPlatformTest(TestingMixin, Merc
         if self.config['enable_webrender']:
             env['MOZ_WEBRENDER'] = '1'
             env['MOZ_ACCELERATED'] = '1'
         if self.config['headless']:
             env['MOZ_HEADLESS'] = '1'
             env['MOZ_HEADLESS_WIDTH'] = self.config['headless_width']
             env['MOZ_HEADLESS_HEIGHT'] = self.config['headless_height']
 
+        if self.config['disable_stylo']:
+            if self.config['single_stylo_traversal']:
+                self.fatal("--disable-stylo conflicts with --single-stylo-traversal")
+            if self.config['enable_stylo']:
+                self.fatal("--disable-stylo conflicts with --enable-stylo")
+
         if self.config['single_stylo_traversal']:
             env['STYLO_THREADS'] = '1'
         else:
             env['STYLO_THREADS'] = '4'
 
+        if self.config['enable_stylo']:
+            env['STYLO_FORCE_ENABLED'] = '1'
+
         env = self.query_env(partial_env=env, log_level=INFO)
 
         start_time = datetime.now()
         max_verify_time = timedelta(minutes=60)
         max_verify_tests = 10
         verified_tests = 0
 
         if self.config.get("verify") is True:
--- a/toolkit/components/telemetry/TelemetryEnvironment.jsm
+++ b/toolkit/components/telemetry/TelemetryEnvironment.jsm
@@ -240,16 +240,17 @@ const DEFAULT_ENVIRONMENT_PREFS = new Ma
   ["layers.async-video.enabled", {what: RECORD_PREF_VALUE}],
   ["layers.componentalpha.enabled", {what: RECORD_PREF_VALUE}],
   ["layers.d3d11.disable-warp", {what: RECORD_PREF_VALUE}],
   ["layers.d3d11.force-warp", {what: RECORD_PREF_VALUE}],
   ["layers.offmainthreadcomposition.force-disabled", {what: RECORD_PREF_VALUE}],
   ["layers.prefer-d3d9", {what: RECORD_PREF_VALUE}],
   ["layers.prefer-opengl", {what: RECORD_PREF_VALUE}],
   ["layout.css.devPixelsPerPx", {what: RECORD_PREF_VALUE}],
+  ["layout.css.servo.enabled", {what: RECORD_PREF_VALUE}],
   ["marionette.enabled", {what: RECORD_PREF_VALUE}],
   ["network.proxy.autoconfig_url", {what: RECORD_PREF_STATE}],
   ["network.proxy.http", {what: RECORD_PREF_STATE}],
   ["network.proxy.ssl", {what: RECORD_PREF_STATE}],
   ["pdfjs.disabled", {what: RECORD_PREF_VALUE}],
   ["places.history.enabled", {what: RECORD_PREF_VALUE}],
   ["plugins.remember_infobar_dismissal", {what: RECORD_PREF_VALUE}],
   ["plugins.show_infobar", {what: RECORD_PREF_VALUE}],
--- a/toolkit/library/rust/gkrust-features.mozbuild
+++ b/toolkit/library/rust/gkrust-features.mozbuild
@@ -1,18 +1,23 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # 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/.
 
-gkrust_features = ['servo', 'bindgen']
+gkrust_features = []
+if CONFIG['MOZ_STYLO']:
+    gkrust_features += ['servo']
 
-if CONFIG['MOZ_DEBUG']:
-    gkrust_features += ['gecko_debug']
+    if CONFIG['MOZ_STYLO_BINDGEN']:
+        gkrust_features += ['bindgen']
+
+    if CONFIG['MOZ_DEBUG']:
+        gkrust_features += ['gecko_debug']
 
 if CONFIG['MOZ_BUILD_WEBRENDER']:
     gkrust_features += ['quantum_render']
 
 if CONFIG['MOZ_PULSEAUDIO']:
     gkrust_features += ['cubeb_pulse_rust']
 
 if CONFIG['MOZ_RUST_SIMD']:
--- a/toolkit/modules/AppConstants.jsm
+++ b/toolkit/modules/AppConstants.jsm
@@ -328,9 +328,17 @@ this.AppConstants = Object.freeze({
 #endif
 
   HAVE_SHELL_SERVICE:
 #ifdef HAVE_SHELL_SERVICE
     true,
 #else
     false,
 #endif
+
+  MOZ_STYLO:
+#ifdef MOZ_STYLO
+    true,
+#else
+    false,
+#endif
+
 });
--- a/toolkit/modules/Troubleshoot.jsm
+++ b/toolkit/modules/Troubleshoot.jsm
@@ -11,16 +11,19 @@ ChromeUtils.import("resource://gre/modul
 ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
 
 var Experiments;
 try {
   Experiments = ChromeUtils.import("resource:///modules/experiments/Experiments.jsm").Experiments;
 } catch (e) {
 }
 
+const env = Cc["@mozilla.org/process/environment;1"]
+              .getService(Ci.nsIEnvironment);
+
 // We use a preferences whitelist to make sure we only show preferences that
 // are useful for support and won't compromise the user's privacy.  Note that
 // entries are *prefixes*: for example, "accessibility." applies to all prefs
 // under the "accessibility.*" branch.
 const PREFS_WHITELIST = [
   "accessibility.",
   "apz.",
   "browser.cache.",
@@ -59,16 +62,17 @@ const PREFS_WHITELIST = [
   "general.useragent.",
   "gfx.",
   "html5.",
   "image.",
   "javascript.",
   "keyword.",
   "layers.",
   "layout.css.dpi",
+  "layout.css.servo.",
   "layout.display-list.",
   "media.",
   "mousewheel.",
   "network.",
   "permissions.default.image",
   "places.",
   "plugin.",
   "plugins.",
@@ -215,16 +219,43 @@ var dataProviders = {
                          .createInstance(Ci.nsISupportsPRUint64);
       let appinfo = Services.appinfo.QueryInterface(Ci.nsIObserver);
       appinfo.observe(e10sStatus, "getE10SBlocked", "");
       data.autoStartStatus = e10sStatus.data;
     } catch (e) {
       data.autoStartStatus = -1;
     }
 
+    data.styloBuild = AppConstants.MOZ_STYLO;
+    data.styloDefault = Services.prefs.getDefaultBranch(null)
+                                .getBoolPref("layout.css.servo.enabled", false);
+    data.styloResult = false;
+    // Perhaps a bit redundant in places, but this is easier to compare with the
+    // the real check in `nsLayoutUtils.cpp` to ensure they test the same way.
+    if (AppConstants.MOZ_STYLO) {
+      if (env.get("STYLO_FORCE_ENABLED")) {
+        data.styloResult = true;
+      } else if (env.get("STYLO_FORCE_DISABLED")) {
+        data.styloResult = false;
+      } else {
+        data.styloResult =
+          Services.prefs.getBoolPref("layout.css.servo.enabled", false);
+      }
+    }
+    data.styloChromeDefault =
+      Services.prefs.getDefaultBranch(null)
+              .getBoolPref("layout.css.servo.chrome.enabled", false);
+    data.styloChromeResult = false;
+    if (data.styloResult) {
+      let winUtils = Services.wm.getMostRecentWindow("").
+                     QueryInterface(Ci.nsIInterfaceRequestor).
+                     getInterface(Ci.nsIDOMWindowUtils);
+      data.styloChromeResult = winUtils.isStyledByServo;
+    }
+
     if (Services.policies) {
       data.policiesStatus = Services.policies.status;
     }
 
     const keyGoogle = Services.urlFormatter.formatURL("%GOOGLE_API_KEY%").trim();
     data.keyGoogleFound = keyGoogle != "no-google-api-key" && keyGoogle.length > 0;
 
     const keyMozilla = Services.urlFormatter.formatURL("%MOZILLA_API_KEY%").trim();
--- a/toolkit/modules/tests/browser/browser_Troubleshoot.js
+++ b/toolkit/modules/tests/browser/browser_Troubleshoot.js
@@ -139,16 +139,31 @@ const SNAPSHOT_SCHEMA = {
           type: "number",
         },
         currentContentProcesses: {
           type: "number",
         },
         maxContentProcesses: {
           type: "number",
         },
+        styloBuild: {
+          type: "boolean",
+        },
+        styloDefault: {
+          type: "boolean",
+        },
+        styloResult: {
+          type: "boolean",
+        },
+        styloChromeDefault: {
+          type: "boolean",
+        },
+        styloChromeResult: {
+          type: "boolean",
+        },
         policiesStatus: {
           type: "number",
         },
         keyGoogleFound: {
           type: "boolean",
         },
         keyMozillaFound: {
           type: "boolean",
--- a/toolkit/moz.configure
+++ b/toolkit/moz.configure
@@ -545,16 +545,57 @@ simple_keyfile('Google API')
 id_and_secret_keyfile('Bing API')
 
 simple_keyfile('Adjust SDK')
 
 id_and_secret_keyfile('Leanplum SDK')
 
 simple_keyfile('Pocket API')
 
+# Servo integration
+# ==============================================================
+option('--enable-stylo', nargs='?', choices=('build',),
+       help='Include Stylo in the build.  "build" means to disable Stylo at ' +
+            'runtime.')
+
+@depends('--enable-stylo', '--help')
+def stylo_config(value, _):
+    # If nothing is specified, default to building and enabling Stylo,
+    # and not building the old style system.
+    build_stylo = True
+    enable_stylo = True
+    old_style = None
+
+    if len(value) and value[0] == 'build':
+        # Build but disable by request.
+        enable_stylo = None
+        old_style = True
+    elif value.origin != 'default' and not bool(value):
+        # Disable stylo entirely.
+        old_style = True
+        build_stylo = None
+        enable_stylo = None
+
+    return namespace(
+        build = build_stylo,
+        enable = enable_stylo,
+        old_style = old_style,
+    )
+
+option('--disable-stylo-build-bindgen',
+       help='Disable build-time bindgen for Stylo')
+
+@depends('--enable-stylo-build-bindgen', '--enable-compile-environment')
+def building_stylo_bindgen(bindgen_enabled, compile_environment):
+    if not compile_environment:
+        return False
+    if not bindgen_enabled:
+        return False
+    return True
+
 # We support setting up the appropriate options for Stylo's build-time
 # bindings generation via setting LLVM_CONFIG or by providing explicit
 # configure options.  The Windows installer of LLVM/Clang doesn't provide
 # llvm-config, so we need both methods to support all of our tier-1
 # platforms.
 @depends(host)
 @imports('which')
 @imports('os')
@@ -594,161 +635,171 @@ def llvm_config_paths(host):
                                         os.path.expanduser(os.path.join('~', '.mozbuild')))
     bootstrap_llvm_config = os.path.join(mozbuild_state_dir, 'clang', 'bin', 'llvm-config')
 
     llvm_config_progs.append(bootstrap_llvm_config)
 
     return llvm_config_progs
 
 llvm_config = check_prog('LLVM_CONFIG', llvm_config_paths,
+                         when=building_stylo_bindgen,
                          what='llvm-config', allow_missing=True)
 
-option('--with-libclang-path', nargs=1,
-       help='Absolute path to a directory containing Clang/LLVM libraries for Stylo (version 3.9.x or above)')
-option('--with-clang-path', nargs=1,
-       help='Absolute path to a Clang binary for Stylo bindgen (version 3.9.x or above)')
+with only_when(building_stylo_bindgen):
+    option('--with-libclang-path', nargs=1,
+           help='Absolute path to a directory containing Clang/LLVM libraries for Stylo (version 3.9.x or above)')
+    option('--with-clang-path', nargs=1,
+           help='Absolute path to a Clang binary for Stylo bindgen (version 3.9.x or above)')
+
+    def invoke_llvm_config(llvm_config, *options):
+        '''Invoke llvm_config with the given options and return the first line of
+        output.'''
+        lines = check_cmd_output(llvm_config, *options).splitlines()
+        return lines[0]
 
-def invoke_llvm_config(llvm_config, *options):
-    '''Invoke llvm_config with the given options and return the first line of
-    output.'''
-    lines = check_cmd_output(llvm_config, *options).splitlines()
-    return lines[0]
+    @imports(_from='textwrap', _import='dedent')
+    def check_minimum_llvm_config_version(llvm_config):
+        version = Version(invoke_llvm_config(llvm_config, '--version'))
+        min_version = Version('3.9.0')
+        if version < min_version:
+            die(dedent('''\
+            llvm installation {} is incompatible with Stylo bindgen.
 
-@imports(_from='textwrap', _import='dedent')
-def check_minimum_llvm_config_version(llvm_config):
-    version = Version(invoke_llvm_config(llvm_config, '--version'))
-    min_version = Version('3.9.0')
-    if version < min_version:
-        die(dedent('''\
-        llvm installation {} is incompatible with Stylo bindgen.
+            To compile Stylo, please install version {} or greater of
+            Clang + LLVM and ensure that the 'llvm-config' from that
+            installation is first on your path.
+
+            You can verify this by typing 'llvm-config --version'.
+            '''.format(version, min_version)))
 
-        To compile Stylo, please install version {} or greater of
-        Clang + LLVM and ensure that the 'llvm-config' from that
-        installation is first on your path.
-
-        You can verify this by typing 'llvm-config --version'.
-        '''.format(version, min_version)))
+    @depends(llvm_config, '--with-libclang-path', '--with-clang-path',
+             host_library_name_info, host)
+    @imports('os.path')
+    @imports('glob')
+    @imports(_from='textwrap', _import='dedent')
+    def bindgen_config_paths(llvm_config, libclang_path, clang_path,
+                             library_name_info, host):
+        def search_for_libclang(path):
+            # Try to ensure that the clang shared library that bindgen is going
+            # to look for is actually present.  The files that we search for
+            # mirror the logic in clang-sys/build.rs.
+            libclang_choices = []
+            if host.os == 'WINNT':
+                libclang_choices.append('libclang.dll')
+            libclang_choices.append('%sclang%s' % (library_name_info.dll.prefix,
+                                                   library_name_info.dll.suffix))
+            if host.kernel == 'Linux':
+                libclang_choices.append('libclang.so.1')
 
-@depends(llvm_config, '--with-libclang-path', '--with-clang-path',
-         host_library_name_info, host)
-@imports('os.path')
-@imports('glob')
-@imports(_from='textwrap', _import='dedent')
-def bindgen_config_paths(llvm_config, libclang_path, clang_path,
-                         library_name_info, host):
-    def search_for_libclang(path):
-        # Try to ensure that the clang shared library that bindgen is going
-        # to look for is actually present.  The files that we search for
-        # mirror the logic in clang-sys/build.rs.
-        libclang_choices = []
-        if host.os == 'WINNT':
-            libclang_choices.append('libclang.dll')
-        libclang_choices.append('%sclang%s' % (library_name_info.dll.prefix,
-                                               library_name_info.dll.suffix))
-        if host.kernel == 'Linux':
-            libclang_choices.append('libclang.so.1')
+            if host.os == 'OpenBSD':
+                libclang_choices = glob.glob(path + '/libclang.so.*.*')
+
+            # At least one of the choices must be found.
+            for choice in libclang_choices:
+                libclang = os.path.join(path, choice)
+                if os.path.exists(libclang):
+                    return (True, None)
+            else:
+                return (False, list(set(libclang_choices)))
 
-        if host.os == 'OpenBSD':
-            libclang_choices = glob.glob(path + '/libclang.so.*.*')
-
-        # At least one of the choices must be found.
-        for choice in libclang_choices:
-            libclang = os.path.join(path, choice)
-            if os.path.exists(libclang):
-                return (True, None)
-        else:
-            return (False, list(set(libclang_choices)))
+        if not libclang_path and not clang_path:
+            # We must have LLVM_CONFIG in this case.
+            if not llvm_config:
+                die(dedent('''\
+                Could not find LLVM/Clang installation for compiling stylo build-time
+                bindgen.  Please specify the 'LLVM_CONFIG' environment variable
+                (recommended), pass the '--with-libclang-path' and '--with-clang-path'
+                options to configure, or put 'llvm-config' in your PATH.  Altering your
+                PATH may expose 'clang' as well, potentially altering your compiler,
+                which may not be what you intended.'''))
 
-    if not libclang_path and not clang_path:
-        # We must have LLVM_CONFIG in this case.
-        if not llvm_config:
-            die(dedent('''\
-            Could not find LLVM/Clang installation for compiling stylo build-time
-            bindgen.  Please specify the 'LLVM_CONFIG' environment variable
-            (recommended), pass the '--with-libclang-path' and '--with-clang-path'
-            options to configure, or put 'llvm-config' in your PATH.  Altering your
-            PATH may expose 'clang' as well, potentially altering your compiler,
-            which may not be what you intended.'''))
+            check_minimum_llvm_config_version(llvm_config)
+            libclang_arg = '--bindir' if host.os == 'WINNT' else '--libdir'
+            libclang_path = invoke_llvm_config(llvm_config, libclang_arg)
+            clang_path = os.path.join(invoke_llvm_config(llvm_config, '--bindir'),
+                                      'clang')
+            libclang_path = normsep(libclang_path)
+            clang_path = normsep(clang_path)
+
+            # Debian-based distros, at least, can have llvm-config installed
+            # but not have other packages installed.  Since the user is trying
+            # to use their system packages, we can't be more specific about what
+            # they need.
+            clang_resolved = find_program(clang_path)
+            if not clang_resolved:
+                die(dedent('''\
+                The file {} returned by `llvm-config {}` does not exist.
+                clang is required to build Stylo.  Please install the necessary packages,
+                run `mach bootstrap`, or add --disable-stylo to your mozconfig.
+                '''.format(clang_path, '--bindir')))
 
-        check_minimum_llvm_config_version(llvm_config)
-        libclang_arg = '--bindir' if host.os == 'WINNT' else '--libdir'
-        libclang_path = invoke_llvm_config(llvm_config, libclang_arg)
-        clang_path = os.path.join(invoke_llvm_config(llvm_config, '--bindir'),
-                                  'clang')
-        libclang_path = normsep(libclang_path)
-        clang_path = normsep(clang_path)
+            if not os.path.exists(libclang_path):
+                die(dedent('''\
+                The directory {} returned by `llvm-config {}` does not exist.
+                clang is required to build Stylo.  Please install the necessary packages,
+                run `mach bootstrap`, or add --disable-stylo to your mozconfig.
+                '''.format(libclang_path, libclang_arg)))
+
+            (found, searched) = search_for_libclang(libclang_path)
+            if not found:
+                die(dedent('''\
+                Could not find the clang shared library in the path {}
+                returned by `llvm-config {}` (searched for files {}).
+                clang is required to build Stylo.  Please install the necessary packages,
+                run `mach bootstrap`, or add --disable-stylo to your mozconfig.
+                '''.format(libclang_path, libclang_arg, searched)))
 
-        # Debian-based distros, at least, can have llvm-config installed
-        # but not have other packages installed.  Since the user is trying
-        # to use their system packages, we can't be more specific about what
-        # they need.
-        clang_resolved = find_program(clang_path)
-        if not clang_resolved:
+            return namespace(
+                libclang_path=libclang_path,
+                clang_path=clang_resolved,
+            )
+
+        if (not libclang_path and clang_path) or \
+           (libclang_path and not clang_path):
             die(dedent('''\
-            The file {} returned by `llvm-config {}` does not exist.
-            clang is required to build Firefox.  Please install the necessary
-            packages, or run `mach bootstrap`.
-            '''.format(clang_path, '--bindir')))
+            You must provide both of --with-libclang-path and --with-clang-path
+            or neither of them.'''))
+
+        libclang_path = libclang_path[0]
+        clang_path = clang_path[0]
 
-        if not os.path.exists(libclang_path):
+        if not os.path.exists(libclang_path) or \
+           not os.path.isdir(libclang_path):
             die(dedent('''\
-            The directory {} returned by `llvm-config {}` does not exist.
-            clang is required to build Firefox.  Please install the necessary
-            packages, or run `mach bootstrap`.
-            '''.format(libclang_path, libclang_arg)))
+            The argument to --with-libclang-path is not a directory: {}
+            '''.format(libclang_path)))
 
         (found, searched) = search_for_libclang(libclang_path)
         if not found:
             die(dedent('''\
             Could not find the clang shared library in the path {}
-            returned by `llvm-config {}` (searched for files {}).
-            clang is required to build Firefox.  Please install the necessary
-            packages, or run `mach bootstrap`.
-            '''.format(libclang_path, libclang_arg, searched)))
+            specified by --with-libclang-path (searched for files {}).
+            '''.format(libclang_path, searched)))
+
+        clang_resolved = find_program(clang_path)
+        if not clang_resolved:
+            die(dedent('''\
+            The argument to --with-clang-path is not a file: {}
+            '''.format(clang_path)))
 
         return namespace(
             libclang_path=libclang_path,
             clang_path=clang_resolved,
         )
 
-    if (not libclang_path and clang_path) or \
-       (libclang_path and not clang_path):
-        die(dedent('''\
-        You must provide both of --with-libclang-path and --with-clang-path
-        or neither of them.'''))
-
-    libclang_path = libclang_path[0]
-    clang_path = clang_path[0]
-
-    if not os.path.exists(libclang_path) or \
-       not os.path.isdir(libclang_path):
-        die(dedent('''\
-        The argument to --with-libclang-path is not a directory: {}
-        '''.format(libclang_path)))
+    set_config('MOZ_LIBCLANG_PATH', bindgen_config_paths.libclang_path)
+    set_config('MOZ_CLANG_PATH', bindgen_config_paths.clang_path)
+    set_config('MOZ_STYLO_BINDGEN', depends_if('--enable-stylo-build-bindgen')(lambda _: True))
 
-    (found, searched) = search_for_libclang(libclang_path)
-    if not found:
-        die(dedent('''\
-        Could not find the clang shared library in the path {}
-        specified by --with-libclang-path (searched for files {}).
-        '''.format(libclang_path, searched)))
-
-    clang_resolved = find_program(clang_path)
-    if not clang_resolved:
-        die(dedent('''\
-        The argument to --with-clang-path is not a file: {}
-        '''.format(clang_path)))
-
-    return namespace(
-        libclang_path=libclang_path,
-        clang_path=clang_resolved,
-    )
-
-set_config('MOZ_LIBCLANG_PATH', bindgen_config_paths.libclang_path)
-set_config('MOZ_CLANG_PATH', bindgen_config_paths.clang_path)
+set_config('MOZ_STYLO', stylo_config.build)
+set_define('MOZ_STYLO', stylo_config.build)
+set_config('MOZ_STYLO_ENABLE', stylo_config.enable)
+set_define('MOZ_STYLO_ENABLE', stylo_config.enable)
+set_config('MOZ_OLD_STYLE', stylo_config.old_style)
+set_define('MOZ_OLD_STYLE', stylo_config.old_style)
 
 option('--with-servo', env='SERVO_TARGET_DIR', nargs=1,
        help='Absolute path of the target directory where libgeckoservo can '
             'be found. This is generally servo_src_dir/target/release.')
 
 @depends_if('--with-servo')
 def servo_target_dir(value):
     return value[0]
--- a/toolkit/mozapps/installer/packager.mk
+++ b/toolkit/mozapps/installer/packager.mk
@@ -86,21 +86,23 @@ ifdef ENABLE_MOZSEARCH_PLUGIN
           find . -type d -name save-analysis | xargs zip -r5D '$(ABS_DIST)/$(PKG_PATH)$(MOZSEARCH_RUST_ANALYSIS_BASENAME).zip'
 endif
 ifeq (Darwin, $(OS_ARCH))
 ifdef MOZ_ASAN
 	@echo "Rewriting ASan runtime dylib paths for all binaries in $(DIST)/$(MOZ_PKG_DIR)$(_BINPATH) ..."
 	$(PYTHON) $(MOZILLA_DIR)/build/unix/rewrite_asan_dylib.py $(DIST)/$(MOZ_PKG_DIR)$(_BINPATH)
 endif # MOZ_ASAN
 endif # Darwin
+ifdef MOZ_STYLO
 ifndef MOZ_ARTIFACT_BUILDS
 	@echo 'Packing stylo binding files...'
 	cd '$(DIST)/rust_bindings/style' && \
 		zip -r5D '$(ABS_DIST)/$(PKG_PATH)$(STYLO_BINDINGS_PACKAGE)' .
 endif # MOZ_ARTIFACT_BUILDS
+endif # MOZ_STYLO
 
 prepare-package: stage-package
 
 make-package-internal: prepare-package make-sourcestamp-file make-buildinfo-file make-mozinfo-file
 	@echo 'Compressing...'
 	cd $(DIST) && $(MAKE_PACKAGE)
 
 make-package: FORCE
--- a/toolkit/mozapps/installer/upload-files.mk
+++ b/toolkit/mozapps/installer/upload-files.mk
@@ -402,33 +402,35 @@ UPLOAD_FILES= \
   $(call QUOTED_WILDCARD,$(MOZ_BUILDID_INFO_TXT_FILE)) \
   $(call QUOTED_WILDCARD,$(MOZ_MOZINFO_FILE)) \
   $(call QUOTED_WILDCARD,$(MOZ_TEST_PACKAGES_FILE)) \
   $(call QUOTED_WILDCARD,$(PKG_JSSHELL)) \
   $(call QUOTED_WILDCARD,$(DIST)/$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip) \
   $(call QUOTED_WILDCARD,$(topobjdir)/$(MOZ_BUILD_APP)/installer/windows/instgen/setup.exe) \
   $(call QUOTED_WILDCARD,$(topobjdir)/$(MOZ_BUILD_APP)/installer/windows/instgen/setup-stub.exe) \
   $(call QUOTED_WILDCARD,$(topsrcdir)/toolchains.json) \
-  $(call QUOTED_WILDCARD,$(DIST)/$(PKG_PATH)$(STYLO_BINDINGS_PACKAGE)) \
   $(if $(UPLOAD_EXTRA_FILES), $(foreach f, $(UPLOAD_EXTRA_FILES), $(wildcard $(DIST)/$(f))))
 
 ifneq ($(filter-out en-US x-test,$(AB_CD)),)
   UPLOAD_FILES += \
     $(call QUOTED_WILDCARD,$(topobjdir)/$(MOZ_BUILD_APP)/installer/windows/l10ngen/setup.exe) \
     $(call QUOTED_WILDCARD,$(topobjdir)/$(MOZ_BUILD_APP)/installer/windows/l10ngen/setup-stub.exe)
 endif
 
 
 ifdef MOZ_CODE_COVERAGE
   UPLOAD_FILES += \
     $(call QUOTED_WILDCARD,$(DIST)/$(PKG_PATH)$(CODE_COVERAGE_ARCHIVE_BASENAME).zip) \
     $(call QUOTED_WILDCARD,$(topobjdir)/chrome-map.json) \
     $(NULL)
 endif
 
+ifdef MOZ_STYLO
+  UPLOAD_FILES += $(call QUOTED_WILDCARD,$(DIST)/$(PKG_PATH)$(STYLO_BINDINGS_PACKAGE))
+endif
 
 ifdef ENABLE_MOZSEARCH_PLUGIN
   UPLOAD_FILES += $(call QUOTED_WILDCARD,$(DIST)/$(PKG_PATH)$(MOZSEARCH_ARCHIVE_BASENAME).zip)
   UPLOAD_FILES += $(call QUOTED_WILDCARD,$(DIST)/$(PKG_PATH)$(MOZSEARCH_RUST_ANALYSIS_BASENAME).zip)
 endif
 
 SIGN_CHECKSUM_CMD=
 ifdef MOZ_SIGN_CMD