Bug 1530751 - Make the pres context optional in the style system. r=jwatt
authorEmilio Cobos Álvarez <emilio@crisal.io>
Wed, 06 Mar 2019 21:36:12 +0000
changeset 520593 26ac004eeb4cc3876cf822e91ef25206586a1537
parent 520592 2e2dd6d6d5762cd5a60acdb1f14efadf76dcf490
child 520594 1e12deff6c1e0a6c5cabc0374627a52499ae880d
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
bugs1530751
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 1530751 - Make the pres context optional in the style system. r=jwatt Differential Revision: https://phabricator.services.mozilla.com/D21239
layout/base/nsPresContext.cpp
layout/base/nsPresContext.h
layout/style/PreferenceSheet.cpp
layout/style/PreferenceSheet.h
layout/style/ServoBindings.h
modules/libpref/init/StaticPrefList.h
servo/components/style/gecko/data.rs
servo/components/style/gecko/media_features.rs
servo/components/style/gecko/media_queries.rs
servo/components/style/gecko/wrapper.rs
servo/ports/geckolib/glue.rs
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -165,17 +165,16 @@ nsPresContext::nsPresContext(dom::Docume
       mInterruptChecksToSkip(0),
       mElementsRestyled(0),
       mFramesConstructed(0),
       mFramesReflowed(0),
       mInteractionTimeEnabled(true),
       mHasPendingInterrupt(false),
       mPendingInterruptFromTest(false),
       mInterruptsEnabled(false),
-      mUseDocumentColors(true),
       mSendAfterPaintToContent(false),
       mUseFocusColors(false),
       mDrawImageBackground(true),  // always draw the background
       mDrawColorBackground(true),
       // mNeverAnimate is initialised below, in constructor body
       mPaginated(aType != eContext_Galley),
       mCanPaginatedScroll(false),
       mDoScaledTwips(true),
@@ -339,38 +338,16 @@ bool nsPresContext::IsChromeOriginImage(
 }
 
 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();
   PreferenceSheet::EnsureInitialized();
-
-  static int32_t sDocumentColorsSetting;
-  static bool sDocumentColorsSettingPrefCached = false;
-  if (!sDocumentColorsSettingPrefCached) {
-    sDocumentColorsSettingPrefCached = true;
-    Preferences::AddIntVarCache(&sDocumentColorsSetting,
-                                "browser.display.document_color_use", 0);
-  }
-
-  // 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 {
-    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.
     return;
   }
@@ -1657,19 +1634,19 @@ bool nsPresContext::HasAuthorSpecifiedRu
     return false;
   }
 
   // Anonymous boxes are more complicated, and we just assume that they
   // cannot have any author-specified rules here.
   if (aFrame->Style()->IsAnonBox()) {
     return false;
   }
