diff --git a/servo/components/layout_thread/lib.rs b/servo/components/layout_thread/lib.rs index 2f0fa57e5a30..576588abda88 100644 --- a/servo/components/layout_thread/lib.rs +++ b/servo/components/layout_thread/lib.rs @@ -594,6 +594,7 @@ impl LayoutThread { 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), diff --git a/servo/components/style/context.rs b/servo/components/style/context.rs index e9733cb0985d..d53af678a40b 100644 --- a/servo/components/style/context.rs +++ b/servo/components/style/context.rs @@ -117,6 +117,9 @@ 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, diff --git a/servo/components/style/gecko/data.rs b/servo/components/style/gecko/data.rs index 08cb11a4fe35..f845ec421c2f 100644 --- a/servo/components/style/gecko/data.rs +++ b/servo/components/style/gecko/data.rs @@ -187,6 +187,13 @@ impl PerDocumentStyleDataImpl { ); } + /// Returns whether private browsing is enabled. + pub fn is_private_browsing_enabled(&self) -> bool { + let doc = + self.stylist.device().pres_context().mDocument.raw::(); + unsafe { bindings::Gecko_IsPrivateBrowsingEnabled(doc) } + } + /// Get the default computed values for this document. pub fn default_computed_values(&self) -> &Arc { self.stylist.device().default_computed_values_arc() diff --git a/servo/components/style/gecko/generated/bindings.rs b/servo/components/style/gecko/generated/bindings.rs index 3226c67b1d03..fb3d1a35c898 100644 --- a/servo/components/style/gecko/generated/bindings.rs +++ b/servo/components/style/gecko/generated/bindings.rs @@ -746,6 +746,12 @@ extern "C" { 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: diff --git a/servo/components/style/properties/properties.mako.rs b/servo/components/style/properties/properties.mako.rs index 33d59ad41056..b2445f53dfb0 100644 --- a/servo/components/style/properties/properties.mako.rs +++ b/servo/components/style/properties/properties.mako.rs @@ -2837,9 +2837,13 @@ bitflags! { /// 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, } } diff --git a/servo/components/style/style_adjuster.rs b/servo/components/style/style_adjuster.rs index 5ddcd42a095e..8222634317e3 100644 --- a/servo/components/style/style_adjuster.rs +++ b/servo/components/style/style_adjuster.rs @@ -436,15 +436,20 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> { /// 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); } } diff --git a/servo/components/style/style_resolver.rs b/servo/components/style/style_resolver.rs index dcb7134cf505..204f60219074 100644 --- a/servo/components/style/style_resolver.rs +++ b/servo/components/style/style_resolver.rs @@ -12,7 +12,8 @@ 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}; @@ -474,8 +475,12 @@ where 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() { diff --git a/servo/ports/geckolib/glue.rs b/servo/ports/geckolib/glue.rs index 0164bf9e280f..028f8ee8d3fc 100644 --- a/servo/ports/geckolib/glue.rs +++ b/servo/ports/geckolib/glue.rs @@ -182,8 +182,13 @@ fn create_shared_context<'a>(global_style_data: &GlobalStyleData, 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(), @@ -1737,8 +1742,7 @@ pub extern "C" fn Servo_ComputedValues_GetStyleBits(values: ServoStyleContextBor 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;