summaryrefslogtreecommitdiffstats
path: root/servo/components/style/gecko
diff options
context:
space:
mode:
Diffstat (limited to 'servo/components/style/gecko')
-rw-r--r--servo/components/style/gecko/arc_types.rs13
-rw-r--r--servo/components/style/gecko/media_features.rs19
-rw-r--r--servo/components/style/gecko/media_queries.rs41
-rw-r--r--servo/components/style/gecko/non_ts_pseudo_class_list.rs1
-rw-r--r--servo/components/style/gecko/pseudo_element.rs6
-rw-r--r--servo/components/style/gecko/selector_parser.rs4
-rw-r--r--servo/components/style/gecko/snapshot.rs29
-rw-r--r--servo/components/style/gecko/url.rs2
-rw-r--r--servo/components/style/gecko/wrapper.rs79
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()
}