diff options
Diffstat (limited to 'servo/components/style/gecko')
-rw-r--r-- | servo/components/style/gecko/arc_types.rs | 13 | ||||
-rw-r--r-- | servo/components/style/gecko/media_features.rs | 19 | ||||
-rw-r--r-- | servo/components/style/gecko/media_queries.rs | 41 | ||||
-rw-r--r-- | servo/components/style/gecko/non_ts_pseudo_class_list.rs | 1 | ||||
-rw-r--r-- | servo/components/style/gecko/pseudo_element.rs | 6 | ||||
-rw-r--r-- | servo/components/style/gecko/selector_parser.rs | 4 | ||||
-rw-r--r-- | servo/components/style/gecko/snapshot.rs | 29 | ||||
-rw-r--r-- | servo/components/style/gecko/url.rs | 2 | ||||
-rw-r--r-- | servo/components/style/gecko/wrapper.rs | 79 |
9 files changed, 139 insertions, 55 deletions
diff --git a/servo/components/style/gecko/arc_types.rs b/servo/components/style/gecko/arc_types.rs index 24bf22d69a..420b86d332 100644 --- a/servo/components/style/gecko/arc_types.rs +++ b/servo/components/style/gecko/arc_types.rs @@ -16,7 +16,8 @@ use crate::stylesheets::keyframes_rule::Keyframe; use crate::stylesheets::{ ContainerRule, CounterStyleRule, CssRules, DocumentRule, FontFaceRule, FontFeatureValuesRule, FontPaletteValuesRule, ImportRule, KeyframesRule, LayerBlockRule, LayerStatementRule, - MediaRule, NamespaceRule, PageRule, PropertyRule, StyleRule, StylesheetContents, SupportsRule, + MediaRule, NamespaceRule, PageRule, PropertyRule, ScopeRule, StartingStyleRule, StyleRule, + StylesheetContents, SupportsRule, }; use servo_arc::Arc; @@ -169,3 +170,13 @@ impl_simple_arc_ffi!( Servo_AnimationValue_AddRef, Servo_AnimationValue_Release ); +impl_simple_arc_ffi!( + ScopeRule, + Servo_ScopeRule_AddRef, + Servo_ScopeRule_Release +); +impl_simple_arc_ffi!( + StartingStyleRule, + Servo_StartingStyleRule_AddRef, + Servo_StartingStyleRule_Release +); diff --git a/servo/components/style/gecko/media_features.rs b/servo/components/style/gecko/media_features.rs index 8de45d95c2..df1c5e464b 100644 --- a/servo/components/style/gecko/media_features.rs +++ b/servo/components/style/gecko/media_features.rs @@ -8,13 +8,14 @@ use crate::gecko_bindings::bindings; use crate::gecko_bindings::structs; use crate::gecko_bindings::structs::ScreenColorGamut; use crate::media_queries::{Device, MediaType}; -use crate::queries::condition::KleeneValue; +use crate::parser::ParserContext; use crate::queries::feature::{AllowsRanges, Evaluator, FeatureFlags, QueryFeatureDescription}; use crate::queries::values::Orientation; use crate::values::computed::{CSSPixelLength, Context, Ratio, Resolution}; use crate::values::AtomString; use app_units::Au; use euclid::default::Size2D; +use selectors::kleene_value::KleeneValue; fn device_size(device: &Device) -> Size2D<Au> { let mut width = 0; @@ -286,16 +287,26 @@ fn eval_prefers_contrast(context: &Context, query_value: Option<PrefersContrast> pub enum ForcedColors { /// Page colors are not being forced. None, + /// Page colors would be forced in content. + #[parse(condition = "ParserContext::chrome_rules_enabled")] + Requested, /// Page colors are being forced. Active, } +impl ForcedColors { + /// Returns whether forced-colors is active for this page. + pub fn is_active(self) -> bool { + matches!(self, Self::Active) + } +} + /// https://drafts.csswg.org/mediaqueries-5/#forced-colors fn eval_forced_colors(context: &Context, query_value: Option<ForcedColors>) -> bool { - let forced = !context.device().use_document_colors(); + let forced = context.device().forced_colors(); match query_value { - Some(query_value) => forced == (query_value == ForcedColors::Active), - None => forced, + Some(query_value) => query_value == forced, + None => forced != ForcedColors::None, } } diff --git a/servo/components/style/gecko/media_queries.rs b/servo/components/style/gecko/media_queries.rs index ef156ab380..ded66027f2 100644 --- a/servo/components/style/gecko/media_queries.rs +++ b/servo/components/style/gecko/media_queries.rs @@ -29,6 +29,8 @@ use std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering}; use std::{cmp, fmt}; use style_traits::{CSSPixel, DevicePixel}; +use super::media_features::ForcedColors; + /// The `Device` in Gecko wraps a pres context, has a default values computed, /// and contains all the viewport rule state. pub struct Device { @@ -172,10 +174,9 @@ impl Device { Length::new(f32::from_bits(self.root_font_size.load(Ordering::Relaxed))) } - /// Set the font size of the root element (for rem) - pub fn set_root_font_size(&self, size: Length) { - self.root_font_size - .store(size.px().to_bits(), Ordering::Relaxed) + /// Set the font size of the root element (for rem), in zoom-independent CSS pixels. + pub fn set_root_font_size(&self, size: f32) { + self.root_font_size.store(size.to_bits(), Ordering::Relaxed) } /// Get the line height of the root element (for rlh) @@ -186,10 +187,9 @@ impl Device { )) } - /// Set the line height of the root element (for rlh) - pub fn set_root_line_height(&self, size: Length) { - self.root_line_height - .store(size.px().to_bits(), Ordering::Relaxed); + /// Set the line height of the root element (for rlh), in zoom-independent CSS pixels. + pub fn set_root_line_height(&self, size: f32) { + self.root_line_height.store(size.to_bits(), Ordering::Relaxed); } /// The quirks mode of the document. @@ -498,12 +498,27 @@ impl Device { /// Returns whether document colors are enabled. #[inline] - pub fn use_document_colors(&self) -> bool { - let doc = self.document(); - if doc.mIsBeingUsedAsImage() { - return true; + pub fn forced_colors(&self) -> ForcedColors { + if self.document().mIsBeingUsedAsImage() { + // SVG images never force colors. + return ForcedColors::None + } + let prefs = self.pref_sheet_prefs(); + if !prefs.mUseDocumentColors { + return ForcedColors::Active + } + // On Windows, having a high contrast theme also means that the OS is requesting the + // colors to be forced. This is mostly convenience for the front-end, which wants to + // reuse the forced-colors styles for chrome in this case as well, and it's a lot + // more convenient to use `(forced-colors)` than + // `(forced-colors) or ((-moz-platform: windows) and (prefers-contrast))`. + // + // TODO(emilio): We might want to factor in here the lwtheme attribute in the root element + // and so on. + if cfg!(target_os = "windows") && prefs.mUseAccessibilityTheme && prefs.mIsChrome { + return ForcedColors::Requested; } - self.pref_sheet_prefs().mUseDocumentColors + ForcedColors::None } /// Computes a system color and returns it as an nscolor. diff --git a/servo/components/style/gecko/non_ts_pseudo_class_list.rs b/servo/components/style/gecko/non_ts_pseudo_class_list.rs index cc7495dd9c..f628c77ad5 100644 --- a/servo/components/style/gecko/non_ts_pseudo_class_list.rs +++ b/servo/components/style/gecko/non_ts_pseudo_class_list.rs @@ -98,7 +98,6 @@ macro_rules! apply_non_ts_list { // media query results are more expensive than document state changes. So for now // making them pseudo-classes is probably the right trade-off. ("-moz-is-html", MozIsHTML, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), - ("-moz-lwtheme", MozLWTheme, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), ("-moz-window-inactive", MozWindowInactive, _, _), ] } diff --git a/servo/components/style/gecko/pseudo_element.rs b/servo/components/style/gecko/pseudo_element.rs index 3bcd873455..f0e79a8acd 100644 --- a/servo/components/style/gecko/pseudo_element.rs +++ b/servo/components/style/gecko/pseudo_element.rs @@ -159,6 +159,11 @@ impl PseudoElement { matches!(*self, Self::Highlight(_)) } + /// Whether this pseudo-element is the ::target-text pseudo. + #[inline] + pub fn is_target_text(&self) -> bool { + *self == PseudoElement::TargetText + } /// 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 @@ -168,6 +173,7 @@ impl PseudoElement { pub fn enabled_in_content(&self) -> bool { match *self { Self::Highlight(..) => pref!("dom.customHighlightAPI.enabled"), + Self::TargetText => pref!("dom.text_fragments.enabled"), Self::SliderFill | Self::SliderTrack | Self::SliderThumb => { pref!("layout.css.modern-range-pseudos.enabled") }, diff --git a/servo/components/style/gecko/selector_parser.rs b/servo/components/style/gecko/selector_parser.rs index 203e6a3609..100bb45e81 100644 --- a/servo/components/style/gecko/selector_parser.rs +++ b/servo/components/style/gecko/selector_parser.rs @@ -196,7 +196,6 @@ impl NonTSPseudoClass { None => DocumentState::empty(), }, NonTSPseudoClass::MozWindowInactive => DocumentState::WINDOW_INACTIVE, - NonTSPseudoClass::MozLWTheme => DocumentState::LWTHEME, _ => DocumentState::empty(), } } @@ -214,11 +213,10 @@ impl NonTSPseudoClass { NonTSPseudoClass::MozNativeAnonymous | // :-moz-placeholder is parsed but never matches. NonTSPseudoClass::MozPlaceholder | - // :-moz-is-html, :-moz-lwtheme, :-moz-locale-dir and :-moz-window-inactive + // :-moz-is-html, :-moz-locale-dir and :-moz-window-inactive // depend only on the state of the document, which is invariant across all // elements involved in a given style cache. NonTSPseudoClass::MozIsHTML | - NonTSPseudoClass::MozLWTheme | NonTSPseudoClass::MozLocaleDir(_) | NonTSPseudoClass::MozWindowInactive ) diff --git a/servo/components/style/gecko/snapshot.rs b/servo/components/style/gecko/snapshot.rs index 2ff04406ac..8f6eb120d5 100644 --- a/servo/components/style/gecko/snapshot.rs +++ b/servo/components/style/gecko/snapshot.rs @@ -171,4 +171,33 @@ impl ElementSnapshot for GeckoElementSnapshot { Some(AtomString(unsafe { Atom::from_addrefed(ptr) })) } } + + /// Returns true if the snapshot has stored state for custom states + #[inline] + fn has_custom_states(&self) -> bool { + self.has_any(Flags::CustomState) + } + + /// Returns true if the snapshot has a given CustomState + #[inline] + fn has_custom_state(&self, state: &AtomIdent) -> bool { + unsafe { + self.mCustomStates.iter().any(|setstate| { + AtomIdent::with(setstate.mRawPtr, |setstate| state == setstate) + }) + } + } + + #[inline] + fn each_custom_state<F>(&self, mut callback: F) + where + F: FnMut(&AtomIdent), + { + unsafe { + for atom in self.mCustomStates.iter() { + AtomIdent::with(atom.mRawPtr, &mut callback) + } + } + } + } diff --git a/servo/components/style/gecko/url.rs b/servo/components/style/gecko/url.rs index 7fe32acc20..fa8d22adb6 100644 --- a/servo/components/style/gecko/url.rs +++ b/servo/components/style/gecko/url.rs @@ -18,7 +18,7 @@ use std::fmt::{self, Write}; use std::mem::ManuallyDrop; use std::sync::RwLock; use style_traits::{CssWriter, ParseError, ToCss}; -use to_shmem::{self, SharedMemoryBuilder, ToShmem}; +use to_shmem::{SharedMemoryBuilder, ToShmem}; /// A CSS url() value for gecko. #[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] diff --git a/servo/components/style/gecko/wrapper.rs b/servo/components/style/gecko/wrapper.rs index 43cf6e7941..eab968149c 100644 --- a/servo/components/style/gecko/wrapper.rs +++ b/servo/components/style/gecko/wrapper.rs @@ -19,7 +19,7 @@ use crate::bloom::each_relevant_element_hash; use crate::context::{PostAnimationTasks, QuirksMode, SharedStyleContext, UpdateAnimationsTasks}; use crate::data::ElementData; use crate::dom::{LayoutIterator, NodeInfo, OpaqueNode, TDocument, TElement, TNode, TShadowRoot}; -use crate::gecko::selector_parser::{CustomState, NonTSPseudoClass, PseudoElement, SelectorImpl}; +use crate::gecko::selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl}; use crate::gecko::snapshot_helpers; use crate::gecko_bindings::bindings; use crate::gecko_bindings::bindings::Gecko_ElementHasAnimations; @@ -889,7 +889,11 @@ impl<'le> GeckoElement<'le> { AnimationValue::from_computed_values(property_declaration_id, before_change_style); let to = AnimationValue::from_computed_values(property_declaration_id, after_change_style); - debug_assert_eq!(to.is_some(), from.is_some()); + // If the declaration contains a custom property and getComputedValue was previously called + // before that custom property was defined, `from` will be `None` here. + debug_assert!( + to.is_some() == from.is_some() || matches!(to, Some(AnimationValue::Custom(..))) + ); from != to } @@ -1237,20 +1241,6 @@ impl<'le> TElement for GeckoElement<'le> { } #[inline] - fn has_custom_state(&self, state: &CustomState) -> bool { - if !self.is_html_element() { - return false; - } - let check_state_ptr: *const nsAtom = state.0.as_ptr(); - self.extended_slots().map_or(false, |slot| { - (&slot.mCustomStates).iter().any(|setstate| { - let setstate_ptr: *const nsAtom = setstate.mRawPtr; - setstate_ptr == check_state_ptr - }) - }) - } - - #[inline] fn has_part_attr(&self) -> bool { self.as_node() .get_bool_flag(nsINode_BooleanFlag::ElementHasPart) @@ -1292,6 +1282,20 @@ impl<'le> TElement for GeckoElement<'le> { } #[inline] + fn each_custom_state<F>(&self, mut callback: F) + where + F: FnMut(&AtomIdent), + { + if let Some(slots) = self.extended_slots() { + unsafe { + for atom in slots.mCustomStates.iter() { + AtomIdent::with(atom.mRawPtr, &mut callback) + } + } + } + } + + #[inline] fn each_exported_part<F>(&self, name: &AtomIdent, callback: F) where F: FnMut(&AtomIdent), @@ -1551,14 +1555,13 @@ impl<'le> TElement for GeckoElement<'le> { let mut transitions_to_keep = PropertyDeclarationIdSet::default(); for transition_property in after_change_style.transition_properties() { - let physical_longhand = PropertyDeclarationId::Longhand( - transition_property - .longhand_id - .to_physical(after_change_style.writing_mode), - ); - transitions_to_keep.insert(physical_longhand); + let physical_property = transition_property + .property + .as_borrowed() + .to_physical(after_change_style.writing_mode); + transitions_to_keep.insert(physical_property); if self.needs_transitions_update_per_property( - physical_longhand, + physical_property, after_change_ui_style .transition_combined_duration_at(transition_property.index) .seconds(), @@ -1791,17 +1794,17 @@ impl<'le> TElement for GeckoElement<'le> { self.as_node().selector_flags() & node_flags == node_flags } - fn relative_selector_search_direction(&self) -> Option<ElementSelectorFlags> { + fn relative_selector_search_direction(&self) -> ElementSelectorFlags { use crate::gecko_bindings::structs::NodeSelectorFlags; let flags = self.as_node().selector_flags(); if (flags & NodeSelectorFlags::RelativeSelectorSearchDirectionAncestorSibling.0) != 0 { - Some(ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR_SIBLING) + ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR_SIBLING } else if (flags & NodeSelectorFlags::RelativeSelectorSearchDirectionAncestor.0) != 0 { - Some(ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR) + ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR } else if (flags & NodeSelectorFlags::RelativeSelectorSearchDirectionSibling.0) != 0 { - Some(ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING) + ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING } else { - None + ElementSelectorFlags::empty() } } } @@ -2042,15 +2045,14 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { NonTSPseudoClass::MozAutofillPreview | NonTSPseudoClass::MozRevealed | NonTSPseudoClass::MozValueEmpty => self.state().intersects(pseudo_class.state_flag()), - // TODO: This applying only to HTML elements is weird. NonTSPseudoClass::Dir(ref dir) => { - self.is_html_element() && self.state().intersects(dir.element_state()) + self.state().intersects(dir.element_state()) }, NonTSPseudoClass::AnyLink => self.is_link(), NonTSPseudoClass::Link => { self.is_link() && context.visited_handling().matches_unvisited() }, - NonTSPseudoClass::CustomState(ref state) => self.has_custom_state(state), + NonTSPseudoClass::CustomState(ref state) => self.has_custom_state(&state.0), NonTSPseudoClass::Visited => { self.is_link() && context.visited_handling().matches_visited() }, @@ -2101,7 +2103,6 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { bindings::Gecko_IsSelectListBox(self.0) }, NonTSPseudoClass::MozIsHTML => self.as_node().owner_doc().is_html_document(), - NonTSPseudoClass::MozLWTheme | NonTSPseudoClass::MozLocaleDir(..) | NonTSPseudoClass::MozWindowInactive => { let state_bit = pseudo_class.document_state_flag(); @@ -2186,6 +2187,20 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { } #[inline] + fn has_custom_state(&self, state: &AtomIdent) -> bool { + if !self.is_html_element() { + return false; + } + let check_state_ptr: *const nsAtom = state.as_ptr(); + self.extended_slots().map_or(false, |slot| { + (&slot.mCustomStates).iter().any(|setstate| { + let setstate_ptr: *const nsAtom = setstate.mRawPtr; + setstate_ptr == check_state_ptr + }) + }) + } + + #[inline] fn is_html_element_in_html_document(&self) -> bool { self.is_html_element() && self.as_node().owner_doc().is_html_document() } |