-  return Servo_HasAuthorSpecifiedRules(aFrame->Style(), elem,
-                                       aFrame->Style()->GetPseudoType(),
-                                       aRuleTypeMask, UseDocumentColors());
+
+  auto* set = PresShell()->StyleSet()->RawSet();
+  return Servo_HasAuthorSpecifiedRules(set, aFrame->Style(), elem, aRuleTypeMask);
 }
 
 gfxUserFontSet* nsPresContext::GetUserFontSet() {
   return mDocument->GetUserFontSet();
 }
 
 void nsPresContext::UserFontSetUpdated(gfxUserFontEntry* aUpdatedFont) {
   if (!mShell) return;
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -836,24 +836,16 @@ class nsPresContext : public nsISupports
   // Is this presentation in a chrome docshell?
   bool IsChrome() const;
   bool IsChromeOriginImage() const;
 
   // Public API for native theme code to get style internals.
   bool HasAuthorSpecifiedRules(const nsIFrame* aFrame,
                                uint32_t ruleTypeMask) const;
 
-  // Is it OK to let the page specify colors and backgrounds?
-  bool UseDocumentColors() const {
-    MOZ_ASSERT(mUseDocumentColors || !(IsChrome() || IsChromeOriginImage()),
-               "We should never have a chrome doc or image that can't use its "
-               "colors.");
-    return mUseDocumentColors;
-  }
-
   // Explicitly enable and disable paint flashing.
   void SetPaintFlashing(bool aPaintFlashing) {
     mPaintFlashing = aPaintFlashing;
     mPaintFlashingInitialized = true;
   }
 
   // This method should be used instead of directly accessing mPaintFlashing,
   // as that value may be out of date when mPaintFlashingInitialized is false.
@@ -1222,17 +1214,16 @@ class nsPresContext : public nsISupports
   bool mInteractionTimeEnabled;
 
   // last time we did a full style flush
   mozilla::TimeStamp mLastStyleUpdateForAllAnimations;
 
   unsigned mHasPendingInterrupt : 1;
   unsigned mPendingInterruptFromTest : 1;
   unsigned mInterruptsEnabled : 1;
-  unsigned mUseDocumentColors : 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;
--- a/layout/style/PreferenceSheet.cpp
+++ b/layout/style/PreferenceSheet.cpp
@@ -34,32 +34,34 @@ static void GetColor(const char* aPrefNa
   aColor = result;
 }
 
 bool PreferenceSheet::ShouldUseChromePrefs(const Document& aDoc) {
   return aDoc.IsInChromeDocShell() ||
     (aDoc.IsBeingUsedAsImage() && aDoc.IsDocumentURISchemeChrome());
 }
 
-bool PreferenceSheet::UseAccessibilityTheme(bool aIsChrome) {
+static bool UseAccessibilityTheme(bool aIsChrome) {
   return !aIsChrome &&
          !!LookAndFeel::GetInt(LookAndFeel::eIntID_UseAccessibilityTheme, 0);
 }
 
 void PreferenceSheet::Prefs::Load(bool aIsChrome) {
   *this = {};
 
+  mIsChrome = aIsChrome;
+  mUseAccessibilityTheme = UseAccessibilityTheme(aIsChrome);
   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) &&
+  const bool usePrefColors = !aIsChrome && !mUseAccessibilityTheme &&
                              !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) {
--- a/layout/style/PreferenceSheet.h
+++ b/layout/style/PreferenceSheet.h
@@ -26,16 +26,19 @@ struct PreferenceSheet {
     nscolor mDefaultColor = NS_RGB(0, 0, 0);
     nscolor mDefaultBackgroundColor = NS_RGB(0xFF, 0xFF, 0xFF);
 
     nscolor mLinkBackgroundColor = mDefaultBackgroundColor;
 
     nscolor mFocusTextColor = mDefaultColor;
     nscolor mFocusBackgroundColor = mDefaultBackgroundColor;
 
+    bool mIsChrome = false;
+    bool mUseAccessibilityTheme = false;
+
     bool mUnderlineLinks = true;
     bool mUseFocusColors = false;
     uint8_t mFocusRingWidth = 1;
     bool mFocusRingStyle = false;
     bool mFocusRingOnAnything = false;
 
     void Load(bool aIsChrome);
   };
@@ -58,17 +61,16 @@ struct PreferenceSheet {
   }
 
   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;
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -831,21 +831,20 @@ ComputedStyleStrong Servo_ResolvePseudoS
 ComputedStyleStrong Servo_ComputedValues_ResolveXULTreePseudoStyle(
     RawGeckoElementBorrowed element, nsAtom* pseudo_tag,
     ComputedStyleBorrowed inherited_style, const mozilla::AtomArray* input_word,
     RawServoStyleSetBorrowed set);
 
 void Servo_SetExplicitStyle(RawGeckoElementBorrowed element,
                             ComputedStyleBorrowed primary_style);
 
-bool Servo_HasAuthorSpecifiedRules(ComputedStyleBorrowed style,
+bool Servo_HasAuthorSpecifiedRules(RawServoStyleSetBorrowed set,
+                                   ComputedStyleBorrowed style,
                                    RawGeckoElementBorrowed element,
-                                   mozilla::PseudoStyleType pseudo_type,
-                                   uint32_t rule_type_mask,
-                                   bool author_colors_allowed);
+                                   uint32_t rule_type_mask);
 
 // Resolves style for an element or pseudo-element without processing pending
 // restyles first. The Element and its ancestors may be unstyled, have pending
 // restyles, or be in a display:none subtree. Styles are cached when possible,
 // though caching is not possible within display:none subtrees, and the styles
 // may be invalidated by already-scheduled restyles.
 //
 // The tree must be in a consistent state such that a normal traversal could be
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -576,16 +576,24 @@ VARCACHE_PREF(
 )
 
 VARCACHE_PREF(
   "browser.display.use_system_colors",
    browser_display_use_system_colors,
   bool, true
 )
 
+// 0 = default: always, except in high contrast mode
+// 1 = always
+// 2 = never
+VARCACHE_PREF(
+  "browser.display.document_color_use",
+   browser_display_document_color_use,
+  uint32_t, 0
+)
 VARCACHE_PREF(
   "browser.display.use_focus_colors",
    browser_display_use_focus_colors,
   bool, false
 )
 
 VARCACHE_PREF(
   "browser.underline_anchors",
--- a/servo/components/style/gecko/data.rs
+++ b/servo/components/style/gecko/data.rs
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
 
 //! Data needed to style a Gecko document.
 
 use crate::context::QuirksMode;
 use crate::dom::TElement;
 use crate::gecko_bindings::bindings::{self, RawServoStyleSet};
-use crate::gecko_bindings::structs::{RawGeckoPresContextBorrowed, ServoStyleSetSizes};
+use crate::gecko_bindings::structs::{self, ServoStyleSetSizes};
 use crate::gecko_bindings::structs::{StyleSheet as DomStyleSheet, StyleSheetInfo};
 use crate::gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI};
 use crate::invalidation::media_queries::{MediaListKey, ToMediaListKey};
 use crate::media_queries::{Device, MediaList};
 use crate::properties::ComputedValues;
 use crate::selector_parser::SnapshotMap;
 use crate::shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
 use crate::stylesheets::{CssRule, Origin, StylesheetContents, StylesheetInDocument};
@@ -137,19 +137,19 @@ pub struct PerDocumentStyleDataImpl {
     pub stylist: Stylist,
 }
 
 /// The data itself is an `AtomicRefCell`, which guarantees the proper semantics
 /// and unexpected races while trying to mutate it.
 pub struct PerDocumentStyleData(AtomicRefCell<PerDocumentStyleDataImpl>);
 
 impl PerDocumentStyleData {
-    /// Create a dummy `PerDocumentStyleData`.
-    pub fn new(pres_context: RawGeckoPresContextBorrowed) -> Self {
-        let device = Device::new(pres_context);
+    /// Create a `PerDocumentStyleData`.
+    pub fn new(document: *const structs::Document) -> Self {
+        let device = Device::new(document);
 
         // 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 = device.document().mCompatMode;
 
         PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl {
--- a/servo/components/style/gecko/media_features.rs
+++ b/servo/components/style/gecko/media_features.rs
@@ -12,22 +12,23 @@ use crate::media_queries::media_feature_
 use crate::media_queries::{Device, MediaType};
 use crate::values::computed::CSSPixelLength;
 use crate::values::computed::Resolution;
 use crate::Atom;
 use app_units::Au;
 use euclid::Size2D;
 
 fn viewport_size(device: &Device) -> Size2D<Au> {
-    let pc = device.pres_context();
-    if pc.mIsRootPaginatedDocument() != 0 {
-        // We want the page size, including unprintable areas and margins.
-        // FIXME(emilio, bug 1414600): Not quite!
-        let area = &pc.mPageSize;
-        return Size2D::new(Au(area.width), Au(area.height));
+    if let Some(pc) = device.pres_context() {
+        if pc.mIsRootPaginatedDocument() != 0 {
+            // We want the page size, including unprintable areas and margins.
+            // FIXME(emilio, bug 1414600): Not quite!
+            let area = &pc.mPageSize;
+            return Size2D::new(Au(area.width), Au(area.height));
+        }
     }
     device.au_viewport_size()
 }
 
 fn device_size(device: &Device) -> Size2D<Au> {
     let mut width = 0;
     let mut height = 0;
     unsafe {
--- a/servo/components/style/gecko/media_queries.rs
+++ b/servo/components/style/gecko/media_queries.rs
@@ -3,17 +3,16 @@
  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
 
 //! Gecko's media-query device and expression representation.
 
 use crate::custom_properties::CssEnvironment;
 use crate::gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor};
 use crate::gecko_bindings::bindings;
 use crate::gecko_bindings::structs;
-use crate::gecko_bindings::structs::{nsPresContext, RawGeckoPresContextBorrowed};
 use crate::media_queries::MediaType;
 use crate::properties::ComputedValues;
 use crate::string_cache::Atom;
 use crate::values::computed::font::FontSize;
 use crate::values::{CustomIdent, KeyframesName};
 use app_units::Au;
 use app_units::AU_PER_PX;
 use cssparser::RGBA;
@@ -23,20 +22,19 @@ use servo_arc::Arc;
 use std::fmt;
 use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize, Ordering};
 use style_traits::viewport::ViewportConstraints;
 use style_traits::{CSSPixel, DevicePixel};
 
 /// The `Device` in Gecko wraps a pres context, has a default values computed,
 /// and contains all the viewport rule state.
 pub struct Device {
-    /// NB: The pres context lifetime is tied to the styleset, who owns the
-    /// stylist, and thus the `Device`, so having a raw pres context pointer
-    /// here is fine.
-    pres_context: RawGeckoPresContextBorrowed,
+    /// NB: The document owns the styleset, who owns the stylist, and thus the
+    /// `Device`, so having a raw document pointer here is fine.
+    document: *const structs::Document,
     default_values: Arc<ComputedValues>,
     /// The font size of the root element
     /// This is set when computing the style of the root
     /// element, and used for rem units in other elements.
     ///
     /// When computing the style of the root element, there can't be any
     /// other style being computed at the same time, given we need the style of
     /// the parent to compute everything else. So it is correct to just use
@@ -76,22 +74,22 @@ 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 };
+    pub fn new(document: *const structs::Document) -> Self {
+        assert!(!document.is_null());
+        let doc = unsafe { &*document };
         let prefs = unsafe { &*bindings::Gecko_GetPrefSheetPrefs(doc) };
         Device {
-            pres_context,
+            document,
             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(prefs.mDefaultColor as usize),
             used_root_font_size: AtomicBool::new(false),
             used_viewport_size: AtomicBool::new(false),
             environment: CssEnvironment,
         }
@@ -107,19 +105,24 @@ impl Device {
     /// relevant viewport constraints.
     pub fn account_for_viewport_rule(&mut self, _constraints: &ViewportConstraints) {
         unreachable!("Gecko doesn't support @viewport");
     }
 
     /// Whether any animation name may be referenced from the style of any
     /// element.
     pub fn animation_name_may_be_referenced(&self, name: &KeyframesName) -> bool {
+        let pc = match self.pres_context() {
+            Some(pc) => pc,
+            None => return false,
+        };
+
         unsafe {
             bindings::Gecko_AnimationNameMayBeReferencedFromStyle(
-                self.pres_context(),
+                pc,
                 name.as_atom().as_ptr(),
             )
         }
     }
 
     /// Returns the default computed values as a reference, in order to match
     /// Servo.
     pub fn default_computed_values(&self) -> &ComputedValues {
@@ -151,26 +154,28 @@ impl Device {
             .store(convert_rgba_to_nscolor(&color) as usize, Ordering::Relaxed)
     }
 
     /// Returns the body text color.
     pub fn body_text_color(&self) -> RGBA {
         convert_nscolor_to_rgba(self.body_text_color.load(Ordering::Relaxed) as u32)
     }
 
-    /// Gets the pres context associated with this document.
-    #[inline]
-    pub fn pres_context(&self) -> &nsPresContext {
-        unsafe { &*self.pres_context }
-    }
-
     /// Gets the document pointer.
     #[inline]
     pub fn document(&self) -> &structs::Document {
-        unsafe { &*self.pres_context().mDocument.mRawPtr }
+        unsafe { &*self.document }
+    }
+
+    /// Gets the pres context associated with this document.
+    #[inline]
+    pub fn pres_context(&self) -> Option<&structs::nsPresContext> {
+        unsafe {
+            self.document().mPresShell.as_ref()?.mPresContext.mRawPtr.as_ref()
+        }
     }
 
     /// Gets the preference stylesheet prefs for our document.
     #[inline]
     pub fn pref_sheet_prefs(&self) -> &structs::PreferenceSheet_Prefs {
         unsafe { &*bindings::Gecko_GetPrefSheetPrefs(self.document()) }
     }
 
@@ -196,31 +201,39 @@ impl Device {
     /// This includes the viewport override from `@viewport` rules, and also the
     /// default computed values.
     pub fn reset(&mut self) {
         self.reset_computed_values();
     }
 
     /// Returns the current media type of the device.
     pub fn media_type(&self) -> MediaType {
+        let pc = match self.pres_context() {
+            Some(pc) => pc,
+            None => return MediaType::screen(),
+        };
+
         // Gecko allows emulating random media with mIsEmulatingMedia and
         // mMediaEmulated.
-        let context = self.pres_context();
-        let medium_to_use = if context.mIsEmulatingMedia() != 0 {
-            context.mMediaEmulated.mRawPtr
+        let medium_to_use = if pc.mIsEmulatingMedia() != 0 {
+            pc.mMediaEmulated.mRawPtr
         } else {
-            context.mMedium
+            pc.mMedium
         };
 
         MediaType(CustomIdent(unsafe { Atom::from_raw(medium_to_use) }))
     }
 
     /// Returns the current viewport size in app units.
     pub fn au_viewport_size(&self) -> Size2D<Au> {
-        let area = &self.pres_context().mVisibleArea;
+        let pc = match self.pres_context() {
+            Some(pc) => pc,
+            None => return Size2D::new(Au(0), Au(0)),
+        };
+        let area = &pc.mVisibleArea;
         Size2D::new(Au(area.width), Au(area.height))
     }
 
     /// Returns the current viewport size in app units, recording that it's been
     /// used for viewport unit resolution.
     pub fn au_viewport_size_for_viewport_unit_resolution(&self) -> Size2D<Au> {
         self.used_viewport_size.store(true, Ordering::Relaxed);
         self.au_viewport_size()
@@ -228,39 +241,68 @@ impl Device {
 
     /// Returns whether we ever looked up the viewport size of the Device.
     pub fn used_viewport_size(&self) -> bool {
         self.used_viewport_size.load(Ordering::Relaxed)
     }
 
     /// Returns the device pixel ratio.
     pub fn device_pixel_ratio(&self) -> TypedScale<f32, CSSPixel, DevicePixel> {
-        let override_dppx = self.pres_context().mOverrideDPPX;
+        let pc = match self.pres_context() {
+            Some(pc) => pc,
+            None => return TypedScale::new(1.),
+        };
+
+        let override_dppx = pc.mOverrideDPPX;
         if override_dppx > 0.0 {
             return TypedScale::new(override_dppx);
         }
-        let au_per_dpx = self.pres_context().mCurAppUnitsPerDevPixel as f32;
+
+        let au_per_dpx = pc.mCurAppUnitsPerDevPixel as f32;
         let au_per_px = AU_PER_PX as f32;
         TypedScale::new(au_per_px / au_per_dpx)
     }
 
     /// Returns whether document colors are enabled.
+    #[inline]
     pub fn use_document_colors(&self) -> bool {
-        self.pres_context().mUseDocumentColors() != 0
+        let doc = self.document();
+        if doc.mIsBeingUsedAsImage() {
+            return true;
+        }
+        let document_color_use = unsafe {
+            structs::StaticPrefs_sVarCache_browser_display_document_color_use
+        };
+        let prefs = self.pref_sheet_prefs();
+        match document_color_use {
+            1 => true,
+            2 => prefs.mIsChrome,
+            _ => !prefs.mUseAccessibilityTheme,
+        }
     }
 
     /// Returns the default background color.
     pub fn default_background_color(&self) -> RGBA {
         convert_nscolor_to_rgba(self.pref_sheet_prefs().mDefaultBackgroundColor)
     }
 
+    /// Returns the current effective text zoom.
+    #[inline]
+    fn effective_text_zoom(&self) -> f32 {
+        let pc = match self.pres_context() {
+            Some(pc) => pc,
+            None => return 1.,
+        };
+        pc.mEffectiveTextZoom
+    }
+
     /// 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)
+        size.scale_by(self.effective_text_zoom())
     }
 
     /// Un-apply text zoom.
     #[inline]
     pub fn unzoom_text(&self, size: Au) -> Au {
-        size.scale_by(1. / self.pres_context().mEffectiveTextZoom)
+        size.scale_by(1. / self.effective_text_zoom())
     }
 }
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -1039,19 +1039,23 @@ impl FontMetricsProvider for GeckoFontMe
         &self,
         font: &Font,
         font_size: Au,
         wm: WritingMode,
         in_media_query: bool,
         device: &Device,
     ) -> FontMetricsQueryResult {
         use crate::gecko_bindings::bindings::Gecko_GetFontMetrics;
+        let pc = match device.pres_context() {
+            Some(pc) => pc,
+            None => return FontMetricsQueryResult::NotAvailable,
+        };
         let gecko_metrics = unsafe {
             Gecko_GetFontMetrics(
-                device.pres_context(),
+                pc,
                 wm.is_vertical() && !wm.is_sideways(),
                 font.gecko(),
                 font_size.0,
                 // we don't use the user font set in a media query
                 !in_media_query,
             )
         };
         let metrics = FontMetrics {
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -3344,28 +3344,30 @@ pub extern "C" fn Servo_SetExplicitStyle
     // work for other things, we just haven't had a reason to do so.
     debug_assert!(element.get_data().is_none());
     let mut data = unsafe { element.ensure_data() };
     data.styles.primary = Some(unsafe { ArcBorrow::from_ref(style) }.clone_arc());
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_HasAuthorSpecifiedRules(
+    raw_data: RawServoStyleSetBorrowed,
     style: ComputedStyleBorrowed,
     element: RawGeckoElementBorrowed,
-    pseudo_type: PseudoStyleType,
     rule_type_mask: u32,
-    author_colors_allowed: bool,
 ) -> bool {
+    let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
     let element = GeckoElement(element);
-    let pseudo = PseudoElement::from_pseudo_type(pseudo_type);
 
     let guard = (*GLOBAL_STYLE_DATA).shared_lock.read();
     let guards = StylesheetGuards::same(&guard);
 
+    let pseudo = style.pseudo();
+    let author_colors_allowed = data.stylist.device().use_document_colors();
+
     style.rules().has_author_specified_rules(
         element,
         pseudo,
         &guards,
         rule_type_mask,
         author_colors_allowed,
     )
 }
@@ -3571,17 +3573,18 @@ pub extern "C" fn Servo_ComputedValues_G
 
 /// See the comment in `Device` to see why it's ok to pass an owned reference to
 /// the pres context (hint: the context outlives the StyleSet, that holds the
 /// device alive).
 #[no_mangle]
 pub extern "C" fn Servo_StyleSet_Init(
     pres_context: RawGeckoPresContextBorrowed,
 ) -> *mut RawServoStyleSet {
-    let data = Box::new(PerDocumentStyleData::new(pres_context));
+    let doc = pres_context.mDocument.mRawPtr;
+    let data = Box::new(PerDocumentStyleData::new(doc));
     Box::into_raw(data) as *mut RawServoStyleSet
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_StyleSet_RebuildCachedData(raw_data: RawServoStyleSetBorrowed) {
     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
     data.stylist.device_mut().rebuild_cached_data();
 }
@@ -3589,19 +3592,18 @@ pub extern "C" fn Servo_StyleSet_Rebuild
 #[no_mangle]
 pub extern "C" fn Servo_StyleSet_Drop(data: RawServoStyleSetOwned) {
     let _ = data.into_box::<PerDocumentStyleData>();
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn Servo_StyleSet_CompatModeChanged(raw_data: RawServoStyleSetBorrowed) {
     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
-    let doc = &*data.stylist.device().pres_context().mDocument.mRawPtr;
-    data.stylist
-        .set_quirks_mode(QuirksMode::from(doc.mCompatMode));
+    let quirks_mode = data.stylist.device().document().mCompatMode;
+    data.stylist.set_quirks_mode(quirks_mode.into());
 }
 
 fn parse_property_into(
     declarations: &mut SourcePropertyDeclaration,
     property_id: PropertyId,
     value: *const nsACString,
     data: *mut URLExtraData,
     parsing_mode: structs::ParsingMode,