From 86b3b6a32f2f1e1064ec0bdd70f37bddf44b377c Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 21 Jul 2017 14:16:06 -0400 Subject: [PATCH] Filter out non-applying properties when cascading style for ::first-letter/::first-line/::placeholder. r=emilio Part 3 of the fix for Gecko bug 1382786 . --- components/style/gecko/pseudo_element.rs | 13 +++++++++++++ components/style/properties/properties.mako.rs | 15 +++++++++++++++ components/style/servo/selector_parser.rs | 13 +++++++++++++ 3 files changed, 41 insertions(+) diff --git a/components/style/gecko/pseudo_element.rs b/components/style/gecko/pseudo_element.rs index 97ce0f4e5a1..7765122bd61 100644 --- a/components/style/gecko/pseudo_element.rs +++ b/components/style/gecko/pseudo_element.rs @@ -10,6 +10,8 @@ use cssparser::{ToCss, serialize_identifier}; use gecko_bindings::structs::{self, CSSPseudoElementType}; +use properties::{PropertyFlags, APPLIES_TO_FIRST_LETTER, APPLIES_TO_FIRST_LINE}; +use properties::APPLIES_TO_PLACEHOLDER; use selector_parser::{NonTSPseudoClass, PseudoElementCascadeType, SelectorImpl}; use std::fmt; use string_cache::Atom; @@ -119,4 +121,15 @@ impl PseudoElement { _ => self.clone(), } } + + /// Property flag that properties must have to apply to this pseudo-element. + #[inline] + pub fn property_restriction(&self) -> Option { + match *self { + PseudoElement::FirstLetter => Some(APPLIES_TO_FIRST_LETTER), + PseudoElement::FirstLine => Some(APPLIES_TO_FIRST_LINE), + PseudoElement::Placeholder => Some(APPLIES_TO_PLACEHOLDER), + _ => None, + } + } } diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 6eeeb33f913..6e1bf5e7477 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -2872,11 +2872,26 @@ pub fn cascade( &[] }; let node_importance = node.importance(); + + let property_restriction = pseudo.and_then(|p| p.property_restriction()); + declarations .iter() // Yield declarations later in source order (with more precedence) first. .rev() .filter_map(move |&(ref declaration, declaration_importance)| { + if let Some(property_restriction) = property_restriction { + // declaration.id() is either a longhand or a custom + // property. Custom properties are always allowed, but + // longhands are only allowed if they have our + // property_restriction flag set. + if let PropertyDeclarationId::Longhand(id) = declaration.id() { + if !id.flags().contains(property_restriction) { + return None + } + } + } + if declaration_importance == node_importance { Some((declaration, cascade_level)) } else { diff --git a/components/style/servo/selector_parser.rs b/components/style/servo/selector_parser.rs index e2dfc46f74d..b231265775a 100644 --- a/components/style/servo/selector_parser.rs +++ b/components/style/servo/selector_parser.rs @@ -13,6 +13,7 @@ use dom::{OpaqueNode, TElement, TNode}; use element_state::ElementState; use fnv::FnvHashMap; use invalidation::element::element_wrapper::ElementSnapshot; +use properties::PropertyFlags; use selector_parser::{AttrValue as SelectorAttrValue, ElementExt, PseudoElementCascadeType, SelectorParser}; use selectors::Element; use selectors::attr::{AttrSelectorOperation, NamespaceConstraint, CaseSensitivity}; @@ -39,6 +40,12 @@ pub enum PseudoElement { Before, Selection, // If/when :first-letter is added, update is_first_letter accordingly. + + // If/when ::first-letter, ::first-line, or ::placeholder are added, adjust + // our property_restriction implementation to do property filtering for + // them. Also, make sure the UA sheet has the !important rules some of the + // APPLIES_TO_PLACEHOLDER properties expect! + // Non-eager pseudos. DetailsSummary, DetailsContent, @@ -169,6 +176,12 @@ impl PseudoElement { /// Stub, only Gecko needs this pub fn pseudo_info(&self) { () } + + /// Property flag that properties must have to apply to this pseudo-element. + #[inline] + pub fn property_restriction(&self) -> Option { + None + } } /// The type used for storing pseudo-class string arguments.