diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2017-05-24 16:08:02 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-05-24 16:08:02 -0500 |
commit | 8ae546f7ea158466441987d4a86c5c440f0a5e00 (patch) | |
tree | b2eaae4c7b661879577a5bdddff9b811ef39bc4e | |
parent | bb310efbb9e84cf0bd44170c4e08bac664f0ce86 (diff) | |
parent | 8c9c506f9015da5a23858a6eaf75bd7ee187a01e (diff) | |
download | servo-8ae546f7ea158466441987d4a86c5c440f0a5e00.tar.gz servo-8ae546f7ea158466441987d4a86c5c440f0a5e00.zip |
Auto merge of #17027 - Manishearth:rollup, r=Manishearth
Rollup of 9 pull requests
- Successful merges: #16993, #17000, #17010, #17013, #17014, #17017, #17019, #17020, #17022
- Failed merges:
<!-- 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/17027)
<!-- Reviewable:end -->
-rw-r--r-- | components/script/textinput.rs | 20 | ||||
-rw-r--r-- | components/style/data.rs | 29 | ||||
-rw-r--r-- | components/style/dom.rs | 24 | ||||
-rw-r--r-- | components/style/gecko/media_queries.rs | 4 | ||||
-rw-r--r-- | components/style/gecko/non_ts_pseudo_class_list.rs | 1 | ||||
-rw-r--r-- | components/style/gecko/pseudo_element.rs | 9 | ||||
-rw-r--r-- | components/style/gecko/selector_parser.rs | 3 | ||||
-rw-r--r-- | components/style/gecko/wrapper.rs | 20 | ||||
-rw-r--r-- | components/style/gecko_string_cache/mod.rs | 4 | ||||
-rw-r--r-- | components/style/matching.rs | 228 | ||||
-rw-r--r-- | components/style/properties/declaration_block.rs | 15 | ||||
-rw-r--r-- | components/style/properties/helpers/animated_properties.mako.rs | 2 | ||||
-rw-r--r-- | components/style/properties/longhand/font.mako.rs | 17 | ||||
-rw-r--r-- | components/style/properties/shorthand/background.mako.rs | 20 | ||||
-rw-r--r-- | components/style/rule_tree/mod.rs | 52 | ||||
-rw-r--r-- | components/style/servo/selector_parser.rs | 6 | ||||
-rw-r--r-- | components/style/stylist.rs | 16 | ||||
-rw-r--r-- | components/style/traversal.rs | 4 |
18 files changed, 297 insertions, 177 deletions
diff --git a/components/script/textinput.rs b/components/script/textinput.rs index 144be9dbd78..b508ba2806c 100644 --- a/components/script/textinput.rs +++ b/components/script/textinput.rs @@ -632,14 +632,6 @@ impl<T: ClipboardProvider> TextInput<T> { self.insert_char(c); KeyReaction::DispatchInput }, - #[cfg(target_os = "macos")] - (None, Key::Home) => { - KeyReaction::RedrawSelection - }, - #[cfg(target_os = "macos")] - (None, Key::End) => { - KeyReaction::RedrawSelection - }, (None, Key::Delete) => { self.delete_char(Direction::Forward); KeyReaction::DispatchInput @@ -694,12 +686,18 @@ impl<T: ClipboardProvider> TextInput<T> { }, (None, Key::Enter) | (None, Key::KpEnter) => self.handle_return(), (None, Key::Home) => { - self.edit_point.index = 0; + #[cfg(not(target_os = "macos"))] + { + self.edit_point.index = 0; + } KeyReaction::RedrawSelection }, (None, Key::End) => { - self.edit_point.index = self.current_line_length(); - self.assert_ok_selection(); + #[cfg(not(target_os = "macos"))] + { + self.edit_point.index = self.current_line_length(); + self.assert_ok_selection(); + } KeyReaction::RedrawSelection }, (None, Key::PageUp) => { diff --git a/components/style/data.rs b/components/style/data.rs index 6e0feb35b68..a0d694b9518 100644 --- a/components/style/data.rs +++ b/components/style/data.rs @@ -6,12 +6,12 @@ use context::SharedStyleContext; use dom::TElement; -use properties::ComputedValues; +use properties::{AnimationRules, ComputedValues, PropertyDeclarationBlock}; use properties::longhands::display::computed_value as display; use restyle_hints::{HintComputationContext, RestyleReplacements, RestyleHint}; use rule_tree::StrongRuleNode; use selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage}; -use shared_lock::StylesheetGuards; +use shared_lock::{Locked, StylesheetGuards}; use std::fmt; use stylearc::Arc; use traversal::TraversalFlags; @@ -558,4 +558,29 @@ impl ElementData { pub fn restyle_mut(&mut self) -> &mut RestyleData { self.get_restyle_mut().expect("Calling restyle_mut without RestyleData") } + + /// Returns SMIL overriden value if exists. + pub fn get_smil_override(&self) -> Option<&Arc<Locked<PropertyDeclarationBlock>>> { + if cfg!(feature = "servo") { + // Servo has no knowledge of a SMIL rule, so just avoid looking for it. + return None; + } + + match self.get_styles() { + Some(s) => s.primary.rules.get_smil_animation_rule(), + None => None, + } + } + + /// Returns AnimationRules that has processed during animation-only restyles. + pub fn get_animation_rules(&self) -> AnimationRules { + if cfg!(feature = "servo") { + return AnimationRules(None, None) + } + + match self.get_styles() { + Some(s) => s.primary.rules.get_animation_rules(), + None => AnimationRules(None, None), + } + } } diff --git a/components/style/dom.rs b/components/style/dom.rs index 36997de5c32..188cbb10d32 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -274,20 +274,6 @@ pub trait PresentationalHintsSynthesizer { where V: Push<ApplicableDeclarationBlock>; } -/// The animation rules. -/// -/// The first one is for Animation cascade level, and the second one is for -/// Transition cascade level. -pub struct AnimationRules(pub Option<Arc<Locked<PropertyDeclarationBlock>>>, - pub Option<Arc<Locked<PropertyDeclarationBlock>>>); - -impl AnimationRules { - /// Returns whether these animation rules represents an actual rule or not. - pub fn is_empty(&self) -> bool { - self.0.is_none() && self.1.is_none() - } -} - /// The element trait, the main abstraction the style crate acts over. pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone + ElementExt + PresentationalHintsSynthesizer { @@ -348,11 +334,6 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone + None } - /// Get this element's animation rules. - fn get_animation_rules(&self) -> AnimationRules { - AnimationRules(None, None) - } - /// Get this element's animation rule by the cascade level. fn get_animation_rule_by_cascade(&self, _cascade_level: CascadeLevel) @@ -525,6 +506,11 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone + /// Returns true if the element has all the specified selector flags. fn has_selector_flags(&self, flags: ElementSelectorFlags) -> bool; + /// In Gecko, element has a flag that represents the element may have + /// any type of animations or not to bail out animation stuff early. + /// Whereas Servo doesn't have such flag. + fn may_have_animations(&self) -> bool { false } + /// Creates a task to update various animation state on a given (pseudo-)element. #[cfg(feature = "gecko")] fn update_animations(&self, diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs index 2444338f174..4105e685cb2 100644 --- a/components/style/gecko/media_queries.rs +++ b/components/style/gecko/media_queries.rs @@ -128,6 +128,10 @@ impl ToCss for Expression { where W: fmt::Write, { dest.write_str("(")?; + + if (self.feature.mReqFlags & nsMediaFeature_RequirementFlags::eHasWebkitPrefix as u8) != 0 { + dest.write_str("-webkit-")?; + } match self.range { nsMediaExpression_Range::eMin => dest.write_str("min-")?, nsMediaExpression_Range::eMax => dest.write_str("max-")?, diff --git a/components/style/gecko/non_ts_pseudo_class_list.rs b/components/style/gecko/non_ts_pseudo_class_list.rs index f6551ce90d4..524ecb2e655 100644 --- a/components/style/gecko/non_ts_pseudo_class_list.rs +++ b/components/style/gecko/non_ts_pseudo_class_list.rs @@ -107,6 +107,7 @@ macro_rules! apply_non_ts_list { ("-moz-only-whitespace", MozOnlyWhitespace, mozOnlyWhitespace, _, _), ("-moz-native-anonymous", MozNativeAnonymous, mozNativeAnonymous, _, PSEUDO_CLASS_INTERNAL), ("-moz-is-html", MozIsHTML, mozIsHTML, _, _), + ("-moz-placeholder", MozPlaceholder, mozPlaceholder, _, _), ], string: [ ("-moz-system-metric", MozSystemMetric, mozSystemMetric, _, PSEUDO_CLASS_INTERNAL), diff --git a/components/style/gecko/pseudo_element.rs b/components/style/gecko/pseudo_element.rs index a501198f28e..888fdbdc33c 100644 --- a/components/style/gecko/pseudo_element.rs +++ b/components/style/gecko/pseudo_element.rs @@ -102,6 +102,15 @@ impl PseudoElement { pub fn is_precomputed(&self) -> bool { self.is_anon_box() } + + /// Covert non-canonical pseudo-element to canonical one, and keep a + /// canonical one as it is. + pub fn canonical(&self) -> PseudoElement { + match *self { + PseudoElement::MozPlaceholder => PseudoElement::Placeholder, + _ => self.clone(), + } + } } impl ToCss for PseudoElement { diff --git a/components/style/gecko/selector_parser.rs b/components/style/gecko/selector_parser.rs index 787ecd5b2cb..30242dc9bcb 100644 --- a/components/style/gecko/selector_parser.rs +++ b/components/style/gecko/selector_parser.rs @@ -166,7 +166,8 @@ impl NonTSPseudoClass { !matches!(*self, NonTSPseudoClass::MozAny(_) | NonTSPseudoClass::Dir(_) | - NonTSPseudoClass::MozIsHTML) + NonTSPseudoClass::MozIsHTML | + NonTSPseudoClass::MozPlaceholder) } /// Convert NonTSPseudoClass to Gecko's CSSPseudoClassType. diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index e043ff57223..fc56362810c 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -18,7 +18,7 @@ use app_units::Au; use atomic_refcell::AtomicRefCell; use context::{QuirksMode, SharedStyleContext, UpdateAnimationsTasks}; use data::ElementData; -use dom::{self, AnimationRules, DescendantsBit, LayoutIterator, NodeInfo, TElement, TNode, UnsafeNode}; +use dom::{self, DescendantsBit, LayoutIterator, NodeInfo, TElement, TNode, UnsafeNode}; use dom::{OpaqueNode, PresentationalHintsSynthesizer}; use element_state::ElementState; use error_reporting::RustLogReporter; @@ -423,11 +423,6 @@ impl<'le> GeckoElement<'le> { } #[inline] - fn may_have_animations(&self) -> bool { - self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementHasAnimations) - } - - #[inline] fn has_id(&self) -> bool { self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementHasID) } @@ -613,11 +608,6 @@ impl<'le> TElement for GeckoElement<'le> { declarations.map(|s| s.as_arc_opt()).unwrap_or(None) } - fn get_animation_rules(&self) -> AnimationRules { - AnimationRules(self.get_animation_rule(), - self.get_transition_rule()) - } - fn get_animation_rule_by_cascade(&self, cascade_level: ServoCascadeLevel) -> Option<Arc<Locked<PropertyDeclarationBlock>>> { match cascade_level { @@ -782,6 +772,11 @@ impl<'le> TElement for GeckoElement<'le> { (self.flags() & node_flags) == node_flags } + #[inline] + fn may_have_animations(&self) -> bool { + self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementHasAnimations) + } + fn update_animations(&self, before_change_style: Option<Arc<ComputedValues>>, tasks: UpdateAnimationsTasks) { @@ -1335,6 +1330,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { NonTSPseudoClass::MozIsHTML => { self.is_html_element_in_html_document() } + NonTSPseudoClass::MozPlaceholder => false, NonTSPseudoClass::MozAny(ref sels) => { sels.iter().any(|s| { matches_complex_selector(s, self, context, flags_setter) @@ -1368,7 +1364,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { // match the proper pseudo-element, given how we rulehash the stuff // based on the pseudo. match self.implemented_pseudo_element() { - Some(ref pseudo) => pseudo == pseudo_element, + Some(ref pseudo) => *pseudo == pseudo_element.canonical(), None => false, } } diff --git a/components/style/gecko_string_cache/mod.rs b/components/style/gecko_string_cache/mod.rs index fa89f5eab48..4973428f1e8 100644 --- a/components/style/gecko_string_cache/mod.rs +++ b/components/style/gecko_string_cache/mod.rs @@ -239,6 +239,10 @@ impl Atom { /// Return whether two atoms are ASCII-case-insensitive matches pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool { + if self == other { + return true; + } + let a = self.as_slice(); let b = other.as_slice(); a.len() == b.len() && a.iter().zip(b).all(|(&a16, &b16)| { diff --git a/components/style/matching.rs b/components/style/matching.rs index e0a8e4ec755..df5ac723097 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -10,10 +10,10 @@ use cascade_info::CascadeInfo; use context::{SelectorFlagsMap, SharedStyleContext, StyleContext}; use data::{ComputedStyle, ElementData, RestyleData}; -use dom::{AnimationRules, TElement, TNode}; +use dom::{TElement, TNode}; use font_metrics::FontMetricsProvider; use log::LogLevel::Trace; -use properties::{CascadeFlags, ComputedValues, SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP, cascade}; +use properties::{AnimationRules, CascadeFlags, ComputedValues, SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP, cascade}; use properties::longhands::display::computed_value as display; use restyle_hints::{RESTYLE_CSS_ANIMATIONS, RESTYLE_CSS_TRANSITIONS, RestyleReplacements}; use restyle_hints::{RESTYLE_STYLE_ATTRIBUTE, RESTYLE_SMIL}; @@ -254,12 +254,15 @@ trait PrivateMatchMethods: TElement { // We could make that a bit better if the complexity cost is not too // big, but given further restyles are posted directly to // pseudo-elements, it doesn't seem worth the effort at a glance. - if pseudo.is_eager() && self.get_animation_rules().is_empty() { + if pseudo.is_eager() { let parent = self.parent_element().unwrap(); - let parent_data = parent.borrow_data().unwrap(); - let pseudo_style = - parent_data.styles().pseudos.get(&pseudo).unwrap(); - return pseudo_style.values().clone() + if !parent.may_have_animations() || + primary_style.rules.get_animation_rules().is_empty() { + let parent_data = parent.borrow_data().unwrap(); + let pseudo_style = + parent_data.styles().pseudos.get(&pseudo).unwrap(); + return pseudo_style.values().clone() + } } } @@ -684,6 +687,8 @@ pub trait MatchMethods : TElement { { let implemented_pseudo = self.implemented_pseudo_element(); if let Some(ref pseudo) = implemented_pseudo { + // We don't expect to match against a non-canonical pseudo-element. + debug_assert_eq!(*pseudo, pseudo.canonical()); if pseudo.is_eager() { // If it's an eager element-backed pseudo, just grab the matched // rules from the parent, and update animations. @@ -692,38 +697,39 @@ pub trait MatchMethods : TElement { let pseudo_style = parent_data.styles().pseudos.get(&pseudo).unwrap(); let mut rules = pseudo_style.rules.clone(); - let animation_rules = self.get_animation_rules(); - - // Handle animations here. - if let Some(animation_rule) = animation_rules.0 { - let animation_rule_node = - context.shared.stylist.rule_tree() - .update_rule_at_level(CascadeLevel::Animations, - Some(&animation_rule), - &mut rules, - &context.shared.guards); - if let Some(node) = animation_rule_node { - rules = node; + if parent.may_have_animations() { + let animation_rules = data.get_animation_rules(); + + // Handle animations here. + if let Some(animation_rule) = animation_rules.0 { + let animation_rule_node = + context.shared.stylist.rule_tree() + .update_rule_at_level(CascadeLevel::Animations, + Some(&animation_rule), + &mut rules, + &context.shared.guards); + if let Some(node) = animation_rule_node { + rules = node; + } } - } - if let Some(animation_rule) = animation_rules.1 { - let animation_rule_node = - context.shared.stylist.rule_tree() - .update_rule_at_level(CascadeLevel::Transitions, - Some(&animation_rule), - &mut rules, - &context.shared.guards); - if let Some(node) = animation_rule_node { - rules = node; + if let Some(animation_rule) = animation_rules.1 { + let animation_rule_node = + context.shared.stylist.rule_tree() + .update_rule_at_level(CascadeLevel::Transitions, + Some(&animation_rule), + &mut rules, + &context.shared.guards); + if let Some(node) = animation_rule_node { + rules = node; + } } } - let important_rules_changed = self.has_animations() && data.has_styles() && data.important_rules_are_different(&rules, - &context.shared.guards); + &context.shared.guards); return RulesMatchedResult { rule_nodes_changed: data.set_primary_rules(rules), @@ -736,30 +742,35 @@ pub trait MatchMethods : TElement { let stylist = &context.shared.stylist; let style_attribute = self.style_attribute(); - let smil_override = self.get_smil_override(); - let animation_rules = self.get_animation_rules(); - let bloom = context.thread_local.bloom_filter.filter(); - + { + let smil_override = data.get_smil_override(); + let animation_rules = if self.may_have_animations() { + data.get_animation_rules() + } else { + AnimationRules(None, None) + }; + let bloom = context.thread_local.bloom_filter.filter(); - let map = &mut context.thread_local.selector_flags; - let mut set_selector_flags = |element: &Self, flags: ElementSelectorFlags| { - self.apply_selector_flags(map, element, flags); - }; + let map = &mut context.thread_local.selector_flags; + let mut set_selector_flags = |element: &Self, flags: ElementSelectorFlags| { + self.apply_selector_flags(map, element, flags); + }; - let mut matching_context = - MatchingContext::new(MatchingMode::Normal, Some(bloom)); + let mut matching_context = + MatchingContext::new(MatchingMode::Normal, Some(bloom)); - // Compute the primary rule node. - stylist.push_applicable_declarations(self, - implemented_pseudo.as_ref(), - style_attribute, - smil_override, - animation_rules, - &mut applicable_declarations, - &mut matching_context, - &mut set_selector_flags); + // Compute the primary rule node. + stylist.push_applicable_declarations(self, + implemented_pseudo.as_ref(), + style_attribute, + smil_override, + animation_rules, + &mut applicable_declarations, + &mut matching_context, + &mut set_selector_flags); - *relations = matching_context.relations; + *relations = matching_context.relations; + } let primary_rule_node = compute_rule_node::<Self>(stylist.rule_tree(), @@ -963,81 +974,82 @@ pub trait MatchMethods : TElement { } /// Updates the rule nodes without re-running selector matching, using just - /// the rule tree. Returns RulesChanged which indicates whether the rule nodes changed - /// and whether the important rules changed. + /// the rule tree. Returns true if an !important rule was replaced. fn replace_rules(&self, replacements: RestyleReplacements, context: &StyleContext<Self>, data: &mut ElementData) - -> RulesChanged { + -> bool { use properties::PropertyDeclarationBlock; use shared_lock::Locked; let element_styles = &mut data.styles_mut(); let primary_rules = &mut element_styles.primary.rules; - let mut result = RulesChanged::empty(); - { - let mut replace_rule_node = |level: CascadeLevel, - pdb: Option<&Arc<Locked<PropertyDeclarationBlock>>>, - path: &mut StrongRuleNode| { - let new_node = context.shared.stylist.rule_tree() - .update_rule_at_level(level, pdb, path, &context.shared.guards); - if let Some(n) = new_node { + let replace_rule_node = |level: CascadeLevel, + pdb: Option<&Arc<Locked<PropertyDeclarationBlock>>>, + path: &mut StrongRuleNode| -> bool { + let new_node = context.shared.stylist.rule_tree() + .update_rule_at_level(level, pdb, path, &context.shared.guards); + match new_node { + Some(n) => { *path = n; - if level.is_important() { - result.insert(IMPORTANT_RULES_CHANGED); - } else { - result.insert(NORMAL_RULES_CHANGED); - } - } - }; - - // Animation restyle hints are processed prior to other restyle - // hints in the animation-only traversal. - // - // Non-animation restyle hints will be processed in a subsequent - // normal traversal. - if replacements.intersects(RestyleReplacements::for_animations()) { - debug_assert!(context.shared.traversal_flags.for_animation_only()); - - if replacements.contains(RESTYLE_SMIL) { - replace_rule_node(CascadeLevel::SMILOverride, - self.get_smil_override(), - primary_rules); - } - - let mut replace_rule_node_for_animation = |level: CascadeLevel, - primary_rules: &mut StrongRuleNode| { - let animation_rule = self.get_animation_rule_by_cascade(level); - replace_rule_node(level, - animation_rule.as_ref(), - primary_rules); - }; - - // Apply Transition rules and Animation rules if the corresponding restyle hint - // is contained. - if replacements.contains(RESTYLE_CSS_TRANSITIONS) { - replace_rule_node_for_animation(CascadeLevel::Transitions, - primary_rules); - } + level.is_important() + }, + None => false, + } + }; - if replacements.contains(RESTYLE_CSS_ANIMATIONS) { - replace_rule_node_for_animation(CascadeLevel::Animations, - primary_rules); - } - } else if replacements.contains(RESTYLE_STYLE_ATTRIBUTE) { + if !context.shared.traversal_flags.for_animation_only() { + let mut result = false; + if replacements.contains(RESTYLE_STYLE_ATTRIBUTE) { let style_attribute = self.style_attribute(); - replace_rule_node(CascadeLevel::StyleAttributeNormal, - style_attribute, + result |= replace_rule_node(CascadeLevel::StyleAttributeNormal, + style_attribute, + primary_rules); + result |= replace_rule_node(CascadeLevel::StyleAttributeImportant, + style_attribute, + primary_rules); + } + return result; + } + + // Animation restyle hints are processed prior to other restyle + // hints in the animation-only traversal. + // + // Non-animation restyle hints will be processed in a subsequent + // normal traversal. + if replacements.intersects(RestyleReplacements::for_animations()) { + debug_assert!(context.shared.traversal_flags.for_animation_only()); + + if replacements.contains(RESTYLE_SMIL) { + replace_rule_node(CascadeLevel::SMILOverride, + self.get_smil_override(), primary_rules); - replace_rule_node(CascadeLevel::StyleAttributeImportant, - style_attribute, + } + + let replace_rule_node_for_animation = |level: CascadeLevel, + primary_rules: &mut StrongRuleNode| { + let animation_rule = self.get_animation_rule_by_cascade(level); + replace_rule_node(level, + animation_rule.as_ref(), primary_rules); + }; + + // Apply Transition rules and Animation rules if the corresponding restyle hint + // is contained. + if replacements.contains(RESTYLE_CSS_TRANSITIONS) { + replace_rule_node_for_animation(CascadeLevel::Transitions, + primary_rules); + } + + if replacements.contains(RESTYLE_CSS_ANIMATIONS) { + replace_rule_node_for_animation(CascadeLevel::Animations, + primary_rules); } } - result + false } /// Attempts to share a style with another node. This method is unsafe diff --git a/components/style/properties/declaration_block.rs b/components/style/properties/declaration_block.rs index 1bd565f2153..e7c1b73d6c8 100644 --- a/components/style/properties/declaration_block.rs +++ b/components/style/properties/declaration_block.rs @@ -11,6 +11,7 @@ use cssparser::{DeclarationListParser, parse_important}; use cssparser::{Parser, AtRuleParser, DeclarationParser, Delimiter}; use error_reporting::ParseErrorReporter; use parser::{PARSING_MODE_DEFAULT, ParsingMode, ParserContext, log_css_error}; +use shared_lock::Locked; use std::fmt; use std::slice::Iter; use style_traits::ToCss; @@ -18,6 +19,20 @@ use stylesheets::{CssRuleType, Origin, UrlExtraData}; use super::*; #[cfg(feature = "gecko")] use properties::animated_properties::AnimationValueMap; +/// The animation rules. +/// +/// The first one is for Animation cascade level, and the second one is for +/// Transition cascade level. +pub struct AnimationRules<'a>(pub Option<&'a Arc<Locked<PropertyDeclarationBlock>>>, + pub Option<&'a Arc<Locked<PropertyDeclarationBlock>>>); + +impl<'a> AnimationRules<'a> { + /// Returns whether these animation rules represents an actual rule or not. + pub fn is_empty(&self) -> bool { + self.0.is_none() && self.1.is_none() + } +} + /// A declaration [importance][importance]. /// /// [importance]: https://drafts.csswg.org/css-cascade/#importance diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 3b9c2f69823..39e3a6a14a1 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -753,6 +753,7 @@ impl <T> Animatable for Option<T> (&Some(ref this), &Some(ref other)) => { Ok(this.add_weighted(other, self_portion, other_portion).ok()) } + (&None, &None) => Ok(None), _ => Err(()), } } @@ -763,6 +764,7 @@ impl <T> Animatable for Option<T> (&Some(ref this), &Some(ref other)) => { this.compute_distance(other) }, + (&None, &None) => Ok(0.0), _ => Err(()), } } diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index cd60b303436..d9990d9dfdc 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -464,12 +464,13 @@ ${helpers.single_keyword_system("font-variant-caps", } /// Obtain a Servo computed value from a Gecko computed font-weight - pub unsafe fn from_gecko_weight(weight: u16) -> Self { - use std::mem::transmute; - debug_assert!(weight >= 100); - debug_assert!(weight <= 900); - debug_assert!(weight % 10 == 0); - transmute(weight) + pub fn from_gecko_weight(weight: u16) -> Self { + match weight { + % for weight in range(100, 901, 100): + ${weight} => T::Weight${weight}, + % endfor + _ => panic!("from_gecko_weight: called with invalid weight") + } } } } @@ -2362,9 +2363,7 @@ ${helpers.single_keyword("-moz-math-variant", quoted: true }) }).collect::<Vec<_>>(); - let weight = unsafe { - longhands::font_weight::computed_value::T::from_gecko_weight(system.weight) - }; + let weight = longhands::font_weight::computed_value::T::from_gecko_weight(system.weight); let ret = ComputedSystemFont { font_family: longhands::font_family::computed_value::T(family), font_size: Au(system.size), diff --git a/components/style/properties/shorthand/background.mako.rs b/components/style/properties/shorthand/background.mako.rs index b4f3f9fe079..5a7747cf3fb 100644 --- a/components/style/properties/shorthand/background.mako.rs +++ b/components/style/properties/shorthand/background.mako.rs @@ -39,17 +39,20 @@ let mut background_${name} = background_${name}::SpecifiedValue(Vec::new()); % endfor try!(input.parse_comma_separated(|input| { + // background-color can only be in the last element, so if it + // is parsed anywhere before, the value is invalid. + if background_color.is_some() { + return Err(()); + } + % for name in "image position repeat size attachment origin clip".split(): let mut ${name} = None; % endfor loop { - if let Ok(value) = input.try(|i| CSSColor::parse(context, i)) { - if background_color.is_none() { + if background_color.is_none() { + if let Ok(value) = input.try(|i| CSSColor::parse(context, i)) { background_color = Some(value); continue - } else { - // color can only be the last element - return Err(()) } } if position.is_none() { @@ -69,6 +72,13 @@ if ${name}.is_none() { if let Ok(value) = input.try(|input| background_${name}::single_value ::parse(context, input)) { + % if name == "clip" and product == "gecko": + // "text" value of background-clip should not be part of background + // shorthand per current spec and impls. + if value == background_clip::single_value::SpecifiedValue::text { + return Err(()); + } + % endif ${name} = Some(value); continue } diff --git a/components/style/rule_tree/mod.rs b/components/style/rule_tree/mod.rs index 8b288b82489..866eb9adab9 100644 --- a/components/style/rule_tree/mod.rs +++ b/components/style/rule_tree/mod.rs @@ -8,7 +8,7 @@ #[cfg(feature = "servo")] use heapsize::HeapSizeOf; -use properties::{Importance, LonghandIdSet, PropertyDeclarationBlock}; +use properties::{AnimationRules, Importance, LonghandIdSet, PropertyDeclarationBlock}; use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard}; use smallvec::SmallVec; use std::io::{self, Write}; @@ -1142,6 +1142,56 @@ impl StrongRuleNode { } result } + + /// Returns PropertyDeclarationBlock for this node. + /// This function must be called only for animation level node. + fn get_animation_style(&self) -> &Arc<Locked<PropertyDeclarationBlock>> { + debug_assert!(self.cascade_level().is_animation(), + "The cascade level should be an animation level"); + match *self.style_source().unwrap() { + StyleSource::Declarations(ref block) => block, + StyleSource::Style(_) => unreachable!("animating style should not be a style rule"), + } + } + + /// Returns SMIL override declaration block if exists. + pub fn get_smil_animation_rule(&self) -> Option<&Arc<Locked<PropertyDeclarationBlock>>> { + if cfg!(feature = "servo") { + // Servo has no knowledge of a SMIL rule, so just avoid looking for it. + return None; + } + + self.self_and_ancestors() + .take_while(|node| node.cascade_level() >= CascadeLevel::SMILOverride) + .find(|node| node.cascade_level() == CascadeLevel::SMILOverride) + .map(|node| node.get_animation_style()) + } + + /// Returns AnimationRules that has processed during animation-only restyles. + pub fn get_animation_rules(&self) -> AnimationRules { + if cfg!(feature = "servo") { + return AnimationRules(None, None); + } + + let mut animation = None; + let mut transition = None; + + for node in self.self_and_ancestors() + .take_while(|node| node.cascade_level() >= CascadeLevel::Animations) { + match node.cascade_level() { + CascadeLevel::Animations => { + debug_assert!(animation.is_none()); + animation = Some(node.get_animation_style()) + }, + CascadeLevel::Transitions => { + debug_assert!(transition.is_none()); + transition = Some(node.get_animation_style()) + }, + _ => {}, + } + } + AnimationRules(animation, transition) + } } /// An iterator over a rule node and its ancestors. diff --git a/components/style/servo/selector_parser.rs b/components/style/servo/selector_parser.rs index fdc14b11e29..1cae314ddec 100644 --- a/components/style/servo/selector_parser.rs +++ b/components/style/servo/selector_parser.rs @@ -152,6 +152,12 @@ impl PseudoElement { PseudoElement::ServoInlineAbsolute => PseudoElementCascadeType::Precomputed, } } + + /// Covert non-canonical pseudo-element to canonical one, and keep a + /// canonical one as it is. + pub fn canonical(&self) -> PseudoElement { + self.clone() + } } /// A non tree-structural pseudo-class. diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 7fb64c8acf5..a453588c469 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -8,7 +8,7 @@ use {Atom, LocalName, Namespace}; use bit_vec::BitVec; use context::{QuirksMode, SharedStyleContext}; use data::ComputedStyle; -use dom::{AnimationRules, TElement}; +use dom::TElement; use element_state::ElementState; use error_reporting::RustLogReporter; use font_metrics::FontMetricsProvider; @@ -17,9 +17,9 @@ use gecko_bindings::structs::nsIAtom; use keyframes::KeyframesAnimation; use media_queries::Device; use properties::{self, CascadeFlags, ComputedValues}; +use properties::{AnimationRules, PropertyDeclarationBlock}; #[cfg(feature = "servo")] use properties::INHERIT_ALL; -use properties::PropertyDeclarationBlock; use restyle_hints::{HintComputationContext, DependencySet, RestyleHint}; use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource}; use selector_map::{SelectorMap, SelectorMapEntry}; @@ -473,7 +473,7 @@ impl Stylist { { let map = if let Some(pseudo) = selector.pseudo_element() { self.pseudos_map - .entry(pseudo.clone()) + .entry(pseudo.canonical()) .or_insert_with(PerPseudoElementSelectorMap::new) .borrow_for_origin(&stylesheet.origin) } else { @@ -665,8 +665,9 @@ impl Stylist { -> Option<StrongRuleNode> where E: TElement { + let pseudo = pseudo.canonical(); debug_assert!(pseudo.is_lazy()); - if self.pseudos_map.get(pseudo).is_none() { + if self.pseudos_map.get(&pseudo).is_none() { return None } @@ -698,7 +699,7 @@ impl Stylist { let mut matching_context = MatchingContext::new(MatchingMode::ForStatelessPseudoElement, None); self.push_applicable_declarations(element, - Some(pseudo), + Some(&pseudo), None, None, AnimationRules(None, None), @@ -943,7 +944,7 @@ impl Stylist { if let Some(anim) = animation_rules.0 { Push::push( applicable_declarations, - ApplicableDeclarationBlock::from_declarations(anim, + ApplicableDeclarationBlock::from_declarations(anim.clone(), CascadeLevel::Animations)); } debug!("animation: {:?}", context.relations); @@ -961,7 +962,8 @@ impl Stylist { if let Some(anim) = animation_rules.1 { Push::push( applicable_declarations, - ApplicableDeclarationBlock::from_declarations(anim, CascadeLevel::Transitions)); + ApplicableDeclarationBlock::from_declarations(anim.clone(), + CascadeLevel::Transitions)); } debug!("transition: {:?}", context.relations); debug!("push_applicable_declarations: shareable: {:?}", context.relations); diff --git a/components/style/traversal.rs b/components/style/traversal.rs index 6e6ccf813a1..146069b1bc3 100644 --- a/components/style/traversal.rs +++ b/components/style/traversal.rs @@ -770,11 +770,11 @@ fn compute_style<E, D>(_traversal: &D, ) } CascadeWithReplacements(flags) => { - let rules_changed = element.replace_rules(flags, context, data); + let important_rules_changed = element.replace_rules(flags, context, data); element.cascade_primary_and_pseudos( context, data, - rules_changed.important_rules_changed() + important_rules_changed ) } CascadeOnly => { |