mirror of
https://github.com/servo/servo.git
synced 2025-06-21 07:38:59 +01:00
This never worked, but it's more visible with the new form controls which have more padding. Make the anonymous div and co a pseudo-element, so that they inherit from the <input> properly in all cases. This works for non-number inputs because the editor root is a direct child of the <input>, but it doesn't for number inputs because there's a flex wrapper in between. This way overflow-clip-box: inherit does what we want. Reset the padding in the inline direction, as the padding for <input type=number> applies to the arrow boxes as well, and thus we'd double-apply it. Differential Revision: https://phabricator.services.mozilla.com/D65271
212 lines
6.9 KiB
Rust
212 lines
6.9 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
//! Gecko's definition of a pseudo-element.
|
|
//!
|
|
//! Note that a few autogenerated bits of this live in
|
|
//! `pseudo_element_definition.mako.rs`. If you touch that file, you probably
|
|
//! need to update the checked-in files for Servo.
|
|
|
|
use crate::gecko_bindings::structs::{self, PseudoStyleType};
|
|
use crate::properties::longhands::display::computed_value::T as Display;
|
|
use crate::properties::{ComputedValues, PropertyFlags};
|
|
use crate::selector_parser::{PseudoElementCascadeType, SelectorImpl};
|
|
use crate::str::{starts_with_ignore_ascii_case, string_as_ascii_lowercase};
|
|
use crate::string_cache::Atom;
|
|
use crate::values::serialize_atom_identifier;
|
|
use cssparser::ToCss;
|
|
use std::fmt;
|
|
use thin_slice::ThinBoxedSlice;
|
|
|
|
include!(concat!(
|
|
env!("OUT_DIR"),
|
|
"/gecko/pseudo_element_definition.rs"
|
|
));
|
|
|
|
impl ::selectors::parser::PseudoElement for PseudoElement {
|
|
type Impl = SelectorImpl;
|
|
|
|
// ::slotted() should support all tree-abiding pseudo-elements, see
|
|
// https://drafts.csswg.org/css-scoping/#slotted-pseudo
|
|
// https://drafts.csswg.org/css-pseudo-4/#treelike
|
|
#[inline]
|
|
fn valid_after_slotted(&self) -> bool {
|
|
matches!(
|
|
*self,
|
|
PseudoElement::Before |
|
|
PseudoElement::After |
|
|
PseudoElement::Marker |
|
|
PseudoElement::Placeholder
|
|
)
|
|
}
|
|
|
|
#[inline]
|
|
fn accepts_state_pseudo_classes(&self) -> bool {
|
|
self.supports_user_action_state()
|
|
}
|
|
}
|
|
|
|
impl PseudoElement {
|
|
/// Returns the kind of cascade type that a given pseudo is going to use.
|
|
///
|
|
/// In Gecko we only compute ::before and ::after eagerly. We save the rules
|
|
/// for anonymous boxes separately, so we resolve them as precomputed
|
|
/// pseudos.
|
|
///
|
|
/// We resolve the others lazily, see `Servo_ResolvePseudoStyle`.
|
|
pub fn cascade_type(&self) -> PseudoElementCascadeType {
|
|
if self.is_eager() {
|
|
debug_assert!(!self.is_anon_box());
|
|
return PseudoElementCascadeType::Eager;
|
|
}
|
|
|
|
if self.is_precomputed() {
|
|
return PseudoElementCascadeType::Precomputed;
|
|
}
|
|
|
|
PseudoElementCascadeType::Lazy
|
|
}
|
|
|
|
/// Whether the pseudo-element should inherit from the default computed
|
|
/// values instead of from the parent element.
|
|
///
|
|
/// This is not the common thing, but there are some pseudos (namely:
|
|
/// ::backdrop), that shouldn't inherit from the parent element.
|
|
pub fn inherits_from_default_values(&self) -> bool {
|
|
matches!(*self, PseudoElement::Backdrop)
|
|
}
|
|
|
|
/// Gets the canonical index of this eagerly-cascaded pseudo-element.
|
|
#[inline]
|
|
pub fn eager_index(&self) -> usize {
|
|
EAGER_PSEUDOS
|
|
.iter()
|
|
.position(|p| p == self)
|
|
.expect("Not an eager pseudo")
|
|
}
|
|
|
|
/// Creates a pseudo-element from an eager index.
|
|
#[inline]
|
|
pub fn from_eager_index(i: usize) -> Self {
|
|
EAGER_PSEUDOS[i].clone()
|
|
}
|
|
|
|
/// Whether the current pseudo element is ::before or ::after.
|
|
#[inline]
|
|
pub fn is_before_or_after(&self) -> bool {
|
|
self.is_before() || self.is_after()
|
|
}
|
|
|
|
/// Whether this pseudo-element is the ::before pseudo.
|
|
#[inline]
|
|
pub fn is_before(&self) -> bool {
|
|
*self == PseudoElement::Before
|
|
}
|
|
|
|
/// Whether this pseudo-element is the ::after pseudo.
|
|
#[inline]
|
|
pub fn is_after(&self) -> bool {
|
|
*self == PseudoElement::After
|
|
}
|
|
|
|
/// Whether this pseudo-element is the ::marker pseudo.
|
|
#[inline]
|
|
pub fn is_marker(&self) -> bool {
|
|
*self == PseudoElement::Marker
|
|
}
|
|
|
|
/// Whether this pseudo-element is the ::selection pseudo.
|
|
#[inline]
|
|
pub fn is_selection(&self) -> bool {
|
|
*self == PseudoElement::Selection
|
|
}
|
|
|
|
/// Whether this pseudo-element is ::first-letter.
|
|
#[inline]
|
|
pub fn is_first_letter(&self) -> bool {
|
|
*self == PseudoElement::FirstLetter
|
|
}
|
|
|
|
/// Whether this pseudo-element is ::first-line.
|
|
#[inline]
|
|
pub fn is_first_line(&self) -> bool {
|
|
*self == PseudoElement::FirstLine
|
|
}
|
|
|
|
/// Whether this pseudo-element is the ::-moz-color-swatch pseudo.
|
|
#[inline]
|
|
pub fn is_color_swatch(&self) -> bool {
|
|
*self == PseudoElement::MozColorSwatch
|
|
}
|
|
|
|
/// Whether this pseudo-element is lazily-cascaded.
|
|
#[inline]
|
|
pub fn is_lazy(&self) -> bool {
|
|
!self.is_eager() && !self.is_precomputed()
|
|
}
|
|
|
|
/// Whether this pseudo-element supports user action selectors.
|
|
pub fn supports_user_action_state(&self) -> bool {
|
|
(self.flags() & structs::CSS_PSEUDO_ELEMENT_SUPPORTS_USER_ACTION_STATE) != 0
|
|
}
|
|
|
|
/// Whether this pseudo-element is enabled for all content.
|
|
pub fn enabled_in_content(&self) -> bool {
|
|
(self.flags() & structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS_AND_CHROME) == 0
|
|
}
|
|
|
|
/// Whether this pseudo is enabled explicitly in UA sheets.
|
|
pub fn enabled_in_ua_sheets(&self) -> bool {
|
|
(self.flags() & structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS) != 0
|
|
}
|
|
|
|
/// Whether this pseudo is enabled explicitly in chrome sheets.
|
|
pub fn enabled_in_chrome(&self) -> bool {
|
|
(self.flags() & structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_CHROME) != 0
|
|
}
|
|
|
|
/// Whether this pseudo-element skips flex/grid container display-based
|
|
/// fixup.
|
|
#[inline]
|
|
pub fn skip_item_display_fixup(&self) -> bool {
|
|
(self.flags() & structs::CSS_PSEUDO_ELEMENT_IS_FLEX_OR_GRID_ITEM) == 0
|
|
}
|
|
|
|
/// Whether this pseudo-element is precomputed.
|
|
#[inline]
|
|
pub fn is_precomputed(&self) -> bool {
|
|
self.is_anon_box() && !self.is_tree_pseudo_element()
|
|
}
|
|
|
|
/// Property flag that properties must have to apply to this pseudo-element.
|
|
#[inline]
|
|
pub fn property_restriction(&self) -> Option<PropertyFlags> {
|
|
Some(match *self {
|
|
PseudoElement::FirstLetter => PropertyFlags::APPLIES_TO_FIRST_LETTER,
|
|
PseudoElement::FirstLine => PropertyFlags::APPLIES_TO_FIRST_LINE,
|
|
PseudoElement::Placeholder => PropertyFlags::APPLIES_TO_PLACEHOLDER,
|
|
PseudoElement::Cue => PropertyFlags::APPLIES_TO_CUE,
|
|
PseudoElement::Marker if static_prefs::pref!("layout.css.marker.restricted") => {
|
|
PropertyFlags::APPLIES_TO_MARKER
|
|
},
|
|
_ => return None,
|
|
})
|
|
}
|
|
|
|
/// Whether this pseudo-element should actually exist if it has
|
|
/// the given styles.
|
|
pub fn should_exist(&self, style: &ComputedValues) -> bool {
|
|
debug_assert!(self.is_eager());
|
|
|
|
if style.get_box().clone_display() == Display::None {
|
|
return false;
|
|
}
|
|
|
|
if self.is_before_or_after() && style.ineffective_content_property() {
|
|
return false;
|
|
}
|
|
|
|
true
|
|
}
|
|
}
|