1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 //! Gecko's definition of a pseudo-element. 6 //! 7 //! Note that a few autogenerated bits of this live in 8 //! `pseudo_element_definition.mako.rs`. If you touch that file, you probably 9 //! need to update the checked-in files for Servo. 10 11 use cssparser::ToCss; 12 use gecko_bindings::structs::{self, CSSPseudoElementType}; 13 use properties::{CascadeFlags, ComputedValues, PropertyFlags}; 14 use properties::longhands::display::computed_value::T as Display; 15 use selector_parser::{NonTSPseudoClass, PseudoElementCascadeType, SelectorImpl}; 16 use std::fmt; 17 use string_cache::Atom; 18 use values::serialize_atom_identifier; 19 20 include!(concat!(env!("OUT_DIR"), "/gecko/pseudo_element_definition.rs")); 21 22 impl ::selectors::parser::PseudoElement for PseudoElement { 23 type Impl = SelectorImpl; 24 supports_pseudo_class(&self, pseudo_class: &NonTSPseudoClass) -> bool25 fn supports_pseudo_class(&self, pseudo_class: &NonTSPseudoClass) -> bool { 26 if !self.supports_user_action_state() { 27 return false; 28 } 29 30 return pseudo_class.is_safe_user_action_state(); 31 } 32 } 33 34 impl PseudoElement { 35 /// Returns the kind of cascade type that a given pseudo is going to use. 36 /// 37 /// In Gecko we only compute ::before and ::after eagerly. We save the rules 38 /// for anonymous boxes separately, so we resolve them as precomputed 39 /// pseudos. 40 /// 41 /// We resolve the others lazily, see `Servo_ResolvePseudoStyle`. cascade_type(&self) -> PseudoElementCascadeType42 pub fn cascade_type(&self) -> PseudoElementCascadeType { 43 if self.is_eager() { 44 debug_assert!(!self.is_anon_box()); 45 return PseudoElementCascadeType::Eager 46 } 47 48 if self.is_precomputed() { 49 return PseudoElementCascadeType::Precomputed 50 } 51 52 PseudoElementCascadeType::Lazy 53 } 54 55 /// The CascadeFlags needed to cascade this pseudo-element. 56 /// 57 /// This is only needed to support the broken INHERIT_ALL pseudo mode for 58 /// Servo. 59 #[inline] cascade_flags(&self) -> CascadeFlags60 pub fn cascade_flags(&self) -> CascadeFlags { 61 CascadeFlags::empty() 62 } 63 64 /// Whether the pseudo-element should inherit from the default computed 65 /// values instead of from the parent element. 66 /// 67 /// This is not the common thing, but there are some pseudos (namely: 68 /// ::backdrop), that shouldn't inherit from the parent element. inherits_from_default_values(&self) -> bool69 pub fn inherits_from_default_values(&self) -> bool { 70 matches!(*self, PseudoElement::Backdrop) 71 } 72 73 /// Gets the canonical index of this eagerly-cascaded pseudo-element. 74 #[inline] eager_index(&self) -> usize75 pub fn eager_index(&self) -> usize { 76 EAGER_PSEUDOS.iter().position(|p| p == self) 77 .expect("Not an eager pseudo") 78 } 79 80 /// Creates a pseudo-element from an eager index. 81 #[inline] from_eager_index(i: usize) -> Self82 pub fn from_eager_index(i: usize) -> Self { 83 EAGER_PSEUDOS[i].clone() 84 } 85 86 /// Whether the current pseudo element is ::before or ::after. 87 #[inline] is_before_or_after(&self) -> bool88 pub fn is_before_or_after(&self) -> bool { 89 self.is_before() || self.is_after() 90 } 91 92 /// Whether this pseudo-element is the ::before pseudo. 93 #[inline] is_before(&self) -> bool94 pub fn is_before(&self) -> bool { 95 *self == PseudoElement::Before 96 } 97 98 /// Whether this pseudo-element is the ::after pseudo. 99 #[inline] is_after(&self) -> bool100 pub fn is_after(&self) -> bool { 101 *self == PseudoElement::After 102 } 103 104 /// Whether this pseudo-element is ::first-letter. 105 #[inline] is_first_letter(&self) -> bool106 pub fn is_first_letter(&self) -> bool { 107 *self == PseudoElement::FirstLetter 108 } 109 110 /// Whether this pseudo-element is ::first-line. 111 #[inline] is_first_line(&self) -> bool112 pub fn is_first_line(&self) -> bool { 113 *self == PseudoElement::FirstLine 114 } 115 116 /// Whether this pseudo-element is ::-moz-fieldset-content. 117 #[inline] is_fieldset_content(&self) -> bool118 pub fn is_fieldset_content(&self) -> bool { 119 *self == PseudoElement::FieldsetContent 120 } 121 122 /// Whether this pseudo-element is lazily-cascaded. 123 #[inline] is_lazy(&self) -> bool124 pub fn is_lazy(&self) -> bool { 125 !self.is_eager() && !self.is_precomputed() 126 } 127 128 /// Whether this pseudo-element supports user action selectors. supports_user_action_state(&self) -> bool129 pub fn supports_user_action_state(&self) -> bool { 130 (self.flags() & structs::CSS_PSEUDO_ELEMENT_SUPPORTS_USER_ACTION_STATE) != 0 131 } 132 133 /// Whether this pseudo-element is enabled for all content. enabled_in_content(&self) -> bool134 pub fn enabled_in_content(&self) -> bool { 135 (self.flags() & structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS_AND_CHROME) == 0 136 } 137 138 /// Whether this pseudo is enabled explicitly in UA sheets. enabled_in_ua_sheets(&self) -> bool139 pub fn enabled_in_ua_sheets(&self) -> bool { 140 (self.flags() & structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS) != 0 141 } 142 143 /// Whether this pseudo is enabled explicitly in chrome sheets. enabled_in_chrome(&self) -> bool144 pub fn enabled_in_chrome(&self) -> bool { 145 (self.flags() & structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_CHROME) != 0 146 } 147 148 /// Whether this pseudo-element skips flex/grid container display-based 149 /// fixup. 150 #[inline] skip_item_display_fixup(&self) -> bool151 pub fn skip_item_display_fixup(&self) -> bool { 152 (self.flags() & structs::CSS_PSEUDO_ELEMENT_IS_FLEX_OR_GRID_ITEM) == 0 153 } 154 155 /// Whether this pseudo-element is precomputed. 156 #[inline] is_precomputed(&self) -> bool157 pub fn is_precomputed(&self) -> bool { 158 self.is_anon_box() && !self.is_tree_pseudo_element() 159 } 160 161 /// Covert non-canonical pseudo-element to canonical one, and keep a 162 /// canonical one as it is. canonical(&self) -> PseudoElement163 pub fn canonical(&self) -> PseudoElement { 164 match *self { 165 PseudoElement::MozPlaceholder => PseudoElement::Placeholder, 166 _ => self.clone(), 167 } 168 } 169 170 /// Property flag that properties must have to apply to this pseudo-element. 171 #[inline] property_restriction(&self) -> Option<PropertyFlags>172 pub fn property_restriction(&self) -> Option<PropertyFlags> { 173 match *self { 174 PseudoElement::FirstLetter => Some(PropertyFlags::APPLIES_TO_FIRST_LETTER), 175 PseudoElement::FirstLine => Some(PropertyFlags::APPLIES_TO_FIRST_LINE), 176 PseudoElement::Placeholder => Some(PropertyFlags::APPLIES_TO_PLACEHOLDER), 177 _ => None, 178 } 179 } 180 181 /// Whether this pseudo-element should actually exist if it has 182 /// the given styles. should_exist(&self, style: &ComputedValues) -> bool183 pub fn should_exist(&self, style: &ComputedValues) -> bool { 184 if style.get_box().clone_display() == Display::None { 185 return false; 186 } 187 188 if self.is_before_or_after() && style.ineffective_content_property() { 189 return false; 190 } 191 192 true 193 } 194 } 195