Auto merge of #17032 - jryans:stylo-visited, r=emilio

Stylo: visited pseudo-class support

Reviewed in https://bugzilla.mozilla.org/show_bug.cgi?id=1328509

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/17032)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-05-24 19:53:48 -05:00 committed by GitHub
commit 1f323f8848
18 changed files with 1016 additions and 236 deletions

View file

@ -100,6 +100,11 @@ pub struct ComputedValues {
pub font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>,
/// The cached system font. See longhand/font.mako.rs
pub cached_system_font: Option<longhands::system_font::ComputedSystemFont>,
/// The element's computed values if visited, only computed if there's a
/// relevant link for this element. A element's "relevant link" is the
/// element being matched if it is a link or the nearest ancestor link.
visited_style: Option<Arc<ComputedValues>>,
}
impl ComputedValues {
@ -107,6 +112,7 @@ impl ComputedValues {
writing_mode: WritingMode,
root_font_size: Au,
font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>,
visited_style: Option<Arc<ComputedValues>>,
% for style_struct in data.style_structs:
${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
% endfor
@ -117,6 +123,7 @@ impl ComputedValues {
root_font_size: root_font_size,
cached_system_font: None,
font_size_keyword: font_size_keyword,
visited_style: visited_style,
% for style_struct in data.style_structs:
${style_struct.ident}: ${style_struct.ident},
% endfor
@ -130,6 +137,7 @@ impl ComputedValues {
root_font_size: longhands::font_size::get_initial_value(), // FIXME(bz): Also seems dubious?
font_size_keyword: Some((Default::default(), 1.)),
cached_system_font: None,
visited_style: None,
% for style_struct in data.style_structs:
${style_struct.ident}: style_structs::${style_struct.name}::default(pres_context),
% endfor
@ -168,6 +176,23 @@ impl ComputedValues {
}
% endfor
/// Gets a reference to the visited computed values, if any.
pub fn get_visited_style(&self) -> Option<<&Arc<ComputedValues>> {
self.visited_style.as_ref()
}
/// Gets a reference to the visited computed values. Panic if the element
/// does not have visited computed values.
pub fn visited_style(&self) -> &Arc<ComputedValues> {
self.get_visited_style().unwrap()
}
/// Clone the visited computed values Arc. Used for inheriting parent styles
/// in StyleBuilder::for_inheritance.
pub fn clone_visited_style(&self) -> Option<Arc<ComputedValues>> {
self.visited_style.clone()
}
pub fn custom_properties(&self) -> Option<Arc<ComputedValuesMap>> {
self.custom_properties.clone()
}

View file

@ -576,6 +576,57 @@ impl LonghandId {
% endfor
}
}
/// Only a few properties are allowed to depend on the visited state of
/// links. When cascading visited styles, we can save time by only
/// processing these properties.
fn is_visited_dependent(&self) -> bool {
matches!(*self,
% if product == "gecko":
LonghandId::ColumnRuleColor |
LonghandId::TextEmphasisColor |
LonghandId::WebkitTextFillColor |
LonghandId::WebkitTextStrokeColor |
LonghandId::TextDecorationColor |
LonghandId::Fill |
LonghandId::Stroke |
LonghandId::CaretColor |
% endif
LonghandId::Color |
LonghandId::BackgroundColor |
LonghandId::BorderTopColor |
LonghandId::BorderRightColor |
LonghandId::BorderBottomColor |
LonghandId::BorderLeftColor |
LonghandId::OutlineColor
)
}
/// The computed value of some properties depends on the (sometimes
/// computed) value of *other* properties.
///
/// So we classify properties into "early" and "other", such that the only
/// dependencies can be from "other" to "early".
///
/// Unfortunately, its not easy to check that this classification is
/// correct.
fn is_early_property(&self) -> bool {
matches!(*self,
% if product == 'gecko':
LonghandId::TextOrientation |
LonghandId::AnimationName |
LonghandId::TransitionProperty |
LonghandId::XLang |
LonghandId::MozScriptLevel |
% endif
LonghandId::FontSize |
LonghandId::FontFamily |
LonghandId::Color |
LonghandId::TextDecorationLine |
LonghandId::WritingMode |
LonghandId::Direction
)
}
}
/// An identifier for a given shorthand property.
@ -1743,6 +1794,11 @@ pub struct ComputedValues {
pub root_font_size: Au,
/// The keyword behind the current font-size property, if any
pub font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>,
/// The element's computed values if visited, only computed if there's a
/// relevant link for this element. A element's "relevant link" is the
/// element being matched if it is a link or the nearest ancestor link.
visited_style: Option<Arc<ComputedValues>>,
}
#[cfg(feature = "servo")]
@ -1752,6 +1808,7 @@ impl ComputedValues {
writing_mode: WritingMode,
root_font_size: Au,
font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>,
visited_style: Option<Arc<ComputedValues>>,
% for style_struct in data.active_style_structs():
${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
% endfor
@ -1761,6 +1818,7 @@ impl ComputedValues {
writing_mode: writing_mode,
root_font_size: root_font_size,
font_size_keyword: font_size_keyword,
visited_style: visited_style,
% for style_struct in data.active_style_structs():
${style_struct.ident}: ${style_struct.ident},
% endfor
@ -1796,6 +1854,23 @@ impl ComputedValues {
}
% endfor
/// Gets a reference to the visited computed values, if any.
pub fn get_visited_style(&self) -> Option<<&Arc<ComputedValues>> {
self.visited_style.as_ref()
}
/// Gets a reference to the visited computed values. Panic if the element
/// does not have visited computed values.
pub fn visited_style(&self) -> &Arc<ComputedValues> {
self.get_visited_style().unwrap()
}
/// Clone the visited computed values Arc. Used for inheriting parent styles
/// in StyleBuilder::for_inheritance.
pub fn clone_visited_style(&self) -> Option<Arc<ComputedValues>> {
self.visited_style.clone()
}
/// Get the custom properties map if necessary.
///
/// Cloning the Arc here is fine because it only happens in the case where
@ -2183,6 +2258,10 @@ pub struct StyleBuilder<'a> {
pub root_font_size: Au,
/// The keyword behind the current font-size property, if any.
pub font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>,
/// The element's style if visited, only computed if there's a relevant link
/// for this element. A element's "relevant link" is the element being
/// matched if it is a link or the nearest ancestor link.
visited_style: Option<Arc<ComputedValues>>,
% for style_struct in data.active_style_structs():
${style_struct.ident}: StyleStructRef<'a, style_structs::${style_struct.name}>,
% endfor
@ -2195,6 +2274,7 @@ impl<'a> StyleBuilder<'a> {
writing_mode: WritingMode,
root_font_size: Au,
font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>,
visited_style: Option<Arc<ComputedValues>>,
% for style_struct in data.active_style_structs():
${style_struct.ident}: &'a Arc<style_structs::${style_struct.name}>,
% endfor
@ -2204,6 +2284,7 @@ impl<'a> StyleBuilder<'a> {
writing_mode: writing_mode,
root_font_size: root_font_size,
font_size_keyword: font_size_keyword,
visited_style: visited_style,
% for style_struct in data.active_style_structs():
${style_struct.ident}: StyleStructRef::Borrowed(${style_struct.ident}),
% endfor
@ -2223,6 +2304,7 @@ impl<'a> StyleBuilder<'a> {
parent.writing_mode,
parent.root_font_size,
parent.font_size_keyword,
parent.clone_visited_style(),
% for style_struct in data.active_style_structs():
% if style_struct.inherited:
parent.${style_struct.name_lower}_arc(),
@ -2296,6 +2378,7 @@ impl<'a> StyleBuilder<'a> {
self.writing_mode,
self.root_font_size,
self.font_size_keyword,
self.visited_style,
% for style_struct in data.active_style_structs():
self.${style_struct.ident}.build(),
% endfor
@ -2339,6 +2422,7 @@ mod lazy_static_module {
writing_mode: WritingMode::empty(),
root_font_size: longhands::font_size::get_initial_value(),
font_size_keyword: Some((Default::default(), 1.)),
visited_style: None,
};
}
}
@ -2370,6 +2454,8 @@ bitflags! {
/// Whether to skip any root element and flex/grid item display style
/// fixup.
const SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP = 0x02,
/// Whether to only cascade properties that are visited dependent.
const VISITED_DEPENDENT_ONLY = 0x04,
}
}
@ -2392,6 +2478,7 @@ pub fn cascade(device: &Device,
guards: &StylesheetGuards,
parent_style: Option<<&ComputedValues>,
layout_parent_style: Option<<&ComputedValues>,
visited_style: Option<Arc<ComputedValues>>,
cascade_info: Option<<&mut CascadeInfo>,
error_reporter: &ParseErrorReporter,
font_metrics_provider: &FontMetricsProvider,
@ -2438,6 +2525,7 @@ pub fn cascade(device: &Device,
iter_declarations,
inherited_style,
layout_parent_style,
visited_style,
cascade_info,
error_reporter,
font_metrics_provider,
@ -2453,6 +2541,7 @@ pub fn apply_declarations<'a, F, I>(device: &Device,
iter_declarations: F,
inherited_style: &ComputedValues,
layout_parent_style: &ComputedValues,
visited_style: Option<Arc<ComputedValues>>,
mut cascade_info: Option<<&mut CascadeInfo>,
error_reporter: &ParseErrorReporter,
font_metrics_provider: &FontMetricsProvider,
@ -2483,6 +2572,7 @@ pub fn apply_declarations<'a, F, I>(device: &Device,
WritingMode::empty(),
inherited_style.root_font_size,
inherited_style.font_size_keyword,
visited_style,
% for style_struct in data.active_style_structs():
% if style_struct.inherited:
inherited_style.${style_struct.name_lower}_arc(),
@ -2496,6 +2586,7 @@ pub fn apply_declarations<'a, F, I>(device: &Device,
WritingMode::empty(),
inherited_style.root_font_size,
inherited_style.font_size_keyword,
visited_style,
% for style_struct in data.active_style_structs():
inherited_style.${style_struct.name_lower}_arc(),
% endfor
@ -2544,6 +2635,14 @@ pub fn apply_declarations<'a, F, I>(device: &Device,
PropertyDeclarationId::Custom(..) => continue,
};
// Only a few properties are allowed to depend on the visited state
// of links. When cascading visited styles, we can save time by
// only processing these properties.
if flags.contains(VISITED_DEPENDENT_ONLY) &&
!longhand_id.is_visited_dependent() {
continue
}
// The computed value of some properties depends on the
// (sometimes computed) value of *other* properties.
//
@ -2555,26 +2654,11 @@ pub fn apply_declarations<'a, F, I>(device: &Device,
//
// Unfortunately, its not easy to check that this
// classification is correct.
let is_early_property = matches!(longhand_id,
LonghandId::FontSize |
LonghandId::FontFamily |
LonghandId::Color |
LonghandId::TextDecorationLine |
LonghandId::WritingMode |
LonghandId::Direction
% if product == 'gecko':
| LonghandId::TextOrientation
| LonghandId::AnimationName
| LonghandId::TransitionProperty
| LonghandId::XLang
| LonghandId::MozScriptLevel
% endif
);
if
% if category_to_cascade_now == "early":
!
% endif
is_early_property
longhand_id.is_early_property()
{
continue
}