Bug 1530193 - Refactor preference stylesheet prefs to not require a pres context. r=jwatt
authorEmilio Cobos Álvarez <emilio@crisal.io>
Wed, 06 Mar 2019 21:34:30 +0000
changeset 520592 2e2dd6d6d5762cd5a60acdb1f14efadf76dcf490
parent 520591 4a50be47adebd4c8f4fd2fb0171aa0c40d611921
child 520593 26ac004eeb4cc3876cf822e91ef25206586a1537
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwatt
bugs1530193
milestone67.0a1
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
Bug 1530193 - Refactor preference stylesheet prefs to not require a pres context. r=jwatt We really only have two sets of prefs, one for chrome-like documents (stuff in chrome docshells + chrome-origin images), and one for the rest. Differential Revision: https://phabricator.services.mozilla.com/D20946
layout/base/PresShell.cpp
layout/base/nsPresContext.cpp
layout/base/nsPresContext.h
layout/style/GeckoBindings.cpp
layout/style/GeckoBindings.h
layout/style/PreferenceSheet.cpp
layout/style/PreferenceSheet.h
layout/style/ServoBindings.toml
layout/style/moz.build
layout/style/nsLayoutStylesheetCache.cpp
layout/style/nsLayoutStylesheetCache.h
layout/style/nsStyleStruct.cpp
modules/libpref/init/StaticPrefList.h
servo/components/style/gecko/data.rs
servo/components/style/gecko/media_queries.rs
servo/components/style/gecko/wrapper.rs
servo/components/style/values/specified/color.rs
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -1439,29 +1439,23 @@ void nsIPresShell::UpdatePreferenceStyle
     return;
   }
 
   // Documents in chrome shells do not have any preference style rules applied.
   if (nsContentUtils::IsInChromeDocshell(mDocument)) {
     return;
   }
 
-  // We need to pass in mPresContext so that if the nsLayoutStylesheetCache
-  // needs to recreate the pref style sheet, it has somewhere to get the
-  // pref styling information from.  All pres contexts for
-  // IsChromeOriginImage() == false will have the same pref styling information,
-  // and similarly for IsChromeOriginImage() == true, so it doesn't really
-  // matter which pres context we pass in when it does need to be recreated.
-  // (See nsPresContext::GetDocumentColorPreferences for how whether we
-  // are a chrome origin image affects some pref styling information.)
+  PreferenceSheet::EnsureInitialized();
   auto cache = nsLayoutStylesheetCache::Singleton();
+
   RefPtr<StyleSheet> newPrefSheet =
-      mPresContext->IsChromeOriginImage()
-          ? cache->ChromePreferenceSheet(mPresContext)
-          : cache->ContentPreferenceSheet(mPresContext);
+      PreferenceSheet::ShouldUseChromePrefs(*mDocument)
+          ? cache->ChromePreferenceSheet()
+          : cache->ContentPreferenceSheet();
 
   if (mPrefStyleSheet == newPrefSheet) {
     return;
   }
 
   RemovePreferenceStyles();
 
   // NOTE(emilio): This sheet is added as an agent sheet, because we don't want
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -105,31 +105,16 @@ uint8_t gNotifySubDocInvalidationData;
  * of local invalidations of them and their descendant layers.
  * Pass a callback to ComputeDifferences to have these called.
  */
 class ContainerLayerPresContext : public LayerUserData {
  public:
   nsPresContext* mPresContext;
 };
 
