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 -->
This commit is contained in:
bors-servo 2017-05-24 16:08:02 -05:00 committed by GitHub
commit 8ae546f7ea
18 changed files with 299 additions and 179 deletions

View file

@ -632,14 +632,6 @@ impl<T: ClipboardProvider> TextInput<T> {
self.insert_char(c); self.insert_char(c);
KeyReaction::DispatchInput KeyReaction::DispatchInput
}, },
#[cfg(target_os = "macos")]
(None, Key::Home) => {
KeyReaction::RedrawSelection
},
#[cfg(target_os = "macos")]
(None, Key::End) => {
KeyReaction::RedrawSelection
},
(None, Key::Delete) => { (None, Key::Delete) => {
self.delete_char(Direction::Forward); self.delete_char(Direction::Forward);
KeyReaction::DispatchInput KeyReaction::DispatchInput
@ -694,12 +686,18 @@ impl<T: ClipboardProvider> TextInput<T> {
}, },
(None, Key::Enter) | (None, Key::KpEnter) => self.handle_return(), (None, Key::Enter) | (None, Key::KpEnter) => self.handle_return(),
(None, Key::Home) => { (None, Key::Home) => {
self.edit_point.index = 0; #[cfg(not(target_os = "macos"))]
{
self.edit_point.index = 0;
}
KeyReaction::RedrawSelection KeyReaction::RedrawSelection
}, },
(None, Key::End) => { (None, Key::End) => {
self.edit_point.index = self.current_line_length(); #[cfg(not(target_os = "macos"))]
self.assert_ok_selection(); {
self.edit_point.index = self.current_line_length();
self.assert_ok_selection();
}
KeyReaction::RedrawSelection KeyReaction::RedrawSelection
}, },
(None, Key::PageUp) => { (None, Key::PageUp) => {

View file

@ -6,12 +6,12 @@
use context::SharedStyleContext; use context::SharedStyleContext;
use dom::TElement; use dom::TElement;
use properties::ComputedValues; use properties::{AnimationRules, ComputedValues, PropertyDeclarationBlock};
use properties::longhands::display::computed_value as display; use properties::longhands::display::computed_value as display;
use restyle_hints::{HintComputationContext, RestyleReplacements, RestyleHint}; use restyle_hints::{HintComputationContext, RestyleReplacements, RestyleHint};
use rule_tree::StrongRuleNode; use rule_tree::StrongRuleNode;
use selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage}; use selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage};
use shared_lock::StylesheetGuards; use shared_lock::{Locked, StylesheetGuards};
use std::fmt; use std::fmt;
use stylearc::Arc; use stylearc::Arc;
use traversal::TraversalFlags; use traversal::TraversalFlags;
@ -558,4 +558,29 @@ impl ElementData {
pub fn restyle_mut(&mut self) -> &mut RestyleData { pub fn restyle_mut(&mut self) -> &mut RestyleData {
self.get_restyle_mut().expect("Calling restyle_mut without 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),
}
}
} }

View file

@ -274,20 +274,6 @@ pub trait PresentationalHintsSynthesizer {
where V: Push<ApplicableDeclarationBlock>; 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. /// The element trait, the main abstraction the style crate acts over.
pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone + pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone +
ElementExt + PresentationalHintsSynthesizer { ElementExt + PresentationalHintsSynthesizer {
@ -348,11 +334,6 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone +
None 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. /// Get this element's animation rule by the cascade level.
fn get_animation_rule_by_cascade(&self, fn get_animation_rule_by_cascade(&self,
_cascade_level: CascadeLevel) _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. /// Returns true if the element has all the specified selector flags.
fn has_selector_flags(&self, flags: ElementSelectorFlags) -> bool; 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. /// Creates a task to update various animation state on a given (pseudo-)element.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
fn update_animations(&self, fn update_animations(&self,

View file

@ -128,6 +128,10 @@ impl ToCss for Expression {
where W: fmt::Write, where W: fmt::Write,
{ {
dest.write_str("(")?; dest.write_str("(")?;
if (self.feature.mReqFlags & nsMediaFeature_RequirementFlags::eHasWebkitPrefix as u8) != 0 {
dest.write_str("-webkit-")?;
}
match self.range { match self.range {
nsMediaExpression_Range::eMin => dest.write_str("min-")?, nsMediaExpression_Range::eMin => dest.write_str("min-")?,
nsMediaExpression_Range::eMax => dest.write_str("max-")?, nsMediaExpression_Range::eMax => dest.write_str("max-")?,

View file

@ -107,6 +107,7 @@ macro_rules! apply_non_ts_list {
("-moz-only-whitespace", MozOnlyWhitespace, mozOnlyWhitespace, _, _), ("-moz-only-whitespace", MozOnlyWhitespace, mozOnlyWhitespace, _, _),
("-moz-native-anonymous", MozNativeAnonymous, mozNativeAnonymous, _, PSEUDO_CLASS_INTERNAL), ("-moz-native-anonymous", MozNativeAnonymous, mozNativeAnonymous, _, PSEUDO_CLASS_INTERNAL),
("-moz-is-html", MozIsHTML, mozIsHTML, _, _), ("-moz-is-html", MozIsHTML, mozIsHTML, _, _),
("-moz-placeholder", MozPlaceholder, mozPlaceholder, _, _),
], ],
string: [ string: [
("-moz-system-metric", MozSystemMetric, mozSystemMetric, _, PSEUDO_CLASS_INTERNAL), ("-moz-system-metric", MozSystemMetric, mozSystemMetric, _, PSEUDO_CLASS_INTERNAL),

View file

@ -102,6 +102,15 @@ impl PseudoElement {
pub fn is_precomputed(&self) -> bool { pub fn is_precomputed(&self) -> bool {
self.is_anon_box() 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 { impl ToCss for PseudoElement {

View file

@ -166,7 +166,8 @@ impl NonTSPseudoClass {
!matches!(*self, !matches!(*self,
NonTSPseudoClass::MozAny(_) | NonTSPseudoClass::MozAny(_) |
NonTSPseudoClass::Dir(_) | NonTSPseudoClass::Dir(_) |
NonTSPseudoClass::MozIsHTML) NonTSPseudoClass::MozIsHTML |
NonTSPseudoClass::MozPlaceholder)
} }
/// Convert NonTSPseudoClass to Gecko's CSSPseudoClassType. /// Convert NonTSPseudoClass to Gecko's CSSPseudoClassType.

View file

@ -18,7 +18,7 @@ use app_units::Au;
use atomic_refcell::AtomicRefCell; use atomic_refcell::AtomicRefCell;
use context::{QuirksMode, SharedStyleContext, UpdateAnimationsTasks}; use context::{QuirksMode, SharedStyleContext, UpdateAnimationsTasks};
use data::ElementData; 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 dom::{OpaqueNode, PresentationalHintsSynthesizer};
use element_state::ElementState; use element_state::ElementState;
use error_reporting::RustLogReporter; use error_reporting::RustLogReporter;
@ -422,11 +422,6 @@ impl<'le> GeckoElement<'le> {
} }
} }
#[inline]
fn may_have_animations(&self) -> bool {
self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementHasAnimations)
}
#[inline] #[inline]
fn has_id(&self) -> bool { fn has_id(&self) -> bool {
self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementHasID) 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) 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) fn get_animation_rule_by_cascade(&self, cascade_level: ServoCascadeLevel)
-> Option<Arc<Locked<PropertyDeclarationBlock>>> { -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
match cascade_level { match cascade_level {
@ -782,6 +772,11 @@ impl<'le> TElement for GeckoElement<'le> {
(self.flags() & node_flags) == node_flags (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, fn update_animations(&self,
before_change_style: Option<Arc<ComputedValues>>, before_change_style: Option<Arc<ComputedValues>>,
tasks: UpdateAnimationsTasks) { tasks: UpdateAnimationsTasks) {
@ -1335,6 +1330,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
NonTSPseudoClass::MozIsHTML => { NonTSPseudoClass::MozIsHTML => {
self.is_html_element_in_html_document() self.is_html_element_in_html_document()
} }
NonTSPseudoClass::MozPlaceholder => false,
NonTSPseudoClass::MozAny(ref sels) => { NonTSPseudoClass::MozAny(ref sels) => {
sels.iter().any(|s| { sels.iter().any(|s| {
matches_complex_selector(s, self, context, flags_setter) 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 // match the proper pseudo-element, given how we rulehash the stuff
// based on the pseudo. // based on the pseudo.
match self.implemented_pseudo_element() { match self.implemented_pseudo_element() {
Some(ref pseudo) => pseudo == pseudo_element, Some(ref pseudo) => *pseudo == pseudo_element.canonical(),
None => false, None => false,
} }
} }

View file

@ -239,6 +239,10 @@ impl Atom {
/// Return whether two atoms are ASCII-case-insensitive matches /// Return whether two atoms are ASCII-case-insensitive matches
pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool { pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
if self == other {
return true;
}
let a = self.as_slice(); let a = self.as_slice();
let b = other.as_slice(); let b = other.as_slice();
a.len() == b.len() && a.iter().zip(b).all(|(&a16, &b16)| { a.len() == b.len() && a.iter().zip(b).all(|(&a16, &b16)| {

View file

@ -10,10 +10,10 @@
use cascade_info::CascadeInfo; use cascade_info::CascadeInfo;
use context::{SelectorFlagsMap, SharedStyleContext, StyleContext}; use context::{SelectorFlagsMap, SharedStyleContext, StyleContext};
use data::{ComputedStyle, ElementData, RestyleData}; use data::{ComputedStyle, ElementData, RestyleData};
use dom::{AnimationRules, TElement, TNode}; use dom::{TElement, TNode};
use font_metrics::FontMetricsProvider; use font_metrics::FontMetricsProvider;
use log::LogLevel::Trace; 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 properties::longhands::display::computed_value as display;
use restyle_hints::{RESTYLE_CSS_ANIMATIONS, RESTYLE_CSS_TRANSITIONS, RestyleReplacements}; use restyle_hints::{RESTYLE_CSS_ANIMATIONS, RESTYLE_CSS_TRANSITIONS, RestyleReplacements};
use restyle_hints::{RESTYLE_STYLE_ATTRIBUTE, RESTYLE_SMIL}; 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 // We could make that a bit better if the complexity cost is not too
// big, but given further restyles are posted directly to // big, but given further restyles are posted directly to
// pseudo-elements, it doesn't seem worth the effort at a glance. // 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 = self.parent_element().unwrap();
let parent_data = parent.borrow_data().unwrap(); if !parent.may_have_animations() ||
let pseudo_style = primary_style.rules.get_animation_rules().is_empty() {
parent_data.styles().pseudos.get(&pseudo).unwrap(); let parent_data = parent.borrow_data().unwrap();
return pseudo_style.values().clone() 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(); let implemented_pseudo = self.implemented_pseudo_element();
if let Some(ref pseudo) = implemented_pseudo { 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 pseudo.is_eager() {
// If it's an eager element-backed pseudo, just grab the matched // If it's an eager element-backed pseudo, just grab the matched
// rules from the parent, and update animations. // rules from the parent, and update animations.
@ -692,38 +697,39 @@ pub trait MatchMethods : TElement {
let pseudo_style = let pseudo_style =
parent_data.styles().pseudos.get(&pseudo).unwrap(); parent_data.styles().pseudos.get(&pseudo).unwrap();
let mut rules = pseudo_style.rules.clone(); let mut rules = pseudo_style.rules.clone();
let animation_rules = self.get_animation_rules(); if parent.may_have_animations() {
let animation_rules = data.get_animation_rules();
// Handle animations here. // Handle animations here.
if let Some(animation_rule) = animation_rules.0 { if let Some(animation_rule) = animation_rules.0 {
let animation_rule_node = let animation_rule_node =
context.shared.stylist.rule_tree() context.shared.stylist.rule_tree()
.update_rule_at_level(CascadeLevel::Animations, .update_rule_at_level(CascadeLevel::Animations,
Some(&animation_rule), Some(&animation_rule),
&mut rules, &mut rules,
&context.shared.guards); &context.shared.guards);
if let Some(node) = animation_rule_node { if let Some(node) = animation_rule_node {
rules = 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 = let important_rules_changed =
self.has_animations() && self.has_animations() &&
data.has_styles() && data.has_styles() &&
data.important_rules_are_different(&rules, data.important_rules_are_different(&rules,
&context.shared.guards); &context.shared.guards);
return RulesMatchedResult { return RulesMatchedResult {
rule_nodes_changed: data.set_primary_rules(rules), rule_nodes_changed: data.set_primary_rules(rules),
@ -736,30 +742,35 @@ pub trait MatchMethods : TElement {
let stylist = &context.shared.stylist; let stylist = &context.shared.stylist;
let style_attribute = self.style_attribute(); let style_attribute = self.style_attribute();
let smil_override = self.get_smil_override(); {
let animation_rules = self.get_animation_rules(); let smil_override = data.get_smil_override();
let bloom = context.thread_local.bloom_filter.filter(); 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 matching_context =
let mut set_selector_flags = |element: &Self, flags: ElementSelectorFlags| { MatchingContext::new(MatchingMode::Normal, Some(bloom));
self.apply_selector_flags(map, element, flags);
};
let mut matching_context = // Compute the primary rule node.
MatchingContext::new(MatchingMode::Normal, Some(bloom)); 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. *relations = matching_context.relations;
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;
let primary_rule_node = let primary_rule_node =
compute_rule_node::<Self>(stylist.rule_tree(), 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 /// Updates the rule nodes without re-running selector matching, using just
/// the rule tree. Returns RulesChanged which indicates whether the rule nodes changed /// the rule tree. Returns true if an !important rule was replaced.
/// and whether the important rules changed.
fn replace_rules(&self, fn replace_rules(&self,
replacements: RestyleReplacements, replacements: RestyleReplacements,
context: &StyleContext<Self>, context: &StyleContext<Self>,
data: &mut ElementData) data: &mut ElementData)
-> RulesChanged { -> bool {
use properties::PropertyDeclarationBlock; use properties::PropertyDeclarationBlock;
use shared_lock::Locked; use shared_lock::Locked;
let element_styles = &mut data.styles_mut(); let element_styles = &mut data.styles_mut();
let primary_rules = &mut element_styles.primary.rules; let primary_rules = &mut element_styles.primary.rules;
let mut result = RulesChanged::empty();
{ let replace_rule_node = |level: CascadeLevel,
let mut replace_rule_node = |level: CascadeLevel, pdb: Option<&Arc<Locked<PropertyDeclarationBlock>>>,
pdb: Option<&Arc<Locked<PropertyDeclarationBlock>>>, path: &mut StrongRuleNode| -> bool {
path: &mut StrongRuleNode| { let new_node = context.shared.stylist.rule_tree()
let new_node = context.shared.stylist.rule_tree() .update_rule_at_level(level, pdb, path, &context.shared.guards);
.update_rule_at_level(level, pdb, path, &context.shared.guards); match new_node {
if let Some(n) = new_node { Some(n) => {
*path = n; *path = n;
if level.is_important() { level.is_important()
result.insert(IMPORTANT_RULES_CHANGED); },
} else { None => false,
result.insert(NORMAL_RULES_CHANGED); }
} };
}
if !context.shared.traversal_flags.for_animation_only() {
let mut result = false;
if replacements.contains(RESTYLE_STYLE_ATTRIBUTE) {
let style_attribute = self.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);
}
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);
}; };
// Animation restyle hints are processed prior to other restyle // Apply Transition rules and Animation rules if the corresponding restyle hint
// hints in the animation-only traversal. // is contained.
// if replacements.contains(RESTYLE_CSS_TRANSITIONS) {
// Non-animation restyle hints will be processed in a subsequent replace_rule_node_for_animation(CascadeLevel::Transitions,
// normal traversal. primary_rules);
if replacements.intersects(RestyleReplacements::for_animations()) { }
debug_assert!(context.shared.traversal_flags.for_animation_only());
if replacements.contains(RESTYLE_SMIL) { if replacements.contains(RESTYLE_CSS_ANIMATIONS) {
replace_rule_node(CascadeLevel::SMILOverride, replace_rule_node_for_animation(CascadeLevel::Animations,
self.get_smil_override(), primary_rules);
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);
}
if replacements.contains(RESTYLE_CSS_ANIMATIONS) {
replace_rule_node_for_animation(CascadeLevel::Animations,
primary_rules);
}
} else if replacements.contains(RESTYLE_STYLE_ATTRIBUTE) {
let style_attribute = self.style_attribute();
replace_rule_node(CascadeLevel::StyleAttributeNormal,
style_attribute,
primary_rules);
replace_rule_node(CascadeLevel::StyleAttributeImportant,
style_attribute,
primary_rules);
} }
} }
result false
} }
/// Attempts to share a style with another node. This method is unsafe /// Attempts to share a style with another node. This method is unsafe

View file

@ -11,6 +11,7 @@ use cssparser::{DeclarationListParser, parse_important};
use cssparser::{Parser, AtRuleParser, DeclarationParser, Delimiter}; use cssparser::{Parser, AtRuleParser, DeclarationParser, Delimiter};
use error_reporting::ParseErrorReporter; use error_reporting::ParseErrorReporter;
use parser::{PARSING_MODE_DEFAULT, ParsingMode, ParserContext, log_css_error}; use parser::{PARSING_MODE_DEFAULT, ParsingMode, ParserContext, log_css_error};
use shared_lock::Locked;
use std::fmt; use std::fmt;
use std::slice::Iter; use std::slice::Iter;
use style_traits::ToCss; use style_traits::ToCss;
@ -18,6 +19,20 @@ use stylesheets::{CssRuleType, Origin, UrlExtraData};
use super::*; use super::*;
#[cfg(feature = "gecko")] use properties::animated_properties::AnimationValueMap; #[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]. /// A declaration [importance][importance].
/// ///
/// [importance]: https://drafts.csswg.org/css-cascade/#importance /// [importance]: https://drafts.csswg.org/css-cascade/#importance

View file

@ -753,6 +753,7 @@ impl <T> Animatable for Option<T>
(&Some(ref this), &Some(ref other)) => { (&Some(ref this), &Some(ref other)) => {
Ok(this.add_weighted(other, self_portion, other_portion).ok()) Ok(this.add_weighted(other, self_portion, other_portion).ok())
} }
(&None, &None) => Ok(None),
_ => Err(()), _ => Err(()),
} }
} }
@ -763,6 +764,7 @@ impl <T> Animatable for Option<T>
(&Some(ref this), &Some(ref other)) => { (&Some(ref this), &Some(ref other)) => {
this.compute_distance(other) this.compute_distance(other)
}, },
(&None, &None) => Ok(0.0),
_ => Err(()), _ => Err(()),
} }
} }

View file

@ -464,12 +464,13 @@ ${helpers.single_keyword_system("font-variant-caps",
} }
/// Obtain a Servo computed value from a Gecko computed font-weight /// Obtain a Servo computed value from a Gecko computed font-weight
pub unsafe fn from_gecko_weight(weight: u16) -> Self { pub fn from_gecko_weight(weight: u16) -> Self {
use std::mem::transmute; match weight {
debug_assert!(weight >= 100); % for weight in range(100, 901, 100):
debug_assert!(weight <= 900); ${weight} => T::Weight${weight},
debug_assert!(weight % 10 == 0); % endfor
transmute(weight) _ => panic!("from_gecko_weight: called with invalid weight")
}
} }
} }
} }
@ -2362,9 +2363,7 @@ ${helpers.single_keyword("-moz-math-variant",
quoted: true quoted: true
}) })
}).collect::<Vec<_>>(); }).collect::<Vec<_>>();
let weight = unsafe { let weight = longhands::font_weight::computed_value::T::from_gecko_weight(system.weight);
longhands::font_weight::computed_value::T::from_gecko_weight(system.weight)
};
let ret = ComputedSystemFont { let ret = ComputedSystemFont {
font_family: longhands::font_family::computed_value::T(family), font_family: longhands::font_family::computed_value::T(family),
font_size: Au(system.size), font_size: Au(system.size),

View file

@ -39,17 +39,20 @@
let mut background_${name} = background_${name}::SpecifiedValue(Vec::new()); let mut background_${name} = background_${name}::SpecifiedValue(Vec::new());
% endfor % endfor
try!(input.parse_comma_separated(|input| { 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(): % for name in "image position repeat size attachment origin clip".split():
let mut ${name} = None; let mut ${name} = None;
% endfor % endfor
loop { 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); background_color = Some(value);
continue continue
} else {
// color can only be the last element
return Err(())
} }
} }
if position.is_none() { if position.is_none() {
@ -69,6 +72,13 @@
if ${name}.is_none() { if ${name}.is_none() {
if let Ok(value) = input.try(|input| background_${name}::single_value if let Ok(value) = input.try(|input| background_${name}::single_value
::parse(context, input)) { ::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); ${name} = Some(value);
continue continue
} }

View file

@ -8,7 +8,7 @@
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
use heapsize::HeapSizeOf; use heapsize::HeapSizeOf;
use properties::{Importance, LonghandIdSet, PropertyDeclarationBlock}; use properties::{AnimationRules, Importance, LonghandIdSet, PropertyDeclarationBlock};
use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard}; use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::io::{self, Write}; use std::io::{self, Write};
@ -1142,6 +1142,56 @@ impl StrongRuleNode {
} }
result 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. /// An iterator over a rule node and its ancestors.

View file

@ -152,6 +152,12 @@ impl PseudoElement {
PseudoElement::ServoInlineAbsolute => PseudoElementCascadeType::Precomputed, 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. /// A non tree-structural pseudo-class.

View file

@ -8,7 +8,7 @@ use {Atom, LocalName, Namespace};
use bit_vec::BitVec; use bit_vec::BitVec;
use context::{QuirksMode, SharedStyleContext}; use context::{QuirksMode, SharedStyleContext};
use data::ComputedStyle; use data::ComputedStyle;
use dom::{AnimationRules, TElement}; use dom::TElement;
use element_state::ElementState; use element_state::ElementState;
use error_reporting::RustLogReporter; use error_reporting::RustLogReporter;
use font_metrics::FontMetricsProvider; use font_metrics::FontMetricsProvider;
@ -17,9 +17,9 @@ use gecko_bindings::structs::nsIAtom;
use keyframes::KeyframesAnimation; use keyframes::KeyframesAnimation;
use media_queries::Device; use media_queries::Device;
use properties::{self, CascadeFlags, ComputedValues}; use properties::{self, CascadeFlags, ComputedValues};
use properties::{AnimationRules, PropertyDeclarationBlock};
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
use properties::INHERIT_ALL; use properties::INHERIT_ALL;
use properties::PropertyDeclarationBlock;
use restyle_hints::{HintComputationContext, DependencySet, RestyleHint}; use restyle_hints::{HintComputationContext, DependencySet, RestyleHint};
use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource}; use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
use selector_map::{SelectorMap, SelectorMapEntry}; use selector_map::{SelectorMap, SelectorMapEntry};
@ -473,7 +473,7 @@ impl Stylist {
{ {
let map = if let Some(pseudo) = selector.pseudo_element() { let map = if let Some(pseudo) = selector.pseudo_element() {
self.pseudos_map self.pseudos_map
.entry(pseudo.clone()) .entry(pseudo.canonical())
.or_insert_with(PerPseudoElementSelectorMap::new) .or_insert_with(PerPseudoElementSelectorMap::new)
.borrow_for_origin(&stylesheet.origin) .borrow_for_origin(&stylesheet.origin)
} else { } else {
@ -665,8 +665,9 @@ impl Stylist {
-> Option<StrongRuleNode> -> Option<StrongRuleNode>
where E: TElement where E: TElement
{ {
let pseudo = pseudo.canonical();
debug_assert!(pseudo.is_lazy()); debug_assert!(pseudo.is_lazy());
if self.pseudos_map.get(pseudo).is_none() { if self.pseudos_map.get(&pseudo).is_none() {
return None return None
} }
@ -698,7 +699,7 @@ impl Stylist {
let mut matching_context = let mut matching_context =
MatchingContext::new(MatchingMode::ForStatelessPseudoElement, None); MatchingContext::new(MatchingMode::ForStatelessPseudoElement, None);
self.push_applicable_declarations(element, self.push_applicable_declarations(element,
Some(pseudo), Some(&pseudo),
None, None,
None, None,
AnimationRules(None, None), AnimationRules(None, None),
@ -943,7 +944,7 @@ impl Stylist {
if let Some(anim) = animation_rules.0 { if let Some(anim) = animation_rules.0 {
Push::push( Push::push(
applicable_declarations, applicable_declarations,
ApplicableDeclarationBlock::from_declarations(anim, ApplicableDeclarationBlock::from_declarations(anim.clone(),
CascadeLevel::Animations)); CascadeLevel::Animations));
} }
debug!("animation: {:?}", context.relations); debug!("animation: {:?}", context.relations);
@ -961,7 +962,8 @@ impl Stylist {
if let Some(anim) = animation_rules.1 { if let Some(anim) = animation_rules.1 {
Push::push( Push::push(
applicable_declarations, applicable_declarations,
ApplicableDeclarationBlock::from_declarations(anim, CascadeLevel::Transitions)); ApplicableDeclarationBlock::from_declarations(anim.clone(),
CascadeLevel::Transitions));
} }
debug!("transition: {:?}", context.relations); debug!("transition: {:?}", context.relations);
debug!("push_applicable_declarations: shareable: {:?}", context.relations); debug!("push_applicable_declarations: shareable: {:?}", context.relations);

View file

@ -770,11 +770,11 @@ fn compute_style<E, D>(_traversal: &D,
) )
} }
CascadeWithReplacements(flags) => { 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( element.cascade_primary_and_pseudos(
context, context,
data, data,
rules_changed.important_rules_changed() important_rules_changed
) )
} }
CascadeOnly => { CascadeOnly => {