aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2017-05-24 16:08:02 -0500
committerGitHub <noreply@github.com>2017-05-24 16:08:02 -0500
commit8ae546f7ea158466441987d4a86c5c440f0a5e00 (patch)
treeb2eaae4c7b661879577a5bdddff9b811ef39bc4e
parentbb310efbb9e84cf0bd44170c4e08bac664f0ce86 (diff)
parent8c9c506f9015da5a23858a6eaf75bd7ee187a01e (diff)
downloadservo-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.rs20
-rw-r--r--components/style/data.rs29
-rw-r--r--components/style/dom.rs24
-rw-r--r--components/style/gecko/media_queries.rs4
-rw-r--r--components/style/gecko/non_ts_pseudo_class_list.rs1
-rw-r--r--components/style/gecko/pseudo_element.rs9
-rw-r--r--components/style/gecko/selector_parser.rs3
-rw-r--r--components/style/gecko/wrapper.rs20
-rw-r--r--components/style/gecko_string_cache/mod.rs4
-rw-r--r--components/style/matching.rs228
-rw-r--r--components/style/properties/declaration_block.rs15
-rw-r--r--components/style/properties/helpers/animated_properties.mako.rs2
-rw-r--r--components/style/properties/longhand/font.mako.rs17
-rw-r--r--components/style/properties/shorthand/background.mako.rs20
-rw-r--r--components/style/rule_tree/mod.rs52
-rw-r--r--components/style/servo/selector_parser.rs6
-rw-r--r--components/style/stylist.rs16
-rw-r--r--components/style/traversal.rs4
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 => {