-nscolor nsPresContext::MakeColorPref(const nsString& aColor) {
-  ServoStyleSet* styleSet = mShell ? mShell->StyleSet() : nullptr;
-
-  nscolor result;
-  bool ok =
-      ServoCSSParser::ComputeColor(styleSet, NS_RGB(0, 0, 0), aColor, &result);
-
-  if (!ok) {
-    // Any better choices?
-    result = NS_RGB(0, 0, 0);
-  }
-
-  return result;
-}
-
 bool nsPresContext::IsDOMPaintEventPending() {
   if (!mTransactions.IsEmpty()) {
     return true;
   }
 
   nsRootPresContext* drpc = GetRootPresContext();
   if (drpc && drpc->mRefreshDriver->ViewManagerFlushIsPending()) {
     // Since we're promising that there will be a MozAfterPaint event
@@ -167,44 +152,32 @@ nsPresContext::nsPresContext(dom::Docume
       mFullZoom(1.0),
       mOverrideDPPX(0.0),
       mLastFontInflationScreenSize(gfxSize(-1.0, -1.0)),
       mCurAppUnitsPerDevPixel(0),
       mAutoQualityMinFontSizePixelsPref(0),
       mPageSize(-1, -1),
       mPageScale(0.0),
       mPPScale(1.0f),
-      mDefaultColor(NS_RGBA(0, 0, 0, 0)),
-      mBackgroundColor(NS_RGB(0xFF, 0xFF, 0xFF)),
-      mLinkColor(NS_RGB(0x00, 0x00, 0xEE)),
-      mActiveLinkColor(NS_RGB(0xEE, 0x00, 0x00)),
-      mVisitedLinkColor(NS_RGB(0x55, 0x1A, 0x8B)),
-      mFocusBackgroundColor(mBackgroundColor),
-      mFocusTextColor(mDefaultColor),
-      mBodyTextColor(mDefaultColor),
       mViewportScrollOverrideElement(nullptr),
       mViewportScrollStyles(StyleOverflow::Auto, StyleOverflow::Auto),
-      mFocusRingWidth(1),
       mExistThrottledUpdates(false),
       // mImageAnimationMode is initialised below, in constructor body
       mImageAnimationModePref(imgIContainer::kNormalAnimMode),
       mInterruptChecksToSkip(0),
       mElementsRestyled(0),
       mFramesConstructed(0),
       mFramesReflowed(0),
       mInteractionTimeEnabled(true),
       mHasPendingInterrupt(false),
       mPendingInterruptFromTest(false),
       mInterruptsEnabled(false),
       mUseDocumentColors(true),
-      mUnderlineLinks(true),
       mSendAfterPaintToContent(false),
       mUseFocusColors(false),
-      mFocusRingOnAnything(false),
-      mFocusRingStyle(false),
       mDrawImageBackground(true),  // always draw the background
       mDrawColorBackground(true),
       // mNeverAnimate is initialised below, in constructor body
       mPaginated(aType != eContext_Galley),
       mCanPaginatedScroll(false),
       mDoScaledTwips(true),
       mIsRootPaginatedDocument(false),
       mPrefBidiDirection(false),
@@ -365,81 +338,37 @@ bool nsPresContext::IsChromeOriginImage(
          Document()->IsDocumentURISchemeChrome();
 }
 
 void nsPresContext::GetDocumentColorPreferences() {
   // Make sure the preferences are initialized.  In the normal run,
   // they would already be, because gfxPlatform would have been created,
   // but in some reference tests, that is not the case.
   gfxPrefs::GetSingleton();
-
-  int32_t useAccessibilityTheme = 0;
-  bool usePrefColors = true;
+  PreferenceSheet::EnsureInitialized();
+
   static int32_t sDocumentColorsSetting;
   static bool sDocumentColorsSettingPrefCached = false;
   if (!sDocumentColorsSettingPrefCached) {
     sDocumentColorsSettingPrefCached = true;
     Preferences::AddIntVarCache(&sDocumentColorsSetting,
                                 "browser.display.document_color_use", 0);
   }
 
-  if (IsChrome() || IsChromeOriginImage()) {
-    usePrefColors = false;
-  } else {
-    useAccessibilityTheme =
-        LookAndFeel::GetInt(LookAndFeel::eIntID_UseAccessibilityTheme, 0);
-    usePrefColors = !useAccessibilityTheme;
-  }
-  if (usePrefColors) {
-    usePrefColors =
-        !Preferences::GetBool("browser.display.use_system_colors", false);
-  }
-
-  if (nsContentUtils::UseStandinsForNativeColors()) {
-    // Once the |nsContentUtils::UseStandinsForNativeColors()| is true,
-    // use fixed color values instead of preferred colors and system colors.
-    mDefaultColor = LookAndFeel::GetColorUsingStandins(
-        LookAndFeel::eColorID_windowtext, NS_RGB(0x00, 0x00, 0x00));
-    mBackgroundColor = LookAndFeel::GetColorUsingStandins(
-        LookAndFeel::eColorID_window, NS_RGB(0xff, 0xff, 0xff));
-  } else if (usePrefColors) {
-    nsAutoString colorStr;
-    Preferences::GetString("browser.display.foreground_color", colorStr);
-    if (!colorStr.IsEmpty()) {
-      mDefaultColor = MakeColorPref(colorStr);
-    }
-
-    colorStr.Truncate();
-    Preferences::GetString("browser.display.background_color", colorStr);
-    if (!colorStr.IsEmpty()) {
-      mBackgroundColor = MakeColorPref(colorStr);
-    }
-  } else {
-    mDefaultColor = LookAndFeel::GetColor(
-        LookAndFeel::eColorID_WindowForeground, NS_RGB(0x00, 0x00, 0x00));
-    mBackgroundColor = LookAndFeel::GetColor(
-        LookAndFeel::eColorID_WindowBackground, NS_RGB(0xFF, 0xFF, 0xFF));
-  }
-
-  // Wherever we got the default background color from, ensure it is
-  // opaque.
-  mBackgroundColor =
-      NS_ComposeColors(NS_RGB(0xFF, 0xFF, 0xFF), mBackgroundColor);
-
   // Now deal with the pref:
   // 0 = default: always, except in high contrast mode
   // 1 = always
   // 2 = never
   if (sDocumentColorsSetting == 1 || mDocument->IsBeingUsedAsImage()) {
     mUseDocumentColors = true;
   } else if (sDocumentColorsSetting == 2) {
     mUseDocumentColors = IsChrome() || IsChromeOriginImage();
   } else {
-    MOZ_ASSERT(!useAccessibilityTheme || !(IsChrome() || IsChromeOriginImage()),
-               "The accessibility theme should only be on for non-chrome");
+    bool useAccessibilityTheme =
+        PreferenceSheet::UseAccessibilityTheme(IsChrome());
     mUseDocumentColors = !useAccessibilityTheme;
   }
 }
 
 void nsPresContext::GetUserPreferences() {
   if (!GetPresShell()) {
     // No presshell means nothing to do here.  We'll do this when we
     // get a presshell.
@@ -450,67 +379,16 @@ void nsPresContext::GetUserPreferences()
       Preferences::GetInt("browser.display.auto_quality_min_font_size");
 
   // * document colors
   GetDocumentColorPreferences();
 
   mSendAfterPaintToContent = Preferences::GetBool(
       "dom.send_after_paint_to_content", mSendAfterPaintToContent);
 
-  // * link colors
-  mUnderlineLinks =
-      Preferences::GetBool("browser.underline_anchors", mUnderlineLinks);
-
-  nsAutoString colorStr;
-  Preferences::GetString("browser.anchor_color", colorStr);
-  if (!colorStr.IsEmpty()) {
-    mLinkColor = MakeColorPref(colorStr);
-  }
-
-  colorStr.Truncate();
-  Preferences::GetString("browser.active_color", colorStr);
-  if (!colorStr.IsEmpty()) {
-    mActiveLinkColor = MakeColorPref(colorStr);
-  }
-
-  colorStr.Truncate();
-  Preferences::GetString("browser.visited_color", colorStr);
-  if (!colorStr.IsEmpty()) {
-    mVisitedLinkColor = MakeColorPref(colorStr);
-  }
-
-  mUseFocusColors =
-      Preferences::GetBool("browser.display.use_focus_colors", mUseFocusColors);
-
-  mFocusTextColor = mDefaultColor;
-  mFocusBackgroundColor = mBackgroundColor;
-
-  colorStr.Truncate();
-  Preferences::GetString("browser.display.focus_text_color", colorStr);
-  if (!colorStr.IsEmpty()) {
-    mFocusTextColor = MakeColorPref(colorStr);
-  }
-
-  colorStr.Truncate();
-  Preferences::GetString("browser.display.focus_background_color", colorStr);
-  if (!colorStr.IsEmpty()) {
-    mFocusBackgroundColor = MakeColorPref(colorStr);
-  }
-
-  mFocusRingWidth =
-      Preferences::GetInt("browser.display.focus_ring_width", mFocusRingWidth);
-
-  mFocusRingOnAnything = Preferences::GetBool(
-      "browser.display.focus_ring_on_anything", mFocusRingOnAnything);
-
-  mFocusRingStyle =
-      Preferences::GetInt("browser.display.focus_ring_style", mFocusRingStyle);
-
-  mBodyTextColor = mDefaultColor;
-
   mPrefScrollbarSide = Preferences::GetInt("layout.scrollbar.side");
 
   Document()->ResetLangPrefs();
 
   // * image animation
   nsAutoCString animatePref;
   Preferences::GetCString("image.animation_mode", animatePref);
   if (animatePref.EqualsLiteral("normal"))
@@ -633,16 +511,17 @@ void nsPresContext::PreferenceChanged(co
 
   // We will end up calling InvalidatePreferenceSheets one from each pres
   // context, but all it's doing is clearing its cached sheet pointers, so it
   // won't be wastefully recreating the sheet multiple times.
   //
   // The first pres context that has its pref changed runnable called will
   // be the one to cause the reconstruction of the pref style sheet.
   nsLayoutStylesheetCache::InvalidatePreferenceSheets();
+  PreferenceSheet::Refresh();
   DispatchPrefChangedRunnableIfNeeded();
 
   if (prefName.EqualsLiteral("nglayout.debug.paint_flashing") ||
       prefName.EqualsLiteral("nglayout.debug.paint_flashing_chrome")) {
     mPaintFlashingInitialized = false;
     return;
   }
 }
@@ -1473,16 +1352,18 @@ void nsPresContext::SysColorChangedInter
     // Don't use the cached values for the system colors
     LookAndFeel::Refresh();
     sLookAndFeelChanged = false;
   }
 
   // Invalidate cached '-moz-windows-accent-color-applies' media query:
   RefreshSystemMetrics();
 
+  PreferenceSheet::Refresh();
+
   // Reset default background and foreground colors for the document since
   // they may be using system colors
   GetDocumentColorPreferences();
 
   // The system color values are computed to colors in the style data,
   // so normal style data comparison is sufficient here.
   RebuildAllStyleData(nsChangeHint(0), nsRestyleHint(0));
 }
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -8,16 +8,17 @@
 
 #ifndef nsPresContext_h___
 #define nsPresContext_h___
 
 #include "mozilla/Attributes.h"
 #include "mozilla/MediaFeatureChange.h"
 #include "mozilla/NotNull.h"
 #include "mozilla/ScrollStyles.h"
+#include "mozilla/PreferenceSheet.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/WeakPtr.h"
 #include "nsColor.h"
 #include "nsCoord.h"
 #include "nsCOMPtr.h"
 #include "nsIPresShell.h"
 #include "nsIPresShellInlines.h"
 #include "nsRect.h"
@@ -81,22 +82,16 @@ class ContainerLayer;
 class LayerManager;
 }  // namespace layers
 namespace dom {
 class Document;
 class Element;
 }  // namespace dom
 }  // namespace mozilla
 
-// supported values for cached bool types
-//
-// FIXME(emilio): We have StaticPrefs now, probably all of these should be
-// migrated.
-enum nsPresContext_CachedBoolPrefType { kPresContext_UnderlineLinks = 1 };
-
 // supported values for cached integer pref types
 enum nsPresContext_CachedIntPrefType {
   kPresContext_ScrollbarSide = 1,
   kPresContext_BidiDirection
 };
 
 // IDs for the default variable and fixed fonts (not to be changed, see
 // nsFont.h) To be used for Get/SetDefaultFont(). The other IDs in nsFont.h are
@@ -354,31 +349,16 @@ class nsPresContext : public nsISupports
    */
   void EmulateMedium(const nsAString& aMediaType);
 
   /*
    * Restore the viewer's natural medium
    */
   void StopEmulatingMedium();
 
-  /** Get a cached boolean pref, by its type */
-  // *  - initially created for bugs 31816, 20760, 22963
-  bool GetCachedBoolPref(nsPresContext_CachedBoolPrefType aPrefType) const {
-    // If called with a constant parameter, the compiler should optimize
-    // this switch statement away.
-    switch (aPrefType) {
-      case kPresContext_UnderlineLinks:
-        return mUnderlineLinks;
-      default:
-        NS_ERROR("Invalid arg passed to GetCachedBoolPref");
-    }
-
-    return false;
-  }
-
   /** Get a cached integer pref, by its type */
   // *  - initially created for bugs 30910, 61883, 74186, 84398
   int32_t GetCachedIntPref(nsPresContext_CachedIntPrefType aPrefType) const {
     // If called with a constant parameter, the compiler should optimize
     // this switch statement away.
     switch (aPrefType) {
       case kPresContext_ScrollbarSide:
         return mPrefScrollbarSide;
@@ -386,38 +366,22 @@ class nsPresContext : public nsISupports
         return mPrefBidiDirection;
       default:
         NS_ERROR("invalid arg passed to GetCachedIntPref");
     }
 
     return false;
   }
 
-  /**
-   * Get the default colors
-   */
-  nscolor DefaultColor() const { return mDefaultColor; }
-  nscolor DefaultBackgroundColor() const { return mBackgroundColor; }
-  nscolor DefaultLinkColor() const { return mLinkColor; }
-  nscolor DefaultActiveLinkColor() const { return mActiveLinkColor; }
-  nscolor DefaultVisitedLinkColor() const { return mVisitedLinkColor; }
-  nscolor FocusBackgroundColor() const { return mFocusBackgroundColor; }
-  nscolor FocusTextColor() const { return mFocusTextColor; }
-
-  /**
-   * Body text color, for use in quirks mode only.
-   */
-  nscolor BodyTextColor() const { return mBodyTextColor; }
-  void SetBodyTextColor(nscolor aColor) { mBodyTextColor = aColor; }
-
-  bool GetUseFocusColors() const { return mUseFocusColors; }
-  uint8_t FocusRingWidth() const { return mFocusRingWidth; }
-  bool GetFocusRingOnAnything() const { return mFocusRingOnAnything; }
-  uint8_t GetFocusRingStyle() const { return mFocusRingStyle; }
-
+  const mozilla::PreferenceSheet::Prefs& PrefSheetPrefs() const {
+    return mozilla::PreferenceSheet::PrefsFor(*mDocument);
+  }
+  nscolor DefaultBackgroundColor() const {
+    return PrefSheetPrefs().mDefaultBackgroundColor;
+  }
 
   nsISupports* GetContainerWeak() const;
 
   nsIDocShell* GetDocShell() const;
 
   // XXX this are going to be replaced with set/get container
   void SetLinkHandler(nsILinkHandler* aHandler) { mLinkHandler = aHandler; }
   nsILinkHandler* GetLinkHandler() { return mLinkHandler; }
@@ -1215,40 +1179,26 @@ class nsPresContext : public nsISupports
 
   mozilla::UniquePtr<gfxMissingFontRecorder> mMissingFonts;
 
   nsRect mVisibleArea;
   nsSize mPageSize;
   float mPageScale;
   float mPPScale;
 
-  nscolor mDefaultColor;
-  nscolor mBackgroundColor;
-
-  nscolor mLinkColor;
-  nscolor mActiveLinkColor;
-  nscolor mVisitedLinkColor;
-
-  nscolor mFocusBackgroundColor;
-  nscolor mFocusTextColor;
-
-  nscolor mBodyTextColor;
-
   // This is a non-owning pointer. May be null. If non-null, it's guaranteed to
   // be pointing to an element that's still alive, because we'll reset it in
   // UpdateViewportScrollStylesOverride() as part of the cleanup code when
   // this element is removed from the document. (For <body> and the root
   // element, this call happens in nsCSSFrameConstructor::ContentRemoved(). For
   // fullscreen elements, it happens in the fullscreen-specific cleanup invoked
   // by Element::UnbindFromTree().)
   mozilla::dom::Element* MOZ_NON_OWNING_REF mViewportScrollOverrideElement;
   ScrollStyles mViewportScrollStyles;
 
-  uint8_t mFocusRingWidth;
-
   bool mExistThrottledUpdates;
 
   uint16_t mImageAnimationMode;
   uint16_t mImageAnimationModePref;
 
   uint32_t mInterruptChecksToSkip;
 
   // Counters for tests and tools that want to detect frame construction
@@ -1273,17 +1223,16 @@ class nsPresContext : public nsISupports
 
   // last time we did a full style flush
   mozilla::TimeStamp mLastStyleUpdateForAllAnimations;
 
   unsigned mHasPendingInterrupt : 1;
   unsigned mPendingInterruptFromTest : 1;
   unsigned mInterruptsEnabled : 1;
   unsigned mUseDocumentColors : 1;
-  unsigned mUnderlineLinks : 1;
   unsigned mSendAfterPaintToContent : 1;
   unsigned mUseFocusColors : 1;
   unsigned mFocusRingOnAnything : 1;
   unsigned mFocusRingStyle : 1;
   unsigned mDrawImageBackground : 1;
   unsigned mDrawColorBackground : 1;
   unsigned mNeverAnimate : 1;
   unsigned mPaginated : 1;
@@ -1342,18 +1291,16 @@ class nsPresContext : public nsISupports
   unsigned mInitialized : 1;
 #endif
 
   mozilla::Maybe<mozilla::MediaFeatureChange> mPendingMediaFeatureValuesChange;
 
  protected:
   virtual ~nsPresContext();
 
-  nscolor MakeColorPref(const nsString& aColor);
-
   void LastRelease();
 
 #ifdef DEBUG
  private:
   friend struct nsAutoLayoutPhase;
   uint32_t mLayoutPhaseCount[eLayoutPhase_COUNT];
 
  public:
--- a/layout/style/GeckoBindings.cpp
+++ b/layout/style/GeckoBindings.cpp
@@ -760,16 +760,20 @@ nsAtom* Gecko_GetXMLLangValue(RawGeckoEl
   RefPtr<nsAtom> atom = attr->GetAtomValue();
   return atom.forget().take();
 }
 
 Document::DocumentTheme Gecko_GetDocumentLWTheme(const Document* aDocument) {
   return aDocument->ThreadSafeGetDocumentLWTheme();
 }
 
+const PreferenceSheet::Prefs* Gecko_GetPrefSheetPrefs(const Document* aDoc) {
+  return &PreferenceSheet::PrefsFor(*aDoc);
+}
+
 bool Gecko_IsTableBorderNonzero(RawGeckoElementBorrowed aElement) {
   if (!aElement->IsHTMLElement(nsGkAtoms::table)) {
     return false;
   }
   const nsAttrValue* val = aElement->GetParsedAttr(nsGkAtoms::border);
   return val &&
          (val->Type() != nsAttrValue::eInteger || val->GetIntegerValue() != 0);
 }
--- a/layout/style/GeckoBindings.h
+++ b/layout/style/GeckoBindings.h
@@ -12,16 +12,17 @@
 #include <stdint.h>
 
 #include "mozilla/ServoTypes.h"
 #include "mozilla/ServoBindingTypes.h"
 #include "mozilla/css/DocumentMatchingFunction.h"
 #include "mozilla/css/SheetLoadData.h"
 #include "mozilla/EffectCompositor.h"
 #include "mozilla/ComputedTimingFunction.h"
+#include "mozilla/PreferenceSheet.h"
 #include "nsCSSValue.h"
 #include "nsStyleStruct.h"
 
 class nsAtom;
 class nsIURI;
 class nsSimpleContentList;
 struct nsFont;
 
@@ -133,16 +134,19 @@ bool Gecko_IsRootElement(RawGeckoElement
 bool Gecko_MatchLang(RawGeckoElementBorrowed element, nsAtom* override_lang,
                      bool has_override_lang, const char16_t* value);
 
 nsAtom* Gecko_GetXMLLangValue(RawGeckoElementBorrowed element);
 
 mozilla::dom::Document::DocumentTheme Gecko_GetDocumentLWTheme(
     const mozilla::dom::Document*);
 
+const mozilla::PreferenceSheet::Prefs* Gecko_GetPrefSheetPrefs(
+    const mozilla::dom::Document*);
+
 bool Gecko_IsTableBorderNonzero(RawGeckoElementBorrowed element);
 bool Gecko_IsBrowserFrame(RawGeckoElementBorrowed element);
 
 // Attributes.
 #define SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS(prefix_, implementor_)   \
   nsAtom* prefix_##LangValue(implementor_ element);                            \
   bool prefix_##HasAttr(implementor_ element, nsAtom* ns, nsAtom* name);       \
   bool prefix_##AttrEquals(implementor_ element, nsAtom* ns, nsAtom* name,     \
new file mode 100644
--- /dev/null
+++ b/layout/style/PreferenceSheet.cpp
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "PreferenceSheet.h"
+
+#include "ServoCSSParser.h"
+#include "MainThreadUtils.h"
+#include "mozilla/StaticPrefs.h"
+#include "mozilla/LookAndFeel.h"
+#include "mozilla/dom/Document.h"
+#include "nsContentUtils.h"
+
+using mozilla::dom::Document;
+
+namespace mozilla {
+
+bool PreferenceSheet::sInitialized;
+PreferenceSheet::Prefs PreferenceSheet::sContentPrefs;
+PreferenceSheet::Prefs PreferenceSheet::sChromePrefs;
+
+static void GetColor(const char* aPrefName, nscolor& aColor) {
+  nsAutoString value;
+  Preferences::GetString(aPrefName, value);
+  if (value.IsEmpty()) {
+    return;
+  }
+  nscolor result;
+  if (!ServoCSSParser::ComputeColor(nullptr, NS_RGB(0, 0, 0), value, &result)) {
+    return;
+  }
+  aColor = result;
+}
+
+bool PreferenceSheet::ShouldUseChromePrefs(const Document& aDoc) {
+  return aDoc.IsInChromeDocShell() ||
+    (aDoc.IsBeingUsedAsImage() && aDoc.IsDocumentURISchemeChrome());
+}
+
+bool PreferenceSheet::UseAccessibilityTheme(bool aIsChrome) {
+  return !aIsChrome &&
+         !!LookAndFeel::GetInt(LookAndFeel::eIntID_UseAccessibilityTheme, 0);
+}
+
+void PreferenceSheet::Prefs::Load(bool aIsChrome) {
+  *this = {};
+
+  mUnderlineLinks = StaticPrefs::browser_underline_anchors();
+
+  mUseFocusColors = StaticPrefs::browser_display_use_focus_colors();
+  mFocusRingWidth = StaticPrefs::browser_display_focus_ring_width();
+  mFocusRingStyle = StaticPrefs::browser_display_focus_ring_style();
+  mFocusRingOnAnything = StaticPrefs::browser_display_focus_ring_on_anything();
+
+  const bool usePrefColors = !aIsChrome && !UseAccessibilityTheme(aIsChrome) &&
+                             !StaticPrefs::browser_display_use_system_colors();
+
+  if (nsContentUtils::UseStandinsForNativeColors()) {
+    mDefaultColor = LookAndFeel::GetColorUsingStandins(
+        LookAndFeel::eColorID_windowtext, mDefaultColor);
+    mDefaultBackgroundColor = LookAndFeel::GetColorUsingStandins(
+        LookAndFeel::eColorID_window, mDefaultBackgroundColor);
+  } else if (usePrefColors) {
+    GetColor("browser.display.background_color", mDefaultBackgroundColor);
+    GetColor("browser.display.foreground_color", mDefaultColor);
+  } else {
+    mDefaultColor = LookAndFeel::GetColor(
+        LookAndFeel::eColorID_WindowForeground, mDefaultColor);
+    mDefaultBackgroundColor = LookAndFeel::GetColor(
+        LookAndFeel::eColorID_WindowBackground, mDefaultBackgroundColor);
+  }
+
+  GetColor("browser.anchor_color", mLinkColor);
+  GetColor("browser.active_color", mActiveLinkColor);
+  GetColor("browser.visited_color", mVisitedLinkColor);
+
+  GetColor("browser.display.focus_text_color", mFocusTextColor);
+  GetColor("browser.display.focus_background_color", mFocusBackgroundColor);
+
+  // Wherever we got the default background color from, ensure it is
+  // opaque.
+  mDefaultBackgroundColor =
+      NS_ComposeColors(NS_RGB(0xFF, 0xFF, 0xFF), mDefaultBackgroundColor);
+}
+
+void PreferenceSheet::Initialize() {
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!sInitialized);
+
+  sInitialized = true;
+
+  sContentPrefs.Load(false);
+  sChromePrefs.Load(true);
+}
+
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/layout/style/PreferenceSheet.h
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/* Some prefable colors for style system use */
+
+#ifndef mozilla_ColorPreferences_h
+#define mozilla_ColorPreferences_h
+
+#include "nsColor.h"
+
+namespace mozilla {
+
+namespace dom {
+class Document;
+}
+
+struct PreferenceSheet {
+  struct Prefs {
+    nscolor mLinkColor = NS_RGB(0x00, 0x00, 0xEE);
+    nscolor mActiveLinkColor = NS_RGB(0xEE, 0x00, 0x00);
+    nscolor mVisitedLinkColor = NS_RGB(0x55, 0x1A, 0x8B);
+
+    nscolor mDefaultColor = NS_RGB(0, 0, 0);
+    nscolor mDefaultBackgroundColor = NS_RGB(0xFF, 0xFF, 0xFF);
+
+    nscolor mLinkBackgroundColor = mDefaultBackgroundColor;
+
+    nscolor mFocusTextColor = mDefaultColor;
+    nscolor mFocusBackgroundColor = mDefaultBackgroundColor;
+
+    bool mUnderlineLinks = true;
+    bool mUseFocusColors = false;
+    uint8_t mFocusRingWidth = 1;
+    bool mFocusRingStyle = false;
+    bool mFocusRingOnAnything = false;
+
+    void Load(bool aIsChrome);
+  };
+
+  static void EnsureInitialized() {
+    if (sInitialized) {
+      return;
+    }
+    Initialize();
+  }
+
+  static void Refresh() {
+    sInitialized = false;
+    EnsureInitialized();
+  }
+
+  static Prefs& ContentPrefs() {
+    MOZ_ASSERT(sInitialized);
+    return sContentPrefs;
+  }
+
+  static Prefs& ChromePrefs() {
+    MOZ_ASSERT(sInitialized);
+    return sChromePrefs;
+  }
+
+  static bool ShouldUseChromePrefs(const dom::Document&);
+  static bool UseAccessibilityTheme(bool aIsChrome);
+  static const Prefs& PrefsFor(const dom::Document& aDocument) {
+    return ShouldUseChromePrefs(aDocument) ? ChromePrefs() : ContentPrefs();
+  }
+
+ private:
+  static bool sInitialized;
+  static Prefs sContentPrefs;
+  static Prefs sChromePrefs;
+
+  static void Initialize();
+};
+
+}  // namespace mozilla
+
+#endif
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -174,16 +174,17 @@ whitelist-types = [
     "RawServoAnimationValueMap",  # TODO(heycam): Handle this elsewhere.
     "mozilla::DeclarationBlockMutationClosure",
     "mozilla::AnimationPropertySegment",
     "mozilla::AnonymousCounterStyle",
     "mozilla::AtomArray",
     "mozilla::ComputedTiming",
     "mozilla::ComputedTimingFunction",
     "mozilla::ComputedTimingFunction::BeforeFlag",
+    "mozilla::PreferenceSheet",
     "mozilla::SeenPtrs",
     "mozilla::ServoElementSnapshot.*",
     "mozilla::ComputedStyle",
     "mozilla::StyleSheet",
     "mozilla::ServoStyleSheetInner",
     "mozilla::ServoStyleSetSizes",
     "mozilla::ServoTraversalStatistics",
     "mozilla::css::LoaderReusableStyleSheets",
@@ -520,16 +521,17 @@ structs-types = [
     "gfxFontFeature",
     "mozilla::gfx::FontVariation",
     "mozilla::DeclarationBlockMutationClosure",
     "nsAttrValue",
     "nsIContent",
     "nsINode",
     "Document",
     "Document_DocumentTheme",
+    "mozilla::PreferenceSheet_Prefs",
     "nsSimpleContentList",
     "mozilla::MediumFeaturesChangedResult",
     "RawGeckoAnimationPropertySegment",
     "RawGeckoComputedTiming",
     "RawGeckoCSSPropertyIDList",
     "RawGeckoDocument",
     "RawGeckoElement",
     "Element",
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -82,16 +82,17 @@ EXPORTS.mozilla += [
     'CSSPropFlags.h',
     'DeclarationBlock.h',
     'DocumentStyleRootIterator.h',
     'GeckoBindings.h',
     'LayerAnimationInfo.h',
     'MappedDeclarations.h',
     'MediaFeatureChange.h',
     'PostTraversalTask.h',
+    'PreferenceSheet.h',
     'PreloadedStyleSheet.h',
     'PseudoStyleType.h',
     'RustCell.h',
     'ServoArcTypeList.h',
     'ServoBindings.h',
     'ServoBindingTypes.h',
     'ServoBoxedTypeList.h',
     'ServoComputedData.h',
@@ -206,16 +207,17 @@ UNIFIED_SOURCES += [
     'nsStyleCoord.cpp',
     'nsStyleStruct.cpp',
     'nsStyleTransformMatrix.cpp',
     'nsStyleUtil.cpp',
     'nsTransitionManager.cpp',
     'PaintWorkletGlobalScope.cpp',
     'PaintWorkletImpl.cpp',
     'PostTraversalTask.cpp',
+    'PreferenceSheet.cpp',
     'PreloadedStyleSheet.cpp',
     'PseudoStyleType.cpp',
     'Rule.cpp',
     'ServoCSSParser.cpp',
     'ServoCSSRuleList.cpp',
     'ServoElementSnapshot.cpp',
     'ServoStyleSet.cpp',
     'StreamLoader.cpp',
--- a/layout/style/nsLayoutStylesheetCache.cpp
+++ b/layout/style/nsLayoutStylesheetCache.cpp
@@ -62,29 +62,29 @@ nsresult nsLayoutStylesheetCache::Observ
 StyleSheet* nsLayoutStylesheetCache::GetUserContentSheet() {
   return mUserContentSheet;
 }
 
 StyleSheet* nsLayoutStylesheetCache::GetUserChromeSheet() {
   return mUserChromeSheet;
 }
 
-StyleSheet* nsLayoutStylesheetCache::ChromePreferenceSheet(
-    nsPresContext* aPresContext) {
+StyleSheet* nsLayoutStylesheetCache::ChromePreferenceSheet() {
   if (!mChromePreferenceSheet) {
-    BuildPreferenceSheet(&mChromePreferenceSheet, aPresContext);
+    BuildPreferenceSheet(&mChromePreferenceSheet,
+                         PreferenceSheet::ChromePrefs());
   }
 
   return mChromePreferenceSheet;
 }
 
-StyleSheet* nsLayoutStylesheetCache::ContentPreferenceSheet(
-    nsPresContext* aPresContext) {
+StyleSheet* nsLayoutStylesheetCache::ContentPreferenceSheet() {
   if (!mContentPreferenceSheet) {
-    BuildPreferenceSheet(&mContentPreferenceSheet, aPresContext);
+    BuildPreferenceSheet(&mContentPreferenceSheet,
+                         PreferenceSheet::ContentPrefs());
   }
 
   return mContentPreferenceSheet;
 }
 
 void nsLayoutStylesheetCache::Shutdown() {
   gCSSLoader = nullptr;
   NS_WARNING_ASSERTION(!gStyleCache || !gUserContentSheetURL,
@@ -315,17 +315,17 @@ void nsLayoutStylesheetCache::LoadSheet(
 void nsLayoutStylesheetCache::InvalidatePreferenceSheets() {
   if (gStyleCache) {
     gStyleCache->mContentPreferenceSheet = nullptr;
     gStyleCache->mChromePreferenceSheet = nullptr;
   }
 }
 
 void nsLayoutStylesheetCache::BuildPreferenceSheet(
-    RefPtr<StyleSheet>* aSheet, nsPresContext* aPresContext) {
+    RefPtr<StyleSheet>* aSheet, const PreferenceSheet::Prefs& aPrefs) {
   *aSheet = new StyleSheet(eAgentSheetFeatures, CORS_NONE,
                            mozilla::net::RP_Unset, dom::SRIMetadata());
 
   StyleSheet* sheet = *aSheet;
 
   nsCOMPtr<nsIURI> uri;
   NS_NewURI(getter_AddRefs(uri), "about:PreferenceStyleSheet", nullptr);
   MOZ_ASSERT(uri, "URI creation shouldn't fail");
@@ -341,38 +341,37 @@ void nsLayoutStylesheetCache::BuildPrefe
 #define NS_GET_R_G_B(color_) \
   NS_GET_R(color_), NS_GET_G(color_), NS_GET_B(color_)
 
   sheetText.AppendLiteral(
       "@namespace url(http://www.w3.org/1999/xhtml);\n"
       "@namespace svg url(http://www.w3.org/2000/svg);\n");
 
   // Rules for link styling.
-  nscolor linkColor = aPresContext->DefaultLinkColor();
-  nscolor activeColor = aPresContext->DefaultActiveLinkColor();
-  nscolor visitedColor = aPresContext->DefaultVisitedLinkColor();
+  nscolor linkColor = aPrefs.mLinkColor;
+  nscolor activeColor = aPrefs.mActiveLinkColor;
+  nscolor visitedColor = aPrefs.mVisitedLinkColor;
 
   sheetText.AppendPrintf(
       "*|*:link { color: #%02x%02x%02x; }\n"
       "*|*:any-link:active { color: #%02x%02x%02x; }\n"
       "*|*:visited { color: #%02x%02x%02x; }\n",
       NS_GET_R_G_B(linkColor), NS_GET_R_G_B(activeColor),
       NS_GET_R_G_B(visitedColor));
 
-  bool underlineLinks =
-      aPresContext->GetCachedBoolPref(kPresContext_UnderlineLinks);
+  bool underlineLinks = aPrefs.mUnderlineLinks;
   sheetText.AppendPrintf("*|*:any-link%s { text-decoration: %s; }\n",
                          underlineLinks ? ":not(svg|a)" : "",
                          underlineLinks ? "underline" : "none");
 
   // Rules for focus styling.
 
-  bool focusRingOnAnything = aPresContext->GetFocusRingOnAnything();
-  uint8_t focusRingWidth = aPresContext->FocusRingWidth();
-  uint8_t focusRingStyle = aPresContext->GetFocusRingStyle();
+  bool focusRingOnAnything = aPrefs.mFocusRingOnAnything;
+  uint8_t focusRingWidth = aPrefs.mFocusRingWidth;
+  uint8_t focusRingStyle = aPrefs.mFocusRingStyle;
 
   if ((focusRingWidth != 1 && focusRingWidth <= 4) || focusRingOnAnything) {
     if (focusRingWidth != 1) {
       // If the focus ring width is different from the default, fix buttons
       // with rings.
       sheetText.AppendPrintf(
           "button::-moz-focus-inner, input[type=\"reset\"]::-moz-focus-inner, "
           "input[type=\"button\"]::-moz-focus-inner, "
@@ -395,19 +394,19 @@ void nsLayoutStylesheetCache::BuildPrefe
         focusRingStyle == 0 ?  // solid
             "solid -moz-mac-focusring"
                             : "dotted WindowText",
         focusRingStyle == 0 ?  // solid
             "-moz-outline-radius: 3px; outline-offset: 1px; "
                             : "");
   }
 
-  if (aPresContext->GetUseFocusColors()) {
-    nscolor focusText = aPresContext->FocusTextColor();
-    nscolor focusBG = aPresContext->FocusBackgroundColor();
+  if (aPrefs.mUseFocusColors) {
+    nscolor focusText = aPrefs.mFocusTextColor;
+    nscolor focusBG = aPrefs.mFocusBackgroundColor;
     sheetText.AppendPrintf(
         "*:focus, *:focus > font { color: #%02x%02x%02x !important; "
         "background-color: #%02x%02x%02x !important; }\n",
         NS_GET_R_G_B(focusText), NS_GET_R_G_B(focusBG));
   }
 
   NS_ASSERTION(sheetText.Length() <= kPreallocSize,
                "kPreallocSize should be big enough to build preference style "
--- a/layout/style/nsLayoutStylesheetCache.h
+++ b/layout/style/nsLayoutStylesheetCache.h
@@ -6,16 +6,17 @@
 
 #ifndef nsLayoutStylesheetCache_h__
 #define nsLayoutStylesheetCache_h__
 
 #include "nsIMemoryReporter.h"
 #include "nsIObserver.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/PreferenceSheet.h"
 #include "mozilla/NotNull.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/css/Loader.h"
 
 class nsIFile;
 class nsIURI;
 
 namespace mozilla {
@@ -41,18 +42,18 @@ class nsLayoutStylesheetCache final : pu
 
 #define STYLE_SHEET(identifier_, url_, lazy_) \
   mozilla::NotNull<mozilla::StyleSheet*> identifier_##Sheet();
 #include "mozilla/UserAgentStyleSheetList.h"
 #undef STYLE_SHEET
 
   mozilla::StyleSheet* GetUserContentSheet();
   mozilla::StyleSheet* GetUserChromeSheet();
-  mozilla::StyleSheet* ChromePreferenceSheet(nsPresContext* aPresContext);
-  mozilla::StyleSheet* ContentPreferenceSheet(nsPresContext* aPresContext);
+  mozilla::StyleSheet* ChromePreferenceSheet();
+  mozilla::StyleSheet* ContentPreferenceSheet();
 
   static void InvalidatePreferenceSheets();
 
   static void Shutdown();
 
   static void SetUserContentCSSURL(nsIURI* aURI);
 
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
@@ -68,17 +69,17 @@ class nsLayoutStylesheetCache final : pu
                     mozilla::css::FailureAction aFailureAction);
   void LoadSheetFile(nsIFile* aFile, RefPtr<mozilla::StyleSheet>* aSheet,
                      mozilla::css::SheetParsingMode aParsingMode,
                      mozilla::css::FailureAction aFailureAction);
   void LoadSheet(nsIURI* aURI, RefPtr<mozilla::StyleSheet>* aSheet,
                  mozilla::css::SheetParsingMode aParsingMode,
                  mozilla::css::FailureAction aFailureAction);
   void BuildPreferenceSheet(RefPtr<mozilla::StyleSheet>* aSheet,
-                            nsPresContext* aPresContext);
+                            const mozilla::PreferenceSheet::Prefs&);
 
   static mozilla::StaticRefPtr<nsLayoutStylesheetCache> gStyleCache;
   static mozilla::StaticRefPtr<mozilla::css::Loader> gCSSLoader;
   static mozilla::StaticRefPtr<nsIURI> gUserContentSheetURL;
 
 #define STYLE_SHEET(identifier_, url_, lazy_) \
   RefPtr<mozilla::StyleSheet> m##identifier_##Sheet;
 #include "mozilla/UserAgentStyleSheetList.h"
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -30,16 +30,17 @@
 #include "imgIContainer.h"
 #include "CounterStyleManager.h"
 
 #include "mozilla/dom/AnimationEffectBinding.h"  // for PlaybackDirection
 #include "mozilla/dom/DocGroup.h"
 #include "mozilla/dom/ImageTracker.h"
 #include "mozilla/CORSMode.h"
 #include "mozilla/ClearOnShutdown.h"
+#include "mozilla/PreferenceSheet.h"
 #include "mozilla/Likely.h"
 #include "nsIURI.h"
 #include "mozilla/dom/Document.h"
 #include <algorithm>
 #include "ImageLoader.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
@@ -1661,18 +1662,17 @@ nsChangeHint nsStyleTableBorder::CalcDif
   }
 }
 
 // --------------------
 // nsStyleColor
 //
 
 static nscolor DefaultColor(const Document& aDocument) {
-  auto* pc = aDocument.GetPresContext();
-  return pc ? pc->DefaultColor() : NS_RGB(0, 0, 0);
+  return PreferenceSheet::PrefsFor(aDocument).mDefaultColor;
 }
 
 nsStyleColor::nsStyleColor(const Document& aDocument)
     : mColor(DefaultColor(aDocument)) {
   MOZ_COUNT_CTOR(nsStyleColor);
 }
 
 nsStyleColor::nsStyleColor(const nsStyleColor& aSource)
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -549,16 +549,64 @@ VARCACHE_PREF(
 
 VARCACHE_PREF(
   "full-screen-api.unprefix.enabled",
    full_screen_api_unprefix_enabled,
   bool, true
 )
 
 //---------------------------------------------------------------------------
+// Preference stylesheet prefs.
+//---------------------------------------------------------------------------
+
+VARCACHE_PREF(
+  "browser.display.focus_ring_on_anything",
+   browser_display_focus_ring_on_anything,
+  bool, false
+)
+
+VARCACHE_PREF(
+  "browser.display.focus_ring_width",
+   browser_display_focus_ring_width,
+  uint32_t, 1
+)
+
+VARCACHE_PREF(
+  "browser.display.focus_ring_style",
+   browser_display_focus_ring_style,
+  bool, false
+)
+
+VARCACHE_PREF(
+  "browser.display.use_system_colors",
+   browser_display_use_system_colors,
+  bool, true
+)
+
+VARCACHE_PREF(
+  "browser.display.use_focus_colors",
+   browser_display_use_focus_colors,
+  bool, false
+)
+
+VARCACHE_PREF(
+  "browser.underline_anchors",
+   browser_underline_anchors,
+  bool, true
+)
+
+PREF("browser.display.foreground_color", String, "")
+PREF("browser.display.background_color", String, "")
+PREF("browser.display.focus_background_color", String, "")
+PREF("browser.display.focus_text_color", String, "")
+PREF("browser.anchor_color", String, "")
+PREF("browser.active_color", String, "")
+PREF("browser.visited_color", String, "")
+
+//---------------------------------------------------------------------------
 // Graphics prefs
 //---------------------------------------------------------------------------
 
 // In theory: 0 = never, 1 = quick, 2 = always, though we always just use it as
 // a bool!
 VARCACHE_PREF(
   "browser.display.use_document_fonts",
    browser_display_use_document_fonts,
--- a/servo/components/style/gecko/data.rs
+++ b/servo/components/style/gecko/data.rs
@@ -145,17 +145,17 @@ impl PerDocumentStyleData {
     /// Create a dummy `PerDocumentStyleData`.
     pub fn new(pres_context: RawGeckoPresContextBorrowed) -> Self {
         let device = Device::new(pres_context);
 
         // FIXME(emilio, tlin): How is this supposed to work with XBL? This is
         // right now not always honored, see bug 1405543...
         //
         // Should we just force XBL Stylists to be NoQuirks?
-        let quirks_mode = unsafe { (*device.pres_context().mDocument.mRawPtr).mCompatMode };
+        let quirks_mode = device.document().mCompatMode;
 
         PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl {
             stylist: Stylist::new(device, quirks_mode.into()),
         }))
     }
 
     /// Get an immutable reference to this style data.
     pub fn borrow(&self) -> AtomicRef<PerDocumentStyleDataImpl> {
@@ -186,18 +186,17 @@ impl PerDocumentStyleDataImpl {
     /// Get the default computed values for this document.
     pub fn default_computed_values(&self) -> &Arc<ComputedValues> {
         self.stylist.device().default_computed_values_arc()
     }
 
     /// Returns whether visited styles are enabled.
     #[inline]
     pub fn visited_styles_enabled(&self) -> bool {
-        let doc = self.stylist.device().pres_context().mDocument.mRawPtr;
-        unsafe { bindings::Gecko_VisitedStylesEnabled(doc) }
+        unsafe { bindings::Gecko_VisitedStylesEnabled(self.stylist.device().document()) }
     }
 
     /// Measure heap usage.
     pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
         self.stylist.add_size_of(ops, sizes);
     }
 }
 
--- a/servo/components/style/gecko/media_queries.rs
+++ b/servo/components/style/gecko/media_queries.rs
@@ -78,24 +78,24 @@ impl fmt::Debug for Device {
 
 unsafe impl Sync for Device {}
 unsafe impl Send for Device {}
 
 impl Device {
     /// Trivially constructs a new `Device`.
     pub fn new(pres_context: RawGeckoPresContextBorrowed) -> Self {
         assert!(!pres_context.is_null());
+        let doc = unsafe { &*(*pres_context).mDocument.mRawPtr };
+        let prefs = unsafe { &*bindings::Gecko_GetPrefSheetPrefs(doc) };
         Device {
             pres_context,
-            default_values: ComputedValues::default_values(unsafe {
-                &*(*pres_context).mDocument.mRawPtr
-            }),
+            default_values: ComputedValues::default_values(doc),
             // FIXME(bz): Seems dubious?
             root_font_size: AtomicIsize::new(FontSize::medium().size().0 as isize),
-            body_text_color: AtomicUsize::new(unsafe { &*pres_context }.mDefaultColor as usize),
+            body_text_color: AtomicUsize::new(prefs.mDefaultColor as usize),
             used_root_font_size: AtomicBool::new(false),
             used_viewport_size: AtomicBool::new(false),
             environment: CssEnvironment,
         }
     }
 
     /// Get the relevant environment to resolve `env()` functions.
     #[inline]
@@ -163,16 +163,22 @@ impl Device {
     }
 
     /// Gets the document pointer.
     #[inline]
     pub fn document(&self) -> &structs::Document {
         unsafe { &*self.pres_context().mDocument.mRawPtr }
     }
 
+    /// Gets the preference stylesheet prefs for our document.
+    #[inline]
+    pub fn pref_sheet_prefs(&self) -> &structs::PreferenceSheet_Prefs {
+        unsafe { &*bindings::Gecko_GetPrefSheetPrefs(self.document()) }
+    }
+
     /// Recreates the default computed values.
     pub fn reset_computed_values(&mut self) {
         self.default_values = ComputedValues::default_values(self.document());
     }
 
     /// Rebuild all the cached data.
     pub fn rebuild_cached_data(&mut self) {
         self.reset_computed_values();
@@ -238,17 +244,17 @@ impl Device {
 
     /// Returns whether document colors are enabled.
     pub fn use_document_colors(&self) -> bool {
         self.pres_context().mUseDocumentColors() != 0
     }
 
     /// Returns the default background color.
     pub fn default_background_color(&self) -> RGBA {
-        convert_nscolor_to_rgba(self.pres_context().mBackgroundColor)
+        convert_nscolor_to_rgba(self.pref_sheet_prefs().mDefaultBackgroundColor)
     }
 
     /// Applies text zoom to a font-size or line-height value (see nsStyleFont::ZoomText).
     #[inline]
     pub fn zoom_text(&self, size: Au) -> Au {
         size.scale_by(self.pres_context().mEffectiveTextZoom)
     }
 
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -1238,17 +1238,17 @@ impl<'le> TElement for GeckoElement<'le>
 
     #[inline]
     fn as_node(&self) -> Self::ConcreteNode {
         unsafe { GeckoNode(&*(self.0 as *const _ as *const RawGeckoNode)) }
     }
 
     fn owner_doc_matches_for_testing(&self, device: &Device) -> bool {
         self.as_node().owner_doc().0 as *const structs::Document ==
-            device.pres_context().mDocument.mRawPtr
+            device.document() as *const _
     }
 
     fn style_attribute(&self) -> Option<ArcBorrow<Locked<PropertyDeclarationBlock>>> {
         if !self.may_have_style_attribute() {
             return None;
         }
 
         let declarations = unsafe { Gecko_GetStyleAttrDeclarationBlock(self.0) };
--- a/servo/components/style/values/specified/color.rs
+++ b/servo/components/style/values/specified/color.rs
@@ -345,23 +345,23 @@ impl Color {
             Color::Complex(ref complex) => Some(*complex),
             #[cfg(feature = "gecko")]
             Color::System(system) => _context
                 .map(|context| convert_nscolor_to_computedcolor(system.to_computed_value(context))),
             #[cfg(feature = "gecko")]
             Color::Special(special) => {
                 use self::gecko::SpecialColorKeyword as Keyword;
                 _context.map(|context| {
-                    let pres_context = context.device().pres_context();
+                    let prefs = context.device().pref_sheet_prefs();
                     convert_nscolor_to_computedcolor(match special {
-                        Keyword::MozDefaultColor => pres_context.mDefaultColor,
-                        Keyword::MozDefaultBackgroundColor => pres_context.mBackgroundColor,
-                        Keyword::MozHyperlinktext => pres_context.mLinkColor,
-                        Keyword::MozActivehyperlinktext => pres_context.mActiveLinkColor,
-                        Keyword::MozVisitedhyperlinktext => pres_context.mVisitedLinkColor,
+                        Keyword::MozDefaultColor => prefs.mDefaultColor,
+                        Keyword::MozDefaultBackgroundColor => prefs.mDefaultBackgroundColor,
+                        Keyword::MozHyperlinktext => prefs.mLinkColor,
+                        Keyword::MozActivehyperlinktext => prefs.mActiveLinkColor,
+                        Keyword::MozVisitedhyperlinktext => prefs.mVisitedLinkColor,
                     })
                 })
             },
             #[cfg(feature = "gecko")]
             Color::InheritFromBodyQuirk => {
                 _context.map(|context| ComputedColor::rgba(context.device().body_text_color()))
             },
         }