servo: Merge #17828 - stylo: Visited link fixes (from emilio:visited-now); r=Manishearth
authorEmilio Cobos Álvarez <emilio@crisal.io>
Sun, 23 Jul 2017 13:46:43 -0700
changeset 419186 37c161b31cf5e7c2f460b0e37b372c45cfb57904
parent 419185 de668ab058ff8614980481e459fce96c44cb9342
child 419187 e170c7eca2c441a1453cbddfd8b16269a22ea868
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersManishearth
milestone56.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
servo: Merge #17828 - stylo: Visited link fixes (from emilio:visited-now); r=Manishearth Straight from https://bugzilla.mozilla.org/show_bug.cgi?id=1383307 Source-Repo: https://github.com/servo/servo Source-Revision: 2241d5879e5d66c52d2b4f17ad730c5de1eff364
servo/components/layout_thread/lib.rs
servo/components/style/context.rs
servo/components/style/gecko/data.rs
servo/components/style/gecko/generated/bindings.rs
servo/components/style/properties/properties.mako.rs
servo/components/style/style_adjuster.rs
servo/components/style/style_resolver.rs
servo/ports/geckolib/glue.rs
--- a/servo/components/layout_thread/lib.rs
+++ b/servo/components/layout_thread/lib.rs
@@ -589,16 +589,17 @@ impl LayoutThread {
             ThreadLocalStyleContextCreationInfo::new(self.new_animations_sender.clone());
 
         LayoutContext {
             id: self.id,
             style_context: SharedStyleContext {
                 stylist: &self.stylist,
                 options: StyleSystemOptions::default(),
                 guards: guards,
+                visited_styles_enabled: false,
                 running_animations: self.running_animations.clone(),
                 expired_animations: self.expired_animations.clone(),
                 local_context_creation_data: Mutex::new(thread_local_style_context_creation_data),
                 timer: self.timer.clone(),
                 quirks_mode: self.quirks_mode.unwrap(),
                 traversal_flags: TraversalFlags::empty(),
                 snapshot_map: snapshot_map,
             },
--- a/servo/components/style/context.rs
+++ b/servo/components/style/context.rs
@@ -112,16 +112,19 @@ impl Default for StyleSystemOptions {
 /// A shared style context.
 ///
 /// There's exactly one of these during a given restyle traversal, and it's
 /// shared among the worker threads.
 pub struct SharedStyleContext<'a> {
     /// The CSS selector stylist.
     pub stylist: &'a Stylist,
 
+    /// Whether visited styles are enabled.
+    pub visited_styles_enabled: bool,
+
     /// Configuration options.
     pub options: StyleSystemOptions,
 
     /// Guards for pre-acquired locks
     pub guards: StylesheetGuards<'a>,
 
     /// The current timer for transitions and animations. This is needed to test
     /// them.
--- a/servo/components/style/gecko/data.rs
+++ b/servo/components/style/gecko/data.rs
@@ -182,16 +182,23 @@ impl PerDocumentStyleDataImpl {
             &StylesheetGuards::same(guard),
             /* ua_sheets = */ None,
             /* stylesheets_changed = */ true,
             author_style_disabled,
             &mut extra_data
         );
     }
 
+    /// Returns whether private browsing is enabled.
+    pub fn is_private_browsing_enabled(&self) -> bool {
+        let doc =
+            self.stylist.device().pres_context().mDocument.raw::<nsIDocument>();
+        unsafe { bindings::Gecko_IsPrivateBrowsingEnabled(doc) }
+    }
+
     /// Get the default computed values for this document.
     pub fn default_computed_values(&self) -> &Arc<ComputedValues> {
         self.stylist.device().default_computed_values_arc()
     }
 
     /// Clear the stylist.  This will be a no-op if the stylist is
     /// already cleared; the stylist handles that.
     pub fn clear_stylist(&mut self) {
--- a/servo/components/style/gecko/generated/bindings.rs
+++ b/servo/components/style/gecko/generated/bindings.rs
@@ -742,16 +742,22 @@ extern "C" {
      -> RawServoDeclarationBlockStrongBorrowedOrNull;
 }
 extern "C" {
     pub fn Gecko_GetActiveLinkAttrDeclarationBlock(element:
                                                        RawGeckoElementBorrowed)
      -> RawServoDeclarationBlockStrongBorrowedOrNull;
 }
 extern "C" {
+    pub fn Gecko_IsPrivateBrowsingEnabled(aDoc: *const nsIDocument) -> bool;
+}
+extern "C" {
+    pub fn Gecko_AreVisitedLinksEnabled() -> bool;
+}
+extern "C" {
     pub fn Gecko_GetAnimationRule(aElementOrPseudo: RawGeckoElementBorrowed,
                                   aCascadeLevel:
                                       EffectCompositor_CascadeLevel,
                                   aAnimationValues:
                                       RawServoAnimationValueMapBorrowedMut)
      -> bool;
 }
 extern "C" {
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -2832,19 +2832,23 @@ bitflags! {
         /// Whether to convert display:contents into display:inline.  This
         /// is used by Gecko to prevent display:contents on generated
         /// content.
         const PROHIBIT_DISPLAY_CONTENTS = 1 << 4,
 
         /// Whether we're styling the ::-moz-fieldset-content anonymous box.
         const IS_FIELDSET_CONTENT = 1 << 5,
 
+        /// Whether we're computing the style of a link, either visited or
+        /// unvisited.
+        const IS_LINK = 1 << 6,
+
         /// Whether we're computing the style of a link element that happens to
         /// be visited.
-        const IS_VISITED_LINK = 1 << 6,
+        const IS_VISITED_LINK = 1 << 7,
     }
 }
 
 /// Performs the CSS cascade, computing new styles for an element from its parent style.
 ///
 /// The arguments are:
 ///
 ///   * `device`: Used to get the initial viewport and other external state.
--- a/servo/components/style/style_adjuster.rs
+++ b/servo/components/style/style_adjuster.rs
@@ -431,25 +431,30 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
     ///
     /// NOTE(emilio): We don't do this for text styles, which is... dubious, but
     /// Gecko doesn't seem to do it either. It's extremely easy to do if needed
     /// though.
     ///
     /// FIXME(emilio): This isn't technically a style adjustment thingie, could
     /// it move somewhere else?
     fn adjust_for_visited(&mut self, flags: CascadeFlags) {
-        use properties::IS_VISITED_LINK;
+        use properties::{IS_LINK, IS_VISITED_LINK};
         use properties::computed_value_flags::IS_RELEVANT_LINK_VISITED;
 
         if !self.style.has_visited_style() {
             return;
         }
 
-        if flags.contains(IS_VISITED_LINK) ||
-            self.style.inherited_style().flags.contains(IS_RELEVANT_LINK_VISITED) {
+        let relevant_link_visited = if flags.contains(IS_LINK) {
+            flags.contains(IS_VISITED_LINK)
+        } else {
+            self.style.inherited_style().flags.contains(IS_RELEVANT_LINK_VISITED)
+        };
+
+        if relevant_link_visited {
             self.style.flags.insert(IS_RELEVANT_LINK_VISITED);
         }
     }
 
     /// Adjusts the style to account for various fixups that don't fit naturally
     /// into the cascade.
     ///
     /// When comparing to Gecko, this is similar to the work done by
--- a/servo/components/style/style_resolver.rs
+++ b/servo/components/style/style_resolver.rs
@@ -7,17 +7,18 @@
 use applicable_declarations::ApplicableDeclarationList;
 use cascade_info::CascadeInfo;
 use context::{CascadeInputs, ElementCascadeInputs, StyleContext};
 use data::{ElementStyles, EagerPseudoStyles};
 use dom::TElement;
 use log::LogLevel::Trace;
 use matching::{CascadeVisitedMode, MatchMethods};
 use properties::{AnimationRules, CascadeFlags, ComputedValues};
-use properties::{IS_ROOT_ELEMENT, IS_VISITED_LINK, PROHIBIT_DISPLAY_CONTENTS, SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP};
+use properties::{IS_LINK, IS_ROOT_ELEMENT, IS_VISITED_LINK};
+use properties::{PROHIBIT_DISPLAY_CONTENTS, SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP};
 use properties::{VISITED_DEPENDENT_ONLY, cascade};
 use rule_tree::StrongRuleNode;
 use selector_parser::{PseudoElement, SelectorImpl};
 use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode, VisitedHandlingMode};
 use servo_arc::Arc;
 use stylist::RuleInclusion;
 
 /// A struct that takes care of resolving the style of a given element.
@@ -469,18 +470,22 @@ where
     ) -> Arc<ComputedValues> {
         let mut cascade_info = CascadeInfo::new();
         let mut cascade_flags = CascadeFlags::empty();
 
         if self.element.skip_root_and_item_based_display_fixup() {
             cascade_flags.insert(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP);
         }
 
-        if pseudo.is_none() && self.element.is_visited_link() {
-            cascade_flags.insert(IS_VISITED_LINK);
+        if pseudo.is_none() && self.element.is_link() {
+            cascade_flags.insert(IS_LINK);
+            if self.element.is_visited_link() &&
+                self.context.shared.visited_styles_enabled {
+                cascade_flags.insert(IS_VISITED_LINK);
+            }
         }
 
         if cascade_visited.visited_dependent_only() {
             // If this element is a link, we want its visited style to inherit
             // from the regular style of its parent, because only the
             // visitedness of the relevant link should influence style.
             if pseudo.is_some() || !self.element.is_link() {
                 parent_style = parent_style.map(|s| {
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -177,18 +177,23 @@ unsafe fn dummy_url_data() -> &'static R
 }
 
 fn create_shared_context<'a>(global_style_data: &GlobalStyleData,
                              guard: &'a SharedRwLockReadGuard,
                              per_doc_data: &'a PerDocumentStyleDataImpl,
                              traversal_flags: TraversalFlags,
                              snapshot_map: &'a ServoElementSnapshotTable)
                              -> SharedStyleContext<'a> {
+    let visited_styles_enabled =
+        unsafe { bindings::Gecko_AreVisitedLinksEnabled() } &&
+        !per_doc_data.is_private_browsing_enabled();
+
     SharedStyleContext {
         stylist: &per_doc_data.stylist,
+        visited_styles_enabled: visited_styles_enabled,
         options: global_style_data.options.clone(),
         guards: StylesheetGuards::same(guard),
         timer: Timer::new(),
         quirks_mode: per_doc_data.stylist.quirks_mode(),
         traversal_flags: traversal_flags,
         snapshot_map: snapshot_map,
     }
 }
@@ -1732,18 +1737,17 @@ pub extern "C" fn Servo_ComputedValues_I
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_ComputedValues_GetStyleBits(values: ServoStyleContextBorrowed) -> u64 {
     use style::properties::computed_value_flags::*;
     let flags = values.flags;
     let mut result = 0;
     if flags.contains(IS_RELEVANT_LINK_VISITED) {
-        // FIXME(emilio): This doesn't account for the pref.
-        // result |= structs::NS_STYLE_RELEVANT_LINK_VISITED as u64;
+        result |= structs::NS_STYLE_RELEVANT_LINK_VISITED as u64;
     }
     if flags.contains(HAS_TEXT_DECORATION_LINES) {
         result |= structs::NS_STYLE_HAS_TEXT_DECORATION_LINES as u64;
     }
     if flags.contains(SHOULD_SUPPRESS_LINEBREAK) {
         result |= structs::NS_STYLE_SUPPRESS_LINEBREAK as u64;
     }
     if flags.contains(IS_TEXT_COMBINED) {